/** Visit the given node at the given depth */
  private void visitNode(int depth, Node node) {
    if (node == mStartNode) {
      mInRange = true;
    }

    if (mInRange) {
      visitBeforeChildren(depth, node);
      if (mOpenTagOnly && mStartNode == node) {
        mInRange = false;
        return;
      }
    }

    NodeList children = node.getChildNodes();
    for (int i = 0, n = children.getLength(); i < n; i++) {
      Node child = children.item(i);
      visitNode(depth + 1, child);
    }

    if (mInRange) {
      visitAfterChildren(depth, node);
    }

    if (node == mEndNode) {
      mInRange = false;
    }
  }
  /**
   * Start pretty-printing at the given node, which must either be the startNode or contain it as a
   * descendant.
   *
   * @param rootDepth the depth of the given node, used to determine indentation
   * @param root the node to start pretty printing from (which may not itself be included in the
   *     start to end node range but should contain it)
   * @param startNode the node to start formatting at
   * @param endNode the node to end formatting at
   * @param out the {@link StringBuilder} to pretty print into
   * @param openTagOnly if true, only format the open tag of the startNode (and nothing else)
   */
  public void prettyPrint(
      int rootDepth,
      Node root,
      Node startNode,
      Node endNode,
      StringBuilder out,
      boolean openTagOnly) {
    if (startNode == null) {
      startNode = root;
    }
    if (endNode == null) {
      endNode = root;
    }
    assert !openTagOnly || startNode == endNode;

    mStartNode = startNode;
    mOpenTagOnly = openTagOnly;
    mEndNode = endNode;
    mOut = out;
    mInRange = false;
    mIndentString = mPrefs.getOneIndentUnit();

    visitNode(rootDepth, root);

    if (mEndWithNewline && !endsWithLineSeparator()) {
      mOut.append(mLineSeparator);
    }
  }