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;
+ }
}