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]);
|