Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4167752

Accessibility support for character bounds broken for HTML table text

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P4 P4
    • None
    • 1.2.0
    • client-libs
    • unknown, x86
    • generic, windows_nt

      JEditorPane.getAccessibleContext().getAccessibleText().getCharacterBounds() doens't return a valid rectangle for text generated by the HTMLEditorKit for HTML tables. It returns null instead. This is because JTextComponent.modelToView() for the character index returned in JTextComponent.viewToModel(Point p) for the point under which the table cell is rendered throwing a BadLocationException().

      The following code illustrates the bug:

      /**
       * Program tests:
       * bug #4167752 (HTML character bounds broken for HTML table)
       * bug #4171509 (HTMLEditorKit should support StyleConstants)
       *
       * To test these bugs, create an HTML file with the following content
       * below, and invoke HtmlBug as follows:
       * java HtmlBug file://bugtest.html
       *
       * bugtest.html:
            <HTML><HEAD><TITLE>bugtest</TITLE></HEAD>
            <BODY>
            Normal, <b>bold,</b> <i>italic,</i> <u>underline</u> <p>
            <TABLE BORDER CELLSPACING=4 CELLPADDING=4 COLS=2 WIDTH="50%">
            <CAPTION>Table caption</CAPTION>
            <TR><TD>r1c1</TD><TD>r1c2</TD></TR>
            </TABLE>
            </BODY></HTML>
       */

      import java.awt.*;
      import java.net.URL;
      import java.net.MalformedURLException;
      import java.util.Properties;
      import java.io.IOException;
      import javax.swing.*;
      import javax.swing.event.*;
      import javax.swing.text.*;
      import javax.swing.text.html.*;
      import javax.accessibility.*;
      import java.io.*;


      /**
       * Simple wrapper around JEditorPane to browse html.
       * Useful to browse the javadoc for swing...
       * java HtmlBug file:/path-to-swing-docs/packages.html
       */
      public class HtmlBug implements HyperlinkListener {

          JEditorPane html;

          public HtmlBug(URL u) {
              try {
                  Properties props = System.getProperties();
                  props.put("http.proxyHost", "webcache1.eng");
                  props.put("http.proxyPort", "8080");
                  html = new JEditorPane(u);
                  html.setBackground(Color.white);
                  html.addHyperlinkListener(this);
                  html.setEditable(true);
                  JScrollPane scroller = new JScrollPane();
                  JViewport vp = scroller.getViewport();
                  vp.add(html);
                  vp.setBackingStoreEnabled(true);


                  JFrame f = new JFrame("testing");
                  f.getContentPane().setLayout(new BorderLayout());
                  f.getContentPane().add("Center", scroller);
                  f.pack();
                  f.setSize(600, 600);
                  f.setVisible(true);

                 
              } catch (IOException ioe) {
                  System.err.println("IOException: " + ioe.getMessage());
                  System.exit(1);
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }

          /**
           * Notification of a change relative to a
           * hyperlink.
           */
          public void hyperlinkUpdate(HyperlinkEvent e) {
              if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
                  if (e instanceof HTMLFrameHyperlinkEvent) {
                      HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent)e;
                      HTMLDocument doc = (HTMLDocument)html.getDocument();
                      doc.processHTMLFrameHyperlinkEvent(evt);
                  } else {
                      try {
                          System.err.println("setPage called with: " + e.getURL());
                          html.setPage(e.getURL());
                      } catch (IOException ioe) {
                          System.err.println("ioexception: " + ioe);
                      }
                  }
              }
          }

          /**
           * Walk through the document, dumping the contents via the
           * Java Accessibility API
           */
          public void dumpContentsViaAccessibilityAPI() {
      AccessibleContext ac = html.getAccessibleContext();
      AccessibleText at = ac.getAccessibleText();
      int count = at.getCharCount();
      for (int i = 0; i < count; i++) {
      dumpCharacterInfo(at, i);
      }
          }

          /**
           * Perform the calls in AccessibleJTextComponent.getCharacterBounds()
           * one at a time, to better illustrate failure
           */
          public void detailedRectLook(int i) {
      System.out.println("Detailed Rect look at #" + i);
      Document model = html.getDocument();
              if (i < 0 || i > model.getLength()-1) {
      System.out.println(" -> i < 0 || i > model.getLength()-1");
      return;
              }
      System.out.println(" -> i > 0 && i < model.getLength()-1");
              Rectangle rect;
              try {
                  rect = html.modelToView(i);
      System.out.println(" -> modelToView(" + i + ") succedded!");
      if (rect != null) {
      System.out.println(" -> rect = " + rect.toString());
      } else {
      System.out.println(" -> rect = (null)");
      }
              } catch (BadLocationException e) {
      System.out.println(" -> modelToView(" + i + ") failed!");
      System.out.println(" -> received BadLocationException = " + e.toString());
              }
          }

          /**
           *
           */
          public void dumpCharacterInfo(AccessibleText at, int index) {
      System.out.println("Examining character # " + index + ": " + at.getAtIndex(AccessibleText.CHARACTER, index));
      Rectangle r = at.getCharacterBounds(index);
      if (r != null) {
      System.out.println(" -> rect = " + r.toString());
      } else {
      System.out.println(" -> rect = (null)");
      }
      String attrString = new String();
      AttributeSet as = at.getCharacterAttribute(index);
              if (StyleConstants.isBold(as)) { attrString += "bold"; }
              if (StyleConstants.isItalic(as)) { attrString += "; italic"; }
              if (StyleConstants.isUnderline(as)) { attrString += "; underline"; }
      System.out.println(" -> attributes: " + attrString);
          }

          public static void main(String[] args) {
              if (args.length != 1) {
                  System.err.println("need URL argument");
                  System.exit(1);
              }
              try {
                  URL u = new URL(args[0]);
                  HtmlBug bug = new HtmlBug(u);
      bug.dumpContentsViaAccessibilityAPI();
      bug.detailedRectLook(52); // char offset 52 is in a table
              } catch (MalformedURLException e) {
                  System.err.println("Bad url");
                  System.exit(1);
              }
          }
      }

            tprinzing Tim Prinzing (Inactive)
            pkorn Peter Korn (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: