This implements relative fonts for the HTML renderer. It can parse and
handle font sizes measured in 'em' and '%' now, as well as the 'larger'
and 'smaller' keywords.

It also fixes some minor glitches and can now render the japi pages
almost perfect:

http://kennke.org/~roman/japi5.png

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

        * gnu/javax/swing/text/html/css/CSSParser.java
        (parseDeclaration): Trim string before reporting.
        * gnu/javax/swing/text/html/css/FontSize.java
        (size): New field.
        (isRelative): New field.
        (sizeIndex): New field.
        (FontSize): Initialize new fields.
        (getValue): Changed to call getValue(int).
        (getValue(int)): New method. Implements relative font sizes.
        (isRelative): New method.
        (mapAbsolute): Store index.
        (mapEM): New helper method.
        (mapLarger): New helper method.
        (mapPercent): New helper method.
        (mapRelative): New helper method.
        (mapSmaller): New helper method.
        (mapValue): New helper method.
        * javax/swing/text/html/CSS.java
        (parseBackgroundShorthand): Create CSSColor directly.
        * javax/swing/text/html/StyleSheet.java
        (addRule): Invalidate resolved styles.
        (getFont): Call new getFontSize() method to resolve relative
        font sizes.
        (getFontSize): New helper method. Resolves relative font sizes.
        (translateHTMLToCSS): Create CSS objects directly.

/Roman

Index: javax/swing/text/html/CSS.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/CSS.java,v
retrieving revision 1.10
diff -u -1 -5 -r1.10 CSS.java
--- javax/swing/text/html/CSS.java	15 Nov 2006 11:03:00 -0000	1.10
+++ javax/swing/text/html/CSS.java	17 Nov 2006 22:11:02 -0000
@@ -536,19 +536,19 @@
   static void addInternal(MutableAttributeSet atts, Attribute a, String v)
   {
     if (a == Attribute.BACKGROUND)
       parseBackgroundShorthand(atts, v);
   }
 
   private static void parseBackgroundShorthand(MutableAttributeSet atts,
                                                String v)
   {
     StringTokenizer tokens = new StringTokenizer(v, " ");
     while (tokens.hasMoreElements())
       {
         String token = tokens.nextToken();
         if (CSSColor.isValidColor(token))
           atts.addAttribute(Attribute.BACKGROUND_COLOR,
-                            getValue(Attribute.BACKGROUND_COLOR, token));
+                            new CSSColor(token));
       }
   }
 }
