1. /*
  2. * @(#)CSS.java 1.30 00/02/02
  3. *
  4. * Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing.text.html;
  11. import java.awt.Color;
  12. import java.awt.Font;
  13. import java.awt.Toolkit;
  14. import java.io.*;
  15. import java.lang.reflect.Method;
  16. import java.net.URL;
  17. import java.net.MalformedURLException;
  18. import java.util.Enumeration;
  19. import java.util.Hashtable;
  20. import java.util.Vector;
  21. import javax.swing.ImageIcon;
  22. import javax.swing.SizeRequirements;
  23. import javax.swing.text.*;
  24. /**
  25. * Defines a set of
  26. * <a href="http://www.w3.org/TR/REC-CSS1">CSS attributes</a>
  27. * as a typesafe enumeration. The HTML View implementations use
  28. * CSS attributes to determine how they will render. This also defines
  29. * methods to map between CSS/HTML/StyleConstants. Any shorthand
  30. * properties, such as font, are mapped to the intrinsic properties.
  31. * <p>The following describes the CSS properties that are suppored by the
  32. * rendering engine:
  33. * <ul><li>font-family
  34. * <li>font-style
  35. * <li>font-size (supports relative units)
  36. * <li>font-weight
  37. * <li>font
  38. * <li>color
  39. * <li>background-color (with the exception of transparent)
  40. * <li>background-image
  41. * <li>background-repeat
  42. * <li>background-position
  43. * <li>background
  44. * <li>background-repeat
  45. * <li>text-decoration (with the exception of blink and overline)
  46. * <li>vertical-align (only sup and super)
  47. * <li>text-align (justify is treated as center)
  48. * <li>margin-top
  49. * <li>margin-right
  50. * <li>margin-bottom
  51. * <li>margin-left
  52. * <li>margin
  53. * <li>padding-top
  54. * <li>padding-right
  55. * <li>padding-bottom
  56. * <li>padding-left
  57. * <li>border-style (only supports inset, outset and none)
  58. * <li>list-style-type
  59. * <li>list-style-position
  60. * </ul>
  61. * The following are modeled, but currently not rendered.
  62. * <ul><li>font-variant
  63. * <li>background-attachment (background always treated as scroll)
  64. * <li>word-spacing
  65. * <li>letter-spacing
  66. * <li>text-indent
  67. * <li>text-transform
  68. * <li>line-height
  69. * <li>border-top-width (this is used to indicate if a border should be used)
  70. * <li>border-right-width
  71. * <li>border-bottom-width
  72. * <li>border-left-width
  73. * <li>border-width
  74. * <li>border-top
  75. * <li>border-right
  76. * <li>border-bottom
  77. * <li>border-left
  78. * <li>border
  79. * <li>width
  80. * <li>height
  81. * <li>float
  82. * <li>clear
  83. * <li>display
  84. * <li>white-space
  85. * <li>list-style
  86. * </ul>
  87. * <p><b>Note: for the time being we do not fully support relative units,
  88. * unless noted, so that
  89. * p { margin-top: 10% } will be treated as if no margin-top was specified.
  90. *
  91. * @author Timothy Prinzing
  92. * @author Scott Violet
  93. * @version 1.30 02/02/00
  94. * @see StyleSheet
  95. */
  96. public class CSS implements Serializable {
  97. /**
  98. * Definitions to be used as a key on AttributeSet's
  99. * that might hold CSS attributes. Since this is a
  100. * closed set (i.e. defined exactly by the specification),
  101. * it is final and cannot be extended.
  102. */
  103. public static final class Attribute {
  104. private Attribute(String name, String defaultValue, boolean inherited) {
  105. this.name = name;
  106. this.defaultValue = defaultValue;
  107. this.inherited = inherited;
  108. }
  109. /**
  110. * The string representation of the attribute. This
  111. * should exactly match the string specified in the
  112. * CSS specification.
  113. */
  114. public String toString() {
  115. return name;
  116. }
  117. /**
  118. * Fetch the default value for the attribute.
  119. * If there is no default value (such as for
  120. * composite attributes), null will be returned.
  121. */
  122. public String getDefaultValue() {
  123. return defaultValue;
  124. }
  125. /**
  126. * Indicates if the attribute should be inherited
  127. * from the parent or not.
  128. */
  129. public boolean isInherited() {
  130. return inherited;
  131. }
  132. private String name;
  133. private String defaultValue;
  134. private boolean inherited;
  135. public static final Attribute BACKGROUND =
  136. new Attribute("background", null, false);
  137. public static final Attribute BACKGROUND_ATTACHMENT =
  138. new Attribute("background-attachment", "scroll", false);
  139. public static final Attribute BACKGROUND_COLOR =
  140. new Attribute("background-color", "transparent", false);
  141. public static final Attribute BACKGROUND_IMAGE =
  142. new Attribute("background-image", "none", false);
  143. public static final Attribute BACKGROUND_POSITION =
  144. new Attribute("background-position", null, false);
  145. public static final Attribute BACKGROUND_REPEAT =
  146. new Attribute("background-repeat", "repeat", false);
  147. public static final Attribute BORDER =
  148. new Attribute("border", null, false);
  149. public static final Attribute BORDER_BOTTOM =
  150. new Attribute("border-bottom", null, false);
  151. public static final Attribute BORDER_BOTTOM_WIDTH =
  152. new Attribute("border-bottom-width", "medium", false);
  153. public static final Attribute BORDER_COLOR =
  154. new Attribute("border-color", null, false);
  155. public static final Attribute BORDER_LEFT =
  156. new Attribute("border-left", null, false);
  157. public static final Attribute BORDER_LEFT_WIDTH =
  158. new Attribute("border-left-width", "medium", false);
  159. public static final Attribute BORDER_RIGHT =
  160. new Attribute("border-right", null, false);
  161. public static final Attribute BORDER_RIGHT_WIDTH =
  162. new Attribute("border-right-width", "medium", false);
  163. public static final Attribute BORDER_STYLE =
  164. new Attribute("border-style", "none", false);
  165. public static final Attribute BORDER_TOP =
  166. new Attribute("border-top", null, false);
  167. public static final Attribute BORDER_TOP_WIDTH =
  168. new Attribute("border-top-width", "medium", false);
  169. public static final Attribute BORDER_WIDTH =
  170. new Attribute("border-width", "medium", false);
  171. public static final Attribute CLEAR =
  172. new Attribute("clear", "none", false);
  173. public static final Attribute COLOR =
  174. new Attribute("color", null, true);
  175. public static final Attribute DISPLAY =
  176. new Attribute("display", "block", false);
  177. public static final Attribute FLOAT =
  178. new Attribute("float", "none", false);
  179. public static final Attribute FONT =
  180. new Attribute("font", null, true);
  181. public static final Attribute FONT_FAMILY =
  182. new Attribute("font-family", null, true);
  183. public static final Attribute FONT_SIZE =
  184. new Attribute("font-size", "medium", true);
  185. public static final Attribute FONT_STYLE =
  186. new Attribute("font-style", "normal", true);
  187. public static final Attribute FONT_VARIANT =
  188. new Attribute("font-variant", "normal", true);
  189. public static final Attribute FONT_WEIGHT =
  190. new Attribute("font-weight", "normal", true);
  191. public static final Attribute HEIGHT =
  192. new Attribute("height", "auto", false);
  193. public static final Attribute LETTER_SPACING =
  194. new Attribute("letter-spacing", "normal", true);
  195. public static final Attribute LINE_HEIGHT =
  196. new Attribute("line-height", "normal", true);
  197. public static final Attribute LIST_STYLE =
  198. new Attribute("list-style", null, true);
  199. public static final Attribute LIST_STYLE_IMAGE =
  200. new Attribute("list-style-image", "none", true);
  201. public static final Attribute LIST_STYLE_POSITION =
  202. new Attribute("list-style-position", "outside", true);
  203. public static final Attribute LIST_STYLE_TYPE =
  204. new Attribute("list-style-type", "disc", true);
  205. public static final Attribute MARGIN =
  206. new Attribute("margin", null, false);
  207. public static final Attribute MARGIN_BOTTOM =
  208. new Attribute("margin-bottom", "0", false);
  209. public static final Attribute MARGIN_LEFT =
  210. new Attribute("margin-left", "0", false);
  211. public static final Attribute MARGIN_RIGHT =
  212. new Attribute("margin-right", "0", false);
  213. public static final Attribute MARGIN_TOP =
  214. new Attribute("margin-top", "0", false);
  215. public static final Attribute PADDING =
  216. new Attribute("padding", null, false);
  217. public static final Attribute PADDING_BOTTOM =
  218. new Attribute("padding-bottom", "0", false);
  219. public static final Attribute PADDING_LEFT =
  220. new Attribute("padding-left", "0", false);
  221. public static final Attribute PADDING_RIGHT =
  222. new Attribute("padding-right", "0", false);
  223. public static final Attribute PADDING_TOP =
  224. new Attribute("padding-top", "0", false);
  225. public static final Attribute TEXT_ALIGN =
  226. new Attribute("text-align", null, true);
  227. public static final Attribute TEXT_DECORATION =
  228. new Attribute("text-decoration", "none", true);
  229. public static final Attribute TEXT_INDENT =
  230. new Attribute("text-indent", "0", true);
  231. public static final Attribute TEXT_TRANSFORM =
  232. new Attribute("text-transform", "none", true);
  233. public static final Attribute VERTICAL_ALIGN =
  234. new Attribute("vertical-align", "baseline", false);
  235. public static final Attribute WORD_SPACING =
  236. new Attribute("word-spacing", "normal", true);
  237. public static final Attribute WHITE_SPACE =
  238. new Attribute("white-space", "normal", true);
  239. public static final Attribute WIDTH =
  240. new Attribute("width", "auto", false);
  241. /*public*/ static final Attribute BORDER_SPACING =
  242. new Attribute("border-spacing", "0", true);
  243. /*public*/ static final Attribute CAPTION_SIDE =
  244. new Attribute("caption-side", "left", true);
  245. // All possible CSS attribute keys.
  246. static final Attribute[] allAttributes = {
  247. BACKGROUND, BACKGROUND_ATTACHMENT, BACKGROUND_COLOR,
  248. BACKGROUND_IMAGE, BACKGROUND_POSITION, BACKGROUND_REPEAT,
  249. BORDER, BORDER_BOTTOM, BORDER_BOTTOM_WIDTH, BORDER_COLOR,
  250. BORDER_LEFT, BORDER_LEFT_WIDTH, BORDER_RIGHT, BORDER_RIGHT_WIDTH,
  251. BORDER_STYLE, BORDER_TOP, BORDER_TOP_WIDTH, BORDER_WIDTH,
  252. CLEAR, COLOR, DISPLAY, FLOAT, FONT, FONT_FAMILY, FONT_SIZE,
  253. FONT_STYLE, FONT_VARIANT, FONT_WEIGHT, HEIGHT, LETTER_SPACING,
  254. LINE_HEIGHT, LIST_STYLE, LIST_STYLE_IMAGE, LIST_STYLE_POSITION,
  255. LIST_STYLE_TYPE, MARGIN, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT,
  256. MARGIN_TOP, PADDING, PADDING_BOTTOM, PADDING_LEFT, PADDING_RIGHT,
  257. PADDING_TOP, TEXT_ALIGN, TEXT_DECORATION, TEXT_INDENT, TEXT_TRANSFORM,
  258. VERTICAL_ALIGN, WORD_SPACING, WHITE_SPACE, WIDTH,
  259. BORDER_SPACING, CAPTION_SIDE
  260. };
  261. private static final Attribute[] ALL_MARGINS =
  262. { MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM, MARGIN_LEFT };
  263. private static final Attribute[] ALL_PADDING =
  264. { PADDING_TOP, PADDING_RIGHT, PADDING_BOTTOM, PADDING_LEFT };
  265. private static final Attribute[] ALL_BORDER_WIDTHS =
  266. { BORDER_TOP_WIDTH, BORDER_RIGHT_WIDTH, BORDER_BOTTOM_WIDTH,
  267. BORDER_LEFT_WIDTH };
  268. }
  269. static final class Value {
  270. private Value(String name) {
  271. this.name = name;
  272. }
  273. /**
  274. * The string representation of the attribute. This
  275. * should exactly match the string specified in the
  276. * CSS specification.
  277. */
  278. public String toString() {
  279. return name;
  280. }
  281. static final Value INHERITED = new Value("inherited");
  282. static final Value NONE = new Value("none");
  283. static final Value DOTTED = new Value("dotted");
  284. static final Value DASHED = new Value("dashed");
  285. static final Value SOLID = new Value("solid");
  286. static final Value DOUBLE = new Value("double");
  287. static final Value GROOVE = new Value("groove");
  288. static final Value RIDGE = new Value("ridge");
  289. static final Value INSET = new Value("inset");
  290. static final Value OUTSET = new Value("outset");
  291. // Lists.
  292. static final Value BLANK_LIST_ITEM = new Value("none");
  293. static final Value DISC = new Value("disc");
  294. static final Value CIRCLE = new Value("circle");
  295. static final Value SQUARE = new Value("square");
  296. static final Value DECIMAL = new Value("decimal");
  297. static final Value LOWER_ROMAN = new Value("lower-roman");
  298. static final Value UPPER_ROMAN = new Value("upper-roman");
  299. static final Value LOWER_ALPHA = new Value("lower-alpha");
  300. static final Value UPPER_ALPHA = new Value("upper-alpha");
  301. // background-repeat
  302. static final Value BACKGROUND_NO_REPEAT = new Value("no-repeat");
  303. static final Value BACKGROUND_REPEAT = new Value("repeat");
  304. static final Value BACKGROUND_REPEAT_X = new Value("repeat-x");
  305. static final Value BACKGROUND_REPEAT_Y = new Value("repeat-y");
  306. // background-attachment
  307. static final Value BACKGROUND_SCROLL = new Value("scroll");
  308. static final Value BACKGROUND_FIXED = new Value("fixed");
  309. private String name;
  310. static final Value[] allValues = {
  311. INHERITED, NONE, DOTTED, DASHED, SOLID, DOUBLE, GROOVE,
  312. RIDGE, INSET, OUTSET, DISC, CIRCLE, SQUARE, DECIMAL,
  313. LOWER_ROMAN, UPPER_ROMAN, LOWER_ALPHA, UPPER_ALPHA,
  314. BLANK_LIST_ITEM, BACKGROUND_NO_REPEAT, BACKGROUND_REPEAT,
  315. BACKGROUND_REPEAT_X, BACKGROUND_REPEAT_Y,
  316. BACKGROUND_FIXED, BACKGROUND_FIXED
  317. };
  318. }
  319. public CSS() {
  320. baseFontSize = 3;
  321. // setup the css conversion table
  322. valueConvertor = new Hashtable();
  323. valueConvertor.put(CSS.Attribute.FONT_SIZE, new FontSize());
  324. valueConvertor.put(CSS.Attribute.FONT_FAMILY, new FontFamily());
  325. valueConvertor.put(CSS.Attribute.FONT_WEIGHT, new FontWeight());
  326. valueConvertor.put(CSS.Attribute.BORDER_STYLE, new BorderStyle());
  327. Object cv = new ColorValue();
  328. valueConvertor.put(CSS.Attribute.COLOR, cv);
  329. valueConvertor.put(CSS.Attribute.BACKGROUND_COLOR, cv);
  330. valueConvertor.put(CSS.Attribute.BORDER_COLOR, cv);
  331. Object lv = new LengthValue();
  332. valueConvertor.put(CSS.Attribute.MARGIN_TOP, lv);
  333. valueConvertor.put(CSS.Attribute.MARGIN_BOTTOM, lv);
  334. valueConvertor.put(CSS.Attribute.MARGIN_LEFT, lv);
  335. valueConvertor.put(CSS.Attribute.MARGIN_RIGHT, lv);
  336. valueConvertor.put(CSS.Attribute.PADDING_TOP, lv);
  337. valueConvertor.put(CSS.Attribute.PADDING_BOTTOM, lv);
  338. valueConvertor.put(CSS.Attribute.PADDING_LEFT, lv);
  339. valueConvertor.put(CSS.Attribute.PADDING_RIGHT, lv);
  340. Object bv = new BorderWidthValue(null, 0);
  341. valueConvertor.put(CSS.Attribute.BORDER_WIDTH, lv);
  342. valueConvertor.put(CSS.Attribute.BORDER_TOP_WIDTH, bv);
  343. valueConvertor.put(CSS.Attribute.BORDER_BOTTOM_WIDTH, bv);
  344. valueConvertor.put(CSS.Attribute.BORDER_LEFT_WIDTH, bv);
  345. valueConvertor.put(CSS.Attribute.BORDER_RIGHT_WIDTH, bv);
  346. valueConvertor.put(CSS.Attribute.TEXT_INDENT, lv);
  347. valueConvertor.put(CSS.Attribute.WIDTH, lv);
  348. valueConvertor.put(CSS.Attribute.HEIGHT, lv);
  349. valueConvertor.put(CSS.Attribute.BORDER_SPACING, lv);
  350. Object sv = new StringValue();
  351. valueConvertor.put(CSS.Attribute.FONT_STYLE, sv);
  352. valueConvertor.put(CSS.Attribute.TEXT_DECORATION, sv);
  353. valueConvertor.put(CSS.Attribute.TEXT_ALIGN, sv);
  354. valueConvertor.put(CSS.Attribute.VERTICAL_ALIGN, sv);
  355. Object valueMapper = new CssValueMapper();
  356. valueConvertor.put(CSS.Attribute.LIST_STYLE_TYPE,
  357. valueMapper);
  358. valueConvertor.put(CSS.Attribute.BACKGROUND_IMAGE,
  359. new BackgroundImage());
  360. valueConvertor.put(CSS.Attribute.BACKGROUND_POSITION,
  361. new BackgroundPosition());
  362. valueConvertor.put(CSS.Attribute.BACKGROUND_REPEAT,
  363. valueMapper);
  364. valueConvertor.put(CSS.Attribute.BACKGROUND_ATTACHMENT,
  365. valueMapper);
  366. Object generic = new CssValue();
  367. int n = CSS.Attribute.allAttributes.length;
  368. for (int i = 0; i < n; i++) {
  369. CSS.Attribute key = CSS.Attribute.allAttributes[i];
  370. if (valueConvertor.get(key) == null) {
  371. valueConvertor.put(key, generic);
  372. }
  373. }
  374. }
  375. /**
  376. * Sets the base font size. <code>sz</code> is a CSS value, and is
  377. * not necessarily the point size. Use getPointSize to determine the
  378. * point size corresponding to <code>sz</code>.
  379. */
  380. void setBaseFontSize(int sz) {
  381. if (sz < 1)
  382. baseFontSize = 0;
  383. else if (sz > 7)
  384. baseFontSize = 7;
  385. else
  386. baseFontSize = sz;
  387. }
  388. /**
  389. * Sets the base font size from the passed in string.
  390. */
  391. void setBaseFontSize(String size) {
  392. int relSize, absSize, diff;
  393. if (size != null) {
  394. if (size.startsWith("+")) {
  395. relSize = Integer.valueOf(size.substring(1)).intValue();
  396. setBaseFontSize(baseFontSize + relSize);
  397. } else if (size.startsWith("-")) {
  398. relSize = -Integer.valueOf(size.substring(1)).intValue();
  399. setBaseFontSize(baseFontSize + relSize);
  400. } else {
  401. setBaseFontSize(Integer.valueOf(size).intValue());
  402. }
  403. }
  404. }
  405. /**
  406. * Returns the base font size.
  407. */
  408. int getBaseFontSize() {
  409. return baseFontSize;
  410. }
  411. /**
  412. * Parses the CSS property <code>key</code> with value
  413. * <code>value</code> placing the result in <code>att</code>.
  414. */
  415. void addInternalCSSValue(MutableAttributeSet attr,
  416. CSS.Attribute key, String value) {
  417. if (key == CSS.Attribute.FONT) {
  418. ShorthandFontParser.parseShorthandFont(this, value, attr);
  419. }
  420. else if (key == CSS.Attribute.BACKGROUND) {
  421. ShorthandBackgroundParser.parseShorthandBackground
  422. (this, value, attr);
  423. }
  424. else if (key == CSS.Attribute.MARGIN) {
  425. ShorthandMarginParser.parseShorthandMargin(this, value, attr,
  426. CSS.Attribute.ALL_MARGINS);
  427. }
  428. else if (key == CSS.Attribute.PADDING) {
  429. ShorthandMarginParser.parseShorthandMargin(this, value, attr,
  430. CSS.Attribute.ALL_PADDING);
  431. }
  432. else if (key == CSS.Attribute.BORDER_WIDTH) {
  433. ShorthandMarginParser.parseShorthandMargin(this, value, attr,
  434. CSS.Attribute.ALL_BORDER_WIDTHS);
  435. }
  436. else {
  437. Object iValue = getInternalCSSValue(key, value);
  438. if (iValue != null) {
  439. attr.addAttribute(key, iValue);
  440. }
  441. }
  442. }
  443. /**
  444. * Gets the internal CSS representation of <code>value</code> which is
  445. * a CSS value of the CSS attribute named <code>key</code>. The receiver
  446. * should not modify <code>value</code>, and the first <code>count</code>
  447. * strings are valid.
  448. */
  449. Object getInternalCSSValue(CSS.Attribute key, String value) {
  450. CssValue conv = (CssValue) valueConvertor.get(key);
  451. return conv.parseCssValue(value);
  452. }
  453. /**
  454. * Maps from a StyleConstants to a CSS Attribute.
  455. */
  456. Attribute styleConstantsKeyToCSSKey(StyleConstants sc) {
  457. return (Attribute)styleConstantToCssMap.get(sc);
  458. }
  459. /**
  460. * Maps from a StyleConstants value to a CSS value.
  461. */
  462. Object styleConstantsValueToCSSValue(StyleConstants sc,
  463. Object styleValue) {
  464. Object cssKey = styleConstantsKeyToCSSKey(sc);
  465. if (cssKey != null) {
  466. CssValue conv = (CssValue)valueConvertor.get(cssKey);
  467. return conv.fromStyleConstants(sc, styleValue);
  468. }
  469. return null;
  470. }
  471. /**
  472. * Converts the passed in CSS value to a StyleConstants value.
  473. * <code>key</code> identifies the CSS attribute being mapped.
  474. */
  475. Object cssValueToStyleConstantsValue(StyleConstants key, Object value) {
  476. if (value instanceof CssValue) {
  477. return ((CssValue)value).toStyleConstants((StyleConstants)key,
  478. null);
  479. }
  480. return null;
  481. }
  482. /**
  483. * Returns the font for the values in the passed in AttributeSet.
  484. * It is assumed the keys will be CSS.Attribute keys.
  485. * <code>sc</code> is the StyleContext that will be messaged to get
  486. * the font once the size, name and style have been determined.
  487. */
  488. Font getFont(StyleContext sc, AttributeSet a, int defaultSize) {
  489. int size = getFontSize(a, defaultSize);
  490. /*
  491. * If the vertical alignment is set to either superscirpt or
  492. * subscript we reduce the font size by 2 points.
  493. */
  494. StringValue vAlignV = (StringValue)a.getAttribute
  495. (CSS.Attribute.VERTICAL_ALIGN);
  496. if ((vAlignV != null)) {
  497. String vAlign = vAlignV.toString();
  498. if ((vAlign.indexOf("sup") >= 0) ||
  499. (vAlign.indexOf("sub") >= 0)) {
  500. size -= 2;
  501. }
  502. }
  503. FontFamily familyValue = (FontFamily)a.getAttribute
  504. (CSS.Attribute.FONT_FAMILY);
  505. String family = (familyValue != null) ? familyValue.getValue() :
  506. "SansSerif";
  507. int style = Font.PLAIN;
  508. FontWeight weightValue = (FontWeight) a.getAttribute
  509. (CSS.Attribute.FONT_WEIGHT);
  510. if ((weightValue != null) && (weightValue.getValue() > 400)) {
  511. style |= Font.BOLD;
  512. }
  513. Object fs = a.getAttribute(CSS.Attribute.FONT_STYLE);
  514. if ((fs != null) && (fs.toString().indexOf("italic") >= 0)) {
  515. style |= Font.ITALIC;
  516. }
  517. Font f = sc.getFont(family, style, size);
  518. return f;
  519. }
  520. static int getFontSize(AttributeSet attr, int defaultSize) {
  521. // PENDING(prinz) this is a 1.1 based implementation, need to also
  522. // have a 1.2 version.
  523. FontSize sizeValue = (FontSize)attr.getAttribute(CSS.Attribute.
  524. FONT_SIZE);
  525. return (sizeValue != null) ? (int)sizeValue.getValue(attr) :
  526. defaultSize;
  527. }
  528. /**
  529. * Takes a set of attributes and turn it into a color
  530. * specification. This might be used to specify things
  531. * like brighter, more hue, etc.
  532. * This will return null if there is no value for <code>key</code>.
  533. *
  534. * @param key CSS.Attribute identifying where color is stored.
  535. * @param a the set of attributes
  536. * @return the color
  537. */
  538. Color getColor(AttributeSet a, CSS.Attribute key) {
  539. ColorValue cv = (ColorValue) a.getAttribute(key);
  540. if (cv != null) {
  541. return cv.getValue();
  542. }
  543. return null;
  544. }
  545. /**
  546. * Returns the size of a font from the passed in string.
  547. *
  548. * @param size CSS string describing font size
  549. * @param baseFontSize size to use for relative units.
  550. */
  551. float getPointSize(String size) {
  552. int relSize, absSize, diff, index;
  553. if (size != null) {
  554. if (size.startsWith("+")) {
  555. relSize = Integer.valueOf(size.substring(1)).intValue();
  556. return getPointSize(baseFontSize + relSize);
  557. } else if (size.startsWith("-")) {
  558. relSize = -Integer.valueOf(size.substring(1)).intValue();
  559. return getPointSize(baseFontSize + relSize);
  560. } else {
  561. absSize = Integer.valueOf(size).intValue();
  562. return getPointSize(absSize);
  563. }
  564. }
  565. return 0;
  566. }
  567. /**
  568. * Returns the length of the attribute in <code>a</code> with
  569. * key <code>key</code>.
  570. */
  571. float getLength(AttributeSet a, CSS.Attribute key) {
  572. LengthValue lv = (LengthValue) a.getAttribute(key);
  573. float len = (lv != null) ? lv.getValue() : 0;
  574. return len;
  575. }
  576. /**
  577. * Convert a set of HTML attributes to an equivalent
  578. * set of CSS attributes.
  579. *
  580. * @param AttributeSet containing the HTML attributes.
  581. * @return AttributeSet containing the corresponding CSS attributes.
  582. * The AttributeSet will be empty if there are no mapping
  583. * CSS attributes.
  584. */
  585. AttributeSet translateHTMLToCSS(AttributeSet htmlAttrSet) {
  586. MutableAttributeSet cssAttrSet = new SimpleAttributeSet();
  587. Element elem = (Element)htmlAttrSet;
  588. HTML.Tag tag = getHTMLTag(htmlAttrSet);
  589. if ((tag == HTML.Tag.TD) || (tag == HTML.Tag.TH)) {
  590. // translate border width into the cells
  591. AttributeSet tableAttr = elem.getParentElement().
  592. getParentElement().getAttributes();
  593. translateAttribute(HTML.Attribute.BORDER, tableAttr, cssAttrSet);
  594. String pad = (String)tableAttr.getAttribute(HTML.Attribute.CELLPADDING);
  595. if (pad != null) {
  596. Object v = getInternalCSSValue(CSS.Attribute.PADDING_TOP, pad);
  597. cssAttrSet.addAttribute(CSS.Attribute.PADDING_TOP, v);
  598. cssAttrSet.addAttribute(CSS.Attribute.PADDING_BOTTOM, v);
  599. cssAttrSet.addAttribute(CSS.Attribute.PADDING_LEFT, v);
  600. cssAttrSet.addAttribute(CSS.Attribute.PADDING_RIGHT, v);
  601. }
  602. }
  603. if (elem.isLeaf()) {
  604. translateEmbeddedAttributes(htmlAttrSet, cssAttrSet);
  605. } else {
  606. translateAttributes(tag, htmlAttrSet, cssAttrSet);
  607. }
  608. if (tag == HTML.Tag.CAPTION) {
  609. /*
  610. * Navigator uses ALIGN for caption placement and IE uses VALIGN.
  611. */
  612. Object v = htmlAttrSet.getAttribute(HTML.Attribute.ALIGN);
  613. if ((v != null) && (v.equals("top") || v.equals("bottom"))) {
  614. cssAttrSet.addAttribute(CSS.Attribute.CAPTION_SIDE, v);
  615. cssAttrSet.removeAttribute(CSS.Attribute.TEXT_ALIGN);
  616. } else {
  617. v = htmlAttrSet.getAttribute(HTML.Attribute.VALIGN);
  618. if (v != null) {
  619. cssAttrSet.addAttribute(CSS.Attribute.CAPTION_SIDE, v);
  620. }
  621. }
  622. }
  623. return cssAttrSet;
  624. }
  625. private static final Hashtable attributeMap = new Hashtable();
  626. private static final Hashtable valueMap = new Hashtable();
  627. /**
  628. * The HTML/CSS size model has seven slots
  629. * that one can assign sizes to.
  630. */
  631. static int sizeMap[] = { 8, 10, 12, 14, 18, 24, 36 };
  632. /**
  633. * The hashtable and the static initalization block below,
  634. * set up a mapping from well-known HTML attributes to
  635. * CSS attributes. For the most part, there is a 1-1 mapping
  636. * between the two. However in the case of certain HTML
  637. * attributes for example HTML.Attribute.VSPACE or
  638. * HTML.Attribute.HSPACE, end up mapping to two CSS.Attribute's.
  639. * Therefore, the value associated with each HTML.Attribute.
  640. * key ends up being an array of CSS.Attribute.* objects.
  641. */
  642. private static final Hashtable htmlAttrToCssAttrMap = new Hashtable(20);
  643. /**
  644. * The hashtable and static initialization that follows sets
  645. * up a translation from StyleConstants (i.e. the <em>well known</em>
  646. * attributes) to the associated CSS attributes.
  647. */
  648. private static final Hashtable styleConstantToCssMap = new Hashtable(17);
  649. /** Maps from HTML value to a CSS value. Used in internal mapping. */
  650. private static final Hashtable htmlValueToCssValueMap = new Hashtable(8);
  651. /** Maps from CSS value (string) to internal value. */
  652. private static final Hashtable cssValueToInternalValueMap = new Hashtable(13);
  653. /** Used to indicate if a font family name is valid. */
  654. private static Hashtable fontMapping;
  655. private static final Object fontMappingLock = new Object();
  656. static {
  657. // load the attribute map
  658. for (int i = 0; i < Attribute.allAttributes.length; i++ ) {
  659. attributeMap.put(Attribute.allAttributes[i].toString(),
  660. Attribute.allAttributes[i]);
  661. }
  662. // load the value map
  663. for (int i = 0; i < Value.allValues.length; i++ ) {
  664. valueMap.put(Value.allValues[i].toString(),
  665. Value.allValues[i]);
  666. }
  667. htmlAttrToCssAttrMap.put(HTML.Attribute.COLOR,
  668. new CSS.Attribute[]{CSS.Attribute.COLOR});
  669. htmlAttrToCssAttrMap.put(HTML.Attribute.TEXT,
  670. new CSS.Attribute[]{CSS.Attribute.COLOR});
  671. htmlAttrToCssAttrMap.put(HTML.Attribute.CLEAR,
  672. new CSS.Attribute[]{CSS.Attribute.CLEAR});
  673. htmlAttrToCssAttrMap.put(HTML.Attribute.BACKGROUND,
  674. new CSS.Attribute[]{CSS.Attribute.BACKGROUND_IMAGE});
  675. htmlAttrToCssAttrMap.put(HTML.Attribute.BGCOLOR,
  676. new CSS.Attribute[]{CSS.Attribute.BACKGROUND_COLOR});
  677. htmlAttrToCssAttrMap.put(HTML.Attribute.WIDTH,
  678. new CSS.Attribute[]{CSS.Attribute.WIDTH});
  679. htmlAttrToCssAttrMap.put(HTML.Attribute.HEIGHT,
  680. new CSS.Attribute[]{CSS.Attribute.HEIGHT});
  681. htmlAttrToCssAttrMap.put(HTML.Attribute.BORDER,
  682. new CSS.Attribute[]{CSS.Attribute.BORDER_TOP_WIDTH, CSS.Attribute.BORDER_RIGHT_WIDTH, CSS.Attribute.BORDER_BOTTOM_WIDTH, CSS.Attribute.BORDER_LEFT_WIDTH});
  683. htmlAttrToCssAttrMap.put(HTML.Attribute.CELLPADDING,
  684. new CSS.Attribute[]{CSS.Attribute.PADDING});
  685. htmlAttrToCssAttrMap.put(HTML.Attribute.CELLSPACING,
  686. new CSS.Attribute[]{CSS.Attribute.BORDER_SPACING});
  687. htmlAttrToCssAttrMap.put(HTML.Attribute.MARGINWIDTH,
  688. new CSS.Attribute[]{CSS.Attribute.MARGIN_LEFT,
  689. CSS.Attribute.MARGIN_RIGHT});
  690. htmlAttrToCssAttrMap.put(HTML.Attribute.MARGINHEIGHT,
  691. new CSS.Attribute[]{CSS.Attribute.MARGIN_TOP,
  692. CSS.Attribute.MARGIN_BOTTOM});
  693. htmlAttrToCssAttrMap.put(HTML.Attribute.HSPACE,
  694. new CSS.Attribute[]{CSS.Attribute.PADDING_LEFT,
  695. CSS.Attribute.PADDING_RIGHT});
  696. htmlAttrToCssAttrMap.put(HTML.Attribute.VSPACE,
  697. new CSS.Attribute[]{CSS.Attribute.PADDING_BOTTOM,
  698. CSS.Attribute.PADDING_TOP});
  699. htmlAttrToCssAttrMap.put(HTML.Attribute.FACE,
  700. new CSS.Attribute[]{CSS.Attribute.FONT_FAMILY});
  701. htmlAttrToCssAttrMap.put(HTML.Attribute.SIZE,
  702. new CSS.Attribute[]{CSS.Attribute.FONT_SIZE});
  703. htmlAttrToCssAttrMap.put(HTML.Attribute.VALIGN,
  704. new CSS.Attribute[]{CSS.Attribute.VERTICAL_ALIGN});
  705. htmlAttrToCssAttrMap.put(HTML.Attribute.ALIGN,
  706. new CSS.Attribute[]{CSS.Attribute.VERTICAL_ALIGN,
  707. CSS.Attribute.TEXT_ALIGN,
  708. CSS.Attribute.FLOAT});
  709. htmlAttrToCssAttrMap.put(HTML.Attribute.TYPE,
  710. new CSS.Attribute[]{CSS.Attribute.LIST_STYLE_TYPE});
  711. htmlAttrToCssAttrMap.put(HTML.Attribute.NOWRAP,
  712. new CSS.Attribute[]{CSS.Attribute.WHITE_SPACE});
  713. // initialize StyleConstants mapping
  714. styleConstantToCssMap.put(StyleConstants.FontFamily,
  715. CSS.Attribute.FONT_FAMILY);
  716. styleConstantToCssMap.put(StyleConstants.FontSize,
  717. CSS.Attribute.FONT_SIZE);
  718. styleConstantToCssMap.put(StyleConstants.Bold,
  719. CSS.Attribute.FONT_WEIGHT);
  720. styleConstantToCssMap.put(StyleConstants.Italic,
  721. CSS.Attribute.FONT_STYLE);
  722. styleConstantToCssMap.put(StyleConstants.Underline,
  723. CSS.Attribute.TEXT_DECORATION);
  724. styleConstantToCssMap.put(StyleConstants.StrikeThrough,
  725. CSS.Attribute.TEXT_DECORATION);
  726. styleConstantToCssMap.put(StyleConstants.Superscript,
  727. CSS.Attribute.VERTICAL_ALIGN);
  728. styleConstantToCssMap.put(StyleConstants.Subscript,
  729. CSS.Attribute.VERTICAL_ALIGN);
  730. styleConstantToCssMap.put(StyleConstants.Foreground,
  731. CSS.Attribute.COLOR);
  732. styleConstantToCssMap.put(StyleConstants.Background,
  733. CSS.Attribute.BACKGROUND_COLOR);
  734. styleConstantToCssMap.put(StyleConstants.FirstLineIndent,
  735. CSS.Attribute.TEXT_INDENT);
  736. styleConstantToCssMap.put(StyleConstants.LeftIndent,
  737. CSS.Attribute.MARGIN_LEFT);
  738. styleConstantToCssMap.put(StyleConstants.RightIndent,
  739. CSS.Attribute.MARGIN_RIGHT);
  740. styleConstantToCssMap.put(StyleConstants.SpaceAbove,
  741. CSS.Attribute.MARGIN_TOP);
  742. styleConstantToCssMap.put(StyleConstants.SpaceBelow,
  743. CSS.Attribute.MARGIN_BOTTOM);
  744. styleConstantToCssMap.put(StyleConstants.Alignment,
  745. CSS.Attribute.TEXT_ALIGN);
  746. // HTML->CSS
  747. htmlValueToCssValueMap.put("disc", CSS.Value.DISC);
  748. htmlValueToCssValueMap.put("square", CSS.Value.SQUARE);
  749. htmlValueToCssValueMap.put("circle", CSS.Value.CIRCLE);
  750. htmlValueToCssValueMap.put("1", CSS.Value.DECIMAL);
  751. htmlValueToCssValueMap.put("a", CSS.Value.LOWER_ALPHA);
  752. htmlValueToCssValueMap.put("A", CSS.Value.UPPER_ALPHA);
  753. htmlValueToCssValueMap.put("i", CSS.Value.LOWER_ROMAN);
  754. htmlValueToCssValueMap.put("I", CSS.Value.UPPER_ROMAN);
  755. // CSS-> internal CSS
  756. cssValueToInternalValueMap.put("disc", CSS.Value.DISC);
  757. cssValueToInternalValueMap.put("square", CSS.Value.SQUARE);
  758. cssValueToInternalValueMap.put("circle", CSS.Value.CIRCLE);
  759. cssValueToInternalValueMap.put("decimal", CSS.Value.DECIMAL);
  760. cssValueToInternalValueMap.put("lower-roman", CSS.Value.LOWER_ROMAN);
  761. cssValueToInternalValueMap.put("upper-roman", CSS.Value.UPPER_ROMAN);
  762. cssValueToInternalValueMap.put("lower-alpha", CSS.Value.LOWER_ALPHA);
  763. cssValueToInternalValueMap.put("upper-alpha", CSS.Value.UPPER_ALPHA);
  764. cssValueToInternalValueMap.put("repeat", CSS.Value.BACKGROUND_REPEAT);
  765. cssValueToInternalValueMap.put("no-repeat",
  766. CSS.Value.BACKGROUND_NO_REPEAT);
  767. cssValueToInternalValueMap.put("repeat-x",
  768. CSS.Value.BACKGROUND_REPEAT_X);
  769. cssValueToInternalValueMap.put("repeat-y",
  770. CSS.Value.BACKGROUND_REPEAT_Y);
  771. cssValueToInternalValueMap.put("scroll",
  772. CSS.Value.BACKGROUND_SCROLL);
  773. cssValueToInternalValueMap.put("fixed",
  774. CSS.Value.BACKGROUND_FIXED);
  775. // Register all the CSS attribute keys for archival/unarchival
  776. Object[] keys = CSS.Attribute.allAttributes;
  777. try {
  778. for (int i = 0; i < keys.length; i++) {
  779. StyleContext.registerStaticAttributeKey(keys[i]);
  780. }
  781. } catch (Throwable e) {
  782. e.printStackTrace();
  783. }
  784. // Register all the CSS Values for archival/unarchival
  785. keys = CSS.Value.allValues;
  786. try {
  787. for (int i = 0; i < keys.length; i++) {
  788. StyleContext.registerStaticAttributeKey(keys[i]);
  789. }
  790. } catch (Throwable e) {
  791. e.printStackTrace();
  792. }
  793. }
  794. /**
  795. * Returns a hashtable whose contents are used to indicate the valid
  796. * fonts.
  797. */
  798. static Hashtable getValidFontNameMapping() {
  799. if (fontMapping == null) {
  800. // This can get called from multiple threads, lock before setting
  801. synchronized(fontMappingLock) {
  802. if (fontMapping == null) {
  803. String[] names = null;
  804. // Use the 1.2 GraphicsEnvironment for getting font names,
  805. // if we can.
  806. try {
  807. Class ge = Class.forName("java.awt.GraphicsEnvironment");
  808. if (ge != null) {
  809. Method method = ge.getDeclaredMethod
  810. ("getLocalGraphicsEnvironment", null);
  811. if (method != null) {
  812. Object instance = method.invoke(ge, null);
  813. if (instance != null) {
  814. method = ge.getMethod
  815. ("getAvailableFontFamilyNames", null);
  816. if (method != null) {
  817. names = (String[])method.invoke
  818. (instance, null);
  819. }
  820. }
  821. }
  822. }
  823. }
  824. catch (Throwable th) { }
  825. if (names == null) {
  826. // We can't, use the Toolkit method.
  827. names = Toolkit.getDefaultToolkit().getFontList();
  828. }
  829. if (names != null) {
  830. fontMapping = new Hashtable(names.length * 2);
  831. for (int counter = names.length - 1; counter >= 0;
  832. counter--) {
  833. // Put both lowercase and case value in table.
  834. fontMapping.put(names[counter].toLowerCase(),
  835. names[counter]);
  836. fontMapping.put(names[counter], names[counter]);
  837. }
  838. }
  839. else {
  840. fontMapping = new Hashtable(1);
  841. }
  842. }
  843. }
  844. }
  845. return fontMapping;
  846. }
  847. /**
  848. * Return the set of all possible CSS attribute keys.
  849. */
  850. public static Attribute[] getAllAttributeKeys() {
  851. Attribute[] keys = new Attribute[Attribute.allAttributes.length];
  852. System.arraycopy(Attribute.allAttributes, 0, keys, 0, Attribute.allAttributes.length);
  853. return keys;
  854. }
  855. /**
  856. * Translate a string to a CSS.Attribute object. This
  857. * will return null if there is no attribute by the given
  858. * name.
  859. * @param name the name of the CSS attribute to fetch the
  860. * typesafe enumeration for.
  861. * @returns the CSS.Attribute object, or null if the string
  862. * doesn't represent a valid attribute key.
  863. */
  864. public static final Attribute getAttribute(String name) {
  865. return (Attribute) attributeMap.get(name);
  866. }
  867. /**
  868. * Translate a string to a CSS.Value object. This
  869. * will return null if there is no value by the given
  870. * name.
  871. * @param name the name of the CSS value to fetch the
  872. * typesafe enumeration for.
  873. * @returns the CSS.Value object, or null if the string
  874. * doesn't represent a valid CSS value name. This does
  875. * not mean it doesn't represent a valid CSS value.
  876. */
  877. static final Value getValue(String name) {
  878. return (Value) valueMap.get(name);
  879. }
  880. //
  881. // Conversion related methods/classes
  882. //
  883. /**
  884. * Returns a URL for the given CSS url string. If relative,
  885. * <code>base</code> is used as the parent. If a valid URL can not
  886. * be found, this will not throw a MalformedURLException, instead
  887. * null will be returned.
  888. */
  889. static URL getURL(URL base, String cssString) {
  890. if (cssString == null) {
  891. return null;
  892. }
  893. if (cssString.startsWith("url(") &&
  894. cssString.endsWith(")")) {
  895. cssString = cssString.substring(4, cssString.length() - 1);
  896. }
  897. // Absolute first
  898. try {
  899. URL url = new URL(cssString);
  900. if (url != null) {
  901. return url;
  902. }
  903. } catch (MalformedURLException mue) {
  904. }
  905. // Then relative
  906. if (base != null) {
  907. // Relative URL, try from base
  908. try {
  909. URL url = new URL(base, cssString);
  910. return url;
  911. }
  912. catch (MalformedURLException muee) {
  913. }
  914. }
  915. return null;
  916. }
  917. /**
  918. * Converts a type Color to a hex string
  919. * in the format "#RRGGBB"
  920. */
  921. static String colorToHex(Color color) {
  922. String colorstr = new String("#");
  923. // Red
  924. String str = Integer.toHexString(color.getRed());
  925. if (str.length() > 2)
  926. str = str.substring(0, 2);
  927. else if (str.length() < 2)
  928. colorstr += "0" + str;
  929. else
  930. colorstr += str;
  931. // Green
  932. str = Integer.toHexString(color.getGreen());
  933. if (str.length() > 2)
  934. str = str.substring(0, 2);
  935. else if (str.length() < 2)
  936. colorstr += "0" + str;
  937. else
  938. colorstr += str;
  939. // Blue
  940. str = Integer.toHexString(color.getBlue());
  941. if (str.length() > 2)
  942. str = str.substring(0, 2);
  943. else if (str.length() < 2)
  944. colorstr += "0" + str;
  945. else
  946. colorstr += str;
  947. return colorstr;
  948. }
  949. /**
  950. * Convert a "#FFFFFF" hex string to a Color.
  951. * If the color specification is bad, an attempt
  952. * will be made to fix it up.
  953. */
  954. static final Color hexToColor(String value) {
  955. String digits;
  956. int n = value.length();
  957. if (value.startsWith("#")) {
  958. digits = value.substring(1, Math.min(value.length(), 7));
  959. } else {
  960. digits = value;
  961. }
  962. String hstr = "0x" + digits;
  963. Color c;
  964. try {
  965. c = Color.decode(hstr);
  966. } catch (NumberFormatException nfe) {
  967. c = null;
  968. }
  969. return c;
  970. }
  971. /**
  972. * Convert a color string such as "RED" or "#NNNNNN" to a Color.
  973. * Note: This will only convert the HTML3.2 color strings
  974. * or a string of length 7;
  975. * otherwise, it will return null.
  976. */
  977. static Color stringToColor(String str) {
  978. Color color = null;
  979. if (str.charAt(0) == '#')
  980. color = hexToColor(str);
  981. else if (str.equalsIgnoreCase("Black"))
  982. color = hexToColor("#000000");
  983. else if(str.equalsIgnoreCase("Silver"))
  984. color = hexToColor("#C0C0C0");
  985. else if(str.equalsIgnoreCase("Gray"))
  986. color = hexToColor("#808080");
  987. else if(str.equalsIgnoreCase("White"))
  988. color = hexToColor("#FFFFFF");
  989. else if(str.equalsIgnoreCase("Maroon"))
  990. color = hexToColor("#800000");
  991. else if(str.equalsIgnoreCase("Red"))
  992. color = hexToColor("#FF0000");
  993. else if(str.equalsIgnoreCase("Purple"))
  994. color = hexToColor("#800080");
  995. else if(str.equalsIgnoreCase("Fuchsia"))
  996. color = hexToColor("#FF00FF");
  997. else if(str.equalsIgnoreCase("Green"))
  998. color = hexToColor("#008000");
  999. else if(str.equalsIgnoreCase("Lime"))
  1000. color = hexToColor("#00FF00");
  1001. else if(str.equalsIgnoreCase("Olive"))
  1002. color = hexToColor("#808000");
  1003. else if(str.equalsIgnoreCase("Yellow"))
  1004. color = hexToColor("#FFFF00");
  1005. else if(str.equalsIgnoreCase("Navy"))
  1006. color = hexToColor("#000080");
  1007. else if(str.equalsIgnoreCase("Blue"))
  1008. color = hexToColor("#0000FF");
  1009. else if(str.equalsIgnoreCase("Teal"))
  1010. color = hexToColor("#008080");
  1011. else if(str.equalsIgnoreCase("Aqua"))
  1012. color = hexToColor("#00FFFF");
  1013. else
  1014. color = hexToColor(str); // sometimes get specified without leading #
  1015. return color;
  1016. }
  1017. static int getIndexOfSize(float pt) {
  1018. for (int i = 0; i < sizeMap.length; i ++ )
  1019. if (pt <= sizeMap[i])
  1020. return i;
  1021. return sizeMap.length - 1;
  1022. }
  1023. /**
  1024. * @return an array of all the strings in <code>value</code>
  1025. * that are separated by whitespace.
  1026. */
  1027. static String[] parseStrings(