1 7 package javax.swing.text.html; 8 9 import java.awt.Color ; 10 import java.awt.Font ; 11 import java.awt.GraphicsEnvironment ; 12 import java.awt.Toolkit ; 13 import java.awt.HeadlessException ; 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 java.util.Locale ; 22 import javax.swing.ImageIcon ; 23 import javax.swing.SizeRequirements ; 24 import javax.swing.text.*; 25 26 98 public class CSS implements Serializable { 99 100 106 public static final class Attribute { 107 108 private Attribute(String name, String defaultValue, boolean inherited) { 109 this.name = name; 110 this.defaultValue = defaultValue; 111 this.inherited = inherited; 112 } 113 114 119 public String toString() { 120 return name; 121 } 122 123 128 public String getDefaultValue() { 129 return defaultValue; 130 } 131 132 136 public boolean isInherited() { 137 return inherited; 138 } 139 140 private String name; 141 private String defaultValue; 142 private boolean inherited; 143 144 145 public static final Attribute BACKGROUND = 146 new Attribute("background", null, false); 147 148 public static final Attribute BACKGROUND_ATTACHMENT = 149 new Attribute("background-attachment", "scroll", false); 150 151 public static final Attribute BACKGROUND_COLOR = 152 new Attribute("background-color", "transparent", false); 153 154 public static final Attribute BACKGROUND_IMAGE = 155 new Attribute("background-image", "none", false); 156 157 public static final Attribute BACKGROUND_POSITION = 158 new Attribute("background-position", null, false); 159 160 public static final Attribute BACKGROUND_REPEAT = 161 new Attribute("background-repeat", "repeat", false); 162 163 public static final Attribute BORDER = 164 new Attribute("border", null, false); 165 166 public static final Attribute BORDER_BOTTOM = 167 new Attribute("border-bottom", null, false); 168 169 public static final Attribute BORDER_BOTTOM_WIDTH = 170 new Attribute("border-bottom-width", "medium", false); 171 172 public static final Attribute BORDER_COLOR = 173 new Attribute("border-color", "black", false); 174 175 public static final Attribute BORDER_LEFT = 176 new Attribute("border-left", null, false); 177 178 public static final Attribute BORDER_LEFT_WIDTH = 179 new Attribute("border-left-width", "medium", false); 180 181 public static final Attribute BORDER_RIGHT = 182 new Attribute("border-right", null, false); 183 184 public static final Attribute BORDER_RIGHT_WIDTH = 185 new Attribute("border-right-width", "medium", false); 186 187 public static final Attribute BORDER_STYLE = 188 new Attribute("border-style", "none", false); 189 190 public static final Attribute BORDER_TOP = 191 new Attribute("border-top", null, false); 192 193 public static final Attribute BORDER_TOP_WIDTH = 194 new Attribute("border-top-width", "medium", false); 195 196 public static final Attribute BORDER_WIDTH = 197 new Attribute("border-width", "medium", false); 198 199 public static final Attribute CLEAR = 200 new Attribute("clear", "none", false); 201 202 public static final Attribute COLOR = 203 new Attribute("color", "black", true); 204 205 public static final Attribute DISPLAY = 206 new Attribute("display", "block", false); 207 208 public static final Attribute FLOAT = 209 new Attribute("float", "none", false); 210 211 public static final Attribute FONT = 212 new Attribute("font", null, true); 213 214 public static final Attribute FONT_FAMILY = 215 new Attribute("font-family", null, true); 216 217 public static final Attribute FONT_SIZE = 218 new Attribute("font-size", "medium", true); 219 220 public static final Attribute FONT_STYLE = 221 new Attribute("font-style", "normal", true); 222 223 public static final Attribute FONT_VARIANT = 224 new Attribute("font-variant", "normal", true); 225 226 public static final Attribute FONT_WEIGHT = 227 new Attribute("font-weight", "normal", true); 228 229 public static final Attribute HEIGHT = 230 new Attribute("height", "auto", false); 231 232 public static final Attribute LETTER_SPACING = 233 new Attribute("letter-spacing", "normal", true); 234 235 public static final Attribute LINE_HEIGHT = 236 new Attribute("line-height", "normal", true); 237 238 public static final Attribute LIST_STYLE = 239 new Attribute("list-style", null, true); 240 241 public static final Attribute LIST_STYLE_IMAGE = 242 new Attribute("list-style-image", "none", true); 243 244 public static final Attribute LIST_STYLE_POSITION = 245 new Attribute("list-style-position", "outside", true); 246 247 public static final Attribute LIST_STYLE_TYPE = 248 new Attribute("list-style-type", "disc", true); 249 250 public static final Attribute MARGIN = 251 new Attribute("margin", null, false); 252 253 public static final Attribute MARGIN_BOTTOM = 254 new Attribute("margin-bottom", "0", false); 255 256 public static final Attribute MARGIN_LEFT = 257 new Attribute("margin-left", "0", false); 258 259 public static final Attribute MARGIN_RIGHT = 260 new Attribute("margin-right", "0", false); 261 262 267 static final Attribute MARGIN_LEFT_LTR = 268 new Attribute("margin-left-ltr", 269 Integer.toString(Integer.MIN_VALUE), false); 270 271 static final Attribute MARGIN_LEFT_RTL = 272 new Attribute("margin-left-rtl", 273 Integer.toString(Integer.MIN_VALUE), false); 274 275 static final Attribute MARGIN_RIGHT_LTR = 276 new Attribute("margin-right-ltr", 277 Integer.toString(Integer.MIN_VALUE), false); 278 279 static final Attribute MARGIN_RIGHT_RTL = 280 new Attribute("margin-right-rtl", 281 Integer.toString(Integer.MIN_VALUE), false); 282 283 284 public static final Attribute MARGIN_TOP = 285 new Attribute("margin-top", "0", false); 286 287 public static final Attribute PADDING = 288 new Attribute("padding", null, false); 289 290 public static final Attribute PADDING_BOTTOM = 291 new Attribute("padding-bottom", "0", false); 292 293 public static final Attribute PADDING_LEFT = 294 new Attribute("padding-left", "0", false); 295 296 public static final Attribute PADDING_RIGHT = 297 new Attribute("padding-right", "0", false); 298 299 public static final Attribute PADDING_TOP = 300 new Attribute("padding-top", "0", false); 301 302 public static final Attribute TEXT_ALIGN = 303 new Attribute("text-align", null, true); 304 305 public static final Attribute TEXT_DECORATION = 306 new Attribute("text-decoration", "none", true); 307 308 public static final Attribute TEXT_INDENT = 309 new Attribute("text-indent", "0", true); 310 311 public static final Attribute TEXT_TRANSFORM = 312 new Attribute("text-transform", "none", true); 313 314 public static final Attribute VERTICAL_ALIGN = 315 new Attribute("vertical-align", "baseline", false); 316 317 public static final Attribute WORD_SPACING = 318 new Attribute("word-spacing", "normal", true); 319 320 public static final Attribute WHITE_SPACE = 321 new Attribute("white-space", "normal", true); 322 323 public static final Attribute WIDTH = 324 new Attribute("width", "auto", false); 325 326 static final Attribute BORDER_SPACING = 327 new Attribute("border-spacing", "0", true); 328 329 static final Attribute CAPTION_SIDE = 330 new Attribute("caption-side", "left", true); 331 332 static final Attribute[] allAttributes = { 334 BACKGROUND, BACKGROUND_ATTACHMENT, BACKGROUND_COLOR, 335 BACKGROUND_IMAGE, BACKGROUND_POSITION, BACKGROUND_REPEAT, 336 BORDER, BORDER_BOTTOM, BORDER_BOTTOM_WIDTH, BORDER_COLOR, 337 BORDER_LEFT, BORDER_LEFT_WIDTH, BORDER_RIGHT, BORDER_RIGHT_WIDTH, 338 BORDER_STYLE, BORDER_TOP, BORDER_TOP_WIDTH, BORDER_WIDTH, 339 CLEAR, COLOR, DISPLAY, FLOAT, FONT, FONT_FAMILY, FONT_SIZE, 340 FONT_STYLE, FONT_VARIANT, FONT_WEIGHT, HEIGHT, LETTER_SPACING, 341 LINE_HEIGHT, LIST_STYLE, LIST_STYLE_IMAGE, LIST_STYLE_POSITION, 342 LIST_STYLE_TYPE, MARGIN, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT, 343 MARGIN_TOP, PADDING, PADDING_BOTTOM, PADDING_LEFT, PADDING_RIGHT, 344 PADDING_TOP, TEXT_ALIGN, TEXT_DECORATION, TEXT_INDENT, TEXT_TRANSFORM, 345 VERTICAL_ALIGN, WORD_SPACING, WHITE_SPACE, WIDTH, 346 BORDER_SPACING, CAPTION_SIDE, 347 MARGIN_LEFT_LTR, MARGIN_LEFT_RTL, MARGIN_RIGHT_LTR, MARGIN_RIGHT_RTL 348 }; 349 350 private static final Attribute[] ALL_MARGINS = 351 { MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM, MARGIN_LEFT }; 352 private static final Attribute[] ALL_PADDING = 353 { PADDING_TOP, PADDING_RIGHT, PADDING_BOTTOM, PADDING_LEFT }; 354 private static final Attribute[] ALL_BORDER_WIDTHS = 355 { BORDER_TOP_WIDTH, BORDER_RIGHT_WIDTH, BORDER_BOTTOM_WIDTH, 356 BORDER_LEFT_WIDTH }; 357 358 } 359 360 static final class Value { 361 362 private Value(String name) { 363 this.name = name; 364 } 365 366 371 public String toString() { 372 return name; 373 } 374 375 static final Value INHERITED = new Value("inherited"); 376 static final Value NONE = new Value("none"); 377 static final Value DOTTED = new Value("dotted"); 378 static final Value DASHED = new Value("dashed"); 379 static final Value SOLID = new Value("solid"); 380 static final Value DOUBLE = new Value("double"); 381 static final Value GROOVE = new Value("groove"); 382 static final Value RIDGE = new Value("ridge"); 383 static final Value INSET = new Value("inset"); 384 static final Value OUTSET = new Value("outset"); 385 static final Value BLANK_LIST_ITEM = new Value("none"); 387 static final Value DISC = new Value("disc"); 388 static final Value CIRCLE = new Value("circle"); 389 static final Value SQUARE = new Value("square"); 390 static final Value DECIMAL = new Value("decimal"); 391 static final Value LOWER_ROMAN = new Value("lower-roman"); 392 static final Value UPPER_ROMAN = new Value("upper-roman"); 393 static final Value LOWER_ALPHA = new Value("lower-alpha"); 394 static final Value UPPER_ALPHA = new Value("upper-alpha"); 395 static final Value BACKGROUND_NO_REPEAT = new Value("no-repeat"); 397 static final Value BACKGROUND_REPEAT = new Value("repeat"); 398 static final Value BACKGROUND_REPEAT_X = new Value("repeat-x"); 399 static final Value BACKGROUND_REPEAT_Y = new Value("repeat-y"); 400 static final Value BACKGROUND_SCROLL = new Value("scroll"); 402 static final Value BACKGROUND_FIXED = new Value("fixed"); 403 404 private String name; 405 406 static final Value[] allValues = { 407 INHERITED, NONE, DOTTED, DASHED, SOLID, DOUBLE, GROOVE, 408 RIDGE, INSET, OUTSET, DISC, CIRCLE, SQUARE, DECIMAL, 409 LOWER_ROMAN, UPPER_ROMAN, LOWER_ALPHA, UPPER_ALPHA, 410 BLANK_LIST_ITEM, BACKGROUND_NO_REPEAT, BACKGROUND_REPEAT, 411 BACKGROUND_REPEAT_X, BACKGROUND_REPEAT_Y, 412 BACKGROUND_FIXED, BACKGROUND_FIXED 413 }; 414 } 415 416 public CSS() { 417 baseFontSize = baseFontSizeIndex + 1; 418 valueConvertor = new Hashtable (); 420 valueConvertor.put(CSS.Attribute.FONT_SIZE, new FontSize()); 421 valueConvertor.put(CSS.Attribute.FONT_FAMILY, new FontFamily()); 422 valueConvertor.put(CSS.Attribute.FONT_WEIGHT, new FontWeight()); 423 valueConvertor.put(CSS.Attribute.BORDER_STYLE, new BorderStyle()); 424 Object cv = new ColorValue(); 425 valueConvertor.put(CSS.Attribute.COLOR, cv); 426 valueConvertor.put(CSS.Attribute.BACKGROUND_COLOR, cv); 427 valueConvertor.put(CSS.Attribute.BORDER_COLOR, cv); 428 Object lv = new LengthValue(); 429 valueConvertor.put(CSS.Attribute.MARGIN_TOP, lv); 430 valueConvertor.put(CSS.Attribute.MARGIN_BOTTOM, lv); 431 valueConvertor.put(CSS.Attribute.MARGIN_LEFT, lv); 432 valueConvertor.put(CSS.Attribute.MARGIN_LEFT_LTR, lv); 433 valueConvertor.put(CSS.Attribute.MARGIN_LEFT_RTL, lv); 434 valueConvertor.put(CSS.Attribute.MARGIN_RIGHT, lv); 435 valueConvertor.put(CSS.Attribute.MARGIN_RIGHT_LTR, lv); 436 valueConvertor.put(CSS.Attribute.MARGIN_RIGHT_RTL, lv); 437 valueConvertor.put(CSS.Attribute.PADDING_TOP, lv); 438 valueConvertor.put(CSS.Attribute.PADDING_BOTTOM, lv); 439 valueConvertor.put(CSS.Attribute.PADDING_LEFT, lv); 440 valueConvertor.put(CSS.Attribute.PADDING_RIGHT, lv); 441 Object bv = new BorderWidthValue(null, 0); 442 valueConvertor.put(CSS.Attribute.BORDER_WIDTH, lv); 443 valueConvertor.put(CSS.Attribute.BORDER_TOP_WIDTH, bv); 444 valueConvertor.put(CSS.Attribute.BORDER_BOTTOM_WIDTH, bv); 445 valueConvertor.put(CSS.Attribute.BORDER_LEFT_WIDTH, bv); 446 valueConvertor.put(CSS.Attribute.BORDER_RIGHT_WIDTH, bv); 447 Object nlv = new LengthValue(true); 448 valueConvertor.put(CSS.Attribute.TEXT_INDENT, nlv); 449 valueConvertor.put(CSS.Attribute.WIDTH, lv); 450 valueConvertor.put(CSS.Attribute.HEIGHT, lv); 451 valueConvertor.put(CSS.Attribute.BORDER_SPACING, lv); 452 Object sv = new StringValue(); 453 valueConvertor.put(CSS.Attribute.FONT_STYLE, sv); 454 valueConvertor.put(CSS.Attribute.TEXT_DECORATION, sv); 455 valueConvertor.put(CSS.Attribute.TEXT_ALIGN, sv); 456 valueConvertor.put(CSS.Attribute.VERTICAL_ALIGN, sv); 457 Object valueMapper = new CssValueMapper(); 458 valueConvertor.put(CSS.Attribute.LIST_STYLE_TYPE, 459 valueMapper); 460 valueConvertor.put(CSS.Attribute.BACKGROUND_IMAGE, 461 new BackgroundImage()); 462 valueConvertor.put(CSS.Attribute.BACKGROUND_POSITION, 463 new BackgroundPosition()); 464 valueConvertor.put(CSS.Attribute.BACKGROUND_REPEAT, 465 valueMapper); 466 valueConvertor.put(CSS.Attribute.BACKGROUND_ATTACHMENT, 467 valueMapper); 468 Object generic = new CssValue(); 469 int n = CSS.Attribute.allAttributes.length; 470 for (int i = 0; i < n; i++) { 471 CSS.Attribute key = CSS.Attribute.allAttributes[i]; 472 if (valueConvertor.get(key) == null) { 473 valueConvertor.put(key, generic); 474 } 475 } 476 } 477 478 483 void setBaseFontSize(int sz) { 484 if (sz < 1) 485 baseFontSize = 0; 486 else if (sz > 7) 487 baseFontSize = 7; 488 else 489 baseFontSize = sz; 490 } 491 492 495 void setBaseFontSize(String size) { 496 int relSize, absSize, diff; 497 498 if (size != null) { 499 if (size.startsWith("+")) { 500 relSize = Integer.valueOf(size.substring(1)).intValue(); 501 setBaseFontSize(baseFontSize + relSize); 502 } else if (size.startsWith("-")) { 503 relSize = -Integer.valueOf(size.substring(1)).intValue(); 504 setBaseFontSize(baseFontSize + relSize); 505 } else { 506 setBaseFontSize(Integer.valueOf(size).intValue()); 507 } 508 } 509 } 510 511 514 int getBaseFontSize() { 515 return baseFontSize; 516 } 517 518 522 void addInternalCSSValue(MutableAttributeSet attr, 523 CSS.Attribute key, String value) { 524 if (key == CSS.Attribute.FONT) { 525 ShorthandFontParser.parseShorthandFont(this, value, attr); 526 } 527 else if (key == CSS.Attribute.BACKGROUND) { 528 ShorthandBackgroundParser.parseShorthandBackground 529 (this, value, attr); 530 } 531 else if (key == CSS.Attribute.MARGIN) { 532 ShorthandMarginParser.parseShorthandMargin(this, value, attr, 533 CSS.Attribute.ALL_MARGINS); 534 } 535 else if (key == CSS.Attribute.PADDING) { 536 ShorthandMarginParser.parseShorthandMargin(this, value, attr, 537 CSS.Attribute.ALL_PADDING); 538 } 539 else if (key == CSS.Attribute.BORDER_WIDTH) { 540 ShorthandMarginParser.parseShorthandMargin(this, value, attr, 541 CSS.Attribute.ALL_BORDER_WIDTHS); 542 } 543 else { 544 Object iValue = getInternalCSSValue(key, value); 545 if (iValue != null) { 546 attr.addAttribute(key, iValue); 547 } 548 } 549 } 550 551 557 Object getInternalCSSValue(CSS.Attribute key, String value) { 558 CssValue conv = (CssValue) valueConvertor.get(key); 559 Object r = conv.parseCssValue(value); 560 return r != null ? r : conv.parseCssValue(key.getDefaultValue()); 561 } 562 563 566 Attribute styleConstantsKeyToCSSKey(StyleConstants sc) { 567 return (Attribute)styleConstantToCssMap.get(sc); 568 } 569 570 573 Object styleConstantsValueToCSSValue(StyleConstants sc, 574 Object styleValue) { 575 Object cssKey = styleConstantsKeyToCSSKey(sc); 576 if (cssKey != null) { 577 CssValue conv = (CssValue)valueConvertor.get(cssKey); 578 return conv.fromStyleConstants(sc, styleValue); 579 } 580 return null; 581 } 582 583 587 Object cssValueToStyleConstantsValue(StyleConstants key, Object value) { 588 if (value instanceof CssValue) { 589 return ((CssValue)value).toStyleConstants((StyleConstants)key, 590 null); 591 } 592 return null; 593 } 594 595 601 Font getFont(StyleContext sc, AttributeSet a, int defaultSize, StyleSheet ss) { 602 ss = getStyleSheet(ss); 603 int size = getFontSize(a, defaultSize, ss); 604 605 609 StringValue vAlignV = (StringValue)a.getAttribute 610 (CSS.Attribute.VERTICAL_ALIGN); 611 if ((vAlignV != null)) { 612 String vAlign = vAlignV.toString(); 613 if ((vAlign.indexOf("sup") >= 0) || 614 (vAlign.indexOf("sub") >= 0)) { 615 size -= 2; 616 } 617 } 618 619 FontFamily familyValue = (FontFamily)a.getAttribute 620 (CSS.Attribute.FONT_FAMILY); 621 String family = (familyValue != null) ? familyValue.getValue() : 622 "SansSerif"; 623 int style = Font.PLAIN; 624 FontWeight weightValue = (FontWeight) a.getAttribute 625 (CSS.Attribute.FONT_WEIGHT); 626 if ((weightValue != null) && (weightValue.getValue() > 400)) { 627 style |= Font.BOLD; 628 } 629 Object fs = a.getAttribute(CSS.Attribute.FONT_STYLE); 630 if ((fs != null) && (fs.toString().indexOf("italic") >= 0)) { 631 style |= Font.ITALIC; 632 } 633 if (family.equalsIgnoreCase("monospace")) { 634 family = "Monospaced"; 635 } 636 Font f = sc.getFont(family, style, size); 637 if (f == null 638 || (f.getFamily().equals("Dialog") 639 && ! family.equalsIgnoreCase("Dialog"))) { 640 family = "SansSerif"; 641 f = sc.getFont(family, style, size); 642 } 643 return f; 644 } 645 646 static int getFontSize(AttributeSet attr, int defaultSize, StyleSheet ss) { 647 FontSize sizeValue = (FontSize)attr.getAttribute(CSS.Attribute. 650 FONT_SIZE); 651 652 return (sizeValue != null) ? (int)sizeValue.getValue(attr, ss) : 653 defaultSize; 654 } 655 656 666 Color getColor(AttributeSet a, CSS.Attribute key) { 667 ColorValue cv = (ColorValue) a.getAttribute(key); 668 if (cv != null) { 669 return cv.getValue(); 670 } 671 return null; 672 } 673 674 680 float getPointSize(String size, StyleSheet ss) { 681 int relSize, absSize, diff, index; 682 ss = getStyleSheet(ss); 683 if (size != null) { 684 if (size.startsWith("+")) { 685 relSize = Integer.valueOf(size.substring(1)).intValue(); 686 return getPointSize(baseFontSize + relSize, ss); 687 } else if (size.startsWith("-")) { 688 relSize = -Integer.valueOf(size.substring(1)).intValue(); 689 return getPointSize(baseFontSize + relSize, ss); 690 } else { 691 absSize = Integer.valueOf(size).intValue(); 692 return getPointSize(absSize, ss); 693 } 694 } 695 return 0; 696 } 697 698 702 float getLength(AttributeSet a, CSS.Attribute key, StyleSheet ss) { 703 ss = getStyleSheet(ss); 704 LengthValue lv = (LengthValue) a.getAttribute(key); 705 boolean isW3CLengthUnits = (ss == null) ? false : ss.isW3CLengthUnits(); 706 float len = (lv != null) ? lv.getValue(isW3CLengthUnits) : 0; 707 return len; 708 } 709 710 719 AttributeSet translateHTMLToCSS(AttributeSet htmlAttrSet) { 720 MutableAttributeSet cssAttrSet = new SimpleAttributeSet(); 721 Element elem = (Element)htmlAttrSet; 722 HTML.Tag tag = getHTMLTag(htmlAttrSet); 723 if ((tag == HTML.Tag.TD) || (tag == HTML.Tag.TH)) { 724 AttributeSet tableAttr = elem.getParentElement(). 726 getParentElement().getAttributes(); 727 translateAttribute(HTML.Attribute.BORDER, tableAttr, cssAttrSet); 728 String pad = (String )tableAttr.getAttribute(HTML.Attribute.CELLPADDING); 729 if (pad != null) { 730 LengthValue v = 731 (LengthValue)getInternalCSSValue(CSS.Attribute.PADDING_TOP, pad); 732 v.span = (v.span < 0) ? 0 : v.span; 733 cssAttrSet.addAttribute(CSS.Attribute.PADDING_TOP, v); 734 cssAttrSet.addAttribute(CSS.Attribute.PADDING_BOTTOM, v); 735 cssAttrSet.addAttribute(CSS.Attribute.PADDING_LEFT, v); 736 cssAttrSet.addAttribute(CSS.Attribute.PADDING_RIGHT, v); 737 } 738 } 739 if (elem.isLeaf()) { 740 translateEmbeddedAttributes(htmlAttrSet, cssAttrSet); 741 } else { 742 translateAttributes(tag, htmlAttrSet, cssAttrSet); 743 } 744 if (tag == HTML.Tag.CAPTION) { 745 748 Object v = htmlAttrSet.getAttribute(HTML.Attribute.ALIGN); 749 if ((v != null) && (v.equals("top") || v.equals("bottom"))) { 750 cssAttrSet.addAttribute(CSS.Attribute.CAPTION_SIDE, v); 751 cssAttrSet.removeAttribute(CSS.Attribute.TEXT_ALIGN); 752 } else { 753 v = htmlAttrSet.getAttribute(HTML.Attribute.VALIGN); 754 if (v != null) { 755 cssAttrSet.addAttribute(CSS.Attribute.CAPTION_SIDE, v); 756 } 757 } 758 } 759 return cssAttrSet; 760 } 761 762 private static final Hashtable attributeMap = new Hashtable (); 763 private static final Hashtable valueMap = new Hashtable (); 764 765 775 private static final Hashtable htmlAttrToCssAttrMap = new Hashtable (20); 776 777 782 private static final Hashtable styleConstantToCssMap = new Hashtable (17); 783 784 private static final Hashtable htmlValueToCssValueMap = new Hashtable (8); 785 786 private static final Hashtable cssValueToInternalValueMap = new Hashtable (13); 787 788 static { 789 for (int i = 0; i < Attribute.allAttributes.length; i++ ) { 791 attributeMap.put(Attribute.allAttributes[i].toString(), 792 Attribute.allAttributes[i]); 793 } 794 for (int i = 0; i < Value.allValues.length; i++ ) { 796 valueMap.put(Value.allValues[i].toString(), 797 Value.allValues[i]); 798 } 799 800 htmlAttrToCssAttrMap.put(HTML.Attribute.COLOR, 801 new CSS.Attribute []{CSS.Attribute.COLOR}); 802 htmlAttrToCssAttrMap.put(HTML.Attribute.TEXT, 803 new CSS.Attribute []{CSS.Attribute.COLOR}); 804 htmlAttrToCssAttrMap.put(HTML.Attribute.CLEAR, 805 new CSS.Attribute []{CSS.Attribute.CLEAR}); 806 htmlAttrToCssAttrMap.put(HTML.Attribute.BACKGROUND, 807 new CSS.Attribute []{CSS.Attribute.BACKGROUND_IMAGE}); 808 htmlAttrToCssAttrMap.put(HTML.Attribute.BGCOLOR, 809 new CSS.Attribute []{CSS.Attribute.BACKGROUND_COLOR}); 810 htmlAttrToCssAttrMap.put(HTML.Attribute.WIDTH, 811 new CSS.Attribute []{CSS.Attribute.WIDTH}); 812 htmlAttrToCssAttrMap.put(HTML.Attribute.HEIGHT, 813 new CSS.Attribute []{CSS.Attribute.HEIGHT}); 814 htmlAttrToCssAttrMap.put(HTML.Attribute.BORDER, 815 new CSS.Attribute []{CSS.Attribute.BORDER_TOP_WIDTH, CSS.Attribute.BORDER_RIGHT_WIDTH, CSS.Attribute.BORDER_BOTTOM_WIDTH, CSS.Attribute.BORDER_LEFT_WIDTH}); 816 htmlAttrToCssAttrMap.put(HTML.Attribute.CELLPADDING, 817 new CSS.Attribute []{CSS.Attribute.PADDING}); 818 htmlAttrToCssAttrMap.put(HTML.Attribute.CELLSPACING, 819 new CSS.Attribute []{CSS.Attribute.BORDER_SPACING}); 820 htmlAttrToCssAttrMap.put(HTML.Attribute.MARGINWIDTH, 821 new CSS.Attribute []{CSS.Attribute.MARGIN_LEFT, 822 CSS.Attribute.MARGIN_RIGHT}); 823 htmlAttrToCssAttrMap.put(HTML.Attribute.MARGINHEIGHT, 824 new CSS.Attribute []{CSS.Attribute.MARGIN_TOP, 825 CSS.Attribute.MARGIN_BOTTOM}); 826 htmlAttrToCssAttrMap.put(HTML.Attribute.HSPACE, 827 new CSS.Attribute []{CSS.Attribute.PADDING_LEFT, 828 CSS.Attribute.PADDING_RIGHT}); 829 htmlAttrToCssAttrMap.put(HTML.Attribute.VSPACE, 830 new CSS.Attribute []{CSS.Attribute.PADDING_BOTTOM, 831 CSS.Attribute.PADDING_TOP}); 832 htmlAttrToCssAttrMap.put(HTML.Attribute.FACE, 833 new CSS.Attribute []{CSS.Attribute.FONT_FAMILY}); 834 htmlAttrToCssAttrMap.put(HTML.Attribute.SIZE, 835 new CSS.Attribute []{CSS.Attribute.FONT_SIZE}); 836 htmlAttrToCssAttrMap.put(HTML.Attribute.VALIGN, 837 new CSS.Attribute []{CSS.Attribute.VERTICAL_ALIGN}); 838 htmlAttrToCssAttrMap.put(HTML.Attribute.ALIGN, 839 new CSS.Attribute []{CSS.Attribute.VERTICAL_ALIGN, 840 CSS.Attribute.TEXT_ALIGN, 841 CSS.Attribute.FLOAT}); 842 htmlAttrToCssAttrMap.put(HTML.Attribute.TYPE, 843 new CSS.Attribute []{CSS.Attribute.LIST_STYLE_TYPE}); 844 htmlAttrToCssAttrMap.put(HTML.Attribute.NOWRAP, 845 new CSS.Attribute []{CSS.Attribute.WHITE_SPACE}); 846 847 styleConstantToCssMap.put(StyleConstants.FontFamily, 849 CSS.Attribute.FONT_FAMILY); 850 styleConstantToCssMap.put(StyleConstants.FontSize, 851 CSS.Attribute.FONT_SIZE); 852 styleConstantToCssMap.put(StyleConstants.Bold, 853 CSS.Attribute.FONT_WEIGHT); 854 styleConstantToCssMap.put(StyleConstants.Italic, 855 CSS.Attribute.FONT_STYLE); 856 styleConstantToCssMap.put(StyleConstants.Underline, 857 CSS.Attribute.TEXT_DECORATION); 858 styleConstantToCssMap.put(StyleConstants.StrikeThrough, 859 CSS.Attribute.TEXT_DECORATION); 860 styleConstantToCssMap.put(StyleConstants.Superscript, 861 CSS.Attribute.VERTICAL_ALIGN); 862 styleConstantToCssMap.put(StyleConstants.Subscript, 863 CSS.Attribute.VERTICAL_ALIGN); 864 styleConstantToCssMap.put(StyleConstants.Foreground, 865 CSS.Attribute.COLOR); 866 styleConstantToCssMap.put(StyleConstants.Background, 867 CSS.Attribute.BACKGROUND_COLOR); 868 styleConstantToCssMap.put(StyleConstants.FirstLineIndent, 869 CSS.Attribute.TEXT_INDENT); 870 styleConstantToCssMap.put(StyleConstants.LeftIndent, 871 CSS.Attribute.MARGIN_LEFT); 872 styleConstantToCssMap.put(StyleConstants.RightIndent, 873 CSS.Attribute.MARGIN_RIGHT); 874 styleConstantToCssMap.put(StyleConstants.SpaceAbove, 875 CSS.Attribute.MARGIN_TOP); 876 styleConstantToCssMap.put(StyleConstants.SpaceBelow, 877 CSS.Attribute.MARGIN_BOTTOM); 878 styleConstantToCssMap.put(StyleConstants.Alignment, 879 CSS.Attribute.TEXT_ALIGN); 880 881 htmlValueToCssValueMap.put("disc", CSS.Value.DISC); 883 htmlValueToCssValueMap.put("square", CSS.Value.SQUARE); 884 htmlValueToCssValueMap.put("circle", CSS.Value.CIRCLE); 885 htmlValueToCssValueMap.put("1", CSS.Value.DECIMAL); 886 htmlValueToCssValueMap.put("a", CSS.Value.LOWER_ALPHA); 887 htmlValueToCssValueMap.put("A", CSS.Value.UPPER_ALPHA); 888 htmlValueToCssValueMap.put("i", CSS.Value.LOWER_ROMAN); 889 htmlValueToCssValueMap.put("I", CSS.Value.UPPER_ROMAN); 890 891 cssValueToInternalValueMap.put("none", CSS.Value.NONE); 893 cssValueToInternalValueMap.put("disc", CSS.Value.DISC); 894 cssValueToInternalValueMap.put("square", CSS.Value.SQUARE); 895 cssValueToInternalValueMap.put("circle", CSS.Value.CIRCLE); 896 cssValueToInternalValueMap.put("decimal", CSS.Value.DECIMAL); 897 cssValueToInternalValueMap.put("lower-roman", CSS.Value.LOWER_ROMAN); 898 cssValueToInternalValueMap.put("upper-roman", CSS.Value.UPPER_ROMAN); 899 cssValueToInternalValueMap.put("lower-alpha", CSS.Value.LOWER_ALPHA); 900 cssValueToInternalValueMap.put("upper-alpha", CSS.Value.UPPER_ALPHA); 901 cssValueToInternalValueMap.put("repeat", CSS.Value.BACKGROUND_REPEAT); 902 cssValueToInternalValueMap.put("no-repeat", 903 CSS.Value.BACKGROUND_NO_REPEAT); 904 cssValueToInternalValueMap.put("repeat-x", 905 CSS.Value.BACKGROUND_REPEAT_X); 906 cssValueToInternalValueMap.put("repeat-y", 907 CSS.Value.BACKGROUND_REPEAT_Y); 908 cssValueToInternalValueMap.put("scroll", 909 CSS.Value.BACKGROUND_SCROLL); 910 cssValueToInternalValueMap.put("fixed", 911 CSS.Value.BACKGROUND_FIXED); 912 913 Object [] keys = CSS.Attribute.allAttributes; 915 try { 916 for (int i = 0; i < keys.length; i++) { 917 StyleContext.registerStaticAttributeKey(keys[i]); 918 } 919 } catch (Throwable e) { 920 e.printStackTrace(); 921 } 922 923 keys = CSS.Value.allValues; 925 try { 926 for (int i = 0; i < keys.length; i++) { 927 StyleContext.registerStaticAttributeKey(keys[i]); 928 } 929 } catch (Throwable e) { 930 e.printStackTrace(); 931 } 932 } 933 934 937 public static Attribute[] getAllAttributeKeys() { 938 Attribute[] keys = new Attribute[Attribute.allAttributes.length]; 939 System.arraycopy(Attribute.allAttributes, 0, keys, 0, Attribute.allAttributes.length); 940 return keys; 941 } 942 943 954 public static final Attribute getAttribute(String name) { 955 return (Attribute) attributeMap.get(name); 956 } 957 958 970 static final Value getValue(String name) { 971 return (Value) valueMap.get(name); 972 } 973 974 975 979 985 static URL getURL(URL base, String cssString) { 986 if (cssString == null) { 987 return null; 988 } 989 if (cssString.startsWith("url(") && 990 cssString.endsWith(")")) { 991 cssString = cssString.substring(4, cssString.length() - 1); 992 } 993 try { 995 URL url = new URL (cssString); 996 if (url != null) { 997 return url; 998 } 999 } catch (MalformedURLException mue) { 1000 } 1001 if (base != null) { 1003 try { 1005 URL url = new URL (base, cssString); 1006 return url; 1007 } 1008 catch (MalformedURLException muee) { 1009 } 1010 } 1011 return null; 1012 } 1013 1014 1018 static String colorToHex(Color color) { 1019 1020 String colorstr = new String ("#"); 1021 1022 String str = Integer.toHexString(color.getRed()); 1024 if (str.length() > 2) 1025 str = str.substring(0, 2); 1026 else if (str.length() < 2) 1027 colorstr += "0" + str; 1028 else 1029 colorstr += str; 1030 1031 str = Integer.toHexString(color.getGreen()); 1033 if (str.length() > 2) 1034 str = str.substring(0, 2); 1035 else if (str.length() < 2) 1036 colorstr += "0" + str; 1037 else 1038 colorstr += str; 1039 1040 str = Integer.toHexString(color.getBlue()); 1042 if (str.length() > 2) 1043 str = str.substring(0, 2); 1044 else if (str.length() < 2) 1045 colorstr += "0" + str; 1046 else 1047 colorstr += str; 1048 1049 return colorstr; 1050 } 1051 1052 1057 static final Color hexToColor(String value) { 1058 String digits; 1059 int n = value.length(); 1060 if (value.startsWith("#")) { 1061 digits = value.substring(1, Math.min(value.length(), 7)); 1062 } else { 1063 digits = value; 1064 } 1065 String hstr = "0x" + digits; 1066 Color c; 1067 try { 1068 c = Color.decode(hstr); 1069 } catch (NumberFormatException nfe) { 1070 c = null; 1071 } 1072 return c; 1073 } 1074 1075 1079 static Color stringToColor(String str) { 1080 Color color = null; 1081 1082 if (str.length() == 0) 1083 color = Color.black; 1084 else if (str.startsWith("rgb(")) { 1085 color = parseRGB(str); 1086 } 1087 else if (str.charAt(0) == '#') 1088 color = hexToColor(str); 1089 else if (str.equalsIgnoreCase("Black")) 1090 color = hexToColor("#000000"); 1091 else if(str.equalsIgnoreCase("Silver")) 1092 color = hexToColor("#C0C0C0"); 1093 else if(str.equalsIgnoreCase("Gray")) 1094 color = hexToColor("#808080"); 1095 else if(str.equalsIgnoreCase("White")) 1096 color = hexToColor("#FFFFFF"); 1097 else if(str.equalsIgnoreCase("Maroon")) 1098 color = hexToColor("#800000"); 1099 else if(str.equalsIgnoreCase("Red")) 1100 color = hexToColor("#FF0000"); 1101 else if(str.equalsIgnoreCase("Purple")) 1102 color = hexToColor("#800080"); 1103 else if(str.equalsIgnoreCase("Fuchsia")) 1104 color = hexToColor("#FF00FF"); 1105 else if(str.equalsIgnoreCase("Green")) 1106 color = hexToColor("#008000"); 1107 else if(str.equalsIgnoreCase("Lime")) 1108 color = hexToColor("#00FF00"); 1109 else if(str.equalsIgnoreCase("Olive")) 1110 color = hexToColor("#808000"); 1111 else if(str.equalsIgnoreCase("Yellow")) 1112 color = hexToColor("#FFFF00"); 1113 else if(str.equalsIgnoreCase("Navy")) 1114 color = hexToColor("#000080"); 1115 else if(str.equalsIgnoreCase("Blue")) 1116 color = hexToColor("#0000FF"); 1117 else if(str.equalsIgnoreCase("Teal")) 1118 color = hexToColor("#008080"); 1119 else if(str.equalsIgnoreCase("Aqua")) 1120 color = hexToColor("#00FFFF"); 1121 else 1122 color = hexToColor(str); return color; 1124 } 1125 1126 1132 private static Color parseRGB(String string) { 1133 int[] index = new int[1]; 1135 1136 index[0] = 4; 1137 int red = getColorComponent(string, index); 1138 int green = getColorComponent(string, index); 1139 int blue = getColorComponent(string, index); 1140 1141 return new Color (red, green, blue); 1142 } 1143 1144 1150 private static int getColorComponent(String string, int[] index) { 1151 int length = string.length(); 1152 char aChar; 1153 1154 while(index[0] < length && (aChar = string.charAt(index[0])) != '-' && 1156 !Character.isDigit(aChar) && aChar != '.') { 1157 index[0]++; 1158 } 1159 1160 int start = index[0]; 1161 1162 if (start < length && string.charAt(index[0]) == '-') { 1163 index[0]++; 1164 } 1165 while(index[0] < length && 1166 Character.isDigit(string.charAt(index[0]))) { 1167 index[0]++; 1168 } 1169 if (index[0] < length && string.charAt(index[0]) == '.') { 1170 index[0]++; 1172 while(index[0] < length && 1173 Character.isDigit(string.charAt(index[0]))) { 1174 index[0]++; 1175 } 1176 } 1177 if (start != index[0]) { 1178 try { 1179 float value = Float.parseFloat(string.substring 1180 (start, index[0])); 1181 1182 if (index[0] < length && string.charAt(index[0]) == '%') { 1183 index[0]++; 1184 value = value * 255f / 100f; 1185 } 1186 return Math.min(255, Math.max(0, (int)value)); 1187 } catch (NumberFormatException nfe) { 1188 } 1190 } 1191 return 0; 1192 } 1193 1194 static int getIndexOfSize(float pt, int[] sizeMap) { 1195 for (int i = 0; i < sizeMap.length; i ++ ) 1196 if (pt <= sizeMap[i]) 1197 return i + 1; 1198 return sizeMap.length; 1199 } 1200 1201 static int getIndexOfSize(float pt, StyleSheet ss) { 1202 int[] sizeMap = (ss != null) ? ss.getSizeMap() : 1203 StyleSheet.sizeMapDefault; 1204 return getIndexOfSize(pt, sizeMap); 1205 } 1206 1207 1208 1212 static String [] parseStrings(String value) { 1213 int current, last; 1214 int length = (value == null) ? 0 : value.length(); 1215 Vector temp = new Vector (4); 1216 1217 current = 0; 1218 while (current < length) { 1219 while (current < length && Character.isWhitespace 1221 (value.charAt(current))) { 1222 current++; 1223 } 1224 last = current; 1225 while (current < length && !Character.isWhitespace 1226 (value.charAt(current))) { 1227 current++; 1228 } 1229 if (last != current) { 1230 temp.addElement(value.substring(last, current)); 1231 } 1232 current++; 1233 } 1234 String [] retValue = new String [temp.size()]; 1235 temp.copyInto(retValue); 1236 return retValue; 1237 } 1238 1239 1243 float getPointSize(int index, StyleSheet ss) { 1244 ss = getStyleSheet(ss); 1245 int[] sizeMap = (ss != null) ? ss.getSizeMap() : 1246 StyleSheet.sizeMapDefault; 1247 --index; 1248 if (index < 0) 1249 return sizeMap[0]; 1250 else if (index > sizeMap.length - 1) 1251 return sizeMap[sizeMap.length - 1]; 1252 else 1253 return sizeMap[index]; 1254 } 1255 1256 1257 private void translateEmbeddedAttributes(AttributeSet htmlAttrSet, 1258 MutableAttributeSet cssAttrSet) { 1259 Enumeration keys = htmlAttrSet.getAttributeNames(); 1260 if (htmlAttrSet.getAttribute(StyleConstants.NameAttribute) == 1261 HTML.Tag.HR) { 1262 translateAttributes(HTML.Tag.HR, htmlAttrSet, cssAttrSet); 1264 } 1265 while (keys.hasMoreElements()) { 1266 Object key = keys.nextElement(); 1267 if (key instanceof HTML.Tag ) { 1268 HTML.Tag tag = (HTML.Tag )key; 1269 Object o = htmlAttrSet.getAttribute(tag); 1270 if (o != null && o instanceof AttributeSet) { 1271 translateAttributes(tag, (AttributeSet)o, cssAttrSet); 1272 } 1273 } else if (key instanceof CSS.Attribute ) { 1274 cssAttrSet.addAttribute(key, htmlAttrSet.getAttribute(key)); 1275 } 1276 } 1277 } 1278 1279 private void translateAttributes(HTML.Tag tag, 1280 AttributeSet htmlAttrSet, 1281 MutableAttributeSet cssAttrSet) { 1282 Enumeration names = htmlAttrSet.getAttributeNames(); 1283 while (names.hasMoreElements()) { 1284 Object name = names.nextElement(); 1285 1286 if (name instanceof HTML.Attribute ) { 1287 HTML.Attribute key = (HTML.Attribute )name; 1288 1289 1295 if (key == HTML.Attribute.ALIGN) { 1296 String htmlAttrValue = (String )htmlAttrSet.getAttribute(HTML.Attribute.ALIGN); 1297 if (htmlAttrValue != null) { 1298 CSS.Attribute cssAttr = getCssAlignAttribute(tag, htmlAttrSet); 1299 if (cssAttr != null) { 1300 Object o = getCssValue(cssAttr, htmlAttrValue); 1301 if (o != null) { 1302 cssAttrSet.addAttribute(cssAttr, o); 1303 } 1304 } 1305 } 1306 } else { 1307 1308 1312 1313 if (key == HTML.Attribute.SIZE && !isHTMLFontTag(tag)) { 1314 continue; 1315 } 1316 1317 translateAttribute(key, htmlAttrSet, cssAttrSet); 1318 } 1319 } else if (name instanceof CSS.Attribute ) { 1320 cssAttrSet.addAttribute(name, htmlAttrSet.getAttribute(name)); 1321 } 1322 } 1323 } 1324 1325 private void translateAttribute(HTML.Attribute key, 1326 AttributeSet htmlAttrSet, 1327 MutableAttributeSet cssAttrSet) { 1328 1332 CSS.Attribute [] cssAttrList = getCssAttribute(key); 1333 1334 String htmlAttrValue = (String )htmlAttrSet.getAttribute(key); 1335 1336 if (cssAttrList == null || htmlAttrValue == null) { 1337 return; 1338 } 1339 for (int i = 0; i < cssAttrList.length; i++) { 1340 Object o = getCssValue(cssAttrList[i], htmlAttrValue); 1341 if (o != null) { 1342 cssAttrSet.addAttribute(cssAttrList[i], o); 1343 } 1344 } 1345 } 1346 1347 1355 Object getCssValue(CSS.Attribute cssAttr, String htmlAttrValue) { 1356 CssValue value = (CssValue)valueConvertor.get(cssAttr); 1357 Object o = value.parseHtmlValue(htmlAttrValue); 1358 return o; 1359 } 1360 1361 1367 private CSS.Attribute [] getCssAttribute(HTML.Attribute hAttr) { 1368 return (CSS.Attribute [])htmlAttrToCssAttrMap.get(hAttr); 1369 } 1370 1371 1382 private CSS.Attribute getCssAlignAttribute(HTML.Tag tag, 1383 AttributeSet htmlAttrSet) { 1384 return CSS.Attribute.TEXT_ALIGN; 1385 1400 } 1401 1402 1408 private HTML.Tag getHTMLTag(AttributeSet htmlAttrSet) { 1409 Object o = htmlAttrSet.getAttribute(StyleConstants.NameAttribute); 1410 if (o instanceof HTML.Tag ) { 1411 HTML.Tag tag = (HTML.Tag ) o; 1412 return tag; 1413 } 1414 return null; 1415 } 1416 1417 1418 private boolean isHTMLFontTag(HTML.Tag tag) { 1419 return (tag != null && ((tag == HTML.Tag.FONT) || (tag == HTML.Tag.BASEFONT))); 1420 } 1421 1422 1423 private boolean isFloater(String alignValue) { 1424 return (alignValue.equals("left") || alignValue.equals("right")); 1425 } 1426 1427 private boolean validTextAlignValue(String alignValue) { 1428 return (isFloater(alignValue) || alignValue.equals("center")); 1429 } 1430 1431 1458 static class CssValue implements Serializable { 1459 1460 1466 Object parseCssValue(String value) { 1467 return value; 1468 } 1469 1470 1479 Object parseHtmlValue(String value) { 1480 return parseCssValue(value); 1481 } 1482 1483 1494 Object fromStyleConstants(StyleConstants key, Object value) { 1495 return null; 1496 } 1497 1498 1510 Object toStyleConstants(StyleConstants key, View v) { 1511 return null; 1512 } 1513 1514 1517 public String toString() { 1518 return svalue; 1519 } 1520 1521 1525 String svalue; 1526 } 1527 1528 1536 static class StringValue extends CssValue { 1537 1538 1544 Object parseCssValue(String value) { 1545 StringValue sv = new StringValue(); 1546 sv.svalue = value; 1547 return sv; 1548 } 1549 1550 1561 Object fromStyleConstants(StyleConstants key, Object value) { 1562 if (key == StyleConstants.Italic) { 1563 if (value.equals(Boolean.TRUE)) { 1564 return parseCssValue("italic"); 1565 } 1566 return parseCssValue(""); 1567 } else if (key == StyleConstants.Underline) { 1568 if (value.equals(Boolean.TRUE)) { 1569 return parseCssValue("underline"); 1570 } 1571 return parseCssValue(""); 1572 } else if (key == StyleConstants.Alignment) { 1573 int align = ((Integer )value).intValue(); 1574 String ta; 1575 switch(align) { 1576 case StyleConstants.ALIGN_LEFT: 1577 ta = "left"; 1578 break; 1579 case StyleConstants.ALIGN_RIGHT: 1580 ta = "right"; 1581 break; 1582 case StyleConstants.ALIGN_CENTER: 1583 ta = "center"; 1584 break; 1585 case StyleConstants.ALIGN_JUSTIFIED: 1586 ta = "justify"; 1587 break; 1588 default: 1589 ta = "left"; 1590 } 1591 return parseCssValue(ta); 1592 } else if (key == StyleConstants.StrikeThrough) { 1593 if (value.equals(Boolean.TRUE)) { 1594 return parseCssValue("line-through"); 1595 } 1596 return parseCssValue(""); 1597 } else if (key == StyleConstants.Superscript) { 1598 if (value.equals(Boolean.TRUE)) { 1599 return parseCssValue("super"); 1600 } 1601 return parseCssValue(""); 1602 } else if (key == StyleConstants.Subscript) { 1603 if (value.equals(Boolean.TRUE)) { 1604 return parseCssValue("sub"); 1605 } 1606 return parseCssValue(""); 1607 } 1608 return null; 1609 } 1610 1611 1621 Object toStyleConstants(StyleConstants key, View v) { 1622 if (key == StyleConstants.Italic) { 1623 if (svalue.indexOf("italic") >= 0) { 1624 return Boolean.TRUE; 1625 } 1626 return Boolean.FALSE; 1627 } else if (key == StyleConstants.Underline) { 1628 if (svalue.indexOf("underline") >= 0) { 1629 return Boolean.TRUE; 1630 } 1631 return Boolean.FALSE; 1632 } else if (key == StyleConstants.Alignment) { 1633 if (svalue.equals("right")) { 1634 return new Integer (StyleConstants.ALIGN_RIGHT); 1635 } else if (svalue.equals("center")) { 1636 return new Integer (StyleConstants.ALIGN_CENTER); 1637 } else if (svalue.equals("justify")) { 1638 return new Integer (StyleConstants.ALIGN_JUSTIFIED); 1639 } 1640 return new Integer (StyleConstants.ALIGN_LEFT); 1641 } else if (key == StyleConstants.StrikeThrough) { 1642 if (svalue.indexOf("line-through") >= 0) { 1643 return Boolean.TRUE; 1644 } 1645 return Boolean.FALSE; 1646 } else if (key == StyleConstants.Superscript) { 1647 if (svalue.indexOf("super") >= 0) { 1648 return Boolean.TRUE; 1649 } 1650 return Boolean.FALSE; 1651 } else if (key == StyleConstants.Subscript) { 1652 if (svalue.indexOf("sub") >= 0) { 1653 return Boolean.TRUE; 1654 } 1655 return Boolean.FALSE; 1656 } 1657 return null; 1658 } 1659 1660 boolean isItalic() { 1662 return (svalue.indexOf("italic") != -1); 1663 } 1664 1665 boolean isStrike() { 1666 return (svalue.indexOf("line-through") != -1); 1667 } 1668 1669 boolean isUnderline() { 1670 return (svalue.indexOf("underline") != -1); 1671 } 1672 1673 boolean isSub() { 1674 return (svalue.indexOf("sub") != -1); 1675 } 1676 1677 boolean isSup() { 1678 return (svalue.indexOf("sup") != -1); 1679 } 1680 } 1681 1682 1692 class FontSize extends CssValue { 1693 1694 1703 float getValue(AttributeSet a, StyleSheet ss) { 1704 ss = getStyleSheet(ss); 1705 if (index) { 1706 return getPointSize((int) value, ss); 1708 } 1709 else if (lu == null) { 1710 return value; 1711 } 1712 else { 1713 if (lu.type == 0) { 1714 boolean isW3CLengthUnits = (ss == null) ? false : ss.isW3CLengthUnits(); 1715 return lu.getValue(isW3CLengthUnits); 1716 } 1717 if (a != null) { 1718 AttributeSet resolveParent = a.getResolveParent(); 1719 1720 if (resolveParent != null) { 1721 int pValue = StyleConstants.getFontSize(resolveParent); 1722 1723 float retValue; 1724 if (lu.type == 1 || lu.type == 3) { 1725 retValue = lu.value * (float)pValue; 1726 } 1727 else { 1728 retValue = lu.value + (float)pValue; 1729 } 1730 return retValue; 1731 } 1732 } 1733 return 12; 1735 } 1736 } 1737 1738 Object parseCssValue(String value) { 1739 FontSize fs = new FontSize(); 1740 fs.svalue = value; 1741 try { 1742 if (value.equals("xx-small")) { 1743 fs.value = 1; 1744 fs.index = true; 1745 } else if (value.equals("x-small")) { 1746 fs.value = 2; 1747 fs.index = true; 1748 } else if (value.equals("small")) { 1749 fs.value = 3; 1750 fs.index = true; 1751 } else if (value.equals("medium")) { 1752 fs.value = 4; 1753 fs.index = true; 1754 } else if (value.equals("large")) { 1755 fs.value = 5; 1756 fs.index = true; 1757 } else if (value.equals("x-large")) { 1758 fs.value = 6; 1759 fs.index = true; 1760 } else if (value.equals("xx-large")) { 1761 fs.value = 7; 1762 fs.index = true; 1763 } else { 1764 fs.lu = new LengthUnit(value, (short)1, 1f); 1765 } 1766 } catch (NumberFormatException nfe) { 1775 fs = null; 1776 } 1777 return fs; 1778 } 1779 1780 Object parseHtmlValue(String value) { 1781 FontSize fs = new FontSize(); 1782 fs.svalue = value; 1783 1784 try { 1785 1789 int baseFontSize = getBaseFontSize(); 1790 if ((value != null) && (value.charAt(0) == '+')) { 1791 int relSize = Integer.valueOf(value.substring(1)).intValue(); 1792 fs.value = baseFontSize + relSize; 1793 fs.index = true; 1794 } else if ((value != null) && (value.charAt(0) == '-')) { 1795 int relSize = -Integer.valueOf(value.substring(1)).intValue(); 1796 fs.value = baseFontSize + relSize; 1797 fs.index = true; 1798 } else { 1799 fs.value = Integer.parseInt(value); 1800 if (fs.value > 7) { 1801 fs.value = 7; 1802 } else if (fs.value < 0) { 1803 fs.value = 0; 1804 } 1805 fs.index = true; 1806 } 1807 1808 } catch (NumberFormatException nfe) { 1809 fs = null; 1810 } 1811 return fs; 1812 } 1813 1814 1825 Object fromStyleConstants(StyleConstants key, Object value) { 1826 if (value instanceof Number ) { 1827 FontSize fs = new FontSize(); 1828 1829 fs.value = getIndexOfSize(((Number )value).floatValue(), StyleSheet.sizeMapDefault); 1830 fs.svalue = Integer.toString((int)fs.value); 1831 fs.index = true; 1832 return fs; 1833 } 1834 return parseCssValue(value.toString()); 1835 } 1836 1837 1846 Object toStyleConstants(StyleConstants key, View v) { 1847 if (v != null) { 1848 return new Integer ((int) getValue(v.getAttributes(), null)); 1849 } 1850 return new Integer ((int) getValue(null, null)); 1851 } 1852 1853 float value; 1854 boolean index; 1855 LengthUnit lu; 1856 } 1857 1858 static class FontFamily extends CssValue { 1859 1860 1863 String getValue() { 1864 return family; 1865 } 1866 1867 Object parseCssValue(String value) { 1868 int cIndex = value.indexOf(','); 1869 FontFamily ff = new FontFamily(); 1870 ff.svalue = value; 1871 ff.family = null; 1872 1873 if (cIndex == -1) { 1874 setFontName(ff, value); 1875 } 1876 else { 1877 boolean done = false; 1878 int lastIndex; 1879 int length = value.length(); 1880 cIndex = 0; 1881 while (!done) { 1882 while (cIndex < length && 1884 Character.isWhitespace(value.charAt(cIndex))) 1885 cIndex++; 1886 lastIndex = cIndex; 1888 cIndex = value.indexOf(',', cIndex); 1889 if (cIndex == -1) { 1890 cIndex = length; 1891 } 1892 if (lastIndex < length) { 1893 if (lastIndex != cIndex) { 1894 int lastCharIndex = cIndex; 1895 if (cIndex > 0 && value.charAt(cIndex - 1) == ' '){ 1896 lastCharIndex--; 1897 } 1898 setFontName(ff, value.substring 1899 (lastIndex, lastCharIndex)); 1900 done = (ff.family != null); 1901 } 1902 cIndex++; 1903 } 1904 else { 1905 done = true; 1906 } 1907 } 1908 } 1909 if (ff.family == null) { 1910 ff.family = "SansSerif"; 1911 } 1912 return ff; 1913 } 1914 1915 private void setFontName(FontFamily ff, String fontName) { 1916 ff.family = fontName; 1917 } 1918 1919 Object parseHtmlValue(String value) { 1920 return parseCssValue(value); 1922 } 1923 1924 1935 Object fromStyleConstants(StyleConstants key, Object value) { 1936 return parseCssValue(value.toString()); 1937 } 1938 1939 1948 Object toStyleConstants(StyleConstants key, View v) { 1949 return family; 1950 } 1951 1952 String family; 1953 } 1954 1955 static class FontWeight extends CssValue { 1956 1957 int getValue() { 1958 return weight; 1959 } 1960 1961 Object parseCssValue(String value) { 1962 FontWeight fw = new FontWeight(); 1963 fw.svalue = value; 1964 if (value.equals("bold")) { 1965 fw.weight = 700; 1966 } else if (value.equals("normal")) { 1967 fw.weight = 400; 1968 } else { 1969 try { 1971 fw.weight = Integer.parseInt(value); 1972 } catch (NumberFormatException nfe) { 1973 fw = null; 1974 } 1975 } 1976 return fw; 1977 } 1978 1979 1990 Object fromStyleConstants(StyleConstants key, Object value) { 1991 if (value.equals(Boolean.TRUE)) { 1992 return parseCssValue("bold"); 1993 } 1994 return parseCssValue("normal"); 1995 } 1996 1997 2006 Object toStyleConstants(StyleConstants key, View v) { 2007 return (weight > 500) ? Boolean.TRUE : Boolean.FALSE; 2008 } 2009 2010 boolean isBold() { 2011 return (weight > 500); 2012 } 2013 2014 int weight; 2015 } 2016 2017 static class ColorValue extends CssValue { 2018 2019 2022 Color getValue() { 2023 return c; 2024 } 2025 2026 Object parseCssValue(String value) { 2027 2028 Color c = stringToColor(value); 2029 if (c != null) { 2030 ColorValue cv = new ColorValue(); 2031 cv.svalue = value; 2032 cv.c = c; 2033 return cv; 2034 } 2035 return null; 2036 } 2037 2038 Object parseHtmlValue(String value) { 2039 return parseCssValue(value); 2040 } 2041 2042 2053 Object fromStyleConstants(StyleConstants key, Object value) { 2054 ColorValue colorValue = new ColorValue(); 2055 colorValue.c = (Color )value; 2056 colorValue.svalue = colorToHex(colorValue.c); 2057 return colorValue; 2058 } 2059 2060 2069 Object toStyleConstants(StyleConstants key, View v) { 2070 return c; 2071 } 2072 2073 Color c; 2074 } 2075 2076 static class BorderStyle extends CssValue { 2077 2078 CSS.Value getValue() { 2079 return style; 2080 } 2081 2082 Object parseCssValue(String value) { 2083 CSS.Value cssv = CSS.getValue(value); 2084 if (cssv != null) { 2085 if ((cssv == CSS.Value.INSET) || 2086 (cssv == CSS.Value.OUTSET) || 2087 (cssv == CSS.Value.NONE) || 2088 (cssv == CSS.Value.DOTTED) || 2089 (cssv == CSS.Value.DASHED) || 2090 (cssv == CSS.Value.SOLID) || 2091 (cssv == CSS.Value.DOUBLE) || 2092 (cssv == CSS.Value.GROOVE) || 2093 (cssv == CSS.Value.RIDGE)) { 2094 2095 BorderStyle bs = new BorderStyle(); 2096 bs.svalue = value; 2097 bs.style = cssv; 2098 return bs; 2099 } 2100 } 2101 return null; 2102 } 2103 2104 private void writeObject(java.io.ObjectOutputStream s) 2105 throws IOException { 2106 s.defaultWriteObject(); 2107 if (style == null) { 2108 s.writeObject(null); 2109 } 2110 else { 2111 s.writeObject(style.toString()); 2112 } 2113 } 2114 2115 private void readObject(ObjectInputStream s) 2116 throws ClassNotFoundException , IOException { 2117 s.defaultReadObject(); 2118 Object value = s.readObject(); 2119 if (value != null) { 2120 style = CSS.getValue((String )value); 2121 } 2122 } 2123 2124 transient private CSS.Value style; 2126 } 2127 2128 static class LengthValue extends CssValue { 2129 2130 2133 boolean mayBeNegative; 2134 2135 LengthValue() { 2136 this(false); 2137 } 2138 2139 LengthValue(boolean mayBeNegative) { 2140 this.mayBeNegative = mayBeNegative; 2141 } 2142 2143 2146 float getValue() { 2147 return getValue(false); 2148 } 2149 2150 float getValue(boolean isW3CLengthUnits) { 2151 return getValue(0, isW3CLengthUnits); 2152 } 2153 2154 2158 float getValue(float currentValue) { 2159 return getValue(currentValue, false); 2160 } 2161 float getValue(float currentValue, boolean isW3CLengthUnits) { 2162 if (percentage) { 2163 return span * currentValue; 2164 } 2165 return LengthUnit.getValue(span, units, isW3CLengthUnits); 2166 } 2167 2168 2172 boolean isPercentage() { 2173 return percentage; 2174 } 2175 2176 Object parseCssValue(String value) { 2177 LengthValue lv; 2178 try { 2179 float absolute = Float.valueOf(value).floatValue(); 2181 lv = new LengthValue(); 2182 lv.span = absolute; 2183 } catch (NumberFormatException nfe) { 2184 LengthUnit lu = new LengthUnit(value, 2186 LengthUnit.UNINITALIZED_LENGTH, 2187 0); 2188 2189 switch (lu.type) { 2192 case 0: 2193 lv = new LengthValue(); 2195 lv.span = 2196 (mayBeNegative) ? lu.value : Math.max(0, lu.value); 2197 lv.units = lu.units; 2198 break; 2199 case 1: 2200 lv = new LengthValue(); 2202 lv.span = Math.max(0, Math.min(1, lu.value)); 2203 lv.percentage = true; 2204 break; 2205 default: 2206 return null; 2207 } 2208 } 2209 lv.svalue = value; 2210 return lv; 2211 } 2212 2213 Object parseHtmlValue(String value) { 2214 if (value.equals(HTML.NULL_ATTRIBUTE_VALUE)) { 2215 value = "1"; 2216 } 2217 return parseCssValue(value); 2218 } 2219 2230 Object fromStyleConstants(StyleConstants key, Object value) { 2231 LengthValue v = new LengthValue(); 2232 v.svalue = value.toString(); 2233 v.span = ((Float )value).floatValue(); 2234 return v; 2235 } 2236 2237 2246 Object toStyleConstants(StyleConstants key, View v) { 2247 return new Float (getValue(false)); 2248 } 2249 2250 2252 boolean percentage; 2253 2255 float span; 2256 2257 String units = null; 2258 } 2259 2260 2261 2265 static class BorderWidthValue extends LengthValue { 2266 BorderWidthValue(String svalue, int index) { 2267 this.svalue = svalue; 2268 span = values[index]; 2269 percentage = false; 2270 } 2271 2272 Object parseCssValue(String value) { 2273 if (value != null) { 2274 if (value.equals("thick")) { 2275 return new BorderWidthValue(value, 2); 2276 } 2277 else if (value.equals("medium")) { 2278 return new BorderWidthValue(value, 1); 2279 } 2280 else if (value.equals("thin")) { 2281 return new BorderWidthValue(value, 0); 2282 } 2283 } 2284 return super.parseCssValue(value); 2286 } 2287 2288 Object parseHtmlValue(String value) { 2289 if (value == HTML.NULL_ATTRIBUTE_VALUE) { 2290 return parseCssValue("medium"); 2291 } 2292 return parseCssValue(value); 2293 } 2294 2295 2296 private static final float[] values = { 1, 2, 4 }; 2297 } 2298 2299 2300 2304 static class CssValueMapper extends CssValue { 2305 Object parseCssValue(String value) { 2306 Object retValue = cssValueToInternalValueMap.get(value); 2307 if (retValue == null) { 2308 retValue = cssValueToInternalValueMap.get(value.toLowerCase()); 2309 } 2310 return retValue; 2311 } 2312 2313 2314 Object parseHtmlValue(String value) { 2315 Object retValue = htmlValueToCssValueMap.get(value); 2316 if (retValue == null) { 2317 retValue = htmlValueToCssValueMap.get(value.toLowerCase()); 2318 } 2319 return retValue; 2320 } 2321 } 2322 2323 2324 2327 static class BackgroundPosition extends CssValue { 2328 float horizontalPosition; 2329 float verticalPosition; 2330 short relative; 2335 2336 Object parseCssValue(String value) { 2337 String [] strings = CSS.parseStrings(value); 2350 int count = strings.length; 2351 BackgroundPosition bp = new BackgroundPosition(); 2352 bp.relative = 5; 2353 bp.svalue = value; 2354 2355 if (count > 0) { 2356 short found = 0; 2358 int index = 0; 2359 while (index < count) { 2360 String string = strings[index++]; 2362 if (string.equals("center")) { 2363 found |= 4; 2364 continue; 2365 } 2366 else { 2367 if ((found & 1) == 0) { 2368 if (string.equals("top")) { 2369 found |= 1; 2370 } 2371 else if (string.equals("bottom")) { 2372 found |= 1; 2373 bp.verticalPosition = 1; 2374 continue; 2375 } 2376 } 2377 if ((found & 2) == 0) { 2378 if (string.equals("left")) { 2379 found |= 2; 2380 bp.horizontalPosition = 0; 2381 } 2382 else if (string.equals("right")) { 2383 found |= 2; 2384 bp.horizontalPosition = 1; 2385 } 2386 } 2387 } 2388 } 2389 if (found != 0) { 2390 if ((found & 1) == 1) { 2391 if ((found & 2) == 0) { 2392 bp.horizontalPosition = .5f; 2394 } 2395 } 2396 else if ((found & 2) == 2) { 2397 bp.verticalPosition = .5f; 2399 } 2400 else { 2401 bp.horizontalPosition = bp.verticalPosition = .5f; 2403 } 2404 } 2405 else { 2406 LengthUnit lu = new LengthUnit(strings[0], (short)0, 0f); 2408 2409 if (lu.type == 0) { 2410 bp.horizontalPosition = lu.value; 2411 bp.relative = (short)(1 ^ bp.relative); 2412 } 2413 else if (lu.type == 1) { 2414 bp.horizontalPosition = lu.value; 2415 } 2416 else if (lu.type == 3) { 2417 bp.horizontalPosition = lu.value; 2418 bp.relative = (short)((1 ^ bp.relative) | 2); 2419 } 2420 if (count > 1) { 2421 lu = new LengthUnit(strings[1], (short)0, 0f); 2422 2423 if (lu.type == 0) { 2424 bp.verticalPosition = lu.value; 2425 bp.relative = (short)(4 ^ bp.relative); 2426 } 2427 else if (lu.type == 1) { 2428 bp.verticalPosition = lu.value; 2429 } 2430 else if (lu.type == 3) { 2431 bp.verticalPosition = lu.value; 2432 bp.relative = (short)((4 ^ bp.relative) | 8); 2433 } 2434 } 2435 else { 2436 bp.verticalPosition = .5f; 2437 } 2438 } 2439 } 2440 return bp; 2441 } 2442 2443 boolean isHorizontalPositionRelativeToSize() { 2444 return ((relative & 1) == 1); 2445 } 2446 2447 boolean isHorizontalPositionRelativeToFontSize() { 2448 return ((relative & 2) == 2); 2449 } 2450 2451 float getHorizontalPosition() { 2452 return horizontalPosition; 2453 } 2454 2455 boolean isVerticalPositionRelativeToSize() { 2456 return ((relative & 4) == 4); 2457 } 2458 2459 boolean isVerticalPositionRelativeToFontSize() { 2460 return ((relative & 8) == 8); 2461 } 2462 2463 float getVerticalPosition() { 2464 return verticalPosition; 2465 } 2466 } 2467 2468 2469 2472 static class BackgroundImage extends CssValue { 2473 private boolean loadedImage; 2474 private ImageIcon image; 2475 2476 Object parseCssValue(String value) { 2477 BackgroundImage retValue = new BackgroundImage(); 2478 retValue.svalue = value; 2479 return retValue; 2480 } 2481 2482 Object parseHtmlValue(String value) { 2483 return parseCssValue(value); 2484 } 2485 2486 ImageIcon getImage(URL base) { 2488 if (!loadedImage) { 2489 synchronized(this) { 2490 if (!loadedImage) { 2491 URL url = CSS.getURL(base, svalue); 2492 loadedImage = true; 2493 if (url != null) { 2494 image = new ImageIcon (url); 2495 } 2496 } 2497 } 2498 } 2499 return image; 2500 } 2501 } 2502 2503 2507 static class LengthUnit implements Serializable { 2508 static Hashtable lengthMapping = new Hashtable (6); 2509 static Hashtable w3cLengthMapping = new Hashtable (6); 2510 static { 2511 lengthMapping.put("pt", new Float (1f)); 2512 lengthMapping.put("px", new Float (1.3f)); 2514 lengthMapping.put("mm", new Float (2.83464f)); 2515 lengthMapping.put("cm", new Float (28.3464f)); 2516 lengthMapping.put("pc", new Float (12f)); 2517 lengthMapping.put("in", new Float (72f)); 2518 int res = 72; 2519 try { 2520 res = Toolkit.getDefaultToolkit().getScreenResolution(); 2521 } catch (HeadlessException e) { 2522 } 2523 w3cLengthMapping.put("pt", new Float (res/72f)); 2525 w3cLengthMapping.put("px", new Float (1f)); 2526 w3cLengthMapping.put("mm", new Float (res/25.4f)); 2527 w3cLengthMapping.put("cm", new Float (res/2.54f)); 2528 w3cLengthMapping.put("pc", new Float (res/6f)); 2529 w3cLengthMapping.put("in", new Float (res)); 2530 } 2531 2532 LengthUnit(String value, short defaultType, float defaultValue) { 2533 parse(value, defaultType, defaultValue); 2534 } 2535 2536 void parse(String value, short defaultType, float defaultValue) { 2537 type = defaultType; 2538 this.value = defaultValue; 2539 2540 int length = value.length(); 2541 if (length > 0 && value.charAt(length - 1) == '%') { 2542 try { 2543 this.value = Float.valueOf(value.substring(0, length - 1)). 2544 floatValue() / 100.0f; 2545 type = 1; 2546 } 2547 catch (NumberFormatException nfe) { } 2548 } 2549 if (length >= 2) { 2550 units = value.substring(length - 2, length); 2551 Float scale = (Float )lengthMapping.get(units); 2552 if (scale != null) { 2553 try { 2554 this.value = Float.valueOf(value.substring(0, 2555 length - 2)).floatValue(); 2556 type = 0; 2557 } 2558 catch (NumberFormatException nfe) { } 2559 } 2560 else if (units.equals("em") || 2561 units.equals("ex")) { 2562 try { 2563 this.value = Float.valueOf(value.substring(0, 2564 length - 2)).floatValue(); 2565 type = 3; 2566 } 2567 catch (NumberFormatException nfe) { } 2568 } 2569 else if (value.equals("larger")) { 2570 this.value = 2f; 2571 type = 2; 2572 } 2573 else if (value.equals("smaller")) { 2574 this.value = -2; 2575 type = 2; 2576 } 2577 else { 2578 try { 2580 this.value = Float.valueOf(value).floatValue(); 2581 type = 0; 2582 } catch (NumberFormatException nfe) {} 2583 } 2584 } 2585 else if (length > 0) { 2586 try { 2588 this.value = Float.valueOf(value).floatValue(); 2589 type = 0; 2590 } catch (NumberFormatException nfe) {} 2591 } 2592 } 2593 2594 float getValue(boolean w3cLengthUnits) { 2595 Hashtable mapping = (w3cLengthUnits) ? w3cLengthMapping : lengthMapping; 2596 float scale = 1; 2597 if (units != null) { 2598 Float scaleFloat = (Float )mapping.get(units); 2599 if (scaleFloat != null) { 2600 scale = scaleFloat.floatValue(); 2601 } 2602 } 2603 return this.value * scale; 2604 2605 } 2606 2607 static float getValue(float value, String units, Boolean w3cLengthUnits) { 2608 Hashtable mapping = (w3cLengthUnits) ? w3cLengthMapping : lengthMapping; 2609 float scale = 1; 2610 if (units != null) { 2611 Float scaleFloat = (Float )mapping.get(units); 2612 if (scaleFloat != null) { 2613 scale = scaleFloat.floatValue(); 2614 } 2615 } 2616 return value * scale; 2617 } 2618 2619 public String toString() { 2620 return type + " " + value; 2621 } 2622 2623 short type; 2630 float value; 2631 String units = null; 2632 2633 2634 static final short UNINITALIZED_LENGTH = (short)10; 2635 } 2636 2637 2638 2643 static class ShorthandFontParser { 2644 2648 static void parseShorthandFont(CSS css, String value, 2649 MutableAttributeSet attr) { 2650 String [] strings = CSS.parseStrings(value); 2654 int count = strings.length; 2655 int index = 0; 2656 short found = 0; 2658 int maxC = Math.min(3, count); 2659 2660 while (index < maxC) { 2662 if ((found & 1) == 0 && isFontStyle(strings[index])) { 2663 css.addInternalCSSValue(attr, CSS.Attribute.FONT_STYLE, 2664 strings[index++]); 2665 found |= 1; 2666 } 2667 else if ((found & 2) == 0 && isFontVariant(strings[index])) { 2668 css.addInternalCSSValue(attr, CSS.Attribute.FONT_VARIANT, 2669 strings[index++]); 2670 found |= 2; 2671 } 2672 else if ((found & 4) == 0 && isFontWeight(strings[index])) { 2673 css.addInternalCSSValue(attr, CSS.Attribute.FONT_WEIGHT, 2674 strings[index++]); 2675 found |= 4; 2676 } 2677 else if (strings[index].equals("normal")) { 2678 index++; 2679 } 2680 else { 2681 break; 2682 } 2683 } 2684 if ((found & 1) == 0) { 2685 css.addInternalCSSValue(attr, CSS.Attribute.FONT_STYLE, 2686 "normal"); 2687 } 2688 if ((found & 2) == 0) { 2689 css.addInternalCSSValue(attr, CSS.Attribute.FONT_VARIANT, 2690 "normal"); 2691 } 2692 if ((found & 4) == 0) { 2693 css.addInternalCSSValue(attr, CSS.Attribute.FONT_WEIGHT, 2694 "normal"); 2695 } 2696 2697 if (index < count) { 2699 String fontSize = strings[index]; 2700 int slashIndex = fontSize.indexOf('/'); 2701 2702 if (slashIndex != -1) { 2703 fontSize = fontSize.substring(0, slashIndex); 2704 strings[index] = strings[index].substring(slashIndex); 2705 } 2706 else { 2707 index++; 2708 } 2709 css.addInternalCSSValue(attr, CSS.Attribute.FONT_SIZE, 2710 fontSize); 2711 } 2712 else { 2713 css.addInternalCSSValue(attr, CSS.Attribute.FONT_SIZE, 2714 "medium"); 2715 } 2716 2717 if (index < count && strings[index].startsWith("/")) { 2719 String lineHeight = null; 2720 if (strings[index].equals("/")) { 2721 if (++index < count) { 2722 lineHeight = strings[index++]; 2723 } 2724 } 2725 else { 2726 lineHeight = strings[index++].substring(1); 2727 } 2728 if (lineHeight != null) { 2730 css.addInternalCSSValue(attr, CSS.Attribute.LINE_HEIGHT, 2731 lineHeight); 2732 } 2733 else { 2734 css.addInternalCSSValue(attr, CSS.Attribute.LINE_HEIGHT, 2735 "normal"); 2736 } 2737 } 2738 else { 2739 css.addInternalCSSValue(attr, CSS.Attribute.LINE_HEIGHT, 2740 "normal"); 2741 } 2742 2743 if (index < count) { 2745 String family = strings[index++]; 2746 2747 while (index < count) { 2748 family += " " + strings[index++]; 2749 } 2750 css.addInternalCSSValue(attr, CSS.Attribute.FONT_FAMILY, 2751 family); 2752 } 2753 else { 2754 css.addInternalCSSValue(attr, CSS.Attribute.FONT_FAMILY, 2755 "SansSerif"); 2756 } 2757 } 2758 2759 private static boolean isFontStyle(String string) { 2760 return (string.equals("italic") || 2761 string.equals("oblique")); 2762 } 2763 2764 private static boolean isFontVariant(String string) { 2765 return (string.equals("small-caps")); 2766 } 2767 2768 private static boolean isFontWeight(String string) { 2769 if (string.equals("bold") || string.equals("bolder") || 2770 string.equals("italic") || string.equals("lighter")) { 2771 return true; 2772 } 2773 return (string.length() == 3 && 2775 string.charAt(0) >= '1' && string.charAt(0) <= '9' && 2776 string.charAt(1) == '0' && string.charAt(2) == '0'); 2777 } 2778 2779 } 2780 2781 2782 2785 static class ShorthandBackgroundParser { 2786 2790 static void parseShorthandBackground(CSS css, String value, 2791 MutableAttributeSet attr) { 2792 String [] strings = parseStrings(value); 2793 int count = strings.length; 2794 int index = 0; 2795 short found = 0; 2798 2799 while (index < count) { 2800 String string = strings[index++]; 2801 if ((found & 1) == 0 && isImage(string)) { 2802 css.addInternalCSSValue(attr, CSS.Attribute. 2803 BACKGROUND_IMAGE, string); 2804 found |= 1; 2805 } 2806 else if ((found & 2) == 0 && isRepeat(string)) { 2807 css.addInternalCSSValue(attr, CSS.Attribute. 2808 BACKGROUND_REPEAT, string); 2809 found |= 2; 2810 } 2811 else if ((found & 4) == 0 && isAttachment(string)) { 2812 css.addInternalCSSValue(attr, CSS.Attribute. 2813 BACKGROUND_ATTACHMENT, string); 2814 found |= 4; 2815 } 2816 else if ((found & 8) == 0 && isPosition(string)) { 2817 if (index < count && isPosition(strings[index])) { 2818 css.addInternalCSSValue(attr, CSS.Attribute. 2819 BACKGROUND_POSITION, 2820 string + " " + 2821 strings[index++]); 2822 } 2823 else { 2824 css.addInternalCSSValue(attr, CSS.Attribute. 2825 BACKGROUND_POSITION, string); 2826 } 2827 found |= 8; 2828 } 2829 else if ((found & 16) == 0 && isColor(string)) { 2830 css.addInternalCSSValue(attr, CSS.Attribute. 2831 BACKGROUND_COLOR, string); 2832 found |= 16; 2833 } 2834 } 2835 if ((found & 1) == 0) { 2836 css.addInternalCSSValue(attr, CSS.Attribute.BACKGROUND_IMAGE, 2837 null); 2838 } 2839 if ((found & 2) == 0) { 2840 css.addInternalCSSValue(attr, CSS.Attribute.BACKGROUND_REPEAT, 2841 "repeat"); 2842 } 2843 if ((found & 4) == 0) { 2844 css.addInternalCSSValue(attr, CSS.Attribute. 2845 BACKGROUND_ATTACHMENT, "scroll"); 2846 } 2847 if ((found & 8) == 0) { 2848 css.addInternalCSSValue(attr, CSS.Attribute. 2849 BACKGROUND_POSITION, null); 2850 } 2851 2858 } 2859 2860 static boolean isImage(String string) { 2861 return (string.startsWith("url(") && string.endsWith(")")); 2862 } 2863 2864 static boolean isRepeat(String string) { 2865 return (string.equals("repeat-x") || string.equals("repeat-y") || 2866 string.equals("repeat") || string.equals("no-repeat")); 2867 } 2868 2869 static boolean isAttachment(String string) { 2870 return (string.equals("fixed") || string.equals("scroll")); 2871 } 2872 2873 static boolean isPosition(String string) { 2874 return (string.equals("top") || string.equals("bottom") || 2875 string.equals("left") || string.equals("right") || 2876 string.equals("center") || 2877 (string.length() > 0 && 2878 Character.isDigit(string.charAt(0)))); 2879 } 2880 2881 static boolean isColor(String string) { 2882 return (CSS.stringToColor(string) != null); 2883 } 2884 } 2885 2886 2887 2890 static class ShorthandMarginParser { 2891 2896 static void parseShorthandMargin(CSS css, String value, 2897 MutableAttributeSet attr, 2898 CSS.Attribute [] names) { 2899 String [] strings = parseStrings(value); 2900 int count = strings.length; 2901 int index = 0; 2902 switch (count) { 2903 case 0: 2904 return; 2906 case 1: 2907 for (int counter = 0; counter < 4; counter++) { 2909 css.addInternalCSSValue(attr, names[counter], strings[0]); 2910 } 2911 break; 2912 case 2: 2913 css.addInternalCSSValue(attr, names[0], strings[0]); 2915 css.addInternalCSSValue(attr, names[2], strings[0]); 2916 css.addInternalCSSValue(attr, names[1], strings[1]); 2917 css.addInternalCSSValue(attr, names[3], strings[1]); 2918 break; 2919 case 3: 2920 css.addInternalCSSValue(attr, names[0], strings[0]); 2921 css.addInternalCSSValue(attr, names[1], strings[1]); 2922 css.addInternalCSSValue(attr, names[2], strings[2]); 2923 css.addInternalCSSValue(attr, names[3], strings[1]); 2924 break; 2925 default: 2926 for (int counter = 0; counter < 4; counter++) { 2927 css.addInternalCSSValue(attr, names[counter], 2928 strings[counter]); 2929 } 2930 break; 2931 } 2932 } 2933 } 2934 2935 2940 static SizeRequirements calculateTiledRequirements(LayoutIterator iter, SizeRequirements r) { 2941 long minimum = 0; 2942 long maximum = 0; 2943 long preferred = 0; 2944 int lastMargin = 0; 2945 int totalSpacing = 0; 2946 int n = iter.getCount(); 2947 for (int i = 0; i < n; i++) { 2948 iter.setIndex(i); 2949 int margin0 = lastMargin; 2950 int margin1 = (int) iter.getLeadingCollapseSpan(); 2951 totalSpacing += Math.max(margin0, margin1);; 2952 preferred += (int) iter.getPreferredSpan(0); 2953 minimum += iter.getMinimumSpan(0); 2954 maximum += iter.getMaximumSpan(0); 2955 2956 lastMargin = (int) iter.getTrailingCollapseSpan(); 2957 } 2958 totalSpacing += lastMargin; 2959 totalSpacing += 2 * iter.getBorderWidth(); 2960 2961 minimum += totalSpacing; 2963 preferred += totalSpacing; 2964 maximum += totalSpacing; 2965 2966 if (r == null) { 2968 r = new SizeRequirements (); 2969 } 2970 r.minimum = (minimum > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)minimum; 2971 r.preferred = (preferred > Integer.MAX_VALUE) ? Integer.MAX_VALUE :(int) preferred; 2972 r.maximum = (maximum > Integer.MAX_VALUE) ? Integer.MAX_VALUE :(int) maximum; 2973 return r; 2974 } 2975 2976 2982 static void calculateTiledLayout(LayoutIterator iter, int targetSpan) { 2983 2984 2988 long preferred = 0; 2989 long currentPreferred = 0; 2990 int lastMargin = 0; 2991 int totalSpacing = 0; 2992 int n = iter.getCount(); 2993 int adjustmentWeightsCount = LayoutIterator.WorstAdjustmentWeight + 1; 2994 long gain[] = new long[adjustmentWeightsCount]; 2996 long loss[] = new long[adjustmentWeightsCount]; 2998 2999 for (int i = 0; i < adjustmentWeightsCount; i++) { 3000 gain[i] = loss[i] = 0; 3001 } 3002 for (int i = 0; i < n; i++) { 3003 iter.setIndex(i); 3004 int margin0 = lastMargin; 3005 int margin1 = (int) iter.getLeadingCollapseSpan(); 3006 3007 iter.setOffset(Math.max(margin0, margin1)); 3008 totalSpacing += iter.getOffset(); 3009 3010 currentPreferred = (long)iter.getPreferredSpan(targetSpan); 3011 iter.setSpan((int) currentPreferred); 3012 preferred += currentPreferred; 3013 gain[iter.getAdjustmentWeight()] += 3014 (long)iter.getMaximumSpan(targetSpan) - currentPreferred; 3015 loss[iter.getAdjustmentWeight()] += 3016 currentPreferred - (long)iter.getMinimumSpan(targetSpan); 3017 lastMargin = (int) iter.getTrailingCollapseSpan(); 3018 } 3019 totalSpacing += lastMargin; 3020 totalSpacing += 2 * iter.getBorderWidth(); 3021 3022 for (int i = 1; i < adjustmentWeightsCount; i++) { 3023 gain[i] += gain[i - 1]; 3024 loss[i] += loss[i - 1]; 3025 } 3026 3027 3032 3033 int allocated = targetSpan - totalSpacing; 3035 long desiredAdjustment = allocated - preferred; 3036 long adjustmentsArray[] = (desiredAdjustment > 0) ? gain : loss; 3037 desiredAdjustment = Math.abs(desiredAdjustment); 3038 int adjustmentLevel = 0; 3039 for (;adjustmentLevel <= LayoutIterator.WorstAdjustmentWeight; 3040 adjustmentLevel++) { 3041 if (adjustmentsArray[adjustmentLevel] >= desiredAdjustment) { 3044 break; 3045 } 3046 } 3047 float adjustmentFactor = 0.0f; 3048 if (adjustmentLevel <= LayoutIterator.WorstAdjustmentWeight) { 3049 desiredAdjustment -= (adjustmentLevel > 0) ? 3050 adjustmentsArray[adjustmentLevel - 1] : 0; 3051 if (desiredAdjustment != 0) { 3052 float maximumAdjustment = 3053 adjustmentsArray[adjustmentLevel] - 3054 ((adjustmentLevel > 0) ? 3055 adjustmentsArray[adjustmentLevel - 1] : 0 3056 ); 3057 adjustmentFactor = desiredAdjustment / maximumAdjustment; 3058 } 3059 } 3060 int totalOffset = (int)iter.getBorderWidth();; 3062 for (int i = 0; i < n; i++) { 3063 iter.setIndex(i); 3064 iter.setOffset( iter.getOffset() + totalOffset); 3065 if (iter.getAdjustmentWeight() < adjustmentLevel) { 3066 iter.setSpan((int) 3067 ((allocated > preferred) ? 3068 Math.floor(iter.getMaximumSpan(targetSpan)) : 3069 Math.ceil(iter.getMinimumSpan(targetSpan)) 3070 ) 3071 ); 3072 } else if (iter.getAdjustmentWeight() == adjustmentLevel) { 3073 int availableSpan = (allocated > preferred) ? 3074 (int) iter.getMaximumSpan(targetSpan) - iter.getSpan() : 3075 iter.getSpan() - (int) iter.getMinimumSpan(targetSpan); 3076 int adj = (int)Math.floor(adjustmentFactor * availableSpan); 3077 iter.setSpan(iter.getSpan() + 3078 ((allocated > preferred) ? adj : -adj)); 3079 } 3080 totalOffset = (int) Math.min((long) iter.getOffset() + 3081 (long) iter.getSpan(), 3082 Integer.MAX_VALUE); 3083 } 3084 3085 int roundError = targetSpan - totalOffset - 3087 (int)iter.getTrailingCollapseSpan() - 3088 (int)iter.getBorderWidth(); 3089 int adj = (roundError > 0) ? 1 : -1; 3090 roundError *= adj; 3091 3092 boolean canAdjust = true; 3093 while (roundError > 0 && canAdjust) { 3094 canAdjust = false; 3096 int offsetAdjust = 0; 3097 for (int i = 0; i < n; i++) { 3099 iter.setIndex(i); 3100 iter.setOffset(iter.getOffset() + offsetAdjust); 3101 int curSpan = iter.getSpan(); 3102 if (roundError > 0) { 3103 int boundGap = (adj > 0) ? 3104 (int)Math.floor(iter.getMaximumSpan(targetSpan)) - curSpan : 3105 curSpan - (int)Math.ceil(iter.getMinimumSpan(targetSpan)); 3106 if (boundGap >= 1) { 3107 canAdjust = true; 3108 iter.setSpan(curSpan + adj); 3109 offsetAdjust += adj; 3110 roundError--; 3111 } 3112 } 3113 } 3114 } 3115 } 3116 3117 3121 interface LayoutIterator { 3122 3123 void setOffset(int offs); 3124 3125 int getOffset(); 3126 3127 void setSpan(int span); 3128 3129 int getSpan(); 3130 3131 int getCount(); 3132 3133 void setIndex(int i); 3134 3135 float getMinimumSpan(float parentSpan); 3136 3137 float getPreferredSpan(float parentSpan); 3138 3139 float getMaximumSpan(float parentSpan); 3140 3141 int getAdjustmentWeight(); 3143 3145 float getBorderWidth(); 3146 3147 float getLeadingCollapseSpan(); 3148 3149 float getTrailingCollapseSpan(); 3150 public static final int WorstAdjustmentWeight = 2; 3151 } 3152 3153 3157 private void writeObject(java.io.ObjectOutputStream s) 3158 throws IOException 3159 { 3160 s.defaultWriteObject(); 3161 3162 Enumeration keys = valueConvertor.keys(); 3164 s.writeInt(valueConvertor.size()); 3165 if (keys != null) { 3166 while (keys.hasMoreElements()) { 3167 Object key = keys.nextElement(); 3168 Object value = valueConvertor.get(key); 3169 if (!(key instanceof Serializable) && 3170 (key = StyleContext.getStaticAttributeKey(key)) == null) { 3171 key = null; 3173 value = null; 3174 } 3175 else if (!(value instanceof Serializable) && 3176 (value = StyleContext.getStaticAttributeKey(value)) == null){ 3177 key = null; 3179 value = null; 3180 } 3181 s.writeObject(key); 3182 s.writeObject(value); 3183 } 3184 } 3185 } 3186 3187 private void readObject(ObjectInputStream s) 3188 throws ClassNotFoundException , IOException 3189 { 3190 s.defaultReadObject(); 3191 int numValues = s.readInt(); 3193 valueConvertor = new Hashtable (Math.max(1, numValues)); 3194 while (numValues-- > 0) { 3195 Object key = s.readObject(); 3196 Object value = s.readObject(); 3197 Object staticKey = StyleContext.getStaticAttribute(key); 3198 if (staticKey != null) { 3199 key = staticKey; 3200 } 3201 Object staticValue = StyleContext.getStaticAttribute(value); 3202 if (staticValue != null) { 3203 value = staticValue; 3204 } 3205 if (key != null && value != null) { 3206 valueConvertor.put(key, value); 3207 } 3208 } 3209 } 3210 3211 3212 3223 private StyleSheet getStyleSheet(StyleSheet ss) { 3224 if (ss != null) { 3225 styleSheet = ss; 3226 } 3227 return styleSheet; 3228 } 3229 3233 3234 private transient Hashtable valueConvertor; 3235 3236 3237 private int baseFontSize; 3238 3239 private transient StyleSheet styleSheet = null; 3240 3241 static int baseFontSizeIndex = 3; 3242} 3243 | Popular Tags |