< prev index next >

src/java.desktop/share/classes/javax/swing/text/html/CSS.java

Print this page




 718                            valueMapper);
 719         valueConvertor.put(CSS.Attribute.BACKGROUND_IMAGE,
 720                            new BackgroundImage());
 721         valueConvertor.put(CSS.Attribute.BACKGROUND_POSITION,
 722                            new BackgroundPosition());
 723         valueConvertor.put(CSS.Attribute.BACKGROUND_REPEAT,
 724                            valueMapper);
 725         valueConvertor.put(CSS.Attribute.BACKGROUND_ATTACHMENT,
 726                            valueMapper);
 727         Object generic = new CssValue();
 728         int n = CSS.Attribute.allAttributes.length;
 729         for (int i = 0; i < n; i++) {
 730             CSS.Attribute key = CSS.Attribute.allAttributes[i];
 731             if (valueConvertor.get(key) == null) {
 732                 valueConvertor.put(key, generic);
 733             }
 734         }
 735     }
 736 
 737     /**
 738      * Sets the base font size. <code>sz</code> is a CSS value, and is
 739      * not necessarily the point size. Use getPointSize to determine the
 740      * point size corresponding to <code>sz</code>.
 741      */
 742     void setBaseFontSize(int sz) {
 743         if (sz < 1)
 744           baseFontSize = 0;
 745         else if (sz > 7)
 746           baseFontSize = 7;
 747         else
 748           baseFontSize = sz;
 749     }
 750 
 751     /**
 752      * Sets the base font size from the passed in string.
 753      */
 754     void setBaseFontSize(String size) {
 755         int relSize, absSize, diff;
 756 
 757         if (size != null) {
 758             if (size.startsWith("+")) {
 759                 relSize = Integer.valueOf(size.substring(1)).intValue();
 760                 setBaseFontSize(baseFontSize + relSize);
 761             } else if (size.startsWith("-")) {
 762                 relSize = -Integer.valueOf(size.substring(1)).intValue();
 763                 setBaseFontSize(baseFontSize + relSize);
 764             } else {
 765                 setBaseFontSize(Integer.valueOf(size).intValue());
 766             }
 767         }
 768     }
 769 
 770     /**
 771      * Returns the base font size.
 772      */
 773     int getBaseFontSize() {
 774         return baseFontSize;
 775     }
 776 
 777     /**
 778      * Parses the CSS property <code>key</code> with value
 779      * <code>value</code> placing the result in <code>att</code>.
 780      */
 781     void addInternalCSSValue(MutableAttributeSet attr,
 782                              CSS.Attribute key, String value) {
 783         if (key == CSS.Attribute.FONT) {
 784             ShorthandFontParser.parseShorthandFont(this, value, attr);
 785         }
 786         else if (key == CSS.Attribute.BACKGROUND) {
 787             ShorthandBackgroundParser.parseShorthandBackground
 788                                (this, value, attr);
 789         }
 790         else if (key == CSS.Attribute.MARGIN) {
 791             ShorthandMarginParser.parseShorthandMargin(this, value, attr,
 792                                            CSS.Attribute.ALL_MARGINS);
 793         }
 794         else if (key == CSS.Attribute.PADDING) {
 795             ShorthandMarginParser.parseShorthandMargin(this, value, attr,
 796                                            CSS.Attribute.ALL_PADDING);
 797         }
 798         else if (key == CSS.Attribute.BORDER_WIDTH) {
 799             ShorthandMarginParser.parseShorthandMargin(this, value, attr,


 806         else if (key == CSS.Attribute.BORDER_STYLE) {
 807             ShorthandMarginParser.parseShorthandMargin(this, value, attr,
 808                                             CSS.Attribute.ALL_BORDER_STYLES);
 809         }
 810         else if ((key == CSS.Attribute.BORDER) ||
 811                    (key == CSS.Attribute.BORDER_TOP) ||
 812                    (key == CSS.Attribute.BORDER_RIGHT) ||
 813                    (key == CSS.Attribute.BORDER_BOTTOM) ||
 814                    (key == CSS.Attribute.BORDER_LEFT)) {
 815             ShorthandBorderParser.parseShorthandBorder(attr, key, value);
 816         }
 817         else {
 818             Object iValue = getInternalCSSValue(key, value);
 819             if (iValue != null) {
 820                 attr.addAttribute(key, iValue);
 821             }
 822         }
 823     }
 824 
 825     /**
 826      * Gets the internal CSS representation of <code>value</code> which is
 827      * a CSS value of the CSS attribute named <code>key</code>. The receiver
 828      * should not modify <code>value</code>, and the first <code>count</code>
 829      * strings are valid.
 830      */
 831     Object getInternalCSSValue(CSS.Attribute key, String value) {
 832         CssValue conv = (CssValue) valueConvertor.get(key);
 833         Object r = conv.parseCssValue(value);
 834         return r != null ? r : conv.parseCssValue(key.getDefaultValue());
 835     }
 836 
 837     /**
 838      * Maps from a StyleConstants to a CSS Attribute.
 839      */
 840     Attribute styleConstantsKeyToCSSKey(StyleConstants sc) {
 841         return styleConstantToCssMap.get(sc);
 842     }
 843 
 844     /**
 845      * Maps from a StyleConstants value to a CSS value.
 846      */
 847     Object styleConstantsValueToCSSValue(StyleConstants sc,
 848                                          Object styleValue) {
 849         Attribute cssKey = styleConstantsKeyToCSSKey(sc);
 850         if (cssKey != null) {
 851             CssValue conv = (CssValue)valueConvertor.get(cssKey);
 852             return conv.fromStyleConstants(sc, styleValue);
 853         }
 854         return null;
 855     }
 856 
 857     /**
 858      * Converts the passed in CSS value to a StyleConstants value.
 859      * <code>key</code> identifies the CSS attribute being mapped.
 860      */
 861     Object cssValueToStyleConstantsValue(StyleConstants key, Object value) {
 862         if (value instanceof CssValue) {
 863             return ((CssValue)value).toStyleConstants(key, null);
 864         }
 865         return null;
 866     }
 867 
 868     /**
 869      * Returns the font for the values in the passed in AttributeSet.
 870      * It is assumed the keys will be CSS.Attribute keys.
 871      * <code>sc</code> is the StyleContext that will be messaged to get
 872      * the font once the size, name and style have been determined.
 873      */
 874     Font getFont(StyleContext sc, AttributeSet a, int defaultSize, StyleSheet ss) {
 875         ss = getStyleSheet(ss);
 876         int size = getFontSize(a, defaultSize, ss);
 877 
 878         /*
 879          * If the vertical alignment is set to either superscript or
 880          * subscript we reduce the font size by 2 points.
 881          */
 882         StringValue vAlignV = (StringValue)a.getAttribute
 883                               (CSS.Attribute.VERTICAL_ALIGN);
 884         if ((vAlignV != null)) {
 885             String vAlign = vAlignV.toString();
 886             if ((vAlign.indexOf("sup") >= 0) ||
 887                 (vAlign.indexOf("sub") >= 0)) {
 888                 size -= 2;
 889             }
 890         }
 891 


 913             family = Font.SANS_SERIF;
 914             f = sc.getFont(family, style, size);
 915         }
 916         return f;
 917     }
 918 
 919     static int getFontSize(AttributeSet attr, int defaultSize, StyleSheet ss) {
 920         // PENDING(prinz) this is a 1.1 based implementation, need to also
 921         // have a 1.2 version.
 922         FontSize sizeValue = (FontSize)attr.getAttribute(CSS.Attribute.
 923                                                          FONT_SIZE);
 924 
 925         return (sizeValue != null) ? sizeValue.getValue(attr, ss)
 926                                    : defaultSize;
 927     }
 928 
 929     /**
 930      * Takes a set of attributes and turn it into a color
 931      * specification.  This might be used to specify things
 932      * like brighter, more hue, etc.
 933      * This will return null if there is no value for <code>key</code>.
 934      *
 935      * @param key CSS.Attribute identifying where color is stored.
 936      * @param a the set of attributes
 937      * @return the color
 938      */
 939     Color getColor(AttributeSet a, CSS.Attribute key) {
 940         ColorValue cv = (ColorValue) a.getAttribute(key);
 941         if (cv != null) {
 942             return cv.getValue();
 943         }
 944         return null;
 945     }
 946 
 947     /**
 948      * Returns the size of a font from the passed in string.
 949      *
 950      * @param size CSS string describing font size
 951      * @param baseFontSize size to use for relative units.
 952      */
 953     float getPointSize(String size, StyleSheet ss) {
 954         int relSize, absSize, diff, index;
 955         ss = getStyleSheet(ss);
 956         if (size != null) {
 957             if (size.startsWith("+")) {
 958                 relSize = Integer.valueOf(size.substring(1)).intValue();
 959                 return getPointSize(baseFontSize + relSize, ss);
 960             } else if (size.startsWith("-")) {
 961                 relSize = -Integer.valueOf(size.substring(1)).intValue();
 962                 return getPointSize(baseFontSize + relSize, ss);
 963             } else {
 964                 absSize = Integer.valueOf(size).intValue();
 965                 return getPointSize(absSize, ss);
 966             }
 967         }
 968         return 0;
 969     }
 970 
 971     /**
 972      * Returns the length of the attribute in <code>a</code> with
 973      * key <code>key</code>.
 974      */
 975     float getLength(AttributeSet a, CSS.Attribute key, StyleSheet ss) {
 976         ss = getStyleSheet(ss);
 977         LengthValue lv = (LengthValue) a.getAttribute(key);
 978         boolean isW3CLengthUnits = (ss == null) ? false : ss.isW3CLengthUnits();
 979         float len = (lv != null) ? lv.getValue(isW3CLengthUnits) : 0;
 980         return len;
 981     }
 982 
 983     /**
 984      * Convert a set of HTML attributes to an equivalent
 985      * set of CSS attributes.
 986      *
 987      * @param htmlAttrSet AttributeSet containing the HTML attributes.
 988      * @return AttributeSet containing the corresponding CSS attributes.
 989      *        The AttributeSet will be empty if there are no mapping
 990      *        CSS attributes.
 991      */
 992     AttributeSet translateHTMLToCSS(AttributeSet htmlAttrSet) {
 993         MutableAttributeSet cssAttrSet = new SimpleAttributeSet();


1219             for (Object key : keys) {
1220                 StyleContext.registerStaticAttributeKey(key);
1221             }
1222         } catch (Throwable e) {
1223             e.printStackTrace();
1224         }
1225     }
1226 
1227     /**
1228      * Return the set of all possible CSS attribute keys.
1229      *
1230      * @return the set of all possible CSS attribute keys
1231      */
1232     public static Attribute[] getAllAttributeKeys() {
1233         Attribute[] keys = new Attribute[Attribute.allAttributes.length];
1234         System.arraycopy(Attribute.allAttributes, 0, keys, 0, Attribute.allAttributes.length);
1235         return keys;
1236     }
1237 
1238     /**
1239      * Translates a string to a <code>CSS.Attribute</code> object.
1240      * This will return <code>null</code> if there is no attribute
1241      * by the given name.
1242      *
1243      * @param name the name of the CSS attribute to fetch the
1244      *  typesafe enumeration for
1245      * @return the <code>CSS.Attribute</code> object,
1246      *  or <code>null</code> if the string
1247      *  doesn't represent a valid attribute key
1248      */
1249     public static final Attribute getAttribute(String name) {
1250         return attributeMap.get(name);
1251     }
1252 
1253     /**
1254      * Translates a string to a <code>CSS.Value</code> object.
1255      * This will return <code>null</code> if there is no value
1256      * by the given name.
1257      *
1258      * @param name the name of the CSS value to fetch the
1259      *  typesafe enumeration for
1260      * @return the <code>CSS.Value</code> object,
1261      *  or <code>null</code> if the string
1262      *  doesn't represent a valid CSS value name; this does
1263      *  not mean that it doesn't represent a valid CSS value
1264      */
1265     static final Value getValue(String name) {
1266         return valueMap.get(name);
1267     }
1268 
1269 
1270     //
1271     // Conversion related methods/classes
1272     //
1273 
1274     /**
1275      * Returns a URL for the given CSS url string. If relative,
1276      * <code>base</code> is used as the parent. If a valid URL can not
1277      * be found, this will not throw a MalformedURLException, instead
1278      * null will be returned.
1279      */
1280     static URL getURL(URL base, String cssString) {
1281         if (cssString == null) {
1282             return null;
1283         }
1284         if (cssString.startsWith("url(") &&
1285             cssString.endsWith(")")) {
1286             cssString = cssString.substring(4, cssString.length() - 1);
1287         }
1288         // Absolute first
1289         try {
1290             URL url = new URL(cssString);
1291             if (url != null) {
1292                 return url;
1293             }
1294         } catch (MalformedURLException mue) {
1295         }
1296         // Then relative


1407       else if(str.equalsIgnoreCase("Olive"))
1408         color = hexToColor("#808000");
1409       else if(str.equalsIgnoreCase("Yellow"))
1410         color = hexToColor("#FFFF00");
1411       else if(str.equalsIgnoreCase("Navy"))
1412         color = hexToColor("#000080");
1413       else if(str.equalsIgnoreCase("Blue"))
1414         color = hexToColor("#0000FF");
1415       else if(str.equalsIgnoreCase("Teal"))
1416         color = hexToColor("#008080");
1417       else if(str.equalsIgnoreCase("Aqua"))
1418         color = hexToColor("#00FFFF");
1419       else if(str.equalsIgnoreCase("Orange"))
1420         color = hexToColor("#FF8000");
1421       else
1422           color = hexToColor(str); // sometimes get specified without leading #
1423       return color;
1424     }
1425 
1426     /**
1427      * Parses a String in the format <code>rgb(r, g, b)</code> where
1428      * each of the Color components is either an integer, or a floating number
1429      * with a % after indicating a percentage value of 255. Values are
1430      * constrained to fit with 0-255. The resulting Color is returned.
1431      */
1432     private static Color parseRGB(String string) {
1433         // Find the next numeric char
1434         int[] index = new int[1];
1435 
1436         index[0] = 4;
1437         int red = getColorComponent(string, index);
1438         int green = getColorComponent(string, index);
1439         int blue = getColorComponent(string, index);
1440 
1441         return new Color(red, green, blue);
1442     }
1443 
1444     /**
1445      * Returns the next integer value from <code>string</code> starting
1446      * at <code>index[0]</code>. The value can either can an integer, or
1447      * a percentage (floating number ending with %), in which case it is
1448      * multiplied by 255.
1449      */
1450     private static int getColorComponent(String string, int[] index) {
1451         int length = string.length();
1452         char aChar;
1453 
1454         // Skip non-decimal chars
1455         while(index[0] < length && (aChar = string.charAt(index[0])) != '-' &&
1456               !Character.isDigit(aChar) && aChar != '.') {
1457             index[0]++;
1458         }
1459 
1460         int start = index[0];
1461 
1462         if (start < length && string.charAt(index[0]) == '-') {
1463             index[0]++;
1464         }
1465         while(index[0] < length &&
1466                          Character.isDigit(string.charAt(index[0]))) {


1489             }
1490         }
1491         return 0;
1492     }
1493 
1494     static int getIndexOfSize(float pt, int[] sizeMap) {
1495         for (int i = 0; i < sizeMap.length; i ++ )
1496                 if (pt <= sizeMap[i])
1497                         return i + 1;
1498         return sizeMap.length;
1499     }
1500 
1501     static int getIndexOfSize(float pt, StyleSheet ss) {
1502         int[] sizeMap = (ss != null) ? ss.getSizeMap() :
1503             StyleSheet.sizeMapDefault;
1504         return getIndexOfSize(pt, sizeMap);
1505     }
1506 
1507 
1508     /**
1509      * @return an array of all the strings in <code>value</code>
1510      *         that are separated by whitespace.
1511      */
1512     static String[] parseStrings(String value) {
1513         int         current, last;
1514         int         length = (value == null) ? 0 : value.length();
1515         Vector<String> temp = new Vector<String>(4);
1516 
1517         current = 0;
1518         while (current < length) {
1519             // Skip ws
1520             while (current < length && Character.isWhitespace
1521                    (value.charAt(current))) {
1522                 current++;
1523             }
1524             last = current;
1525             while (current < length && !Character.isWhitespace
1526                    (value.charAt(current))) {
1527                 current++;
1528             }
1529             if (last != current) {


1766          * have a special binary format for is a String.
1767          */
1768         Object parseCssValue(String value) {
1769             return value;
1770         }
1771 
1772         /**
1773          * Convert an HTML attribute value to a CSS attribute
1774          * value.  If there is no conversion, return null.
1775          * This is implemented to simply forward to the CSS
1776          * parsing by default (since some of the attribute
1777          * values are the same).  If the attribute value
1778          * isn't recognized as a CSS value it is generally
1779          * returned as null.
1780          */
1781         Object parseHtmlValue(String value) {
1782             return parseCssValue(value);
1783         }
1784 
1785         /**
1786          * Converts a <code>StyleConstants</code> attribute value to
1787          * a CSS attribute value.  If there is no conversion,
1788          * returns <code>null</code>.  By default, there is no conversion.
1789          *
1790          * @param key the <code>StyleConstants</code> attribute
1791          * @param value the value of a <code>StyleConstants</code>
1792          *   attribute to be converted
1793          * @return the CSS value that represents the
1794          *   <code>StyleConstants</code> value
1795          */
1796         Object fromStyleConstants(StyleConstants key, Object value) {
1797             return null;
1798         }
1799 
1800         /**
1801          * Converts a CSS attribute value to a
1802          * <code>StyleConstants</code>
1803          * value.  If there is no conversion, returns
1804          * <code>null</code>.
1805          * By default, there is no conversion.
1806          *
1807          * @param key the <code>StyleConstants</code> attribute
1808          * @param v the view containing <code>AttributeSet</code>
1809          * @return the <code>StyleConstants</code> attribute value that
1810          *   represents the CSS attribute value
1811          */
1812         Object toStyleConstants(StyleConstants key, View v) {
1813             return null;
1814         }
1815 
1816         /**
1817          * Return the CSS format of the value
1818          */
1819         public String toString() {
1820             return svalue;
1821         }
1822 
1823         /**
1824          * The value as a string... before conversion to a
1825          * binary format.
1826          */
1827         String svalue;
1828     }
1829 


1834      * value as a string (via the superclass), but
1835      * provides StyleConstants conversion support for the
1836      * CSS attributes that are held as strings.
1837      */
1838     @SuppressWarnings("serial") // Same-version serialization only
1839     static class StringValue extends CssValue {
1840 
1841         /**
1842          * Convert a CSS value string to the internal format
1843          * (for fast processing) used in the attribute sets.
1844          * This produces a StringValue, so that it can be
1845          * used to convert from CSS to StyleConstants values.
1846          */
1847         Object parseCssValue(String value) {
1848             StringValue sv = new StringValue();
1849             sv.svalue = value;
1850             return sv;
1851         }
1852 
1853         /**
1854          * Converts a <code>StyleConstants</code> attribute value to
1855          * a CSS attribute value.  If there is no conversion
1856          * returns <code>null</code>.
1857          *
1858          * @param key the <code>StyleConstants</code> attribute
1859          * @param value the value of a <code>StyleConstants</code>
1860          *   attribute to be converted
1861          * @return the CSS value that represents the
1862          *   <code>StyleConstants</code> value
1863          */
1864         Object fromStyleConstants(StyleConstants key, Object value) {
1865             if (key == StyleConstants.Italic) {
1866                 if (value.equals(Boolean.TRUE)) {
1867                     return parseCssValue("italic");
1868                 }
1869                 return parseCssValue("");
1870             } else if (key == StyleConstants.Underline) {
1871                 if (value.equals(Boolean.TRUE)) {
1872                     return parseCssValue("underline");
1873                 }
1874                 return parseCssValue("");
1875             } else if (key == StyleConstants.Alignment) {
1876                 int align = ((Integer)value).intValue();
1877                 String ta;
1878                 switch(align) {
1879                 case StyleConstants.ALIGN_LEFT:
1880                     ta = "left";
1881                     break;
1882                 case StyleConstants.ALIGN_RIGHT:


1896                 if (value.equals(Boolean.TRUE)) {
1897                     return parseCssValue("line-through");
1898                 }
1899                 return parseCssValue("");
1900             } else if (key == StyleConstants.Superscript) {
1901                 if (value.equals(Boolean.TRUE)) {
1902                     return parseCssValue("super");
1903                 }
1904                 return parseCssValue("");
1905             } else if (key == StyleConstants.Subscript) {
1906                 if (value.equals(Boolean.TRUE)) {
1907                     return parseCssValue("sub");
1908                 }
1909                 return parseCssValue("");
1910             }
1911             return null;
1912         }
1913 
1914         /**
1915          * Converts a CSS attribute value to a
1916          * <code>StyleConstants</code> value.
1917          * If there is no conversion, returns <code>null</code>.
1918          * By default, there is no conversion.
1919          *
1920          * @param key the <code>StyleConstants</code> attribute
1921          * @return the <code>StyleConstants</code> attribute value that
1922          *   represents the CSS attribute value
1923          */
1924         Object toStyleConstants(StyleConstants key, View v) {
1925             if (key == StyleConstants.Italic) {
1926                 if (svalue.indexOf("italic") >= 0) {
1927                     return Boolean.TRUE;
1928                 }
1929                 return Boolean.FALSE;
1930             } else if (key == StyleConstants.Underline) {
1931                 if (svalue.indexOf("underline") >= 0) {
1932                     return Boolean.TRUE;
1933                 }
1934                 return Boolean.FALSE;
1935             } else if (key == StyleConstants.Alignment) {
1936                 if (svalue.equals("right")) {
1937                     return StyleConstants.ALIGN_RIGHT;
1938                 } else if (svalue.equals("center")) {
1939                     return StyleConstants.ALIGN_CENTER;
1940                 } else if  (svalue.equals("justify")) {
1941                     return StyleConstants.ALIGN_JUSTIFIED;


2102                     int relSize = -Integer.valueOf(value.substring(1)).intValue();
2103                     fs.value = baseFontSize + relSize;
2104                     fs.index = true;
2105                 } else {
2106                     fs.value = Integer.parseInt(value);
2107                     if (fs.value > 7) {
2108                         fs.value = 7;
2109                     } else if (fs.value < 0) {
2110                         fs.value = 0;
2111                     }
2112                     fs.index = true;
2113                 }
2114 
2115             } catch (NumberFormatException nfe) {
2116                 fs = null;
2117             }
2118             return fs;
2119         }
2120 
2121         /**
2122          * Converts a <code>StyleConstants</code> attribute value to
2123          * a CSS attribute value.  If there is no conversion
2124          * returns <code>null</code>.  By default, there is no conversion.
2125          *
2126          * @param key the <code>StyleConstants</code> attribute
2127          * @param value the value of a <code>StyleConstants</code>
2128          *   attribute to be converted
2129          * @return the CSS value that represents the
2130          *   <code>StyleConstants</code> value
2131          */
2132         Object fromStyleConstants(StyleConstants key, Object value) {
2133             if (value instanceof Number) {
2134                 FontSize fs = new FontSize();
2135 
2136                 fs.value = getIndexOfSize(((Number)value).floatValue(), StyleSheet.sizeMapDefault);
2137                 fs.svalue = Integer.toString((int)fs.value);
2138                 fs.index = true;
2139                 return fs;
2140             }
2141             return parseCssValue(value.toString());
2142         }
2143 
2144         /**
2145          * Converts a CSS attribute value to a <code>StyleConstants</code>
2146          * value.  If there is no conversion, returns <code>null</code>.
2147          * By default, there is no conversion.
2148          *
2149          * @param key the <code>StyleConstants</code> attribute
2150          * @return the <code>StyleConstants</code> attribute value that
2151          *   represents the CSS attribute value
2152          */
2153         Object toStyleConstants(StyleConstants key, View v) {
2154             if (v != null) {
2155                 return Integer.valueOf(getValue(v.getAttributes(), null));
2156             }
2157             return Integer.valueOf(getValue(null, null));
2158         }
2159 
2160         float value;
2161         boolean index;
2162         LengthUnit lu;
2163     }
2164 
2165     @SuppressWarnings("serial") // Same-version serialization only
2166     static class FontFamily extends CssValue {
2167 
2168         /**
2169          * Returns the font family to use.
2170          */


2213                         done = true;
2214                     }
2215                 }
2216             }
2217             if (ff.family == null) {
2218                 ff.family = Font.SANS_SERIF;
2219             }
2220             return ff;
2221         }
2222 
2223         private void setFontName(FontFamily ff, String fontName) {
2224             ff.family = fontName;
2225         }
2226 
2227         Object parseHtmlValue(String value) {
2228             // TBD
2229             return parseCssValue(value);
2230         }
2231 
2232         /**
2233          * Converts a <code>StyleConstants</code> attribute value to
2234          * a CSS attribute value.  If there is no conversion
2235          * returns <code>null</code>.  By default, there is no conversion.
2236          *
2237          * @param key the <code>StyleConstants</code> attribute
2238          * @param value the value of a <code>StyleConstants</code>
2239          *   attribute to be converted
2240          * @return the CSS value that represents the
2241          *   <code>StyleConstants</code> value
2242          */
2243         Object fromStyleConstants(StyleConstants key, Object value) {
2244             return parseCssValue(value.toString());
2245         }
2246 
2247         /**
2248          * Converts a CSS attribute value to a <code>StyleConstants</code>
2249          * value.  If there is no conversion, returns <code>null</code>.
2250          * By default, there is no conversion.
2251          *
2252          * @param key the <code>StyleConstants</code> attribute
2253          * @return the <code>StyleConstants</code> attribute value that
2254          *   represents the CSS attribute value
2255          */
2256         Object toStyleConstants(StyleConstants key, View v) {
2257             return family;
2258         }
2259 
2260         String family;
2261     }
2262 
2263     @SuppressWarnings("serial") // Same-version serialization only
2264     static class FontWeight extends CssValue {
2265 
2266         int getValue() {
2267             return weight;
2268         }
2269 
2270         Object parseCssValue(String value) {
2271             FontWeight fw = new FontWeight();
2272             fw.svalue = value;
2273             if (value.equals("bold")) {
2274                 fw.weight = 700;
2275             } else if (value.equals("normal")) {
2276                 fw.weight = 400;
2277             } else {
2278                 // PENDING(prinz) add support for relative values
2279                 try {
2280                     fw.weight = Integer.parseInt(value);
2281                 } catch (NumberFormatException nfe) {
2282                     fw = null;
2283                 }
2284             }
2285             return fw;
2286         }
2287 
2288         /**
2289          * Converts a <code>StyleConstants</code> attribute value to
2290          * a CSS attribute value.  If there is no conversion
2291          * returns <code>null</code>.  By default, there is no conversion.
2292          *
2293          * @param key the <code>StyleConstants</code> attribute
2294          * @param value the value of a <code>StyleConstants</code>
2295          *   attribute to be converted
2296          * @return the CSS value that represents the
2297          *   <code>StyleConstants</code> value
2298          */
2299         Object fromStyleConstants(StyleConstants key, Object value) {
2300             if (value.equals(Boolean.TRUE)) {
2301                 return parseCssValue("bold");
2302             }
2303             return parseCssValue("normal");
2304         }
2305 
2306         /**
2307          * Converts a CSS attribute value to a <code>StyleConstants</code>
2308          * value.  If there is no conversion, returns <code>null</code>.
2309          * By default, there is no conversion.
2310          *
2311          * @param key the <code>StyleConstants</code> attribute
2312          * @return the <code>StyleConstants</code> attribute value that
2313          *   represents the CSS attribute value
2314          */
2315         Object toStyleConstants(StyleConstants key, View v) {
2316             return (weight > 500) ? Boolean.TRUE : Boolean.FALSE;
2317         }
2318 
2319         boolean isBold() {
2320             return (weight > 500);
2321         }
2322 
2323         int weight;
2324     }
2325 
2326     @SuppressWarnings("serial") // Same-version serialization only
2327     static class ColorValue extends CssValue {
2328 
2329         /**
2330          * Returns the color to use.
2331          */
2332         Color getValue() {
2333             return c;
2334         }
2335 
2336         Object parseCssValue(String value) {
2337 
2338             Color c = stringToColor(value);
2339             if (c != null) {
2340                 ColorValue cv = new ColorValue();
2341                 cv.svalue = value;
2342                 cv.c = c;
2343                 return cv;
2344             }
2345             return null;
2346         }
2347 
2348         Object parseHtmlValue(String value) {
2349             return parseCssValue(value);
2350         }
2351 
2352         /**
2353          * Converts a <code>StyleConstants</code> attribute value to
2354          * a CSS attribute value.  If there is no conversion
2355          * returns <code>null</code>.  By default, there is no conversion.
2356          *
2357          * @param key the <code>StyleConstants</code> attribute
2358          * @param value the value of a <code>StyleConstants</code>
2359          *   attribute to be converted
2360          * @return the CSS value that represents the
2361          *   <code>StyleConstants</code> value
2362          */
2363         Object fromStyleConstants(StyleConstants key, Object value) {
2364             ColorValue colorValue = new ColorValue();
2365             colorValue.c = (Color)value;
2366             colorValue.svalue = colorToHex(colorValue.c);
2367             return colorValue;
2368         }
2369 
2370         /**
2371          * Converts a CSS attribute value to a <code>StyleConstants</code>
2372          * value.  If there is no conversion, returns <code>null</code>.
2373          * By default, there is no conversion.
2374          *
2375          * @param key the <code>StyleConstants</code> attribute
2376          * @return the <code>StyleConstants</code> attribute value that
2377          *   represents the CSS attribute value
2378          */
2379         Object toStyleConstants(StyleConstants key, View v) {
2380             return c;
2381         }
2382 
2383         Color c;
2384     }
2385 
2386     @SuppressWarnings("serial") // Same-version serialization only
2387     static class BorderStyle extends CssValue {
2388 
2389         CSS.Value getValue() {
2390             return style;
2391         }
2392 
2393         Object parseCssValue(String value) {
2394             CSS.Value cssv = CSS.getValue(value);
2395             if (cssv != null) {
2396                 if ((cssv == CSS.Value.INSET) ||


2448             this(false);
2449         }
2450 
2451         LengthValue(boolean mayBeNegative) {
2452             this.mayBeNegative = mayBeNegative;
2453         }
2454 
2455         /**
2456          * Returns the length (span) to use.
2457          */
2458         float getValue() {
2459             return getValue(false);
2460         }
2461 
2462         float getValue(boolean isW3CLengthUnits) {
2463             return getValue(0, isW3CLengthUnits);
2464         }
2465 
2466         /**
2467          * Returns the length (span) to use. If the value represents
2468          * a percentage, it is scaled based on <code>currentValue</code>.
2469          */
2470         float getValue(float currentValue) {
2471             return getValue(currentValue, false);
2472         }
2473         float getValue(float currentValue, boolean isW3CLengthUnits) {
2474             if (percentage) {
2475                 return span * currentValue;
2476             }
2477             return LengthUnit.getValue(span, units, isW3CLengthUnits);
2478         }
2479 
2480         /**
2481          * Returns true if the length represents a percentage of the
2482          * containing box.
2483          */
2484         boolean isPercentage() {
2485             return percentage;
2486         }
2487 
2488         Object parseCssValue(String value) {


2512                     // %
2513                     lv = new LengthValue();
2514                     lv.span = Math.max(0, Math.min(1, lu.value));
2515                     lv.percentage = true;
2516                     break;
2517                 default:
2518                     return null;
2519                 }
2520             }
2521             lv.svalue = value;
2522             return lv;
2523         }
2524 
2525         Object parseHtmlValue(String value) {
2526             if (value.equals(HTML.NULL_ATTRIBUTE_VALUE)) {
2527                 value = "1";
2528             }
2529             return parseCssValue(value);
2530         }
2531         /**
2532          * Converts a <code>StyleConstants</code> attribute value to
2533          * a CSS attribute value.  If there is no conversion,
2534          * returns <code>null</code>.  By default, there is no conversion.
2535          *
2536          * @param key the <code>StyleConstants</code> attribute
2537          * @param value the value of a <code>StyleConstants</code>
2538          *   attribute to be converted
2539          * @return the CSS value that represents the
2540          *   <code>StyleConstants</code> value
2541          */
2542         Object fromStyleConstants(StyleConstants key, Object value) {
2543             LengthValue v = new LengthValue();
2544             v.svalue = value.toString();
2545             v.span = ((Float)value).floatValue();
2546             return v;
2547         }
2548 
2549         /**
2550          * Converts a CSS attribute value to a <code>StyleConstants</code>
2551          * value.  If there is no conversion, returns <code>null</code>.
2552          * By default, there is no conversion.
2553          *
2554          * @param key the <code>StyleConstants</code> attribute
2555          * @return the <code>StyleConstants</code> attribute value that
2556          *   represents the CSS attribute value
2557          */
2558         Object toStyleConstants(StyleConstants key, View v) {
2559             return new Float(getValue(false));
2560         }
2561 
2562         /** If true, span is a percentage value, and that to determine
2563          * the length another value needs to be passed in. */
2564         boolean percentage;
2565         /** Either the absolute value (percentage == false) or
2566          * a percentage value. */
2567         float span;
2568 
2569         String units = null;
2570     }
2571 
2572 
2573     /**
2574      * BorderWidthValue is used to model BORDER_XXX_WIDTH and adds support
2575      * for the thin/medium/thick values.


2946         //     50% will have a value = .5
2947         // 2 - add value to parent value.
2948         // 3 - em/ex relative to font size of element (except for
2949         //     font-size, which is relative to parent).
2950         short type;
2951         float value;
2952         String units = null;
2953 
2954 
2955         static final short UNINITALIZED_LENGTH = (short)10;
2956     }
2957 
2958 
2959     /**
2960      * Class used to parse font property. The font property is shorthand
2961      * for the other font properties. This expands the properties, placing
2962      * them in the attributeset.
2963      */
2964     static class ShorthandFontParser {
2965         /**
2966          * Parses the shorthand font string <code>value</code>, placing the
2967          * result in <code>attr</code>.
2968          */
2969         static void parseShorthandFont(CSS css, String value,
2970                                        MutableAttributeSet attr) {
2971             // font is of the form:
2972             // [ <font-style> || <font-variant> || <font-weight> ]? <font-size>
2973             //   [ / <line-height> ]? <font-family>
2974             String[]   strings = CSS.parseStrings(value);
2975             int        count = strings.length;
2976             int        index = 0;
2977             // bitmask, 1 for style, 2 for variant, 3 for weight
2978             short      found = 0;
2979             int        maxC = Math.min(3, count);
2980 
2981             // Check for font-style font-variant font-weight
2982             while (index < maxC) {
2983                 if ((found & 1) == 0 && isFontStyle(strings[index])) {
2984                     css.addInternalCSSValue(attr, CSS.Attribute.FONT_STYLE,
2985                                             strings[index++]);
2986                     found |= 1;
2987                 }


3088 
3089         private static boolean isFontWeight(String string) {
3090             if (string.equals("bold") || string.equals("bolder") ||
3091                 string.equals("italic") || string.equals("lighter")) {
3092                 return true;
3093             }
3094             // test for 100-900
3095             return (string.length() == 3 &&
3096                     string.charAt(0) >= '1' && string.charAt(0) <= '9' &&
3097                     string.charAt(1) == '0' && string.charAt(2) == '0');
3098         }
3099 
3100     }
3101 
3102 
3103     /**
3104      * Parses the background property into its intrinsic values.
3105      */
3106     static class ShorthandBackgroundParser {
3107         /**
3108          * Parses the shorthand font string <code>value</code>, placing the
3109          * result in <code>attr</code>.
3110          */
3111         static void parseShorthandBackground(CSS css, String value,
3112                                              MutableAttributeSet attr) {
3113             String[] strings = parseStrings(value);
3114             int count = strings.length;
3115             int index = 0;
3116             // bitmask: 0 for image, 1 repeat, 2 attachment, 3 position,
3117             //          4 color
3118             short found = 0;
3119 
3120             while (index < count) {
3121                 String string = strings[index++];
3122                 if ((found & 1) == 0 && isImage(string)) {
3123                     css.addInternalCSSValue(attr, CSS.Attribute.
3124                                             BACKGROUND_IMAGE, string);
3125                     found |= 1;
3126                 }
3127                 else if ((found & 2) == 0 && isRepeat(string)) {
3128                     css.addInternalCSSValue(attr, CSS.Attribute.
3129                                             BACKGROUND_REPEAT, string);


3194         static boolean isPosition(String string) {
3195             return (string.equals("top") || string.equals("bottom") ||
3196                     string.equals("left") || string.equals("right") ||
3197                     string.equals("center") ||
3198                     (string.length() > 0 &&
3199                      Character.isDigit(string.charAt(0))));
3200         }
3201 
3202         static boolean isColor(String string) {
3203             return (CSS.stringToColor(string) != null);
3204         }
3205     }
3206 
3207 
3208     /**
3209      * Used to parser margin and padding.
3210      */
3211     static class ShorthandMarginParser {
3212         /**
3213          * Parses the shorthand margin/padding/border string
3214          * <code>value</code>, placing the result in <code>attr</code>.
3215          * <code>names</code> give the 4 instrinsic property names.
3216          */
3217         static void parseShorthandMargin(CSS css, String value,
3218                                          MutableAttributeSet attr,
3219                                          CSS.Attribute[] names) {
3220             String[] strings = parseStrings(value);
3221             int count = strings.length;
3222             int index = 0;
3223             switch (count) {
3224             case 0:
3225                 // empty string
3226                 return;
3227             case 1:
3228                 // Identifies all values.
3229                 for (int counter = 0; counter < 4; counter++) {
3230                     css.addInternalCSSValue(attr, names[counter], strings[0]);
3231                 }
3232                 break;
3233             case 2:
3234                 // 0 & 2 = strings[0], 1 & 3 = strings[1]
3235                 css.addInternalCSSValue(attr, names[0], strings[0]);




 718                            valueMapper);
 719         valueConvertor.put(CSS.Attribute.BACKGROUND_IMAGE,
 720                            new BackgroundImage());
 721         valueConvertor.put(CSS.Attribute.BACKGROUND_POSITION,
 722                            new BackgroundPosition());
 723         valueConvertor.put(CSS.Attribute.BACKGROUND_REPEAT,
 724                            valueMapper);
 725         valueConvertor.put(CSS.Attribute.BACKGROUND_ATTACHMENT,
 726                            valueMapper);
 727         Object generic = new CssValue();
 728         int n = CSS.Attribute.allAttributes.length;
 729         for (int i = 0; i < n; i++) {
 730             CSS.Attribute key = CSS.Attribute.allAttributes[i];
 731             if (valueConvertor.get(key) == null) {
 732                 valueConvertor.put(key, generic);
 733             }
 734         }
 735     }
 736 
 737     /**
 738      * Sets the base font size. {@code sz} is a CSS value, and is
 739      * not necessarily the point size. Use getPointSize to determine the
 740      * point size corresponding to {@code sz}.
 741      */
 742     void setBaseFontSize(int sz) {
 743         if (sz < 1)
 744           baseFontSize = 0;
 745         else if (sz > 7)
 746           baseFontSize = 7;
 747         else
 748           baseFontSize = sz;
 749     }
 750 
 751     /**
 752      * Sets the base font size from the passed in string.
 753      */
 754     void setBaseFontSize(String size) {
 755         int relSize, absSize, diff;
 756 
 757         if (size != null) {
 758             if (size.startsWith("+")) {
 759                 relSize = Integer.valueOf(size.substring(1)).intValue();
 760                 setBaseFontSize(baseFontSize + relSize);
 761             } else if (size.startsWith("-")) {
 762                 relSize = -Integer.valueOf(size.substring(1)).intValue();
 763                 setBaseFontSize(baseFontSize + relSize);
 764             } else {
 765                 setBaseFontSize(Integer.valueOf(size).intValue());
 766             }
 767         }
 768     }
 769 
 770     /**
 771      * Returns the base font size.
 772      */
 773     int getBaseFontSize() {
 774         return baseFontSize;
 775     }
 776 
 777     /**
 778      * Parses the CSS property {@code key} with value
 779      * {@code value} placing the result in {@code att}.
 780      */
 781     void addInternalCSSValue(MutableAttributeSet attr,
 782                              CSS.Attribute key, String value) {
 783         if (key == CSS.Attribute.FONT) {
 784             ShorthandFontParser.parseShorthandFont(this, value, attr);
 785         }
 786         else if (key == CSS.Attribute.BACKGROUND) {
 787             ShorthandBackgroundParser.parseShorthandBackground
 788                                (this, value, attr);
 789         }
 790         else if (key == CSS.Attribute.MARGIN) {
 791             ShorthandMarginParser.parseShorthandMargin(this, value, attr,
 792                                            CSS.Attribute.ALL_MARGINS);
 793         }
 794         else if (key == CSS.Attribute.PADDING) {
 795             ShorthandMarginParser.parseShorthandMargin(this, value, attr,
 796                                            CSS.Attribute.ALL_PADDING);
 797         }
 798         else if (key == CSS.Attribute.BORDER_WIDTH) {
 799             ShorthandMarginParser.parseShorthandMargin(this, value, attr,


 806         else if (key == CSS.Attribute.BORDER_STYLE) {
 807             ShorthandMarginParser.parseShorthandMargin(this, value, attr,
 808                                             CSS.Attribute.ALL_BORDER_STYLES);
 809         }
 810         else if ((key == CSS.Attribute.BORDER) ||
 811                    (key == CSS.Attribute.BORDER_TOP) ||
 812                    (key == CSS.Attribute.BORDER_RIGHT) ||
 813                    (key == CSS.Attribute.BORDER_BOTTOM) ||
 814                    (key == CSS.Attribute.BORDER_LEFT)) {
 815             ShorthandBorderParser.parseShorthandBorder(attr, key, value);
 816         }
 817         else {
 818             Object iValue = getInternalCSSValue(key, value);
 819             if (iValue != null) {
 820                 attr.addAttribute(key, iValue);
 821             }
 822         }
 823     }
 824 
 825     /**
 826      * Gets the internal CSS representation of {@code value} which is
 827      * a CSS value of the CSS attribute named {@code key}. The receiver
 828      * should not modify {@code value}, and the first {@code count}
 829      * strings are valid.
 830      */
 831     Object getInternalCSSValue(CSS.Attribute key, String value) {
 832         CssValue conv = (CssValue) valueConvertor.get(key);
 833         Object r = conv.parseCssValue(value);
 834         return r != null ? r : conv.parseCssValue(key.getDefaultValue());
 835     }
 836 
 837     /**
 838      * Maps from a StyleConstants to a CSS Attribute.
 839      */
 840     Attribute styleConstantsKeyToCSSKey(StyleConstants sc) {
 841         return styleConstantToCssMap.get(sc);
 842     }
 843 
 844     /**
 845      * Maps from a StyleConstants value to a CSS value.
 846      */
 847     Object styleConstantsValueToCSSValue(StyleConstants sc,
 848                                          Object styleValue) {
 849         Attribute cssKey = styleConstantsKeyToCSSKey(sc);
 850         if (cssKey != null) {
 851             CssValue conv = (CssValue)valueConvertor.get(cssKey);
 852             return conv.fromStyleConstants(sc, styleValue);
 853         }
 854         return null;
 855     }
 856 
 857     /**
 858      * Converts the passed in CSS value to a StyleConstants value.
 859      * {@code key} identifies the CSS attribute being mapped.
 860      */
 861     Object cssValueToStyleConstantsValue(StyleConstants key, Object value) {
 862         if (value instanceof CssValue) {
 863             return ((CssValue)value).toStyleConstants(key, null);
 864         }
 865         return null;
 866     }
 867 
 868     /**
 869      * Returns the font for the values in the passed in AttributeSet.
 870      * It is assumed the keys will be CSS.Attribute keys.
 871      * {@code sc} is the StyleContext that will be messaged to get
 872      * the font once the size, name and style have been determined.
 873      */
 874     Font getFont(StyleContext sc, AttributeSet a, int defaultSize, StyleSheet ss) {
 875         ss = getStyleSheet(ss);
 876         int size = getFontSize(a, defaultSize, ss);
 877 
 878         /*
 879          * If the vertical alignment is set to either superscript or
 880          * subscript we reduce the font size by 2 points.
 881          */
 882         StringValue vAlignV = (StringValue)a.getAttribute
 883                               (CSS.Attribute.VERTICAL_ALIGN);
 884         if ((vAlignV != null)) {
 885             String vAlign = vAlignV.toString();
 886             if ((vAlign.indexOf("sup") >= 0) ||
 887                 (vAlign.indexOf("sub") >= 0)) {
 888                 size -= 2;
 889             }
 890         }
 891 


 913             family = Font.SANS_SERIF;
 914             f = sc.getFont(family, style, size);
 915         }
 916         return f;
 917     }
 918 
 919     static int getFontSize(AttributeSet attr, int defaultSize, StyleSheet ss) {
 920         // PENDING(prinz) this is a 1.1 based implementation, need to also
 921         // have a 1.2 version.
 922         FontSize sizeValue = (FontSize)attr.getAttribute(CSS.Attribute.
 923                                                          FONT_SIZE);
 924 
 925         return (sizeValue != null) ? sizeValue.getValue(attr, ss)
 926                                    : defaultSize;
 927     }
 928 
 929     /**
 930      * Takes a set of attributes and turn it into a color
 931      * specification.  This might be used to specify things
 932      * like brighter, more hue, etc.
 933      * This will return null if there is no value for {@code key}.
 934      *
 935      * @param key CSS.Attribute identifying where color is stored.
 936      * @param a the set of attributes
 937      * @return the color
 938      */
 939     Color getColor(AttributeSet a, CSS.Attribute key) {
 940         ColorValue cv = (ColorValue) a.getAttribute(key);
 941         if (cv != null) {
 942             return cv.getValue();
 943         }
 944         return null;
 945     }
 946 
 947     /**
 948      * Returns the size of a font from the passed in string.
 949      *
 950      * @param size CSS string describing font size
 951      * @param baseFontSize size to use for relative units.
 952      */
 953     float getPointSize(String size, StyleSheet ss) {
 954         int relSize, absSize, diff, index;
 955         ss = getStyleSheet(ss);
 956         if (size != null) {
 957             if (size.startsWith("+")) {
 958                 relSize = Integer.valueOf(size.substring(1)).intValue();
 959                 return getPointSize(baseFontSize + relSize, ss);
 960             } else if (size.startsWith("-")) {
 961                 relSize = -Integer.valueOf(size.substring(1)).intValue();
 962                 return getPointSize(baseFontSize + relSize, ss);
 963             } else {
 964                 absSize = Integer.valueOf(size).intValue();
 965                 return getPointSize(absSize, ss);
 966             }
 967         }
 968         return 0;
 969     }
 970 
 971     /**
 972      * Returns the length of the attribute in {@code a} with
 973      * key {@code key}.
 974      */
 975     float getLength(AttributeSet a, CSS.Attribute key, StyleSheet ss) {
 976         ss = getStyleSheet(ss);
 977         LengthValue lv = (LengthValue) a.getAttribute(key);
 978         boolean isW3CLengthUnits = (ss == null) ? false : ss.isW3CLengthUnits();
 979         float len = (lv != null) ? lv.getValue(isW3CLengthUnits) : 0;
 980         return len;
 981     }
 982 
 983     /**
 984      * Convert a set of HTML attributes to an equivalent
 985      * set of CSS attributes.
 986      *
 987      * @param htmlAttrSet AttributeSet containing the HTML attributes.
 988      * @return AttributeSet containing the corresponding CSS attributes.
 989      *        The AttributeSet will be empty if there are no mapping
 990      *        CSS attributes.
 991      */
 992     AttributeSet translateHTMLToCSS(AttributeSet htmlAttrSet) {
 993         MutableAttributeSet cssAttrSet = new SimpleAttributeSet();


1219             for (Object key : keys) {
1220                 StyleContext.registerStaticAttributeKey(key);
1221             }
1222         } catch (Throwable e) {
1223             e.printStackTrace();
1224         }
1225     }
1226 
1227     /**
1228      * Return the set of all possible CSS attribute keys.
1229      *
1230      * @return the set of all possible CSS attribute keys
1231      */
1232     public static Attribute[] getAllAttributeKeys() {
1233         Attribute[] keys = new Attribute[Attribute.allAttributes.length];
1234         System.arraycopy(Attribute.allAttributes, 0, keys, 0, Attribute.allAttributes.length);
1235         return keys;
1236     }
1237 
1238     /**
1239      * Translates a string to a {@code CSS.Attribute} object.
1240      * This will return {@code null} if there is no attribute
1241      * by the given name.
1242      *
1243      * @param name the name of the CSS attribute to fetch the
1244      *  typesafe enumeration for
1245      * @return the {@code CSS.Attribute} object,
1246      *  or {@code null} if the string
1247      *  doesn't represent a valid attribute key
1248      */
1249     public static final Attribute getAttribute(String name) {
1250         return attributeMap.get(name);
1251     }
1252 
1253     /**
1254      * Translates a string to a {@code CSS.Value} object.
1255      * This will return {@code null} if there is no value
1256      * by the given name.
1257      *
1258      * @param name the name of the CSS value to fetch the
1259      *  typesafe enumeration for
1260      * @return the {@code CSS.Value} object,
1261      *  or {@code null} if the string
1262      *  doesn't represent a valid CSS value name; this does
1263      *  not mean that it doesn't represent a valid CSS value
1264      */
1265     static final Value getValue(String name) {
1266         return valueMap.get(name);
1267     }
1268 
1269 
1270     //
1271     // Conversion related methods/classes
1272     //
1273 
1274     /**
1275      * Returns a URL for the given CSS url string. If relative,
1276      * {@code base} is used as the parent. If a valid URL can not
1277      * be found, this will not throw a MalformedURLException, instead
1278      * null will be returned.
1279      */
1280     static URL getURL(URL base, String cssString) {
1281         if (cssString == null) {
1282             return null;
1283         }
1284         if (cssString.startsWith("url(") &&
1285             cssString.endsWith(")")) {
1286             cssString = cssString.substring(4, cssString.length() - 1);
1287         }
1288         // Absolute first
1289         try {
1290             URL url = new URL(cssString);
1291             if (url != null) {
1292                 return url;
1293             }
1294         } catch (MalformedURLException mue) {
1295         }
1296         // Then relative


1407       else if(str.equalsIgnoreCase("Olive"))
1408         color = hexToColor("#808000");
1409       else if(str.equalsIgnoreCase("Yellow"))
1410         color = hexToColor("#FFFF00");
1411       else if(str.equalsIgnoreCase("Navy"))
1412         color = hexToColor("#000080");
1413       else if(str.equalsIgnoreCase("Blue"))
1414         color = hexToColor("#0000FF");
1415       else if(str.equalsIgnoreCase("Teal"))
1416         color = hexToColor("#008080");
1417       else if(str.equalsIgnoreCase("Aqua"))
1418         color = hexToColor("#00FFFF");
1419       else if(str.equalsIgnoreCase("Orange"))
1420         color = hexToColor("#FF8000");
1421       else
1422           color = hexToColor(str); // sometimes get specified without leading #
1423       return color;
1424     }
1425 
1426     /**
1427      * Parses a String in the format {@code rgb(r, g, b)} where
1428      * each of the Color components is either an integer, or a floating number
1429      * with a % after indicating a percentage value of 255. Values are
1430      * constrained to fit with 0-255. The resulting Color is returned.
1431      */
1432     private static Color parseRGB(String string) {
1433         // Find the next numeric char
1434         int[] index = new int[1];
1435 
1436         index[0] = 4;
1437         int red = getColorComponent(string, index);
1438         int green = getColorComponent(string, index);
1439         int blue = getColorComponent(string, index);
1440 
1441         return new Color(red, green, blue);
1442     }
1443 
1444     /**
1445      * Returns the next integer value from {@code string} starting
1446      * at {@code index[0]}. The value can either can an integer, or
1447      * a percentage (floating number ending with %), in which case it is
1448      * multiplied by 255.
1449      */
1450     private static int getColorComponent(String string, int[] index) {
1451         int length = string.length();
1452         char aChar;
1453 
1454         // Skip non-decimal chars
1455         while(index[0] < length && (aChar = string.charAt(index[0])) != '-' &&
1456               !Character.isDigit(aChar) && aChar != '.') {
1457             index[0]++;
1458         }
1459 
1460         int start = index[0];
1461 
1462         if (start < length && string.charAt(index[0]) == '-') {
1463             index[0]++;
1464         }
1465         while(index[0] < length &&
1466                          Character.isDigit(string.charAt(index[0]))) {


1489             }
1490         }
1491         return 0;
1492     }
1493 
1494     static int getIndexOfSize(float pt, int[] sizeMap) {
1495         for (int i = 0; i < sizeMap.length; i ++ )
1496                 if (pt <= sizeMap[i])
1497                         return i + 1;
1498         return sizeMap.length;
1499     }
1500 
1501     static int getIndexOfSize(float pt, StyleSheet ss) {
1502         int[] sizeMap = (ss != null) ? ss.getSizeMap() :
1503             StyleSheet.sizeMapDefault;
1504         return getIndexOfSize(pt, sizeMap);
1505     }
1506 
1507 
1508     /**
1509      * @return an array of all the strings in {@code value}
1510      *         that are separated by whitespace.
1511      */
1512     static String[] parseStrings(String value) {
1513         int         current, last;
1514         int         length = (value == null) ? 0 : value.length();
1515         Vector<String> temp = new Vector<String>(4);
1516 
1517         current = 0;
1518         while (current < length) {
1519             // Skip ws
1520             while (current < length && Character.isWhitespace
1521                    (value.charAt(current))) {
1522                 current++;
1523             }
1524             last = current;
1525             while (current < length && !Character.isWhitespace
1526                    (value.charAt(current))) {
1527                 current++;
1528             }
1529             if (last != current) {


1766          * have a special binary format for is a String.
1767          */
1768         Object parseCssValue(String value) {
1769             return value;
1770         }
1771 
1772         /**
1773          * Convert an HTML attribute value to a CSS attribute
1774          * value.  If there is no conversion, return null.
1775          * This is implemented to simply forward to the CSS
1776          * parsing by default (since some of the attribute
1777          * values are the same).  If the attribute value
1778          * isn't recognized as a CSS value it is generally
1779          * returned as null.
1780          */
1781         Object parseHtmlValue(String value) {
1782             return parseCssValue(value);
1783         }
1784 
1785         /**
1786          * Converts a {@code StyleConstants} attribute value to
1787          * a CSS attribute value.  If there is no conversion,
1788          * returns {@code null}.  By default, there is no conversion.
1789          *
1790          * @param key the {@code StyleConstants} attribute
1791          * @param value the value of a {@code StyleConstants}
1792          *   attribute to be converted
1793          * @return the CSS value that represents the
1794          *   {@code StyleConstants} value
1795          */
1796         Object fromStyleConstants(StyleConstants key, Object value) {
1797             return null;
1798         }
1799 
1800         /**
1801          * Converts a CSS attribute value to a
1802          * {@code StyleConstants}
1803          * value.  If there is no conversion, returns
1804          * {@code null}.
1805          * By default, there is no conversion.
1806          *
1807          * @param key the {@code StyleConstants} attribute
1808          * @param v the view containing {@code AttributeSet}
1809          * @return the {@code StyleConstants} attribute value that
1810          *   represents the CSS attribute value
1811          */
1812         Object toStyleConstants(StyleConstants key, View v) {
1813             return null;
1814         }
1815 
1816         /**
1817          * Return the CSS format of the value
1818          */
1819         public String toString() {
1820             return svalue;
1821         }
1822 
1823         /**
1824          * The value as a string... before conversion to a
1825          * binary format.
1826          */
1827         String svalue;
1828     }
1829 


1834      * value as a string (via the superclass), but
1835      * provides StyleConstants conversion support for the
1836      * CSS attributes that are held as strings.
1837      */
1838     @SuppressWarnings("serial") // Same-version serialization only
1839     static class StringValue extends CssValue {
1840 
1841         /**
1842          * Convert a CSS value string to the internal format
1843          * (for fast processing) used in the attribute sets.
1844          * This produces a StringValue, so that it can be
1845          * used to convert from CSS to StyleConstants values.
1846          */
1847         Object parseCssValue(String value) {
1848             StringValue sv = new StringValue();
1849             sv.svalue = value;
1850             return sv;
1851         }
1852 
1853         /**
1854          * Converts a {@code StyleConstants} attribute value to
1855          * a CSS attribute value.  If there is no conversion
1856          * returns {@code null}.
1857          *
1858          * @param key the {@code StyleConstants} attribute
1859          * @param value the value of a {@code StyleConstants}
1860          *   attribute to be converted
1861          * @return the CSS value that represents the
1862          *   {@code StyleConstants} value
1863          */
1864         Object fromStyleConstants(StyleConstants key, Object value) {
1865             if (key == StyleConstants.Italic) {
1866                 if (value.equals(Boolean.TRUE)) {
1867                     return parseCssValue("italic");
1868                 }
1869                 return parseCssValue("");
1870             } else if (key == StyleConstants.Underline) {
1871                 if (value.equals(Boolean.TRUE)) {
1872                     return parseCssValue("underline");
1873                 }
1874                 return parseCssValue("");
1875             } else if (key == StyleConstants.Alignment) {
1876                 int align = ((Integer)value).intValue();
1877                 String ta;
1878                 switch(align) {
1879                 case StyleConstants.ALIGN_LEFT:
1880                     ta = "left";
1881                     break;
1882                 case StyleConstants.ALIGN_RIGHT:


1896                 if (value.equals(Boolean.TRUE)) {
1897                     return parseCssValue("line-through");
1898                 }
1899                 return parseCssValue("");
1900             } else if (key == StyleConstants.Superscript) {
1901                 if (value.equals(Boolean.TRUE)) {
1902                     return parseCssValue("super");
1903                 }
1904                 return parseCssValue("");
1905             } else if (key == StyleConstants.Subscript) {
1906                 if (value.equals(Boolean.TRUE)) {
1907                     return parseCssValue("sub");
1908                 }
1909                 return parseCssValue("");
1910             }
1911             return null;
1912         }
1913 
1914         /**
1915          * Converts a CSS attribute value to a
1916          * {@code StyleConstants} value.
1917          * If there is no conversion, returns {@code null}.
1918          * By default, there is no conversion.
1919          *
1920          * @param key the {@code StyleConstants} attribute
1921          * @return the {@code StyleConstants} attribute value that
1922          *   represents the CSS attribute value
1923          */
1924         Object toStyleConstants(StyleConstants key, View v) {
1925             if (key == StyleConstants.Italic) {
1926                 if (svalue.indexOf("italic") >= 0) {
1927                     return Boolean.TRUE;
1928                 }
1929                 return Boolean.FALSE;
1930             } else if (key == StyleConstants.Underline) {
1931                 if (svalue.indexOf("underline") >= 0) {
1932                     return Boolean.TRUE;
1933                 }
1934                 return Boolean.FALSE;
1935             } else if (key == StyleConstants.Alignment) {
1936                 if (svalue.equals("right")) {
1937                     return StyleConstants.ALIGN_RIGHT;
1938                 } else if (svalue.equals("center")) {
1939                     return StyleConstants.ALIGN_CENTER;
1940                 } else if  (svalue.equals("justify")) {
1941                     return StyleConstants.ALIGN_JUSTIFIED;


2102                     int relSize = -Integer.valueOf(value.substring(1)).intValue();
2103                     fs.value = baseFontSize + relSize;
2104                     fs.index = true;
2105                 } else {
2106                     fs.value = Integer.parseInt(value);
2107                     if (fs.value > 7) {
2108                         fs.value = 7;
2109                     } else if (fs.value < 0) {
2110                         fs.value = 0;
2111                     }
2112                     fs.index = true;
2113                 }
2114 
2115             } catch (NumberFormatException nfe) {
2116                 fs = null;
2117             }
2118             return fs;
2119         }
2120 
2121         /**
2122          * Converts a {@code StyleConstants} attribute value to
2123          * a CSS attribute value.  If there is no conversion
2124          * returns {@code null}.  By default, there is no conversion.
2125          *
2126          * @param key the {@code StyleConstants} attribute
2127          * @param value the value of a {@code StyleConstants}
2128          *   attribute to be converted
2129          * @return the CSS value that represents the
2130          *   {@code StyleConstants} value
2131          */
2132         Object fromStyleConstants(StyleConstants key, Object value) {
2133             if (value instanceof Number) {
2134                 FontSize fs = new FontSize();
2135 
2136                 fs.value = getIndexOfSize(((Number)value).floatValue(), StyleSheet.sizeMapDefault);
2137                 fs.svalue = Integer.toString((int)fs.value);
2138                 fs.index = true;
2139                 return fs;
2140             }
2141             return parseCssValue(value.toString());
2142         }
2143 
2144         /**
2145          * Converts a CSS attribute value to a {@code StyleConstants}
2146          * value.  If there is no conversion, returns {@code null}.
2147          * By default, there is no conversion.
2148          *
2149          * @param key the {@code StyleConstants} attribute
2150          * @return the {@code StyleConstants} attribute value that
2151          *   represents the CSS attribute value
2152          */
2153         Object toStyleConstants(StyleConstants key, View v) {
2154             if (v != null) {
2155                 return Integer.valueOf(getValue(v.getAttributes(), null));
2156             }
2157             return Integer.valueOf(getValue(null, null));
2158         }
2159 
2160         float value;
2161         boolean index;
2162         LengthUnit lu;
2163     }
2164 
2165     @SuppressWarnings("serial") // Same-version serialization only
2166     static class FontFamily extends CssValue {
2167 
2168         /**
2169          * Returns the font family to use.
2170          */


2213                         done = true;
2214                     }
2215                 }
2216             }
2217             if (ff.family == null) {
2218                 ff.family = Font.SANS_SERIF;
2219             }
2220             return ff;
2221         }
2222 
2223         private void setFontName(FontFamily ff, String fontName) {
2224             ff.family = fontName;
2225         }
2226 
2227         Object parseHtmlValue(String value) {
2228             // TBD
2229             return parseCssValue(value);
2230         }
2231 
2232         /**
2233          * Converts a {@code StyleConstants} attribute value to
2234          * a CSS attribute value.  If there is no conversion
2235          * returns {@code null}.  By default, there is no conversion.
2236          *
2237          * @param key the {@code StyleConstants} attribute
2238          * @param value the value of a {@code StyleConstants}
2239          *   attribute to be converted
2240          * @return the CSS value that represents the
2241          *   {@code StyleConstants} value
2242          */
2243         Object fromStyleConstants(StyleConstants key, Object value) {
2244             return parseCssValue(value.toString());
2245         }
2246 
2247         /**
2248          * Converts a CSS attribute value to a {@code StyleConstants}
2249          * value.  If there is no conversion, returns {@code null}.
2250          * By default, there is no conversion.
2251          *
2252          * @param key the {@code StyleConstants} attribute
2253          * @return the {@code StyleConstants} attribute value that
2254          *   represents the CSS attribute value
2255          */
2256         Object toStyleConstants(StyleConstants key, View v) {
2257             return family;
2258         }
2259 
2260         String family;
2261     }
2262 
2263     @SuppressWarnings("serial") // Same-version serialization only
2264     static class FontWeight extends CssValue {
2265 
2266         int getValue() {
2267             return weight;
2268         }
2269 
2270         Object parseCssValue(String value) {
2271             FontWeight fw = new FontWeight();
2272             fw.svalue = value;
2273             if (value.equals("bold")) {
2274                 fw.weight = 700;
2275             } else if (value.equals("normal")) {
2276                 fw.weight = 400;
2277             } else {
2278                 // PENDING(prinz) add support for relative values
2279                 try {
2280                     fw.weight = Integer.parseInt(value);
2281                 } catch (NumberFormatException nfe) {
2282                     fw = null;
2283                 }
2284             }
2285             return fw;
2286         }
2287 
2288         /**
2289          * Converts a {@code StyleConstants} attribute value to
2290          * a CSS attribute value.  If there is no conversion
2291          * returns {@code null}.  By default, there is no conversion.
2292          *
2293          * @param key the {@code StyleConstants} attribute
2294          * @param value the value of a {@code StyleConstants}
2295          *   attribute to be converted
2296          * @return the CSS value that represents the
2297          *   {@code StyleConstants} value
2298          */
2299         Object fromStyleConstants(StyleConstants key, Object value) {
2300             if (value.equals(Boolean.TRUE)) {
2301                 return parseCssValue("bold");
2302             }
2303             return parseCssValue("normal");
2304         }
2305 
2306         /**
2307          * Converts a CSS attribute value to a {@code StyleConstants}
2308          * value.  If there is no conversion, returns {@code null}.
2309          * By default, there is no conversion.
2310          *
2311          * @param key the {@code StyleConstants} attribute
2312          * @return the {@code StyleConstants} attribute value that
2313          *   represents the CSS attribute value
2314          */
2315         Object toStyleConstants(StyleConstants key, View v) {
2316             return (weight > 500) ? Boolean.TRUE : Boolean.FALSE;
2317         }
2318 
2319         boolean isBold() {
2320             return (weight > 500);
2321         }
2322 
2323         int weight;
2324     }
2325 
2326     @SuppressWarnings("serial") // Same-version serialization only
2327     static class ColorValue extends CssValue {
2328 
2329         /**
2330          * Returns the color to use.
2331          */
2332         Color getValue() {
2333             return c;
2334         }
2335 
2336         Object parseCssValue(String value) {
2337 
2338             Color c = stringToColor(value);
2339             if (c != null) {
2340                 ColorValue cv = new ColorValue();
2341                 cv.svalue = value;
2342                 cv.c = c;
2343                 return cv;
2344             }
2345             return null;
2346         }
2347 
2348         Object parseHtmlValue(String value) {
2349             return parseCssValue(value);
2350         }
2351 
2352         /**
2353          * Converts a {@code StyleConstants} attribute value to
2354          * a CSS attribute value.  If there is no conversion
2355          * returns {@code null}.  By default, there is no conversion.
2356          *
2357          * @param key the {@code StyleConstants} attribute
2358          * @param value the value of a {@code StyleConstants}
2359          *   attribute to be converted
2360          * @return the CSS value that represents the
2361          *   {@code StyleConstants} value
2362          */
2363         Object fromStyleConstants(StyleConstants key, Object value) {
2364             ColorValue colorValue = new ColorValue();
2365             colorValue.c = (Color)value;
2366             colorValue.svalue = colorToHex(colorValue.c);
2367             return colorValue;
2368         }
2369 
2370         /**
2371          * Converts a CSS attribute value to a {@code StyleConstants}
2372          * value.  If there is no conversion, returns {@code null}.
2373          * By default, there is no conversion.
2374          *
2375          * @param key the {@code StyleConstants} attribute
2376          * @return the {@code StyleConstants} attribute value that
2377          *   represents the CSS attribute value
2378          */
2379         Object toStyleConstants(StyleConstants key, View v) {
2380             return c;
2381         }
2382 
2383         Color c;
2384     }
2385 
2386     @SuppressWarnings("serial") // Same-version serialization only
2387     static class BorderStyle extends CssValue {
2388 
2389         CSS.Value getValue() {
2390             return style;
2391         }
2392 
2393         Object parseCssValue(String value) {
2394             CSS.Value cssv = CSS.getValue(value);
2395             if (cssv != null) {
2396                 if ((cssv == CSS.Value.INSET) ||


2448             this(false);
2449         }
2450 
2451         LengthValue(boolean mayBeNegative) {
2452             this.mayBeNegative = mayBeNegative;
2453         }
2454 
2455         /**
2456          * Returns the length (span) to use.
2457          */
2458         float getValue() {
2459             return getValue(false);
2460         }
2461 
2462         float getValue(boolean isW3CLengthUnits) {
2463             return getValue(0, isW3CLengthUnits);
2464         }
2465 
2466         /**
2467          * Returns the length (span) to use. If the value represents
2468          * a percentage, it is scaled based on {@code currentValue}.
2469          */
2470         float getValue(float currentValue) {
2471             return getValue(currentValue, false);
2472         }
2473         float getValue(float currentValue, boolean isW3CLengthUnits) {
2474             if (percentage) {
2475                 return span * currentValue;
2476             }
2477             return LengthUnit.getValue(span, units, isW3CLengthUnits);
2478         }
2479 
2480         /**
2481          * Returns true if the length represents a percentage of the
2482          * containing box.
2483          */
2484         boolean isPercentage() {
2485             return percentage;
2486         }
2487 
2488         Object parseCssValue(String value) {


2512                     // %
2513                     lv = new LengthValue();
2514                     lv.span = Math.max(0, Math.min(1, lu.value));
2515                     lv.percentage = true;
2516                     break;
2517                 default:
2518                     return null;
2519                 }
2520             }
2521             lv.svalue = value;
2522             return lv;
2523         }
2524 
2525         Object parseHtmlValue(String value) {
2526             if (value.equals(HTML.NULL_ATTRIBUTE_VALUE)) {
2527                 value = "1";
2528             }
2529             return parseCssValue(value);
2530         }
2531         /**
2532          * Converts a {@code StyleConstants} attribute value to
2533          * a CSS attribute value.  If there is no conversion,
2534          * returns {@code null}.  By default, there is no conversion.
2535          *
2536          * @param key the {@code StyleConstants} attribute
2537          * @param value the value of a {@code StyleConstants}
2538          *   attribute to be converted
2539          * @return the CSS value that represents the
2540          *   {@code StyleConstants} value
2541          */
2542         Object fromStyleConstants(StyleConstants key, Object value) {
2543             LengthValue v = new LengthValue();
2544             v.svalue = value.toString();
2545             v.span = ((Float)value).floatValue();
2546             return v;
2547         }
2548 
2549         /**
2550          * Converts a CSS attribute value to a {@code StyleConstants}
2551          * value.  If there is no conversion, returns {@code null}.
2552          * By default, there is no conversion.
2553          *
2554          * @param key the {@code StyleConstants} attribute
2555          * @return the {@code StyleConstants} attribute value that
2556          *   represents the CSS attribute value
2557          */
2558         Object toStyleConstants(StyleConstants key, View v) {
2559             return new Float(getValue(false));
2560         }
2561 
2562         /** If true, span is a percentage value, and that to determine
2563          * the length another value needs to be passed in. */
2564         boolean percentage;
2565         /** Either the absolute value (percentage == false) or
2566          * a percentage value. */
2567         float span;
2568 
2569         String units = null;
2570     }
2571 
2572 
2573     /**
2574      * BorderWidthValue is used to model BORDER_XXX_WIDTH and adds support
2575      * for the thin/medium/thick values.


2946         //     50% will have a value = .5
2947         // 2 - add value to parent value.
2948         // 3 - em/ex relative to font size of element (except for
2949         //     font-size, which is relative to parent).
2950         short type;
2951         float value;
2952         String units = null;
2953 
2954 
2955         static final short UNINITALIZED_LENGTH = (short)10;
2956     }
2957 
2958 
2959     /**
2960      * Class used to parse font property. The font property is shorthand
2961      * for the other font properties. This expands the properties, placing
2962      * them in the attributeset.
2963      */
2964     static class ShorthandFontParser {
2965         /**
2966          * Parses the shorthand font string {@code value}, placing the
2967          * result in {@code attr}.
2968          */
2969         static void parseShorthandFont(CSS css, String value,
2970                                        MutableAttributeSet attr) {
2971             // font is of the form:
2972             // [ <font-style> || <font-variant> || <font-weight> ]? <font-size>
2973             //   [ / <line-height> ]? <font-family>
2974             String[]   strings = CSS.parseStrings(value);
2975             int        count = strings.length;
2976             int        index = 0;
2977             // bitmask, 1 for style, 2 for variant, 3 for weight
2978             short      found = 0;
2979             int        maxC = Math.min(3, count);
2980 
2981             // Check for font-style font-variant font-weight
2982             while (index < maxC) {
2983                 if ((found & 1) == 0 && isFontStyle(strings[index])) {
2984                     css.addInternalCSSValue(attr, CSS.Attribute.FONT_STYLE,
2985                                             strings[index++]);
2986                     found |= 1;
2987                 }


3088 
3089         private static boolean isFontWeight(String string) {
3090             if (string.equals("bold") || string.equals("bolder") ||
3091                 string.equals("italic") || string.equals("lighter")) {
3092                 return true;
3093             }
3094             // test for 100-900
3095             return (string.length() == 3 &&
3096                     string.charAt(0) >= '1' && string.charAt(0) <= '9' &&
3097                     string.charAt(1) == '0' && string.charAt(2) == '0');
3098         }
3099 
3100     }
3101 
3102 
3103     /**
3104      * Parses the background property into its intrinsic values.
3105      */
3106     static class ShorthandBackgroundParser {
3107         /**
3108          * Parses the shorthand font string {@code value}, placing the
3109          * result in {@code attr}.
3110          */
3111         static void parseShorthandBackground(CSS css, String value,
3112                                              MutableAttributeSet attr) {
3113             String[] strings = parseStrings(value);
3114             int count = strings.length;
3115             int index = 0;
3116             // bitmask: 0 for image, 1 repeat, 2 attachment, 3 position,
3117             //          4 color
3118             short found = 0;
3119 
3120             while (index < count) {
3121                 String string = strings[index++];
3122                 if ((found & 1) == 0 && isImage(string)) {
3123                     css.addInternalCSSValue(attr, CSS.Attribute.
3124                                             BACKGROUND_IMAGE, string);
3125                     found |= 1;
3126                 }
3127                 else if ((found & 2) == 0 && isRepeat(string)) {
3128                     css.addInternalCSSValue(attr, CSS.Attribute.
3129                                             BACKGROUND_REPEAT, string);


3194         static boolean isPosition(String string) {
3195             return (string.equals("top") || string.equals("bottom") ||
3196                     string.equals("left") || string.equals("right") ||
3197                     string.equals("center") ||
3198                     (string.length() > 0 &&
3199                      Character.isDigit(string.charAt(0))));
3200         }
3201 
3202         static boolean isColor(String string) {
3203             return (CSS.stringToColor(string) != null);
3204         }
3205     }
3206 
3207 
3208     /**
3209      * Used to parser margin and padding.
3210      */
3211     static class ShorthandMarginParser {
3212         /**
3213          * Parses the shorthand margin/padding/border string
3214          * {@code value}, placing the result in {@code attr}.
3215          * {@code names} give the 4 instrinsic property names.
3216          */
3217         static void parseShorthandMargin(CSS css, String value,
3218                                          MutableAttributeSet attr,
3219                                          CSS.Attribute[] names) {
3220             String[] strings = parseStrings(value);
3221             int count = strings.length;
3222             int index = 0;
3223             switch (count) {
3224             case 0:
3225                 // empty string
3226                 return;
3227             case 1:
3228                 // Identifies all values.
3229                 for (int counter = 0; counter < 4; counter++) {
3230                     css.addInternalCSSValue(attr, names[counter], strings[0]);
3231                 }
3232                 break;
3233             case 2:
3234                 // 0 & 2 = strings[0], 1 & 3 = strings[1]
3235                 css.addInternalCSSValue(attr, names[0], strings[0]);


< prev index next >