The attached patch does:
- Implement bullet painting and formatting for HTML lists.
- Fix the CSS parser/resolver to correctly resolve CSS selectors, that
was completely borked before. This should improve HTML rendering
significantly.

2006-11-07  Roman Kennke  <[EMAIL PROTECTED]>

        * javax/swing/text/html/HTMLEditorKit.java
        (HTMLFactory.create): Include ListView.
        * javax/swing/text/html/ListView.java
        (paint): Removed comment.
        * javax/swing/text/html/StyleSheet.java
        (CSSStyle.priority): New field.
        (CSSStyle.CSSStyle(int)): New constructor with priority.
        (CSSStyle.compareTo): New method. Used for sorting the styles.
        (CSSStyleSheetParserCallback.declaration): Store the style
        with the complete selector.
        (ListPainter.attributes): Renamed as field.
        (ListPainter.styleSheet): New field.
        (ListPainter.type): New field.
        (ListPainter.ListPainter): Pass StyleSheet to constructor.
        (ListPainter.paint): Provide simplistic implementation.
        (getListPainter): Pass StyleSheet to constructor.
        (resolveStyle): Fixed CSS style resolving.
Index: javax/swing/text/html/HTMLEditorKit.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/HTMLEditorKit.java,v
retrieving revision 1.37
diff -u -1 -5 -r1.37 HTMLEditorKit.java
--- javax/swing/text/html/HTMLEditorKit.java	2 Nov 2006 21:36:29 -0000	1.37
+++ javax/swing/text/html/HTMLEditorKit.java	7 Nov 2006 15:16:07 -0000
@@ -634,51 +634,51 @@
               || tag.equals(HTML.Tag.H3) || tag.equals(HTML.Tag.H4)
               || tag.equals(HTML.Tag.H5) || tag.equals(HTML.Tag.H6)
               || tag.equals(HTML.Tag.DT))
             view = new ParagraphView(element);
           else if (tag.equals(HTML.Tag.LI) || tag.equals(HTML.Tag.DL)
                    || tag.equals(HTML.Tag.DD) || tag.equals(HTML.Tag.BODY)
                    || tag.equals(HTML.Tag.HTML) || tag.equals(HTML.Tag.CENTER)
                    || tag.equals(HTML.Tag.DIV)
                    || tag.equals(HTML.Tag.BLOCKQUOTE)
                    || tag.equals(HTML.Tag.PRE)
                    || tag.equals(HTML.Tag.FORM))
             view = new BlockView(element, View.Y_AXIS);
           else if (tag.equals(HTML.Tag.IMG))
             view = new ImageView(element);
           
-          // FIXME: Uncomment when the views have been implemented
           else if (tag.equals(HTML.Tag.CONTENT))
             view = new InlineView(element);
           else if (tag == HTML.Tag.HEAD)
             view = new NullView(element);
           else if (tag.equals(HTML.Tag.TABLE))
             view = new javax.swing.text.html.TableView(element);
           else if (tag.equals(HTML.Tag.TD))
             view = new ParagraphView(element);
           else if (tag.equals(HTML.Tag.HR))
             view = new HRuleView(element);
           else if (tag.equals(HTML.Tag.BR))
             view = new BRView(element);
           else if (tag.equals(HTML.Tag.INPUT) || tag.equals(HTML.Tag.SELECT)
                    || tag.equals(HTML.Tag.TEXTAREA))
             view = new FormView(element);
 
-          /*
           else if (tag.equals(HTML.Tag.MENU) || tag.equals(HTML.Tag.DIR)
                    || tag.equals(HTML.Tag.UL) || tag.equals(HTML.Tag.OL))
             view = new ListView(element);
+          // FIXME: Uncomment when the views have been implemented
+          /*
           else if (tag.equals(HTML.Tag.OBJECT))
             view = new ObjectView(element);
           else if (tag.equals(HTML.Tag.FRAMESET))
             view = new FrameSetView(element);
           else if (tag.equals(HTML.Tag.FRAME))
             view = new FrameView(element); */
         }
       if (view == null)
         {
           System.err.println("missing tag->view mapping for: " + element);
           view = new NullView(element);
         }
       return view;
     }
   }