Index: javax/swing/text/html/StyleSheet.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/StyleSheet.java,v
retrieving revision 1.16
diff -u -1 -5 -r1.16 StyleSheet.java
--- javax/swing/text/html/StyleSheet.java	16 Nov 2006 16:07:13 -0000	1.16
+++ javax/swing/text/html/StyleSheet.java	17 Nov 2006 22:11:03 -0000
@@ -472,30 +472,33 @@
   {
     CSSStyleSheetParserCallback cb =
       new CSSStyleSheetParserCallback(CSSStyle.PREC_AUTHOR_NORMAL);
     // FIXME: Handle ref.
     StringReader in = new StringReader(rule);
     CSSParser parser = new CSSParser(in, cb);
     try
       {
         parser.parse();
       }
     catch (IOException ex)
       {
         // Shouldn't happen. And if, then we
         System.err.println("IOException while parsing stylesheet: " + ex.getMessage());
       }
+    // Clean up resolved styles cache so that the new styles are recognized
+    // on next stylesheet request.
+    resolvedStyles.clear();
   }
   
   /**
    * Translates a CSS declaration into an AttributeSet. This is called
    * as a result of encountering an HTML style attribute.
    * 
    * @param decl - the declaration to get
    * @return the AttributeSet representing the declaration
    */
   public AttributeSet getDeclaration(String decl)
   {
     if (decl == null)
       return SimpleAttributeSet.EMPTY;
     // FIXME: Not implemented.
     return null;     
@@ -692,37 +695,37 @@
    * @return the set of CSS attributes
    */
   public AttributeSet translateHTMLToCSS(AttributeSet htmlAttrSet)
   {
     AttributeSet cssAttr = htmlAttrSet.copyAttributes();
 
     // The HTML align attribute maps directly to the CSS text-align attribute.
     Object o = htmlAttrSet.getAttribute(HTML.Attribute.ALIGN);
     if (o != null)
       cssAttr = addAttribute(cssAttr, CSS.Attribute.TEXT_ALIGN, o);
 
     // The HTML width attribute maps directly to CSS width.
     o = htmlAttrSet.getAttribute(HTML.Attribute.WIDTH);
     if (o != null)
       cssAttr = addAttribute(cssAttr, CSS.Attribute.WIDTH,
-                             CSS.getValue(CSS.Attribute.WIDTH, o.toString()));
+                             new Length(o.toString()));
 
     // The HTML height attribute maps directly to CSS height.
     o = htmlAttrSet.getAttribute(HTML.Attribute.HEIGHT);
     if (o != null)
       cssAttr = addAttribute(cssAttr, CSS.Attribute.HEIGHT,
-                             CSS.getValue(CSS.Attribute.HEIGHT, o.toString()));
+                             new Length(o.toString()));
 
     o = htmlAttrSet.getAttribute(HTML.Attribute.NOWRAP);
     if (o != null)
       cssAttr = addAttribute(cssAttr, CSS.Attribute.WHITE_SPACE, "nowrap");
 
     // Map cellspacing attr of tables to CSS border-spacing.
     o = htmlAttrSet.getAttribute(HTML.Attribute.CELLSPACING);
     if (o != null)
       cssAttr = addAttribute(cssAttr, CSS.Attribute.BORDER_SPACING,
                              new Length(o.toString()));
 
     // For table cells and headers, fetch the cellpadding value from the
     // parent table and set it as CSS padding attribute.
     HTML.Tag tag = (HTML.Tag)
                    htmlAttrSet.getAttribute(StyleConstants.NameAttribute);
@@ -840,58 +843,90 @@
    * @return the large set of attributes.
    */
   protected MutableAttributeSet createLargeAttributeSet(AttributeSet a)
   {
     return super.createLargeAttributeSet(a);     
   }
   
   /**
    * Gets the font to use for the given set.
    * 
    * @param a - the set to get the font for.
    * @return the font for the set
    */
   public Font getFont(AttributeSet a)
   {
-    FontSize size = (FontSize) a.getAttribute(CSS.Attribute.FONT_SIZE);
-    int realSize = 12;
-    if (size != null)
-      realSize = size.getValue();
+    int realSize = getFontSize(a);
 
     // Decrement size for subscript and superscript.
     Object valign = a.getAttribute(CSS.Attribute.VERTICAL_ALIGN);
     if (valign != null)
       {
         String v = valign.toString();
         if (v.contains("sup") || v.contains("sub"))
           realSize -= 2;
       }
 
     // TODO: Convert font family.
     String family = "SansSerif";
 
     int style = Font.PLAIN;
     FontWeight weight = (FontWeight) a.getAttribute(CSS.Attribute.FONT_WEIGHT);
     if (weight != null)
       style |= weight.getValue();
     FontStyle fStyle = (FontStyle) a.getAttribute(CSS.Attribute.FONT_STYLE);
     if (fStyle != null)
       style |= fStyle.getValue();
     return new Font(family, style, realSize);
   }
   
   /**
+   * Resolves the fontsize for a given set of attributes.
+   *
+   * @param atts the attributes
+   *
+   * @return the resolved font size
+   */
+  private int getFontSize(AttributeSet atts)
+  {
+    int size = 12;
+    if (atts.isDefined(CSS.Attribute.FONT_SIZE))
+      {
+        FontSize fs = (FontSize) atts.getAttribute(CSS.Attribute.FONT_SIZE);
+        if (fs.isRelative())
+          {
+            int parSize = 12;
+            AttributeSet resolver = atts.getResolveParent();
+            if (resolver != null) {
+              parSize = getFontSize(resolver);System.err.println("parent size: " + parSize);    }
+            size = fs.getValue(parSize); 
+          }
+        else
+          {
+            size = fs.getValue();
+          }
+      }
+    else
+      {
+        AttributeSet resolver = atts.getResolveParent();
+        if (resolver != null)
+          size = getFontSize(resolver);
+      }
+    return size;
+  }
+
+  /**
    * Takes a set of attributes and turns it into a foreground
    * color specification. This is used to specify things like, brigher, more hue
    * etc.
    * 
    * @param a - the set to get the foreground color for
    * @return the foreground color for the set
    */
   public Color getForeground(AttributeSet a)
   {
     CSSColor c = (CSSColor) a.getAttribute(CSS.Attribute.COLOR);
     Color color = null;
     if (c != null)
       color = c.getValue();
     return color;     
   }
