/**
   * Returns the bounding box (in the current view) of a specified position in the model. This
   * method is designed for line-wrapped views to use, as it allows you to specify a "starting
   * position" in the line, from which the x-value is assumed to be zero. The idea is that you
   * specify the first character in a physical line as <code>p0</code>, as this is the character
   * where the x-pixel value is 0.
   *
   * @param textArea The text area containing the text.
   * @param s A segment in which to load the line. This is passed in so we don't have to reallocate
   *     a new <code>Segment</code> for each call.
   * @param p0 The starting position in the physical line in the document.
   * @param p1 The position for which to get the bounding box in the view.
   * @param e How to expand tabs.
   * @param rect The rectangle whose x- and width-values are changed to represent the bounding box
   *     of <code>p1</code>. This is reused to keep from needlessly reallocating Rectangles.
   * @param x0 The x-coordinate (pixel) marking the left-hand border of the text. This is useful if
   *     the text area has a border, for example.
   * @return The bounding box in the view of the character <code>p1</code>.
   * @throws BadLocationException If <code>p0</code> or <code>p1</code> is not a valid location in
   *     the specified text area's document.
   * @throws IllegalArgumentException If <code>p0</code> and <code>p1</code> are not on the same
   *     line.
   */
  public static Rectangle getLineWidthUpTo(
      RSyntaxTextArea textArea, Segment s, int p0, int p1, TabExpander e, Rectangle rect, int x0)
      throws BadLocationException {

    RSyntaxDocument doc = (RSyntaxDocument) textArea.getDocument();

    // Ensure p0 and p1 are valid document positions.
    if (p0 < 0) throw new BadLocationException("Invalid document position", p0);
    else if (p1 > doc.getLength()) throw new BadLocationException("Invalid document position", p1);

    // Ensure p0 and p1 are in the same line, and get the start/end
    // offsets for that line.
    Element map = doc.getDefaultRootElement();
    int lineNum = map.getElementIndex(p0);
    // We do ">1" because p1 might be the first position on the next line
    // or the last position on the previous one.
    // if (lineNum!=map.getElementIndex(p1))
    if (Math.abs(lineNum - map.getElementIndex(p1)) > 1)
      throw new IllegalArgumentException(
          "p0 and p1 are not on the " + "same line (" + p0 + ", " + p1 + ").");

    // Get the token list.
    Token t = doc.getTokenListForLine(lineNum);

    // Modify the token list 't' to begin at p0 (but still have correct
    // token types, etc.), and get the x-location (in pixels) of the
    // beginning of this new token list.
    makeTokenListStartAt(t, p0, e, textArea, 0);

    rect = t.listOffsetToView(textArea, e, p1, x0, rect);
    return rect;
  }
  /** {@inheritDoc} */
  public ParseResult parse(RSyntaxDocument doc, String style) {

    result.clearNotices();
    Element root = doc.getDefaultRootElement();
    result.setParsedLines(0, root.getElementCount() - 1);

    if (spf == null || doc.getLength() == 0) {
      return result;
    }

    try {
      SAXParser sp = spf.newSAXParser();
      Handler handler = new Handler(doc);
      DocumentReader r = new DocumentReader(doc);
      InputSource input = new InputSource(r);
      sp.parse(input, handler);
      r.close();
    } catch (SAXParseException spe) {
      // A fatal parse error - ignore; a ParserNotice was already created.
    } catch (Exception e) {
      // e.printStackTrace(); // Will print if DTD specified and can't be found
      result.addNotice(
          new DefaultParserNotice(this, "Error parsing XML: " + e.getMessage(), 0, -1, -1));
    }

    return result;
  }