Index: javax/swing/text/html/ListView.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/ListView.java,v
retrieving revision 1.1
diff -u -1 -5 -r1.1 ListView.java
--- javax/swing/text/html/ListView.java	21 Mar 2006 21:31:56 -0000	1.1
+++ javax/swing/text/html/ListView.java	7 Nov 2006 15:16:07 -0000
@@ -82,33 +82,30 @@
     if (axis != X_AXIS && axis != Y_AXIS)
       throw new IllegalArgumentException("Illegal axis parameter: " + axis);
 
     return 0.5F;
   }
 
   /**
    * Paints the <code>ListView</code>.
    *
    * @param g the graphics context to use for painting
    * @param allocation the allocation given to this view
    */
   public void paint(Graphics g, Shape allocation)
   {
     super.paint(g, allocation);
-    // FIXME: Why is this overridden? I think that painting would be done
-    // by the superclass and the stylesheet... Maybe find out when this
-    // stuff is implemented properly.
   }
 
   /**
    * Paints the child with the specified index into the specified allocation.
    *
    * This implementation forwards to the list painter fetched from the
    * [EMAIL PROTECTED] StyleSheet} and then calls
    * <code>super.paintChild(g, a, index)</code>.
    *
    * @param g the graphics context to use
    * @param a the allocation for the child
    * @param index the child index
    */
   protected void paintChild(Graphics g, Rectangle a, int index)
   {
Index: javax/swing/text/html/StyleSheet.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/StyleSheet.java,v
retrieving revision 1.11
diff -u -1 -5 -r1.11 StyleSheet.java
--- javax/swing/text/html/StyleSheet.java	7 Nov 2006 12:57:13 -0000	1.11
+++ javax/swing/text/html/StyleSheet.java	7 Nov 2006 15:16:07 -0000
@@ -43,33 +43,36 @@
 import gnu.javax.swing.text.html.css.CSSParserCallback;
 import gnu.javax.swing.text.html.css.FontSize;
 import gnu.javax.swing.text.html.css.FontStyle;
 import gnu.javax.swing.text.html.css.FontWeight;
 import gnu.javax.swing.text.html.css.Length;
 
 import java.awt.Color;
 import java.awt.Font;
 import java.awt.Graphics;
 import java.io.IOException;
 import java.io.Reader;
 import java.io.Serializable;
 import java.io.StringReader;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 import java.util.StringTokenizer;
 
 import javax.swing.border.BevelBorder;
 import javax.swing.border.Border;
 import javax.swing.border.LineBorder;
 import javax.swing.event.ChangeListener;
 import javax.swing.text.AttributeSet;
 import javax.swing.text.Element;
 import javax.swing.text.MutableAttributeSet;
 import javax.swing.text.SimpleAttributeSet;
 import javax.swing.text.Style;
 import javax.swing.text.StyleConstants;
 import javax.swing.text.StyleContext;
 import javax.swing.text.View;
 
@@ -77,31 +80,31 @@
 /**
  * This class adds support for defining the visual characteristics of HTML views
  * being rendered. This enables views to be customized by a look-and-feel, mulitple
  * views over the same model can be rendered differently. Each EditorPane has its 
  * own StyleSheet, but by default one sheet will be shared by all of the HTMLEditorKit
  * instances. An HTMLDocument can also have a StyleSheet, which holds specific CSS
  * specs. 
  * 
  *  In order for Views to store less state and therefore be more lightweight, 
  *  the StyleSheet can act as a factory for painters that handle some of the 
  *  rendering tasks. Since the StyleSheet may be used by views over multiple
  *  documents the HTML attributes don't effect the selector being used.
  *  
  *  The rules are stored as named styles, and other information is stored to 
  *  translate the context of an element to a rule.
- * 
+ *
  * @author Lillian Angel ([EMAIL PROTECTED])
  */
 public class StyleSheet extends StyleContext
 {
 
   /**
    * Parses CSS stylesheets using the parser in gnu/javax/swing/html/css.
    *
    * This is package private to avoid accessor methods.
    */
   class CSSStyleSheetParserCallback
     implements CSSParserCallback
   {
     /**
      * The selector for which the rules are currently parsed.
@@ -125,72 +128,83 @@
      * Called at the end of a statement.
      */
     public void endStatement()
     {
       selector = null;
     }
 
     /**
      * Called when a declaration is parsed.
      *
      * @param property the property
      * @param value the value
      */
     public void declaration(String property, String value)
     {
-      for (int i = 0; i < selector.length; i++)
+      CSSStyle style = (CSSStyle) css.get(selector);
+      if (style == null)
         {
-          CSSStyle style = (CSSStyle) css.get(selector[i]);
-          if (style == null)
-            {
-              style = new CSSStyle();
-              css.put(selector[i], style);
-            }
-          CSS.Attribute cssAtt = CSS.getAttribute(property);
-          Object val = CSS.getValue(cssAtt, value);
-          if (cssAtt != null)
-            style.addAttribute(cssAtt, val);
-          // else  // For debugging only.
-          //   System.err.println("no mapping for: " + property);
+          style = new CSSStyle(selector.length);
+          css.put(selector, style);
         }
+      CSS.Attribute cssAtt = CSS.getAttribute(property);
+      Object val = CSS.getValue(cssAtt, value);
+      if (cssAtt != null)
+        style.addAttribute(cssAtt, val);
     }
     
   }
 
   /**
    * Represents a style that is defined by a CSS rule.
    */
   private class CSSStyle
     extends SimpleAttributeSet
-    implements Style
+    implements Style, Comparable
   {
 
+    /**
+     * The priority of this style when matching CSS selectors.
+     */
+    int priority;
+
+    CSSStyle(int prio)
+    {
+      priority = prio;
+    }
+
     public String getName()
     {
       // TODO: Implement this for correctness.
       return null;
     }
 
     public void addChangeListener(ChangeListener listener)
     {
       // TODO: Implement this for correctness.
     }
 
     public void removeChangeListener(ChangeListener listener)
     {
       // TODO: Implement this for correctness.
     }
+
+    public int compareTo(Object o)
+    {
+      CSSStyle other = (CSSStyle) o;
+      return other.priority - priority;
+    }
     
   }
 
   /** The base URL */
   URL base;
   
   /** Base font size (int) */
   int baseFontSize;
   
   /** The style sheets stored. */
   StyleSheet[] styleSheet;
 
   /**
    * Maps element names (selectors) to AttributSet (the corresponding style
    * information).
@@ -362,38 +376,52 @@
    *
    * @param selector the selector
    * @param tags the tags
    * @param ids the corresponding ID attributes
    * @param classes the corresponding CLASS attributes
    *
    * @return the resolved style
    */
   private Style resolveStyle(String selector, String[] tags, String[] ids,
                              String[] classes)
   {
     // FIXME: This style resolver is not correct. But it works good enough for
     // the default.css.
     int count = tags.length;
     ArrayList styles = new ArrayList();
-    for (int i = 0; i < count; i++)
+    Set selectors = css.keySet();
+    for (Iterator i = selectors.iterator(); i.hasNext();)
       {
-        Style style = (Style) css.get(tags[i]);
-        if (style != null)
-          styles.add(style);
-        // FIXME: Handle ID and CLASS attributes.
+        String[] sel = (String[]) i.next();
+        // All parts of the selector must match.
+        if (sel.length <= tags.length)
+          {
+            boolean match = true;
+            for (int j = sel.length - 1; j >= 0 && match; j--)
+              {
+                if (! tags[sel.length - 1 - j].equals(sel[j]))
+                  match = false;
+              }
+            if (match)
+              styles.add(css.get(sel));
+          }
       }
+
+    // Sort selectors.
+    Collections.sort(styles);
     Style[] styleArray = new Style[styles.size()];
+    styleArray = (Style[]) styles.toArray(styleArray);
     Style resolved = new MultiStyle(selector,
                                     (Style[]) styles.toArray(styleArray));
     resolvedStyles.put(selector, resolved);
     return resolved;
   }
 
   /**
    * Gets the rule that best matches the selector. selector is a space
    * separated String of element names. The attributes of the returned 
    * Style will change as rules are added and removed.
    * 
    * @param selector - the element names separated by spaces
    * @return the set of CSS attributes to use to render
    */
   public Style getRule(String selector)
@@ -804,31 +832,31 @@
    * @return the box formatter
    */
   public BoxPainter getBoxPainter(AttributeSet a)
   {
     return new BoxPainter(a, this);     
   }
   
   /**
    * Gets the list formatter to use for the given set of CSS attributes.
    * 
    * @param a - the given set
    * @return the list formatter
    */
   public ListPainter getListPainter(AttributeSet a)
   {
-    return new ListPainter(a);         
+    return new ListPainter(a, this);         
   }
   
   /**
    * Sets the base font size between 1 and 7.
    * 
    * @param sz - the new font size for the base.
    */
   public void setBaseFontSize(int sz)
   {
     if (sz <= 7 && sz >= 1)
       baseFontSize = sz;
   }
   
   /**
    * Sets the base font size from the String. It can either identify
@@ -1051,46 +1079,70 @@
   }
   
   /**
    * This class carries out some of the CSS list formatting duties. Implementations
    * of this class enable views to present the CSS formatting while not knowing anything
    * about how the CSS values are being cached.
    * 
    * @author Lillian Angel ([EMAIL PROTECTED])
    */
   public static class ListPainter implements Serializable
   {
 
     /**
      * Attribute set for painter
      */
-    AttributeSet as;
-    
+    private AttributeSet attributes;
+
+    /**
+     * The associated style sheet.
+     */
+    private StyleSheet styleSheet;
+
+    /**
+     * The bullet type.
+     */
+    private String type;
+
     /**
      * Package-private constructor.
      * 
      * @param as - AttributeSet for painter
      */
-    ListPainter(AttributeSet as)
+    ListPainter(AttributeSet as, StyleSheet ss)
     {
-      this.as = as;
+      attributes = as;
+      styleSheet = ss;
+      type = (String) as.getAttribute(CSS.Attribute.LIST_STYLE_TYPE);
     }
-    
+
     /**
      * Paints the CSS list decoration according to the attributes given.
      * 
      * @param g - the graphics configuration
      * @param x - the x coordinate
      * @param y - the y coordinate
      * @param w - the width of the allocated area
      * @param h - the height of the allocated area
      * @param v - the view making the request
      * @param item - the list item to be painted >=0.
      */
     public void paint(Graphics g, float x, float y, float w, float h, View v,
                       int item)
     {
-      // FIXME: Not implemented.
+      // FIXME: This is a very simplistic list rendering. We still need
+      // to implement different bullet types (see type field) and custom
+      // bullets via images.
+      View itemView = v.getView(item);
+      AttributeSet viewAtts = itemView.getAttributes();
+      Object tag = viewAtts.getAttribute(StyleConstants.NameAttribute);
+      // Only paint something here when the child view is an LI tag
+      // and the calling view is some of the list tags then).
+      if (tag != null && tag == HTML.Tag.LI)
+        {
+          g.setColor(Color.BLACK);
+          g.fillOval((int) x - 15, (int) (h / 2 - 3 + y), 6, 6);
+        }
     }
   }
 
 }

Reply via email to