Index: gnu/javax/swing/text/html/css/CSSParser.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/javax/swing/text/html/css/CSSParser.java,v
retrieving revision 1.3
diff -u -1 -5 -r1.3 CSSParser.java
--- gnu/javax/swing/text/html/css/CSSParser.java	16 Nov 2006 16:07:13 -0000	1.3
+++ gnu/javax/swing/text/html/css/CSSParser.java	17 Nov 2006 22:11:03 -0000
@@ -257,31 +257,31 @@
           } while (token == CSSScanner.S);
 
         // Read ':'.
         if (token == CSSScanner.DELIM && scanner.parseBuffer[0] == ':')
           {
             // Read any number of whitespace.
             do
               {
                 token = readToken();
               } while (token == CSSScanner.S);
             lookahead = token;
 
             StringBuilder value = new StringBuilder();
             if (parseValue(value))
               {
-                callback.declaration(property, value.toString());
+                callback.declaration(property, value.toString().trim());
               }
             else
               {
                 ret = false;
                 error = "Error while reading the property value";
               }
           }
         else
           {
             ret = false;
             error = "Expected colon to separate property and value";
           }
           
       }
     else
Index: gnu/javax/swing/text/html/css/FontSize.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/javax/swing/text/html/css/FontSize.java,v
retrieving revision 1.2
diff -u -1 -5 -r1.2 FontSize.java
--- gnu/javax/swing/text/html/css/FontSize.java	14 Nov 2006 20:53:59 -0000	1.2
+++ gnu/javax/swing/text/html/css/FontSize.java	17 Nov 2006 22:11:03 -0000
@@ -40,66 +40,109 @@
 
 /**
  * Converts CSS font-size values into real (point) values.
  *
  * @author Roman Kennke ([EMAIL PROTECTED])
  */
 public class FontSize
 {
 
   /**
    * The CSS value.
    */
   private String value;
 
   /**
+   * The actual font size.
+   */
+  private int size;
+
+  /**
+   * The index of one of the standard sizes that this font size maps to.
+   * This is -1 if this fontsize doesn't map to one of the standard sizes.
+   *
+   * @see #SCALE
+   */
+  private int sizeIndex;
+
+  /**
+   * True when this font size is relative.
+   */
+  private boolean isRelative;
+
+  /**
    * The default size for 'medium' absolute size. The other absolute sizes
    * are calculated from this.
    */
   public static final int DEFAULT_FONT_SIZE = 12;
 
   /**
    * The scaling factors relative to the medium size. Medium is at index 2.
    */
   private static final double[] SCALE = {0.8, 0.9, 1.0, 1.2, 1.4, 1.6, 1.8 };
 
   /**
    * Creates a new FontSize for the specified value.
    *
    * @param val the value to convert
    */
   public FontSize(String val)
   {
     value = val;
+    sizeIndex = -1;
+    isRelative = false;
+    size = mapValue();
+  }
+
+  /**
+   * Returns the font size value.
+   *
+   * @return the font size value
+   */
+  public int getValue(int p)
+  {
+    if (isRelative)
+      mapRelative(p);
+    return size;
+  }
+
+  public int getValue()
+  {
+    assert ! isRelative;
+    return size;
   }
 
   /**
    * Returns the converted real value in point.
    *
    * @return the converted real value in point
    */
-  public int getValue()
+  private int mapValue()
   {
     int intVal;
     if (value.contains("pt"))
       intVal = mapPoints();
     else if (value.contains("px"))
       intVal = mapPixels();
+    else if (value.contains("em") || value.contains("%")
+        || value.contains("larger") || value.contains("smaller"))
+      {
+        intVal = -1;
+        isRelative = true;
+      }
     else
       intVal = mapAbsolute();
-    // FIXME: Allow relative font values, ('larger' and 'smaller'). This
-    // requires knowledge about the parent element's font size.
     return intVal;
   }
 
   /**
    * Maps point values ('XXXpt').
    *
    * @return the real font size
    */
   private int mapPoints()
   {
     int end = value.indexOf("pt");
     String number = value.substring(0, end);
     int intVal = Integer.parseInt(number);
     return intVal;
   }
@@ -114,52 +157,117 @@
     int end = value.indexOf("px");
     if (end == -1)
       end = value.length();
     String number = value.substring(0, end);
     try
       {
         int intVal = Integer.parseInt(number);
         return intVal;
       }
     catch (NumberFormatException ex)
       {
         return DEFAULT_FONT_SIZE;
       }
   }
 
