Source Code Cross Referenced for CSS.java in  » 6.0-JDK-Core » swing » javax » swing » text » html » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » swing » javax.swing.text.html 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001        /*
0002         * Copyright 1998-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004         *
0005         * This code is free software; you can redistribute it and/or modify it
0006         * under the terms of the GNU General Public License version 2 only, as
0007         * published by the Free Software Foundation.  Sun designates this
0008         * particular file as subject to the "Classpath" exception as provided
0009         * by Sun in the LICENSE file that accompanied this code.
0010         *
0011         * This code is distributed in the hope that it will be useful, but WITHOUT
0012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014         * version 2 for more details (a copy is included in the LICENSE file that
0015         * accompanied this code).
0016         *
0017         * You should have received a copy of the GNU General Public License version
0018         * 2 along with this work; if not, write to the Free Software Foundation,
0019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020         *
0021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022         * CA 95054 USA or visit www.sun.com if you need additional information or
0023         * have any questions.
0024         */
0025        package javax.swing.text.html;
0026
0027        import java.awt.Color;
0028        import java.awt.Font;
0029        import java.awt.GraphicsEnvironment;
0030        import java.awt.Toolkit;
0031        import java.awt.HeadlessException;
0032        import java.awt.Image;
0033        import java.io.*;
0034        import java.lang.reflect.Method;
0035        import java.net.URL;
0036        import java.net.MalformedURLException;
0037        import java.util.Enumeration;
0038        import java.util.Hashtable;
0039        import java.util.Vector;
0040        import java.util.Locale;
0041        import javax.swing.ImageIcon;
0042        import javax.swing.SizeRequirements;
0043        import javax.swing.text.*;
0044
0045        /**
0046         * Defines a set of
0047         * <a href="http://www.w3.org/TR/REC-CSS1">CSS attributes</a>
0048         * as a typesafe enumeration.  The HTML View implementations use
0049         * CSS attributes to determine how they will render. This also defines
0050         * methods to map between CSS/HTML/StyleConstants. Any shorthand
0051         * properties, such as font, are mapped to the intrinsic properties.
0052         * <p>The following describes the CSS properties that are suppored by the
0053         * rendering engine:
0054         * <ul><li>font-family
0055         *   <li>font-style
0056         *   <li>font-size (supports relative units)
0057         *   <li>font-weight
0058         *   <li>font
0059         *   <li>color
0060         *   <li>background-color (with the exception of transparent)
0061         *   <li>background-image
0062         *   <li>background-repeat
0063         *   <li>background-position
0064         *   <li>background
0065         *   <li>background-repeat
0066         *   <li>text-decoration (with the exception of blink and overline)
0067         *   <li>vertical-align (only sup and super)
0068         *   <li>text-align (justify is treated as center)
0069         *   <li>margin-top
0070         *   <li>margin-right
0071         *   <li>margin-bottom
0072         *   <li>margin-left
0073         *   <li>margin
0074         *   <li>padding-top
0075         *   <li>padding-right
0076         *   <li>padding-bottom
0077         *   <li>padding-left
0078         *   <li>border-style (only supports inset, outset and none)
0079         *   <li>list-style-type
0080         *   <li>list-style-position
0081         * </ul>
0082         * The following are modeled, but currently not rendered.
0083         * <ul><li>font-variant
0084         *   <li>background-attachment (background always treated as scroll)
0085         *   <li>word-spacing
0086         *   <li>letter-spacing
0087         *   <li>text-indent
0088         *   <li>text-transform
0089         *   <li>line-height
0090         *   <li>border-top-width (this is used to indicate if a border should be used)
0091         *   <li>border-right-width
0092         *   <li>border-bottom-width
0093         *   <li>border-left-width
0094         *   <li>border-width
0095         *   <li>border-top
0096         *   <li>border-right
0097         *   <li>border-bottom
0098         *   <li>border-left
0099         *   <li>border
0100         *   <li>width
0101         *   <li>height
0102         *   <li>float
0103         *   <li>clear
0104         *   <li>display
0105         *   <li>white-space
0106         *   <li>list-style
0107         * </ul>
0108         * <p><b>Note: for the time being we do not fully support relative units,
0109         * unless noted, so that
0110         * p { margin-top: 10% } will be treated as if no margin-top was specified.
0111         *
0112         * @author  Timothy Prinzing
0113         * @author  Scott Violet
0114         * @version 1.74 05/05/07
0115         * @see StyleSheet
0116         */
0117        public class CSS implements  Serializable {
0118
0119            /**
0120             * Definitions to be used as a key on AttributeSet's
0121             * that might hold CSS attributes.  Since this is a
0122             * closed set (i.e. defined exactly by the specification),
0123             * it is final and cannot be extended.
0124             */
0125            public static final class Attribute {
0126
0127                private Attribute(String name, String defaultValue,
0128                        boolean inherited) {
0129                    this .name = name;
0130                    this .defaultValue = defaultValue;
0131                    this .inherited = inherited;
0132                }
0133
0134                /**
0135                 * The string representation of the attribute.  This
0136                 * should exactly match the string specified in the
0137                 * CSS specification.
0138                 */
0139                public String toString() {
0140                    return name;
0141                }
0142
0143                /**
0144                 * Fetch the default value for the attribute.
0145                 * If there is no default value (such as for
0146                 * composite attributes), null will be returned.
0147                 */
0148                public String getDefaultValue() {
0149                    return defaultValue;
0150                }
0151
0152                /**
0153                 * Indicates if the attribute should be inherited
0154                 * from the parent or not.
0155                 */
0156                public boolean isInherited() {
0157                    return inherited;
0158                }
0159
0160                private String name;
0161                private String defaultValue;
0162                private boolean inherited;
0163
0164                public static final Attribute BACKGROUND = new Attribute(
0165                        "background", null, false);
0166
0167                public static final Attribute BACKGROUND_ATTACHMENT = new Attribute(
0168                        "background-attachment", "scroll", false);
0169
0170                public static final Attribute BACKGROUND_COLOR = new Attribute(
0171                        "background-color", "transparent", false);
0172
0173                public static final Attribute BACKGROUND_IMAGE = new Attribute(
0174                        "background-image", "none", false);
0175
0176                public static final Attribute BACKGROUND_POSITION = new Attribute(
0177                        "background-position", null, false);
0178
0179                public static final Attribute BACKGROUND_REPEAT = new Attribute(
0180                        "background-repeat", "repeat", false);
0181
0182                public static final Attribute BORDER = new Attribute("border",
0183                        null, false);
0184
0185                public static final Attribute BORDER_BOTTOM = new Attribute(
0186                        "border-bottom", null, false);
0187
0188                public static final Attribute BORDER_BOTTOM_WIDTH = new Attribute(
0189                        "border-bottom-width", "medium", false);
0190
0191                public static final Attribute BORDER_COLOR = new Attribute(
0192                        "border-color", "black", false);
0193
0194                public static final Attribute BORDER_LEFT = new Attribute(
0195                        "border-left", null, false);
0196
0197                public static final Attribute BORDER_LEFT_WIDTH = new Attribute(
0198                        "border-left-width", "medium", false);
0199
0200                public static final Attribute BORDER_RIGHT = new Attribute(
0201                        "border-right", null, false);
0202
0203                public static final Attribute BORDER_RIGHT_WIDTH = new Attribute(
0204                        "border-right-width", "medium", false);
0205
0206                public static final Attribute BORDER_STYLE = new Attribute(
0207                        "border-style", "none", false);
0208
0209                public static final Attribute BORDER_TOP = new Attribute(
0210                        "border-top", null, false);
0211
0212                public static final Attribute BORDER_TOP_WIDTH = new Attribute(
0213                        "border-top-width", "medium", false);
0214
0215                public static final Attribute BORDER_WIDTH = new Attribute(
0216                        "border-width", "medium", false);
0217
0218                public static final Attribute CLEAR = new Attribute("clear",
0219                        "none", false);
0220
0221                public static final Attribute COLOR = new Attribute("color",
0222                        "black", true);
0223
0224                public static final Attribute DISPLAY = new Attribute(
0225                        "display", "block", false);
0226
0227                public static final Attribute FLOAT = new Attribute("float",
0228                        "none", false);
0229
0230                public static final Attribute FONT = new Attribute("font",
0231                        null, true);
0232
0233                public static final Attribute FONT_FAMILY = new Attribute(
0234                        "font-family", null, true);
0235
0236                public static final Attribute FONT_SIZE = new Attribute(
0237                        "font-size", "medium", true);
0238
0239                public static final Attribute FONT_STYLE = new Attribute(
0240                        "font-style", "normal", true);
0241
0242                public static final Attribute FONT_VARIANT = new Attribute(
0243                        "font-variant", "normal", true);
0244
0245                public static final Attribute FONT_WEIGHT = new Attribute(
0246                        "font-weight", "normal", true);
0247
0248                public static final Attribute HEIGHT = new Attribute("height",
0249                        "auto", false);
0250
0251                public static final Attribute LETTER_SPACING = new Attribute(
0252                        "letter-spacing", "normal", true);
0253
0254                public static final Attribute LINE_HEIGHT = new Attribute(
0255                        "line-height", "normal", true);
0256
0257                public static final Attribute LIST_STYLE = new Attribute(
0258                        "list-style", null, true);
0259
0260                public static final Attribute LIST_STYLE_IMAGE = new Attribute(
0261                        "list-style-image", "none", true);
0262
0263                public static final Attribute LIST_STYLE_POSITION = new Attribute(
0264                        "list-style-position", "outside", true);
0265
0266                public static final Attribute LIST_STYLE_TYPE = new Attribute(
0267                        "list-style-type", "disc", true);
0268
0269                public static final Attribute MARGIN = new Attribute("margin",
0270                        null, false);
0271
0272                public static final Attribute MARGIN_BOTTOM = new Attribute(
0273                        "margin-bottom", "0", false);
0274
0275                public static final Attribute MARGIN_LEFT = new Attribute(
0276                        "margin-left", "0", false);
0277
0278                public static final Attribute MARGIN_RIGHT = new Attribute(
0279                        "margin-right", "0", false);
0280
0281                /* 
0282                 * made up css attributes to describe orientation depended
0283                 * margins. used for <dir>, <menu>, <ul> etc. see
0284                 * 5088268 for more details
0285                 */
0286                static final Attribute MARGIN_LEFT_LTR = new Attribute(
0287                        "margin-left-ltr", Integer.toString(Integer.MIN_VALUE),
0288                        false);
0289
0290                static final Attribute MARGIN_LEFT_RTL = new Attribute(
0291                        "margin-left-rtl", Integer.toString(Integer.MIN_VALUE),
0292                        false);
0293
0294                static final Attribute MARGIN_RIGHT_LTR = new Attribute(
0295                        "margin-right-ltr",
0296                        Integer.toString(Integer.MIN_VALUE), false);
0297
0298                static final Attribute MARGIN_RIGHT_RTL = new Attribute(
0299                        "margin-right-rtl",
0300                        Integer.toString(Integer.MIN_VALUE), false);
0301
0302                public static final Attribute MARGIN_TOP = new Attribute(
0303                        "margin-top", "0", false);
0304
0305                public static final Attribute PADDING = new Attribute(
0306                        "padding", null, false);
0307
0308                public static final Attribute PADDING_BOTTOM = new Attribute(
0309                        "padding-bottom", "0", false);
0310
0311                public static final Attribute PADDING_LEFT = new Attribute(
0312                        "padding-left", "0", false);
0313
0314                public static final Attribute PADDING_RIGHT = new Attribute(
0315                        "padding-right", "0", false);
0316
0317                public static final Attribute PADDING_TOP = new Attribute(
0318                        "padding-top", "0", false);
0319
0320                public static final Attribute TEXT_ALIGN = new Attribute(
0321                        "text-align", null, true);
0322
0323                public static final Attribute TEXT_DECORATION = new Attribute(
0324                        "text-decoration", "none", true);
0325
0326                public static final Attribute TEXT_INDENT = new Attribute(
0327                        "text-indent", "0", true);
0328
0329                public static final Attribute TEXT_TRANSFORM = new Attribute(
0330                        "text-transform", "none", true);
0331
0332                public static final Attribute VERTICAL_ALIGN = new Attribute(
0333                        "vertical-align", "baseline", false);
0334
0335                public static final Attribute WORD_SPACING = new Attribute(
0336                        "word-spacing", "normal", true);
0337
0338                public static final Attribute WHITE_SPACE = new Attribute(
0339                        "white-space", "normal", true);
0340
0341                public static final Attribute WIDTH = new Attribute("width",
0342                        "auto", false);
0343
0344                /*public*/static final Attribute BORDER_SPACING = new Attribute(
0345                        "border-spacing", "0", true);
0346
0347                /*public*/static final Attribute CAPTION_SIDE = new Attribute(
0348                        "caption-side", "left", true);
0349
0350                // All possible CSS attribute keys.
0351                static final Attribute[] allAttributes = { BACKGROUND,
0352                        BACKGROUND_ATTACHMENT, BACKGROUND_COLOR,
0353                        BACKGROUND_IMAGE, BACKGROUND_POSITION,
0354                        BACKGROUND_REPEAT, BORDER, BORDER_BOTTOM,
0355                        BORDER_BOTTOM_WIDTH, BORDER_COLOR, BORDER_LEFT,
0356                        BORDER_LEFT_WIDTH, BORDER_RIGHT, BORDER_RIGHT_WIDTH,
0357                        BORDER_STYLE, BORDER_TOP, BORDER_TOP_WIDTH,
0358                        BORDER_WIDTH, CLEAR, COLOR, DISPLAY, FLOAT, FONT,
0359                        FONT_FAMILY, FONT_SIZE, FONT_STYLE, FONT_VARIANT,
0360                        FONT_WEIGHT, HEIGHT, LETTER_SPACING, LINE_HEIGHT,
0361                        LIST_STYLE, LIST_STYLE_IMAGE, LIST_STYLE_POSITION,
0362                        LIST_STYLE_TYPE, MARGIN, MARGIN_BOTTOM, MARGIN_LEFT,
0363                        MARGIN_RIGHT, MARGIN_TOP, PADDING, PADDING_BOTTOM,
0364                        PADDING_LEFT, PADDING_RIGHT, PADDING_TOP, TEXT_ALIGN,
0365                        TEXT_DECORATION, TEXT_INDENT, TEXT_TRANSFORM,
0366                        VERTICAL_ALIGN, WORD_SPACING, WHITE_SPACE, WIDTH,
0367                        BORDER_SPACING, CAPTION_SIDE, MARGIN_LEFT_LTR,
0368                        MARGIN_LEFT_RTL, MARGIN_RIGHT_LTR, MARGIN_RIGHT_RTL };
0369
0370                private static final Attribute[] ALL_MARGINS = { MARGIN_TOP,
0371                        MARGIN_RIGHT, MARGIN_BOTTOM, MARGIN_LEFT };
0372                private static final Attribute[] ALL_PADDING = { PADDING_TOP,
0373                        PADDING_RIGHT, PADDING_BOTTOM, PADDING_LEFT };
0374                private static final Attribute[] ALL_BORDER_WIDTHS = {
0375                        BORDER_TOP_WIDTH, BORDER_RIGHT_WIDTH,
0376                        BORDER_BOTTOM_WIDTH, BORDER_LEFT_WIDTH };
0377
0378            }
0379
0380            static final class Value {
0381
0382                private Value(String name) {
0383                    this .name = name;
0384                }
0385
0386                /**
0387                 * The string representation of the attribute.  This
0388                 * should exactly match the string specified in the
0389                 * CSS specification.
0390                 */
0391                public String toString() {
0392                    return name;
0393                }
0394
0395                static final Value INHERITED = new Value("inherited");
0396                static final Value NONE = new Value("none");
0397                static final Value DOTTED = new Value("dotted");
0398                static final Value DASHED = new Value("dashed");
0399                static final Value SOLID = new Value("solid");
0400                static final Value DOUBLE = new Value("double");
0401                static final Value GROOVE = new Value("groove");
0402                static final Value RIDGE = new Value("ridge");
0403                static final Value INSET = new Value("inset");
0404                static final Value OUTSET = new Value("outset");
0405                // Lists.
0406                static final Value BLANK_LIST_ITEM = new Value("none");
0407                static final Value DISC = new Value("disc");
0408                static final Value CIRCLE = new Value("circle");
0409                static final Value SQUARE = new Value("square");
0410                static final Value DECIMAL = new Value("decimal");
0411                static final Value LOWER_ROMAN = new Value("lower-roman");
0412                static final Value UPPER_ROMAN = new Value("upper-roman");
0413                static final Value LOWER_ALPHA = new Value("lower-alpha");
0414                static final Value UPPER_ALPHA = new Value("upper-alpha");
0415                // background-repeat
0416                static final Value BACKGROUND_NO_REPEAT = new Value("no-repeat");
0417                static final Value BACKGROUND_REPEAT = new Value("repeat");
0418                static final Value BACKGROUND_REPEAT_X = new Value("repeat-x");
0419                static final Value BACKGROUND_REPEAT_Y = new Value("repeat-y");
0420                // background-attachment
0421                static final Value BACKGROUND_SCROLL = new Value("scroll");
0422                static final Value BACKGROUND_FIXED = new Value("fixed");
0423
0424                private String name;
0425
0426                static final Value[] allValues = { INHERITED, NONE, DOTTED,
0427                        DASHED, SOLID, DOUBLE, GROOVE, RIDGE, INSET, OUTSET,
0428                        DISC, CIRCLE, SQUARE, DECIMAL, LOWER_ROMAN,
0429                        UPPER_ROMAN, LOWER_ALPHA, UPPER_ALPHA, BLANK_LIST_ITEM,
0430                        BACKGROUND_NO_REPEAT, BACKGROUND_REPEAT,
0431                        BACKGROUND_REPEAT_X, BACKGROUND_REPEAT_Y,
0432                        BACKGROUND_FIXED, BACKGROUND_FIXED };
0433            }
0434
0435            public CSS() {
0436                baseFontSize = baseFontSizeIndex + 1;
0437                // setup the css conversion table
0438                valueConvertor = new Hashtable();
0439                valueConvertor.put(CSS.Attribute.FONT_SIZE, new FontSize());
0440                valueConvertor.put(CSS.Attribute.FONT_FAMILY, new FontFamily());
0441                valueConvertor.put(CSS.Attribute.FONT_WEIGHT, new FontWeight());
0442                valueConvertor.put(CSS.Attribute.BORDER_STYLE,
0443                        new BorderStyle());
0444                Object cv = new ColorValue();
0445                valueConvertor.put(CSS.Attribute.COLOR, cv);
0446                valueConvertor.put(CSS.Attribute.BACKGROUND_COLOR, cv);
0447                valueConvertor.put(CSS.Attribute.BORDER_COLOR, cv);
0448                Object lv = new LengthValue();
0449                valueConvertor.put(CSS.Attribute.MARGIN_TOP, lv);
0450                valueConvertor.put(CSS.Attribute.MARGIN_BOTTOM, lv);
0451                valueConvertor.put(CSS.Attribute.MARGIN_LEFT, lv);
0452                valueConvertor.put(CSS.Attribute.MARGIN_LEFT_LTR, lv);
0453                valueConvertor.put(CSS.Attribute.MARGIN_LEFT_RTL, lv);
0454                valueConvertor.put(CSS.Attribute.MARGIN_RIGHT, lv);
0455                valueConvertor.put(CSS.Attribute.MARGIN_RIGHT_LTR, lv);
0456                valueConvertor.put(CSS.Attribute.MARGIN_RIGHT_RTL, lv);
0457                valueConvertor.put(CSS.Attribute.PADDING_TOP, lv);
0458                valueConvertor.put(CSS.Attribute.PADDING_BOTTOM, lv);
0459                valueConvertor.put(CSS.Attribute.PADDING_LEFT, lv);
0460                valueConvertor.put(CSS.Attribute.PADDING_RIGHT, lv);
0461                Object bv = new BorderWidthValue(null, 0);
0462                valueConvertor.put(CSS.Attribute.BORDER_WIDTH, lv);
0463                valueConvertor.put(CSS.Attribute.BORDER_TOP_WIDTH, bv);
0464                valueConvertor.put(CSS.Attribute.BORDER_BOTTOM_WIDTH, bv);
0465                valueConvertor.put(CSS.Attribute.BORDER_LEFT_WIDTH, bv);
0466                valueConvertor.put(CSS.Attribute.BORDER_RIGHT_WIDTH, bv);
0467                Object nlv = new LengthValue(true);
0468                valueConvertor.put(CSS.Attribute.TEXT_INDENT, nlv);
0469                valueConvertor.put(CSS.Attribute.WIDTH, lv);
0470                valueConvertor.put(CSS.Attribute.HEIGHT, lv);
0471                valueConvertor.put(CSS.Attribute.BORDER_SPACING, lv);
0472                Object sv = new StringValue();
0473                valueConvertor.put(CSS.Attribute.FONT_STYLE, sv);
0474                valueConvertor.put(CSS.Attribute.TEXT_DECORATION, sv);
0475                valueConvertor.put(CSS.Attribute.TEXT_ALIGN, sv);
0476                valueConvertor.put(CSS.Attribute.VERTICAL_ALIGN, sv);
0477                Object valueMapper = new CssValueMapper();
0478                valueConvertor.put(CSS.Attribute.LIST_STYLE_TYPE, valueMapper);
0479                valueConvertor.put(CSS.Attribute.BACKGROUND_IMAGE,
0480                        new BackgroundImage());
0481                valueConvertor.put(CSS.Attribute.BACKGROUND_POSITION,
0482                        new BackgroundPosition());
0483                valueConvertor
0484                        .put(CSS.Attribute.BACKGROUND_REPEAT, valueMapper);
0485                valueConvertor.put(CSS.Attribute.BACKGROUND_ATTACHMENT,
0486                        valueMapper);
0487                Object generic = new CssValue();
0488                int n = CSS.Attribute.allAttributes.length;
0489                for (int i = 0; i < n; i++) {
0490                    CSS.Attribute key = CSS.Attribute.allAttributes[i];
0491                    if (valueConvertor.get(key) == null) {
0492                        valueConvertor.put(key, generic);
0493                    }
0494                }
0495            }
0496
0497            /**
0498             * Sets the base font size. <code>sz</code> is a CSS value, and is
0499             * not necessarily the point size. Use getPointSize to determine the
0500             * point size corresponding to <code>sz</code>.
0501             */
0502            void setBaseFontSize(int sz) {
0503                if (sz < 1)
0504                    baseFontSize = 0;
0505                else if (sz > 7)
0506                    baseFontSize = 7;
0507                else
0508                    baseFontSize = sz;
0509            }
0510
0511            /**
0512             * Sets the base font size from the passed in string.
0513             */
0514            void setBaseFontSize(String size) {
0515                int relSize, absSize, diff;
0516
0517                if (size != null) {
0518                    if (size.startsWith("+")) {
0519                        relSize = Integer.valueOf(size.substring(1)).intValue();
0520                        setBaseFontSize(baseFontSize + relSize);
0521                    } else if (size.startsWith("-")) {
0522                        relSize = -Integer.valueOf(size.substring(1))
0523                                .intValue();
0524                        setBaseFontSize(baseFontSize + relSize);
0525                    } else {
0526                        setBaseFontSize(Integer.valueOf(size).intValue());
0527                    }
0528                }
0529            }
0530
0531            /**
0532             * Returns the base font size.
0533             */
0534            int getBaseFontSize() {
0535                return baseFontSize;
0536            }
0537
0538            /**
0539             * Parses the CSS property <code>key</code> with value
0540             * <code>value</code> placing the result in <code>att</code>.
0541             */
0542            void addInternalCSSValue(MutableAttributeSet attr,
0543                    CSS.Attribute key, String value) {
0544                if (key == CSS.Attribute.FONT) {
0545                    ShorthandFontParser.parseShorthandFont(this , value, attr);
0546                } else if (key == CSS.Attribute.BACKGROUND) {
0547                    ShorthandBackgroundParser.parseShorthandBackground(this ,
0548                            value, attr);
0549                } else if (key == CSS.Attribute.MARGIN) {
0550                    ShorthandMarginParser.parseShorthandMargin(this , value,
0551                            attr, CSS.Attribute.ALL_MARGINS);
0552                } else if (key == CSS.Attribute.PADDING) {
0553                    ShorthandMarginParser.parseShorthandMargin(this , value,
0554                            attr, CSS.Attribute.ALL_PADDING);
0555                } else if (key == CSS.Attribute.BORDER_WIDTH) {
0556                    ShorthandMarginParser.parseShorthandMargin(this , value,
0557                            attr, CSS.Attribute.ALL_BORDER_WIDTHS);
0558                } else {
0559                    Object iValue = getInternalCSSValue(key, value);
0560                    if (iValue != null) {
0561                        attr.addAttribute(key, iValue);
0562                    }
0563                }
0564            }
0565
0566            /**
0567             * Gets the internal CSS representation of <code>value</code> which is
0568             * a CSS value of the CSS attribute named <code>key</code>. The receiver
0569             * should not modify <code>value</code>, and the first <code>count</code>
0570             * strings are valid.
0571             */
0572            Object getInternalCSSValue(CSS.Attribute key, String value) {
0573                CssValue conv = (CssValue) valueConvertor.get(key);
0574                Object r = conv.parseCssValue(value);
0575                return r != null ? r : conv
0576                        .parseCssValue(key.getDefaultValue());
0577            }
0578
0579            /**
0580             * Maps from a StyleConstants to a CSS Attribute.
0581             */
0582            Attribute styleConstantsKeyToCSSKey(StyleConstants sc) {
0583                return (Attribute) styleConstantToCssMap.get(sc);
0584            }
0585
0586            /**
0587             * Maps from a StyleConstants value to a CSS value.
0588             */
0589            Object styleConstantsValueToCSSValue(StyleConstants sc,
0590                    Object styleValue) {
0591                Object cssKey = styleConstantsKeyToCSSKey(sc);
0592                if (cssKey != null) {
0593                    CssValue conv = (CssValue) valueConvertor.get(cssKey);
0594                    return conv.fromStyleConstants(sc, styleValue);
0595                }
0596                return null;
0597            }
0598
0599            /**
0600             * Converts the passed in CSS value to a StyleConstants value.
0601             * <code>key</code> identifies the CSS attribute being mapped.
0602             */
0603            Object cssValueToStyleConstantsValue(StyleConstants key,
0604                    Object value) {
0605                if (value instanceof  CssValue) {
0606                    return ((CssValue) value).toStyleConstants(
0607                            (StyleConstants) key, null);
0608                }
0609                return null;
0610            }
0611
0612            /**
0613             * Returns the font for the values in the passed in AttributeSet.
0614             * It is assumed the keys will be CSS.Attribute keys.
0615             * <code>sc</code> is the StyleContext that will be messaged to get
0616             * the font once the size, name and style have been determined.
0617             */
0618            Font getFont(StyleContext sc, AttributeSet a, int defaultSize,
0619                    StyleSheet ss) {
0620                ss = getStyleSheet(ss);
0621                int size = getFontSize(a, defaultSize, ss);
0622
0623                /*
0624                 * If the vertical alignment is set to either superscirpt or
0625                 * subscript we reduce the font size by 2 points.
0626                 */
0627                StringValue vAlignV = (StringValue) a
0628                        .getAttribute(CSS.Attribute.VERTICAL_ALIGN);
0629                if ((vAlignV != null)) {
0630                    String vAlign = vAlignV.toString();
0631                    if ((vAlign.indexOf("sup") >= 0)
0632                            || (vAlign.indexOf("sub") >= 0)) {
0633                        size -= 2;
0634                    }
0635                }
0636
0637                FontFamily familyValue = (FontFamily) a
0638                        .getAttribute(CSS.Attribute.FONT_FAMILY);
0639                String family = (familyValue != null) ? familyValue.getValue()
0640                        : Font.SANS_SERIF;
0641                int style = Font.PLAIN;
0642                FontWeight weightValue = (FontWeight) a
0643                        .getAttribute(CSS.Attribute.FONT_WEIGHT);
0644                if ((weightValue != null) && (weightValue.getValue() > 400)) {
0645                    style |= Font.BOLD;
0646                }
0647                Object fs = a.getAttribute(CSS.Attribute.FONT_STYLE);
0648                if ((fs != null) && (fs.toString().indexOf("italic") >= 0)) {
0649                    style |= Font.ITALIC;
0650                }
0651                if (family.equalsIgnoreCase("monospace")) {
0652                    family = Font.MONOSPACED;
0653                }
0654                Font f = sc.getFont(family, style, size);
0655                if (f == null
0656                        || (f.getFamily().equals(Font.DIALOG) && !family
0657                                .equalsIgnoreCase(Font.DIALOG))) {
0658                    family = Font.SANS_SERIF;
0659                    f = sc.getFont(family, style, size);
0660                }
0661                return f;
0662            }
0663
0664            static int getFontSize(AttributeSet attr, int defaultSize,
0665                    StyleSheet ss) {
0666                // PENDING(prinz) this is a 1.1 based implementation, need to also
0667                // have a 1.2 version.
0668                FontSize sizeValue = (FontSize) attr
0669                        .getAttribute(CSS.Attribute.FONT_SIZE);
0670
0671                return (sizeValue != null) ? sizeValue.getValue(attr, ss)
0672                        : defaultSize;
0673            }
0674
0675            /**
0676             * Takes a set of attributes and turn it into a color
0677             * specification.  This might be used to specify things
0678             * like brighter, more hue, etc.
0679             * This will return null if there is no value for <code>key</code>.
0680             *
0681             * @param key CSS.Attribute identifying where color is stored.
0682             * @param a the set of attributes
0683             * @return the color
0684             */
0685            Color getColor(AttributeSet a, CSS.Attribute key) {
0686                ColorValue cv = (ColorValue) a.getAttribute(key);
0687                if (cv != null) {
0688                    return cv.getValue();
0689                }
0690                return null;
0691            }
0692
0693            /**
0694             * Returns the size of a font from the passed in string.
0695             *
0696             * @param size CSS string describing font size
0697             * @param baseFontSize size to use for relative units.
0698             */
0699            float getPointSize(String size, StyleSheet ss) {
0700                int relSize, absSize, diff, index;
0701                ss = getStyleSheet(ss);
0702                if (size != null) {
0703                    if (size.startsWith("+")) {
0704                        relSize = Integer.valueOf(size.substring(1)).intValue();
0705                        return getPointSize(baseFontSize + relSize, ss);
0706                    } else if (size.startsWith("-")) {
0707                        relSize = -Integer.valueOf(size.substring(1))
0708                                .intValue();
0709                        return getPointSize(baseFontSize + relSize, ss);
0710                    } else {
0711                        absSize = Integer.valueOf(size).intValue();
0712                        return getPointSize(absSize, ss);
0713                    }
0714                }
0715                return 0;
0716            }
0717
0718            /**
0719             * Returns the length of the attribute in <code>a</code> with
0720             * key <code>key</code>.
0721             */
0722            float getLength(AttributeSet a, CSS.Attribute key, StyleSheet ss) {
0723                ss = getStyleSheet(ss);
0724                LengthValue lv = (LengthValue) a.getAttribute(key);
0725                boolean isW3CLengthUnits = (ss == null) ? false : ss
0726                        .isW3CLengthUnits();
0727                float len = (lv != null) ? lv.getValue(isW3CLengthUnits) : 0;
0728                return len;
0729            }
0730
0731            /**
0732             * Convert a set of HTML attributes to an equivalent
0733             * set of CSS attributes.
0734             *
0735             * @param AttributeSet containing the HTML attributes.
0736             * @return AttributeSet containing the corresponding CSS attributes.
0737             *        The AttributeSet will be empty if there are no mapping
0738             *        CSS attributes.
0739             */
0740            AttributeSet translateHTMLToCSS(AttributeSet htmlAttrSet) {
0741                MutableAttributeSet cssAttrSet = new SimpleAttributeSet();
0742                Element elem = (Element) htmlAttrSet;
0743                HTML.Tag tag = getHTMLTag(htmlAttrSet);
0744                if ((tag == HTML.Tag.TD) || (tag == HTML.Tag.TH)) {
0745                    // translate border width into the cells
0746                    AttributeSet tableAttr = elem.getParentElement()
0747                            .getParentElement().getAttributes();
0748                    translateAttribute(HTML.Attribute.BORDER, tableAttr,
0749                            cssAttrSet);
0750                    String pad = (String) tableAttr
0751                            .getAttribute(HTML.Attribute.CELLPADDING);
0752                    if (pad != null) {
0753                        LengthValue v = (LengthValue) getInternalCSSValue(
0754                                CSS.Attribute.PADDING_TOP, pad);
0755                        v.span = (v.span < 0) ? 0 : v.span;
0756                        cssAttrSet.addAttribute(CSS.Attribute.PADDING_TOP, v);
0757                        cssAttrSet
0758                                .addAttribute(CSS.Attribute.PADDING_BOTTOM, v);
0759                        cssAttrSet.addAttribute(CSS.Attribute.PADDING_LEFT, v);
0760                        cssAttrSet.addAttribute(CSS.Attribute.PADDING_RIGHT, v);
0761                    }
0762                }
0763                if (elem.isLeaf()) {
0764                    translateEmbeddedAttributes(htmlAttrSet, cssAttrSet);
0765                } else {
0766                    translateAttributes(tag, htmlAttrSet, cssAttrSet);
0767                }
0768                if (tag == HTML.Tag.CAPTION) {
0769                    /* 
0770                     * Navigator uses ALIGN for caption placement and IE uses VALIGN.
0771                     */
0772                    Object v = htmlAttrSet.getAttribute(HTML.Attribute.ALIGN);
0773                    if ((v != null) && (v.equals("top") || v.equals("bottom"))) {
0774                        cssAttrSet.addAttribute(CSS.Attribute.CAPTION_SIDE, v);
0775                        cssAttrSet.removeAttribute(CSS.Attribute.TEXT_ALIGN);
0776                    } else {
0777                        v = htmlAttrSet.getAttribute(HTML.Attribute.VALIGN);
0778                        if (v != null) {
0779                            cssAttrSet.addAttribute(CSS.Attribute.CAPTION_SIDE,
0780                                    v);
0781                        }
0782                    }
0783                }
0784                return cssAttrSet;
0785            }
0786
0787            private static final Hashtable attributeMap = new Hashtable();
0788            private static final Hashtable valueMap = new Hashtable();
0789
0790            /**
0791             * The hashtable and the static initalization block below,
0792             * set up a mapping from well-known HTML attributes to
0793             * CSS attributes.  For the most part, there is a 1-1 mapping
0794             * between the two.  However in the case of certain HTML
0795             * attributes for example HTML.Attribute.VSPACE or
0796             * HTML.Attribute.HSPACE, end up mapping to two CSS.Attribute's.
0797             * Therefore, the value associated with each HTML.Attribute.
0798             * key ends up being an array of CSS.Attribute.* objects.
0799             */
0800            private static final Hashtable htmlAttrToCssAttrMap = new Hashtable(
0801                    20);
0802
0803            /**
0804             * The hashtable and static initialization that follows sets
0805             * up a translation from StyleConstants (i.e. the <em>well known</em>
0806             * attributes) to the associated CSS attributes.
0807             */
0808            private static final Hashtable styleConstantToCssMap = new Hashtable(
0809                    17);
0810            /** Maps from HTML value to a CSS value. Used in internal mapping. */
0811            private static final Hashtable htmlValueToCssValueMap = new Hashtable(
0812                    8);
0813            /** Maps from CSS value (string) to internal value. */
0814            private static final Hashtable cssValueToInternalValueMap = new Hashtable(
0815                    13);
0816
0817            static {
0818                // load the attribute map
0819                for (int i = 0; i < Attribute.allAttributes.length; i++) {
0820                    attributeMap.put(Attribute.allAttributes[i].toString(),
0821                            Attribute.allAttributes[i]);
0822                }
0823                // load the value map
0824                for (int i = 0; i < Value.allValues.length; i++) {
0825                    valueMap.put(Value.allValues[i].toString(),
0826                            Value.allValues[i]);
0827                }
0828
0829                htmlAttrToCssAttrMap.put(HTML.Attribute.COLOR,
0830                        new CSS.Attribute[] { CSS.Attribute.COLOR });
0831                htmlAttrToCssAttrMap.put(HTML.Attribute.TEXT,
0832                        new CSS.Attribute[] { CSS.Attribute.COLOR });
0833                htmlAttrToCssAttrMap.put(HTML.Attribute.CLEAR,
0834                        new CSS.Attribute[] { CSS.Attribute.CLEAR });
0835                htmlAttrToCssAttrMap.put(HTML.Attribute.BACKGROUND,
0836                        new CSS.Attribute[] { CSS.Attribute.BACKGROUND_IMAGE });
0837                htmlAttrToCssAttrMap.put(HTML.Attribute.BGCOLOR,
0838                        new CSS.Attribute[] { CSS.Attribute.BACKGROUND_COLOR });
0839                htmlAttrToCssAttrMap.put(HTML.Attribute.WIDTH,
0840                        new CSS.Attribute[] { CSS.Attribute.WIDTH });
0841                htmlAttrToCssAttrMap.put(HTML.Attribute.HEIGHT,
0842                        new CSS.Attribute[] { CSS.Attribute.HEIGHT });
0843                htmlAttrToCssAttrMap.put(HTML.Attribute.BORDER,
0844                        new CSS.Attribute[] { CSS.Attribute.BORDER_TOP_WIDTH,
0845                                CSS.Attribute.BORDER_RIGHT_WIDTH,
0846                                CSS.Attribute.BORDER_BOTTOM_WIDTH,
0847                                CSS.Attribute.BORDER_LEFT_WIDTH });
0848                htmlAttrToCssAttrMap.put(HTML.Attribute.CELLPADDING,
0849                        new CSS.Attribute[] { CSS.Attribute.PADDING });
0850                htmlAttrToCssAttrMap.put(HTML.Attribute.CELLSPACING,
0851                        new CSS.Attribute[] { CSS.Attribute.BORDER_SPACING });
0852                htmlAttrToCssAttrMap.put(HTML.Attribute.MARGINWIDTH,
0853                        new CSS.Attribute[] { CSS.Attribute.MARGIN_LEFT,
0854                                CSS.Attribute.MARGIN_RIGHT });
0855                htmlAttrToCssAttrMap.put(HTML.Attribute.MARGINHEIGHT,
0856                        new CSS.Attribute[] { CSS.Attribute.MARGIN_TOP,
0857                                CSS.Attribute.MARGIN_BOTTOM });
0858                htmlAttrToCssAttrMap.put(HTML.Attribute.HSPACE,
0859                        new CSS.Attribute[] { CSS.Attribute.PADDING_LEFT,
0860                                CSS.Attribute.PADDING_RIGHT });
0861                htmlAttrToCssAttrMap.put(HTML.Attribute.VSPACE,
0862                        new CSS.Attribute[] { CSS.Attribute.PADDING_BOTTOM,
0863                                CSS.Attribute.PADDING_TOP });
0864                htmlAttrToCssAttrMap.put(HTML.Attribute.FACE,
0865                        new CSS.Attribute[] { CSS.Attribute.FONT_FAMILY });
0866                htmlAttrToCssAttrMap.put(HTML.Attribute.SIZE,
0867                        new CSS.Attribute[] { CSS.Attribute.FONT_SIZE });
0868                htmlAttrToCssAttrMap.put(HTML.Attribute.VALIGN,
0869                        new CSS.Attribute[] { CSS.Attribute.VERTICAL_ALIGN });
0870                htmlAttrToCssAttrMap
0871                        .put(HTML.Attribute.ALIGN, new CSS.Attribute[] {
0872                                CSS.Attribute.VERTICAL_ALIGN,
0873                                CSS.Attribute.TEXT_ALIGN, CSS.Attribute.FLOAT });
0874                htmlAttrToCssAttrMap.put(HTML.Attribute.TYPE,
0875                        new CSS.Attribute[] { CSS.Attribute.LIST_STYLE_TYPE });
0876                htmlAttrToCssAttrMap.put(HTML.Attribute.NOWRAP,
0877                        new CSS.Attribute[] { CSS.Attribute.WHITE_SPACE });
0878
0879                // initialize StyleConstants mapping 
0880                styleConstantToCssMap.put(StyleConstants.FontFamily,
0881                        CSS.Attribute.FONT_FAMILY);
0882                styleConstantToCssMap.put(StyleConstants.FontSize,
0883                        CSS.Attribute.FONT_SIZE);
0884                styleConstantToCssMap.put(StyleConstants.Bold,
0885                        CSS.Attribute.FONT_WEIGHT);
0886                styleConstantToCssMap.put(StyleConstants.Italic,
0887                        CSS.Attribute.FONT_STYLE);
0888                styleConstantToCssMap.put(StyleConstants.Underline,
0889                        CSS.Attribute.TEXT_DECORATION);
0890                styleConstantToCssMap.put(StyleConstants.StrikeThrough,
0891                        CSS.Attribute.TEXT_DECORATION);
0892                styleConstantToCssMap.put(StyleConstants.Superscript,
0893                        CSS.Attribute.VERTICAL_ALIGN);
0894                styleConstantToCssMap.put(StyleConstants.Subscript,
0895                        CSS.Attribute.VERTICAL_ALIGN);
0896                styleConstantToCssMap.put(StyleConstants.Foreground,
0897                        CSS.Attribute.COLOR);
0898                styleConstantToCssMap.put(StyleConstants.Background,
0899                        CSS.Attribute.BACKGROUND_COLOR);
0900                styleConstantToCssMap.put(StyleConstants.FirstLineIndent,
0901                        CSS.Attribute.TEXT_INDENT);
0902                styleConstantToCssMap.put(StyleConstants.LeftIndent,
0903                        CSS.Attribute.MARGIN_LEFT);
0904                styleConstantToCssMap.put(StyleConstants.RightIndent,
0905                        CSS.Attribute.MARGIN_RIGHT);
0906                styleConstantToCssMap.put(StyleConstants.SpaceAbove,
0907                        CSS.Attribute.MARGIN_TOP);
0908                styleConstantToCssMap.put(StyleConstants.SpaceBelow,
0909                        CSS.Attribute.MARGIN_BOTTOM);
0910                styleConstantToCssMap.put(StyleConstants.Alignment,
0911                        CSS.Attribute.TEXT_ALIGN);
0912
0913                // HTML->CSS
0914                htmlValueToCssValueMap.put("disc", CSS.Value.DISC);
0915                htmlValueToCssValueMap.put("square", CSS.Value.SQUARE);
0916                htmlValueToCssValueMap.put("circle", CSS.Value.CIRCLE);
0917                htmlValueToCssValueMap.put("1", CSS.Value.DECIMAL);
0918                htmlValueToCssValueMap.put("a", CSS.Value.LOWER_ALPHA);
0919                htmlValueToCssValueMap.put("A", CSS.Value.UPPER_ALPHA);
0920                htmlValueToCssValueMap.put("i", CSS.Value.LOWER_ROMAN);
0921                htmlValueToCssValueMap.put("I", CSS.Value.UPPER_ROMAN);
0922
0923                // CSS-> internal CSS
0924                cssValueToInternalValueMap.put("none", CSS.Value.NONE);
0925                cssValueToInternalValueMap.put("disc", CSS.Value.DISC);
0926                cssValueToInternalValueMap.put("square", CSS.Value.SQUARE);
0927                cssValueToInternalValueMap.put("circle", CSS.Value.CIRCLE);
0928                cssValueToInternalValueMap.put("decimal", CSS.Value.DECIMAL);
0929                cssValueToInternalValueMap.put("lower-roman",
0930                        CSS.Value.LOWER_ROMAN);
0931                cssValueToInternalValueMap.put("upper-roman",
0932                        CSS.Value.UPPER_ROMAN);
0933                cssValueToInternalValueMap.put("lower-alpha",
0934                        CSS.Value.LOWER_ALPHA);
0935                cssValueToInternalValueMap.put("upper-alpha",
0936                        CSS.Value.UPPER_ALPHA);
0937                cssValueToInternalValueMap.put("repeat",
0938                        CSS.Value.BACKGROUND_REPEAT);
0939                cssValueToInternalValueMap.put("no-repeat",
0940                        CSS.Value.BACKGROUND_NO_REPEAT);
0941                cssValueToInternalValueMap.put("repeat-x",
0942                        CSS.Value.BACKGROUND_REPEAT_X);
0943                cssValueToInternalValueMap.put("repeat-y",
0944                        CSS.Value.BACKGROUND_REPEAT_Y);
0945                cssValueToInternalValueMap.put("scroll",
0946                        CSS.Value.BACKGROUND_SCROLL);
0947                cssValueToInternalValueMap.put("fixed",
0948                        CSS.Value.BACKGROUND_FIXED);
0949
0950                // Register all the CSS attribute keys for archival/unarchival
0951                Object[] keys = CSS.Attribute.allAttributes;
0952                try {
0953                    for (int i = 0; i < keys.length; i++) {
0954                        StyleContext.registerStaticAttributeKey(keys[i]);
0955                    }
0956                } catch (Throwable e) {
0957                    e.printStackTrace();
0958                }
0959
0960                // Register all the CSS Values for archival/unarchival
0961                keys = CSS.Value.allValues;
0962                try {
0963                    for (int i = 0; i < keys.length; i++) {
0964                        StyleContext.registerStaticAttributeKey(keys[i]);
0965                    }
0966                } catch (Throwable e) {
0967                    e.printStackTrace();
0968                }
0969            }
0970
0971            /**
0972             * Return the set of all possible CSS attribute keys.
0973             */
0974            public static Attribute[] getAllAttributeKeys() {
0975                Attribute[] keys = new Attribute[Attribute.allAttributes.length];
0976                System.arraycopy(Attribute.allAttributes, 0, keys, 0,
0977                        Attribute.allAttributes.length);
0978                return keys;
0979            }
0980
0981            /**
0982             * Translates a string to a <code>CSS.Attribute</code> object.
0983             * This will return <code>null</code> if there is no attribute
0984             * by the given name.
0985             *
0986             * @param name the name of the CSS attribute to fetch the
0987             *  typesafe enumeration for
0988             * @return the <code>CSS.Attribute</code> object,
0989             *  or <code>null</code> if the string
0990             *  doesn't represent a valid attribute key
0991             */
0992            public static final Attribute getAttribute(String name) {
0993                return (Attribute) attributeMap.get(name);
0994            }
0995
0996            /**
0997             * Translates a string to a <code>CSS.Value</code> object.
0998             * This will return <code>null</code> if there is no value
0999             * by the given name.
1000             *
1001             * @param name the name of the CSS value to fetch the
1002             *  typesafe enumeration for
1003             * @return the <code>CSS.Value</code> object, 
1004             *  or <code>null</code> if the string
1005             *  doesn't represent a valid CSS value name; this does
1006             *  not mean that it doesn't represent a valid CSS value
1007             */
1008            static final Value getValue(String name) {
1009                return (Value) valueMap.get(name);
1010            }
1011
1012            //
1013            // Conversion related methods/classes
1014            //
1015
1016            /**
1017             * Returns a URL for the given CSS url string. If relative,
1018             * <code>base</code> is used as the parent. If a valid URL can not
1019             * be found, this will not throw a MalformedURLException, instead 
1020             * null will be returned.
1021             */
1022            static URL getURL(URL base, String cssString) {
1023                if (cssString == null) {
1024                    return null;
1025                }
1026                if (cssString.startsWith("url(") && cssString.endsWith(")")) {
1027                    cssString = cssString.substring(4, cssString.length() - 1);
1028                }
1029                // Absolute first
1030                try {
1031                    URL url = new URL(cssString);
1032                    if (url != null) {
1033                        return url;
1034                    }
1035                } catch (MalformedURLException mue) {
1036                }
1037                // Then relative
1038                if (base != null) {
1039                    // Relative URL, try from base
1040                    try {
1041                        URL url = new URL(base, cssString);
1042                        return url;
1043                    } catch (MalformedURLException muee) {
1044                    }
1045                }
1046                return null;
1047            }
1048
1049            /**
1050             * Converts a type Color to a hex string
1051             * in the format "#RRGGBB"
1052             */
1053            static String colorToHex(Color color) {
1054
1055                String colorstr = new String("#");
1056
1057                // Red
1058                String str = Integer.toHexString(color.getRed());
1059                if (str.length() > 2)
1060                    str = str.substring(0, 2);
1061                else if (str.length() < 2)
1062                    colorstr += "0" + str;
1063                else
1064                    colorstr += str;
1065
1066                // Green
1067                str = Integer.toHexString(color.getGreen());
1068                if (str.length() > 2)
1069                    str = str.substring(0, 2);
1070                else if (str.length() < 2)
1071                    colorstr += "0" + str;
1072                else
1073                    colorstr += str;
1074
1075                // Blue
1076                str = Integer.toHexString(color.getBlue());
1077                if (str.length() > 2)
1078                    str = str.substring(0, 2);
1079                else if (str.length() < 2)
1080                    colorstr += "0" + str;
1081                else
1082                    colorstr += str;
1083
1084                return colorstr;
1085            }
1086
1087            /**
1088             * Convert a "#FFFFFF" hex string to a Color.
1089             * If the color specification is bad, an attempt
1090             * will be made to fix it up.
1091             */
1092            static final Color hexToColor(String value) {
1093                String digits;
1094                int n = value.length();
1095                if (value.startsWith("#")) {
1096                    digits = value.substring(1, Math.min(value.length(), 7));
1097                } else {
1098                    digits = value;
1099                }
1100                String hstr = "0x" + digits;
1101                Color c;
1102                try {
1103                    c = Color.decode(hstr);
1104                } catch (NumberFormatException nfe) {
1105                    c = null;
1106                }
1107                return c;
1108            }
1109
1110            /**
1111             * Convert a color string such as "RED" or "#NNNNNN" or "rgb(r, g, b)"
1112             * to a Color.
1113             */
1114            static Color stringToColor(String str) {
1115                Color color = null;
1116
1117                if (str.length() == 0)
1118                    color = Color.black;
1119                else if (str.startsWith("rgb(")) {
1120                    color = parseRGB(str);
1121                } else if (str.charAt(0) == '#')
1122                    color = hexToColor(str);
1123                else if (str.equalsIgnoreCase("Black"))
1124                    color = hexToColor("#000000");
1125                else if (str.equalsIgnoreCase("Silver"))
1126                    color = hexToColor("#C0C0C0");
1127                else if (str.equalsIgnoreCase("Gray"))
1128                    color = hexToColor("#808080");
1129                else if (str.equalsIgnoreCase("White"))
1130                    color = hexToColor("#FFFFFF");
1131                else if (str.equalsIgnoreCase("Maroon"))
1132                    color = hexToColor("#800000");
1133                else if (str.equalsIgnoreCase("Red"))
1134                    color = hexToColor("#FF0000");
1135                else if (str.equalsIgnoreCase("Purple"))
1136                    color = hexToColor("#800080");
1137                else if (str.equalsIgnoreCase("Fuchsia"))
1138                    color = hexToColor("#FF00FF");
1139                else if (str.equalsIgnoreCase("Green"))
1140                    color = hexToColor("#008000");
1141                else if (str.equalsIgnoreCase("Lime"))
1142                    color = hexToColor("#00FF00");
1143                else if (str.equalsIgnoreCase("Olive"))
1144                    color = hexToColor("#808000");
1145                else if (str.equalsIgnoreCase("Yellow"))
1146                    color = hexToColor("#FFFF00");
1147                else if (str.equalsIgnoreCase("Navy"))
1148                    color = hexToColor("#000080");
1149                else if (str.equalsIgnoreCase("Blue"))
1150                    color = hexToColor("#0000FF");
1151                else if (str.equalsIgnoreCase("Teal"))
1152                    color = hexToColor("#008080");
1153                else if (str.equalsIgnoreCase("Aqua"))
1154                    color = hexToColor("#00FFFF");
1155                else
1156                    color = hexToColor(str); // sometimes get specified without leading #
1157                return color;
1158            }
1159
1160            /**
1161             * Parses a String in the format <code>rgb(r, g, b)</code> where
1162             * each of the Color components is either an integer, or a floating number
1163             * with a % after indicating a percentage value of 255. Values are
1164             * constrained to fit with 0-255. The resulting Color is returned.
1165             */
1166            private static Color parseRGB(String string) {
1167                // Find the next numeric char
1168                int[] index = new int[1];
1169
1170                index[0] = 4;
1171                int red = getColorComponent(string, index);
1172                int green = getColorComponent(string, index);
1173                int blue = getColorComponent(string, index);
1174
1175                return new Color(red, green, blue);
1176            }
1177
1178            /**
1179             * Returns the next integer value from <code>string</code> starting
1180             * at <code>index[0]</code>. The value can either can an integer, or
1181             * a percentage (floating number ending with %), in which case it is
1182             * multiplied by 255.
1183             */
1184            private static int getColorComponent(String string, int[] index) {
1185                int length = string.length();
1186                char aChar;
1187
1188                // Skip non-decimal chars
1189                while (index[0] < length
1190                        && (aChar = string.charAt(index[0])) != '-'
1191                        && !Character.isDigit(aChar) && aChar != '.') {
1192                    index[0]++;
1193                }
1194
1195                int start = index[0];
1196
1197                if (start < length && string.charAt(index[0]) == '-') {
1198                    index[0]++;
1199                }
1200                while (index[0] < length
1201                        && Character.isDigit(string.charAt(index[0]))) {
1202                    index[0]++;
1203                }
1204                if (index[0] < length && string.charAt(index[0]) == '.') {
1205                    // Decimal value
1206                    index[0]++;
1207                    while (index[0] < length
1208                            && Character.isDigit(string.charAt(index[0]))) {
1209                        index[0]++;
1210                    }
1211                }
1212                if (start != index[0]) {
1213                    try {
1214                        float value = Float.parseFloat(string.substring(start,
1215                                index[0]));
1216
1217                        if (index[0] < length && string.charAt(index[0]) == '%') {
1218                            index[0]++;
1219                            value = value * 255f / 100f;
1220                        }
1221                        return Math.min(255, Math.max(0, (int) value));
1222                    } catch (NumberFormatException nfe) {
1223                        // Treat as 0
1224                    }
1225                }
1226                return 0;
1227            }
1228
1229            static int getIndexOfSize(float pt, int[] sizeMap) {
1230                for (int i = 0; i < sizeMap.length; i++)
1231                    if (pt <= sizeMap[i])
1232                        return i + 1;
1233                return sizeMap.length;
1234            }
1235
1236            static int getIndexOfSize(float pt, StyleSheet ss) {
1237                int[] sizeMap = (ss != null) ? ss.getSizeMap()
1238                        : StyleSheet.sizeMapDefault;
1239                return getIndexOfSize(pt, sizeMap);
1240            }
1241
1242            /**
1243             * @return an array of all the strings in <code>value</code>
1244             *         that are separated by whitespace.
1245             */
1246            static String[] parseStrings(String value) {
1247                int current, last;
1248                int length = (value == null) ? 0 : value.length();
1249                Vector temp = new Vector(4);
1250
1251                current = 0;
1252                while (current < length) {
1253                    // Skip ws
1254                    while (current < length
1255                            && Character.isWhitespace(value.charAt(current))) {
1256                        current++;
1257                    }
1258                    last = current;
1259                    while (current < length
1260                            && !Character.isWhitespace(value.charAt(current))) {
1261                        current++;
1262                    }
1263                    if (last != current) {
1264                        temp.addElement(value.substring(last, current));
1265                    }
1266                    current++;
1267                }
1268                String[] retValue = new String[temp.size()];
1269                temp.copyInto(retValue);
1270                return retValue;
1271            }
1272
1273            /**
1274             * Return the point size, given a size index. Legal HTML index sizes
1275             * are 1-7.
1276             */
1277            float getPointSize(int index, StyleSheet ss) {
1278                ss = getStyleSheet(ss);
1279                int[] sizeMap = (ss != null) ? ss.getSizeMap()
1280                        : StyleSheet.sizeMapDefault;
1281                --index;
1282                if (index < 0)
1283                    return sizeMap[0];
1284                else if (index > sizeMap.length - 1)
1285                    return sizeMap[sizeMap.length - 1];
1286                else
1287                    return sizeMap[index];
1288            }
1289
1290            private void translateEmbeddedAttributes(AttributeSet htmlAttrSet,
1291                    MutableAttributeSet cssAttrSet) {
1292                Enumeration keys = htmlAttrSet.getAttributeNames();
1293                if (htmlAttrSet.getAttribute(StyleConstants.NameAttribute) == HTML.Tag.HR) {
1294                    // HR needs special handling due to us treating it as a leaf.
1295                    translateAttributes(HTML.Tag.HR, htmlAttrSet, cssAttrSet);
1296                }
1297                while (keys.hasMoreElements()) {
1298                    Object key = keys.nextElement();
1299                    if (key instanceof  HTML.Tag) {
1300                        HTML.Tag tag = (HTML.Tag) key;
1301                        Object o = htmlAttrSet.getAttribute(tag);
1302                        if (o != null && o instanceof  AttributeSet) {
1303                            translateAttributes(tag, (AttributeSet) o,
1304                                    cssAttrSet);
1305                        }
1306                    } else if (key instanceof  CSS.Attribute) {
1307                        cssAttrSet.addAttribute(key, htmlAttrSet
1308                                .getAttribute(key));
1309                    }
1310                }
1311            }
1312
1313            private void translateAttributes(HTML.Tag tag,
1314                    AttributeSet htmlAttrSet, MutableAttributeSet cssAttrSet) {
1315                Enumeration names = htmlAttrSet.getAttributeNames();
1316                while (names.hasMoreElements()) {
1317                    Object name = names.nextElement();
1318
1319                    if (name instanceof  HTML.Attribute) {
1320                        HTML.Attribute key = (HTML.Attribute) name;
1321
1322                        /*
1323                         * HTML.Attribute.ALIGN needs special processing.
1324                         * It can map to to 1 of many(3) possible CSS attributes
1325                         * depending on the nature of the tag the attribute is
1326                         * part off and depending on the value of the attribute.
1327                         */
1328                        if (key == HTML.Attribute.ALIGN) {
1329                            String htmlAttrValue = (String) htmlAttrSet
1330                                    .getAttribute(HTML.Attribute.ALIGN);
1331                            if (htmlAttrValue != null) {
1332                                CSS.Attribute cssAttr = getCssAlignAttribute(
1333                                        tag, htmlAttrSet);
1334                                if (cssAttr != null) {
1335                                    Object o = getCssValue(cssAttr,
1336                                            htmlAttrValue);
1337                                    if (o != null) {
1338                                        cssAttrSet.addAttribute(cssAttr, o);
1339                                    }
1340                                }
1341                            }
1342                        } else {
1343
1344                            /*
1345                             * The html size attribute has a mapping in the CSS world only
1346                             * if it is par of a font or base font tag.
1347                             */
1348
1349                            if (key == HTML.Attribute.SIZE
1350                                    && !isHTMLFontTag(tag)) {
1351                                continue;
1352                            }
1353
1354                            translateAttribute(key, htmlAttrSet, cssAttrSet);
1355                        }
1356                    } else if (name instanceof  CSS.Attribute) {
1357                        cssAttrSet.addAttribute(name, htmlAttrSet
1358                                .getAttribute(name));
1359                    }
1360                }
1361            }
1362
1363            private void translateAttribute(HTML.Attribute key,
1364                    AttributeSet htmlAttrSet, MutableAttributeSet cssAttrSet) {
1365                /*
1366                 * In the case of all remaining HTML.Attribute's they
1367                 * map to 1 or more CCS.Attribute.
1368                 */
1369                CSS.Attribute[] cssAttrList = getCssAttribute(key);
1370
1371                String htmlAttrValue = (String) htmlAttrSet.getAttribute(key);
1372
1373                if (cssAttrList == null || htmlAttrValue == null) {
1374                    return;
1375                }
1376                for (int i = 0; i < cssAttrList.length; i++) {
1377                    Object o = getCssValue(cssAttrList[i], htmlAttrValue);
1378                    if (o != null) {
1379                        cssAttrSet.addAttribute(cssAttrList[i], o);
1380                    }
1381                }
1382            }
1383
1384            /**
1385             * Given a CSS.Attribute object and its corresponding HTML.Attribute's
1386             * value, this method returns a CssValue object to associate with the
1387             * CSS attribute.
1388             *
1389             * @param the CSS.Attribute
1390             * @param a String containing the value associated HTML.Attribtue.
1391             */
1392            Object getCssValue(CSS.Attribute cssAttr, String htmlAttrValue) {
1393                CssValue value = (CssValue) valueConvertor.get(cssAttr);
1394                Object o = value.parseHtmlValue(htmlAttrValue);
1395                return o;
1396            }
1397
1398            /**
1399             * Maps an HTML.Attribute object to its appropriate CSS.Attributes.
1400             *
1401             * @param HTML.Attribute
1402             * @return CSS.Attribute[]
1403             */
1404            private CSS.Attribute[] getCssAttribute(HTML.Attribute hAttr) {
1405                return (CSS.Attribute[]) htmlAttrToCssAttrMap.get(hAttr);
1406            }
1407
1408            /**
1409             * Maps HTML.Attribute.ALIGN to either:
1410             *     CSS.Attribute.TEXT_ALIGN
1411             *     CSS.Attribute.FLOAT
1412             *     CSS.Attribute.VERTICAL_ALIGN
1413             * based on the tag associated with the attribute and the
1414             * value of the attribute.
1415             *
1416             * @param AttributeSet containing HTML attributes.
1417             * @return CSS.Attribute mapping for HTML.Attribute.ALIGN.
1418             */
1419            private CSS.Attribute getCssAlignAttribute(HTML.Tag tag,
1420                    AttributeSet htmlAttrSet) {
1421                return CSS.Attribute.TEXT_ALIGN;
1422                /*
1423                 String htmlAttrValue = (String)htmlAttrSet.getAttribute(HTML.Attribute.ALIGN);
1424                 CSS.Attribute cssAttr = CSS.Attribute.TEXT_ALIGN;
1425                 if (htmlAttrValue != null && htmlAttrSet instanceof Element) {
1426                 Element elem = (Element)htmlAttrSet;
1427                 if (!elem.isLeaf() && tag.isBlock() && validTextAlignValue(htmlAttrValue)) {
1428                 return CSS.Attribute.TEXT_ALIGN;
1429                 } else if (isFloater(htmlAttrValue)) {
1430                 return CSS.Attribute.FLOAT;
1431                 } else if (elem.isLeaf()) {
1432                 return CSS.Attribute.VERTICAL_ALIGN;
1433                 }
1434                 }
1435                 return null;
1436                 */
1437            }
1438
1439            /**
1440             * Fetches the tag associated with the HTML AttributeSet.
1441             *
1442             * @param  AttributeSet containing the HTML attributes.
1443             * @return HTML.Tag
1444             */
1445            private HTML.Tag getHTMLTag(AttributeSet htmlAttrSet) {
1446                Object o = htmlAttrSet
1447                        .getAttribute(StyleConstants.NameAttribute);
1448                if (o instanceof  HTML.Tag) {
1449                    HTML.Tag tag = (HTML.Tag) o;
1450                    return tag;
1451                }
1452                return null;
1453            }
1454
1455            private boolean isHTMLFontTag(HTML.Tag tag) {
1456                return (tag != null && ((tag == HTML.Tag.FONT) || (tag == HTML.Tag.BASEFONT)));
1457            }
1458
1459            private boolean isFloater(String alignValue) {
1460                return (alignValue.equals("left") || alignValue.equals("right"));
1461            }
1462
1463            private boolean validTextAlignValue(String alignValue) {
1464                return (isFloater(alignValue) || alignValue.equals("center"));
1465            }
1466
1467            /**
1468             * Base class to CSS values in the attribute sets.  This
1469             * is intended to act as a convertor to/from other attribute
1470             * formats.
1471             * <p>
1472             * The CSS parser uses the parseCssValue method to convert
1473             * a string to whatever format is appropriate a given key
1474             * (i.e. these convertors are stored in a map using the
1475             * CSS.Attribute as a key and the CssValue as the value).
1476             * <p>
1477             * The HTML to CSS conversion process first converts the
1478             * HTML.Attribute to a CSS.Attribute, and then calls
1479             * the parseHtmlValue method on the value of the HTML
1480             * attribute to produce the corresponding CSS value.
1481             * <p>
1482             * The StyleConstants to CSS conversion process first 
1483             * converts the StyleConstants attribute to a 
1484             * CSS.Attribute, and then calls the fromStyleConstants
1485             * method to convert the StyleConstants value to a 
1486             * CSS value.
1487             * <p>
1488             * The CSS to StyleConstants conversion process first
1489             * converts the StyleConstants attribute to a 
1490             * CSS.Attribute, and then calls the toStyleConstants
1491             * method to convert the CSS value to a StyleConstants
1492             * value.
1493             */
1494            static class CssValue implements  Serializable {
1495
1496                /**
1497                 * Convert a CSS value string to the internal format
1498                 * (for fast processing) used in the attribute sets.
1499                 * The fallback storage for any value that we don't
1500                 * have a special binary format for is a String. 
1501                 */
1502                Object parseCssValue(String value) {
1503                    return value;
1504                }
1505
1506                /**
1507                 * Convert an HTML attribute value to a CSS attribute
1508                 * value.  If there is no conversion, return null.
1509                 * This is implemented to simply forward to the CSS
1510                 * parsing by default (since some of the attribute
1511                 * values are the same).  If the attribute value
1512                 * isn't recognized as a CSS value it is generally
1513                 * returned as null.
1514                 */
1515                Object parseHtmlValue(String value) {
1516                    return parseCssValue(value);
1517                }
1518
1519                /**
1520                 * Converts a <code>StyleConstants</code> attribute value to
1521                 * a CSS attribute value.  If there is no conversion,
1522                 * returns <code>null</code>.  By default, there is no conversion.
1523                 * 
1524                 * @param key the <code>StyleConstants</code> attribute
1525                 * @param value the value of a <code>StyleConstants</code>
1526                 *   attribute to be converted
1527                 * @return the CSS value that represents the 
1528                 *   <code>StyleConstants</code> value
1529                 */
1530                Object fromStyleConstants(StyleConstants key, Object value) {
1531                    return null;
1532                }
1533
1534                /**
1535                 * Converts a CSS attribute value to a 
1536                 * <code>StyleConstants</code>
1537                 * value.  If there is no conversion, returns
1538                 * <code>null</code>.
1539                 * By default, there is no conversion.
1540                 *
1541                 * @param key the <code>StyleConstants</code> attribute
1542                 * @param v the view containing <code>AttributeSet</code>
1543                 * @return the <code>StyleConstants</code> attribute value that 
1544                 *   represents the CSS attribute value
1545                 */
1546                Object toStyleConstants(StyleConstants key, View v) {
1547                    return null;
1548                }
1549
1550                /**
1551                 * Return the CSS format of the value
1552                 */
1553                public String toString() {
1554                    return svalue;
1555                }
1556
1557                /**
1558                 * The value as a string... before conversion to a
1559                 * binary format.
1560                 */
1561                String svalue;
1562            }
1563
1564            /**
1565             * By default CSS attributes are represented as simple
1566             * strings.  They also have no conversion to/from
1567             * StyleConstants by default. This class represents the 
1568             * value as a string (via the superclass), but 
1569             * provides StyleConstants conversion support for the 
1570             * CSS attributes that are held as strings.
1571             */
1572            static class StringValue extends CssValue {
1573
1574                /**
1575                 * Convert a CSS value string to the internal format
1576                 * (for fast processing) used in the attribute sets.
1577                 * This produces a StringValue, so that it can be
1578                 * used to convert from CSS to StyleConstants values.
1579                 */
1580                Object parseCssValue(String value) {
1581                    StringValue sv = new StringValue();
1582                    sv.svalue = value;
1583                    return sv;
1584                }
1585
1586                /**
1587                 * Converts a <code>StyleConstants</code> attribute value to
1588                 * a CSS attribute value.  If there is no conversion
1589                 * returns <code>null</code>. 
1590                 * 
1591                 * @param key the <code>StyleConstants</code> attribute
1592                 * @param value the value of a <code>StyleConstants</code>
1593                 *   attribute to be converted
1594                 * @return the CSS value that represents the 
1595                 *   <code>StyleConstants</code> value
1596                 */
1597                Object fromStyleConstants(StyleConstants key, Object value) {
1598                    if (key == StyleConstants.Italic) {
1599                        if (value.equals(Boolean.TRUE)) {
1600                            return parseCssValue("italic");
1601                        }
1602                        return parseCssValue("");
1603                    } else if (key == StyleConstants.Underline) {
1604                        if (value.equals(Boolean.TRUE)) {
1605                            return parseCssValue("underline");
1606                        }
1607                        return parseCssValue("");
1608                    } else if (key == StyleConstants.Alignment) {
1609                        int align = ((Integer) value).intValue();
1610                        String ta;
1611                        switch (align) {
1612                        case StyleConstants.ALIGN_LEFT:
1613                            ta = "left";
1614                            break;
1615                        case StyleConstants.ALIGN_RIGHT:
1616                            ta = "right";
1617                            break;
1618                        case StyleConstants.ALIGN_CENTER:
1619                            ta = "center";
1620                            break;
1621                        case StyleConstants.ALIGN_JUSTIFIED:
1622                            ta = "justify";
1623                            break;
1624                        default:
1625                            ta = "left";
1626                        }
1627                        return parseCssValue(ta);
1628                    } else if (key == StyleConstants.StrikeThrough) {
1629                        if (value.equals(Boolean.TRUE)) {
1630                            return parseCssValue("line-through");
1631                        }
1632                        return parseCssValue("");
1633                    } else if (key == StyleConstants.Superscript) {
1634                        if (value.equals(Boolean.TRUE)) {
1635                            return parseCssValue("super");
1636                        }
1637                        return parseCssValue("");
1638                    } else if (key == StyleConstants.Subscript) {
1639                        if (value.equals(Boolean.TRUE)) {
1640                            return parseCssValue("sub");
1641                        }
1642                        return parseCssValue("");
1643                    }
1644                    return null;
1645                }
1646
1647                /**
1648                 * Converts a CSS attribute value to a 
1649                 * <code>StyleConstants</code> value. 
1650                 * If there is no conversion, returns <code>null</code>.
1651                 * By default, there is no conversion.
1652                 *
1653                 * @param key the <code>StyleConstants</code> attribute
1654                 * @return the <code>StyleConstants</code> attribute value that 
1655                 *   represents the CSS attribute value
1656                 */
1657                Object toStyleConstants(StyleConstants key, View v) {
1658                    if (key == StyleConstants.Italic) {
1659                        if (svalue.indexOf("italic") >= 0) {
1660                            return Boolean.TRUE;
1661                        }
1662                        return Boolean.FALSE;
1663                    } else if (key == StyleConstants.Underline) {
1664                        if (svalue.indexOf("underline") >= 0) {
1665                            return Boolean.TRUE;
1666                        }
1667                        return Boolean.FALSE;
1668                    } else if (key == StyleConstants.Alignment) {
1669                        if (svalue.equals("right")) {
1670                            return new Integer(StyleConstants.ALIGN_RIGHT);
1671                        } else if (svalue.equals("center")) {
1672                            return new Integer(StyleConstants.ALIGN_CENTER);
1673                        } else if (svalue.equals("justify")) {
1674                            return new Integer(StyleConstants.ALIGN_JUSTIFIED);
1675                        }
1676                        return new Integer(StyleConstants.ALIGN_LEFT);
1677                    } else if (key == StyleConstants.StrikeThrough) {
1678                        if (svalue.indexOf("line-through") >= 0) {
1679                            return Boolean.TRUE;
1680                        }
1681                        return Boolean.FALSE;
1682                    } else if (key == StyleConstants.Superscript) {
1683                        if (svalue.indexOf("super") >= 0) {
1684                            return Boolean.TRUE;
1685                        }
1686                        return Boolean.FALSE;
1687                    } else if (key == StyleConstants.Subscript) {
1688                        if (svalue.indexOf("sub") >= 0) {
1689                            return Boolean.TRUE;
1690                        }
1691                        return Boolean.FALSE;
1692                    }
1693                    return null;
1694                }
1695
1696                // Used by ViewAttributeSet
1697                boolean isItalic() {
1698                    return (svalue.indexOf("italic") != -1);
1699                }
1700
1701                boolean isStrike() {
1702                    return (svalue.indexOf("line-through") != -1);
1703                }
1704
1705                boolean isUnderline() {
1706                    return (svalue.indexOf("underline") != -1);
1707                }
1708
1709                boolean isSub() {
1710                    return (svalue.indexOf("sub") != -1);
1711                }
1712
1713                boolean isSup() {
1714                    return (svalue.indexOf("sup") != -1);
1715                }
1716            }
1717
1718            /**
1719             * Represents a value for the CSS.FONT_SIZE attribute.
1720             * The binary format of the value can be one of several
1721             * types.  If the type is Float,
1722             * the value is specified in terms of point or
1723             * percentage, depending upon the ending of the
1724             * associated string.
1725             * If the type is Integer, the value is specified
1726             * in terms of a size index.
1727             */
1728            class FontSize extends CssValue {
1729
1730                /**
1731                 * Returns the size in points.  This is ultimately
1732                 * what we need for the purpose of creating/fetching
1733                 * a Font object.
1734                 *
1735                 * @param a the attribute set the value is being
1736                 *  requested from.  We may need to walk up the
1737                 *  resolve hierarchy if it's relative.
1738                 */
1739                int getValue(AttributeSet a, StyleSheet ss) {
1740                    ss = getStyleSheet(ss);
1741                    if (index) {
1742                        // it's an index, translate from size table
1743                        return Math.round(getPointSize((int) value, ss));
1744                    } else if (lu == null) {
1745                        return Math.round(value);
1746                    } else {
1747                        if (lu.type == 0) {
1748                            boolean isW3CLengthUnits = (ss == null) ? false
1749                                    : ss.isW3CLengthUnits();
1750                            return Math.round(lu.getValue(isW3CLengthUnits));
1751                        }
1752                        if (a != null) {
1753                            AttributeSet resolveParent = a.getResolveParent();
1754
1755                            if (resolveParent != null) {
1756                                int pValue = StyleConstants
1757                                        .getFontSize(resolveParent);
1758
1759                                float retValue;
1760                                if (lu.type == 1 || lu.type == 3) {
1761                                    retValue = lu.value * (float) pValue;
1762                                } else {
1763                                    retValue = lu.value + (float) pValue;
1764                                }
1765                                return Math.round(retValue);
1766                            }
1767                        }
1768                        // a is null, or no resolve parent.
1769                        return 12;
1770                    }
1771                }
1772
1773                Object parseCssValue(String value) {
1774                    FontSize fs = new FontSize();
1775                    fs.svalue = value;
1776                    try {
1777                        if (value.equals("xx-small")) {
1778                            fs.value = 1;
1779                            fs.index = true;
1780                        } else if (value.equals("x-small")) {
1781                            fs.value = 2;
1782                            fs.index = true;
1783                        } else if (value.equals("small")) {
1784                            fs.value = 3;
1785                            fs.index = true;
1786                        } else if (value.equals("medium")) {
1787                            fs.value = 4;
1788                            fs.index = true;
1789                        } else if (value.equals("large")) {
1790                            fs.value = 5;
1791                            fs.index = true;
1792                        } else if (value.equals("x-large")) {
1793                            fs.value = 6;
1794                            fs.index = true;
1795                        } else if (value.equals("xx-large")) {
1796                            fs.value = 7;
1797                            fs.index = true;
1798                        } else {
1799                            fs.lu = new LengthUnit(value, (short) 1, 1f);
1800                        }
1801                        // relative sizes, larger | smaller (adjust from parent by
1802                        // 1.5 pixels)
1803                        // em, ex refer to parent sizes
1804                        // lengths: pt, mm, cm, pc, in, px
1805                        //          em (font height 3em would be 3 times font height)
1806                        //          ex (height of X)
1807                        // lengths are (+/-) followed by a number and two letter
1808                        // unit identifier
1809                    } catch (NumberFormatException nfe) {
1810                        fs = null;
1811                    }
1812                    return fs;
1813                }
1814
1815                Object parseHtmlValue(String value) {
1816                    if ((value == null) || (value.length() == 0)) {
1817                        return null;
1818                    }
1819                    FontSize fs = new FontSize();
1820                    fs.svalue = value;
1821
1822                    try {
1823                        /*
1824                         * relative sizes in the size attribute are relative
1825                         * to the <basefont>'s size.
1826                         */
1827                        int baseFontSize = getBaseFontSize();
1828                        if (value.charAt(0) == '+') {
1829                            int relSize = Integer.valueOf(value.substring(1))
1830                                    .intValue();
1831                            fs.value = baseFontSize + relSize;
1832                            fs.index = true;
1833                        } else if (value.charAt(0) == '-') {
1834                            int relSize = -Integer.valueOf(value.substring(1))
1835                                    .intValue();
1836                            fs.value = baseFontSize + relSize;
1837                            fs.index = true;
1838                        } else {
1839                            fs.value = Integer.parseInt(value);
1840                            if (fs.value > 7) {
1841                                fs.value = 7;
1842                            } else if (fs.value < 0) {
1843                                fs.value = 0;
1844                            }
1845                            fs.index = true;
1846                        }
1847
1848                    } catch (NumberFormatException nfe) {
1849                        fs = null;
1850                    }
1851                    return fs;
1852                }
1853
1854                /**
1855                 * Converts a <code>StyleConstants</code> attribute value to
1856                 * a CSS attribute value.  If there is no conversion
1857                 * returns <code>null</code>.  By default, there is no conversion.
1858                 * 
1859                 * @param key the <code>StyleConstants</code> attribute
1860                 * @param value the value of a <code>StyleConstants</code>
1861                 *   attribute to be converted
1862                 * @return the CSS value that represents the 
1863                 *   <code>StyleConstants</code> value
1864                 */
1865                Object fromStyleConstants(StyleConstants key, Object value) {
1866                    if (value instanceof  Number) {
1867                        FontSize fs = new FontSize();
1868
1869                        fs.value = getIndexOfSize(
1870                                ((Number) value).floatValue(),
1871                                StyleSheet.sizeMapDefault);
1872                        fs.svalue = Integer.toString((int) fs.value);
1873                        fs.index = true;
1874                        return fs;
1875                    }
1876                    return parseCssValue(value.toString());
1877                }
1878
1879                /**
1880                 * Converts a CSS attribute value to a <code>StyleConstants</code>
1881                 * value.  If there is no conversion, returns <code>null</code>.
1882                 * By default, there is no conversion.
1883                 *
1884                 * @param key the <code>StyleConstants</code> attribute
1885                 * @return the <code>StyleConstants</code> attribute value that 
1886                 *   represents the CSS attribute value
1887                 */
1888                Object toStyleConstants(StyleConstants key, View v) {
1889                    if (v != null) {
1890                        return Integer
1891                                .valueOf(getValue(v.getAttributes(), null));
1892                    }
1893                    return Integer.valueOf(getValue(null, null));
1894                }
1895
1896                float value;
1897                boolean index;
1898                LengthUnit lu;
1899            }
1900
1901            static class FontFamily extends CssValue {
1902
1903                /**
1904                 * Returns the font family to use.
1905                 */
1906                String getValue() {
1907                    return family;
1908                }
1909
1910                Object parseCssValue(String value) {
1911                    int cIndex = value.indexOf(',');
1912                    FontFamily ff = new FontFamily();
1913                    ff.svalue = value;
1914                    ff.family = null;
1915
1916                    if (cIndex == -1) {
1917                        setFontName(ff, value);
1918                    } else {
1919                        boolean done = false;
1920                        int lastIndex;
1921                        int length = value.length();
1922                        cIndex = 0;
1923                        while (!done) {
1924                            // skip ws.
1925                            while (cIndex < length
1926                                    && Character.isWhitespace(value
1927                                            .charAt(cIndex)))
1928                                cIndex++;
1929                            // Find next ','
1930                            lastIndex = cIndex;
1931                            cIndex = value.indexOf(',', cIndex);
1932                            if (cIndex == -1) {
1933                                cIndex = length;
1934                            }
1935                            if (lastIndex < length) {
1936                                if (lastIndex != cIndex) {
1937                                    int lastCharIndex = cIndex;
1938                                    if (cIndex > 0
1939                                            && value.charAt(cIndex - 1) == ' ') {
1940                                        lastCharIndex--;
1941                                    }
1942                                    setFontName(ff, value.substring(lastIndex,
1943                                            lastCharIndex));
1944                                    done = (ff.family != null);
1945                                }
1946                                cIndex++;
1947                            } else {
1948                                done = true;
1949                            }
1950                        }
1951                    }
1952                    if (ff.family == null) {
1953                        ff.family = Font.SANS_SERIF;
1954                    }
1955                    return ff;
1956                }
1957
1958                private void setFontName(FontFamily ff, String fontName) {
1959                    ff.family = fontName;
1960                }
1961
1962                Object parseHtmlValue(String value) {
1963                    // TBD
1964                    return parseCssValue(value);
1965                }
1966
1967                /**
1968                 * Converts a <code>StyleConstants</code> attribute value to
1969                 * a CSS attribute value.  If there is no conversion
1970                 * returns <code>null</code>.  By default, there is no conversion.
1971                 * 
1972                 * @param key the <code>StyleConstants</code> attribute
1973                 * @param value the value of a <code>StyleConstants</code>
1974                 *   attribute to be converted
1975                 * @return the CSS value that represents the 
1976                 *   <code>StyleConstants</code> value
1977                 */
1978                Object fromStyleConstants(StyleConstants key, Object value) {
1979                    return parseCssValue(value.toString());
1980                }
1981
1982                /**
1983                 * Converts a CSS attribute value to a <code>StyleConstants</code>
1984                 * value.  If there is no conversion, returns <code>null</code>.
1985                 * By default, there is no conversion.
1986                 *
1987                 * @param key the <code>StyleConstants</code> attribute
1988                 * @return the <code>StyleConstants</code> attribute value that 
1989                 *   represents the CSS attribute value
1990                 */
1991                Object toStyleConstants(StyleConstants key, View v) {
1992                    return family;
1993                }
1994
1995                String family;
1996            }
1997
1998            static class FontWeight extends CssValue {
1999
2000                int getValue() {
2001                    return weight;
2002                }
2003
2004                Object parseCssValue(String value) {
2005                    FontWeight fw = new FontWeight();
2006                    fw.svalue = value;
2007                    if (value.equals("bold")) {
2008                        fw.weight = 700;
2009                    } else if (value.equals("normal")) {
2010                        fw.weight = 400;
2011                    } else {
2012                        // PENDING(prinz) add support for relative values
2013                        try {
2014                            fw.weight = Integer.parseInt(value);
2015                        } catch (NumberFormatException nfe) {
2016                            fw = null;
2017                        }
2018                    }
2019                    return fw;
2020                }
2021
2022                /**
2023                 * Converts a <code>StyleConstants</code> attribute value to
2024                 * a CSS attribute value.  If there is no conversion
2025                 * returns <code>null</code>.  By default, there is no conversion.
2026                 * 
2027                 * @param key the <code>StyleConstants</code> attribute
2028                 * @param value the value of a <code>StyleConstants</code>
2029                 *   attribute to be converted
2030                 * @return the CSS value that represents the 
2031                 *   <code>StyleConstants</code> value
2032                 */
2033                Object fromStyleConstants(StyleConstants key, Object value) {
2034                    if (value.equals(Boolean.TRUE)) {
2035                        return parseCssValue("bold");
2036                    }
2037                    return parseCssValue("normal");
2038                }
2039
2040                /**
2041                 * Converts a CSS attribute value to a <code>StyleConstants</code>
2042                 * value.  If there is no conversion, returns <code>null</code>.
2043                 * By default, there is no conversion.
2044                 *
2045                 * @param key the <code>StyleConstants</code> attribute
2046                 * @return the <code>StyleConstants</code> attribute value that 
2047                 *   represents the CSS attribute value
2048                 */
2049                Object toStyleConstants(StyleConstants key, View v) {
2050                    return (weight > 500) ? Boolean.TRUE : Boolean.FALSE;
2051                }
2052
2053                boolean isBold() {
2054                    return (weight > 500);
2055                }
2056
2057                int weight;
2058            }
2059
2060            static class ColorValue extends CssValue {
2061
2062                /**
2063                 * Returns the color to use.
2064                 */
2065                Color getValue() {
2066                    return c;
2067                }
2068
2069                Object parseCssValue(String value) {
2070
2071                    Color c = stringToColor(value);
2072                    if (c != null) {
2073                        ColorValue cv = new ColorValue();
2074                        cv.svalue = value;
2075                        cv.c = c;
2076                        return cv;
2077                    }
2078                    return null;
2079                }
2080
2081                Object parseHtmlValue(String value) {
2082                    return parseCssValue(value);
2083                }
2084
2085                /**
2086                 * Converts a <code>StyleConstants</code> attribute value to
2087                 * a CSS attribute value.  If there is no conversion
2088                 * returns <code>null</code>.  By default, there is no conversion.
2089                 * 
2090                 * @param key the <code>StyleConstants</code> attribute
2091                 * @param value the value of a <code>StyleConstants</code>
2092                 *   attribute to be converted
2093                 * @return the CSS value that represents the 
2094                 *   <code>StyleConstants</code> value
2095                 */
2096                Object fromStyleConstants(StyleConstants key, Object value) {
2097                    ColorValue colorValue = new ColorValue();
2098                    colorValue.c = (Color) value;
2099                    colorValue.svalue = colorToHex(colorValue.c);
2100                    return colorValue;
2101                }
2102
2103                /**
2104                 * Converts a CSS attribute value to a <code>StyleConstants</code>
2105                 * value.  If there is no conversion, returns <code>null</code>.
2106                 * By default, there is no conversion.
2107                 *
2108                 * @param key the <code>StyleConstants</code> attribute
2109                 * @return the <code>StyleConstants</code> attribute value that 
2110                 *   represents the CSS attribute value
2111                 */
2112                Object toStyleConstants(StyleConstants key, View v) {
2113                    return c;
2114                }
2115
2116                Color c;
2117            }
2118
2119            static class BorderStyle extends CssValue {
2120
2121                CSS.Value getValue() {
2122                    return style;
2123                }
2124
2125                Object parseCssValue(String value) {
2126                    CSS.Value cssv = CSS.getValue(value);
2127                    if (cssv != null) {
2128                        if ((cssv == CSS.Value.INSET)
2129                                || (cssv == CSS.Value.OUTSET)
2130                                || (cssv == CSS.Value.NONE)
2131                                || (cssv == CSS.Value.DOTTED)
2132                                || (cssv == CSS.Value.DASHED)
2133                                || (cssv == CSS.Value.SOLID)
2134                                || (cssv == CSS.Value.DOUBLE)
2135                                || (cssv == CSS.Value.GROOVE)
2136                                || (cssv == CSS.Value.RIDGE)) {
2137
2138                            BorderStyle bs = new BorderStyle();
2139                            bs.svalue = value;
2140                            bs.style = cssv;
2141                            return bs;
2142                        }
2143                    }
2144                    return null;
2145                }
2146
2147                private void writeObject(java.io.ObjectOutputStream s)
2148                        throws IOException {
2149                    s.defaultWriteObject();
2150                    if (style == null) {
2151                        s.writeObject(null);
2152                    } else {
2153                        s.writeObject(style.toString());
2154                    }
2155                }
2156
2157                private void readObject(ObjectInputStream s)
2158                        throws ClassNotFoundException, IOException {
2159                    s.defaultReadObject();
2160                    Object value = s.readObject();
2161                    if (value != null) {
2162                        style = CSS.getValue((String) value);
2163                    }
2164                }
2165
2166                // CSS.Values are static, don't archive it.
2167                transient private CSS.Value style;
2168            }
2169
2170            static class LengthValue extends CssValue {
2171
2172                /**
2173                 * if this length value may be negative.
2174                 */
2175                boolean mayBeNegative;
2176
2177                LengthValue() {
2178                    this (false);
2179                }
2180
2181                LengthValue(boolean mayBeNegative) {
2182                    this .mayBeNegative = mayBeNegative;
2183                }
2184
2185                /**
2186                 * Returns the length (span) to use.
2187                 */
2188                float getValue() {
2189                    return getValue(false);
2190                }
2191
2192                float getValue(boolean isW3CLengthUnits) {
2193                    return getValue(0, isW3CLengthUnits);
2194                }
2195
2196                /**
2197                 * Returns the length (span) to use. If the value represents
2198                 * a percentage, it is scaled based on <code>currentValue</code>.
2199                 */
2200                float getValue(float currentValue) {
2201                    return getValue(currentValue, false);
2202                }
2203
2204                float getValue(float currentValue, boolean isW3CLengthUnits) {
2205                    if (percentage) {
2206                        return span * currentValue;
2207                    }
2208                    return LengthUnit.getValue(span, units, isW3CLengthUnits);
2209                }
2210
2211                /**
2212                 * Returns true if the length represents a percentage of the
2213                 * containing box.
2214                 */
2215                boolean isPercentage() {
2216                    return percentage;
2217                }
2218
2219                Object parseCssValue(String value) {
2220                    LengthValue lv;
2221                    try {
2222                        // Assume pixels
2223                        float absolute = Float.valueOf(value).floatValue();
2224                        lv = new LengthValue();
2225                        lv.span = absolute;
2226                    } catch (NumberFormatException nfe) {
2227                        // Not pixels, use LengthUnit
2228                        LengthUnit lu = new LengthUnit(value,
2229                                LengthUnit.UNINITALIZED_LENGTH, 0);
2230
2231                        // PENDING: currently, we only support absolute values and
2232                        // percentages.
2233                        switch (lu.type) {
2234                        case 0:
2235                            // Absolute
2236                            lv = new LengthValue();
2237                            lv.span = (mayBeNegative) ? lu.value : Math.max(0,
2238                                    lu.value);
2239                            lv.units = lu.units;
2240                            break;
2241                        case 1:
2242                            // %
2243                            lv = new LengthValue();
2244                            lv.span = Math.max(0, Math.min(1, lu.value));
2245                            lv.percentage = true;
2246                            break;
2247                        default:
2248                            return null;
2249                        }
2250                    }
2251                    lv.svalue = value;
2252                    return lv;
2253                }
2254
2255                Object parseHtmlValue(String value) {
2256                    if (value.equals(HTML.NULL_ATTRIBUTE_VALUE)) {
2257                        value = "1";
2258                    }
2259                    return parseCssValue(value);
2260                }
2261
2262                /**
2263                 * Converts a <code>StyleConstants</code> attribute value to
2264                 * a CSS attribute value.  If there is no conversion,
2265                 * returns <code>null</code>.  By default, there is no conversion.
2266                 * 
2267                 * @param key the <code>StyleConstants</code> attribute
2268                 * @param value the value of a <code>StyleConstants</code>
2269                 *   attribute to be converted
2270                 * @return the CSS value that represents the 
2271                 *   <code>StyleConstants</code> value
2272                 */
2273                Object fromStyleConstants(StyleConstants key, Object value) {
2274                    LengthValue v = new LengthValue();
2275                    v.svalue = value.toString();
2276                    v.span = ((Float) value).floatValue();
2277                    return v;
2278                }
2279
2280                /**
2281                 * Converts a CSS attribute value to a <code>StyleConstants</code>
2282                 * value.  If there is no conversion, returns <code>null</code>.
2283                 * By default, there is no conversion.
2284                 *
2285                 * @param key the <code>StyleConstants</code> attribute
2286                 * @return the <code>StyleConstants</code> attribute value that 
2287                 *   represents the CSS attribute value
2288                 */
2289                Object toStyleConstants(StyleConstants key, View v) {
2290                    return new Float(getValue(false));
2291                }
2292
2293                /** If true, span is a percentage value, and that to determine
2294                 * the length another value needs to be passed in. */
2295                boolean percentage;
2296                /** Either the absolute value (percentage == false) or 
2297                 * a percentage value. */
2298                float span;
2299
2300                String units = null;
2301            }
2302
2303            /**
2304             * BorderWidthValue is used to model BORDER_XXX_WIDTH and adds support
2305             * for the thin/medium/thick values.
2306             */
2307            static class BorderWidthValue extends LengthValue {
2308                BorderWidthValue(String svalue, int index) {
2309                    this .svalue = svalue;
2310                    span = values[index];
2311                    percentage = false;
2312                }
2313
2314                Object parseCssValue(String value) {
2315                    if (value != null) {
2316                        if (value.equals("thick")) {
2317                            return new BorderWidthValue(value, 2);
2318                        } else if (value.equals("medium")) {
2319                            return new BorderWidthValue(value, 1);
2320                        } else if (value.equals("thin")) {
2321                            return new BorderWidthValue(value, 0);
2322                        }
2323                    }
2324                    // Assume its a length.
2325                    return super .parseCssValue(value);
2326                }
2327
2328                Object parseHtmlValue(String value) {
2329                    if (value == HTML.NULL_ATTRIBUTE_VALUE) {
2330                        return parseCssValue("medium");
2331                    }
2332                    return parseCssValue(value);
2333                }
2334
2335                /** Values used to represent border width. */
2336                private static final float[] values = { 1, 2, 4 };
2337            }
2338
2339            /**
2340             * Handles uniquing of CSS values, like lists, and background image
2341             * repeating.
2342             */
2343            static class CssValueMapper extends CssValue {
2344                Object parseCssValue(String value) {
2345                    Object retValue = cssValueToInternalValueMap.get(value);
2346                    if (retValue == null) {
2347                        retValue = cssValueToInternalValueMap.get(value
2348                                .toLowerCase());
2349                    }
2350                    return retValue;
2351                }
2352
2353                Object parseHtmlValue(String value) {
2354                    Object retValue = htmlValueToCssValueMap.get(value);
2355                    if (retValue == null) {
2356                        retValue = htmlValueToCssValueMap.get(value
2357                                .toLowerCase());
2358                    }
2359                    return retValue;
2360                }
2361            }
2362
2363            /**
2364             * Used for background images, to represent the position.
2365             */
2366            static class BackgroundPosition extends CssValue {
2367                float horizontalPosition;
2368                float verticalPosition;
2369                // bitmask: bit 0, horizontal relative, bit 1 horizontal relative to
2370                // font size, 2 vertical relative to size, 3 vertical relative to
2371                // font size.
2372                // 
2373                short relative;
2374
2375                Object parseCssValue(String value) {
2376                    // 'top left' and 'left top' both mean the same as '0% 0%'. 
2377                    // 'top', 'top center' and 'center top' mean the same as '50% 0%'. 
2378                    // 'right top' and 'top right' mean the same as '100% 0%'. 
2379                    // 'left', 'left center' and 'center left' mean the same as
2380                    //        '0% 50%'. 
2381                    // 'center' and 'center center' mean the same as '50% 50%'. 
2382                    // 'right', 'right center' and 'center right' mean the same as 
2383                    //        '100% 50%'. 
2384                    // 'bottom left' and 'left bottom' mean the same as '0% 100%'. 
2385                    // 'bottom', 'bottom center' and 'center bottom' mean the same as
2386                    //        '50% 100%'. 
2387                    // 'bottom right' and 'right bottom' mean the same as '100% 100%'. 
2388                    String[] strings = CSS.parseStrings(value);
2389                    int count = strings.length;
2390                    BackgroundPosition bp = new BackgroundPosition();
2391                    bp.relative = 5;
2392                    bp.svalue = value;
2393
2394                    if (count > 0) {
2395                        // bit 0 for vert, 1 hor, 2 for center
2396                        short found = 0;
2397                        int index = 0;
2398                        while (index < count) {
2399                            // First, check for keywords
2400                            String string = strings[index++];
2401                            if (string.equals("center")) {
2402                                found |= 4;
2403                                continue;
2404                            } else {
2405                                if ((found & 1) == 0) {
2406                                    if (string.equals("top")) {
2407                                        found |= 1;
2408                                    } else if (string.equals("bottom")) {
2409                                        found |= 1;
2410                                        bp.verticalPosition = 1;
2411                                        continue;
2412                                    }
2413                                }
2414                                if ((found & 2) == 0) {
2415                                    if (string.equals("left")) {
2416                                        found |= 2;
2417                                        bp.horizontalPosition = 0;
2418                                    } else if (string.equals("right")) {
2419                                        found |= 2;
2420                                        bp.horizontalPosition = 1;
2421                                    }
2422                                }
2423                            }
2424                        }
2425                        if (found != 0) {
2426                            if ((found & 1) == 1) {
2427                                if ((found & 2) == 0) {
2428                                    // vert and no horiz.
2429                                    bp.horizontalPosition = .5f;
2430                                }
2431                            } else if ((found & 2) == 2) {
2432                                // horiz and no vert.
2433                                bp.verticalPosition = .5f;
2434                            } else {
2435                                // no horiz, no vert, but center
2436                                bp.horizontalPosition = bp.verticalPosition = .5f;
2437                            }
2438                        } else {
2439                            // Assume lengths
2440                            LengthUnit lu = new LengthUnit(strings[0],
2441                                    (short) 0, 0f);
2442
2443                            if (lu.type == 0) {
2444                                bp.horizontalPosition = lu.value;
2445                                bp.relative = (short) (1 ^ bp.relative);
2446                            } else if (lu.type == 1) {
2447                                bp.horizontalPosition = lu.value;
2448                            } else if (lu.type == 3) {
2449                                bp.horizontalPosition = lu.value;
2450                                bp.relative = (short) ((1 ^ bp.relative) | 2);
2451                            }
2452                            if (count > 1) {
2453                                lu = new LengthUnit(strings[1], (short) 0, 0f);
2454
2455                                if (lu.type == 0) {
2456                                    bp.verticalPosition = lu.value;
2457                                    bp.relative = (short) (4 ^ bp.relative);
2458                                } else if (lu.type == 1) {
2459                                    bp.verticalPosition = lu.value;
2460                                } else if (lu.type == 3) {
2461                                    bp.verticalPosition = lu.value;
2462                                    bp.relative = (short) ((4 ^ bp.relative) | 8);
2463                                }
2464                            } else {
2465                                bp.verticalPosition = .5f;
2466                            }
2467                        }
2468                    }
2469                    return bp;
2470                }
2471
2472                boolean isHorizontalPositionRelativeToSize() {
2473                    return ((relative & 1) == 1);
2474                }
2475
2476                boolean isHorizontalPositionRelativeToFontSize() {
2477                    return ((relative & 2) == 2);
2478                }
2479
2480                float getHorizontalPosition() {
2481                    return horizontalPosition;
2482                }
2483
2484                boolean isVerticalPositionRelativeToSize() {
2485                    return ((relative & 4) == 4);
2486                }
2487
2488                boolean isVerticalPositionRelativeToFontSize() {
2489                    return ((relative & 8) == 8);
2490                }
2491
2492                float getVerticalPosition() {
2493                    return verticalPosition;
2494                }
2495            }
2496
2497            /**
2498             * Used for BackgroundImages.
2499             */
2500            static class BackgroundImage extends CssValue {
2501                private boolean loadedImage;
2502                private ImageIcon image;
2503
2504                Object parseCssValue(String value) {
2505                    BackgroundImage retValue = new BackgroundImage();
2506                    retValue.svalue = value;
2507                    return retValue;
2508                }
2509
2510                Object parseHtmlValue(String value) {
2511                    return parseCssValue(value);
2512                }
2513
2514                // PENDING: this base is wrong for linked style sheets.
2515                ImageIcon getImage(URL base) {
2516                    if (!loadedImage) {
2517                        synchronized (this ) {
2518                            if (!loadedImage) {
2519                                URL url = CSS.getURL(base, svalue);
2520                                loadedImage = true;
2521                                if (url != null) {
2522                                    image = new ImageIcon();
2523                                    Image tmpImg = Toolkit.getDefaultToolkit()
2524                                            .createImage(url);
2525                                    if (tmpImg != null) {
2526                                        image.setImage(tmpImg);
2527                                    }
2528                                }
2529                            }
2530                        }
2531                    }
2532                    return image;
2533                }
2534            }
2535
2536            /**
2537             * Parses a length value, this is used internally, and never added
2538             * to an AttributeSet or returned to the developer.
2539             */
2540            static class LengthUnit implements  Serializable {
2541                static Hashtable lengthMapping = new Hashtable(6);
2542                static Hashtable w3cLengthMapping = new Hashtable(6);
2543                static {
2544                    lengthMapping.put("pt", new Float(1f));
2545                    // Not sure about 1.3, determined by experiementation. 
2546                    lengthMapping.put("px", new Float(1.3f));
2547                    lengthMapping.put("mm", new Float(2.83464f));
2548                    lengthMapping.put("cm", new Float(28.3464f));
2549                    lengthMapping.put("pc", new Float(12f));
2550                    lengthMapping.put("in", new Float(72f));
2551                    int res = 72;
2552                    try {
2553                        res = Toolkit.getDefaultToolkit().getScreenResolution();
2554                    } catch (HeadlessException e) {
2555                    }
2556                    // mapping according to the CSS2 spec
2557                    w3cLengthMapping.put("pt", new Float(res / 72f));
2558                    w3cLengthMapping.put("px", new Float(1f));
2559                    w3cLengthMapping.put("mm", new Float(res / 25.4f));
2560                    w3cLengthMapping.put("cm", new Float(res / 2.54f));
2561                    w3cLengthMapping.put("pc", new Float(res / 6f));
2562                    w3cLengthMapping.put("in", new Float(res));
2563                }
2564
2565                LengthUnit(String value, short defaultType, float defaultValue) {
2566                    parse(value, defaultType, defaultValue);
2567                }
2568
2569                void parse(String value, short defaultType, float defaultValue) {
2570                    type = defaultType;
2571                    this .value = defaultValue;
2572
2573                    int length = value.length();
2574                    if (length > 0 && value.charAt(length - 1) == '%') {
2575                        try {
2576                            this .value = Float.valueOf(
2577                                    value.substring(0, length - 1))
2578                                    .floatValue() / 100.0f;
2579                            type = 1;
2580                        } catch (NumberFormatException nfe) {
2581                        }
2582                    }
2583                    if (length >= 2) {
2584                        units = value.substring(length - 2, length);
2585                        Float scale = (Float) lengthMapping.get(units);
2586                        if (scale != null) {
2587                            try {
2588                                this .value = Float.valueOf(
2589                                        value.substring(0, length - 2))
2590                                        .floatValue();
2591                                type = 0;
2592                            } catch (NumberFormatException nfe) {
2593                            }
2594                        } else if (units.equals("em") || units.equals("ex")) {
2595                            try {
2596                                this .value = Float.valueOf(
2597                                        value.substring(0, length - 2))
2598                                        .floatValue();
2599                                type = 3;
2600                            } catch (NumberFormatException nfe) {
2601                            }
2602                        } else if (value.equals("larger")) {
2603                            this .value = 2f;
2604                            type = 2;
2605                        } else if (value.equals("smaller")) {
2606                            this .value = -2;
2607                            type = 2;
2608                        } else {
2609                            // treat like points.
2610                            try {
2611                                this .value = Float.valueOf(value).floatValue();
2612                                type = 0;
2613                            } catch (NumberFormatException nfe) {
2614                            }
2615                        }
2616                    } else if (length > 0) {
2617                        // treat like points.
2618                        try {
2619                            this .value = Float.valueOf(value).floatValue();
2620                            type = 0;
2621                        } catch (NumberFormatException nfe) {
2622                        }
2623                    }
2624                }
2625
2626                float getValue(boolean w3cLengthUnits) {
2627                    Hashtable mapping = (w3cLengthUnits) ? w3cLengthMapping
2628                            : lengthMapping;
2629                    float scale = 1;
2630                    if (units != null) {
2631                        Float scaleFloat = (Float) mapping.get(units);
2632                        if (scaleFloat != null) {
2633                            scale = scaleFloat.floatValue();
2634                        }
2635                    }
2636                    return this .value * scale;
2637
2638                }
2639
2640                static float getValue(float value, String units,
2641                        Boolean w3cLengthUnits) {
2642                    Hashtable mapping = (w3cLengthUnits) ? w3cLengthMapping
2643                            : lengthMapping;
2644                    float scale = 1;
2645                    if (units != null) {
2646                        Float scaleFloat = (Float) mapping.get(units);
2647                        if (scaleFloat != null) {
2648                            scale = scaleFloat.floatValue();
2649                        }
2650                    }
2651                    return value * scale;
2652                }
2653
2654                public String toString() {
2655                    return type + " " + value;
2656                }
2657
2658                // 0 - value indicates real value
2659                // 1 - % value, value relative to depends upon key.
2660                //     50% will have a value = .5
2661                // 2 - add value to parent value.
2662                // 3 - em/ex relative to font size of element (except for
2663                //     font-size, which is relative to parent).
2664                short type;
2665                float value;
2666                String units = null;
2667
2668                static final short UNINITALIZED_LENGTH = (short) 10;
2669            }
2670
2671            /**
2672             * Class used to parse font property. The font property is shorthand
2673             * for the other font properties. This expands the properties, placing
2674             * them in the attributeset.
2675             */
2676            static class ShorthandFontParser {
2677                /**
2678                 * Parses the shorthand font string <code>value</code>, placing the
2679                 * result in <code>attr</code>.
2680                 */
2681                static void parseShorthandFont(CSS css, String value,
2682                        MutableAttributeSet attr) {
2683                    // font is of the form:
2684                    // [ <font-style> || <font-variant> || <font-weight> ]? <font-size>
2685                    //   [ / <line-height> ]? <font-family>
2686                    String[] strings = CSS.parseStrings(value);
2687                    int count = strings.length;
2688                    int index = 0;
2689                    // bitmask, 1 for style, 2 for variant, 3 for weight
2690                    short found = 0;
2691                    int maxC = Math.min(3, count);
2692
2693                    // Check for font-style font-variant font-weight
2694                    while (index < maxC) {
2695                        if ((found & 1) == 0 && isFontStyle(strings[index])) {
2696                            css.addInternalCSSValue(attr,
2697                                    CSS.Attribute.FONT_STYLE, strings[index++]);
2698                            found |= 1;
2699                        } else if ((found & 2) == 0
2700                                && isFontVariant(strings[index])) {
2701                            css.addInternalCSSValue(attr,
2702                                    CSS.Attribute.FONT_VARIANT,
2703                                    strings[index++]);
2704                            found |= 2;
2705                        } else if ((found & 4) == 0
2706                                && isFontWeight(strings[index])) {
2707                            css
2708                                    .addInternalCSSValue(attr,
2709                                            CSS.Attribute.FONT_WEIGHT,
2710                                            strings[index++]);
2711                            found |= 4;
2712                        } else if (strings[index].equals("normal")) {
2713                            index++;
2714                        } else {
2715                            break;
2716                        }
2717                    }
2718                    if ((found & 1) == 0) {
2719                        css.addInternalCSSValue(attr, CSS.Attribute.FONT_STYLE,
2720                                "normal");
2721                    }
2722                    if ((found & 2) == 0) {
2723                        css.addInternalCSSValue(attr,
2724                                CSS.Attribute.FONT_VARIANT, "normal");
2725                    }
2726                    if ((found & 4) == 0) {
2727                        css.addInternalCSSValue(attr,
2728                                CSS.Attribute.FONT_WEIGHT, "normal");
2729                    }
2730
2731                    // string at index should be the font-size
2732                    if (index < count) {
2733                        String fontSize = strings[index];
2734                        int slashIndex = fontSize.indexOf('/');
2735
2736                        if (slashIndex != -1) {
2737                            fontSize = fontSize.substring(0, slashIndex);
2738                            strings[index] = strings[index]
2739                                    .substring(slashIndex);
2740                        } else {
2741                            index++;
2742                        }
2743                        css.addInternalCSSValue(attr, CSS.Attribute.FONT_SIZE,
2744                                fontSize);
2745                    } else {
2746                        css.addInternalCSSValue(attr, CSS.Attribute.FONT_SIZE,
2747                                "medium");
2748                    }
2749
2750                    // Check for line height
2751                    if (index < count && strings[index].startsWith("/")) {
2752                        String lineHeight = null;
2753                        if (strings[index].equals("/")) {
2754                            if (++index < count) {
2755                                lineHeight = strings[index++];
2756                            }
2757                        } else {
2758                            lineHeight = strings[index++].substring(1);
2759                        }
2760                        // line height
2761                        if (lineHeight != null) {
2762                            css.addInternalCSSValue(attr,
2763                                    CSS.Attribute.LINE_HEIGHT, lineHeight);
2764                        } else {
2765                            css.addInternalCSSValue(attr,
2766                                    CSS.Attribute.LINE_HEIGHT, "normal");
2767                        }
2768                    } else {
2769                        css.addInternalCSSValue(attr,
2770                                CSS.Attribute.LINE_HEIGHT, "normal");
2771                    }
2772
2773                    // remainder of strings are font-family
2774                    if (index < count) {
2775                        String family = strings[index++];
2776
2777                        while (index < count) {
2778                            family += " " + strings[index++];
2779                        }
2780                        css.addInternalCSSValue(attr,
2781                                CSS.Attribute.FONT_FAMILY, family);
2782                    } else {
2783                        css.addInternalCSSValue(attr,
2784                                CSS.Attribute.FONT_FAMILY, Font.SANS_SERIF);
2785                    }
2786                }
2787
2788                private static boolean isFontStyle(String string) {
2789                    return (string.equals("italic") || string.equals("oblique"));
2790                }
2791
2792                private static boolean isFontVariant(String string) {
2793                    return (string.equals("small-caps"));
2794                }
2795
2796                private static boolean isFontWeight(String string) {
2797                    if (string.equals("bold") || string.equals("bolder")
2798                            || string.equals("italic")
2799                            || string.equals("lighter")) {
2800                        return true;
2801                    }
2802                    // test for 100-900
2803                    return (string.length() == 3 && string.charAt(0) >= '1'
2804                            && string.charAt(0) <= '9'
2805                            && string.charAt(1) == '0' && string.charAt(2) == '0');
2806                }
2807
2808            }
2809
2810            /**
2811             * Parses the background property into its intrinsic values.
2812             */
2813            static class ShorthandBackgroundParser {
2814                /**
2815                 * Parses the shorthand font string <code>value</code>, placing the
2816                 * result in <code>attr</code>.
2817                 */
2818                static void parseShorthandBackground(CSS css, String value,
2819                        MutableAttributeSet attr) {
2820                    String[] strings = parseStrings(value);
2821                    int count = strings.length;
2822                    int index = 0;
2823                    // bitmask: 0 for image, 1 repeat, 2 attachment, 3 position,
2824                    //          4 color
2825                    short found = 0;
2826
2827                    while (index < count) {
2828                        String string = strings[index++];
2829                        if ((found & 1) == 0 && isImage(string)) {
2830                            css.addInternalCSSValue(attr,
2831                                    CSS.Attribute.BACKGROUND_IMAGE, string);
2832                            found |= 1;
2833                        } else if ((found & 2) == 0 && isRepeat(string)) {
2834                            css.addInternalCSSValue(attr,
2835                                    CSS.Attribute.BACKGROUND_REPEAT, string);
2836                            found |= 2;
2837                        } else if ((found & 4) == 0 && isAttachment(string)) {
2838                            css
2839                                    .addInternalCSSValue(
2840                                            attr,
2841                                            CSS.Attribute.BACKGROUND_ATTACHMENT,
2842                                            string);
2843                            found |= 4;
2844                        } else if ((found & 8) == 0 && isPosition(string)) {
2845                            if (index < count && isPosition(strings[index])) {
2846                                css.addInternalCSSValue(attr,
2847                                        CSS.Attribute.BACKGROUND_POSITION,
2848                                        string + " " + strings[index++]);
2849                            } else {
2850                                css.addInternalCSSValue(attr,
2851                                        CSS.Attribute.BACKGROUND_POSITION,
2852                                        string);
2853                            }
2854                            found |= 8;
2855                        } else if ((found & 16) == 0 && isColor(string)) {
2856                            css.addInternalCSSValue(attr,
2857                                    CSS.Attribute.BACKGROUND_COLOR, string);
2858                            found |= 16;
2859                        }
2860                    }
2861                    if ((found & 1) == 0) {
2862                        css.addInternalCSSValue(attr,
2863                                CSS.Attribute.BACKGROUND_IMAGE, null);
2864                    }
2865                    if ((found & 2) == 0) {
2866                        css.addInternalCSSValue(attr,
2867                                CSS.Attribute.BACKGROUND_REPEAT, "repeat");
2868                    }
2869                    if ((found & 4) == 0) {
2870                        css.addInternalCSSValue(attr,
2871                                CSS.Attribute.BACKGROUND_ATTACHMENT, "scroll");
2872                    }
2873                    if ((found & 8) == 0) {
2874                        css.addInternalCSSValue(attr,
2875                                CSS.Attribute.BACKGROUND_POSITION, null);
2876                    }
2877                    // Currently, there is no good way to express this.
2878                    /*
2879                    if ((found & 16) == 0) {
2880                    css.addInternalCSSValue(attr, CSS.Attribute.BACKGROUND_COLOR,
2881                    			null);
2882                    }
2883                     */
2884                }
2885
2886                static boolean isImage(String string) {
2887                    return (string.startsWith("url(") && string.endsWith(")"));
2888                }
2889
2890                static boolean isRepeat(String string) {
2891                    return (string.equals("repeat-x")
2892                            || string.equals("repeat-y")
2893                            || string.equals("repeat") || string
2894                            .equals("no-repeat"));
2895                }
2896
2897                static boolean isAttachment(String string) {
2898                    return (string.equals("fixed") || string.equals("scroll"));
2899                }
2900
2901                static boolean isPosition(String string) {
2902                    return (string.equals("top") || string.equals("bottom")
2903                            || string.equals("left") || string.equals("right")
2904                            || string.equals("center") || (string.length() > 0 && Character
2905                            .isDigit(string.charAt(0))));
2906                }
2907
2908                static boolean isColor(String string) {
2909                    return (CSS.stringToColor(string) != null);
2910                }
2911            }
2912
2913            /**
2914             * Used to parser margin and padding.
2915             */
2916            static class ShorthandMarginParser {
2917                /**
2918                 * Parses the shorthand margin/padding/border string
2919                 * <code>value</code>, placing the result in <code>attr</code>.
2920                 * <code>names</code> give the 4 instrinsic property names.
2921                 */
2922                static void parseShorthandMargin(CSS css, String value,
2923                        MutableAttributeSet attr, CSS.Attribute[] names) {
2924                    String[] strings = parseStrings(value);
2925                    int count = strings.length;
2926                    int index = 0;
2927                    switch (count) {
2928                    case 0:
2929                        // empty string
2930                        return;
2931                    case 1:
2932                        // Identifies all values.
2933                        for (int counter = 0; counter < 4; counter++) {
2934                            css.addInternalCSSValue(attr, names[counter],
2935                                    strings[0]);
2936                        }
2937                        break;
2938                    case 2:
2939                        // 0 & 2 = strings[0], 1 & 3 = strings[1]
2940                        css.addInternalCSSValue(attr, names[0], strings[0]);
2941                        css.addInternalCSSValue(attr, names[2], strings[0]);
2942                        css.addInternalCSSValue(attr, names[1], strings[1]);
2943                        css.addInternalCSSValue(attr, names[3], strings[1]);
2944                        break;
2945                    case 3:
2946                        css.addInternalCSSValue(attr, names[0], strings[0]);
2947                        css.addInternalCSSValue(attr, names[1], strings[1]);
2948                        css.addInternalCSSValue(attr, names[2], strings[2]);
2949                        css.addInternalCSSValue(attr, names[3], strings[1]);
2950                        break;
2951                    default:
2952                        for (int counter = 0; counter < 4; counter++) {
2953                            css.addInternalCSSValue(attr, names[counter],
2954                                    strings[counter]);
2955                        }
2956                        break;
2957                    }
2958                }
2959            }
2960
2961            /**
2962             * Calculate the requirements needed to tile the requirements 
2963             * given by the iterator that would be tiled.  The calculation
2964             * takes into consideration margin and border spacing.
2965             */
2966            static SizeRequirements calculateTiledRequirements(
2967                    LayoutIterator iter, SizeRequirements r) {
2968                long minimum = 0;
2969                long maximum = 0;
2970                long preferred = 0;
2971                int lastMargin = 0;
2972                int totalSpacing = 0;
2973                int n = iter.getCount();
2974                for (int i = 0; i < n; i++) {
2975                    iter.setIndex(i);
2976                    int margin0 = lastMargin;
2977                    int margin1 = (int) iter.getLeadingCollapseSpan();
2978                    totalSpacing += Math.max(margin0, margin1);
2979                    ;
2980                    preferred += (int) iter.getPreferredSpan(0);
2981                    minimum += iter.getMinimumSpan(0);
2982                    maximum += iter.getMaximumSpan(0);
2983
2984                    lastMargin = (int) iter.getTrailingCollapseSpan();
2985                }
2986                totalSpacing += lastMargin;
2987                totalSpacing += 2 * iter.getBorderWidth();
2988
2989                // adjust for the spacing area
2990                minimum += totalSpacing;
2991                preferred += totalSpacing;
2992                maximum += totalSpacing;
2993
2994                // set return value
2995                if (r == null) {
2996                    r = new SizeRequirements();
2997                }
2998                r.minimum = (minimum > Integer.MAX_VALUE) ? Integer.MAX_VALUE
2999                        : (int) minimum;
3000                r.preferred = (preferred > Integer.MAX_VALUE) ? Integer.MAX_VALUE
3001                        : (int) preferred;
3002                r.maximum = (maximum > Integer.MAX_VALUE) ? Integer.MAX_VALUE
3003                        : (int) maximum;
3004                return r;
3005            }
3006
3007            /**
3008             * Calculate a tiled layout for the given iterator.
3009             * This should be done collapsing the neighboring
3010             * margins to be a total of the maximum of the two 
3011             * neighboring margin areas as described in the CSS spec.
3012             */
3013            static void calculateTiledLayout(LayoutIterator iter, int targetSpan) {
3014
3015                /*
3016                 * first pass, calculate the preferred sizes, adjustments needed because
3017                 * of margin collapsing, and the flexibility to adjust the sizes.
3018                 */
3019                long preferred = 0;
3020                long currentPreferred = 0;
3021                int lastMargin = 0;
3022                int totalSpacing = 0;
3023                int n = iter.getCount();
3024                int adjustmentWeightsCount = LayoutIterator.WorstAdjustmentWeight + 1;
3025                //max gain we can get adjusting elements with adjustmentWeight <= i
3026                long gain[] = new long[adjustmentWeightsCount];
3027                //max loss we can get adjusting elements with adjustmentWeight <= i
3028                long loss[] = new long[adjustmentWeightsCount];
3029
3030                for (int i = 0; i < adjustmentWeightsCount; i++) {
3031                    gain[i] = loss[i] = 0;
3032                }
3033                for (int i = 0; i < n; i++) {
3034                    iter.setIndex(i);
3035                    int margin0 = lastMargin;
3036                    int margin1 = (int) iter.getLeadingCollapseSpan();
3037
3038                    iter.setOffset(Math.max(margin0, margin1));
3039                    totalSpacing += iter.getOffset();
3040
3041                    currentPreferred = (long) iter.getPreferredSpan(targetSpan);
3042                    iter.setSpan((int) currentPreferred);
3043                    preferred += currentPreferred;
3044                    gain[iter.getAdjustmentWeight()] += (long) iter
3045                            .getMaximumSpan(targetSpan)
3046                            - currentPreferred;
3047                    loss[iter.getAdjustmentWeight()] += currentPreferred
3048                            - (long) iter.getMinimumSpan(targetSpan);
3049                    lastMargin = (int) iter.getTrailingCollapseSpan();
3050                }
3051                totalSpacing += lastMargin;
3052                totalSpacing += 2 * iter.getBorderWidth();
3053
3054                for (int i = 1; i < adjustmentWeightsCount; i++) {
3055                    gain[i] += gain[i - 1];
3056                    loss[i] += loss[i - 1];
3057                }
3058
3059                /*
3060                 * Second pass, expand or contract by as much as possible to reach
3061                 * the target span.  This takes the margin collapsing into account
3062                 * prior to adjusting the span.
3063                 */
3064
3065                // determine the adjustment to be made
3066                int allocated = targetSpan - totalSpacing;
3067                long desiredAdjustment = allocated - preferred;
3068                long adjustmentsArray[] = (desiredAdjustment > 0) ? gain : loss;
3069                desiredAdjustment = Math.abs(desiredAdjustment);
3070                int adjustmentLevel = 0;
3071                for (; adjustmentLevel <= LayoutIterator.WorstAdjustmentWeight; adjustmentLevel++) {
3072                    // adjustmentsArray[] is sorted. I do not bother about
3073                    // binary search though
3074                    if (adjustmentsArray[adjustmentLevel] >= desiredAdjustment) {
3075                        break;
3076                    }
3077                }
3078                float adjustmentFactor = 0.0f;
3079                if (adjustmentLevel <= LayoutIterator.WorstAdjustmentWeight) {
3080                    desiredAdjustment -= (adjustmentLevel > 0) ? adjustmentsArray[adjustmentLevel - 1]
3081                            : 0;
3082                    if (desiredAdjustment != 0) {
3083                        float maximumAdjustment = adjustmentsArray[adjustmentLevel]
3084                                - ((adjustmentLevel > 0) ? adjustmentsArray[adjustmentLevel - 1]
3085                                        : 0);
3086                        adjustmentFactor = desiredAdjustment
3087                                / maximumAdjustment;
3088                    }
3089                }
3090                // make the adjustments
3091                int totalOffset = (int) iter.getBorderWidth();
3092                ;
3093                for (int i = 0; i < n; i++) {
3094                    iter.setIndex(i);
3095                    iter.setOffset(iter.getOffset() + totalOffset);
3096                    if (iter.getAdjustmentWeight() < adjustmentLevel) {
3097                        iter.setSpan((int) ((allocated > preferred) ? Math
3098                                .floor(iter.getMaximumSpan(targetSpan)) : Math
3099                                .ceil(iter.getMinimumSpan(targetSpan))));
3100                    } else if (iter.getAdjustmentWeight() == adjustmentLevel) {
3101                        int availableSpan = (allocated > preferred) ? (int) iter
3102                                .getMaximumSpan(targetSpan)
3103                                - iter.getSpan()
3104                                : iter.getSpan()
3105                                        - (int) iter.getMinimumSpan(targetSpan);
3106                        int adj = (int) Math.floor(adjustmentFactor
3107                                * availableSpan);
3108                        iter.setSpan(iter.getSpan()
3109                                + ((allocated > preferred) ? adj : -adj));
3110                    }
3111                    totalOffset = (int) Math.min((long) iter.getOffset()
3112                            + (long) iter.getSpan(), Integer.MAX_VALUE);
3113                }
3114
3115                // while rounding we could lose several pixels.
3116                int roundError = targetSpan - totalOffset
3117                        - (int) iter.getTrailingCollapseSpan()
3118                        - (int) iter.getBorderWidth();
3119                int adj = (roundError > 0) ? 1 : -1;
3120                roundError *= adj;
3121
3122                boolean canAdjust = true;
3123                while (roundError > 0 && canAdjust) {
3124                    // check for infinite loop
3125                    canAdjust = false;
3126                    int offsetAdjust = 0;
3127                    // try to distribute roundError. one pixel per cell
3128                    for (int i = 0; i < n; i++) {
3129                        iter.setIndex(i);
3130                        iter.setOffset(iter.getOffset() + offsetAdjust);
3131                        int curSpan = iter.getSpan();
3132                        if (roundError > 0) {
3133                            int boundGap = (adj > 0) ? (int) Math.floor(iter
3134                                    .getMaximumSpan(targetSpan))
3135                                    - curSpan : curSpan
3136                                    - (int) Math.ceil(iter
3137                                            .getMinimumSpan(targetSpan));
3138                            if (boundGap >= 1) {
3139                                canAdjust = true;
3140                                iter.setSpan(curSpan + adj);
3141                                offsetAdjust += adj;
3142                                roundError--;
3143                            }
3144                        }
3145                    }
3146                }
3147            }
3148
3149            /**
3150             * An iterator to express the requirements to use when computing
3151             * layout.
3152             */
3153            interface LayoutIterator {
3154
3155                void setOffset(int offs);
3156
3157                int getOffset();
3158
3159                void setSpan(int span);
3160
3161                int getSpan();
3162
3163                int getCount();
3164
3165                void setIndex(int i);
3166
3167                float getMinimumSpan(float parentSpan);
3168
3169                float getPreferredSpan(float parentSpan);
3170
3171                float getMaximumSpan(float parentSpan);
3172
3173                int getAdjustmentWeight(); //0 is the best weight WorstAdjustmentWeight is a worst one
3174
3175                //float getAlignment();
3176
3177                float getBorderWidth();
3178
3179                float getLeadingCollapseSpan();
3180
3181                float getTrailingCollapseSpan();
3182
3183                public static final int WorstAdjustmentWeight = 2;
3184            }
3185
3186            //
3187            // Serialization support
3188            //
3189
3190            private void writeObject(java.io.ObjectOutputStream s)
3191                    throws IOException {
3192                s.defaultWriteObject();
3193
3194                // Determine what values in valueConvertor need to be written out.
3195                Enumeration keys = valueConvertor.keys();
3196                s.writeInt(valueConvertor.size());
3197                if (keys != null) {
3198                    while (keys.hasMoreElements()) {
3199                        Object key = keys.nextElement();
3200                        Object value = valueConvertor.get(key);
3201                        if (!(key instanceof  Serializable)
3202                                && (key = StyleContext
3203                                        .getStaticAttributeKey(key)) == null) {
3204                            // Should we throw an exception here?
3205                            key = null;
3206                            value = null;
3207                        } else if (!(value instanceof  Serializable)
3208                                && (value = StyleContext
3209                                        .getStaticAttributeKey(value)) == null) {
3210                            // Should we throw an exception here?
3211                            key = null;
3212                            value = null;
3213                        }
3214                        s.writeObject(key);
3215                        s.writeObject(value);
3216                    }
3217                }
3218            }
3219
3220            private void readObject(ObjectInputStream s)
3221                    throws ClassNotFoundException, IOException {
3222                s.defaultReadObject();
3223                // Reconstruct the hashtable.
3224                int numValues = s.readInt();
3225                valueConvertor = new Hashtable(Math.max(1, numValues));
3226                while (numValues-- > 0) {
3227                    Object key = s.readObject();
3228                    Object value = s.readObject();
3229                    Object staticKey = StyleContext.getStaticAttribute(key);
3230                    if (staticKey != null) {
3231                        key = staticKey;
3232                    }
3233                    Object staticValue = StyleContext.getStaticAttribute(value);
3234                    if (staticValue != null) {
3235                        value = staticValue;
3236                    }
3237                    if (key != null && value != null) {
3238                        valueConvertor.put(key, value);
3239                    }
3240                }
3241            }
3242
3243            /*
3244             * we need StyleSheet for resolving lenght units. (see
3245             * isW3CLengthUnits)
3246             * we can not pass stylesheet for handling relative sizes. (do not
3247             * think changing public API is necessary)
3248             * CSS is not likely to be accessed from more then one thread.
3249             * Having local storage for StyleSheet for resolving relative
3250             * sizes is safe 
3251             * 
3252             * idk 08/30/2004
3253             */
3254            private StyleSheet getStyleSheet(StyleSheet ss) {
3255                if (ss != null) {
3256                    styleSheet = ss;
3257                }
3258                return styleSheet;
3259            }
3260
3261            //
3262            // Instance variables
3263            //
3264
3265            /** Maps from CSS key to CssValue. */
3266            private transient Hashtable valueConvertor;
3267
3268            /** Size used for relative units. */
3269            private int baseFontSize;
3270
3271            private transient StyleSheet styleSheet = null;
3272
3273            static int baseFontSizeIndex = 3;
3274        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.