1 18 package org.apache.batik.css.engine; 19 20 import java.io.IOException ; 21 import java.io.StringReader ; 22 import java.net.MalformedURLException ; 23 import java.net.URL ; 24 import java.util.ArrayList ; 25 import java.util.Collections ; 26 import java.util.HashSet ; 27 import java.util.LinkedList ; 28 import java.util.List ; 29 import java.util.Set ; 30 31 import org.apache.batik.css.engine.sac.CSSConditionFactory; 32 import org.apache.batik.css.engine.sac.CSSSelectorFactory; 33 import org.apache.batik.css.engine.sac.ExtendedSelector; 34 import org.apache.batik.css.engine.value.ComputedValue; 35 import org.apache.batik.css.engine.value.InheritValue; 36 import org.apache.batik.css.engine.value.ShorthandManager; 37 import org.apache.batik.css.engine.value.Value; 38 import org.apache.batik.css.engine.value.ValueManager; 39 import org.apache.batik.css.parser.ExtendedParser; 40 import org.apache.batik.util.CSSConstants; 41 import org.apache.batik.util.ParsedURL; 42 import org.w3c.css.sac.CSSException; 43 import org.w3c.css.sac.DocumentHandler; 44 import org.w3c.css.sac.InputSource; 45 import org.w3c.css.sac.LexicalUnit; 46 import org.w3c.css.sac.SACMediaList; 47 import org.w3c.css.sac.SelectorList; 48 import org.w3c.dom.DOMException ; 49 import org.w3c.dom.Document ; 50 import org.w3c.dom.Element ; 51 import org.w3c.dom.NamedNodeMap ; 52 import org.w3c.dom.Node ; 53 import org.w3c.dom.events.Event ; 54 import org.w3c.dom.events.EventListener ; 55 import org.w3c.dom.events.EventTarget ; 56 import org.w3c.dom.events.MutationEvent ; 57 58 64 public abstract class CSSEngine { 65 66 70 protected List fontFaces = new LinkedList (); 71 72 76 public List getFontFaces() { return fontFaces; } 77 78 CSSEngineUserAgent userAgent = null; 79 80 83 public static CSSStylableElement getParentCSSStylableElement(Element elt) { 84 Element e = getParentElement(elt); 85 while (e != null) { 86 if (e instanceof CSSStylableElement) { 87 return (CSSStylableElement)e; 88 } 89 e = getParentElement(e); 90 } 91 return null; 92 } 93 94 98 public static Element getParentElement(Element elt) { 99 Node n = elt.getParentNode(); 100 while (n != null) { 101 n = getLogicalParentNode(n); 102 if (n.getNodeType() == Node.ELEMENT_NODE) { 103 return (Element )n; 104 } 105 n = n.getParentNode(); 106 } 107 return null; 108 } 109 110 113 public static Node getLogicalParentNode(Node parent) { 114 Node node = parent; 115 if (node != null) { 116 if (node instanceof CSSImportedElementRoot) { 117 return ((CSSImportedElementRoot)node).getCSSParentElement(); 118 } else { 119 return node; 120 } 121 } 122 return null; 123 } 124 125 128 public static CSSImportedElementRoot getImportedChild(Node node) { 129 if (node instanceof CSSImportNode) { 130 CSSImportNode inode = (CSSImportNode)node; 131 CSSImportedElementRoot r = inode.getCSSImportedElementRoot(); 132 return r; 133 } 134 return null; 135 } 136 137 140 protected CSSContext cssContext; 141 142 145 protected Document document; 146 147 150 protected URL documentURI; 151 152 155 protected StringIntMap indexes; 156 157 160 protected StringIntMap shorthandIndexes; 161 162 165 protected ValueManager[] valueManagers; 166 167 170 protected ShorthandManager[] shorthandManagers; 171 172 175 protected ExtendedParser parser; 176 177 180 protected String [] pseudoElementNames; 181 182 185 protected int fontSizeIndex = -1; 186 187 190 protected int lineHeightIndex = -1; 191 192 195 protected int colorIndex = -1; 196 197 200 protected StyleSheet userAgentStyleSheet; 201 202 205 protected StyleSheet userStyleSheet; 206 207 210 protected SACMediaList media; 211 212 215 protected List styleSheetNodes; 216 217 220 protected String styleNamespaceURI; 221 222 225 protected String styleLocalName; 226 227 230 protected String classNamespaceURI; 231 232 235 protected String classLocalName; 236 237 240 protected Set nonCSSPresentationalHints; 241 242 245 protected String nonCSSPresentationalHintsNamespaceURI; 246 247 250 protected StyleDeclarationDocumentHandler styleDeclarationDocumentHandler = 251 new StyleDeclarationDocumentHandler(); 252 253 256 protected StyleDeclarationUpdateHandler styleDeclarationUpdateHandler; 257 258 261 protected StyleSheetDocumentHandler styleSheetDocumentHandler = 262 new StyleSheetDocumentHandler(); 263 264 268 protected StyleDeclarationBuilder styleDeclarationBuilder = 269 new StyleDeclarationBuilder(); 270 271 274 protected CSSStylableElement element; 275 276 279 protected URL cssBaseURI; 280 281 284 protected String alternateStyleSheet; 285 286 289 protected EventListener domAttrModifiedListener; 290 291 294 protected EventListener domNodeInsertedListener; 295 296 299 protected EventListener domNodeRemovedListener; 300 301 304 protected EventListener domSubtreeModifiedListener; 305 306 309 protected EventListener domCharacterDataModifiedListener; 310 311 314 protected boolean styleSheetRemoved; 315 316 319 protected Node removedStylableElementSibling; 320 321 324 protected List listeners = Collections.synchronizedList(new LinkedList ()); 325 326 329 protected Set selectorAttributes; 330 331 334 protected final int[] ALL_PROPERTIES; 335 336 339 protected CSSConditionFactory cssConditionFactory; 340 341 360 protected CSSEngine(Document doc, 361 URL uri, 362 ExtendedParser p, 363 ValueManager[] vm, 364 ShorthandManager[] sm, 365 String [] pe, 366 String sns, 367 String sln, 368 String cns, 369 String cln, 370 boolean hints, 371 String hintsNS, 372 CSSContext ctx) { 373 document = doc; 374 documentURI = uri; 375 parser = p; 376 pseudoElementNames = pe; 377 styleNamespaceURI = sns; 378 styleLocalName = sln; 379 classNamespaceURI = cns; 380 classLocalName = cln; 381 cssContext = ctx; 382 383 cssConditionFactory = new CSSConditionFactory(cns, cln, null, "id"); 384 385 int len = vm.length; 386 indexes = new StringIntMap(len); 387 valueManagers = vm; 388 389 for (int i = len - 1; i >= 0; --i) { 390 String pn = vm[i].getPropertyName(); 391 indexes.put(pn, i); 392 if (fontSizeIndex == -1 && 393 pn.equals(CSSConstants.CSS_FONT_SIZE_PROPERTY)) { 394 fontSizeIndex = i; 395 } 396 if (lineHeightIndex == -1 && 397 pn.equals(CSSConstants.CSS_LINE_HEIGHT_PROPERTY)) { 398 lineHeightIndex = i; 399 } 400 if (colorIndex == -1 && 401 pn.equals(CSSConstants.CSS_COLOR_PROPERTY)) { 402 colorIndex = i; 403 } 404 } 405 406 len = sm.length; 407 shorthandIndexes = new StringIntMap(len); 408 shorthandManagers = sm; 409 for (int i = len - 1; i >= 0; --i) { 410 shorthandIndexes.put(sm[i].getPropertyName(), i); 411 } 412 413 if (hints) { 414 nonCSSPresentationalHints = new HashSet (vm.length+sm.length); 415 nonCSSPresentationalHintsNamespaceURI = hintsNS; 416 len = vm.length; 417 for (int i = 0; i < len; i++) { 418 String pn = vm[i].getPropertyName(); 419 nonCSSPresentationalHints.add(pn); 420 } 421 len = sm.length; 422 for (int i = 0; i < len; i++) { 423 String pn = sm[i].getPropertyName(); 424 nonCSSPresentationalHints.add(pn); 425 } 426 } 427 428 if (cssContext.isDynamic() && 429 (document instanceof EventTarget )) { 430 EventTarget et = (EventTarget )document; 432 domAttrModifiedListener = new DOMAttrModifiedListener(); 433 et.addEventListener("DOMAttrModified", 434 domAttrModifiedListener, 435 false); 436 domNodeInsertedListener = new DOMNodeInsertedListener(); 437 et.addEventListener("DOMNodeInserted", 438 domNodeInsertedListener, 439 false); 440 domNodeRemovedListener = new DOMNodeRemovedListener(); 441 et.addEventListener("DOMNodeRemoved", 442 domNodeRemovedListener, 443 false); 444 domSubtreeModifiedListener = new DOMSubtreeModifiedListener(); 445 et.addEventListener("DOMSubtreeModified", 446 domSubtreeModifiedListener, 447 false); 448 domCharacterDataModifiedListener = 449 new DOMCharacterDataModifiedListener(); 450 et.addEventListener("DOMCharacterDataModified", 451 domCharacterDataModifiedListener, 452 false); 453 styleDeclarationUpdateHandler = 454 new StyleDeclarationUpdateHandler(); 455 } 456 457 ALL_PROPERTIES = new int[getNumberOfProperties()]; 458 for (int i = getNumberOfProperties() - 1; i >= 0; --i) { 459 ALL_PROPERTIES[i] = i; 460 } 461 } 462 463 466 public void dispose() { 467 setCSSEngineUserAgent(null); 468 disposeStyleMaps(document.getDocumentElement()); 469 if (document instanceof EventTarget ) { 470 EventTarget et = (EventTarget )document; 472 et.removeEventListener("DOMAttrModified", 473 domAttrModifiedListener, 474 false); 475 et.removeEventListener("DOMNodeInserted", 476 domNodeInsertedListener, 477 false); 478 et.removeEventListener("DOMNodeRemoved", 479 domNodeRemovedListener, 480 false); 481 et.removeEventListener("DOMSubtreeModified", 482 domSubtreeModifiedListener, 483 false); 484 et.removeEventListener("DOMCharacterDataModified", 485 domCharacterDataModifiedListener, 486 false); 487 } 488 } 489 490 private void disposeStyleMaps(Node node) { 491 if (node instanceof CSSStylableElement) { 492 ((CSSStylableElement)node).setComputedStyleMap(null, null); 493 } 494 for (Node n = node.getFirstChild(); 495 n != null; 496 n = n.getNextSibling()) { 497 if (n.getNodeType() == Node.ELEMENT_NODE) { 498 disposeStyleMaps(n); 499 } 500 Node c = getImportedChild(n); 501 if (c != null) { 502 disposeStyleMaps(c); 503 } 504 } 505 } 506 507 510 public CSSContext getCSSContext() { 511 return cssContext; 512 } 513 514 517 public Document getDocument() { 518 return document; 519 } 520 521 524 public int getFontSizeIndex() { 525 return fontSizeIndex; 526 } 527 528 531 public int getLineHeightIndex() { 532 return lineHeightIndex; 533 } 534 535 538 public int getColorIndex() { 539 return colorIndex; 540 } 541 542 545 public int getNumberOfProperties() { 546 return valueManagers.length; 547 } 548 549 552 public int getPropertyIndex(String name) { 553 return indexes.get(name); 554 } 555 556 559 public int getShorthandIndex(String name) { 560 return shorthandIndexes.get(name); 561 } 562 563 566 public String getPropertyName(int idx) { 567 return valueManagers[idx].getPropertyName(); 568 } 569 570 public void setCSSEngineUserAgent(CSSEngineUserAgent userAgent) { 571 this.userAgent = userAgent; 572 } 573 574 public CSSEngineUserAgent getCSSEngineUserAgent() { 575 return userAgent; 576 } 577 578 581 public void setUserAgentStyleSheet(StyleSheet ss) { 582 userAgentStyleSheet = ss; 583 } 584 585 588 public void setUserStyleSheet(StyleSheet ss) { 589 userStyleSheet = ss; 590 } 591 592 595 public ValueManager[] getValueManagers() { 596 return valueManagers; 597 } 598 599 602 public void setMedia(String str) { 603 try { 604 media = parser.parseMedia(str); 605 } catch (Exception e) { 606 String m = e.getMessage(); 607 if (m == null) m = ""; 608 String s =Messages.formatMessage 609 ("media.error", new Object [] { str, m }); 610 throw new DOMException (DOMException.SYNTAX_ERR, s); 611 } 612 } 613 614 617 public void setAlternateStyleSheet(String str) { 618 alternateStyleSheet = str; 619 } 620 621 625 public void importCascadedStyleMaps(Element src, 626 CSSEngine srceng, 627 Element dest) { 628 if (src instanceof CSSStylableElement) { 629 CSSStylableElement csrc = (CSSStylableElement)src; 630 CSSStylableElement cdest = (CSSStylableElement)dest; 631 632 StyleMap sm = srceng.getCascadedStyleMap(csrc, null); 633 sm.setFixedCascadedStyle(true); 634 cdest.setComputedStyleMap(null, sm); 635 636 if (pseudoElementNames != null) { 637 int len = pseudoElementNames.length; 638 for (int i = 0; i < len; i++) { 639 String pe = pseudoElementNames[i]; 640 sm = srceng.getCascadedStyleMap(csrc, pe); 641 cdest.setComputedStyleMap(pe, sm); 642 } 643 } 644 } 645 646 for (Node dn = dest.getFirstChild(), sn = src.getFirstChild(); 647 dn != null; 648 dn = dn.getNextSibling(), sn = sn.getNextSibling()) { 649 if (sn.getNodeType() == Node.ELEMENT_NODE) { 650 importCascadedStyleMaps((Element )sn, srceng, (Element )dn); 651 } 652 } 653 } 654 655 658 public URL getCSSBaseURI() { 659 if (cssBaseURI == null) { 660 cssBaseURI = element.getCSSBase(); 661 } 662 return cssBaseURI; 663 } 664 665 670 public StyleMap getCascadedStyleMap(CSSStylableElement elt, 671 String pseudo) { 672 int props = getNumberOfProperties(); 673 final StyleMap result = new StyleMap(props); 674 675 if (userAgentStyleSheet != null) { 677 List rules = new ArrayList (); 678 addMatchingRules(rules, userAgentStyleSheet, elt, pseudo); 679 addRules(elt, pseudo, result, rules, StyleMap.USER_AGENT_ORIGIN); 680 } 681 682 if (userStyleSheet != null) { 684 List rules = new ArrayList (); 685 addMatchingRules(rules, userStyleSheet, elt, pseudo); 686 addRules(elt, pseudo, result, rules, StyleMap.USER_ORIGIN); 687 } 688 689 element = elt; 690 try { 691 ShorthandManager.PropertyHandler ph = 693 new ShorthandManager.PropertyHandler() { 694 public void property(String pname, LexicalUnit lu, 695 boolean important) { 696 int idx = getPropertyIndex(pname); 697 if (idx != -1) { 698 ValueManager vm = valueManagers[idx]; 699 Value v = vm.createValue(lu, CSSEngine.this); 700 putAuthorProperty(result, idx, v, important, 701 StyleMap.NON_CSS_ORIGIN); 702 return; 703 } 704 idx = getShorthandIndex(pname); 705 if (idx == -1) 706 return; shorthandManagers[idx].setValues 709 (CSSEngine.this, this, lu, important); 710 } 711 }; 712 713 if (nonCSSPresentationalHints != null) { 714 NamedNodeMap attrs = elt.getAttributes(); 715 int len = attrs.getLength(); 716 for (int i = 0; i < len; i++) { 717 Node attr = attrs.item(i); 718 String an = attr.getNodeName(); 719 if (nonCSSPresentationalHints.contains(an)) { 720 try { 721 LexicalUnit lu; 722 lu = parser.parsePropertyValue(attr.getNodeValue()); 723 ph.property(an, lu, false); 724 } catch (Exception e) { 725 String m = e.getMessage(); 726 if (m == null) m = ""; 727 String u = ((documentURI == null)?"<unknown>": 728 documentURI.toString()); 729 String s = Messages.formatMessage 730 ("property.syntax.error.at", 731 new Object [] { u, an, attr.getNodeValue(),m}); 732 DOMException de = new DOMException (DOMException.SYNTAX_ERR, s); 733 if (userAgent == null) throw de; 734 userAgent.displayError(de); 735 } 736 } 737 } 738 } 739 740 List snodes = getStyleSheetNodes(); 742 int slen = snodes.size(); 743 if (slen > 0) { 744 List rules = new ArrayList (); 745 for (int i = 0; i < slen; i++) { 746 CSSStyleSheetNode ssn = (CSSStyleSheetNode)snodes.get(i); 747 StyleSheet ss = ssn.getCSSStyleSheet(); 748 if (ss != null && 749 (!ss.isAlternate() || 750 ss.getTitle() == null || 751 ss.getTitle().equals(alternateStyleSheet)) && 752 mediaMatch(ss.getMedia())) { 753 addMatchingRules(rules, ss, elt, pseudo); 754 } 755 } 756 addRules(elt, pseudo, result, rules, StyleMap.AUTHOR_ORIGIN); 757 } 758 759 if (styleLocalName != null) { 761 String style = elt.getAttributeNS(styleNamespaceURI, 762 styleLocalName); 763 if (style.length() > 0) { 764 try { 765 parser.setSelectorFactory(CSSSelectorFactory.INSTANCE); 766 parser.setConditionFactory(cssConditionFactory); 767 styleDeclarationDocumentHandler.styleMap = result; 768 parser.setDocumentHandler 769 (styleDeclarationDocumentHandler); 770 parser.parseStyleDeclaration(style); 771 styleDeclarationDocumentHandler.styleMap = null; 772 } catch (Exception e) { 773 String m = e.getMessage(); 774 if (m == null) m = ""; 775 String u = ((documentURI == null)?"<unknown>": 776 documentURI.toString()); 777 String s = Messages.formatMessage 778 ("style.syntax.error.at", 779 new Object [] { u, styleLocalName, style, m}); 780 DOMException de = new DOMException (DOMException.SYNTAX_ERR, s); 781 if (userAgent == null) throw de; 782 userAgent.displayError(de); 783 } 784 } 785 } 786 } finally { 787 element = null; 788 cssBaseURI = null; 789 } 790 791 return result; 792 } 793 794 798 public Value getComputedStyle(CSSStylableElement elt, 799 String pseudo, 800 int propidx) { 801 StyleMap sm = elt.getComputedStyleMap(pseudo); 802 if (sm == null) { 803 sm = getCascadedStyleMap(elt, pseudo); 804 elt.setComputedStyleMap(pseudo, sm); 805 } 806 807 Value value = sm.getValue(propidx); 808 if (sm.isComputed(propidx)) 809 return value; 810 811 Value result = value; 812 ValueManager vm = valueManagers[propidx]; 813 CSSStylableElement p = getParentCSSStylableElement(elt); 814 if (value == null) { 815 if ((p == null) || !vm.isInheritedProperty()) 816 result = vm.getDefaultValue(); 817 } else if ((p != null) && (value == InheritValue.INSTANCE)) { 818 result = null; 819 } 820 if (result == null) { 821 result = getComputedStyle(p, null, propidx); 824 sm.putParentRelative(propidx, true); 825 sm.putInherited (propidx, true); 826 } else { 827 result = vm.computeValue(elt, pseudo, this, propidx, 829 sm, result); 830 } 831 if (value == null) { 832 sm.putValue(propidx, result); 833 sm.putNullCascaded(propidx, true); 834 } else if (result != value) { 835 ComputedValue cv = new ComputedValue(value); 836 cv.setComputedValue(result); 837 sm.putValue(propidx, cv); 838 result = cv; 839 } 840 841 sm.putComputed(propidx, true); 842 return result; 843 } 844 845 849 public List getStyleSheetNodes() { 850 if (styleSheetNodes == null) { 851 styleSheetNodes = new ArrayList (); 852 selectorAttributes = new HashSet (); 853 findStyleSheetNodes(document); 855 int len = styleSheetNodes.size(); 856 for (int i = 0; i < len; i++) { 857 CSSStyleSheetNode ssn; 858 ssn = (CSSStyleSheetNode)styleSheetNodes.get(i); 859 StyleSheet ss = ssn.getCSSStyleSheet(); 860 if (ss != null) { 861 findSelectorAttributes(selectorAttributes, ss); 862 } 863 } 864 } 865 return styleSheetNodes; 866 } 867 868 871 protected void findStyleSheetNodes(Node n) { 872 if (n instanceof CSSStyleSheetNode) { 873 styleSheetNodes.add(n); 874 } 875 for (Node nd = n.getFirstChild(); 876 nd != null; 877 nd = nd.getNextSibling()) { 878 findStyleSheetNodes(nd); 879 } 880 } 881 882 885 protected void findSelectorAttributes(Set attrs, StyleSheet ss) { 886 int len = ss.getSize(); 887 for (int i = 0; i < len; i++) { 888 Rule r = ss.getRule(i); 889 switch (r.getType()) { 890 case StyleRule.TYPE: 891 StyleRule style = (StyleRule)r; 892 SelectorList sl = style.getSelectorList(); 893 int slen = sl.getLength(); 894 for (int j = 0; j < slen; j++) { 895 ExtendedSelector s = (ExtendedSelector)sl.item(j); 896 s.fillAttributeSet(attrs); 897 } 898 break; 899 900 case MediaRule.TYPE: 901 case ImportRule.TYPE: 902 MediaRule mr = (MediaRule)r; 903 if (mediaMatch(mr.getMediaList())) { 904 findSelectorAttributes(attrs, mr); 905 } 906 break; 907 } 908 } 909 } 910 911 915 public interface MainPropertyReceiver { 916 919 public void setMainProperty(String name, Value v, boolean important); 920 }; 921 922 public void setMainProperties 923 (CSSStylableElement elt, final MainPropertyReceiver dst, 924 String pname, String value, boolean important){ 925 try { 926 element = elt; 927 LexicalUnit lu = parser.parsePropertyValue(value); 928 ShorthandManager.PropertyHandler ph = 929 new ShorthandManager.PropertyHandler() { 930 public void property(String pname, LexicalUnit lu, 931 boolean important) { 932 int idx = getPropertyIndex(pname); 933 if (idx != -1) { 934 ValueManager vm = valueManagers[idx]; 935 Value v = vm.createValue(lu, CSSEngine.this); 936 dst.setMainProperty(pname, v, important); 937 return; 938 } 939 idx = getShorthandIndex(pname); 940 if (idx == -1) 941 return; shorthandManagers[idx].setValues 944 (CSSEngine.this, this, lu, important); 945 } 946 }; 947 ph.property(pname, lu, important); 948 } catch (Exception e) { 949 String m = e.getMessage(); 950 if (m == null) m = ""; 951 String u = ((documentURI == null)?"<unknown>": 952 documentURI.toString()); 953 String s = Messages.formatMessage 954 ("property.syntax.error.at", 955 new Object [] { u, pname, value, m}); 956 DOMException de = new DOMException (DOMException.SYNTAX_ERR, s); 957 if (userAgent == null) throw de; 958 userAgent.displayError(de); 959 } finally { 960 element = null; 961 cssBaseURI = null; 962 } 963 } 964 965 971 public Value parsePropertyValue(CSSStylableElement elt, 972 String prop, String value) { 973 int idx = getPropertyIndex(prop); 974 if (idx == -1) return null; 975 ValueManager vm = valueManagers[idx]; 976 try { 977 element = elt; 978 LexicalUnit lu; 979 lu = parser.parsePropertyValue(value); 980 return vm.createValue(lu, this); 981 } catch (Exception e) { 982 String m = e.getMessage(); 983 if (m == null) m = ""; 984 String u = ((documentURI == null)?"<unknown>": 985 documentURI.toString()); 986 String s = Messages.formatMessage 987 ("property.syntax.error.at", 988 new Object [] { u, prop, value, m}); 989 DOMException de = new DOMException (DOMException.SYNTAX_ERR, s); 990 if (userAgent == null) throw de; 991 userAgent.displayError(de); 992 } finally { 993 element = null; 994 cssBaseURI = null; 995 } 996 return vm.getDefaultValue(); 997 } 998 999 1003 public StyleDeclaration parseStyleDeclaration(CSSStylableElement elt, 1004 String value) { 1005 styleDeclarationBuilder.styleDeclaration = new StyleDeclaration(); 1006 try { 1007 element = elt; 1008 parser.setSelectorFactory(CSSSelectorFactory.INSTANCE); 1009 parser.setConditionFactory(cssConditionFactory); 1010 parser.setDocumentHandler(styleDeclarationBuilder); 1011 parser.parseStyleDeclaration(value); 1012 } catch (Exception e) { 1013 String m = e.getMessage(); 1014 if (m == null) m = ""; 1015 String u = ((documentURI == null)?"<unknown>": 1016 documentURI.toString()); 1017 String s = Messages.formatMessage 1018 ("syntax.error.at", new Object [] { u, m }); 1019 DOMException de = new DOMException (DOMException.SYNTAX_ERR, s); 1020 if (userAgent == null) throw de; 1021 userAgent.displayError(de); 1022 } finally { 1023 element = null; 1024 cssBaseURI = null; 1025 } 1026 return styleDeclarationBuilder.styleDeclaration; 1027 } 1028 1029 1034 public StyleSheet parseStyleSheet(URL uri, String media) 1035 throws DOMException { 1036 StyleSheet ss = new StyleSheet(); 1037 try { 1038 ss.setMedia(parser.parseMedia(media)); 1039 } catch (Exception e) { 1040 String m = e.getMessage(); 1041 if (m == null) m = ""; 1042 String u = ((documentURI == null)?"<unknown>": 1043 documentURI.toString()); 1044 String s = Messages.formatMessage 1045 ("syntax.error.at", new Object [] { u, m }); 1046 DOMException de = new DOMException (DOMException.SYNTAX_ERR, s); 1047 if (userAgent == null) throw de; 1048 userAgent.displayError(de); 1049 return ss; 1050 } 1051 parseStyleSheet(ss, uri); 1052 return ss; 1053 } 1054 1055 1061 public StyleSheet parseStyleSheet(InputSource is, URL uri, String media) 1062 throws DOMException { 1063 StyleSheet ss = new StyleSheet(); 1064 try { 1065 ss.setMedia(parser.parseMedia(media)); 1066 parseStyleSheet(ss, is, uri); 1067 } catch (Exception e) { 1068 String m = e.getMessage(); 1069 if (m == null) m = ""; 1070 String u = ((documentURI == null)?"<unknown>": 1071 documentURI.toString()); 1072 String s = Messages.formatMessage 1073 ("syntax.error.at", new Object [] { u, m }); 1074 DOMException de = new DOMException (DOMException.SYNTAX_ERR, s); 1075 if (userAgent == null) throw de; 1076 userAgent.displayError(de); 1077 } 1078 return ss; 1079 } 1080 1081 1086 public void parseStyleSheet(StyleSheet ss, URL uri) throws DOMException { 1087 if (uri == null) { 1088 String s = Messages.formatMessage 1089 ("syntax.error.at", 1090 new Object [] { "Null Document reference", "" }); 1091 DOMException de = new DOMException (DOMException.SYNTAX_ERR, s); 1092 if (userAgent == null) throw de; 1093 userAgent.displayError(de); 1094 return; 1095 } 1096 1097 try { 1098 ParsedURL pDocURL = null; 1100 if (documentURI != null) { 1101 pDocURL = new ParsedURL(documentURI); 1102 } 1103 ParsedURL pURL = new ParsedURL(uri); 1104 cssContext.checkLoadExternalResource(pURL, pDocURL); 1105 1106 parseStyleSheet(ss, new InputSource(uri.toString()), uri); 1107 } catch (SecurityException e) { 1108 throw e; 1109 } catch (Exception e) { 1110 String m = e.getMessage(); 1111 if (m == null) m = ""; 1112 String s = Messages.formatMessage 1113 ("syntax.error.at", new Object [] { uri.toString(), m }); 1114 DOMException de = new DOMException (DOMException.SYNTAX_ERR, s); 1115 if (userAgent == null) throw de; 1116 userAgent.displayError(de); 1117 } 1118 } 1119 1120 1126 public StyleSheet parseStyleSheet(String rules, URL uri, String media) 1127 throws DOMException { 1128 StyleSheet ss = new StyleSheet(); 1129 try { 1130 ss.setMedia(parser.parseMedia(media)); 1131 } catch (Exception e) { 1132 String m = e.getMessage(); 1133 if (m == null) m = ""; 1134 String u = ((documentURI == null)?"<unknown>": 1135 documentURI.toString()); 1136 String s = Messages.formatMessage 1137 ("syntax.error.at", new Object [] { u, m }); 1138 DOMException de = new DOMException (DOMException.SYNTAX_ERR, s); 1139 if (userAgent == null) throw de; 1140 userAgent.displayError(de); 1141 return ss; 1142 } 1143 parseStyleSheet(ss, rules, uri); 1144 return ss; 1145 } 1146 1147 1153 public void parseStyleSheet(StyleSheet ss, 1154 String rules, 1155 URL uri) throws DOMException { 1156 try { 1157 parseStyleSheet(ss, new InputSource(new StringReader (rules)), uri); 1158 } catch (Exception e) { 1159 String m = e.getMessage(); 1161 if (m == null) m = ""; 1162 String s = Messages.formatMessage 1163 ("stylesheet.syntax.error", 1164 new Object [] { uri.toString(), rules, m }); 1165 DOMException de = new DOMException (DOMException.SYNTAX_ERR, s); 1166 if (userAgent == null) throw de; 1167 userAgent.displayError(de); 1168 } 1169 } 1170 1171 1176 protected void parseStyleSheet(StyleSheet ss, InputSource is, URL uri) 1177 throws IOException { 1178 parser.setSelectorFactory(CSSSelectorFactory.INSTANCE); 1179 parser.setConditionFactory(cssConditionFactory); 1180 try { 1181 cssBaseURI = uri; 1182 styleSheetDocumentHandler.styleSheet = ss; 1183 parser.setDocumentHandler(styleSheetDocumentHandler); 1184 parser.parseStyleSheet(is); 1185 1186 int len = ss.getSize(); 1188 for (int i = 0; i < len; i++) { 1189 Rule r = ss.getRule(i); 1190 if (r.getType() != ImportRule.TYPE) { 1191 break; 1193 } 1194 ImportRule ir = (ImportRule)r; 1195 parseStyleSheet(ir, ir.getURI()); 1196 } 1197 } finally { 1198 cssBaseURI = null; 1199 } 1200 } 1201 1202 1206 protected void putAuthorProperty(StyleMap dest, 1207 int idx, 1208 Value sval, 1209 boolean imp, 1210 short origin) { 1211 Value dval = dest.getValue(idx); 1212 short dorg = dest.getOrigin(idx); 1213 boolean dimp = dest.isImportant(idx); 1214 1215 boolean cond = dval == null; 1216 if (!cond) { 1217 switch (dorg) { 1218 case StyleMap.USER_ORIGIN: 1219 cond = !dimp; 1220 break; 1221 case StyleMap.AUTHOR_ORIGIN: 1222 cond = !dimp || imp; 1223 break; 1224 default: 1225 cond = true; 1226 } 1227 } 1228 1229 if (cond) { 1230 dest.putValue(idx, sval); 1231 dest.putImportant(idx, imp); 1232 dest.putOrigin(idx, origin); 1233 } 1234 } 1235 1236 1240 protected void addMatchingRules(List rules, 1241 StyleSheet ss, 1242 Element elt, 1243 String pseudo) { 1244 int len = ss.getSize(); 1245 for (int i = 0; i < len; i++) { 1246 Rule r = ss.getRule(i); 1247 switch (r.getType()) { 1248 case StyleRule.TYPE: 1249 StyleRule style = (StyleRule)r; 1250 SelectorList sl = style.getSelectorList(); 1251 int slen = sl.getLength(); 1252 for (int j = 0; j < slen; j++) { 1253 ExtendedSelector s = (ExtendedSelector)sl.item(j); 1254 if (s.match(elt, pseudo)) { 1255 rules.add(style); 1256 } 1257 } 1258 break; 1259 1260 case MediaRule.TYPE: 1261 case ImportRule.TYPE: 1262 MediaRule mr = (MediaRule)r; 1263 if (mediaMatch(mr.getMediaList())) { 1264 addMatchingRules(rules, mr, elt, pseudo); 1265 } 1266 break; 1267 } 1268 } 1269 } 1270 1271 1274 protected void addRules(Element elt, 1275 String pseudo, 1276 StyleMap sm, 1277 List rules, 1278 short origin) { 1279 sortRules(rules, elt, pseudo); 1280 int rlen = rules.size(); 1281 1282 if (origin == StyleMap.AUTHOR_ORIGIN) { 1283 for (int r = 0; r < rlen; r++) { 1284 StyleRule sr = (StyleRule)rules.get(r); 1285 StyleDeclaration sd = sr.getStyleDeclaration(); 1286 int len = sd.size(); 1287 for (int i = 0; i < len; i++) { 1288 putAuthorProperty(sm, 1289 sd.getIndex(i), 1290 sd.getValue(i), 1291 sd.getPriority(i), 1292 origin); 1293 } 1294 } 1295 } else { 1296 for (int r = 0; r < rlen; r++) { 1297 StyleRule sr = (StyleRule)rules.get(r); 1298 StyleDeclaration sd = sr.getStyleDeclaration(); 1299 int len = sd.size(); 1300 for (int i = 0; i < len; i++) { 1301 int idx = sd.getIndex(i); 1302 sm.putValue(idx, sd.getValue(i)); 1303 sm.putImportant(idx, sd.getPriority(i)); 1304 sm.putOrigin(idx, origin); 1305 } 1306 } 1307 } 1308 } 1309 1310 1314 protected void sortRules(List rules, Element elt, String pseudo) { 1315 int len = rules.size(); 1316 for (int i = 0; i < len - 1; i++) { 1317 int idx = i; 1318 int min = Integer.MAX_VALUE; 1319 for (int j = i; j < len; j++) { 1320 StyleRule r = (StyleRule)rules.get(j); 1321 SelectorList sl = r.getSelectorList(); 1322 int spec = 0; 1323 int slen = sl.getLength(); 1324 for (int k = 0; k < slen; k++) { 1325 ExtendedSelector s = (ExtendedSelector)sl.item(k); 1326 if (s.match(elt, pseudo)) { 1327 int sp = s.getSpecificity(); 1328 if (sp > spec) { 1329 spec = sp; 1330 } 1331 } 1332 } 1333 if (spec < min) { 1334 min = spec; 1335 idx = j; 1336 } 1337 } 1338 if (i != idx) { 1339 Object tmp = rules.get(i); 1340 rules.set(i, rules.get(idx)); 1341 rules.set(idx, tmp); 1342 } 1343 } 1344 } 1345 1346 1350 protected boolean mediaMatch(SACMediaList ml) { 1351 if (media == null || 1352 ml == null || 1353 media.getLength() == 0 || 1354 ml.getLength() == 0) { 1355 return true; 1356 } 1357 for (int i = 0; i < ml.getLength(); i++) { 1358 if (ml.item(i).equalsIgnoreCase("all")) 1359 return true; 1360 for (int j = 0; j < media.getLength(); j++) { 1361 if (media.item(j).equalsIgnoreCase("all") || 1362 ml.item(i).equalsIgnoreCase(media.item(j))) { 1363 return true; 1364 } 1365 } 1366 } 1367 return false; 1368 } 1369 1370 1373 protected class StyleDeclarationDocumentHandler 1374 extends DocumentAdapter 1375 implements ShorthandManager.PropertyHandler { 1376 public StyleMap styleMap; 1377 1378 1382 public void property(String name, LexicalUnit value, boolean important) 1383 throws CSSException { 1384 int i = getPropertyIndex(name); 1385 if (i == -1) { 1386 i = getShorthandIndex(name); 1387 if (i == -1) { 1388 return; 1390 } 1391 shorthandManagers[i].setValues(CSSEngine.this, 1392 this, 1393 value, 1394 important); 1395 } else { 1396 Value v = valueManagers[i].createValue(value, CSSEngine.this); 1397 putAuthorProperty(styleMap, i, v, important, 1398 StyleMap.INLINE_AUTHOR_ORIGIN); 1399 } 1400 } 1401 } 1402 1403 1406 protected class StyleDeclarationBuilder 1407 extends DocumentAdapter 1408 implements ShorthandManager.PropertyHandler { 1409 public StyleDeclaration styleDeclaration; 1410 1411 1415 public void property(String name, LexicalUnit value, boolean important) 1416 throws CSSException { 1417 int i = getPropertyIndex(name); 1418 if (i == -1) { 1419 i = getShorthandIndex(name); 1420 if (i == -1) { 1421 return; 1423 } 1424 shorthandManagers[i].setValues(CSSEngine.this, 1425 this, 1426 value, 1427 important); 1428 } else { 1429 Value v = valueManagers[i].createValue(value, CSSEngine.this); 1430 styleDeclaration.append(v, i, important); 1431 } 1432 } 1433 } 1434 1435 1438 protected class StyleSheetDocumentHandler 1439 extends DocumentAdapter 1440 implements ShorthandManager.PropertyHandler { 1441 public StyleSheet styleSheet; 1442 protected StyleRule styleRule; 1443 protected StyleDeclaration styleDeclaration; 1444 1445 1449 public void startDocument(InputSource source) 1450 throws CSSException { 1451 } 1452 1453 1457 public void endDocument(InputSource source) throws CSSException { 1458 } 1459 1460 1464 public void ignorableAtRule(String atRule) throws CSSException { 1465 } 1466 1467 1471 public void importStyle(String uri, 1472 SACMediaList media, 1473 String defaultNamespaceURI) 1474 throws CSSException { 1475 ImportRule ir = new ImportRule(); 1476 ir.setMediaList(media); 1477 ir.setParent(styleSheet); 1478 try { 1479 URL base = getCSSBaseURI(); 1480 URL url; 1481 if (base == null) url = new URL (uri); 1482 else url = new URL (base, uri); 1483 ir.setURI(url); 1484 } catch (MalformedURLException e) { 1485 } 1486 styleSheet.append(ir); 1487 } 1488 1489 1493 public void startMedia(SACMediaList media) throws CSSException { 1494 MediaRule mr = new MediaRule(); 1495 mr.setMediaList(media); 1496 mr.setParent(styleSheet); 1497 styleSheet.append(mr); 1498 styleSheet = mr; 1499 } 1500 1501 1505 public void endMedia(SACMediaList media) throws CSSException { 1506 styleSheet = styleSheet.getParent(); 1507 } 1508 1509 1513 public void startPage(String name, String pseudo_page) 1514 throws CSSException { 1515 } 1516 1517 1521 public void endPage(String name, String pseudo_page) 1522 throws CSSException { 1523 } 1524 1525 1529 public void startFontFace() throws CSSException { 1530 styleDeclaration = new StyleDeclaration(); 1531 } 1532 1533 1537 public void endFontFace() throws CSSException { 1538 StyleMap sm = new StyleMap(getNumberOfProperties()); 1539 int len = styleDeclaration.size(); 1540 for (int i=0; i<len; i++) { 1541 int idx = styleDeclaration.getIndex(i); 1542 sm.putValue(idx, styleDeclaration.getValue(i)); 1543 sm.putImportant(idx, styleDeclaration.getPriority(i)); 1544 sm.putOrigin(idx, StyleMap.AUTHOR_ORIGIN); 1546 } 1547 styleDeclaration = null; 1548 1549 int pidx = getPropertyIndex(CSSConstants.CSS_FONT_FAMILY_PROPERTY); 1550 Value fontFamily = sm.getValue(pidx); 1551 if (fontFamily == null) return; 1552 1553 URL base = getCSSBaseURI(); 1554 ParsedURL purl = null; 1555 if (base != null) purl = new ParsedURL(base); 1556 fontFaces.add(new FontFaceRule(sm, purl)); 1557 } 1558 1559 1563 public void startSelector(SelectorList selectors) throws CSSException { 1564 styleRule = new StyleRule(); 1565 styleRule.setSelectorList(selectors); 1566 styleDeclaration = new StyleDeclaration(); 1567 styleRule.setStyleDeclaration(styleDeclaration); 1568 styleSheet.append(styleRule); 1569 } 1570 1571 1575 public void endSelector(SelectorList selectors) throws CSSException { 1576 styleRule = null; 1577 styleDeclaration = null; 1578 } 1579 1580 1584 public void property(String name, LexicalUnit value, boolean important) 1585 throws CSSException { 1586 int i = getPropertyIndex(name); 1587 if (i == -1) { 1588 i = getShorthandIndex(name); 1589 if (i == -1) { 1590 return; 1592 } 1593 shorthandManagers[i].setValues(CSSEngine.this, 1594 this, 1595 value, 1596 important); 1597 } else { 1598 Value v = valueManagers[i].createValue(value, CSSEngine.this); 1599 styleDeclaration.append(v, i, important); 1600 } 1601 } 1602 } 1603 1604 1607 protected static class DocumentAdapter implements DocumentHandler { 1608 1609 1613 public void startDocument(InputSource source) 1614 throws CSSException { 1615 throw new InternalError (); 1616 } 1617 1618 1622 public void endDocument(InputSource source) throws CSSException { 1623 throw new InternalError (); 1624 } 1625 1626 1630 public void comment(String text) throws CSSException { 1631 } 1633 1634 1638 public void ignorableAtRule(String atRule) throws CSSException { 1639 throw new InternalError (); 1640 } 1641 1642 1646 public void namespaceDeclaration(String prefix, String uri) 1647 throws CSSException { 1648 throw new InternalError (); 1649 } 1650 1651 1655 public void importStyle(String uri, 1656 SACMediaList media, 1657 String defaultNamespaceURI) 1658 throws CSSException { 1659 throw new InternalError (); 1660 } 1661 1662 1666 public void startMedia(SACMediaList media) throws CSSException { 1667 throw new InternalError (); 1668 } 1669 1670 1674 public void endMedia(SACMediaList media) throws CSSException { 1675 throw new InternalError (); 1676 } 1677 1678 1682 public void startPage(String name, String pseudo_page) 1683 throws CSSException { 1684 throw new InternalError (); 1685 } 1686 1687 1691 public void endPage(String name, String pseudo_page) 1692 throws CSSException { 1693 throw new InternalError (); 1694 } 1695 1696 1699 public void startFontFace() throws CSSException { 1700 throw new InternalError (); 1701 } 1702 1703 1706 public void endFontFace() throws CSSException { 1707 throw new InternalError (); 1708 } 1709 1710 1714 public void startSelector(SelectorList selectors) throws CSSException { 1715 throw new InternalError (); 1716 } 1717 1718 1722 public void endSelector(SelectorList selectors) throws CSSException { 1723 throw new InternalError (); 1724 } 1725 1726 1730 public void property(String name, LexicalUnit value, boolean important) 1731 throws CSSException { 1732 throw new InternalError (); 1733 } 1734 } 1735 1736 1738 protected final static CSSEngineListener[] LISTENER_ARRAY = 1739 new CSSEngineListener[0]; 1740 1741 1744 public void addCSSEngineListener(CSSEngineListener l) { 1745 listeners.add(l); 1746 } 1747 1748 1751 public void removeCSSEngineListener(CSSEngineListener l) { 1752 listeners.remove(l); 1753 } 1754 1755 1758 protected void firePropertiesChangedEvent(Element target, int[] props) { 1759 CSSEngineListener[] ll = 1760 (CSSEngineListener[])listeners.toArray(LISTENER_ARRAY); 1761 1762 int len = ll.length; 1763 if (len > 0) { 1764 CSSEngineEvent evt = new CSSEngineEvent(this, target, props); 1765 for (int i = 0; i < len; i++) { 1766 ll[i].propertiesChanged(evt); 1767 } 1768 } 1769 } 1770 1771 1773 1776 protected void inlineStyleAttributeUpdated(CSSStylableElement elt, 1777 StyleMap style, 1778 MutationEvent evt) { 1779 boolean[] updated = styleDeclarationUpdateHandler.updatedProperties; 1780 for (int i = getNumberOfProperties() - 1; i >= 0; --i) { 1781 updated[i] = false; 1782 } 1783 1784 switch (evt.getAttrChange()) { 1785 case MutationEvent.ADDITION: 1786 case MutationEvent.MODIFICATION: 1787 String decl = evt.getNewValue(); 1788 if (decl.length() > 0) { 1790 element = elt; 1791 try { 1792 parser.setSelectorFactory(CSSSelectorFactory.INSTANCE); 1793 parser.setConditionFactory(cssConditionFactory); 1794 styleDeclarationUpdateHandler.styleMap = style; 1795 parser.setDocumentHandler(styleDeclarationUpdateHandler); 1796 parser.parseStyleDeclaration(decl); 1797 styleDeclarationUpdateHandler.styleMap = null; 1798 } catch (Exception e) { 1799 String m = e.getMessage(); 1800 if (m == null) m = ""; 1801 String u = ((documentURI == null)?"<unknown>": 1802 documentURI.toString()); 1803 String s = Messages.formatMessage 1804 ("style.syntax.error.at", 1805 new Object [] { u, styleLocalName, decl, m }); 1806 DOMException de = new DOMException (DOMException.SYNTAX_ERR, s); 1807 if (userAgent == null) throw de; 1808 userAgent.displayError(de); 1809 } finally { 1810 element = null; 1811 cssBaseURI = null; 1812 } 1813 } 1814 1815 case MutationEvent.REMOVAL: 1817 boolean removed = false; 1818 1819 if (evt.getPrevValue() != null && 1820 evt.getPrevValue().length() > 0) { 1821 for (int i = getNumberOfProperties() - 1; i >= 0; --i) { 1824 if (style.isComputed(i) && 1825 style.getOrigin(i) == StyleMap.INLINE_AUTHOR_ORIGIN && 1826 !updated[i]) { 1827 removed = true; 1828 updated[i] = true; 1829 } 1830 } 1831 } 1832 1833 if (removed) { 1834 invalidateProperties(elt, null, updated, true); 1835 } else { 1836 int count = 0; 1837 boolean fs = (fontSizeIndex == -1) 1839 ? false 1840 : updated[fontSizeIndex]; 1841 boolean lh = (lineHeightIndex == -1) 1842 ? false 1843 : updated[lineHeightIndex]; 1844 boolean cl = (colorIndex == -1) 1845 ? false 1846 : updated[colorIndex]; 1847 1848 for (int i = getNumberOfProperties() - 1; i >= 0; --i) { 1849 if (updated[i]) { 1850 count++; 1851 } 1852 else if ((fs && style.isFontSizeRelative(i)) || 1853 (lh && style.isLineHeightRelative(i)) || 1854 (cl && style.isColorRelative(i))) { 1855 updated[i] = true; 1856 clearComputedValue(style, i); 1857 count++; 1858 } 1859 } 1860 1861 if (count > 0) { 1862 int[] props = new int[count]; 1863 count = 0; 1864 for (int i = getNumberOfProperties() - 1; i >= 0; --i) { 1865 if (updated[i]) { 1866 props[count++] = i; 1867 } 1868 } 1869 invalidateProperties(elt, props, null, true); 1870 } 1871 } 1872 break; 1873 1874 default: 1875 throw new InternalError ("Invalid attrChangeType"); 1877 } 1878 } 1879 1880 private static void clearComputedValue(StyleMap style, int n) { 1881 if (style.isNullCascaded(n)) { 1882 style.putValue(n, null); 1883 } else { 1884 Value v = style.getValue(n); 1885 if (v instanceof ComputedValue) { 1886 ComputedValue cv = (ComputedValue)v; 1887 v = cv.getCascadedValue(); 1888 style.putValue(n, v); 1889 } 1890 } 1891 style.putComputed(n, false); 1892 } 1893 1894 1895 1899 protected void invalidateProperties(Node node, 1900 int [] properties, 1901 boolean [] updated, 1902 boolean recascade) { 1903 1904 if (!(node instanceof CSSStylableElement)) 1905 return; 1907 CSSStylableElement elt = (CSSStylableElement)node; 1908 StyleMap style = elt.getComputedStyleMap(null); 1909 if (style == null) 1910 return; 1912 boolean [] diffs = new boolean[getNumberOfProperties()]; 1913 if (updated != null) { 1914 for (int i=0; i< updated.length; i++) { 1915 diffs[i] = updated[i]; 1916 } 1917 } 1918 if (properties != null) { 1919 for (int i=0; i<properties.length; i++) { 1920 diffs[properties[i]] = true; 1921 } 1922 } 1923 int count =0; 1924 if (!recascade) { 1925 for (int i=0; i<diffs.length; i++) { 1926 if (diffs[i]) 1927 count++; 1928 } 1929 } else { 1930 StyleMap newStyle = getCascadedStyleMap(elt, null); 1931 elt.setComputedStyleMap(null, newStyle); 1932 for (int i=0; i<diffs.length; i++) { 1933 if (diffs[i]) { 1934 count++; 1935 continue; } 1937 1938 Value nv = newStyle.getValue(i); 1940 Value ov = null; 1941 if (!style.isNullCascaded(i)) { 1942 ov = style.getValue(i); 1943 if (ov instanceof ComputedValue) { 1944 ov = ((ComputedValue)ov).getCascadedValue(); 1945 } 1946 } 1947 1948 if (nv == ov) continue; 1949 if ((nv != null) && (ov != null)) { 1950 if (nv.equals(ov)) continue; 1951 String ovCssText = ov.getCssText(); 1952 String nvCssText = nv.getCssText(); 1953 if ((nvCssText == ovCssText) || 1954 ((nvCssText != null) && nvCssText.equals(ovCssText))) 1955 continue; 1956 } 1957 count++; 1958 diffs[i] = true; 1959 } 1960 } 1961 int []props = null; 1962 if (count != 0) { 1963 props = new int[count]; 1964 count = 0; 1965 for (int i=0; i<diffs.length; i++) { 1966 if (diffs[i]) 1967 props[count++] = i; 1968 } 1969 } 1970 propagateChanges(elt, props, recascade); 1971 } 1972 1973 1980 protected void propagateChanges(Node node, int[] props, 1981 boolean recascade) { 1982 if (!(node instanceof CSSStylableElement)) 1983 return; 1984 CSSStylableElement elt = (CSSStylableElement)node; 1985 StyleMap style = elt.getComputedStyleMap(null); 1986 if (style != null) { 1987 boolean[] updated = 1988 styleDeclarationUpdateHandler.updatedProperties; 1989 for (int i = getNumberOfProperties() - 1; i >= 0; --i) { 1990 updated[i] = false; 1991 } 1992 if (props != null) { 1993 for (int i = props.length - 1; i >= 0; --i) { 1994 int idx = props[i]; 1995 updated[idx] = true; 1996 } 1997 } 1998 1999 boolean fs = (fontSizeIndex == -1) 2001 ? false 2002 : updated[fontSizeIndex]; 2003 boolean lh = (lineHeightIndex == -1) 2004 ? false 2005 : updated[lineHeightIndex]; 2006 boolean cl = (colorIndex == -1) 2007 ? false 2008 : updated[colorIndex]; 2009 2010 int count = 0; 2011 for (int i = getNumberOfProperties() - 1; i >= 0; --i) { 2012 if (updated[i]) { 2013 count++; 2014 } 2015 else if ((fs && style.isFontSizeRelative(i)) || 2016 (lh && style.isLineHeightRelative(i)) || 2017 (cl && style.isColorRelative(i))) { 2018 updated[i] = true; 2019 clearComputedValue(style, i); 2020 count++; 2021 } 2022 } 2023 2024 if (count == 0) { 2025 props = null; 2026 } else { 2027 props = new int[count]; 2028 count = 0; 2029 for (int i = getNumberOfProperties() - 1; i >= 0; --i) { 2030 if (updated[i]) { 2031 props[count++] = i; 2032 } 2033 } 2034 firePropertiesChangedEvent(elt, props); 2035 } 2036 } 2037 2038 int [] inherited = props; 2039 if (props != null) { 2040 int count = 0; 2043 for (int i=0; i<props.length; i++) { 2044 ValueManager vm = valueManagers[props[i]]; 2045 if (vm.isInheritedProperty()) count++; 2046 else props[i] = -1; 2047 } 2048 2049 if (count == 0) { 2050 inherited = null; 2052 } else { 2053 inherited = new int[count]; 2054 count=0; 2055 for (int i=0; i<props.length; i++) 2056 if (props[i] != -1) 2057 inherited[count++] = props[i]; 2058 } 2059 } 2060 2061 CSSImportedElementRoot ier = getImportedChild(node); 2062 if (ier != null) { 2063 Element e = (Element )ier.getFirstChild(); 2064 CSSEngine subEng = cssContext.getCSSEngineForElement(e); 2071 subEng.invalidateProperties(e, inherited, null, recascade); 2072 } 2073 for (Node n = node.getFirstChild(); 2074 n != null; 2075 n = n.getNextSibling()) { 2076 invalidateProperties(n, inherited, null, recascade); 2077 } 2078 } 2079 2080 2083 protected class StyleDeclarationUpdateHandler 2084 extends DocumentAdapter 2085 implements ShorthandManager.PropertyHandler { 2086 public StyleMap styleMap; 2087 public boolean[] updatedProperties = 2088 new boolean[getNumberOfProperties()]; 2089 2090 2094 public void property(String name, LexicalUnit value, boolean important) 2095 throws CSSException { 2096 int i = getPropertyIndex(name); 2097 if (i == -1) { 2098 i = getShorthandIndex(name); 2099 if (i == -1) { 2100 return; 2102 } 2103 shorthandManagers[i].setValues(CSSEngine.this, 2104 this, 2105 value, 2106 important); 2107 } else { 2108 if (styleMap.isImportant(i)) { 2109 return; 2112 } 2113 2114 updatedProperties[i] = true; 2115 2116 Value v = valueManagers[i].createValue(value, CSSEngine.this); 2117 styleMap.putMask(i, (short)0); 2118 styleMap.putValue(i, v); 2119 styleMap.putOrigin(i, StyleMap.INLINE_AUTHOR_ORIGIN); 2120 } 2121 } 2122 } 2123 2124 2127 protected void nonCSSPresentationalHintUpdated(CSSStylableElement elt, 2128 StyleMap style, 2129 String property, 2130 MutationEvent evt) { 2131 int idx = getPropertyIndex(property); 2133 2134 if (style.isImportant(idx)) { 2135 return; 2138 } 2139 2140 switch (style.getOrigin(idx)) { 2141 case StyleMap.AUTHOR_ORIGIN: 2142 case StyleMap.INLINE_AUTHOR_ORIGIN: 2143 return; 2145 } 2146 2147 switch (evt.getAttrChange()) { 2148 case MutationEvent.ADDITION: 2149 case MutationEvent.MODIFICATION: 2150 element = elt; 2151 try { 2152 LexicalUnit lu; 2153 lu = parser.parsePropertyValue(evt.getNewValue()); 2154 ValueManager vm = valueManagers[idx]; 2155 Value v = vm.createValue(lu, CSSEngine.this); 2156 style.putMask(idx, (short)0); 2157 style.putValue(idx, v); 2158 style.putOrigin(idx, StyleMap.NON_CSS_ORIGIN); 2159 } catch (Exception e) { 2160 String m = e.getMessage(); 2161 if (m == null) m = ""; 2162 String u = ((documentURI == null)?"<unknown>": 2163 documentURI.toString()); 2164 String s = Messages.formatMessage 2165 ("property.syntax.error.at", 2166 new Object [] { u, property, evt.getNewValue(), m }); 2167 DOMException de = new DOMException (DOMException.SYNTAX_ERR, s); 2168 if (userAgent == null) throw de; 2169 userAgent.displayError(de); 2170 } finally { 2171 element = null; 2172 cssBaseURI = null; 2173 } 2174 break; 2175 2176 case MutationEvent.REMOVAL: 2177 { 2178 int [] invalid = { idx }; 2179 invalidateProperties(elt, invalid, null, true); 2180 return; 2181 } 2182 } 2183 2184 boolean[] updated = styleDeclarationUpdateHandler.updatedProperties; 2185 for (int i = getNumberOfProperties() - 1; i >= 0; --i) { 2186 updated[i] = false; 2187 } 2188 updated[idx] = true; 2189 2190 boolean fs = idx == fontSizeIndex; 2192 boolean lh = idx == lineHeightIndex; 2193 boolean cl = idx == colorIndex; 2194 int count = 0; 2195 2196 for (int i = getNumberOfProperties() - 1; i >= 0; --i) { 2197 if (updated[i]) { 2198 count++; 2199 } 2200 else if ((fs && style.isFontSizeRelative(i)) || 2201 (lh && style.isLineHeightRelative(i)) || 2202 (cl && style.isColorRelative(i))) { 2203 updated[i] = true; 2204 clearComputedValue(style, i); 2205 count++; 2206 } 2207 } 2208 2209 int[] props = new int[count]; 2210 count = 0; 2211 for (int i = getNumberOfProperties() - 1; i >= 0; --i) { 2212 if (updated[i]) { 2213 props[count++] = i; 2214 } 2215 } 2216 2217 invalidateProperties(elt, props, null, true); 2218 } 2219 2220 2224 protected class DOMNodeInsertedListener implements EventListener { 2225 public void handleEvent(Event evt) { 2226 EventTarget et = evt.getTarget(); 2227 if (et instanceof CSSStyleSheetNode) { 2228 styleSheetNodes = null; 2229 invalidateProperties(document.getDocumentElement(), 2231 null, null, true); 2232 return; 2233 } 2234 if (et instanceof CSSStylableElement) { 2235 for (Node n = ((Node )evt.getTarget()).getNextSibling(); 2239 n != null; 2240 n = n.getNextSibling()) { 2241 invalidateProperties(n, null, null, true); 2242 } 2243 } 2244 } 2245 } 2246 2247 2251 protected class DOMNodeRemovedListener implements EventListener { 2252 public void handleEvent(Event evt) { 2253 EventTarget et = evt.getTarget(); 2254 if (et instanceof CSSStyleSheetNode) { 2255 styleSheetRemoved = true; 2258 } else if (et instanceof CSSStylableElement) { 2259 removedStylableElementSibling = ((Node )et).getNextSibling(); 2262 } 2263 disposeStyleMaps((Node )et); 2265 } 2266 } 2267 2268 2272 protected class DOMSubtreeModifiedListener implements EventListener { 2273 public void handleEvent(Event evt) { 2274 if (styleSheetRemoved) { 2275 styleSheetRemoved = false; 2276 styleSheetNodes = null; 2277 2278 invalidateProperties(document.getDocumentElement(), 2280 null, null, true); 2281 } else if (removedStylableElementSibling != null) { 2282 for (Node n = removedStylableElementSibling; 2286 n != null; 2287 n = n.getNextSibling()) { 2288 invalidateProperties(n, null, null, true); 2289 } 2290 removedStylableElementSibling = null; 2291 } 2292 } 2293 } 2294 2295 2298 protected class DOMCharacterDataModifiedListener implements EventListener { 2299 public void handleEvent(Event evt) { 2300 Node n = (Node )evt.getTarget(); 2301 if (n.getParentNode() instanceof CSSStyleSheetNode) { 2302 styleSheetNodes = null; 2303 invalidateProperties(document.getDocumentElement(), 2305 null, null, true); 2306 } 2307 } 2308 } 2309 2310 2314 protected class DOMAttrModifiedListener implements EventListener { 2315 public void handleEvent(Event evt) { 2316 EventTarget et = evt.getTarget(); 2317 if (!(et instanceof CSSStylableElement)) { 2318 return; 2320 } 2321 2322 MutationEvent mevt = (MutationEvent )evt; 2323 if (mevt.getNewValue().equals(mevt.getPrevValue())) 2324 return; 2326 Node attr = mevt.getRelatedNode(); 2327 String attrNS = attr.getNamespaceURI(); 2328 String name = ((attrNS == null) ? 2329 attr.getNodeName() : 2330 attr.getLocalName()); 2331 2332 CSSStylableElement elt = (CSSStylableElement)et; 2333 StyleMap style = elt.getComputedStyleMap(null); 2334 if (style != null) { 2335 if ((attrNS == styleNamespaceURI) || 2336 ((attrNS != null) && attrNS.equals(styleNamespaceURI))) { 2337 if (name.equals(styleLocalName)) { 2338 inlineStyleAttributeUpdated(elt, style, mevt); 2340 return; 2341 } 2342 } 2343 2344 if (nonCSSPresentationalHints != null) { 2345 if ((attrNS == nonCSSPresentationalHintsNamespaceURI) || 2346 ((attrNS != null) && 2347 attrNS.equals(nonCSSPresentationalHintsNamespaceURI))) { 2348 if (nonCSSPresentationalHints.contains(name)) { 2349 nonCSSPresentationalHintUpdated(elt, style, name, 2352 mevt); 2353 return; 2354 } 2355 } 2356 } 2357 } 2358 2359 if (selectorAttributes != null && 2360 selectorAttributes.contains(name)) { 2361 invalidateProperties(elt, null, null, true); 2364 for (Node n = elt.getNextSibling(); 2365 n != null; 2366 n = n.getNextSibling()) { 2367 invalidateProperties(n, null, null, true); 2368 } 2369 } 2370 } 2371 } 2372} 2373 | Popular Tags |