+  private int mapPercent(int par)
+  {
+    int end = value.indexOf("%");
+    if (end == -1)
+      end = value.length();
+    String number = value.substring(0, end);
+    try
+      {
+        int intVal = Integer.parseInt(number);
+        return intVal * par / 100;
+      }
+    catch (NumberFormatException ex)
+      {
+        System.err.println("couldn't map value: '" + value + "'");
+        return DEFAULT_FONT_SIZE;
+      }
+  }
+
+  private int mapEM(int par)
+  {
+    int end = value.indexOf("em");
+    if (end == -1)
+      end = value.length();
+    String number = value.substring(0, end);
+    try
+      {
+        float factor = Float.parseFloat(number);
+        // FIXME: Should be relative to the parent element's size.
+        return (int) (factor * par);
+      }
+    catch (NumberFormatException ex)
+      {
+        return DEFAULT_FONT_SIZE;
+      }
+  }
+
+  private int mapSmaller(int par)
+  {
+    return (int) (par * 0.9);
+  }
+
+  private int mapLarger(int par)
+  {
+    return (int) (par * 0.9);
+  }
+
   /**
    * Maps absolute font-size values.
    *
    * @return the real value
    */
   private int mapAbsolute()
   {
     int index;
     if (value.equals("xx-small") || value.equals("x-small"))
       index = 0;
     else if (value.equals("small"))
       index = 1;
     else if (value.equals("medium"))
       index = 2;
     else if (value.equals("large"))
       index = 3;
     else if (value.equals("x-large"))
       index = 4;
     else if (value.equals("xx-large"))
       index = 5;
     else
       index = 2;
     double scale = SCALE[index];
     // FIXME: Scale the real medium size of the document, rather than the
     // constant here.
     int intVal = (int) (scale * DEFAULT_FONT_SIZE);
+    sizeIndex = index;
     return intVal;
   }
 
   /**
    * Returns the string representation.
    */
   public String toString()
   {
     return value;
   }
+
+  private int mapRelative(int par)
+  {
+    if (value.contains("%"))
+      size = mapPercent(par);
+    else if (value.contains("em"))
+      size = mapEM(par);
+    else if (value.contains("larger"))
+      size = mapLarger(par);
+    else if (value.contains("smaller"))
+      size = mapSmaller(par);
+    return size;
+  }
+
+  public boolean isRelative()
+  {
+    return isRelative;
+  }
 }

Reply via email to