KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > text > html > CSS


1 /*
2  * @(#)CSS.java 1.59 06/02/24
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package javax.swing.text.html;
8
9 import java.awt.Color JavaDoc;
10 import java.awt.Font JavaDoc;
11 import java.awt.GraphicsEnvironment JavaDoc;
12 import java.awt.Toolkit JavaDoc;
13 import java.awt.HeadlessException JavaDoc;
14 import java.io.*;
15 import java.lang.reflect.Method JavaDoc;
16 import java.net.URL JavaDoc;
17 import java.net.MalformedURLException JavaDoc;
18 import java.util.Enumeration JavaDoc;
19 import java.util.Hashtable JavaDoc;
20 import java.util.Vector JavaDoc;
21 import java.util.Locale JavaDoc;
22 import javax.swing.ImageIcon JavaDoc;
23 import javax.swing.SizeRequirements JavaDoc;
24 import javax.swing.text.*;
25
26 /**
27  * Defines a set of
28  * <a HREF="http://www.w3.org/TR/REC-CSS1">CSS attributes</a>
29  * as a typesafe enumeration. The HTML View implementations use
30  * CSS attributes to determine how they will render. This also defines
31  * methods to map between CSS/HTML/StyleConstants. Any shorthand
32  * properties, such as font, are mapped to the intrinsic properties.
33  * <p>The following describes the CSS properties that are suppored by the
34  * rendering engine:
35  * <ul><li>font-family
36  * <li>font-style
37  * <li>font-size (supports relative units)
38  * <li>font-weight
39  * <li>font
40  * <li>color
41  * <li>background-color (with the exception of transparent)
42  * <li>background-image
43  * <li>background-repeat
44  * <li>background-position
45  * <li>background
46  * <li>background-repeat
47  * <li>text-decoration (with the exception of blink and overline)
48  * <li>vertical-align (only sup and super)
49  * <li>text-align (justify is treated as center)
50  * <li>margin-top
51  * <li>margin-right
52  * <li>margin-bottom
53  * <li>margin-left
54  * <li>margin
55  * <li>padding-top
56  * <li>padding-right
57  * <li>padding-bottom
58  * <li>padding-left
59  * <li>border-style (only supports inset, outset and none)
60  * <li>list-style-type
61  * <li>list-style-position
62  * </ul>
63  * The following are modeled, but currently not rendered.
64  * <ul><li>font-variant
65  * <li>background-attachment (background always treated as scroll)
66  * <li>word-spacing
67  * <li>letter-spacing
68  * <li>text-indent
69  * <li>text-transform
70  * <li>line-height
71  * <li>border-top-width (this is used to indicate if a border should be used)
72  * <li>border-right-width
73  * <li>border-bottom-width
74  * <li>border-left-width
75  * <li>border-width
76  * <li>border-top
77  * <li>border-right
78  * <li>border-bottom
79  * <li>border-left
80  * <li>border
81  * <li>width
82  * <li>height
83  * <li>float
84  * <li>clear
85  * <li>display
86  * <li>white-space
87  * <li>list-style
88  * </ul>
89  * <p><b>Note: for the time being we do not fully support relative units,
90  * unless noted, so that
91  * p { margin-top: 10% } will be treated as if no margin-top was specified.
92  *
93  * @author Timothy Prinzing
94  * @author Scott Violet
95  * @version 1.59 02/24/06
96  * @see StyleSheet
97  */

