KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > css > engine > CSSEngine


1 /*
2
3    Copyright 2002-2004 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.css.engine;
19
20 import java.io.IOException JavaDoc;
21 import java.io.StringReader JavaDoc;
22 import java.net.MalformedURLException JavaDoc;
23 import java.net.URL JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Collections JavaDoc;
26 import java.util.HashSet JavaDoc;
27 import java.util.LinkedList JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Set JavaDoc;
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 JavaDoc;
49 import org.w3c.dom.Document JavaDoc;
50 import org.w3c.dom.Element JavaDoc;
51 import org.w3c.dom.NamedNodeMap JavaDoc;
52 import org.w3c.dom.Node JavaDoc;
53 import org.w3c.dom.events.Event JavaDoc;
54 import org.w3c.dom.events.EventListener JavaDoc;
55 import org.w3c.dom.events.EventTarget JavaDoc;
56 import org.w3c.dom.events.MutationEvent JavaDoc;
57
58 /**
59  * This is the base class for all the CSS engines.
60  *
61  * @author <a HREF="mailto:stephane@hillion.org">Stephane Hillion</a>
62  * @version $Id: CSSEngine.java,v 1.42 2004/12/03 12:20:15 deweese Exp $
63  */

64 public abstract class CSSEngine {
65
66     /**
67      * List of StyleMap objects, one for each @font-face rule
68      * encountered by this CSSEngine.
69      */

70     protected List JavaDoc fontFaces = new LinkedList JavaDoc();
71
72     /**
73      * Get's the StyleMaps generated by @font-face rules
74      * encountered by this CSSEngine thus far.
75      */

76     public List JavaDoc getFontFaces() { return fontFaces; }
77
78     CSSEngineUserAgent userAgent = null;
79
80     /**
81      * Returns the next stylable parent of the given element.
82      */

83     public static CSSStylableElement getParentCSSStylableElement(Element JavaDoc elt) {
84         Element JavaDoc 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     /**
95      * Returns the next parent element of the given element, from the
96      * CSS point of view.
97      */

98     public static Element JavaDoc getParentElement(Element JavaDoc elt) {
99         Node JavaDoc n = elt.getParentNode();
100         while (n != null) {
101             n = getLogicalParentNode(n);
102             if (n.getNodeType() == Node.ELEMENT_NODE) {
103                 return (Element JavaDoc)n;
104             }
105             n = n.getParentNode();
106         }
107         return null;
108     }
109
110     /**
111      * Returns the logical parent of a node, given its physical parent.
112      */

113     public static Node JavaDoc getLogicalParentNode(Node JavaDoc parent) {
114         Node JavaDoc 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     /**
126      * Returns the imported child of the given node, if any.
127      */

128     public static CSSImportedElementRoot getImportedChild(Node JavaDoc 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     /**
138      * The CSS context.
139      */

140     protected CSSContext cssContext;
141     
142     /**
143      * The associated document.
144      */

145     protected Document JavaDoc document;
146
147     /**
148      * The document URI.
149      */

150     protected URL JavaDoc documentURI;
151
152     /**
153      * The property/int mappings.
154      */

155     protected StringIntMap indexes;
156
157     /**
158      * The shorthand-property/int mappings.
159      */

160     protected StringIntMap shorthandIndexes;
161
162     /**
163      * The value managers.
164      */

165     protected ValueManager[] valueManagers;
166
167     /**
168      * The shorthand managers.
169      */

170     protected ShorthandManager[] shorthandManagers;
171
172     /**
173      * The CSS parser.
174      */

175     protected ExtendedParser parser;
176
177     /**
178      * The pseudo-element names.
179      */

180     protected String JavaDoc[] pseudoElementNames;
181
182     /**
183      * The font-size property index.
184      */

185     protected int fontSizeIndex = -1;
186
187     /**
188      * The line-height property index.
189      */

190     protected int lineHeightIndex = -1;
191
192     /**
193      * The color property index.
194      */

195     protected int colorIndex = -1;
196
197     /**
198      * The user-agent style-sheet.
199      */

200     protected StyleSheet userAgentStyleSheet;
201
202     /**
203      * The user style-sheet.
204      */

205     protected StyleSheet userStyleSheet;
206
207     /**
208      * The media to use to cascade properties.
209      */

210     protected SACMediaList media;
211
212     /**
213      * The DOM nodes which contains StyleSheets.
214      */

215     protected List JavaDoc styleSheetNodes;
216
217     /**
218      * The style attribute namespace URI.
219      */

220     protected String JavaDoc styleNamespaceURI;
221
222     /**
223      * The style attribute local name.
224      */

225     protected String JavaDoc styleLocalName;
226     
227     /**
228      * The class attribute namespace URI.
229      */

230     protected String JavaDoc classNamespaceURI;
231
232     /**
233      * The class attribute local name.
234      */

235     protected String JavaDoc classLocalName;
236     
237     /**
238      * The non CSS presentational hints.
239      */

240     protected Set JavaDoc nonCSSPresentationalHints;
241
242     /**
243      * The non CSS presentational hints namespace URI.
244      */

245     protected String JavaDoc nonCSSPresentationalHintsNamespaceURI;
246
247     /**
248      * The style declaration document handler.
249      */

250     protected StyleDeclarationDocumentHandler styleDeclarationDocumentHandler =
251         new StyleDeclarationDocumentHandler();
252
253     /**
254      * The style declaration update handler.
255      */

256     protected StyleDeclarationUpdateHandler styleDeclarationUpdateHandler;
257
258     /**
259      * The style sheet document handler.
260      */

261     protected StyleSheetDocumentHandler styleSheetDocumentHandler =
262         new StyleSheetDocumentHandler();
263
264     /**
265      * The style declaration document handler used to build a
266      * StyleDeclaration object.
267      */

268     protected StyleDeclarationBuilder styleDeclarationBuilder =
269         new StyleDeclarationBuilder();
270
271     /**
272      * The current element.
273      */

274     protected CSSStylableElement element;
275
276     /**
277      * The current base URI.
278      */

279     protected URL JavaDoc cssBaseURI;
280
281     /**
282      * The alternate stylesheet title.
283      */

284     protected String JavaDoc alternateStyleSheet;
285
286     /**
287      * The DOMAttrModified event listener.
288      */

289     protected EventListener JavaDoc domAttrModifiedListener;
290
291     /**
292      * The DOMNodeInserted event listener.
293      */

294     protected EventListener JavaDoc domNodeInsertedListener;
295
296     /**
297      * The DOMNodeRemoved event listener.
298      */

299     protected EventListener JavaDoc domNodeRemovedListener;
300
301     /**
302      * The DOMSubtreeModified event listener.
303      */

304     protected EventListener JavaDoc domSubtreeModifiedListener;
305
306     /**
307      * The DOMCharacterDataModified event listener.
308      */

309     protected EventListener JavaDoc domCharacterDataModifiedListener;
310
311     /**
312      * Whether a style sheet as been removed from the document.
313      */

314     protected boolean styleSheetRemoved;
315
316     /**
317      * The right sibling of the last removed node.
318      */

319     protected Node JavaDoc removedStylableElementSibling;
320
321     /**
322      * The listeners.
323      */

324     protected List JavaDoc listeners = Collections.synchronizedList(new LinkedList JavaDoc());
325
326     /**
327      * The attributes found in stylesheets selectors.
328      */

329     protected Set JavaDoc selectorAttributes;
330
331     /**
332      * Used to fire a change event for all the properties.
333      */

334     protected final int[] ALL_PROPERTIES;
335
336     /**
337      * The CSS condition factory.
338      */

339     protected CSSConditionFactory cssConditionFactory;
340
341     /**
342      * Creates a new CSSEngine.
343      * @param doc The associated document.
344      * @param uri The document URI.
345      * @param p The CSS parser.
346      * @param vm The property value managers.
347      * @param sm The shorthand properties managers.
348      * @param pe The pseudo-element names supported by the associated
349      * XML dialect. Must be null if no support for pseudo-
350      * elements is required.
351      * @param sns The namespace URI of the style attribute.
352      * @param sln The local name of the style attribute.
353      * @param cns The namespace URI of the class attribute.
354      * @param cln The local name of the class attribute.
355      * @param hints Whether the CSS engine should support non CSS
356      * presentational hints.
357      * @param hintsNS The hints namespace URI.
358      * @param ctx The CSS context.
359      */

360     protected CSSEngine(Document JavaDoc doc,
361                         URL JavaDoc uri,
362                         ExtendedParser p,
363                         ValueManager[] vm,
364                         ShorthandManager[] sm,
365                         String JavaDoc[] pe,
366                         String JavaDoc sns,
367                         String JavaDoc sln,
368                         String JavaDoc cns,
369                         String JavaDoc cln,
370                         boolean hints,
371                         String JavaDoc 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 JavaDoc 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 JavaDoc(vm.length+sm.length);
415             nonCSSPresentationalHintsNamespaceURI = hintsNS;
416             len = vm.length;
417             for (int i = 0; i < len; i++) {
418                 String JavaDoc pn = vm[i].getPropertyName();
419                 nonCSSPresentationalHints.add(pn);
420             }
421             len = sm.length;
422             for (int i = 0; i < len; i++) {
423                 String JavaDoc pn = sm[i].getPropertyName();
424                 nonCSSPresentationalHints.add(pn);
425             }
426         }
427
428         if (cssContext.isDynamic() &&
429             (document instanceof EventTarget JavaDoc)) {
430             // Attach the mutation events listeners.
431
EventTarget JavaDoc et = (EventTarget JavaDoc)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     /**
464      * Disposes the CSSEngine and all the attached resources.
465      */

466     public void dispose() {
467         setCSSEngineUserAgent(null);
468         disposeStyleMaps(document.getDocumentElement());
469         if (document instanceof EventTarget JavaDoc) {
470             // Detach the mutation events listeners.
471
EventTarget JavaDoc et = (EventTarget JavaDoc)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 JavaDoc node) {
491         if (node instanceof CSSStylableElement) {
492             ((CSSStylableElement)node).setComputedStyleMap(null, null);
493         }
494         for (Node JavaDoc n = node.getFirstChild();
495              n != null;
496              n = n.getNextSibling()) {
497             if (n.getNodeType() == Node.ELEMENT_NODE) {
498                 disposeStyleMaps(n);
499             }
500             Node JavaDoc c = getImportedChild(n);
501             if (c != null) {
502                 disposeStyleMaps(c);
503             }
504         }
505     }
506
507     /**
508      * Returns the CSS context.
509      */

510     public CSSContext getCSSContext() {
511         return cssContext;
512     }
513
514     /**
515      * Returns the document associated with this engine.
516      */

517     public Document JavaDoc getDocument() {
518         return document;
519     }
520
521     /**
522      * Returns the font-size property index.
523      */

524     public int getFontSizeIndex() {
525         return fontSizeIndex;
526     }
527
528     /**
529      * Returns the line-height property index.
530      */

531     public int getLineHeightIndex() {
532         return lineHeightIndex;
533     }
534
535     /**
536      * Returns the color property index.
537      */

538     public int getColorIndex() {
539         return colorIndex;
540     }
541
542     /**
543      * Returns the number of properties.
544      */

545     public int getNumberOfProperties() {
546         return valueManagers.length;
547     }
548
549     /**
550      * Returns the property index, or -1.
551      */

552     public int getPropertyIndex(String JavaDoc name) {
553         return indexes.get(name);
554     }
555
556     /**
557      * Returns the shorthand property index, or -1.
558      */

559     public int getShorthandIndex(String JavaDoc name) {
560         return shorthandIndexes.get(name);
561     }
562
563     /**
564      * Returns the name of the property at the given index.
565      */

566     public String JavaDoc 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     /**
579      * Sets the user agent style-sheet.
580      */

581     public void setUserAgentStyleSheet(StyleSheet ss) {
582         userAgentStyleSheet = ss;
583     }
584
585     /**
586      * Sets the user style-sheet.
587      */

588     public void setUserStyleSheet(StyleSheet ss) {
589         userStyleSheet = ss;
590     }
591
592     /**
593      * Returns the ValueManagers.
594      */

595     public ValueManager[] getValueManagers() {
596         return valueManagers;
597     }
598
599     /**
600      * Sets the media to use to compute the styles.
601      */

602     public void setMedia(String JavaDoc str) {
603         try {
604             media = parser.parseMedia(str);
605         } catch (Exception JavaDoc e) {
606             String JavaDoc m = e.getMessage();
607             if (m == null) m = "";
608             String JavaDoc s =Messages.formatMessage
609                 ("media.error", new Object JavaDoc[] { str, m });
610             throw new DOMException JavaDoc(DOMException.SYNTAX_ERR, s);
611         }
612     }
613
614     /**
615      * Sets the alternate style-sheet title.
616      */

617     public void setAlternateStyleSheet(String JavaDoc str) {
618         alternateStyleSheet = str;
619     }
620
621     /**
622      * Recursively imports the cascaded style from a source element
623      * to an element of the current document.
624      */

625     public void importCascadedStyleMaps(Element JavaDoc src,
626                                         CSSEngine srceng,
627                                         Element JavaDoc 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 JavaDoc pe = pseudoElementNames[i];
640                     sm = srceng.getCascadedStyleMap(csrc, pe);
641                     cdest.setComputedStyleMap(pe, sm);
642                 }
643             }
644         }
645
646         for (Node JavaDoc 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 JavaDoc)sn, srceng, (Element JavaDoc)dn);
651             }
652         }
653     }
654
655     /**
656      * Returns the current base-url.
657      */