98 public class CSS implements Serializable {
99
100     /**
101      * Definitions to be used as a key on AttributeSet's
102      * that might hold CSS attributes. Since this is a
103      * closed set (i.e. defined exactly by the specification),
104      * it is final and cannot be extended.
105      */

106     public static final class Attribute {
107
108     private Attribute(String JavaDoc name, String JavaDoc defaultValue, boolean inherited) {
109         this.name = name;
110         this.defaultValue = defaultValue;
111         this.inherited = inherited;
112     }
113
114     /**
115      * The string representation of the attribute. This
116      * should exactly match the string specified in the
117      * CSS specification.
118      */

119     public String JavaDoc toString() {
120         return name;
121     }
122
123     /**
124      * Fetch the default value for the attribute.
125      * If there is no default value (such as for
126      * composite attributes), null will be returned.
127      */

128     public String JavaDoc getDefaultValue() {
129         return defaultValue;
130     }
131
132     /**
133      * Indicates if the attribute should be inherited
134      * from the parent or not.
135      */

136     public boolean isInherited() {
137         return inherited;
138     }
139
140     private String JavaDoc name;
141     private String JavaDoc defaultValue;
142     private boolean inherited;
143
144
145     public static final Attribute BACKGROUND =
146         new Attribute("background", null, false);
147
148     public static final Attribute BACKGROUND_ATTACHMENT =
149         new Attribute("background-attachment", "scroll", false);
150
151     public static final Attribute BACKGROUND_COLOR =
152         new Attribute("background-color", "transparent", false);
153
154     public static final Attribute BACKGROUND_IMAGE =
155         new Attribute("background-image", "none", false);
156
157     public static final Attribute BACKGROUND_POSITION =
158         new Attribute("background-position", null, false);
159
160     public static final Attribute BACKGROUND_REPEAT =
161         new Attribute("background-repeat", "repeat", false);
162
163     public static final Attribute BORDER =
164         new Attribute("border", null, false);
165
166     public static final Attribute BORDER_BOTTOM =
167         new Attribute("border-bottom", null, false);
168
169     public static final Attribute BORDER_BOTTOM_WIDTH =
170         new Attribute("border-bottom-width", "medium", false);
171
172     public static final Attribute BORDER_COLOR =
173         new Attribute("border-color", "black", false);
174
175     public static final Attribute BORDER_LEFT =
176         new Attribute("border-left", null, false);
177
178     public static final Attribute BORDER_LEFT_WIDTH =
179         new Attribute("border-left-width", "medium", false);
180
181     public static final Attribute BORDER_RIGHT =
182         new Attribute("border-right", null, false);
183
184     public static final Attribute BORDER_RIGHT_WIDTH =
185         new Attribute("border-right-width", "medium", false);
186
187     public static final Attribute BORDER_STYLE =
188         new Attribute("border-style", "none", false);
189
190     public static final Attribute BORDER_TOP =
191         new Attribute("border-top", null, false);
192
193     public static final Attribute BORDER_TOP_WIDTH =
194         new Attribute("border-top-width", "medium", false);
195
196     public static final Attribute BORDER_WIDTH =
197         new Attribute("border-width", "medium", false);
198
199     public static final Attribute CLEAR =
200         new Attribute("clear", "none", false);
201
202     public static final Attribute COLOR =
203         new Attribute("color", "black", true);
204
205     public static final Attribute DISPLAY =
206         new Attribute("display", "block", false);
207
208     public static final Attribute FLOAT =
209         new Attribute("float", "none", false);
210
211     public static final Attribute FONT =
212         new Attribute("font", null, true);
213
214     public static final Attribute FONT_FAMILY =
215         new Attribute("font-family", null, true);
216
217     public static final Attribute FONT_SIZE =
218         new Attribute("font-size", "medium", true);
219
220     public static final Attribute FONT_STYLE =
221         new Attribute("font-style", "normal", true);
222
223     public static final Attribute FONT_VARIANT =
224         new Attribute("font-variant", "normal", true);
225
226     public static final Attribute FONT_WEIGHT =
227         new Attribute("font-weight", "normal", true);
228
229     public static final Attribute HEIGHT =
230         new Attribute("height", "auto", false);
231
232     public static final Attribute LETTER_SPACING =
233         new Attribute("letter-spacing", "normal", true);
234
235     public static final Attribute LINE_HEIGHT =
236         new Attribute("line-height", "normal", true);
237
238     public static final Attribute LIST_STYLE =
239         new Attribute("list-style", null, true);
240
241     public static final Attribute LIST_STYLE_IMAGE =
242         new Attribute("list-style-image", "none", true);
243
244     public static final Attribute LIST_STYLE_POSITION =
245         new Attribute("list-style-position", "outside", true);
246
247     public static final Attribute LIST_STYLE_TYPE =
248         new Attribute("list-style-type", "disc", true);
249
250     public static final Attribute MARGIN =
251         new Attribute("margin", null, false);
252
253     public static final Attribute MARGIN_BOTTOM =
254         new Attribute("margin-bottom", "0", false);
255
256     public static final Attribute MARGIN_LEFT =
257         new Attribute("margin-left", "0", false);
258
259     public static final Attribute MARGIN_RIGHT =
260         new Attribute("margin-right", "0", false);
261
262         /*
263          * made up css attributes to describe orientation depended
264          * margins. used for <dir>, <menu>, <ul> etc. see
265          * 5088268 for more details
266          */

267         static final Attribute MARGIN_LEFT_LTR =
268             new Attribute("margin-left-ltr",
269                           Integer.toString(Integer.MIN_VALUE), false);
270
271         static final Attribute MARGIN_LEFT_RTL =
272             new Attribute("margin-left-rtl",
273                           Integer.toString(Integer.MIN_VALUE), false);
274         
275         static final Attribute MARGIN_RIGHT_LTR =
276             new Attribute("margin-right-ltr",
277                           Integer.toString(Integer.MIN_VALUE), false);
278
279         static final Attribute MARGIN_RIGHT_RTL =
280             new Attribute("margin-right-rtl",
281                           Integer.toString(Integer.MIN_VALUE), false);
282
283
284     public static final Attribute MARGIN_TOP =
285         new Attribute("margin-top", "0", false);
286
287     public static final Attribute PADDING =
288         new Attribute("padding", null, false);
289
290     public static final Attribute PADDING_BOTTOM =
291         new Attribute("padding-bottom", "0", false);
292
293     public static final Attribute PADDING_LEFT =
294         new Attribute("padding-left", "0", false);
295
296     public static final Attribute PADDING_RIGHT =
297         new Attribute("padding-right", "0", false);
298
299     public static final Attribute PADDING_TOP =
300         new Attribute("padding-top", "0", false);
301
302     public static final Attribute TEXT_ALIGN =
303         new Attribute("text-align", null, true);
304
305     public static final Attribute TEXT_DECORATION =
306         new Attribute("text-decoration", "none", true);
307
308     public static final Attribute TEXT_INDENT =
309         new Attribute("text-indent", "0", true);
310
311     public static final Attribute TEXT_TRANSFORM =
312         new Attribute("text-transform", "none", true);
313
314     public static final Attribute VERTICAL_ALIGN =
315         new Attribute("vertical-align", "baseline", false);
316
317     public static final Attribute WORD_SPACING =
318         new Attribute("word-spacing", "normal", true);
319
320     public static final Attribute WHITE_SPACE =
321         new Attribute("white-space", "normal", true);
322
323     public static final Attribute WIDTH =
324         new Attribute("width", "auto", false);
325
326     /*public*/ static final Attribute BORDER_SPACING =
327         new Attribute("border-spacing", "0", true);
328
329     /*public*/ static final Attribute CAPTION_SIDE =
330         new Attribute("caption-side", "left", true);
331
332     // All possible CSS attribute keys.
333
static final Attribute[] allAttributes = {
334         BACKGROUND, BACKGROUND_ATTACHMENT, BACKGROUND_COLOR,
335         BACKGROUND_IMAGE, BACKGROUND_POSITION, BACKGROUND_REPEAT,
336         BORDER, BORDER_BOTTOM, BORDER_BOTTOM_WIDTH, BORDER_COLOR,
337         BORDER_LEFT, BORDER_LEFT_WIDTH, BORDER_RIGHT, BORDER_RIGHT_WIDTH,
338         BORDER_STYLE, BORDER_TOP, BORDER_TOP_WIDTH, BORDER_WIDTH,
339         CLEAR, COLOR, DISPLAY, FLOAT, FONT, FONT_FAMILY, FONT_SIZE,
340         FONT_STYLE, FONT_VARIANT, FONT_WEIGHT, HEIGHT, LETTER_SPACING,
341         LINE_HEIGHT, LIST_STYLE, LIST_STYLE_IMAGE, LIST_STYLE_POSITION,
342         LIST_STYLE_TYPE, MARGIN, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT,
343         MARGIN_TOP, PADDING, PADDING_BOTTOM, PADDING_LEFT, PADDING_RIGHT,
344         PADDING_TOP, TEXT_ALIGN, TEXT_DECORATION, TEXT_INDENT, TEXT_TRANSFORM,
345         VERTICAL_ALIGN, WORD_SPACING, WHITE_SPACE, WIDTH,
346             BORDER_SPACING, CAPTION_SIDE,
347             MARGIN_LEFT_LTR, MARGIN_LEFT_RTL, MARGIN_RIGHT_LTR, MARGIN_RIGHT_RTL
348     };
349
350     private static final Attribute[] ALL_MARGINS =
351             { MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM, MARGIN_LEFT };
352     private static final Attribute[] ALL_PADDING =
353             { PADDING_TOP, PADDING_RIGHT, PADDING_BOTTOM, PADDING_LEFT };
354     private static final Attribute[] ALL_BORDER_WIDTHS =
355             { BORDER_TOP_WIDTH, BORDER_RIGHT_WIDTH, BORDER_BOTTOM_WIDTH,
356           BORDER_LEFT_WIDTH };
357
358     }
359
360     static final class Value {
361
362     private Value(String JavaDoc name) {
363         this.name = name;
364     }
365
366     /**
367      * The string representation of the attribute. This
368      * should exactly match the string specified in the
369      * CSS specification.
370      */

371     public String JavaDoc toString() {
372         return name;
373     }
374
375     static final Value INHERITED = new Value("inherited");
376     static final Value NONE = new Value("none");
377     static final Value DOTTED = new Value("dotted");
378     static final Value DASHED = new Value("dashed");
379     static final Value SOLID = new Value("solid");
380     static final Value DOUBLE = new Value("double");
381     static final Value GROOVE = new Value("groove");
382     static final Value RIDGE = new Value("ridge");
383     static final Value INSET = new Value("inset");
384     static final Value OUTSET = new Value("outset");
385     // Lists.
386
static final Value BLANK_LIST_ITEM = new Value("none");
387     static final Value DISC = new Value("disc");
388     static final Value CIRCLE = new Value("circle");
389     static final Value SQUARE = new Value("square");
390     static final Value DECIMAL = new Value("decimal");
391     static final Value LOWER_ROMAN = new Value("lower-roman");
392     static final Value UPPER_ROMAN = new Value("upper-roman");
393     static final Value LOWER_ALPHA = new Value("lower-alpha");
394     static final Value UPPER_ALPHA = new Value("upper-alpha");
395     // background-repeat
396
static final Value BACKGROUND_NO_REPEAT = new Value("no-repeat");
397     static final Value BACKGROUND_REPEAT = new Value("repeat");
398     static final Value BACKGROUND_REPEAT_X = new Value("repeat-x");
399     static final Value BACKGROUND_REPEAT_Y = new Value("repeat-y");
400     // background-attachment
401
static final Value BACKGROUND_SCROLL = new Value("scroll");
402     static final Value BACKGROUND_FIXED = new Value("fixed");
403
404     private String JavaDoc name;
405
406     static final Value[] allValues = {
407         INHERITED, NONE, DOTTED, DASHED, SOLID, DOUBLE, GROOVE,
408         RIDGE, INSET, OUTSET, DISC, CIRCLE, SQUARE, DECIMAL,
409         LOWER_ROMAN, UPPER_ROMAN, LOWER_ALPHA, UPPER_ALPHA,
410         BLANK_LIST_ITEM, BACKGROUND_NO_REPEAT, BACKGROUND_REPEAT,
411         BACKGROUND_REPEAT_X, BACKGROUND_REPEAT_Y,
412         BACKGROUND_FIXED, BACKGROUND_FIXED
413     };
414     }
415
416     public CSS() {
417     baseFontSize = baseFontSizeIndex + 1;
418     // setup the css conversion table
419
valueConvertor = new Hashtable JavaDoc();
420     valueConvertor.put(CSS.Attribute.FONT_SIZE, new FontSize());
421     valueConvertor.put(CSS.Attribute.FONT_FAMILY, new FontFamily());
422     valueConvertor.put(CSS.Attribute.FONT_WEIGHT, new FontWeight());
423     valueConvertor.put(CSS.Attribute.BORDER_STYLE, new BorderStyle());
424     Object JavaDoc cv = new ColorValue();
425     valueConvertor.put(CSS.Attribute.COLOR, cv);
426     valueConvertor.put(CSS.Attribute.BACKGROUND_COLOR, cv);
427     valueConvertor.put(CSS.Attribute.BORDER_COLOR, cv);
428     Object JavaDoc lv = new LengthValue();
429     valueConvertor.put(CSS.Attribute.MARGIN_TOP, lv);
430     valueConvertor.put(CSS.Attribute.MARGIN_BOTTOM, lv);
431     valueConvertor.put(CSS.Attribute.MARGIN_LEFT, lv);
432         valueConvertor.put(CSS.Attribute.MARGIN_LEFT_LTR, lv);
433         valueConvertor.put(CSS.Attribute.MARGIN_LEFT_RTL, lv);
434     valueConvertor.put(CSS.Attribute.MARGIN_RIGHT, lv);
435         valueConvertor.put(CSS.Attribute.MARGIN_RIGHT_LTR, lv);
436         valueConvertor.put(CSS.Attribute.MARGIN_RIGHT_RTL, lv);
437     valueConvertor.put(CSS.Attribute.PADDING_TOP, lv);
438     valueConvertor.put(CSS.Attribute.PADDING_BOTTOM, lv);
439     valueConvertor.put(CSS.Attribute.PADDING_LEFT, lv);
440     valueConvertor.put(CSS.Attribute.PADDING_RIGHT, lv);
441     Object JavaDoc bv = new BorderWidthValue(null, 0);
442     valueConvertor.put(CSS.Attribute.BORDER_WIDTH, lv);
443     valueConvertor.put(CSS.Attribute.BORDER_TOP_WIDTH, bv);
444     valueConvertor.put(CSS.Attribute.BORDER_BOTTOM_WIDTH, bv);
445     valueConvertor.put(CSS.Attribute.BORDER_LEFT_WIDTH, bv);
446     valueConvertor.put(CSS.Attribute.BORDER_RIGHT_WIDTH, bv);
447     Object JavaDoc nlv = new LengthValue(true);
448     valueConvertor.put(CSS.Attribute.TEXT_INDENT, nlv);
449     valueConvertor.put(CSS.Attribute.WIDTH, lv);
450     valueConvertor.put(CSS.Attribute.HEIGHT, lv);
451     valueConvertor.put(CSS.Attribute.BORDER_SPACING, lv);
452     Object JavaDoc sv = new StringValue();
453     valueConvertor.put(CSS.Attribute.FONT_STYLE, sv);
454     valueConvertor.put(CSS.Attribute.TEXT_DECORATION, sv);
455     valueConvertor.put(CSS.Attribute.TEXT_ALIGN, sv);
456     valueConvertor.put(CSS.Attribute.VERTICAL_ALIGN, sv);
457     Object JavaDoc valueMapper = new CssValueMapper();
458     valueConvertor.put(CSS.Attribute.LIST_STYLE_TYPE,
459                valueMapper);
460     valueConvertor.put(CSS.Attribute.BACKGROUND_IMAGE,
461                new BackgroundImage());
462     valueConvertor.put(CSS.Attribute.BACKGROUND_POSITION,
463                new BackgroundPosition());
464     valueConvertor.put(CSS.Attribute.BACKGROUND_REPEAT,
465                valueMapper);
466     valueConvertor.put(CSS.Attribute.BACKGROUND_ATTACHMENT,
467                valueMapper);
468     Object JavaDoc generic = new CssValue();
469     int n = CSS.Attribute.allAttributes.length;
470     for (int i = 0; i < n; i++) {
471         CSS.Attribute JavaDoc key = CSS.Attribute.allAttributes[i];
472         if (valueConvertor.get(key) == null) {
473         valueConvertor.put(key, generic);
474         }
475     }
476     }
477
478     /**
479      * Sets the base font size. <code>sz</code> is a CSS value, and is
480      * not necessarily the point size. Use getPointSize to determine the
481      * point size corresponding to <code>sz</code>.
482      */

483     void setBaseFontSize(int sz) {
484     if (sz < 1)
485       baseFontSize = 0;
486     else if (sz > 7)
487       baseFontSize = 7;
488     else
489       baseFontSize = sz;
490     }
491
492     /**
493      * Sets the base font size from the passed in string.
494      */

495     void setBaseFontSize(String JavaDoc size) {
496     int relSize, absSize, diff;
497
498     if (size != null) {
499         if (size.startsWith("+")) {
500         relSize = Integer.valueOf(size.substring(1)).intValue();
501         setBaseFontSize(baseFontSize + relSize);
502         } else if (size.startsWith("-")) {
503         relSize = -Integer.valueOf(size.substring(1)).intValue();
504         setBaseFontSize(baseFontSize + relSize);
505         } else {
506         setBaseFontSize(Integer.valueOf(size).intValue());
507         }
508     }
509     }
510
511     /**
512      * Returns the base font size.
513      */

514     int getBaseFontSize() {
515     return baseFontSize;
516     }
517
518     /**
519      * Parses the CSS property <code>key</code> with value
520      * <code>value</code> placing the result in <code>att</code>.
521      */

522     void addInternalCSSValue(MutableAttributeSet attr,
523                  CSS.Attribute JavaDoc key, String JavaDoc value) {
524     if (key == CSS.Attribute.FONT) {
525         ShorthandFontParser.parseShorthandFont(this, value, attr);
526     }
527     else if (key == CSS.Attribute.BACKGROUND) {
528         ShorthandBackgroundParser.parseShorthandBackground
529                        (this, value, attr);
530     }
531     else if (key == CSS.Attribute.MARGIN) {
532         ShorthandMarginParser.parseShorthandMargin(this, value, attr,
533                        CSS.Attribute.ALL_MARGINS);
534     }
535     else if (key == CSS.Attribute.PADDING) {
536         ShorthandMarginParser.parseShorthandMargin(this, value, attr,
537                        CSS.Attribute.ALL_PADDING);
538     }
539     else if (key == CSS.Attribute.BORDER_WIDTH) {
540         ShorthandMarginParser.parseShorthandMargin(this, value, attr,
541                        CSS.Attribute.ALL_BORDER_WIDTHS);
542     }
543     else {
544         Object JavaDoc iValue = getInternalCSSValue(key, value);
545         if (iValue != null) {
546         attr.addAttribute(key, iValue);
547         }
548     }
549     }
550
551     /**
552      * Gets the internal CSS representation of <code>value</code> which is
553      * a CSS value of the CSS attribute named <code>key</code>. The receiver
554      * should not modify <code>value</code>, and the first <code>count</code>
555      * strings are valid.
556      */

557     Object JavaDoc getInternalCSSValue(CSS.Attribute JavaDoc key, String JavaDoc value) {
558     CssValue conv = (CssValue) valueConvertor.get(key);
559         Object JavaDoc r = conv.parseCssValue(value);
560         return r != null ? r : conv.parseCssValue(key.getDefaultValue());
561     }
562
563     /**
564      * Maps from a StyleConstants to a CSS Attribute.
565      */

566     Attribute styleConstantsKeyToCSSKey(StyleConstants sc) {
567     return (Attribute)styleConstantToCssMap.get(sc);
568     }
569
570     /**
571      * Maps from a StyleConstants value to a CSS value.
572      */

573     Object JavaDoc styleConstantsValueToCSSValue(StyleConstants sc,
574                      Object JavaDoc styleValue) {
575     Object JavaDoc cssKey = styleConstantsKeyToCSSKey(sc);
576     if (cssKey != null) {
577         CssValue conv = (CssValue)valueConvertor.get(cssKey);
578         return conv.fromStyleConstants(sc, styleValue);
579     }
580     return null;
581     }
582
583     /**
584      * Converts the passed in CSS value to a StyleConstants value.
585      * <code>key</code> identifies the CSS attribute being mapped.
586      */

587     Object JavaDoc cssValueToStyleConstantsValue(StyleConstants key, Object JavaDoc value) {
588     if (value instanceof CssValue) {
589         return ((CssValue)value).toStyleConstants((StyleConstants)key,
590                               null);
591     }
592     return null;
593     }
594
595     /**
596      * Returns the font for the values in the passed in AttributeSet.
597      * It is assumed the keys will be CSS.Attribute keys.
598      * <code>sc</code> is the StyleContext that will be messaged to get
599      * the font once the size, name and style have been determined.
600      */

601     Font JavaDoc getFont(StyleContext sc, AttributeSet a, int defaultSize, StyleSheet JavaDoc ss) {
602         ss = getStyleSheet(ss);
603     int size = getFontSize(a, defaultSize, ss);
604
605     /*
606      * If the vertical alignment is set to either superscirpt or
607      * subscript we reduce the font size by 2 points.
608      */

609     StringValue vAlignV = (StringValue)a.getAttribute
610                           (CSS.Attribute.VERTICAL_ALIGN);
611     if ((vAlignV != null)) {
612         String JavaDoc vAlign = vAlignV.toString();
613         if ((vAlign.indexOf("sup") >= 0) ||
614         (vAlign.indexOf("sub") >= 0)) {
615         size -= 2;
616         }
617     }
618     
619     FontFamily familyValue = (FontFamily)a.getAttribute
620                                         (CSS.Attribute.FONT_FAMILY);
621     String JavaDoc family = (familyValue != null) ? familyValue.getValue() :
622                               "SansSerif";
623     int style = Font.PLAIN;
624     FontWeight weightValue = (FontWeight) a.getAttribute
625                               (CSS.Attribute.FONT_WEIGHT);
626     if ((weightValue != null) && (weightValue.getValue() > 400)) {
627         style |= Font.BOLD;
628     }
629     Object JavaDoc fs = a.getAttribute(CSS.Attribute.FONT_STYLE);
630     if ((fs != null) && (fs.toString().indexOf("italic") >= 0)) {
631         style |= Font.ITALIC;
632     }
633         if (family.equalsIgnoreCase("monospace")) {
634             family = "Monospaced";
635         }
636     Font JavaDoc f = sc.getFont(family, style, size);
637         if (f == null
638             || (f.getFamily().equals("Dialog")
639                 && ! family.equalsIgnoreCase("Dialog"))) {
640             family = "SansSerif";
641             f = sc.getFont(family, style, size);
642         }
643     return f;
644     }
645
646     static int getFontSize(AttributeSet attr, int defaultSize, StyleSheet JavaDoc ss) {
647     // PENDING(prinz) this is a 1.1 based implementation, need to also
648
// have a 1.2 version.
649
FontSize sizeValue = (FontSize)attr.getAttribute(CSS.Attribute.
650                              FONT_SIZE);
651
652     return (sizeValue != null) ? (int)sizeValue.getValue(attr, ss) :
653                                  defaultSize;
654     }
655
656     /**
657      * Takes a set of attributes and turn it into a color
658      * specification. This might be used to specify things
659      * like brighter, more hue, etc.
660      * This will return null if there is no value for <code>key</code>.
661      *
662      * @param key CSS.Attribute identifying where color is stored.
663      * @param a the set of attributes
664      * @return the color
665      */

666     Color JavaDoc getColor(AttributeSet a, CSS.Attribute JavaDoc key) {
667     ColorValue cv = (ColorValue) a.getAttribute(key);
668     if (cv != null) {
669         return cv.getValue();
670     }
671     return null;
672     }
673
674     /**
675      * Returns the size of a font from the passed in string.
676      *
677      * @param size CSS string describing font size
678      * @param baseFontSize size to use for relative units.
679      */

680     float getPointSize(String JavaDoc size, StyleSheet JavaDoc ss) {
681     int relSize, absSize, diff, index;
682         ss = getStyleSheet(ss);
683     if (size != null) {
684         if (size.startsWith("+")) {
685         relSize = Integer.valueOf(size.substring(1)).intValue();
686         return getPointSize(baseFontSize + relSize, ss);
687         } else if (size.startsWith("-")) {
688         relSize = -Integer.valueOf(size.substring(1)).intValue();
689         return getPointSize(baseFontSize + relSize, ss);
690         } else {
691         absSize = Integer.valueOf(size).intValue();
692         return getPointSize(absSize, ss);
693         }
694     }
695     return 0;
696     }
697
698     /**
699      * Returns the length of the attribute in <code>a</code> with
700      * key <code>key</code>.
701      */

702     float getLength(AttributeSet a, CSS.Attribute JavaDoc key, StyleSheet JavaDoc ss) {
703         ss = getStyleSheet(ss);
704     LengthValue lv = (LengthValue) a.getAttribute(key);
705         boolean isW3CLengthUnits = (ss == null) ? false : ss.isW3CLengthUnits();
706         float len = (lv != null) ? lv.getValue(isW3CLengthUnits) : 0;
707     return len;
708     }
709
710     /**
711      * Convert a set of HTML attributes to an equivalent
712      * set of CSS attributes.
713      *
714      * @param AttributeSet containing the HTML attributes.
715      * @return AttributeSet containing the corresponding CSS attributes.
716      * The AttributeSet will be empty if there are no mapping
717      * CSS attributes.
718      */

719     AttributeSet translateHTMLToCSS(AttributeSet htmlAttrSet) {
720     MutableAttributeSet cssAttrSet = new SimpleAttributeSet();
721     Element elem = (Element)htmlAttrSet;
722     HTML.Tag JavaDoc tag = getHTMLTag(htmlAttrSet);
723     if ((tag == HTML.Tag.TD) || (tag == HTML.Tag.TH)) {
724         // translate border width into the cells
725
AttributeSet tableAttr = elem.getParentElement().
726                              getParentElement().getAttributes();
727         translateAttribute(HTML.Attribute.BORDER, tableAttr, cssAttrSet);
728         String JavaDoc pad = (String JavaDoc)tableAttr.getAttribute(HTML.Attribute.CELLPADDING);
729         if (pad != null) {
730         LengthValue v =
731             (LengthValue)getInternalCSSValue(CSS.Attribute.PADDING_TOP, pad);
732         v.span = (v.span < 0) ? 0 : v.span;
733         cssAttrSet.addAttribute(CSS.Attribute.PADDING_TOP, v);
734         cssAttrSet.addAttribute(CSS.Attribute.PADDING_BOTTOM, v);
735         cssAttrSet.addAttribute(CSS.Attribute.PADDING_LEFT, v);
736         cssAttrSet.addAttribute(CSS.Attribute.PADDING_RIGHT, v);
737         }
738     }
739     if (elem.isLeaf()) {
740         translateEmbeddedAttributes(htmlAttrSet, cssAttrSet);
741     } else {
742         translateAttributes(tag, htmlAttrSet, cssAttrSet);
743     }
744     if (tag == HTML.Tag.CAPTION) {
745         /*
746          * Navigator uses ALIGN for caption placement and IE uses VALIGN.
747          */

748         Object JavaDoc v = htmlAttrSet.getAttribute(HTML.Attribute.ALIGN);
749         if ((v != null) && (v.equals("top") || v.equals("bottom"))) {
750         cssAttrSet.addAttribute(CSS.Attribute.CAPTION_SIDE, v);
751         cssAttrSet.removeAttribute(CSS.Attribute.TEXT_ALIGN);
752         } else {
753         v = htmlAttrSet.getAttribute(HTML.Attribute.VALIGN);
754         if (v != null) {
755             cssAttrSet.addAttribute(CSS.Attribute.CAPTION_SIDE, v);
756         }
757         }
758     }
759     return cssAttrSet;
760     }
761
762     private static final Hashtable JavaDoc attributeMap = new Hashtable JavaDoc();
763     private static final Hashtable JavaDoc valueMap = new Hashtable JavaDoc();
764
765     /**
766      * The hashtable and the static initalization block below,
767      * set up a mapping from well-known HTML attributes to
768      * CSS attributes. For the most part, there is a 1-1 mapping
769      * between the two. However in the case of certain HTML
770      * attributes for example HTML.Attribute.VSPACE or
771      * HTML.Attribute.HSPACE, end up mapping to two CSS.Attribute's.
772      * Therefore, the value associated with each HTML.Attribute.
773      * key ends up being an array of CSS.Attribute.* objects.
774      */

775     private static final Hashtable JavaDoc htmlAttrToCssAttrMap = new Hashtable JavaDoc(20);
776
777     /**
778      * The hashtable and static initialization that follows sets
779      * up a translation from StyleConstants (i.e. the <em>well known</em>
780      * attributes) to the associated CSS attributes.
781      */

782     private static final Hashtable JavaDoc styleConstantToCssMap = new Hashtable JavaDoc(17);
783     /** Maps from HTML value to a CSS value. Used in internal mapping. */
784     private static final Hashtable JavaDoc htmlValueToCssValueMap = new Hashtable JavaDoc(8);
785     /** Maps from CSS value (string) to internal value. */
786     private static final Hashtable JavaDoc cssValueToInternalValueMap = new Hashtable JavaDoc(13);
787
788     static {
789     // load the attribute map
790
for (int i = 0; i < Attribute.allAttributes.length; i++ ) {
791         attributeMap.put(Attribute.allAttributes[i].toString(),
792                  Attribute.allAttributes[i]);
793     }
794     // load the value map
795
for (int i = 0; i < Value.allValues.length; i++ ) {
796         valueMap.put(Value.allValues[i].toString(),
797                  Value.allValues[i]);
798     }
799
800     htmlAttrToCssAttrMap.put(HTML.Attribute.COLOR,
801                  new CSS.Attribute JavaDoc[]{CSS.Attribute.COLOR});
802     htmlAttrToCssAttrMap.put(HTML.Attribute.TEXT,
803                  new CSS.Attribute JavaDoc[]{CSS.Attribute.COLOR});
804     htmlAttrToCssAttrMap.put(HTML.Attribute.CLEAR,
805                  new CSS.Attribute JavaDoc[]{CSS.Attribute.CLEAR});
806     htmlAttrToCssAttrMap.put(HTML.Attribute.BACKGROUND,
807                  new CSS.Attribute JavaDoc[]{CSS.Attribute.BACKGROUND_IMAGE});
808     htmlAttrToCssAttrMap.put(HTML.Attribute.BGCOLOR,
809                  new CSS.Attribute JavaDoc[]{CSS.Attribute.BACKGROUND_COLOR});
810     htmlAttrToCssAttrMap.put(HTML.Attribute.WIDTH,
811                  new CSS.Attribute JavaDoc[]{CSS.Attribute.WIDTH});
812     htmlAttrToCssAttrMap.put(HTML.Attribute.HEIGHT,
813                  new CSS.Attribute JavaDoc[]{CSS.Attribute.HEIGHT});
814     htmlAttrToCssAttrMap.put(HTML.Attribute.BORDER,
815                  new CSS.Attribute JavaDoc[]{CSS.Attribute.BORDER_TOP_WIDTH, CSS.Attribute.BORDER_RIGHT_WIDTH, CSS.Attribute.BORDER_BOTTOM_WIDTH, CSS.Attribute.BORDER_LEFT_WIDTH});
816     htmlAttrToCssAttrMap.put(HTML.Attribute.CELLPADDING,
817                  new CSS.Attribute JavaDoc[]{CSS.Attribute.PADDING});
818     htmlAttrToCssAttrMap.put(HTML.Attribute.CELLSPACING,
819                  new CSS.Attribute JavaDoc[]{CSS.Attribute.BORDER_SPACING});
820     htmlAttrToCssAttrMap.put(HTML.Attribute.MARGINWIDTH,
821                  new CSS.Attribute JavaDoc[]{CSS.Attribute.MARGIN_LEFT,
822                              CSS.Attribute.MARGIN_RIGHT});
823     htmlAttrToCssAttrMap.put(HTML.Attribute.MARGINHEIGHT,
824                  new CSS.Attribute JavaDoc[]{CSS.Attribute.MARGIN_TOP,
825                              CSS.Attribute.MARGIN_BOTTOM});
826     htmlAttrToCssAttrMap.put(HTML.Attribute.HSPACE,
827                  new CSS.Attribute JavaDoc[]{CSS.Attribute.PADDING_LEFT,
828                              CSS.Attribute.PADDING_RIGHT});
829     htmlAttrToCssAttrMap.put(HTML.Attribute.VSPACE,
830                  new CSS.Attribute JavaDoc[]{CSS.Attribute.PADDING_BOTTOM,
831                              CSS.Attribute.PADDING_TOP});
832     htmlAttrToCssAttrMap.put(HTML.Attribute.FACE,
833                  new CSS.Attribute JavaDoc[]{CSS.Attribute.FONT_FAMILY});
834     htmlAttrToCssAttrMap.put(HTML.Attribute.SIZE,
835                  new CSS.Attribute JavaDoc[]{CSS.Attribute.FONT_SIZE});
836     htmlAttrToCssAttrMap.put(HTML.Attribute.VALIGN,
837                  new CSS.Attribute JavaDoc[]{CSS.Attribute.VERTICAL_ALIGN});
838     htmlAttrToCssAttrMap.put(HTML.Attribute.ALIGN,
839                  new CSS.Attribute JavaDoc[]{CSS.Attribute.VERTICAL_ALIGN,
840                              CSS.Attribute.TEXT_ALIGN,
841                              CSS.Attribute.FLOAT});
842     htmlAttrToCssAttrMap.put(HTML.Attribute.TYPE,
843                  new CSS.Attribute JavaDoc[]{CSS.Attribute.LIST_STYLE_TYPE});
844     htmlAttrToCssAttrMap.put(HTML.Attribute.NOWRAP,
845                  new CSS.Attribute JavaDoc[]{CSS.Attribute.WHITE_SPACE});
846
847     // initialize StyleConstants mapping
848
styleConstantToCssMap.put(StyleConstants.FontFamily,
849                   CSS.Attribute.FONT_FAMILY);
850     styleConstantToCssMap.put(StyleConstants.FontSize,
851                   CSS.Attribute.FONT_SIZE);
852     styleConstantToCssMap.put(StyleConstants.Bold,
853                   CSS.Attribute.FONT_WEIGHT);
854     styleConstantToCssMap.put(StyleConstants.Italic,
855                   CSS.Attribute.FONT_STYLE);
856     styleConstantToCssMap.put(StyleConstants.Underline,
857                   CSS.Attribute.TEXT_DECORATION);
858     styleConstantToCssMap.put(StyleConstants.StrikeThrough,
859                   CSS.Attribute.TEXT_DECORATION);
860     styleConstantToCssMap.put(StyleConstants.Superscript,
861                   CSS.Attribute.VERTICAL_ALIGN);
862     styleConstantToCssMap.put(StyleConstants.Subscript,
863                   CSS.Attribute.VERTICAL_ALIGN);
864     styleConstantToCssMap.put(StyleConstants.Foreground,
865                   CSS.Attribute.COLOR);
866     styleConstantToCssMap.put(StyleConstants.Background,
867                   CSS.Attribute.BACKGROUND_COLOR);
868     styleConstantToCssMap.put(StyleConstants.FirstLineIndent,
869                   CSS.Attribute.TEXT_INDENT);
870     styleConstantToCssMap.put(StyleConstants.LeftIndent,
871                   CSS.Attribute.MARGIN_LEFT);
872     styleConstantToCssMap.put(StyleConstants.RightIndent,
873                   CSS.Attribute.MARGIN_RIGHT);
874     styleConstantToCssMap.put(StyleConstants.SpaceAbove,
875                   CSS.Attribute.MARGIN_TOP);
876     styleConstantToCssMap.put(StyleConstants.SpaceBelow,
877                   CSS.Attribute.MARGIN_BOTTOM);
878     styleConstantToCssMap.put(StyleConstants.Alignment,
879                   CSS.Attribute.TEXT_ALIGN);
880
881     // HTML->CSS
882
htmlValueToCssValueMap.put("disc", CSS.Value.DISC);
883     htmlValueToCssValueMap.put("square", CSS.Value.SQUARE);
884     htmlValueToCssValueMap.put("circle", CSS.Value.CIRCLE);
885     htmlValueToCssValueMap.put("1", CSS.Value.DECIMAL);
886     htmlValueToCssValueMap.put("a", CSS.Value.LOWER_ALPHA);
887     htmlValueToCssValueMap.put("A", CSS.Value.UPPER_ALPHA);
888     htmlValueToCssValueMap.put("i", CSS.Value.LOWER_ROMAN);
889     htmlValueToCssValueMap.put("I", CSS.Value.UPPER_ROMAN);
890
891     // CSS-> internal CSS
892
cssValueToInternalValueMap.put("none", CSS.Value.NONE);
893     cssValueToInternalValueMap.put("disc", CSS.Value.DISC);
894     cssValueToInternalValueMap.put("square", CSS.Value.SQUARE);
895     cssValueToInternalValueMap.put("circle", CSS.Value.CIRCLE);
896     cssValueToInternalValueMap.put("decimal", CSS.Value.DECIMAL);
897     cssValueToInternalValueMap.put("lower-roman", CSS.Value.LOWER_ROMAN);
898     cssValueToInternalValueMap.put("upper-roman", CSS.Value.UPPER_ROMAN);
899     cssValueToInternalValueMap.put("lower-alpha", CSS.Value.LOWER_ALPHA);
900     cssValueToInternalValueMap.put("upper-alpha", CSS.Value.UPPER_ALPHA);
901     cssValueToInternalValueMap.put("repeat", CSS.Value.BACKGROUND_REPEAT);
902     cssValueToInternalValueMap.put("no-repeat",
903                        CSS.Value.BACKGROUND_NO_REPEAT);
904     cssValueToInternalValueMap.put("repeat-x",
905                        CSS.Value.BACKGROUND_REPEAT_X);
906     cssValueToInternalValueMap.put("repeat-y",
907                        CSS.Value.BACKGROUND_REPEAT_Y);
908     cssValueToInternalValueMap.put("scroll",
909                        CSS.Value.BACKGROUND_SCROLL);
910     cssValueToInternalValueMap.put("fixed",
911                        CSS.Value.BACKGROUND_FIXED);
912
913         // Register all the CSS attribute keys for archival/unarchival
914
Object JavaDoc[] keys = CSS.Attribute.allAttributes;
915     try {
916         for (int i = 0; i < keys.length; i++) {
917         StyleContext.registerStaticAttributeKey(keys[i]);
918         }
919     } catch (Throwable JavaDoc e) {
920         e.printStackTrace();
921     }
922
923         // Register all the CSS Values for archival/unarchival
924
keys = CSS.Value.allValues;
925     try {
926         for (int i = 0; i < keys.length; i++) {
927         StyleContext.registerStaticAttributeKey(keys[i]);
928         }
929     } catch (Throwable JavaDoc e) {
930         e.printStackTrace();
931     }
932     }
933
934     /**
935      * Return the set of all possible CSS attribute keys.
936      */

937     public static Attribute[] getAllAttributeKeys() {
938     Attribute[] keys = new Attribute[Attribute.allAttributes.length];
939     System.arraycopy(Attribute.allAttributes, 0, keys, 0, Attribute.allAttributes.length);
940     return keys;
941     }
942
943     /**
944      * Translates a string to a <code>CSS.Attribute</code> object.
945      * This will return <code>null</code> if there is no attribute
946      * by the given name.
947      *
948      * @param name the name of the CSS attribute to fetch the
949      * typesafe enumeration for
950      * @return the <code>CSS.Attribute</code> object,
951      * or <code>null</code> if the string
952      * doesn't represent a valid attribute key
953      */

954     public static final Attribute getAttribute(String JavaDoc name) {
955     return (Attribute) attributeMap.get(name);
956     }
957
958     /**
959      * Translates a string to a <code>CSS.Value</code> object.
960      * This will return <code>null</code> if there is no value
961      * by the given name.
962      *
963      * @param name the name of the CSS value to fetch the
964      * typesafe enumeration for
965      * @return the <code>CSS.Value</code> object,
966      * or <code>null</code> if the string
967      * doesn't represent a valid CSS value name; this does
968      * not mean that it doesn't represent a valid CSS value
969      */

970     static final Value getValue(String JavaDoc name) {
971     return (Value) valueMap.get(name);
972     }
973
974
975     //
976
// Conversion related methods/classes
977
//
978

979     /**
980      * Returns a URL for the given CSS url string. If relative,
981      * <code>base</code> is used as the parent. If a valid URL can not
982      * be found, this will not throw a MalformedURLException, instead
983      * null will be returned.
984      */

985     static URL JavaDoc getURL(URL JavaDoc base, String JavaDoc cssString) {
986     if (cssString == null) {
987         return null;
988     }
989     if (cssString.startsWith("url(") &&
990         cssString.endsWith(")")) {
991         cssString = cssString.substring(4, cssString.length() - 1);
992     }
993     // Absolute first
994
try {
995         URL JavaDoc url = new URL JavaDoc(cssString);
996         if (url != null) {
997         return url;
998         }
999     } catch (MalformedURLException JavaDoc mue) {
1000    }
1001    // Then relative
1002
if (base != null) {
1003        // Relative URL, try from base
1004
try {
1005        URL JavaDoc url = new URL JavaDoc(base, cssString);
1006        return url;
1007        }
1008        catch (MalformedURLException JavaDoc muee) {
1009        }
1010    }
1011    return null;
1012    }
1013
1014    /**
1015     * Converts a type Color to a hex string
1016     * in the format "#RRGGBB"
1017     */

1018    static String JavaDoc colorToHex(Color JavaDoc color) {
1019
1020      String JavaDoc colorstr = new String JavaDoc("#");
1021
1022      // Red
1023
String JavaDoc str = Integer.toHexString(color.getRed());
1024      if (str.length() > 2)
1025    str = str.substring(0, 2);
1026      else if (str.length() < 2)
1027    colorstr += "0" + str;
1028      else
1029    colorstr += str;
1030
1031      // Green
1032
str = Integer.toHexString(color.getGreen());
1033      if (str.length() > 2)
1034    str = str.substring(0, 2);
1035      else if (str.length() < 2)
1036    colorstr += "0" + str;
1037      else
1038    colorstr += str;
1039
1040      // Blue
1041
str = Integer.toHexString(color.getBlue());
1042      if (str.length() > 2)
1043    str = str.substring(0, 2);
1044      else if (str.length() < 2)
1045    colorstr += "0" + str;
1046      else
1047    colorstr += str;
1048
1049      return colorstr;
1050    }
1051
1052     /**
1053      * Convert a "#FFFFFF" hex string to a Color.
1054      * If the color specification is bad, an attempt
1055      * will be made to fix it up.
1056      */

1057    static final Color JavaDoc hexToColor(String JavaDoc value) {
1058    String JavaDoc digits;
1059    int n = value.length();
1060    if (value.startsWith("#")) {
1061        digits = value.substring(1, Math.min(value.length(), 7));
1062    } else {
1063        digits = value;
1064    }
1065    String JavaDoc hstr = "0x" + digits;
1066    Color JavaDoc c;
1067    try {
1068        c = Color.decode(hstr);
1069    } catch (NumberFormatException JavaDoc nfe) {
1070        c = null;
1071    }
1072     return c;
1073     }
1074
1075    /**
1076     * Convert a color string such as "RED" or "#NNNNNN" or "rgb(r, g, b)"
1077     * to a Color.
1078     */

1079    static Color JavaDoc stringToColor(String JavaDoc str) {
1080      Color JavaDoc color = null;
1081
1082      if (str.length() == 0)
1083        color = Color.black;
1084      else if (str.startsWith("rgb(")) {
1085          color = parseRGB(str);
1086      }
1087      else if (str.charAt(0) == '#')
1088        color = hexToColor(str);
1089      else if (str.equalsIgnoreCase("Black"))
1090        color = hexToColor("#000000");
1091      else if(str.equalsIgnoreCase("Silver"))
1092        color = hexToColor("#C0C0C0");
1093      else if(str.equalsIgnoreCase("Gray"))
1094        color = hexToColor("#808080");
1095      else if(str.equalsIgnoreCase("White"))
1096        color = hexToColor("#FFFFFF");
1097      else if(str.equalsIgnoreCase("Maroon"))
1098        color = hexToColor("#800000");
1099      else if(str.equalsIgnoreCase("Red"))
1100        color = hexToColor("#FF0000");
1101      else if(str.equalsIgnoreCase("Purple"))
1102        color = hexToColor("#800080");
1103      else if(str.equalsIgnoreCase("Fuchsia"))
1104        color = hexToColor("#FF00FF");
1105      else if(str.equalsIgnoreCase("Green"))
1106        color = hexToColor("#008000");
1107      else if(str.equalsIgnoreCase("Lime"))
1108        color = hexToColor("#00FF00");
1109      else if(str.equalsIgnoreCase("Olive"))
1110        color = hexToColor("#808000");
1111      else if(str.equalsIgnoreCase("Yellow"))
1112        color = hexToColor("#FFFF00");
1113      else if(str.equalsIgnoreCase("Navy"))
1114        color = hexToColor("#000080");
1115      else if(str.equalsIgnoreCase("Blue"))
1116        color = hexToColor("#0000FF");
1117      else if(str.equalsIgnoreCase("Teal"))
1118        color = hexToColor("#008080");
1119      else if(str.equalsIgnoreCase("Aqua"))
1120        color = hexToColor("#00FFFF");
1121      else
1122      color = hexToColor(str); // sometimes get specified without leading #
1123
return color;
1124    }
1125
1126    /**
1127     * Parses a String in the format <code>rgb(r, g, b)</code> where
1128     * each of the Color components is either an integer, or a floating number
1129     * with a % after indicating a percentage value of 255. Values are
1130     * constrained to fit with 0-255. The resulting Color is returned.
1131     */

1132    private static Color JavaDoc parseRGB(String JavaDoc string) {
1133        // Find the next numeric char
1134
int[] index = new int[1];
1135
1136        index[0] = 4;
1137        int red = getColorComponent(string, index);
1138        int green = getColorComponent(string, index);
1139        int blue = getColorComponent(string, index);
1140
1141        return new Color JavaDoc(red, green, blue);
1142    }
1143
1144    /**
1145     * Returns the next integer value from <code>string</code> starting
1146     * at <code>index[0]</code>. The value can either can an integer, or
1147     * a percentage (floating number ending with %), in which case it is
1148     * multiplied by 255.
1149     */

1150    private static int getColorComponent(String JavaDoc string, int[] index) {
1151        int length = string.length();
1152        char aChar;
1153
1154        // Skip non-decimal chars
1155
while(index[0] < length && (aChar = string.charAt(index[0])) != '-' &&
1156              !Character.isDigit(aChar) && aChar != '.') {
1157            index[0]++;
1158        }
1159
1160        int start = index[0];
1161
1162        if (start < length && string.charAt(index[0]) == '-') {
1163            index[0]++;
1164        }
1165        while(index[0] < length &&
1166                         Character.isDigit(string.charAt(index[0]))) {
1167            index[0]++;
1168        }
1169        if (index[0] < length && string.charAt(index[0]) == '.') {
1170            // Decimal value
1171
index[0]++;
1172            while(index[0] < length &&
1173                  Character.isDigit(string.charAt(index[0]))) {
1174                index[0]++;
1175            }
1176        }
1177        if (start != index[0]) {
1178            try {
1179                float value = Float.parseFloat(string.substring
1180                                               (start, index[0]));
1181
1182                if (index[0] < length && string.charAt(index[0]) == '%') {
1183                    index[0]++;
1184                    value = value * 255f / 100f;
1185                }
1186                return Math.min(255, Math.max(0, (int)value));
1187            } catch (NumberFormatException JavaDoc nfe) {
1188                // Treat as 0
1189
}
1190        }
1191        return 0;
1192    }
1193
1194    static int getIndexOfSize(float pt, int[] sizeMap) {
1195        for (int i = 0; i < sizeMap.length; i ++ )
1196                if (pt <= sizeMap[i])
1197                        return i + 1;
1198        return sizeMap.length;
1199    }
1200
1201    static int getIndexOfSize(float pt, StyleSheet JavaDoc ss) {
1202        int[] sizeMap = (ss != null) ? ss.getSizeMap() :
1203            StyleSheet.sizeMapDefault;
1204        return getIndexOfSize(pt, sizeMap);
1205    }
1206
1207
1208    /**
1209     * @return an array of all the strings in <code>value</code>
1210     * that are separated by whitespace.
1211     */

1212    static String JavaDoc[] parseStrings(String JavaDoc value) {
1213    int current, last;
1214    int length = (value == null) ? 0 : value.length();
1215    Vector JavaDoc temp = new Vector JavaDoc(4);
1216
1217    current = 0;
1218    while (current < length) {
1219        // Skip ws
1220
while (current < length && Character.isWhitespace
1221           (value.charAt(current))) {
1222        current++;
1223        }
1224        last = current;
1225        while (current < length && !Character.isWhitespace
1226           (value.charAt(current))) {
1227        current++;
1228        }
1229        if (last != current) {
1230        temp.addElement(value.substring(last, current));
1231        }
1232        current++;
1233    }
1234    String JavaDoc[] retValue = new String JavaDoc[temp.size()];
1235    temp.copyInto(retValue);
1236    return retValue;
1237    }
1238
1239    /**
1240     * Return the point size, given a size index. Legal HTML index sizes
1241     * are 1-7.
1242     */

1243    float getPointSize(int index, StyleSheet JavaDoc ss) {
1244        ss = getStyleSheet(ss);
1245        int[] sizeMap = (ss != null) ? ss.getSizeMap() :
1246            StyleSheet.sizeMapDefault;
1247        --index;
1248    if (index < 0)
1249      return sizeMap[0];
1250    else if (index > sizeMap.length - 1)
1251      return sizeMap[sizeMap.length - 1];
1252    else
1253      return sizeMap[index];
1254    }
1255
1256
1257    private void translateEmbeddedAttributes(AttributeSet htmlAttrSet,
1258                         MutableAttributeSet cssAttrSet) {
1259    Enumeration JavaDoc keys = htmlAttrSet.getAttributeNames();
1260    if (htmlAttrSet.getAttribute(StyleConstants.NameAttribute) ==
1261        HTML.Tag.HR) {
1262        // HR needs special handling due to us treating it as a leaf.
1263
translateAttributes(HTML.Tag.HR, htmlAttrSet, cssAttrSet);
1264    }
1265    while (keys.hasMoreElements()) {
1266        Object JavaDoc key = keys.nextElement();
1267        if (key instanceof HTML.Tag JavaDoc) {
1268        HTML.Tag JavaDoc tag = (HTML.Tag JavaDoc)key;
1269        Object JavaDoc o = htmlAttrSet.getAttribute(tag);
1270        if (o != null && o instanceof AttributeSet) {
1271            translateAttributes(tag, (AttributeSet)o, cssAttrSet);
1272        }
1273        } else if (key instanceof CSS.Attribute JavaDoc) {
1274        cssAttrSet.addAttribute(key, htmlAttrSet.getAttribute(key));
1275        }
1276    }
1277    }
1278
1279    private void translateAttributes(HTML.Tag JavaDoc tag,
1280                        AttributeSet htmlAttrSet,
1281                        MutableAttributeSet cssAttrSet) {
1282    Enumeration JavaDoc names = htmlAttrSet.getAttributeNames();
1283    while (names.hasMoreElements()) {
1284        Object JavaDoc name = names.nextElement();
1285
1286        if (name instanceof HTML.Attribute JavaDoc) {
1287        HTML.Attribute JavaDoc key = (HTML.Attribute JavaDoc)name;
1288
1289        /*
1290         * HTML.Attribute.ALIGN needs special processing.
1291         * It can map to to 1 of many(3) possible CSS attributes
1292         * depending on the nature of the tag the attribute is
1293         * part off and depending on the value of the attribute.
1294         */

1295        if (key == HTML.Attribute.ALIGN) {
1296            String JavaDoc htmlAttrValue = (String JavaDoc)htmlAttrSet.getAttribute(HTML.Attribute.ALIGN);
1297            if (htmlAttrValue != null) {
1298            CSS.Attribute JavaDoc cssAttr = getCssAlignAttribute(tag, htmlAttrSet);
1299            if (cssAttr != null) {
1300                Object JavaDoc o = getCssValue(cssAttr, htmlAttrValue);
1301                if (o != null) {
1302                cssAttrSet.addAttribute(cssAttr, o);
1303                }
1304            }
1305            }
1306        } else {
1307
1308            /*
1309             * The html size attribute has a mapping in the CSS world only
1310             * if it is par of a font or base font tag.
1311             */

1312
1313            if (key == HTML.Attribute.SIZE && !isHTMLFontTag(tag)) {
1314            continue;
1315            }
1316
1317            translateAttribute(key, htmlAttrSet, cssAttrSet);
1318        }
1319        } else if (name instanceof CSS.Attribute JavaDoc) {
1320        cssAttrSet.addAttribute(name, htmlAttrSet.getAttribute(name));
1321        }
1322    }
1323    }
1324
1325    private void translateAttribute(HTML.Attribute JavaDoc key,
1326                       AttributeSet htmlAttrSet,
1327                       MutableAttributeSet cssAttrSet) {
1328    /*
1329     * In the case of all remaining HTML.Attribute's they
1330     * map to 1 or more CCS.Attribute.
1331     */

1332    CSS.Attribute JavaDoc[] cssAttrList = getCssAttribute(key);
1333    
1334    String JavaDoc htmlAttrValue = (String JavaDoc)htmlAttrSet.getAttribute(key);
1335    
1336    if (cssAttrList == null || htmlAttrValue == null) {
1337        return;
1338    }
1339    for (int i = 0; i < cssAttrList.length; i++) {
1340        Object JavaDoc o = getCssValue(cssAttrList[i], htmlAttrValue);
1341        if (o != null) {
1342        cssAttrSet.addAttribute(cssAttrList[i], o);
1343        }
1344    }
1345    }
1346
1347    /**
1348     * Given a CSS.Attribute object and its corresponding HTML.Attribute's
1349     * value, this method returns a CssValue object to associate with the
1350     * CSS attribute.
1351     *
1352     * @param the CSS.Attribute
1353     * @param a String containing the value associated HTML.Attribtue.
1354     */

1355    Object JavaDoc getCssValue(CSS.Attribute JavaDoc cssAttr, String JavaDoc htmlAttrValue) {
1356    CssValue value = (CssValue)valueConvertor.get(cssAttr);
1357    Object JavaDoc o = value.parseHtmlValue(htmlAttrValue);
1358    return o;
1359    }
1360
1361    /**
1362     * Maps an HTML.Attribute object to its appropriate CSS.Attributes.
1363     *
1364     * @param HTML.Attribute
1365     * @return CSS.Attribute[]
1366     */

1367    private CSS.Attribute JavaDoc[] getCssAttribute(HTML.Attribute JavaDoc hAttr) {
1368    return (CSS.Attribute JavaDoc[])htmlAttrToCssAttrMap.get(hAttr);
1369    }
1370
1371    /**
1372     * Maps HTML.Attribute.ALIGN to either:
1373     * CSS.Attribute.TEXT_ALIGN
1374     * CSS.Attribute.FLOAT
1375     * CSS.Attribute.VERTICAL_ALIGN
1376     * based on the tag associated with the attribute and the
1377     * value of the attribute.
1378     *
1379     * @param AttributeSet containing HTML attributes.
1380     * @return CSS.Attribute mapping for HTML.Attribute.ALIGN.
1381     */

1382    private CSS.Attribute JavaDoc getCssAlignAttribute(HTML.Tag JavaDoc tag,
1383                           AttributeSet htmlAttrSet) {
1384    return CSS.Attribute.TEXT_ALIGN;
1385/*
1386    String htmlAttrValue = (String)htmlAttrSet.getAttribute(HTML.Attribute.ALIGN);
1387    CSS.Attribute cssAttr = CSS.Attribute.TEXT_ALIGN;
1388    if (htmlAttrValue != null && htmlAttrSet instanceof Element) {
1389        Element elem = (Element)htmlAttrSet;
1390        if (!elem.isLeaf() && tag.isBlock() && validTextAlignValue(htmlAttrValue)) {
1391        return CSS.Attribute.TEXT_ALIGN;
1392        } else if (isFloater(htmlAttrValue)) {
1393        return CSS.Attribute.FLOAT;
1394        } else if (elem.isLeaf()) {
1395        return CSS.Attribute.VERTICAL_ALIGN;
1396        }
1397    }
1398    return null;
1399    */

1400    }
1401
1402    /**
1403     * Fetches the tag associated with the HTML AttributeSet.
1404     *
1405     * @param AttributeSet containing the HTML attributes.
1406     * @return HTML.Tag
1407     */

1408    private HTML.Tag JavaDoc getHTMLTag(AttributeSet htmlAttrSet) {
1409    Object JavaDoc o = htmlAttrSet.getAttribute(StyleConstants.NameAttribute);
1410    if (o instanceof HTML.Tag JavaDoc) {
1411        HTML.Tag JavaDoc tag = (HTML.Tag JavaDoc) o;
1412        return tag;
1413    }
1414    return null;
1415    }
1416
1417
1418    private boolean isHTMLFontTag(HTML.Tag JavaDoc tag) {
1419    return (tag != null && ((tag == HTML.Tag.FONT) || (tag == HTML.Tag.BASEFONT)));
1420    }
1421
1422
1423    private boolean isFloater(String JavaDoc alignValue) {
1424    return (alignValue.equals("left") || alignValue.equals("right"));
1425    }
1426
1427    private boolean validTextAlignValue(String JavaDoc alignValue) {
1428    return (isFloater(alignValue) || alignValue.equals("center"));
1429    }
1430
1431    /**
1432     * Base class to CSS values in the attribute sets. This
1433     * is intended to act as a convertor to/from other attribute
1434     * formats.
1435     * <p>
1436     * The CSS parser uses the parseCssValue method to convert
1437     * a string to whatever format is appropriate a given key
1438     * (i.e. these convertors are stored in a map using the
1439     * CSS.Attribute as a key and the CssValue as the value).
1440     * <p>
1441     * The HTML to CSS conversion process first converts the
1442     * HTML.Attribute to a CSS.Attribute, and then calls
1443     * the parseHtmlValue method on the value of the HTML
1444     * attribute to produce the corresponding CSS value.
1445     * <p>
1446     * The StyleConstants to CSS conversion process first
1447     * converts the StyleConstants attribute to a
1448     * CSS.Attribute, and then calls the fromStyleConstants
1449     * method to convert the StyleConstants value to a
1450     * CSS value.
1451     * <p>
1452     * The CSS to StyleConstants conversion process first
1453     * converts the StyleConstants attribute to a
1454     * CSS.Attribute, and then calls the toStyleConstants
1455     * method to convert the CSS value to a StyleConstants
1456     * value.
1457     */

1458    static class CssValue implements Serializable {
1459
1460    /**
1461     * Convert a CSS value string to the internal format
1462     * (for fast processing) used in the attribute sets.
1463     * The fallback storage for any value that we don't
1464     * have a special binary format for is a String.
1465     */

1466    Object JavaDoc parseCssValue(String JavaDoc value) {
1467        return value;
1468    }
1469
1470    /**
1471     * Convert an HTML attribute value to a CSS attribute
1472     * value. If there is no conversion, return null.
1473     * This is implemented to simply forward to the CSS
1474     * parsing by default (since some of the attribute
1475     * values are the same). If the attribute value
1476     * isn't recognized as a CSS value it is generally
1477     * returned as null.
1478     */

1479    Object JavaDoc parseHtmlValue(String JavaDoc value) {
1480        return parseCssValue(value);
1481    }
1482
1483    /**
1484     * Converts a <code>StyleConstants</code> attribute value to
1485     * a CSS attribute value. If there is no conversion,
1486     * returns <code>null</code>. By default, there is no conversion.
1487     *
1488     * @param key the <code>StyleConstants</code> attribute
1489     * @param value the value of a <code>StyleConstants</code>
1490         * attribute to be converted
1491     * @return the CSS value that represents the
1492         * <code>StyleConstants</code> value
1493     */

1494    Object JavaDoc fromStyleConstants(StyleConstants key, Object JavaDoc value) {
1495        return null;
1496    }
1497
1498    /**
1499     * Converts a CSS attribute value to a
1500         * <code>StyleConstants</code>
1501     * value. If there is no conversion, returns
1502         * <code>null</code>.
1503     * By default, there is no conversion.
1504     *
1505     * @param key the <code>StyleConstants</code> attribute
1506     * @param v the view containing <code>AttributeSet</code>
1507     * @return the <code>StyleConstants</code> attribute value that
1508     * represents the CSS attribute value
1509     */

1510    Object JavaDoc toStyleConstants(StyleConstants key, View v) {
1511        return null;
1512    }
1513
1514    /**
1515     * Return the CSS format of the value
1516     */

1517        public String JavaDoc toString() {
1518        return svalue;
1519    }
1520
1521    /**
1522     * The value as a string... before conversion to a
1523     * binary format.
1524     */

1525    String JavaDoc svalue;
1526    }
1527
1528    /**
1529     * By default CSS attributes are represented as simple
1530     * strings. They also have no conversion to/from
1531     * StyleConstants by default. This class represents the
1532     * value as a string (via the superclass), but
1533     * provides StyleConstants conversion support for the
1534     * CSS attributes that are held as strings.
1535     */

1536    static class StringValue extends CssValue {
1537
1538    /**
1539     * Convert a CSS value string to the internal format
1540     * (for fast processing) used in the attribute sets.
1541     * This produces a StringValue, so that it can be
1542     * used to convert from CSS to StyleConstants values.
1543     */

1544    Object JavaDoc parseCssValue(String JavaDoc value) {
1545        StringValue sv = new StringValue();
1546        sv.svalue = value;
1547        return sv;
1548    }
1549
1550    /**
1551     * Converts a <code>StyleConstants</code> attribute value to
1552     * a CSS attribute value. If there is no conversion
1553     * returns <code>null</code>.
1554     *
1555     * @param key the <code>StyleConstants</code> attribute
1556     * @param value the value of a <code>StyleConstants</code>
1557     * attribute to be converted
1558     * @return the CSS value that represents the
1559         * <code>StyleConstants</code> value
1560     */

1561    Object JavaDoc fromStyleConstants(StyleConstants key, Object JavaDoc value) {
1562        if (key == StyleConstants.Italic) {
1563        if (value.equals(Boolean.TRUE)) {
1564            return parseCssValue("italic");
1565        }
1566        return parseCssValue("");
1567        } else if (key == StyleConstants.Underline) {
1568        if (value.equals(Boolean.TRUE)) {
1569            return parseCssValue("underline");
1570        }
1571        return parseCssValue("");
1572        } else if (key == StyleConstants.Alignment) {
1573        int align = ((Integer JavaDoc)value).intValue();
1574        String JavaDoc ta;
1575        switch(align) {
1576        case StyleConstants.ALIGN_LEFT:
1577            ta = "left";
1578            break;
1579        case StyleConstants.ALIGN_RIGHT:
1580            ta = "right";
1581            break;
1582        case StyleConstants.ALIGN_CENTER:
1583            ta = "center";
1584            break;
1585        case StyleConstants.ALIGN_JUSTIFIED:
1586            ta = "justify";
1587            break;
1588        default:
1589            ta = "left";
1590        }
1591        return parseCssValue(ta);
1592        } else if (key == StyleConstants.StrikeThrough) {
1593        if (value.equals(Boolean.TRUE)) {
1594            return parseCssValue("line-through");
1595        }
1596        return parseCssValue("");
1597        } else if (key == StyleConstants.Superscript) {
1598        if (value.equals(Boolean.TRUE)) {
1599            return parseCssValue("super");
1600        }
1601        return parseCssValue("");
1602        } else if (key == StyleConstants.Subscript) {
1603        if (value.equals(Boolean.TRUE)) {
1604            return parseCssValue("sub");
1605        }
1606        return parseCssValue("");
1607        }
1608        return null;
1609    }
1610
1611    /**
1612     * Converts a CSS attribute value to a
1613         * <code>StyleConstants</code> value.
1614         * If there is no conversion, returns <code>null</code>.
1615     * By default, there is no conversion.
1616     *
1617     * @param key the <code>StyleConstants</code> attribute
1618     * @return the <code>StyleConstants</code> attribute value that
1619     * represents the CSS attribute value
1620     */

1621    Object JavaDoc toStyleConstants(StyleConstants key, View v) {
1622        if (key == StyleConstants.Italic) {
1623        if (svalue.indexOf("italic") >= 0) {
1624            return Boolean.TRUE;
1625        }
1626        return Boolean.FALSE;
1627        } else if (key == StyleConstants.Underline) {
1628        if (svalue.indexOf("underline") >= 0) {
1629            return Boolean.TRUE;
1630        }
1631        return Boolean.FALSE;
1632        } else if (key == StyleConstants.Alignment) {
1633        if (svalue.equals("right")) {
1634            return new Integer JavaDoc(StyleConstants.ALIGN_RIGHT);
1635        } else if (svalue.equals("center")) {
1636            return new Integer JavaDoc(StyleConstants.ALIGN_CENTER);
1637        } else if (svalue.equals("justify")) {
1638            return new Integer JavaDoc(StyleConstants.ALIGN_JUSTIFIED);
1639        }
1640        return new Integer JavaDoc(StyleConstants.ALIGN_LEFT);
1641        } else if (key == StyleConstants.StrikeThrough) {
1642        if (svalue.indexOf("line-through") >= 0) {
1643            return Boolean.TRUE;
1644        }
1645        return Boolean.FALSE;
1646        } else if (key == StyleConstants.Superscript) {
1647        if (svalue.indexOf("super") >= 0) {
1648            return Boolean.TRUE;
1649        }
1650        return Boolean.FALSE;
1651        } else if (key == StyleConstants.Subscript) {
1652        if (svalue.indexOf("sub") >= 0) {
1653            return Boolean.TRUE;
1654        }
1655        return Boolean.FALSE;
1656        }
1657        return null;
1658    }
1659
1660    // Used by ViewAttributeSet
1661
boolean isItalic() {
1662        return (svalue.indexOf("italic") != -1);
1663    }
1664
1665    boolean isStrike() {
1666        return (svalue.indexOf("line-through") != -1);
1667    }
1668
1669    boolean isUnderline() {
1670        return (svalue.indexOf("underline") != -1);
1671    }
1672
1673    boolean isSub() {
1674        return (svalue.indexOf("sub") != -1);
1675    }
1676
1677    boolean isSup() {
1678        return (svalue.indexOf("sup") != -1);
1679    }
1680    }
1681
1682    /**
1683     * Represents a value for the CSS.FONT_SIZE attribute.
1684     * The binary format of the value can be one of several
1685     * types. If the type is Float,
1686     * the value is specified in terms of point or
1687     * percentage, depending upon the ending of the
1688     * associated string.
1689     * If the type is Integer, the value is specified
1690     * in terms of a size index.
1691     */

1692    class FontSize extends CssValue {
1693
1694    /**
1695     * Returns the size in points. This is ultimately
1696     * what we need for the purpose of creating/fetching
1697     * a Font object.
1698     *
1699     * @param a the attribute set the value is being
1700     * requested from. We may need to walk up the
1701     * resolve hierarchy if it's relative.
1702     */

1703    float getValue(AttributeSet a, StyleSheet JavaDoc ss) {
1704            ss = getStyleSheet(ss);
1705        if (index) {
1706        // it's an index, translate from size table
1707
return getPointSize((int) value, ss);
1708        }
1709        else if (lu == null) {
1710        return value;
1711        }
1712        else {
1713        if (lu.type == 0) {
1714                    boolean isW3CLengthUnits = (ss == null) ? false : ss.isW3CLengthUnits();
1715                    return lu.getValue(isW3CLengthUnits);
1716        }
1717        if (a != null) {
1718            AttributeSet resolveParent = a.getResolveParent();
1719
1720            if (resolveParent != null) {
1721            int pValue = StyleConstants.getFontSize(resolveParent);
1722
1723            float retValue;
1724            if (lu.type == 1 || lu.type == 3) {
1725                retValue = lu.value * (float)pValue;
1726            }
1727            else {
1728                retValue = lu.value + (float)pValue;
1729            }
1730            return retValue;
1731            }
1732        }
1733        // a is null, or no resolve parent.
1734
return 12;
1735        }
1736    }
1737
1738    Object JavaDoc parseCssValue(String JavaDoc value) {
1739        FontSize fs = new FontSize();
1740        fs.svalue = value;
1741        try {
1742        if (value.equals("xx-small")) {
1743            fs.value = 1;
1744            fs.index = true;
1745        } else if (value.equals("x-small")) {
1746            fs.value = 2;
1747            fs.index = true;
1748        } else if (value.equals("small")) {
1749            fs.value = 3;
1750            fs.index = true;
1751        } else if (value.equals("medium")) {
1752            fs.value = 4;
1753            fs.index = true;
1754        } else if (value.equals("large")) {
1755            fs.value = 5;
1756            fs.index = true;
1757        } else if (value.equals("x-large")) {
1758            fs.value = 6;
1759            fs.index = true;
1760        } else if (value.equals("xx-large")) {
1761            fs.value = 7;
1762            fs.index = true;
1763        } else {
1764            fs.lu = new LengthUnit(value, (short)1, 1f);
1765        }
1766        // relative sizes, larger | smaller (adjust from parent by
1767
// 1.5 pixels)
1768
// em, ex refer to parent sizes
1769
// lengths: pt, mm, cm, pc, in, px
1770
// em (font height 3em would be 3 times font height)
1771
// ex (height of X)
1772
// lengths are (+/-) followed by a number and two letter
1773
// unit identifier
1774
} catch (NumberFormatException JavaDoc nfe) {
1775        fs = null;
1776        }
1777        return fs;
1778    }
1779
1780    Object JavaDoc parseHtmlValue(String JavaDoc value) {
1781        FontSize fs = new FontSize();
1782        fs.svalue = value;
1783
1784        try {
1785        /*
1786         * relative sizes in the size attribute are relative
1787         * to the <basefont>'s size.
1788         */

1789        int baseFontSize = getBaseFontSize();
1790        if ((value != null) && (value.charAt(0) == '+')) {
1791            int relSize = Integer.valueOf(value.substring(1)).intValue();
1792            fs.value = baseFontSize + relSize;
1793            fs.index = true;
1794        } else if ((value != null) && (value.charAt(0) == '-')) {
1795            int relSize = -Integer.valueOf(value.substring(1)).intValue();
1796            fs.value = baseFontSize + relSize;
1797            fs.index = true;
1798        } else {
1799            fs.value = Integer.parseInt(value);
1800            if (fs.value > 7) {
1801            fs.value = 7;
1802            } else if (fs.value < 0) {
1803            fs.value = 0;
1804            }
1805            fs.index = true;
1806        }
1807
1808        } catch (NumberFormatException JavaDoc nfe) {
1809        fs = null;
1810        }
1811        return fs;
1812    }
1813
1814    /**
1815     * Converts a <code>StyleConstants</code> attribute value to
1816     * a CSS attribute value. If there is no conversion
1817     * returns <code>null</code>. By default, there is no conversion.
1818     *
1819     * @param key the <code>StyleConstants</code> attribute
1820     * @param value the value of a <code>StyleConstants</code>
1821     * attribute to be converted
1822     * @return the CSS value that represents the
1823         * <code>StyleConstants</code> value
1824     */

1825    Object JavaDoc fromStyleConstants(StyleConstants key, Object JavaDoc value) {
1826            if (value instanceof Number JavaDoc) {
1827                FontSize fs = new FontSize();
1828
1829                fs.value = getIndexOfSize(((Number JavaDoc)value).floatValue(), StyleSheet.sizeMapDefault);
1830                fs.svalue = Integer.toString((int)fs.value);
1831                fs.index = true;
1832                return fs;
1833            }
1834            return parseCssValue(value.toString());
1835    }
1836
1837    /**
1838     * Converts a CSS attribute value to a <code>StyleConstants</code>
1839     * value. If there is no conversion, returns <code>null</code>.
1840     * By default, there is no conversion.
1841     *
1842     * @param key the <code>StyleConstants</code> attribute
1843     * @return the <code>StyleConstants</code> attribute value that
1844     * represents the CSS attribute value
1845     */

1846    Object JavaDoc toStyleConstants(StyleConstants key, View v) {
1847        if (v != null) {
1848        return new Integer JavaDoc((int) getValue(v.getAttributes(), null));
1849        }
1850        return new Integer JavaDoc((int) getValue(null, null));
1851    }
1852
1853    float value;
1854    boolean index;
1855    LengthUnit lu;
1856    }
1857
1858    static class FontFamily extends CssValue {
1859
1860    /**
1861         * Returns the font family to use.
1862     */

1863    String JavaDoc getValue() {
1864        return family;
1865    }
1866
1867    Object JavaDoc parseCssValue(String JavaDoc value) {
1868        int cIndex = value.indexOf(',');
1869        FontFamily ff = new FontFamily();
1870        ff.svalue = value;
1871        ff.family = null;
1872
1873        if (cIndex == -1) {
1874        setFontName(ff, value);
1875        }
1876        else {
1877        boolean done = false;
1878        int lastIndex;
1879        int length = value.length();
1880        cIndex = 0;
1881        while (!done) {
1882            // skip ws.
1883
while (cIndex < length &&
1884               Character.isWhitespace(value.charAt(cIndex)))
1885            cIndex++;
1886            // Find next ','
1887
lastIndex = cIndex;
1888            cIndex = value.indexOf(',', cIndex);
1889            if (cIndex == -1) {
1890            cIndex = length;
1891            }
1892            if (lastIndex < length) {
1893            if (lastIndex != cIndex) {
1894                int lastCharIndex = cIndex;
1895                if (cIndex > 0 && value.charAt(cIndex - 1) == ' '){
1896                lastCharIndex--;
1897                }
1898                setFontName(ff, value.substring
1899                    (lastIndex, lastCharIndex));
1900                done = (ff.family != null);
1901            }
1902            cIndex++;
1903            }
1904            else {
1905            done = true;
1906            }
1907        }
1908        }
1909        if (ff.family == null) {
1910        ff.family = "SansSerif";
1911        }
1912        return ff;
1913    }
1914
1915    private void setFontName(FontFamily ff, String JavaDoc fontName) {
1916            ff.family = fontName;
1917        }
1918
1919    Object JavaDoc parseHtmlValue(String JavaDoc value) {
1920        // TBD
1921
return parseCssValue(value);
1922    }
1923
1924    /**
1925     * Converts a <code>StyleConstants</code> attribute value to
1926     * a CSS attribute value. If there is no conversion
1927     * returns <code>null</code>. By default, there is no conversion.
1928     *
1929     * @param key the <code>StyleConstants</code> attribute
1930     * @param value the value of a <code>StyleConstants</code>
1931     * attribute to be converted
1932     * @return the CSS value that represents the
1933         * <code>StyleConstants</code> value
1934     */

1935    Object JavaDoc fromStyleConstants(StyleConstants key, Object JavaDoc value) {
1936        return parseCssValue(value.toString());
1937    }
1938
1939    /**
1940     * Converts a CSS attribute value to a <code>StyleConstants</code>
1941     * value. If there is no conversion, returns <code>null</code>.
1942     * By default, there is no conversion.
1943     *
1944     * @param key the <code>StyleConstants</code> attribute
1945     * @return the <code>StyleConstants</code> attribute value that
1946     * represents the CSS attribute value
1947     */

1948    Object JavaDoc toStyleConstants(StyleConstants key, View v) {
1949        return family;
1950    }
1951
1952    String JavaDoc family;
1953    }
1954
1955    static class FontWeight extends CssValue {
1956
1957    int getValue() {
1958        return weight;
1959    }
1960
1961    Object JavaDoc parseCssValue(String JavaDoc value) {
1962        FontWeight fw = new FontWeight();
1963        fw.svalue = value;
1964        if (value.equals("bold")) {
1965        fw.weight = 700;
1966        } else if (value.equals("normal")) {
1967        fw.weight = 400;
1968        } else {
1969        // PENDING(prinz) add support for relative values
1970
try {
1971            fw.weight = Integer.parseInt(value);
1972        } catch (NumberFormatException JavaDoc nfe) {
1973            fw = null;
1974        }
1975        }
1976        return fw;
1977    }
1978
1979    /**
1980     * Converts a <code>StyleConstants</code> attribute value to
1981     * a CSS attribute value. If there is no conversion
1982     * returns <code>null</code>. By default, there is no conversion.
1983     *
1984     * @param key the <code>StyleConstants</code> attribute
1985     * @param value the value of a <code>StyleConstants</code>
1986     * attribute to be converted
1987     * @return the CSS value that represents the
1988         * <code>StyleConstants</code> value
1989     */

1990    Object JavaDoc fromStyleConstants(StyleConstants key, Object JavaDoc value) {
1991        if (value.equals(Boolean.TRUE)) {
1992        return parseCssValue("bold");
1993        }
1994        return parseCssValue("normal");
1995    }
1996
1997    /**
1998     * Converts a CSS attribute value to a <code>StyleConstants</code>
1999     * value. If there is no conversion, returns <code>null</code>.
2000     * By default, there is no conversion.
2001     *
2002     * @param key the <code>StyleConstants</code> attribute
2003     * @return the <code>StyleConstants</code> attribute value that
2004     * represents the CSS attribute value
2005     */

2006    Object JavaDoc toStyleConstants(StyleConstants key, View v) {
2007        return (weight > 500) ? Boolean.TRUE : Boolean.FALSE;
2008    }
2009
2010    boolean isBold() {
2011        return (weight > 500);
2012    }
2013
2014    int weight;
2015    }
2016
2017    static class ColorValue extends CssValue {
2018
2019    /**
2020     * Returns the color to use.
2021     */

2022    Color JavaDoc getValue() {
2023        return c;
2024    }
2025
2026    Object JavaDoc parseCssValue(String JavaDoc value) {
2027
2028        Color JavaDoc c = stringToColor(value);
2029        if (c != null) {
2030        ColorValue cv = new ColorValue();
2031        cv.svalue = value;
2032        cv.c = c;
2033        return cv;
2034        }
2035        return null;
2036    }
2037
2038    Object JavaDoc parseHtmlValue(String JavaDoc value) {
2039        return parseCssValue(value);
2040    }
2041
2042    /**
2043     * Converts a <code>StyleConstants</code> attribute value to
2044     * a CSS attribute value. If there is no conversion
2045     * returns <code>null</code>. By default, there is no conversion.
2046     *
2047     * @param key the <code>StyleConstants</code> attribute
2048     * @param value the value of a <code>StyleConstants</code>
2049     * attribute to be converted
2050     * @return the CSS value that represents the
2051         * <code>StyleConstants</code> value
2052     */

2053    Object JavaDoc fromStyleConstants(StyleConstants key, Object JavaDoc value) {
2054        ColorValue colorValue = new ColorValue();
2055        colorValue.c = (Color JavaDoc)value;
2056        colorValue.svalue = colorToHex(colorValue.c);
2057        return colorValue;
2058    }
2059
2060    /**
2061     * Converts a CSS attribute value to a <code>StyleConstants</code>
2062     * value. If there is no conversion, returns <code>null</code>.
2063     * By default, there is no conversion.
2064     *
2065     * @param key the <code>StyleConstants</code> attribute
2066     * @return the <code>StyleConstants</code> attribute value that
2067     * represents the CSS attribute value
2068     */

2069    Object JavaDoc toStyleConstants(StyleConstants key, View v) {
2070        return c;
2071    }
2072
2073    Color JavaDoc c;
2074    }
2075
2076    static class BorderStyle extends CssValue {
2077
2078    CSS.Value JavaDoc getValue() {
2079        return style;
2080    }
2081
2082    Object JavaDoc parseCssValue(String JavaDoc value) {
2083        CSS.Value JavaDoc cssv = CSS.getValue(value);
2084        if (cssv != null) {
2085        if ((cssv == CSS.Value.INSET) ||
2086            (cssv == CSS.Value.OUTSET) ||
2087            (cssv == CSS.Value.NONE) ||
2088            (cssv == CSS.Value.DOTTED) ||
2089            (cssv == CSS.Value.DASHED) ||
2090            (cssv == CSS.Value.SOLID) ||
2091            (cssv == CSS.Value.DOUBLE) ||
2092            (cssv == CSS.Value.GROOVE) ||
2093            (cssv == CSS.Value.RIDGE)) {
2094
2095            BorderStyle bs = new BorderStyle();
2096            bs.svalue = value;
2097            bs.style = cssv;
2098            return bs;
2099        }
2100        }
2101        return null;
2102    }
2103
2104    private void writeObject(java.io.ObjectOutputStream JavaDoc s)
2105                 throws IOException {
2106        s.defaultWriteObject();
2107        if (style == null) {
2108        s.writeObject(null);
2109        }
2110        else {
2111        s.writeObject(style.toString());
2112        }
2113    }
2114
2115    private void readObject(ObjectInputStream s)
2116        throws ClassNotFoundException JavaDoc, IOException {
2117        s.defaultReadObject();
2118        Object JavaDoc value = s.readObject();
2119        if (value != null) {
2120        style = CSS.getValue((String JavaDoc)value);
2121        }
2122    }
2123
2124    // CSS.Values are static, don't archive it.
2125
transient private CSS.Value JavaDoc style;
2126    }
2127
2128    static class LengthValue extends CssValue {
2129
2130        /**
2131     * if this length value may be negative.
2132     */

2133    boolean mayBeNegative;
2134
2135    LengthValue() {
2136        this(false);
2137    }
2138
2139    LengthValue(boolean mayBeNegative) {
2140        this.mayBeNegative = mayBeNegative;
2141    }
2142
2143    /**
2144     * Returns the length (span) to use.
2145     */

2146        float getValue() {
2147            return getValue(false);
2148        }
2149
2150    float getValue(boolean isW3CLengthUnits) {
2151        return getValue(0, isW3CLengthUnits);
2152    }
2153        
2154    /**
2155     * Returns the length (span) to use. If the value represents
2156     * a percentage, it is scaled based on <code>currentValue</code>.
2157     */

2158    float getValue(float currentValue) {
2159            return getValue(currentValue, false);
2160        }
2161    float getValue(float currentValue, boolean isW3CLengthUnits) {
2162        if (percentage) {
2163        return span * currentValue;
2164        }
2165        return LengthUnit.getValue(span, units, isW3CLengthUnits);
2166    }
2167
2168    /**
2169     * Returns true if the length represents a percentage of the
2170     * containing box.
2171     */

2172    boolean isPercentage() {
2173        return percentage;
2174    }
2175
2176    Object JavaDoc parseCssValue(String JavaDoc value) {
2177        LengthValue lv;
2178        try {
2179        // Assume pixels
2180
float absolute = Float.valueOf(value).floatValue();
2181        lv = new LengthValue();
2182        lv.span = absolute;
2183        } catch (NumberFormatException JavaDoc nfe) {
2184        // Not pixels, use LengthUnit
2185
LengthUnit lu = new LengthUnit(value,
2186                           LengthUnit.UNINITALIZED_LENGTH,
2187                           0);
2188
2189        // PENDING: currently, we only support absolute values and
2190
// percentages.
2191
switch (lu.type) {
2192        case 0:
2193            // Absolute
2194
lv = new LengthValue();
2195            lv.span =
2196            (mayBeNegative) ? lu.value : Math.max(0, lu.value);
2197                    lv.units = lu.units;
2198            break;
2199        case 1:
2200            // %
2201
lv = new LengthValue();
2202            lv.span = Math.max(0, Math.min(1, lu.value));
2203            lv.percentage = true;
2204            break;
2205        default:
2206            return null;
2207        }
2208        }
2209        lv.svalue = value;
2210        return lv;
2211    }
2212
2213    Object JavaDoc parseHtmlValue(String JavaDoc value) {
2214        if (value.equals(HTML.NULL_ATTRIBUTE_VALUE)) {
2215        value = "1";
2216        }
2217        return parseCssValue(value);
2218    }
2219    /**
2220     * Converts a <code>StyleConstants</code> attribute value to
2221     * a CSS attribute value. If there is no conversion,
2222     * returns <code>null</code>. By default, there is no conversion.
2223     *
2224     * @param key the <code>StyleConstants</code> attribute
2225     * @param value the value of a <code>StyleConstants</code>
2226     * attribute to be converted
2227     * @return the CSS value that represents the
2228         * <code>StyleConstants</code> value
2229     */

2230    Object JavaDoc fromStyleConstants(StyleConstants key, Object JavaDoc value) {
2231        LengthValue v = new LengthValue();
2232        v.svalue = value.toString();
2233        v.span = ((Float JavaDoc)value).floatValue();
2234        return v;
2235    }
2236
2237    /**
2238     * Converts a CSS attribute value to a <code>StyleConstants</code>
2239     * value. If there is no conversion, returns <code>null</code>.
2240     * By default, there is no conversion.
2241     *
2242     * @param key the <code>StyleConstants</code> attribute
2243     * @return the <code>StyleConstants</code> attribute value that
2244     * represents the CSS attribute value
2245     */

2246    Object JavaDoc toStyleConstants(StyleConstants key, View v) {
2247        return new Float JavaDoc(getValue(false));
2248    }
2249
2250    /** If true, span is a percentage value, and that to determine
2251     * the length another value needs to be passed in. */

2252    boolean percentage;
2253    /** Either the absolute value (percentage == false) or
2254     * a percentage value. */

2255    float span;
2256
2257        String JavaDoc units = null;
2258    }
2259
2260
2261    /**
2262     * BorderWidthValue is used to model BORDER_XXX_WIDTH and adds support
2263     * for the thin/medium/thick values.
2264     */

2265    static class BorderWidthValue extends LengthValue {
2266    BorderWidthValue(String JavaDoc svalue, int index) {
2267        this.svalue = svalue;
2268            span = values[index];
2269            percentage = false;
2270    }
2271
2272    Object JavaDoc parseCssValue(String JavaDoc value) {
2273        if (value != null) {
2274        if (value.equals("thick")) {
2275            return new BorderWidthValue(value, 2);
2276        }
2277        else if (value.equals("medium")) {
2278            return new BorderWidthValue(value, 1);
2279        }
2280        else if (value.equals("thin")) {
2281            return new BorderWidthValue(value, 0);
2282        }
2283        }
2284        // Assume its a length.
2285
return super.parseCssValue(value);
2286    }
2287
2288    Object JavaDoc parseHtmlValue(String JavaDoc value) {
2289        if (value == HTML.NULL_ATTRIBUTE_VALUE) {
2290        return parseCssValue("medium");
2291        }
2292        return parseCssValue(value);
2293    }
2294
2295    /** Values used to represent border width. */
2296    private static final float[] values = { 1, 2, 4 };
2297   }
2298
2299
2300    /**
2301     * Handles uniquing of CSS values, like lists, and background image
2302     * repeating.
2303     */

2304    static class CssValueMapper extends CssValue {
2305    Object JavaDoc parseCssValue(String JavaDoc value) {
2306        Object JavaDoc retValue = cssValueToInternalValueMap.get(value);
2307        if (retValue == null) {
2308        retValue = cssValueToInternalValueMap.get(value.toLowerCase());
2309        }
2310        return retValue;
2311    }
2312
2313
2314    Object JavaDoc parseHtmlValue(String JavaDoc value) {
2315        Object JavaDoc retValue = htmlValueToCssValueMap.get(value);
2316        if (retValue == null) {
2317        retValue = htmlValueToCssValueMap.get(value.toLowerCase());
2318        }
2319        return retValue;
2320    }
2321    }
2322
2323
2324    /**
2325     * Used for background images, to represent the position.
2326     */

2327    static class BackgroundPosition extends CssValue {
2328    float horizontalPosition;
2329    float verticalPosition;
2330    // bitmask: bit 0, horizontal relative, bit 1 horizontal relative to
2331
// font size, 2 vertical relative to size, 3 vertical relative to
2332
// font size.
2333
//
2334
short relative;
2335
2336    Object JavaDoc parseCssValue(String JavaDoc value) {
2337        // 'top left' and 'left top' both mean the same as '0% 0%'.
2338
// 'top', 'top center' and 'center top' mean the same as '50% 0%'.
2339
// 'right top' and 'top right' mean the same as '100% 0%'.
2340
// 'left', 'left center' and 'center left' mean the same as
2341
// '0% 50%'.
2342
// 'center' and 'center center' mean the same as '50% 50%'.
2343
// 'right', 'right center' and 'center right' mean the same as
2344
// '100% 50%'.
2345
// 'bottom left' and 'left bottom' mean the same as '0% 100%'.
2346
// 'bottom', 'bottom center' and 'center bottom' mean the same as
2347
// '50% 100%'.
2348
// 'bottom right' and 'right bottom' mean the same as '100% 100%'.
2349
String JavaDoc[] strings = CSS.parseStrings(value);
2350        int count = strings.length;
2351        BackgroundPosition bp = new BackgroundPosition();
2352        bp.relative = 5;
2353        bp.svalue = value;
2354
2355        if (count > 0) {
2356        // bit 0 for vert, 1 hor, 2 for center
2357
short found = 0;
2358        int index = 0;
2359        while (index < count) {
2360            // First, check for keywords
2361
String JavaDoc string = strings[index++];
2362            if (string.equals("center")) {
2363            found |= 4;
2364            continue;
2365            }
2366            else {
2367            if ((found & 1) == 0) {
2368                if (string.equals("top")) {
2369                found |= 1;
2370                }
2371                else if (string.equals("bottom")) {
2372                found |= 1;
2373                bp.verticalPosition = 1;
2374                continue;
2375                }
2376            }
2377            if ((found & 2) == 0) {
2378                if (string.equals("left")) {
2379                found |= 2;
2380                bp.horizontalPosition = 0;
2381                }
2382                else if (string.equals("right")) {
2383                found |= 2;
2384                bp.horizontalPosition = 1;
2385                }
2386            }
2387            }
2388        }
2389        if (found != 0) {
2390            if ((found & 1) == 1) {
2391            if ((found & 2) == 0) {
2392                // vert and no horiz.
2393
bp.horizontalPosition = .5f;
2394            }
2395            }
2396            else if ((found & 2) == 2) {
2397            // horiz and no vert.
2398
bp.verticalPosition = .5f;
2399            }
2400            else {
2401            // no horiz, no vert, but center
2402
bp.horizontalPosition = bp.verticalPosition = .5f;
2403            }
2404        }
2405        else {
2406            // Assume lengths
2407
LengthUnit lu = new LengthUnit(strings[0], (short)0, 0f);
2408
2409            if (lu.type == 0) {
2410            bp.horizontalPosition = lu.value;
2411            bp.relative = (short)(1 ^ bp.relative);
2412            }
2413            else if (lu.type == 1) {
2414            bp.horizontalPosition = lu.value;
2415            }
2416            else if (lu.type == 3) {
2417            bp.horizontalPosition = lu.value;
2418            bp.relative = (short)((1 ^ bp.relative) | 2);
2419            }
2420            if (count > 1) {
2421            lu = new LengthUnit(strings[1], (short)0, 0f);
2422
2423            if (lu.type == 0) {
2424                bp.verticalPosition = lu.value;
2425                bp.relative = (short)(4 ^ bp.relative);
2426            }
2427            else if (lu.type == 1) {
2428                bp.verticalPosition = lu.value;
2429            }
2430            else if (lu.type == 3) {
2431                bp.verticalPosition = lu.value;
2432                bp.relative = (short)((4 ^ bp.relative) | 8);
2433            }
2434            }
2435            else {
2436            bp.verticalPosition = .5f;
2437            }
2438        }
2439        }
2440        return bp;
2441    }
2442
2443    boolean isHorizontalPositionRelativeToSize() {
2444        return ((relative & 1) == 1);
2445    }
2446
2447    boolean isHorizontalPositionRelativeToFontSize() {
2448        return ((relative & 2) == 2);
2449    }
2450
2451    float getHorizontalPosition() {
2452        return horizontalPosition;
2453    }
2454
2455    boolean isVerticalPositionRelativeToSize() {
2456        return ((relative & 4) == 4);
2457    }
2458
2459    boolean isVerticalPositionRelativeToFontSize() {
2460        return ((relative & 8) == 8);
2461    }
2462
2463    float getVerticalPosition() {
2464        return verticalPosition;
2465    }
2466    }
2467
2468
2469    /**
2470     * Used for BackgroundImages.
2471     */

2472    static class BackgroundImage extends CssValue {
2473    private boolean loadedImage;
2474    private ImageIcon JavaDoc image;
2475
2476    Object JavaDoc parseCssValue(String JavaDoc value) {
2477        BackgroundImage retValue = new BackgroundImage();
2478        retValue.svalue = value;
2479        return retValue;
2480    }
2481
2482    Object JavaDoc parseHtmlValue(String JavaDoc value) {
2483        return parseCssValue(value);
2484    }
2485
2486    // PENDING: this base is wrong for linked style sheets.
2487
ImageIcon JavaDoc getImage(URL JavaDoc base) {
2488        if (!loadedImage) {
2489        synchronized(this) {
2490            if (!loadedImage) {
2491            URL JavaDoc url = CSS.getURL(base, svalue);
2492            loadedImage = true;
2493            if (url != null) {
2494                image = new ImageIcon JavaDoc(url);
2495            }
2496            }
2497        }
2498        }
2499        return image;
2500    }
2501    }
2502
2503    /**
2504     * Parses a length value, this is used internally, and never added
2505     * to an AttributeSet or returned to the developer.
2506     */

2507    static class LengthUnit implements Serializable {
2508    static Hashtable JavaDoc lengthMapping = new Hashtable JavaDoc(6);
2509        static Hashtable JavaDoc w3cLengthMapping = new Hashtable JavaDoc(6);
2510    static {
2511            lengthMapping.put("pt", new Float JavaDoc(1f));
2512            // Not sure about 1.3, determined by experiementation.
2513
lengthMapping.put("px", new Float JavaDoc(1.3f));
2514            lengthMapping.put("mm", new Float JavaDoc(2.83464f));
2515            lengthMapping.put("cm", new Float JavaDoc(28.3464f));
2516            lengthMapping.put("pc", new Float JavaDoc(12f));
2517            lengthMapping.put("in", new Float JavaDoc(72f));
2518        int res = 72;
2519            try {
2520                res = Toolkit.getDefaultToolkit().getScreenResolution();
2521            } catch (HeadlessException JavaDoc e) {
2522            }
2523        // mapping according to the CSS2 spec
2524
w3cLengthMapping.put("pt", new Float JavaDoc(res/72f));
2525        w3cLengthMapping.put("px", new Float JavaDoc(1f));
2526        w3cLengthMapping.put("mm", new Float JavaDoc(res/25.4f));
2527        w3cLengthMapping.put("cm", new Float JavaDoc(res/2.54f));
2528        w3cLengthMapping.put("pc", new Float JavaDoc(res/6f));
2529        w3cLengthMapping.put("in", new Float JavaDoc(res));
2530    }
2531
2532    LengthUnit(String JavaDoc value, short defaultType, float defaultValue) {
2533        parse(value, defaultType, defaultValue);
2534    }
2535
2536    void parse(String JavaDoc value, short defaultType, float defaultValue) {
2537        type = defaultType;
2538        this.value = defaultValue;
2539
2540        int length = value.length();
2541        if (length > 0 && value.charAt(length - 1) == '%') {
2542        try {
2543            this.value = Float.valueOf(value.substring(0, length - 1)).
2544                                   floatValue() / 100.0f;
2545            type = 1;
2546        }
2547        catch (NumberFormatException JavaDoc nfe) { }
2548        }
2549        if (length >= 2) {
2550        units = value.substring(length - 2, length);
2551        Float JavaDoc scale = (Float JavaDoc)lengthMapping.get(units);
2552        if (scale != null) {
2553            try {
2554            this.value = Float.valueOf(value.substring(0,
2555                               length - 2)).floatValue();
2556            type = 0;
2557            }
2558            catch (NumberFormatException JavaDoc nfe) { }
2559        }
2560        else if (units.equals("em") ||
2561             units.equals("ex")) {
2562            try {
2563            this.value = Float.valueOf(value.substring(0,
2564                      length - 2)).floatValue();
2565            type = 3;
2566            }
2567            catch (NumberFormatException JavaDoc nfe) { }
2568        }
2569        else if (value.equals("larger")) {
2570            this.value = 2f;
2571            type = 2;
2572        }
2573        else if (value.equals("smaller")) {
2574            this.value = -2;
2575            type = 2;
2576        }
2577        else {
2578            // treat like points.
2579
try {
2580            this.value = Float.valueOf(value).floatValue();
2581            type = 0;
2582            } catch (NumberFormatException JavaDoc nfe) {}
2583        }
2584        }
2585            else if (length > 0) {
2586                // treat like points.
2587
try {
2588                    this.value = Float.valueOf(value).floatValue();
2589                    type = 0;
2590                } catch (NumberFormatException JavaDoc nfe) {}
2591            }
2592    }
2593
2594        float getValue(boolean w3cLengthUnits) {
2595            Hashtable JavaDoc mapping = (w3cLengthUnits) ? w3cLengthMapping : lengthMapping;
2596            float scale = 1;
2597            if (units != null) {
2598                Float JavaDoc scaleFloat = (Float JavaDoc)mapping.get(units);
2599                if (scaleFloat != null) {
2600                    scale = scaleFloat.floatValue();
2601                }
2602            }
2603            return this.value * scale;
2604            
2605        }
2606        
2607        static float getValue(float value, String JavaDoc units, Boolean JavaDoc w3cLengthUnits) {
2608            Hashtable JavaDoc mapping = (w3cLengthUnits) ? w3cLengthMapping : lengthMapping;
2609            float scale = 1;
2610            if (units != null) {
2611                Float JavaDoc scaleFloat = (Float JavaDoc)mapping.get(units);
2612                if (scaleFloat != null) {
2613                    scale = scaleFloat.floatValue();
2614                }
2615            }
2616            return value * scale;
2617        }
2618        
2619    public String JavaDoc toString() {
2620        return type + " " + value;
2621    }
2622
2623    // 0 - value indicates real value
2624
// 1 - % value, value relative to depends upon key.
2625
// 50% will have a value = .5
2626
// 2 - add value to parent value.
2627
// 3 - em/ex relative to font size of element (except for
2628
// font-size, which is relative to parent).
2629
short type;
2630    float value;
2631        String JavaDoc units = null;
2632        
2633
2634    static final short UNINITALIZED_LENGTH = (short)10;
2635    }
2636
2637
2638    /**
2639     * Class used to parse font property. The font property is shorthand
2640     * for the other font properties. This expands the properties, placing
2641     * them in the attributeset.
2642     */

2643    static class ShorthandFontParser {
2644    /**
2645     * Parses the shorthand font string <code>value</code>, placing the
2646     * result in <code>attr</code>.
2647     */

2648    static void parseShorthandFont(CSS JavaDoc css, String JavaDoc value,
2649                       MutableAttributeSet attr) {
2650        // font is of the form:
2651
// [ <font-style> || <font-variant> || <font-weight> ]? <font-size>
2652
// [ / <line-height> ]? <font-family>
2653
String JavaDoc[] strings = CSS.parseStrings(value);
2654        int count = strings.length;
2655        int index = 0;
2656        // bitmask, 1 for style, 2 for variant, 3 for weight
2657
short found = 0;
2658        int maxC = Math.min(3, count);
2659
2660        // Check for font-style font-variant font-weight
2661
while (index < maxC) {
2662        if ((found & 1) == 0 && isFontStyle(strings[index])) {
2663            css.addInternalCSSValue(attr, CSS.Attribute.FONT_STYLE,
2664                        strings[index++]);
2665            found |= 1;
2666        }
2667        else if ((found & 2) == 0 && isFontVariant(strings[index])) {
2668            css.addInternalCSSValue(attr, CSS.Attribute.FONT_VARIANT,
2669                        strings[index++]);
2670            found |= 2;
2671        }
2672        else if ((found & 4) == 0 && isFontWeight(strings[index])) {
2673            css.addInternalCSSValue(attr, CSS.Attribute.FONT_WEIGHT,
2674                        strings[index++]);
2675            found |= 4;
2676        }
2677        else if (strings[index].equals("normal")) {
2678            index++;
2679        }
2680        else {
2681            break;
2682        }
2683        }
2684        if ((found & 1) == 0) {
2685        css.addInternalCSSValue(attr, CSS.Attribute.FONT_STYLE,
2686                    "normal");
2687        }
2688        if ((found & 2) == 0) {
2689        css.addInternalCSSValue(attr, CSS.Attribute.FONT_VARIANT,
2690                    "normal");
2691        }
2692        if ((found & 4) == 0) {
2693        css.addInternalCSSValue(attr, CSS.Attribute.FONT_WEIGHT,
2694                    "normal");
2695        }
2696
2697        // string at index should be the font-size
2698
if (index < count) {
2699        String JavaDoc fontSize = strings[index];
2700        int slashIndex = fontSize.indexOf('/');
2701
2702        if (slashIndex != -1) {
2703            fontSize = fontSize.substring(0, slashIndex);
2704            strings[index] = strings[index].substring(slashIndex);
2705        }
2706        else {
2707            index++;
2708        }
2709        css.addInternalCSSValue(attr, CSS.Attribute.FONT_SIZE,
2710                    fontSize);
2711        }
2712        else {
2713        css.addInternalCSSValue(attr, CSS.Attribute.FONT_SIZE,
2714                    "medium");
2715        }
2716
2717        // Check for line height
2718
if (index < count && strings[index].startsWith("/")) {
2719        String JavaDoc lineHeight = null;
2720        if (strings[index].equals("/")) {
2721            if (++index < count) {
2722            lineHeight = strings[index++];
2723            }
2724        }
2725        else {
2726            lineHeight = strings[index++].substring(1);
2727        }
2728        // line height
2729
if (lineHeight != null) {
2730            css.addInternalCSSValue(attr, CSS.Attribute.LINE_HEIGHT,
2731                        lineHeight);
2732        }
2733        else {
2734            css.addInternalCSSValue(attr, CSS.Attribute.LINE_HEIGHT,
2735                        "normal");
2736        }
2737        }
2738        else {
2739        css.addInternalCSSValue(attr, CSS.Attribute.LINE_HEIGHT,
2740                    "normal");
2741        }
2742
2743        // remainder of strings are font-family
2744
if (index < count) {
2745        String JavaDoc family = strings[index++];
2746
2747        while (index < count) {
2748            family += " " + strings[index++];
2749        }
2750        css.addInternalCSSValue(attr, CSS.Attribute.FONT_FAMILY,
2751                    family);
2752        }
2753        else {
2754        css.addInternalCSSValue(attr, CSS.Attribute.FONT_FAMILY,
2755                    "SansSerif");
2756        }
2757    }
2758
2759    private static boolean isFontStyle(String JavaDoc string) {
2760        return (string.equals("italic") ||
2761            string.equals("oblique"));
2762    }
2763
2764    private static boolean isFontVariant(String JavaDoc string) {
2765        return (string.equals("small-caps"));
2766    }
2767
2768    private static boolean isFontWeight(String JavaDoc string) {
2769        if (string.equals("bold") || string.equals("bolder") ||
2770        string.equals("italic") || string.equals("lighter")) {
2771        return true;
2772        }
2773        // test for 100-900
2774
return (string.length() == 3 &&
2775            string.charAt(0) >= '1' && string.charAt(0) <= '9' &&
2776            string.charAt(1) == '0' && string.charAt(2) == '0');
2777    }
2778
2779    }
2780
2781
2782    /**
2783     * Parses the background property into its intrinsic values.
2784     */

2785    static class ShorthandBackgroundParser {
2786    /**
2787     * Parses the shorthand font string <code>value</code>, placing the
2788     * result in <code>attr</code>.
2789     */

2790    static void parseShorthandBackground(CSS JavaDoc css, String JavaDoc value,
2791                         MutableAttributeSet attr) {
2792        String JavaDoc[] strings = parseStrings(value);
2793        int count = strings.length;
2794        int index = 0;
2795        // bitmask: 0 for image, 1 repeat, 2 attachment, 3 position,
2796
// 4 color
2797
short found = 0;
2798
2799        while (index < count) {
2800        String JavaDoc string = strings[index++];
2801        if ((found & 1) == 0 && isImage(string)) {
2802            css.addInternalCSSValue(attr, CSS.Attribute.
2803                        BACKGROUND_IMAGE, string);
2804            found |= 1;
2805        }
2806        else if ((found & 2) == 0 && isRepeat(string)) {
2807            css.addInternalCSSValue(attr, CSS.Attribute.
2808                        BACKGROUND_REPEAT, string);
2809            found |= 2;
2810        }
2811        else if ((found & 4) == 0 && isAttachment(string)) {
2812            css.addInternalCSSValue(attr, CSS.Attribute.
2813                        BACKGROUND_ATTACHMENT, string);
2814            found |= 4;
2815        }
2816        else if ((found & 8) == 0 && isPosition(string)) {
2817            if (index < count && isPosition(strings[index])) {
2818            css.addInternalCSSValue(attr, CSS.Attribute.
2819                        BACKGROUND_POSITION,
2820                        string + " " +
2821                        strings[index++]);
2822            }
2823            else {
2824            css.addInternalCSSValue(attr, CSS.Attribute.
2825                        BACKGROUND_POSITION, string);
2826            }
2827            found |= 8;
2828        }
2829        else if ((found & 16) == 0 && isColor(string)) {
2830            css.addInternalCSSValue(attr, CSS.Attribute.
2831                        BACKGROUND_COLOR, string);
2832            found |= 16;
2833        }
2834        }
2835        if ((found & 1) == 0) {
2836        css.addInternalCSSValue(attr, CSS.Attribute.BACKGROUND_IMAGE,
2837                    null);
2838        }
2839        if ((found & 2) == 0) {
2840        css.addInternalCSSValue(attr, CSS.Attribute.BACKGROUND_REPEAT,
2841                    "repeat");
2842        }
2843        if ((found & 4) == 0) {
2844        css.addInternalCSSValue(attr, CSS.Attribute.
2845                    BACKGROUND_ATTACHMENT, "scroll");
2846        }
2847        if ((found & 8) == 0) {
2848        css.addInternalCSSValue(attr, CSS.Attribute.
2849                    BACKGROUND_POSITION, null);
2850        }
2851        // Currently, there is no good way to express this.
2852
/*
2853        if ((found & 16) == 0) {
2854        css.addInternalCSSValue(attr, CSS.Attribute.BACKGROUND_COLOR,
2855                    null);
2856        }
2857        */

2858    }
2859
2860    static boolean isImage(String JavaDoc string) {
2861        return (string.startsWith("url(") && string.endsWith(")"));
2862    }
2863
2864    static boolean isRepeat(String JavaDoc string) {
2865        return (string.equals("repeat-x") || string.equals("repeat-y") ||
2866            string.equals("repeat") || string.equals("no-repeat"));
2867    }
2868
2869    static boolean isAttachment(String JavaDoc string) {
2870        return (string.equals("fixed") || string.equals("scroll"));
2871    }
2872
2873    static boolean isPosition(String JavaDoc string) {
2874        return (string.equals("top") || string.equals("bottom") ||
2875            string.equals("left") || string.equals("right") ||
2876            string.equals("center") ||
2877            (string.length() > 0 &&
2878             Character.isDigit(string.charAt(0))));
2879    }
2880
2881    static boolean isColor(String JavaDoc string) {
2882        return (CSS.stringToColor(string) != null);
2883    }
2884    }
2885
2886
2887    /**
2888     * Used to parser margin and padding.
2889     */

2890    static class ShorthandMarginParser {
2891    /**
2892     * Parses the shorthand margin/padding/border string
2893     * <code>value</code>, placing the result in <code>attr</code>.
2894     * <code>names</code> give the 4 instrinsic property names.
2895     */

2896    static void parseShorthandMargin(CSS JavaDoc css, String JavaDoc value,
2897                     MutableAttributeSet attr,
2898                     CSS.Attribute JavaDoc[] names) {
2899        String JavaDoc[] strings = parseStrings(value);
2900        int count = strings.length;
2901        int index = 0;
2902        switch (count) {
2903        case 0:
2904        // empty string
2905
return;
2906        case 1:
2907        // Identifies all values.
2908
for (int counter = 0; counter < 4; counter++) {
2909            css.addInternalCSSValue(attr, names[counter], strings[0]);
2910        }
2911        break;
2912        case 2:
2913        // 0 & 2 = strings[0], 1 & 3 = strings[1]
2914
css.addInternalCSSValue(attr, names[0], strings[0]);
2915        css.addInternalCSSValue(attr, names[2], strings[0]);
2916        css.addInternalCSSValue(attr, names[1], strings[1]);
2917        css.addInternalCSSValue(attr, names[3], strings[1]);
2918        break;
2919        case 3:
2920        css.addInternalCSSValue(attr, names[0], strings[0]);
2921        css.addInternalCSSValue(attr, names[1], strings[1]);
2922        css.addInternalCSSValue(attr, names[2], strings[2]);
2923        css.addInternalCSSValue(attr, names[3], strings[1]);
2924        break;
2925        default:
2926        for (int counter = 0; counter < 4; counter++) {
2927            css.addInternalCSSValue(attr, names[counter],
2928                        strings[counter]);
2929        }
2930        break;
2931        }
2932    }
2933    }
2934
2935    /**
2936     * Calculate the requirements needed to tile the requirements
2937     * given by the iterator that would be tiled. The calculation
2938     * takes into consideration margin and border spacing.
2939     */

2940    static SizeRequirements JavaDoc calculateTiledRequirements(LayoutIterator iter, SizeRequirements JavaDoc r) {
2941    long minimum = 0;
2942    long maximum = 0;
2943    long preferred = 0;
2944    int lastMargin = 0;
2945    int totalSpacing = 0;
2946    int n = iter.getCount();
2947    for (int i = 0; i < n; i++) {
2948        iter.setIndex(i);
2949        int margin0 = lastMargin;
2950        int margin1 = (int) iter.getLeadingCollapseSpan();
2951        totalSpacing += Math.max(margin0, margin1);;
2952        preferred += (int) iter.getPreferredSpan(0);
2953        minimum += iter.getMinimumSpan(0);
2954        maximum += iter.getMaximumSpan(0);
2955
2956        lastMargin = (int) iter.getTrailingCollapseSpan();
2957    }
2958    totalSpacing += lastMargin;
2959    totalSpacing += 2 * iter.getBorderWidth();
2960
2961    // adjust for the spacing area
2962
minimum += totalSpacing;
2963    preferred += totalSpacing;
2964    maximum += totalSpacing;
2965
2966    // set return value
2967
if (r == null) {
2968        r = new SizeRequirements JavaDoc();
2969    }
2970    r.minimum = (minimum > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)minimum;
2971    r.preferred = (preferred > Integer.MAX_VALUE) ? Integer.MAX_VALUE :(int) preferred;
2972    r.maximum = (maximum > Integer.MAX_VALUE) ? Integer.MAX_VALUE :(int) maximum;
2973    return r;
2974    }
2975
2976    /**
2977     * Calculate a tiled layout for the given iterator.
2978     * This should be done collapsing the neighboring
2979     * margins to be a total of the maximum of the two
2980     * neighboring margin areas as described in the CSS spec.
2981     */

2982    static void calculateTiledLayout(LayoutIterator iter, int targetSpan) {
2983    
2984    /*
2985     * first pass, calculate the preferred sizes, adjustments needed because
2986     * of margin collapsing, and the flexibility to adjust the sizes.
2987     */

2988    long preferred = 0;
2989    long currentPreferred = 0;
2990    int lastMargin = 0;
2991    int totalSpacing = 0;
2992    int n = iter.getCount();
2993    int adjustmentWeightsCount = LayoutIterator.WorstAdjustmentWeight + 1;
2994    //max gain we can get adjusting elements with adjustmentWeight <= i
2995
long gain[] = new long[adjustmentWeightsCount];
2996    //max loss we can get adjusting elements with adjustmentWeight <= i
2997
long loss[] = new long[adjustmentWeightsCount];
2998
2999    for (int i = 0; i < adjustmentWeightsCount; i++) {
3000        gain[i] = loss[i] = 0;
3001    }
3002    for (int i = 0; i < n; i++) {
3003        iter.setIndex(i);
3004        int margin0 = lastMargin;
3005        int margin1 = (int) iter.getLeadingCollapseSpan();
3006
3007        iter.setOffset(Math.max(margin0, margin1));
3008        totalSpacing += iter.getOffset();
3009
3010        currentPreferred = (long)iter.getPreferredSpan(targetSpan);
3011        iter.setSpan((int) currentPreferred);
3012        preferred += currentPreferred;
3013        gain[iter.getAdjustmentWeight()] +=
3014        (long)iter.getMaximumSpan(targetSpan) - currentPreferred;
3015        loss[iter.getAdjustmentWeight()] +=
3016        currentPreferred - (long)iter.getMinimumSpan(targetSpan);
3017        lastMargin = (int) iter.getTrailingCollapseSpan();
3018    }
3019    totalSpacing += lastMargin;
3020    totalSpacing += 2 * iter.getBorderWidth();
3021    
3022    for (int i = 1; i < adjustmentWeightsCount; i++) {
3023        gain[i] += gain[i - 1];
3024        loss[i] += loss[i - 1];
3025    }
3026
3027    /*
3028     * Second pass, expand or contract by as much as possible to reach
3029     * the target span. This takes the margin collapsing into account
3030     * prior to adjusting the span.
3031     */

3032
3033    // determine the adjustment to be made
3034
int allocated = targetSpan - totalSpacing;
3035    long desiredAdjustment = allocated - preferred;
3036    long adjustmentsArray[] = (desiredAdjustment > 0) ? gain : loss;
3037    desiredAdjustment = Math.abs(desiredAdjustment);
3038    int adjustmentLevel = 0;
3039    for (;adjustmentLevel <= LayoutIterator.WorstAdjustmentWeight;
3040         adjustmentLevel++) {
3041        // adjustmentsArray[] is sorted. I do not bother about
3042
// binary search though
3043
if (adjustmentsArray[adjustmentLevel] >= desiredAdjustment) {
3044        break;
3045        }
3046    }
3047    float adjustmentFactor = 0.0f;
3048    if (adjustmentLevel <= LayoutIterator.WorstAdjustmentWeight) {
3049        desiredAdjustment -= (adjustmentLevel > 0) ?
3050        adjustmentsArray[adjustmentLevel - 1] : 0;
3051        if (desiredAdjustment != 0) {
3052        float maximumAdjustment =
3053            adjustmentsArray[adjustmentLevel] -
3054            ((adjustmentLevel > 0) ?
3055             adjustmentsArray[adjustmentLevel - 1] : 0
3056             );
3057        adjustmentFactor = desiredAdjustment / maximumAdjustment;
3058        }
3059    }
3060    // make the adjustments
3061
int totalOffset = (int)iter.getBorderWidth();;
3062    for (int i = 0; i < n; i++) {
3063        iter.setIndex(i);
3064        iter.setOffset( iter.getOffset() + totalOffset);
3065        if (iter.getAdjustmentWeight() < adjustmentLevel) {
3066        iter.setSpan((int)
3067                 ((allocated > preferred) ?
3068                  Math.floor(iter.getMaximumSpan(targetSpan)) :
3069                  Math.ceil(iter.getMinimumSpan(targetSpan))
3070                  )
3071                 );
3072        } else if (iter.getAdjustmentWeight() == adjustmentLevel) {
3073        int availableSpan = (allocated > preferred) ?
3074            (int) iter.getMaximumSpan(targetSpan) - iter.getSpan() :
3075            iter.getSpan() - (int) iter.getMinimumSpan(targetSpan);
3076        int adj = (int)Math.floor(adjustmentFactor * availableSpan);
3077        iter.setSpan(iter.getSpan() +
3078                 ((allocated > preferred) ? adj : -adj));
3079        }
3080        totalOffset = (int) Math.min((long) iter.getOffset() +
3081                     (long) iter.getSpan(),
3082                     Integer.MAX_VALUE);
3083    }
3084
3085    // while rounding we could lose several pixels.
3086
int roundError = targetSpan - totalOffset -
3087        (int)iter.getTrailingCollapseSpan() -
3088        (int)iter.getBorderWidth();
3089    int adj = (roundError > 0) ? 1 : -1;
3090    roundError *= adj;
3091
3092        boolean canAdjust = true;
3093        while (roundError > 0 && canAdjust) {
3094        // check for infinite loop
3095
canAdjust = false;
3096        int offsetAdjust = 0;
3097        // try to distribute roundError. one pixel per cell
3098
for (int i = 0; i < n; i++) {
3099        iter.setIndex(i);
3100        iter.setOffset(iter.getOffset() + offsetAdjust);
3101                int curSpan = iter.getSpan();
3102                if (roundError > 0) {
3103            int boundGap = (adj > 0) ?
3104            (int)Math.floor(iter.getMaximumSpan(targetSpan)) - curSpan :
3105            curSpan - (int)Math.ceil(iter.getMinimumSpan(targetSpan));
3106            if (boundGap >= 1) {
3107            canAdjust = true;
3108            iter.setSpan(curSpan + adj);
3109            offsetAdjust += adj;
3110            roundError--;
3111            }
3112                }
3113        }
3114    }
3115    }
3116
3117    /**
3118     * An iterator to express the requirements to use when computing
3119     * layout.
3120     */

3121    interface LayoutIterator {
3122
3123    void setOffset(int offs);
3124
3125    int getOffset();
3126
3127    void setSpan(int span);
3128
3129    int getSpan();
3130
3131    int getCount();
3132
3133    void setIndex(int i);
3134
3135    float getMinimumSpan(float parentSpan);
3136
3137    float getPreferredSpan(float parentSpan);
3138
3139    float getMaximumSpan(float parentSpan);
3140
3141    int getAdjustmentWeight(); //0 is the best weight WorstAdjustmentWeight is a worst one
3142

3143    //float getAlignment();
3144

3145    float getBorderWidth();
3146
3147    float getLeadingCollapseSpan();
3148
3149    float getTrailingCollapseSpan();
3150    public static final int WorstAdjustmentWeight = 2;
3151    }
3152
3153    //
3154
// Serialization support
3155
//
3156

3157    private void writeObject(java.io.ObjectOutputStream JavaDoc s)
3158        throws IOException
3159    {
3160        s.defaultWriteObject();
3161
3162    // Determine what values in valueConvertor need to be written out.
3163
Enumeration JavaDoc keys = valueConvertor.keys();
3164    s.writeInt(valueConvertor.size());
3165    if (keys != null) {
3166        while (keys.hasMoreElements()) {
3167        Object JavaDoc key = keys.nextElement();
3168        Object JavaDoc value = valueConvertor.get(key);
3169        if (!(key instanceof Serializable) &&
3170            (key = StyleContext.getStaticAttributeKey(key)) == null) {
3171            // Should we throw an exception here?
3172
key = null;
3173            value = null;
3174        }
3175        else if (!(value instanceof Serializable) &&
3176            (value = StyleContext.getStaticAttributeKey(value)) == null){
3177            // Should we throw an exception here?
3178
key = null;
3179            value = null;
3180        }
3181        s.writeObject(key);
3182        s.writeObject(value);
3183        }
3184    }
3185    }
3186
3187    private void readObject(ObjectInputStream s)
3188      throws ClassNotFoundException JavaDoc, IOException
3189    {
3190        s.defaultReadObject();
3191    // Reconstruct the hashtable.
3192
int numValues = s.readInt();
3193    valueConvertor = new Hashtable JavaDoc(Math.max(1, numValues));
3194    while (numValues-- > 0) {
3195        Object JavaDoc key = s.readObject();
3196        Object JavaDoc value = s.readObject();
3197        Object JavaDoc staticKey = StyleContext.getStaticAttribute(key);
3198        if (staticKey != null) {
3199        key = staticKey;
3200        }
3201        Object JavaDoc staticValue = StyleContext.getStaticAttribute(value);
3202        if (staticValue != null) {
3203        value = staticValue;
3204        }
3205        if (key != null && value != null) {
3206        valueConvertor.put(key, value);
3207        }
3208    }
3209    }
3210
3211
3212    /*
3213     * we need StyleSheet for resolving lenght units. (see
3214     * isW3CLengthUnits)
3215     * we can not pass stylesheet for handling relative sizes. (do not
3216     * think changing public API is necessary)
3217     * CSS is not likely to be accessed from more then one thread.
3218     * Having local storage for StyleSheet for resolving relative
3219     * sizes is safe
3220     *
3221     * idk 08/30/2004
3222     */

3223    private StyleSheet JavaDoc getStyleSheet(StyleSheet JavaDoc ss) {
3224        if (ss != null) {
3225            styleSheet = ss;
3226        }
3227        return styleSheet;
3228    }
3229    //
3230
// Instance variables
3231
//
3232

3233    /** Maps from CSS key to CssValue. */
3234    private transient Hashtable JavaDoc valueConvertor;
3235
3236    /** Size used for relative units. */
3237    private int baseFontSize;
3238
3239    private transient StyleSheet JavaDoc styleSheet = null;
3240
3241    static int baseFontSizeIndex = 3;
3242}
3243
Popular Tags