658     public URL JavaDoc getCSSBaseURI() {
659         if (cssBaseURI == null) {
660             cssBaseURI = element.getCSSBase();
661         }
662         return cssBaseURI;
663     }
664
665     /**
666      * Returns the cascaded style of the given element/pseudo-element.
667      * @param elt The stylable element.
668      * @param pseudo Optional pseudo-element string (null if none).
669      */

670     public StyleMap getCascadedStyleMap(CSSStylableElement elt,
671                                         String JavaDoc pseudo) {
672         int props = getNumberOfProperties();
673         final StyleMap result = new StyleMap(props);
674
675         // Apply the user-agent style-sheet to the result.
676
if (userAgentStyleSheet != null) {
677             List JavaDoc rules = new ArrayList JavaDoc();
678             addMatchingRules(rules, userAgentStyleSheet, elt, pseudo);
679             addRules(elt, pseudo, result, rules, StyleMap.USER_AGENT_ORIGIN);
680         }
681
682         // Apply the user properties style-sheet to the result.
683
if (userStyleSheet != null) {
684             List JavaDoc rules = new ArrayList JavaDoc();
685             addMatchingRules(rules, userStyleSheet, elt, pseudo);
686             addRules(elt, pseudo, result, rules, StyleMap.USER_ORIGIN);
687         }
688
689         element = elt;
690         try {
691             // Apply the non-CSS presentational hints to the result.
692
ShorthandManager.PropertyHandler ph =
693                 new ShorthandManager.PropertyHandler() {
694                     public void property(String JavaDoc 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; // Unknown property...
707
// Shorthand value
708
shorthandManagers[idx].setValues
709                             (CSSEngine.this, this, lu, important);
710                     }
711                 };
712
713             if (nonCSSPresentationalHints != null) {
714                 NamedNodeMap JavaDoc attrs = elt.getAttributes();
715                 int len = attrs.getLength();
716                 for (int i = 0; i < len; i++) {
717                     Node JavaDoc attr = attrs.item(i);
718                     String JavaDoc 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 JavaDoc e) {
725                             String JavaDoc m = e.getMessage();
726                             if (m == null) m = "";
727                             String JavaDoc u = ((documentURI == null)?"<unknown>":
728                                         documentURI.toString());
729                             String JavaDoc s = Messages.formatMessage
730                                 ("property.syntax.error.at",
731                                  new Object JavaDoc[] { u, an, attr.getNodeValue(),m});
732                             DOMException JavaDoc de = new DOMException JavaDoc(DOMException.SYNTAX_ERR, s);
733                             if (userAgent == null) throw de;
734                             userAgent.displayError(de);
735                         }
736                     }
737                 }
738             }
739
740             // Apply the document style-sheets to the result.
741
List JavaDoc snodes = getStyleSheetNodes();
742             int slen = snodes.size();
743             if (slen > 0) {
744                 List JavaDoc rules = new ArrayList JavaDoc();
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             // Apply the inline style to the result.
760
if (styleLocalName != null) {
761                 String JavaDoc 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 JavaDoc e) {
773                         String JavaDoc m = e.getMessage();
774                         if (m == null) m = "";
775                         String JavaDoc u = ((documentURI == null)?"<unknown>":
776                                     documentURI.toString());
777                         String JavaDoc s = Messages.formatMessage
778                             ("style.syntax.error.at",
779                              new Object JavaDoc[] { u, styleLocalName, style, m});
780                         DOMException JavaDoc de = new DOMException JavaDoc(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     /**
795      * Returns the computed style of the given element/pseudo for the
796      * property corresponding to the given index.
797      */

798     public Value getComputedStyle(CSSStylableElement elt,
799                                   String JavaDoc 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             // Value is 'inherit' and p != null.
822
// The pseudo class is not propagated.
823
result = getComputedStyle(p, null, propidx);
824             sm.putParentRelative(propidx, true);
825             sm.putInherited (propidx, true);
826         } else {
827             // Maybe is it a relative value.
828
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     /**
846      * Returns the document CSSStyleSheetNodes in a list. This list is
847      * updated as the document is modified.
848      */

849     public List JavaDoc getStyleSheetNodes() {
850         if (styleSheetNodes == null) {
851             styleSheetNodes = new ArrayList JavaDoc();
852             selectorAttributes = new HashSet JavaDoc();
853             // Find all the style-sheets in the document.
854
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     /**
869      * An auxiliary method for getStyleSheets().
870      */

871     protected void findStyleSheetNodes(Node JavaDoc n) {
872         if (n instanceof CSSStyleSheetNode) {
873             styleSheetNodes.add(n);
874         }
875         for (Node JavaDoc nd = n.getFirstChild();
876              nd != null;
877              nd = nd.getNextSibling()) {
878             findStyleSheetNodes(nd);
879         }
880     }
881
882     /**
883      * Finds the selector attributes in the given stylesheet.
884      */

885     protected void findSelectorAttributes(Set JavaDoc 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     /**
912      * Interface for people interesting in having 'primary' properties
913      * set. Shorthand properties will be expanded "automatically".
914      */

915     public interface MainPropertyReceiver {
916         /**
917          * Called with a non-shorthand property name and it's value.
918          */

919         public void setMainProperty(String JavaDoc name, Value v, boolean important);
920     };
921
922     public void setMainProperties
923         (CSSStylableElement elt, final MainPropertyReceiver dst,
924          String JavaDoc pname, String JavaDoc 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 JavaDoc 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; // Unknown property...
942
// Shorthand value
943
shorthandManagers[idx].setValues
944                             (CSSEngine.this, this, lu, important);
945                     }
946                 };
947             ph.property(pname, lu, important);
948         } catch (Exception JavaDoc e) {
949             String JavaDoc m = e.getMessage();
950             if (m == null) m = "";
951             String JavaDoc u = ((documentURI == null)?"<unknown>":
952                         documentURI.toString());
953             String JavaDoc s = Messages.formatMessage
954                 ("property.syntax.error.at",
955                  new Object JavaDoc[] { u, pname, value, m});
956             DOMException JavaDoc de = new DOMException JavaDoc(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     /**
966      * Parses and creates a property value from elt.
967      * @param elt The element property is from.
968      * @param prop The property name.
969      * @param value The property value.
970      */

971     public Value parsePropertyValue(CSSStylableElement elt,
972                                     String JavaDoc prop, String JavaDoc 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 JavaDoc e) {
982             String JavaDoc m = e.getMessage();
983             if (m == null) m = "";
984             String JavaDoc u = ((documentURI == null)?"<unknown>":
985                         documentURI.toString());
986             String JavaDoc s = Messages.formatMessage
987                 ("property.syntax.error.at",
988                  new Object JavaDoc[] { u, prop, value, m});
989             DOMException JavaDoc de = new DOMException JavaDoc(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     /**
1000     * Parses and creates a style declaration.
1001     * @param value The style declaration text.
1002     */

1003    public StyleDeclaration parseStyleDeclaration(CSSStylableElement elt,
1004                                                  String JavaDoc 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 JavaDoc e) {
1013            String JavaDoc m = e.getMessage();
1014            if (m == null) m = "";
1015            String JavaDoc u = ((documentURI == null)?"<unknown>":
1016                        documentURI.toString());
1017            String JavaDoc s = Messages.formatMessage
1018                ("syntax.error.at", new Object JavaDoc[] { u, m });
1019            DOMException JavaDoc de = new DOMException JavaDoc(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    /**
1030     * Parses and creates a new style-sheet.
1031     * @param uri The style-sheet URI.
1032     * @param media The target media of the style-sheet.
1033     */

1034    public StyleSheet parseStyleSheet(URL JavaDoc uri, String JavaDoc media)
1035        throws DOMException JavaDoc {
1036        StyleSheet ss = new StyleSheet();
1037        try {
1038            ss.setMedia(parser.parseMedia(media));
1039        } catch (Exception JavaDoc e) {
1040            String JavaDoc m = e.getMessage();
1041            if (m == null) m = "";
1042            String JavaDoc u = ((documentURI == null)?"<unknown>":
1043                        documentURI.toString());
1044            String JavaDoc s = Messages.formatMessage
1045                ("syntax.error.at", new Object JavaDoc[] { u, m });
1046            DOMException JavaDoc de = new DOMException JavaDoc(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    /**
1056     * Parses and creates a new style-sheet.
1057     * @param is The input source used to read the document.
1058     * @param uri The base URI.
1059     * @param media The target media of the style-sheet.
1060     */

1061    public StyleSheet parseStyleSheet(InputSource is, URL JavaDoc uri, String JavaDoc media)
1062        throws DOMException JavaDoc {
1063        StyleSheet ss = new StyleSheet();
1064        try {
1065            ss.setMedia(parser.parseMedia(media));
1066            parseStyleSheet(ss, is, uri);
1067        } catch (Exception JavaDoc e) {
1068            String JavaDoc m = e.getMessage();
1069            if (m == null) m = "";
1070            String JavaDoc u = ((documentURI == null)?"<unknown>":
1071                        documentURI.toString());
1072            String JavaDoc s = Messages.formatMessage
1073                ("syntax.error.at", new Object JavaDoc[] { u, m });
1074            DOMException JavaDoc de = new DOMException JavaDoc(DOMException.SYNTAX_ERR, s);
1075            if (userAgent == null) throw de;
1076            userAgent.displayError(de);
1077        }
1078        return ss;
1079    }
1080
1081    /**
1082     * Parses and fills the given style-sheet.
1083     * @param ss The stylesheet to fill.
1084     * @param uri The base URI.
1085     */

1086    public void parseStyleSheet(StyleSheet ss, URL JavaDoc uri) throws DOMException JavaDoc {
1087        if (uri == null) {
1088            String JavaDoc s = Messages.formatMessage
1089                ("syntax.error.at",
1090                 new Object JavaDoc[] { "Null Document reference", "" });
1091            DOMException JavaDoc de = new DOMException JavaDoc(DOMException.SYNTAX_ERR, s);
1092            if (userAgent == null) throw de;
1093            userAgent.displayError(de);
1094            return;
1095        }
1096
1097    try {
1098            // Check that access to the uri is allowed
1099
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 JavaDoc e) {
1108            throw e;
1109        } catch (Exception JavaDoc e) {
1110            String JavaDoc m = e.getMessage();
1111            if (m == null) m = "";
1112            String JavaDoc s = Messages.formatMessage
1113                ("syntax.error.at", new Object JavaDoc[] { uri.toString(), m });
1114            DOMException JavaDoc de = new DOMException JavaDoc(DOMException.SYNTAX_ERR, s);
1115            if (userAgent == null) throw de;
1116            userAgent.displayError(de);
1117        }
1118    }
1119
1120    /**
1121     * Parses and creates a new style-sheet.
1122     * @param rules The style-sheet rules to parse.
1123     * @param uri The style-sheet URI.
1124     * @param media The target media of the style-sheet.
1125     */

1126    public StyleSheet parseStyleSheet(String JavaDoc rules, URL JavaDoc uri, String JavaDoc media)
1127        throws DOMException JavaDoc {
1128        StyleSheet ss = new StyleSheet();
1129        try {
1130            ss.setMedia(parser.parseMedia(media));
1131        } catch (Exception JavaDoc e) {
1132            String JavaDoc m = e.getMessage();
1133            if (m == null) m = "";
1134            String JavaDoc u = ((documentURI == null)?"<unknown>":
1135                        documentURI.toString());
1136            String JavaDoc s = Messages.formatMessage
1137                ("syntax.error.at", new Object JavaDoc[] { u, m });
1138            DOMException JavaDoc de = new DOMException JavaDoc(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    /**
1148     * Parses and fills the given style-sheet.
1149     * @param ss The stylesheet to fill.
1150     * @param rules The style-sheet rules to parse.
1151     * @param uri The base URI.
1152     */

1153    public void parseStyleSheet(StyleSheet ss,
1154                                String JavaDoc rules,
1155                                URL JavaDoc uri) throws DOMException JavaDoc {
1156        try {
1157            parseStyleSheet(ss, new InputSource(new StringReader JavaDoc(rules)), uri);
1158    } catch (Exception JavaDoc e) {
1159            // e.printStackTrace();
1160
String JavaDoc m = e.getMessage();
1161            if (m == null) m = "";
1162            String JavaDoc s = Messages.formatMessage
1163                ("stylesheet.syntax.error",
1164                 new Object JavaDoc[] { uri.toString(), rules, m });
1165            DOMException JavaDoc de = new DOMException JavaDoc(DOMException.SYNTAX_ERR, s);
1166            if (userAgent == null) throw de;
1167            userAgent.displayError(de);
1168        }
1169    }
1170
1171    /**
1172     * Parses and fills the given style-sheet.
1173     * @param ss The stylesheet to fill.
1174     * @param uri The base URI.
1175     */

1176    protected void parseStyleSheet(StyleSheet ss, InputSource is, URL JavaDoc uri)
1177        throws IOException JavaDoc {
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            // Load the imported sheets.
1187
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                    // @import rules must be the first rules.
1192
break;
1193                }
1194                ImportRule ir = (ImportRule)r;
1195                parseStyleSheet(ir, ir.getURI());
1196            }
1197        } finally {
1198            cssBaseURI = null;
1199        }
1200    }
1201
1202    /**
1203     * Puts an author property from a style-map in another style-map,
1204     * if possible.
1205     */

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    /**
1237     * Adds the rules matching the element/pseudo-element of given style
1238     * sheet to the list.
1239     */

1240    protected void addMatchingRules(List JavaDoc rules,
1241                                    StyleSheet ss,
1242                                    Element JavaDoc elt,
1243                                    String JavaDoc 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    /**
1272     * Adds the rules contained in the given list to a stylemap.
1273     */

1274    protected void addRules(Element JavaDoc elt,
1275                            String JavaDoc pseudo,
1276                            StyleMap sm,
1277                            List JavaDoc 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    /**
1311     * Sorts the rules matching the element/pseudo-element of given style
1312     * sheet to the list.
1313     */

1314    protected void sortRules(List JavaDoc rules, Element JavaDoc elt, String JavaDoc 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 JavaDoc tmp = rules.get(i);
1340                rules.set(i, rules.get(idx));
1341                rules.set(idx, tmp);
1342            }
1343        }
1344    }
1345
1346    /**
1347     * Whether the given media list matches the media list of this
1348     * CSSEngine object.
1349     */

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    /**
1371     * To parse a style declaration.
1372     */

1373    protected class StyleDeclarationDocumentHandler
1374        extends DocumentAdapter
1375        implements ShorthandManager.PropertyHandler {
1376        public StyleMap styleMap;
1377    
1378        /**
1379         * <b>SAC</b>: Implements {@link
1380         * DocumentHandler#property(String,LexicalUnit,boolean)}.
1381         */

1382        public void property(String JavaDoc 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                    // Unknown property
1389
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    /**
1404     * To build a StyleDeclaration object.
1405     */

1406    protected class StyleDeclarationBuilder
1407        extends DocumentAdapter
1408        implements ShorthandManager.PropertyHandler {
1409        public StyleDeclaration styleDeclaration;
1410    
1411        /**
1412         * <b>SAC</b>: Implements {@link
1413         * DocumentHandler#property(String,LexicalUnit,boolean)}.
1414         */

1415        public void property(String JavaDoc 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                    // Unknown property
1422
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    /**
1436     * To parse a style sheet.
1437     */

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        /**
1446         * <b>SAC</b>: Implements {@link
1447         * DocumentHandler#startDocument(InputSource)}.
1448         */

1449        public void startDocument(InputSource source)
1450            throws CSSException {
1451        }
1452    
1453        /**
1454         * <b>SAC</b>: Implements {@link
1455         * DocumentHandler#endDocument(InputSource)}.
1456         */

1457        public void endDocument(InputSource source) throws CSSException {
1458        }
1459    
1460        /**
1461         * <b>SAC</b>: Implements {@link
1462         * org.w3c.css.sac.DocumentHandler#ignorableAtRule(String)}.
1463         */

1464        public void ignorableAtRule(String JavaDoc atRule) throws CSSException {
1465        }
1466    
1467        /**
1468         * <b>SAC</b>: Implements {@link
1469         * DocumentHandler#importStyle(String,SACMediaList,String)}.
1470         */

1471        public void importStyle(String JavaDoc uri,
1472                                SACMediaList media,
1473                                String JavaDoc defaultNamespaceURI)
1474            throws CSSException {
1475            ImportRule ir = new ImportRule();
1476            ir.setMediaList(media);
1477            ir.setParent(styleSheet);
1478            try {
1479                URL JavaDoc base = getCSSBaseURI();
1480                URL JavaDoc url;
1481                if (base == null) url = new URL JavaDoc(uri);
1482                else url = new URL JavaDoc(base, uri);
1483                ir.setURI(url);
1484            } catch (MalformedURLException JavaDoc e) {
1485            }
1486            styleSheet.append(ir);
1487        }
1488    
1489        /**
1490         * <b>SAC</b>: Implements {@link
1491         * org.w3c.css.sac.DocumentHandler#startMedia(SACMediaList)}.
1492         */

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        /**
1502         * <b>SAC</b>: Implements {@link
1503         * org.w3c.css.sac.DocumentHandler#endMedia(SACMediaList)}.
1504         */

1505        public void endMedia(SACMediaList media) throws CSSException {
1506            styleSheet = styleSheet.getParent();
1507        }
1508    
1509        /**
1510         * <b>SAC</b>: Implements {@link
1511         * org.w3c.css.sac.DocumentHandler#startPage(String,String)}.
1512         */

1513        public void startPage(String JavaDoc name, String JavaDoc pseudo_page)
1514            throws CSSException {
1515        }
1516    
1517        /**
1518         * <b>SAC</b>: Implements {@link
1519         * org.w3c.css.sac.DocumentHandler#endPage(String,String)}.
1520         */

1521        public void endPage(String JavaDoc name, String JavaDoc pseudo_page)
1522            throws CSSException {
1523        }
1524    
1525        /**
1526         * <b>SAC</b>: Implements {@link
1527         * org.w3c.css.sac.DocumentHandler#startFontFace()}.
1528         */

1529        public void startFontFace() throws CSSException {
1530            styleDeclaration = new StyleDeclaration();
1531        }
1532    
1533        /**
1534         * <b>SAC</b>: Implements {@link
1535         * org.w3c.css.sac.DocumentHandler#endFontFace()}.
1536         */

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                // Not sure on this..
1545
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 JavaDoc base = getCSSBaseURI();
1554            ParsedURL purl = null;
1555            if (base != null) purl = new ParsedURL(base);
1556            fontFaces.add(new FontFaceRule(sm, purl));
1557        }
1558    
1559        /**
1560         * <b>SAC</b>: Implements {@link
1561         * org.w3c.css.sac.DocumentHandler#startSelector(SelectorList)}.
1562         */

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        /**
1572         * <b>SAC</b>: Implements {@link
1573         * org.w3c.css.sac.DocumentHandler#endSelector(SelectorList)}.
1574         */

1575        public void endSelector(SelectorList selectors) throws CSSException {
1576            styleRule = null;
1577            styleDeclaration = null;
1578        }
1579
1580        /**
1581         * <b>SAC</b>: Implements {@link
1582         * DocumentHandler#property(String,LexicalUnit,boolean)}.
1583         */

1584        public void property(String JavaDoc 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                    // Unknown property
1591
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    /**
1605     * Provides an adapter for the DocumentHandler interface.
1606     */

1607    protected static class DocumentAdapter implements DocumentHandler {
1608
1609        /**
1610         * <b>SAC</b>: Implements {@link
1611         * DocumentHandler#startDocument(InputSource)}.
1612         */

1613        public void startDocument(InputSource source)
1614            throws CSSException {
1615            throw new InternalError JavaDoc();
1616        }
1617    
1618        /**
1619         * <b>SAC</b>: Implements {@link
1620         * DocumentHandler#endDocument(InputSource)}.
1621         */

1622        public void endDocument(InputSource source) throws CSSException {
1623            throw new InternalError JavaDoc();
1624        }
1625    
1626        /**
1627         * <b>SAC</b>: Implements {@link
1628         * DocumentHandler#comment(String)}.
1629         */

1630        public void comment(String JavaDoc text) throws CSSException {
1631            // We always ignore the comments.
1632
}
1633    
1634        /**
1635         * <b>SAC</b>: Implements {@link
1636         * DocumentHandler#ignorableAtRule(String)}.
1637         */

1638        public void ignorableAtRule(String JavaDoc atRule) throws CSSException {
1639            throw new InternalError JavaDoc();
1640        }
1641    
1642        /**
1643         * <b>SAC</b>: Implements {@link
1644         * DocumentHandler#namespaceDeclaration(String,String)}.
1645         */

1646        public void namespaceDeclaration(String JavaDoc prefix, String JavaDoc uri)
1647            throws CSSException {
1648            throw new InternalError JavaDoc();
1649        }
1650    
1651        /**
1652         * <b>SAC</b>: Implements {@link
1653         * DocumentHandler#importStyle(String,SACMediaList,String)}.
1654         */

1655        public void importStyle(String JavaDoc uri,
1656                                SACMediaList media,
1657                                String JavaDoc defaultNamespaceURI)
1658            throws CSSException {
1659            throw new InternalError JavaDoc();
1660        }
1661    
1662        /**
1663         * <b>SAC</b>: Implements {@link
1664         * DocumentHandler#startMedia(SACMediaList)}.
1665         */

1666        public void startMedia(SACMediaList media) throws CSSException {
1667            throw new InternalError JavaDoc();
1668        }
1669    
1670        /**
1671         * <b>SAC</b>: Implements {@link
1672         * DocumentHandler#endMedia(SACMediaList)}.
1673         */

1674        public void endMedia(SACMediaList media) throws CSSException {
1675            throw new InternalError JavaDoc();
1676        }
1677    
1678        /**
1679         * <b>SAC</b>: Implements {@link
1680         * DocumentHandler#startPage(String,String)}.
1681         */

1682        public void startPage(String JavaDoc name, String JavaDoc pseudo_page)
1683            throws CSSException {
1684            throw new InternalError JavaDoc();
1685        }
1686    
1687        /**
1688         * <b>SAC</b>: Implements {@link
1689         * DocumentHandler#endPage(String,String)}.
1690         */

1691        public void endPage(String JavaDoc name, String JavaDoc pseudo_page)
1692            throws CSSException {
1693            throw new InternalError JavaDoc();
1694        }
1695    
1696        /**
1697         * <b>SAC</b>: Implements {@link DocumentHandler#startFontFace()}.
1698         */

1699        public void startFontFace() throws CSSException {
1700            throw new InternalError JavaDoc();
1701        }
1702    
1703        /**
1704         * <b>SAC</b>: Implements {@link DocumentHandler#endFontFace()}.
1705         */

1706        public void endFontFace() throws CSSException {
1707            throw new InternalError JavaDoc();
1708        }
1709        
1710        /**
1711         * <b>SAC</b>: Implements {@link
1712         * DocumentHandler#startSelector(SelectorList)}.
1713         */

1714        public void startSelector(SelectorList selectors) throws CSSException {
1715            throw new InternalError JavaDoc();
1716        }
1717    
1718        /**
1719         * <b>SAC</b>: Implements {@link
1720         * DocumentHandler#endSelector(SelectorList)}.
1721         */

1722        public void endSelector(SelectorList selectors) throws CSSException {
1723            throw new InternalError JavaDoc();
1724        }
1725    
1726        /**
1727         * <b>SAC</b>: Implements {@link
1728         * DocumentHandler#property(String,LexicalUnit,boolean)}.
1729         */

1730        public void property(String JavaDoc name, LexicalUnit value, boolean important)
1731            throws CSSException {
1732            throw new InternalError JavaDoc();
1733        }
1734    }
1735
1736    // CSS events /////////////////////////////////////////////////////////
1737

1738    protected final static CSSEngineListener[] LISTENER_ARRAY =
1739        new CSSEngineListener[0];
1740
1741    /**
1742     * Adds a CSS engine listener.
1743     */

1744    public void addCSSEngineListener(CSSEngineListener l) {
1745        listeners.add(l);
1746    }
1747
1748    /**
1749     * Removes a CSS engine listener.
1750     */

1751    public void removeCSSEngineListener(CSSEngineListener l) {
1752        listeners.remove(l);
1753    }
1754
1755    /**
1756     * Fires a CSSEngineEvent, given a list of modified properties.
1757     */

1758    protected void firePropertiesChangedEvent(Element JavaDoc 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    // Dynamic updates ////////////////////////////////////////////////////
1772

1773    /**
1774     * Called when the inline style of the given element has been updated.
1775     */

1776    protected void inlineStyleAttributeUpdated(CSSStylableElement elt,
1777                                               StyleMap style,
1778                                               MutationEvent JavaDoc 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 JavaDoc decl = evt.getNewValue();
1788            // System.err.println("Inline Style Update: '" + decl + "'");
1789
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 JavaDoc e) {
1799                    String JavaDoc m = e.getMessage();
1800                    if (m == null) m = "";
1801                    String JavaDoc u = ((documentURI == null)?"<unknown>":
1802                                documentURI.toString());
1803                    String JavaDoc s = Messages.formatMessage
1804                        ("style.syntax.error.at",
1805                         new Object JavaDoc[] { u, styleLocalName, decl, m });
1806                    DOMException JavaDoc de = new DOMException JavaDoc(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            // Fall through
1816
case MutationEvent.REMOVAL:
1817            boolean removed = false;
1818
1819            if (evt.getPrevValue() != null &&
1820                evt.getPrevValue().length() > 0) {
1821                // Check if the style map has cascaded styles which
1822
// come from the inline style attribute.
1823
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                // Invalidate the relative values
1838
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            // Must not happen
1876
throw new InternalError JavaDoc("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    /**
1896     * Invalidates all the properties of the given node.
1897     *
1898     */

1899    protected void invalidateProperties(Node JavaDoc node,
1900                                        int [] properties,
1901                                        boolean [] updated,
1902                                        boolean recascade) {
1903
1904        if (!(node instanceof CSSStylableElement))
1905            return; // Not Stylable sub tree
1906

1907        CSSStylableElement elt = (CSSStylableElement)node;
1908        StyleMap style = elt.getComputedStyleMap(null);
1909        if (style == null)
1910            return; // Nothing to invalidate.
1911

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; // Already marked changed.
1936
}
1937
1938                // Value nv = getComputedStyle(elt, null, i);
1939
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 JavaDoc ovCssText = ov.getCssText();
1952                    String JavaDoc 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    /**
1974     * Propagates the changes that occurs on the parent of the given node.
1975     * Props is a list of known 'changed' properties.
1976     * If recascade is true then the stylesheets will be applied
1977     * again to see if the any new rules apply (or old rules don't
1978     * apply).
1979     */

1980    protected void propagateChanges(Node JavaDoc 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            // Invalidate the relative values
2000
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            // Filter out uninheritable properties when we
2041
// propogate to children.
2042
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                // nothing to propogate for sure
2051
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 JavaDoc e = (Element JavaDoc)ier.getFirstChild();
2064            // Don't recascade trees that have been imported.
2065
// If you do it will use the stylesheets from this
2066
// document instead of the original document. Also
2067
// currently there isn't any supported way to modify
2068
// the content imported from the other document so
2069
// the cascade can't change.
2070
CSSEngine subEng = cssContext.getCSSEngineForElement(e);
2071            subEng.invalidateProperties(e, inherited, null, recascade);
2072        }
2073        for (Node JavaDoc n = node.getFirstChild();
2074             n != null;
2075             n = n.getNextSibling()) {
2076            invalidateProperties(n, inherited, null, recascade);
2077        }
2078    }
2079
2080    /**
2081     * To parse a style declaration and update a StyleMap.
2082     */

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        /**
2091         * <b>SAC</b>: Implements {@link
2092         * DocumentHandler#property(String,LexicalUnit,boolean)}.
2093         */

2094        public void property(String JavaDoc 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                    // Unknown property
2101
return;
2102                }
2103                shorthandManagers[i].setValues(CSSEngine.this,
2104                                               this,
2105                                               value,
2106                                               important);
2107            } else {
2108                if (styleMap.isImportant(i)) {
2109                    // The previous value is important, and a value
2110
// from a style attribute cannot be important...
2111
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    /**
2125     * Called when a non-CSS presentational hint has been updated.
2126     */

2127    protected void nonCSSPresentationalHintUpdated(CSSStylableElement elt,
2128                                                   StyleMap style,
2129                                                   String JavaDoc property,
2130                                                   MutationEvent JavaDoc evt) {
2131        // System.err.println("update: " + property);
2132
int idx = getPropertyIndex(property);
2133
2134        if (style.isImportant(idx)) {
2135            // The current value is important, and a value
2136
// from an XML attribute cannot be important...
2137
return;
2138        }
2139
2140        switch (style.getOrigin(idx)) {
2141        case StyleMap.AUTHOR_ORIGIN:
2142        case StyleMap.INLINE_AUTHOR_ORIGIN:
2143            // The current value has a greater priority
2144
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 JavaDoc e) {
2160                String JavaDoc m = e.getMessage();
2161                if (m == null) m = "";
2162                String JavaDoc u = ((documentURI == null)?"<unknown>":
2163                            documentURI.toString());
2164                String JavaDoc s = Messages.formatMessage
2165                    ("property.syntax.error.at",
2166                     new Object JavaDoc[] { u, property, evt.getNewValue(), m });
2167                DOMException JavaDoc de = new DOMException JavaDoc(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        // Invalidate the relative values
2191
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    /**
2221     * To handle the insertion of a CSSStyleSheetNode in the
2222     * associated document.
2223     */

2224    protected class DOMNodeInsertedListener implements EventListener JavaDoc {
2225        public void handleEvent(Event JavaDoc evt) {
2226            EventTarget JavaDoc et = evt.getTarget();
2227            if (et instanceof CSSStyleSheetNode) {
2228                styleSheetNodes = null;
2229                // Invalidate all the CSSStylableElements in the document.
2230
invalidateProperties(document.getDocumentElement(),
2231                                     null, null, true);
2232                return;
2233            }
2234            if (et instanceof CSSStylableElement) {
2235                // Invalidate the CSSStylableElement siblings, to
2236
// correctly match the adjacent selectors and
2237
// first-child pseudo-class.
2238
for (Node JavaDoc n = ((Node JavaDoc)evt.getTarget()).getNextSibling();
2239                     n != null;
2240                     n = n.getNextSibling()) {
2241                    invalidateProperties(n, null, null, true);
2242                }
2243            }
2244        }
2245    }
2246
2247    /**
2248     * To handle the removal of a CSSStyleSheetNode from the
2249     * associated document.
2250     */

2251    protected class DOMNodeRemovedListener implements EventListener JavaDoc {
2252        public void handleEvent(Event JavaDoc evt) {
2253            EventTarget JavaDoc et = evt.getTarget();
2254            if (et instanceof CSSStyleSheetNode) {
2255                // Wait for the DOMSubtreeModified to do the invalidations
2256
// because at this time the node is in the tree.
2257
styleSheetRemoved = true;
2258            } else if (et instanceof CSSStylableElement) {
2259                // Wait for the DOMSubtreeModified to do the invalidations
2260
// because at this time the node is in the tree.
2261
removedStylableElementSibling = ((Node JavaDoc)et).getNextSibling();
2262            }
2263            // Clears the computed styles in the removed tree.
2264
disposeStyleMaps((Node JavaDoc)et);
2265        }
2266    }
2267
2268    /**
2269     * To handle the removal of a CSSStyleSheetNode from the
2270     * associated document.
2271     */

2272    protected class DOMSubtreeModifiedListener implements EventListener JavaDoc {
2273        public void handleEvent(Event JavaDoc evt) {
2274            if (styleSheetRemoved) {
2275                styleSheetRemoved = false;
2276                styleSheetNodes = null;
2277
2278                // Invalidate all the CSSStylableElements in the document.
2279
invalidateProperties(document.getDocumentElement(),
2280                                     null, null, true);
2281            } else if (removedStylableElementSibling != null) {
2282                // Invalidate the CSSStylableElement siblings, to
2283
// correctly match the adjacent selectors and
2284
// first-child pseudo-class.
2285
for (Node JavaDoc n = removedStylableElementSibling;
2286                     n != null;
2287                     n = n.getNextSibling()) {
2288                    invalidateProperties(n, null, null, true);
2289                }
2290                removedStylableElementSibling = null;
2291            }
2292        }
2293    }
2294
2295    /**
2296     * To handle the modification of a CSSStyleSheetNode.
2297     */

2298    protected class DOMCharacterDataModifiedListener implements EventListener JavaDoc {
2299        public void handleEvent(Event JavaDoc evt) {
2300            Node JavaDoc n = (Node JavaDoc)evt.getTarget();
2301            if (n.getParentNode() instanceof CSSStyleSheetNode) {
2302                styleSheetNodes = null;
2303                // Invalidate all the CSSStylableElements in the document.
2304
invalidateProperties(document.getDocumentElement(),
2305                                     null, null, true);
2306            }
2307        }
2308    }
2309
2310    /**
2311     * To handle the element attributes modification in the associated
2312     * document.
2313     */

2314    protected class DOMAttrModifiedListener implements EventListener JavaDoc {
2315        public void handleEvent(Event JavaDoc evt) {
2316            EventTarget JavaDoc et = evt.getTarget();
2317            if (!(et instanceof CSSStylableElement)) {
2318                // Not a stylable element.
2319
return;
2320            }
2321
2322            MutationEvent JavaDoc mevt = (MutationEvent JavaDoc)evt;
2323            if (mevt.getNewValue().equals(mevt.getPrevValue()))
2324                return; // no change really...
2325

2326            Node JavaDoc attr = mevt.getRelatedNode();
2327            String JavaDoc attrNS = attr.getNamespaceURI();
2328            String JavaDoc 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                        // The style declaration attribute has been modified.
2339
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                            // The 'name' attribute which represents a non CSS
2350
// presentational hint has been modified.
2351
nonCSSPresentationalHintUpdated(elt, style, name,
2352                                                            mevt);
2353                            return;
2354                        }
2355                    }
2356                }
2357            }
2358
2359            if (selectorAttributes != null &&
2360                selectorAttributes.contains(name)) {
2361                // An attribute has been modified, invalidate all the
2362
// properties to correctly match attribute selectors.
2363
invalidateProperties(elt, null, null, true);
2364                for (Node JavaDoc n = elt.getNextSibling();
2365                     n != null;
2366                     n = n.getNextSibling()) {
2367                    invalidateProperties(n, null, null, true);
2368                }
2369            }
2370        }
2371    }
2372}
2373
Popular Tags