Source Code Cross Referenced for CSSEngine.java in  » IDE-Netbeans » visualweb.api.designer » org » apache » batik » css » engine » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » visualweb.api.designer » org.apache.batik.css.engine 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:
0003:         ============================================================================
0004:                           The Apache Software License, Version 1.1
0005:         ============================================================================
0006:
0007:         Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
0008:
0009:         Redistribution and use in source and binary forms, with or without modifica-
0010:         tion, are permitted provided that the following conditions are met:
0011:
0012:         1. Redistributions of  source code must  retain the above copyright  notice,
0013:            this list of conditions and the following disclaimer.
0014:
0015:         2. Redistributions in binary form must reproduce the above copyright notice,
0016:            this list of conditions and the following disclaimer in the documentation
0017:            and/or other materials provided with the distribution.
0018:
0019:         3. The end-user documentation included with the redistribution, if any, must
0020:            include  the following  acknowledgment:  "This product includes  software
0021:            developed  by the  Apache Software Foundation  (http://www.apache.org/)."
0022:            Alternately, this  acknowledgment may  appear in the software itself,  if
0023:            and wherever such third-party acknowledgments normally appear.
0024:
0025:         4. The names "Batik" and  "Apache Software Foundation" must  not  be
0026:            used to  endorse or promote  products derived from  this software without
0027:            prior written permission. For written permission, please contact
0028:            apache@apache.org.
0029:
0030:         5. Products  derived from this software may not  be called "Apache", nor may
0031:            "Apache" appear  in their name,  without prior written permission  of the
0032:            Apache Software Foundation.
0033:
0034:         THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
0035:         INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
0036:         FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
0037:         APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
0038:         INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
0039:         DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
0040:         OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
0041:         ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
0042:         (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
0043:         THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0044:
0045:         This software  consists of voluntary contributions made  by many individuals
0046:         on  behalf of the Apache Software  Foundation. For more  information on the
0047:         Apache Software Foundation, please see <http://www.apache.org/>.
0048:
0049:         */
0050:
0051:        package org.apache.batik.css.engine;
0052:
0053:        import java.io.IOException;
0054:        import java.io.StringReader; // <nb>
0055:        import java.lang.ref.WeakReference; // </nb>
0056:        import java.net.MalformedURLException;
0057:        import java.net.URL;
0058:        import java.util.ArrayList;
0059:        import java.util.Collections;
0060:        import java.util.HashSet;
0061:        import java.util.LinkedList;
0062:        import java.util.List;
0063:        import java.util.Set;
0064:
0065:        import org.apache.batik.css.engine.sac.CSSConditionFactory;
0066:        import org.apache.batik.css.engine.sac.CSSSelectorFactory;
0067:        import org.apache.batik.css.engine.sac.ExtendedSelector;
0068:        import org.apache.batik.css.engine.value.ComputedValue;
0069:        import org.apache.batik.css.engine.value.InheritValue;
0070:        import org.apache.batik.css.engine.value.ShorthandManager;
0071:        import org.apache.batik.css.engine.value.Value;
0072:        import org.apache.batik.css.engine.value.ValueManager;
0073:        import org.apache.batik.css.parser.ExtendedParser;
0074:        import org.apache.batik.util.CSSConstants;
0075:        import org.apache.batik.util.ParsedURL;
0076:        import org.w3c.css.sac.CSSException;
0077:        import org.w3c.css.sac.DocumentHandler;
0078:        import org.w3c.css.sac.InputSource;
0079:        import org.w3c.css.sac.LexicalUnit;
0080:        import org.w3c.css.sac.SACMediaList;
0081:        import org.w3c.css.sac.SelectorList;
0082:        import org.w3c.dom.DOMException;
0083:        import org.w3c.dom.Document;
0084:        import org.w3c.dom.Element;
0085:        import org.w3c.dom.NamedNodeMap;
0086:        import org.w3c.dom.Node;
0087:        import org.w3c.dom.events.Event;
0088:        import org.w3c.dom.events.EventListener;
0089:        import org.w3c.dom.events.EventTarget;
0090:        import org.w3c.dom.events.MutationEvent; // <rave>
0091:        // BEGIN RAVE MODIFICATIONS
0092:        import java.util.Collection;
0093:        import java.util.Comparator;
0094:        import java.util.Iterator;
0095:        import java.util.Map;
0096:        import java.util.TreeSet;
0097:        import org.apache.batik.css.engine.value.AbstractValue;
0098:        import org.apache.batik.css.parser.AbstractAttributeCondition;
0099:        import org.apache.batik.css.engine.sac.CSSClassCondition;
0100:        import org.apache.batik.css.engine.sac.CSSConditionalSelector;
0101:
0102:        // END RAVE MODIFICATIONS
0103:        // </rave>
0104:
0105:        /**
0106:         * This is the base class for all the CSS engines.
0107:         *
0108:         * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
0109:         * @version $Id$
0110:         * @author Tor Norbye (see // BEGIN RAVE MODIFICATIONS markers)
0111:         */
0112:        public abstract class CSSEngine {
0113:
0114:            // <rave>
0115:            // BEGIN RAVE MODIFICATIONS
0116:            /** Rule filtering will attempt to quickly filter out rules that don't need to be considered when adding matching
0117:             * rules for an element - that's currently the slowest operation in the designer. 
0118:             */
0119:            //public static boolean RULE_FILTERING = true;
0120:            public static final boolean RULE_FILTERING = System
0121:                    .getProperty("rave.nocssfiltering") == null;
0122:            public static final boolean DEBUG_FILTERING = false;
0123:            // END RAVE MODIFICATIONS
0124:            // </rave>
0125:            /**
0126:             * List of StyleMap objects, one for each @font-face rule
0127:             * encountered by this CSSEngine.
0128:             */
0129:            protected List fontFaces = new LinkedList();
0130:
0131:            /**
0132:             * Get's the StyleMaps generated by @font-face rules
0133:             * encountered by this CSSEngine thus far.
0134:             */
0135:            public List getFontFaces() {
0136:                return fontFaces;
0137:            }
0138:
0139:            CSSEngineUserAgent userAgent = null;
0140:
0141:            /**
0142:             * Returns the next stylable parent of the given element.
0143:             */
0144:            public static CSSStylableElement getParentCSSStylableElement(
0145:                    Element elt) {
0146:                // <rave>
0147:                // BEGIN RAVE MODIFICATIONS
0148:                if (elt instanceof  StyleElementLink
0149:                        && ((StyleElementLink) elt).getStyleParent() != null) {
0150:                    return ((StyleElementLink) elt).getStyleParent();
0151:                }
0152:                // END RAVE MODIFICATIONS
0153:                // </rave>
0154:                Element e = getParentElement(elt);
0155:                while (e != null) {
0156:                    if (e instanceof  CSSStylableElement) {
0157:                        return (CSSStylableElement) e;
0158:                    }
0159:                    e = getParentElement(e);
0160:                }
0161:                return null;
0162:            }
0163:
0164:            // <rave>
0165:            // BEGIN RAVE MODIFICATIONS
0166:            public interface StyleElementLink {
0167:                /** Return a parent to use for style purposes, if the regular
0168:                 * parent is null.  This is used in rave to connect markup in
0169:                 * DocumentFragments to the "master" document where the source
0170:                 * jsf element is located. Only the topmost element in the
0171:                 * rendered jsf document fragment will return non-null.
0172:                 */
0173:                CSSStylableElement getStyleParent();
0174:
0175:                /** Set a parent to use for style purposes. See getStyleParent. */
0176:                void setStyleParent(CSSStylableElement parent);
0177:            }
0178:
0179:            // END RAVE MODIFICATIONS
0180:            // </rave>
0181:            /**
0182:             * Returns the next parent element of the given element, from the
0183:             * CSS point of view.
0184:             */
0185:            public static Element getParentElement(Element elt) {
0186:                Node n = elt.getParentNode();
0187:                while (n != null) {
0188:                    n = getLogicalParentNode(n);
0189:                    if (n.getNodeType() == Node.ELEMENT_NODE) {
0190:                        return (Element) n;
0191:                    }
0192:                    n = n.getParentNode();
0193:                }
0194:                return null;
0195:            }
0196:
0197:            /**
0198:             * Returns the logical parent of a node, given its physical parent.
0199:             */
0200:            public static Node getLogicalParentNode(Node parent) {
0201:                Node node = parent;
0202:                if (node != null) {
0203:                    if (node instanceof  CSSImportedElementRoot) {
0204:                        return ((CSSImportedElementRoot) node)
0205:                                .getCSSParentElement();
0206:                    } else {
0207:                        return node;
0208:                    }
0209:                }
0210:                return null;
0211:            }
0212:
0213:            /**
0214:             * Returns the imported child of the given node, if any.
0215:             */
0216:            public static CSSImportedElementRoot getImportedChild(Node node) {
0217:                if (node instanceof  CSSImportNode) {
0218:                    CSSImportNode inode = (CSSImportNode) node;
0219:                    CSSImportedElementRoot r = inode
0220:                            .getCSSImportedElementRoot();
0221:                    return r;
0222:                }
0223:                return null;
0224:            }
0225:
0226:            /**
0227:             * The CSS context.
0228:             */
0229:            protected CSSContext cssContext;
0230:
0231:            /**
0232:             * The associated document.
0233:             */
0234:            protected Document document;
0235:
0236:            /**
0237:             * The document URI.
0238:             */
0239:            protected URL documentURI;
0240:
0241:            /**
0242:             * The property/int mappings.
0243:             */
0244:            protected StringIntMap indexes;
0245:
0246:            /**
0247:             * The shorthand-property/int mappings.
0248:             */
0249:            protected StringIntMap shorthandIndexes;
0250:
0251:            /**
0252:             * The value managers.
0253:             */
0254:            protected ValueManager[] valueManagers;
0255:
0256:            /**
0257:             * The shorthand managers.
0258:             */
0259:            protected ShorthandManager[] shorthandManagers;
0260:
0261:            /**
0262:             * The CSS parser.
0263:             */
0264:            protected ExtendedParser parser;
0265:
0266:            /**
0267:             * The pseudo-element names.
0268:             */
0269:            protected String[] pseudoElementNames;
0270:
0271:            /**
0272:             * The font-size property index.
0273:             */
0274:            protected int fontSizeIndex = -1;
0275:
0276:            /**
0277:             * The line-height property index.
0278:             */
0279:            protected int lineHeightIndex = -1;
0280:
0281:            /**
0282:             * The color property index.
0283:             */
0284:            protected int colorIndex = -1;
0285:
0286:            /**
0287:             * The user-agent style-sheet.
0288:             */
0289:            protected StyleSheet userAgentStyleSheet;
0290:
0291:            /**
0292:             * The user style-sheet.
0293:             */
0294:            protected StyleSheet userStyleSheet;
0295:
0296:            /**
0297:             * The media to use to cascade properties.
0298:             */
0299:            protected SACMediaList media;
0300:
0301:            /**
0302:             * The DOM nodes which contains StyleSheets.
0303:             */
0304:            // <nb> #125149 Memory leak, the style sheet nodes need to be held weakly.
0305:            //    protected List styleSheetNodes;
0306:            // ===
0307:            protected List<WeakReference<CSSStyleSheetNode>> styleSheetNodes;
0308:            // </nb>
0309:
0310:            /**
0311:             * The style attribute namespace URI.
0312:             */
0313:            protected String styleNamespaceURI;
0314:
0315:            /**
0316:             * The style attribute local name.
0317:             */
0318:            protected String styleLocalName;
0319:
0320:            /**
0321:             * The class attribute namespace URI.
0322:             */
0323:            protected String classNamespaceURI;
0324:
0325:            /**
0326:             * The class attribute local name.
0327:             */
0328:            protected String classLocalName;
0329:
0330:            /**
0331:             * The non CSS presentational hints.
0332:             */
0333:            protected Set nonCSSPresentationalHints;
0334:
0335:            /**
0336:             * The non CSS presentational hints namespace URI.
0337:             */
0338:            protected String nonCSSPresentationalHintsNamespaceURI;
0339:
0340:            /**
0341:             * The style declaration document handler.
0342:             */
0343:            protected StyleDeclarationDocumentHandler styleDeclarationDocumentHandler = new StyleDeclarationDocumentHandler();
0344:
0345:            /**
0346:             * The style declaration update handler.
0347:             */
0348:            protected StyleDeclarationUpdateHandler styleDeclarationUpdateHandler;
0349:
0350:            /**
0351:             * The style sheet document handler.
0352:             */
0353:            protected StyleSheetDocumentHandler styleSheetDocumentHandler = new StyleSheetDocumentHandler();
0354:
0355:            /**
0356:             * The style declaration document handler used to build a
0357:             * StyleDeclaration object.
0358:             */
0359:            protected StyleDeclarationBuilder styleDeclarationBuilder = new StyleDeclarationBuilder();
0360:
0361:            /**
0362:             * The current element.
0363:             */
0364:            protected CSSStylableElement element;
0365:
0366:            /**
0367:             * The current base URI.
0368:             */
0369:            protected URL cssBaseURI;
0370:
0371:            /**
0372:             * The alternate stylesheet title.
0373:             */
0374:            protected String alternateStyleSheet;
0375:
0376:            /**
0377:             * The DOMAttrModified event listener.
0378:             */
0379:            protected EventListener domAttrModifiedListener;
0380:
0381:            /**
0382:             * The DOMNodeInserted event listener.
0383:             */
0384:            protected EventListener domNodeInsertedListener;
0385:
0386:            /**
0387:             * The DOMNodeRemoved event listener.
0388:             */
0389:            protected EventListener domNodeRemovedListener;
0390:
0391:            /**
0392:             * The DOMSubtreeModified event listener.
0393:             */
0394:            protected EventListener domSubtreeModifiedListener;
0395:
0396:            /**
0397:             * The DOMCharacterDataModified event listener.
0398:             */
0399:            protected EventListener domCharacterDataModifiedListener;
0400:
0401:            /**
0402:             * Whether a style sheet as been removed from the document.
0403:             */
0404:            protected boolean styleSheetRemoved;
0405:
0406:            /**
0407:             * The right sibling of the last removed node.
0408:             */
0409:            protected Node removedStylableElementSibling;
0410:
0411:            /**
0412:             * The listeners.
0413:             */
0414:            protected List listeners = Collections
0415:                    .synchronizedList(new LinkedList());
0416:
0417:            /**
0418:             * The attributes found in stylesheets selectors.
0419:             */
0420:            protected Set selectorAttributes;
0421:
0422:            /**
0423:             * Used to fire a change event for all the properties.
0424:             */
0425:            protected final int[] ALL_PROPERTIES;
0426:
0427:            /**
0428:             * The CSS condition factory.
0429:             */
0430:            protected CSSConditionFactory cssConditionFactory;
0431:
0432:            /**
0433:             * Creates a new CSSEngine.
0434:             * @param doc The associated document.
0435:             * @param uri The document URI.
0436:             * @param p The CSS parser.
0437:             * @param vm The property value managers.
0438:             * @param sm The shorthand properties managers.
0439:             * @param pe The pseudo-element names supported by the associated
0440:             *           XML dialect. Must be null if no support for pseudo-
0441:             *           elements is required.
0442:             * @param sns The namespace URI of the style attribute.
0443:             * @param sln The local name of the style attribute.
0444:             * @param cns The namespace URI of the class attribute.
0445:             * @param cln The local name of the class attribute.
0446:             * @param hints Whether the CSS engine should support non CSS
0447:             *              presentational hints.
0448:             * @param hintsNS The hints namespace URI.
0449:             * @param ctx The CSS context.
0450:             */
0451:            protected CSSEngine(Document doc, URL uri, ExtendedParser p,
0452:                    ValueManager[] vm, ShorthandManager[] sm, String[] pe,
0453:                    String sns, String sln, String cns, String cln,
0454:                    boolean hints, String hintsNS, CSSContext ctx) {
0455:                document = doc;
0456:                documentURI = uri;
0457:                parser = p;
0458:                pseudoElementNames = pe;
0459:                styleNamespaceURI = sns;
0460:                styleLocalName = sln;
0461:                classNamespaceURI = cns;
0462:                classLocalName = cln;
0463:                cssContext = ctx;
0464:
0465:                cssConditionFactory = new CSSConditionFactory(cns, cln, null,
0466:                        "id");
0467:
0468:                // <rave>
0469:                // BEGIN RAVE MODIFICATIONS
0470:                //        int len = vm.length;
0471:                //        indexes = new StringIntMap(len);
0472:                //        valueManagers = vm;
0473:                //
0474:                //        for (int i = len - 1; i >= 0; --i) {
0475:                //            String pn = vm[i].getPropertyName();
0476:                //            indexes.put(pn, i);
0477:                //            if (fontSizeIndex == -1 &&
0478:                //                pn.equals(CSSConstants.CSS_FONT_SIZE_PROPERTY)) {
0479:                //                fontSizeIndex = i;
0480:                //            }
0481:                //            if (lineHeightIndex == -1 &&
0482:                //                pn.equals(CSSConstants.CSS_LINE_HEIGHT_PROPERTY)) {
0483:                //                lineHeightIndex = i;
0484:                //            }
0485:                //            if (colorIndex == -1 &&
0486:                //                pn.equals(CSSConstants.CSS_COLOR_PROPERTY)) {
0487:                //                colorIndex = i;
0488:                //            }
0489:                //        }
0490:                //
0491:                //        len = sm.length;
0492:                //        shorthandIndexes = new StringIntMap(len);
0493:                //        shorthandManagers = sm;
0494:                //        for (int i = len - 1; i >= 0; --i) {
0495:                //            shorthandIndexes.put(sm[i].getPropertyName(), i);
0496:                //        }
0497:                // Comment this stuff out, and do it in XhtmlCssEngine where we
0498:                // can do a more efficient job (we know the size property indexes
0499:                // directly, and more importantly, since it knows that it's sharing
0500:                // the value manager and shorthand manager indices between the 
0501:                // engines, it might as well share the index maps as well!)
0502:                // We have to do this to compensate though:
0503:                valueManagers = vm;
0504:                shorthandManagers = sm;
0505:                // END RAVE MODIFICATIONS
0506:                // </rave>
0507:
0508:                // <rave>
0509:                // BEGIN RAVE MODIFICATIONS
0510:                //           This support was useless, it was simply aliasing CSS names
0511:                //           to properties! But usually it's not a straight map!
0512:                //           For example, the HTML attribute "background" maps to the
0513:                //           CSS property "background-image" ! And the attribute "bgcolor"
0514:                //           maps to the CSS property "background-color" !  
0515:                //           So instead we'll handle this in subclasses where specific
0516:                //           logic can be written (the attribute value often has to be
0517:                //           special handled too so I can't just provide a map to CSSEngine;
0518:                //           e.g. for "background" for example I need to change the string
0519:                //           value into a URI.)
0520:                //        if (hints) {
0521:                //            len = vm.length;
0522:                //            nonCSSPresentationalHints = new HashSet();
0523:                //            nonCSSPresentationalHintsNamespaceURI = hintsNS;
0524:                //            for (int i = len - 1; i >= 0; --i) {
0525:                //                String pn = vm[i].getPropertyName();
0526:                //                nonCSSPresentationalHints.add(pn);
0527:                //            }
0528:                //        }
0529:                // END RAVE MODIFICATIONS
0530:                // </rave>
0531:
0532:                if (cssContext.isDynamic() && (document instanceof  EventTarget)) {
0533:                    // Attach the mutation events listeners.
0534:                    EventTarget et = (EventTarget) document;
0535:                    domAttrModifiedListener = new DOMAttrModifiedListener();
0536:                    et.addEventListener("DOMAttrModified",
0537:                            domAttrModifiedListener, false);
0538:                    domNodeInsertedListener = new DOMNodeInsertedListener();
0539:                    et.addEventListener("DOMNodeInserted",
0540:                            domNodeInsertedListener, false);
0541:                    domNodeRemovedListener = new DOMNodeRemovedListener();
0542:                    et.addEventListener("DOMNodeRemoved",
0543:                            domNodeRemovedListener, false);
0544:                    domSubtreeModifiedListener = new DOMSubtreeModifiedListener();
0545:                    et.addEventListener("DOMSubtreeModified",
0546:                            domSubtreeModifiedListener, false);
0547:                    domCharacterDataModifiedListener = new DOMCharacterDataModifiedListener();
0548:                    et.addEventListener("DOMCharacterDataModified",
0549:                            domCharacterDataModifiedListener, false);
0550:                    styleDeclarationUpdateHandler = new StyleDeclarationUpdateHandler();
0551:                }
0552:
0553:                ALL_PROPERTIES = new int[getNumberOfProperties()];
0554:                for (int i = getNumberOfProperties() - 1; i >= 0; --i) {
0555:                    ALL_PROPERTIES[i] = i;
0556:                }
0557:            }
0558:
0559:            /**
0560:             * Disposes the CSSEngine and all the attached resources.
0561:             */
0562:            public void dispose() {
0563:                setCSSEngineUserAgent(null);
0564:                disposeStyleMaps(document.getDocumentElement());
0565:                if (document instanceof  EventTarget) {
0566:                    // Detach the mutation events listeners.
0567:                    EventTarget et = (EventTarget) document;
0568:                    et.removeEventListener("DOMAttrModified",
0569:                            domAttrModifiedListener, false);
0570:                    et.removeEventListener("DOMNodeInserted",
0571:                            domNodeInsertedListener, false);
0572:                    et.removeEventListener("DOMNodeRemoved",
0573:                            domNodeRemovedListener, false);
0574:                    et.removeEventListener("DOMSubtreeModified",
0575:                            domSubtreeModifiedListener, false);
0576:                    et.removeEventListener("DOMCharacterDataModified",
0577:                            domCharacterDataModifiedListener, false);
0578:                }
0579:            }
0580:
0581:            // <rave>
0582:            // BEGIN RAVE MODIFICATIONS
0583:            //    private void disposeStyleMaps(Node node) {
0584:            protected void disposeStyleMaps(Node node) {
0585:                // END RAVE MODIFICATIONS
0586:                // </rave>
0587:                if (node instanceof  CSSStylableElement) {
0588:                    ((CSSStylableElement) node).setComputedStyleMap(null, null);
0589:                }
0590:                for (Node n = node.getFirstChild(); n != null; n = n
0591:                        .getNextSibling()) {
0592:                    if (n.getNodeType() == Node.ELEMENT_NODE) {
0593:                        disposeStyleMaps(n);
0594:                    }
0595:                    Node c = getImportedChild(n);
0596:                    if (c != null) {
0597:                        disposeStyleMaps(c);
0598:                    }
0599:                }
0600:            }
0601:
0602:            /**
0603:             * Returns the CSS context.
0604:             */
0605:            public CSSContext getCSSContext() {
0606:                return cssContext;
0607:            }
0608:
0609:            /**
0610:             * Returns the document associated with this engine.
0611:             */
0612:            public Document getDocument() {
0613:                return document;
0614:            }
0615:
0616:            /**
0617:             * Returns the font-size property index.
0618:             */
0619:            public int getFontSizeIndex() {
0620:                return fontSizeIndex;
0621:            }
0622:
0623:            /**
0624:             * Returns the line-height property index.
0625:             */
0626:            public int getLineHeightIndex() {
0627:                return lineHeightIndex;
0628:            }
0629:
0630:            /**
0631:             * Returns the color property index.
0632:             */
0633:            public int getColorIndex() {
0634:                return colorIndex;
0635:            }
0636:
0637:            /**
0638:             * Returns the number of properties.
0639:             */
0640:            public int getNumberOfProperties() {
0641:                return valueManagers.length;
0642:            }
0643:
0644:            /**
0645:             * Returns the property index, or -1.
0646:             */
0647:            public int getPropertyIndex(String name) {
0648:                return indexes.get(name);
0649:            }
0650:
0651:            /**
0652:             * Returns the shorthand property index, or -1.
0653:             */
0654:            public int getShorthandIndex(String name) {
0655:                return shorthandIndexes.get(name);
0656:            }
0657:
0658:            /**
0659:             * Returns the name of the property at the given index.
0660:             */
0661:            public String getPropertyName(int idx) {
0662:                return valueManagers[idx].getPropertyName();
0663:            }
0664:
0665:            public void setCSSEngineUserAgent(CSSEngineUserAgent userAgent) {
0666:                this .userAgent = userAgent;
0667:            }
0668:
0669:            public CSSEngineUserAgent getCSSEngineUserAgent() {
0670:                return userAgent;
0671:            }
0672:
0673:            /**
0674:             * Sets the user agent style-sheet.
0675:             */
0676:            public void setUserAgentStyleSheet(StyleSheet ss) {
0677:                userAgentStyleSheet = ss;
0678:            }
0679:
0680:            /**
0681:             * Sets the user style-sheet.
0682:             */
0683:            public void setUserStyleSheet(StyleSheet ss) {
0684:                userStyleSheet = ss;
0685:            }
0686:
0687:            /**
0688:             * Returns the ValueManagers.
0689:             */
0690:            public ValueManager[] getValueManagers() {
0691:                return valueManagers;
0692:            }
0693:
0694:            /**
0695:             * Sets the media to use to compute the styles.
0696:             */
0697:            public void setMedia(String str) {
0698:                try {
0699:                    media = parser.parseMedia(str);
0700:                } catch (Exception e) {
0701:                    String m = e.getMessage();
0702:                    if (m == null)
0703:                        m = "";
0704:                    String s = Messages.formatMessage("media.error",
0705:                            new Object[] { str, m });
0706:                    throw new DOMException(DOMException.SYNTAX_ERR, s);
0707:                }
0708:            }
0709:
0710:            /**
0711:             * Sets the alternate style-sheet title.
0712:             */
0713:            public void setAlternateStyleSheet(String str) {
0714:                alternateStyleSheet = str;
0715:            }
0716:
0717:            /**
0718:             * Recursively imports the cascaded style from a source element
0719:             * to an element of the current document.
0720:             */
0721:            public void importCascadedStyleMaps(Element src, CSSEngine srceng,
0722:                    Element dest) {
0723:                if (src instanceof  CSSStylableElement) {
0724:                    CSSStylableElement csrc = (CSSStylableElement) src;
0725:                    CSSStylableElement cdest = (CSSStylableElement) dest;
0726:
0727:                    StyleMap sm = srceng.getCascadedStyleMap(csrc, null);
0728:                    sm.setFixedCascadedStyle(true);
0729:                    cdest.setComputedStyleMap(null, sm);
0730:
0731:                    if (pseudoElementNames != null) {
0732:                        int len = pseudoElementNames.length;
0733:                        for (int i = 0; i < len; i++) {
0734:                            String pe = pseudoElementNames[i];
0735:                            sm = srceng.getCascadedStyleMap(csrc, pe);
0736:                            cdest.setComputedStyleMap(pe, sm);
0737:                        }
0738:                    }
0739:                }
0740:
0741:                for (Node dn = dest.getFirstChild(), sn = src.getFirstChild(); dn != null; dn = dn
0742:                        .getNextSibling(), sn = sn.getNextSibling()) {
0743:                    if (sn.getNodeType() == Node.ELEMENT_NODE) {
0744:                        importCascadedStyleMaps((Element) sn, srceng,
0745:                                (Element) dn);
0746:                    }
0747:                }
0748:            }
0749:
0750:            /**
0751:             * Returns the current base-url.
0752:             */
0753:            public URL getCSSBaseURI() {
0754:                if (cssBaseURI == null) {
0755:                    // <rave>
0756:                    // BEGIN RAVE MODIFICATIONS
0757:                    // We sometimes call the parser when there's no URI available (for example
0758:                    // as part of the CSS string parsing service.)  Make sure this isn't a 
0759:                    // big problem by providing a silly URL - resources won't be found in this
0760:                    // case. I should consider requiring a URL for the CSS parse requests...
0761:                    //cssBaseURI = element.getCSSBase();
0762:                    if (element == null) {
0763:                        // No valid URL (such as at style editing time when we're just
0764:                        // editing a stylesheet
0765:                        // Use dummy
0766:                        try {
0767:                            return new URL("http", "localhost", 80, "dummy");
0768:                        } catch (MalformedURLException mfue) {
0769:                        }
0770:                    } else {
0771:                        cssBaseURI = element.getCSSBase();
0772:                    }
0773:                    // ELSE RAVE MODIFICATIONS
0774:                    // </rave>
0775:                }
0776:                return cssBaseURI;
0777:            }
0778:
0779:            /**
0780:             * Returns the cascaded style of the given element/pseudo-element.
0781:             * @param elt The stylable element.
0782:             * @param pseudo Optional pseudo-element string (null if none).
0783:             */
0784:            public StyleMap getCascadedStyleMap(CSSStylableElement elt,
0785:                    String pseudo) {
0786:                int props = getNumberOfProperties();
0787:                StyleMap result = new StyleMap(props);
0788:
0789:                // Apply the user-agent style-sheet to the result.
0790:                if (userAgentStyleSheet != null) {
0791:                    List rules = new ArrayList();
0792:                    addMatchingRules(rules, userAgentStyleSheet, elt, pseudo);
0793:                    addRules(elt, pseudo, result, rules,
0794:                            StyleMap.USER_AGENT_ORIGIN);
0795:                }
0796:
0797:                // Apply the user properties style-sheet to the result.
0798:                if (userStyleSheet != null) {
0799:                    List rules = new ArrayList();
0800:                    addMatchingRules(rules, userStyleSheet, elt, pseudo);
0801:                    addRules(elt, pseudo, result, rules, StyleMap.USER_ORIGIN);
0802:                }
0803:
0804:                element = elt;
0805:                try {
0806:                    // Apply the non-CSS presentational hints to the result.
0807:                    // <rave>
0808:                    // BEGIN RAVE MODIFICATIONS
0809:                    applyNonCSSPresentationalHints(elt, result);
0810:                    //               This support was useless, it was simply aliasing CSS names
0811:                    //               to properties! But usually it's not a straight map!
0812:                    //               For example, the HTML attribute "background" maps to the
0813:                    //               CSS property "background-image" ! And the attribute "bgcolor"
0814:                    //               maps to the CSS property "background-color" !  
0815:                    //               So instead we'll handle this in subclasses where specific
0816:                    //               logic can be written (the attribute value often has to be
0817:                    //               special handled too so I can't just provide a map to CSSEngine;
0818:                    //               e.g. for "background" for example I need to change the string
0819:                    //               value into a URI.)
0820:                    //            if (nonCSSPresentationalHints != null) {
0821:                    //                NamedNodeMap attrs = elt.getAttributes();
0822:                    //                int len = attrs.getLength();
0823:                    //                for (int i = 0; i < len; i++) {
0824:                    //                    Node attr = attrs.item(i);
0825:                    //                    String an = attr.getNodeName();
0826:                    //                    if (nonCSSPresentationalHints.contains(an)) {
0827:                    //                        try {
0828:                    //                            LexicalUnit lu;
0829:                    //                            int idx = getPropertyIndex(an);
0830:                    //                            lu = parser.parsePropertyValue
0831:                    //                                (attr.getNodeValue());
0832:                    //                            ValueManager vm = valueManagers[idx];
0833:                    //                            Value v = vm.createValue(lu, this);
0834:                    //                            putAuthorProperty(result, idx, v, false,
0835:                    //                                              StyleMap.NON_CSS_ORIGIN);
0836:                    //                        } catch (Exception e) {
0837:                    //                            String m = e.getMessage();
0838:                    //                            if (m == null) m = "";
0839:                    //                            String u = ((documentURI == null)?"<unknown>":
0840:                    //                                        documentURI.toString());
0841:                    //                            String s = Messages.formatMessage
0842:                    //                                ("property.syntax.error.at",
0843:                    //                                 new Object[] { u, an, attr.getNodeValue(),m});
0844:                    //                            DOMException de = new DOMException(DOMException.SYNTAX_ERR, s);
0845:                    //                            de.initCause(e);
0846:                    //                            if (userAgent == null) throw de;
0847:                    //                            userAgent.displayError(de);
0848:                    //                        }
0849:                    //                    }
0850:                    //                }
0851:                    //            }
0852:                    // END RAVE MODIFICATIONS
0853:                    // </rave>
0854:
0855:                    // Apply the document style-sheets to the result.
0856:                    // <nb
0857:                    //            List snodes = getStyleSheetNodes();
0858:                    // ===
0859:                    List<WeakReference<CSSStyleSheetNode>> snodes = getStyleSheetNodes();
0860:                    // </nb>
0861:                    int slen = snodes.size();
0862:                    if (slen > 0) {
0863:                        List rules = new ArrayList();
0864:                        for (int i = 0; i < slen; i++) {
0865:                            // <nb>
0866:                            //                    CSSStyleSheetNode ssn = (CSSStyleSheetNode)snodes.get(i);
0867:                            // ===
0868:                            WeakReference<CSSStyleSheetNode> ssnWRef = snodes
0869:                                    .get(i);
0870:                            CSSStyleSheetNode ssn = ssnWRef == null ? null
0871:                                    : ssnWRef.get();
0872:                            if (ssn == null) {
0873:                                continue;
0874:                            }
0875:                            // </nb>
0876:                            StyleSheet ss = ssn.getCSSStyleSheet();
0877:                            if (ss != null
0878:                                    && (!ss.isAlternate()
0879:                                            || ss.getTitle() == null || ss
0880:                                            .getTitle().equals(
0881:                                                    alternateStyleSheet))
0882:                                    && mediaMatch(ss.getMedia())) {
0883:                                addMatchingRules(rules, ss, elt, pseudo);
0884:                            }
0885:                        }
0886:                        addRules(elt, pseudo, result, rules,
0887:                                StyleMap.AUTHOR_ORIGIN);
0888:                    }
0889:                    // <rave>
0890:                    // BEGIN RAVE MODIFICATIONS
0891:                    // Check if we have any transient stylesheet nodes to
0892:                    // consider
0893:                    if (transientStyleSheetNodes != null) {
0894:                        List rules = new ArrayList(transientStyleSheetNodes
0895:                                .size());
0896:                        for (int i = 0; i < transientStyleSheetNodes.size(); i++) {
0897:                            CSSStyleSheetNode ssn = (CSSStyleSheetNode) transientStyleSheetNodes
0898:                                    .get(i);
0899:                            StyleSheet ss = ssn.getCSSStyleSheet();
0900:                            if (ss != null
0901:                                    && (!ss.isAlternate()
0902:                                            || ss.getTitle() == null || ss
0903:                                            .getTitle().equals(
0904:                                                    alternateStyleSheet))
0905:                                    && mediaMatch(ss.getMedia())) {
0906:                                addMatchingRules(rules, ss, elt, pseudo);
0907:                            }
0908:                        }
0909:                        addRules(elt, pseudo, result, rules,
0910:                                StyleMap.AUTHOR_ORIGIN);
0911:                    }
0912:                    // END RAVE MODIFICATIONS
0913:                    // </rave>
0914:
0915:                    // Apply the inline style to the result.
0916:                    if (styleLocalName != null) {
0917:                        String style = elt.getAttributeNS(styleNamespaceURI,
0918:                                styleLocalName);
0919:                        if (style.length() > 0) {
0920:                            try {
0921:                                parser
0922:                                        .setSelectorFactory(CSSSelectorFactory.INSTANCE);
0923:                                parser.setConditionFactory(cssConditionFactory);
0924:                                styleDeclarationDocumentHandler.styleMap = result;
0925:                                parser
0926:                                        .setDocumentHandler(styleDeclarationDocumentHandler);
0927:                                // <rave>
0928:                                // BEGIN RAVE MODIFICATIONS
0929:                                styleDeclarationDocumentHandler.location = elt;
0930:                                styleDeclarationDocumentHandler.lineno = -1;
0931:                                // END RAVE MODIFICATIONS
0932:                                // </rave>
0933:                                parser.parseStyleDeclaration(style);
0934:                                styleDeclarationDocumentHandler.styleMap = null;
0935:                            } catch (Exception e) {
0936:                                String m = e.getMessage();
0937:                                if (m == null)
0938:                                    m = "";
0939:                                String u = ((documentURI == null) ? "<unknown>"
0940:                                        : documentURI.toString());
0941:                                String s = Messages.formatMessage(
0942:                                        "style.syntax.error.at", new Object[] {
0943:                                                u, styleLocalName, style, m });
0944:                                DOMException de = new DOMException(
0945:                                        DOMException.SYNTAX_ERR, s);
0946:                                // <rave>
0947:                                // BEGIN RAVE MODIFICATIONS
0948:                                de.initCause(e);
0949:                                // END RAVE MODIFICATIONS
0950:                                // </rave>
0951:                                if (userAgent == null)
0952:                                    throw de;
0953:                                userAgent.displayError(de);
0954:                            }
0955:                        }
0956:                    }
0957:                } finally {
0958:                    element = null;
0959:                    cssBaseURI = null;
0960:                }
0961:
0962:                return result;
0963:            }
0964:
0965:            // <rave>
0966:            // BEGIN RAVE MODIFICATIONS
0967:            /** Some error occurred while parsing stylesheet - display it to
0968:             * the developer */
0969:            protected void displayError(DOMException e, Object location,
0970:                    int lineno, int column) {
0971:                // Overridden in subclasses
0972:            }
0973:
0974:            protected void displayMissingStyleSheet(String uri) {
0975:                // Overridden in subclasses
0976:            }
0977:
0978:            /** 
0979:             * Shorthand property being set. Set when we're processing a shorthand property
0980:             * such that individual value managers can figure out that they're part of a shorthand
0981:             * property expansion (useful when creating error messages for example 
0982:             */
0983:            private int expandingShorthandProperty = -1;
0984:
0985:            /**
0986:             * Return the shorthand property being set. Set when we're processing a shorthand property
0987:             * such that individual value managers can figure out that they're part of a shorthand
0988:             * property expansion (useful when creating error messages for example. Returns null
0989:             * if no shorthand property is being processed.
0990:             */
0991:            public String getExpandingShorthandProperty() {
0992:                if (expandingShorthandProperty == -1) {
0993:                    return null;
0994:                } else {
0995:                    return shorthandManagers[expandingShorthandProperty]
0996:                            .getPropertyName();
0997:                }
0998:            }
0999:
1000:            /** Set the given element's value for a given attribute; if value is
1001:             * null, remove the attribute. */
1002:            protected void setAttributeValue(Element elt, String name,
1003:                    String value) {
1004:                // This sometimes throws ClassCastExceptions in Xerces -- why?
1005:                //elt.setAttributeNS(styleNamespaceURI, styleLocalName, value);
1006:                if (value != null) {
1007:                    elt.setAttribute(name, value);
1008:                } else {
1009:                    elt.removeAttribute(name);
1010:                }
1011:                /* CAST: Ah I think I know now: in the method they have this comment:
1012:
1013:                // This case may happen if user calls:
1014:                //      elem.setAttribute("name", "value");
1015:                //      elem.setAttributeNS(null, "name", "value");
1016:                // This case is not defined by the DOM spec, we choose
1017:                // to create a new attribute in this case and remove an old one from the tree
1018:                // note this might cause events to be propagated or user data to be lost 
1019:                
1020:                and then they proceed to cast to a CoreDocumentImpl... I bet
1021:                it's just not safe to mix setAttribute and setAttributeNS and
1022:                that's what we must have been doing ... so let's just switch.
1023:                 */
1024:            }
1025:
1026:            /**
1027:             * Scan attributes for an element and transcribe deprecated
1028:             * style-type attributes into real style properties
1029:             */
1030:            protected void applyNonCSSPresentationalHints(
1031:                    CSSStylableElement elt, StyleMap map) {
1032:                // Overridden in subclasses
1033:            }
1034:
1035:            /**
1036:             * For use by the implementation of applyNonCSSPresentationalHints;
1037:             * apply a non-presentational CSS hint as the given CSS value for
1038:             * the given CSS property.
1039:             */
1040:            protected void applyNonCSSPresentationalHint(
1041:                    CSSStylableElement elt, StyleMap map, int idx, String value) {
1042:                try {
1043:                    LexicalUnit lu = parser.parsePropertyValue(value);
1044:                    ValueManager vm = valueManagers[idx];
1045:                    try {
1046:                        Value v = vm.createValue(lu, this );
1047:
1048:                        if (v instanceof  AbstractValue) { // Should I add to Value interface???
1049:                            AbstractValue av = (AbstractValue) v;
1050:                            av.setLocation(elt);
1051:                            av.setLineNumber(-1);
1052:                        }
1053:
1054:                        putAuthorProperty(map, idx, v, false,
1055:                                StyleMap.NON_CSS_ORIGIN);
1056:                    } catch (DOMException e) {
1057:                        // Something bad happened
1058:                        displayError(e, elt, 0, 0);
1059:                        // Continue processing - we're supposed to ignore
1060:                        // errant declarations!!!
1061:                    }
1062:
1063:                } catch (Exception e) {
1064:                    // No longer used???
1065:                    String m = e.getMessage();
1066:                    if (m == null)
1067:                        m = "";
1068:                    String u = ((documentURI == null) ? "<unknown>"
1069:                            : documentURI.toString());
1070:                    String s = Messages.formatMessage // TODO: make our own message here
1071:                            ("property.syntax.error.at", new Object[] { u, "?",
1072:                                    value, m });
1073:                    DOMException de = new DOMException(DOMException.SYNTAX_ERR,
1074:                            s);
1075:                    de.initCause(e);
1076:                    if (userAgent == null)
1077:                        throw de;
1078:                    userAgent.displayError(de);
1079:                }
1080:            }
1081:
1082:            /**
1083:             * For use by the implementation of applyNonCSSPresentationalHints;
1084:             * apply a non-presentational CSS hint as the given CSS value for
1085:             * the given CSS property.
1086:             */
1087:            protected void applyNonCSSPresentationalHint(
1088:                    CSSStylableElement elt, StyleMap map, int idx, Value v) {
1089:                ValueManager vm = valueManagers[idx];
1090:                try {
1091:                    putAuthorProperty(map, idx, v, false,
1092:                            StyleMap.NON_CSS_ORIGIN);
1093:                } catch (DOMException e) {
1094:                    // Something bad happened
1095:                    displayError(e, elt, 0, 0);
1096:                    // Continue processing - we're supposed to ignore
1097:                    // errant declarations!!!
1098:                }
1099:            }
1100:
1101:            /** 
1102:             * Return true iff the given CSS property for the given element
1103:             * is not set, e.g. the default value would be returned instead.
1104:             * Note - it's not the same as asking if the property has the same
1105:             * value as its default property; this method will still return false
1106:             * in that case since it has a value set, so it doesn't have to pull
1107:             * the default value.
1108:             */
1109:            public boolean isDefaultValue(CSSStylableElement elt,
1110:                    String pseudo, int propidx) {
1111:                StyleMap sm = elt.getComputedStyleMap(pseudo);
1112:                if (sm == null) {
1113:                    sm = getCascadedStyleMap(elt, pseudo);
1114:                    elt.setComputedStyleMap(pseudo, sm);
1115:                }
1116:
1117:                Value value = sm.getValue(propidx);
1118:                if (value != null) {
1119:                    return false;
1120:                }
1121:                ValueManager vm = valueManagers[propidx];
1122:                CSSStylableElement p = getParentCSSStylableElement(elt);
1123:                if (value == null && (!vm.isInheritedProperty() || p == null)) {
1124:                    return true;
1125:                }
1126:                return false;
1127:            }
1128:
1129:            /** 
1130:             * Return true iff the given CSS property for the given element
1131:             * was inherited, as opposed to referenced directly by some rule.
1132:             */
1133:            public boolean isInheritedValue(CSSStylableElement elt, int propidx) {
1134:                // Make sure it's computed first
1135:                Value v = getComputedStyle(elt, null, propidx);
1136:                StyleMap sm = elt.getComputedStyleMap(null);
1137:                return sm.isInherited(propidx);
1138:            }
1139:
1140:            /** 
1141:             * Return a list of style classes defined in the stylesheets for
1142:             * this engine.  This will not include any styleclasses defined in
1143:             * the user agent stylesheet.
1144:             */
1145:            public Collection getStyleClasses() {
1146:                //ArrayList styleClasses = new ArrayList();
1147:                TreeSet styleClasses = new TreeSet();
1148:
1149:                // We don't want to list any styleclasses in the user agent stylesheet
1150:                if (userStyleSheet != null) {
1151:                    List rules = new ArrayList();
1152:                    addStyleClasses(styleClasses, userStyleSheet);
1153:                }
1154:
1155:                // Apply the document style-sheets to the result.
1156:                // <nb>
1157:                //        List snodes = getStyleSheetNodes();
1158:                // ===
1159:                List<WeakReference<CSSStyleSheetNode>> snodes = getStyleSheetNodes();
1160:                // </nb>
1161:                int slen = snodes.size();
1162:                if (slen > 0) {
1163:                    for (int i = 0; i < slen; i++) {
1164:                        // <nb>
1165:                        //                CSSStyleSheetNode ssn = (CSSStyleSheetNode)snodes.get(i);
1166:                        // ===
1167:                        WeakReference<CSSStyleSheetNode> ssnWRef = snodes
1168:                                .get(i);
1169:                        CSSStyleSheetNode ssn = ssnWRef == null ? null
1170:                                : ssnWRef.get();
1171:                        if (ssn == null) {
1172:                            continue;
1173:                        }
1174:                        // </nb>
1175:                        StyleSheet ss = ssn.getCSSStyleSheet();
1176:                        if (ss != null
1177:                                && (!ss.isAlternate() || ss.getTitle() == null || ss
1178:                                        .getTitle().equals(alternateStyleSheet))
1179:                                && mediaMatch(ss.getMedia())) {
1180:                            addStyleClasses(styleClasses, ss);
1181:                        }
1182:                    }
1183:                }
1184:                if (transientStyleSheetNodes != null) {
1185:                    for (int i = 0; i < transientStyleSheetNodes.size(); i++) {
1186:                        CSSStyleSheetNode ssn = (CSSStyleSheetNode) transientStyleSheetNodes
1187:                                .get(i);
1188:                        StyleSheet ss = ssn.getCSSStyleSheet();
1189:                        if (ss != null
1190:                                && (!ss.isAlternate() || ss.getTitle() == null || ss
1191:                                        .getTitle().equals(alternateStyleSheet))
1192:                                && mediaMatch(ss.getMedia())) {
1193:                            addStyleClasses(styleClasses, ss);
1194:                        }
1195:                    }
1196:                }
1197:                // Suppress duplicates
1198:                return styleClasses;
1199:            }
1200:
1201:            private void addStyleClasses(Collection styleClasses, StyleSheet ss) {
1202:                int len = ss.getSize();
1203:                for (int i = 0; i < len; i++) {
1204:                    Rule r = ss.getRule(i);
1205:                    switch (r.getType()) {
1206:                    case StyleRule.TYPE:
1207:                        StyleRule style = (StyleRule) r;
1208:                        SelectorList sl = style.getSelectorList();
1209:                        int slen = sl.getLength();
1210:                        for (int j = 0; j < slen; j++) {
1211:                            ExtendedSelector s = (ExtendedSelector) sl.item(j);
1212:                            if (s instanceof  CSSConditionalSelector) {
1213:                                CSSConditionalSelector cs = (CSSConditionalSelector) s;
1214:                                if (cs.getCondition() instanceof  CSSClassCondition) {
1215:                                    CSSClassCondition ck = (CSSClassCondition) cs
1216:                                            .getCondition();
1217:                                    styleClasses.add(ck.getValue());
1218:                                }
1219:                            }
1220:                        }
1221:                        break;
1222:
1223:                    case MediaRule.TYPE:
1224:                    case ImportRule.TYPE:
1225:                        MediaRule mr = (MediaRule) r;
1226:                        if (mediaMatch(mr.getMediaList())) {
1227:                            addStyleClasses(styleClasses, mr);
1228:                        }
1229:                        break;
1230:                    }
1231:                }
1232:            }
1233:
1234:            /** Return a display of the matching rules for the given element */
1235:            public String getMatchingRules(Element elt,
1236:                    boolean includeAgentRules) {
1237:                String pseudo = "";
1238:                StringBuffer sb = new StringBuffer(2000);
1239:
1240:                if (includeAgentRules) {
1241:                    // Apply the user-agent style-sheet to the result.
1242:                    if (userAgentStyleSheet != null) {
1243:                        List rules = new ArrayList();
1244:                        addMatchingRules(rules, userAgentStyleSheet, elt,
1245:                                pseudo);
1246:                        Iterator it = rules.iterator();
1247:                        if (it.hasNext()) {
1248:                            sb.append("Default User Agent Styles:\n");
1249:                        }
1250:                        while (it.hasNext()) {
1251:                            Rule rule = (Rule) it.next();
1252:                            sb.append(rule.toString(this ));
1253:                            sb.append("\n");
1254:                        }
1255:                    }
1256:                }
1257:
1258:                // Apply the user properties style-sheet to the result.
1259:                if (userStyleSheet != null) {
1260:                    List rules = new ArrayList();
1261:                    addMatchingRules(rules, userStyleSheet, elt, pseudo);
1262:                    Iterator it = rules.iterator();
1263:                    if (it.hasNext()) {
1264:                        sb.append("Default User Styles:\n");
1265:                    }
1266:                    while (it.hasNext()) {
1267:                        Rule rule = (Rule) it.next();
1268:                        sb.append(rule.toString(this ));
1269:                        sb.append("\n");
1270:                    }
1271:                }
1272:
1273:                // Apply the document style-sheets to the result.
1274:                // <nb>
1275:                //        List snodes = getStyleSheetNodes();
1276:                // ===
1277:                List<WeakReference<CSSStyleSheetNode>> snodes = getStyleSheetNodes();
1278:                // </nb>
1279:                int slen = snodes.size();
1280:                if (slen > 0) {
1281:                    for (int i = 0; i < slen; i++) {
1282:                        // <nb>
1283:                        //                CSSStyleSheetNode ssn = (CSSStyleSheetNode)snodes.get(i);
1284:                        // ===
1285:                        WeakReference<CSSStyleSheetNode> ssnWRef = snodes
1286:                                .get(i);
1287:                        CSSStyleSheetNode ssn = ssnWRef == null ? null
1288:                                : ssnWRef.get();
1289:                        if (ssn == null) {
1290:                            continue;
1291:                        }
1292:                        // </nb>
1293:                        StyleSheet ss = ssn.getCSSStyleSheet();
1294:                        if (ss != null
1295:                                && (!ss.isAlternate() || ss.getTitle() == null || ss
1296:                                        .getTitle().equals(alternateStyleSheet))
1297:                                && mediaMatch(ss.getMedia())) {
1298:                            List rules = new ArrayList();
1299:                            addMatchingRules(rules, ss, elt, pseudo);
1300:                            Iterator it = rules.iterator();
1301:                            if (it.hasNext()) {
1302:                                sb.append(ss.getTitle() + ":\n");
1303:                            }
1304:                            while (it.hasNext()) {
1305:                                Rule rule = (Rule) it.next();
1306:                                sb.append(rule.toString(this ));
1307:                                sb.append("\n");
1308:                            }
1309:                        }
1310:                    }
1311:                }
1312:
1313:                // Check if we have any transient stylesheet nodes to
1314:                // consider
1315:                if (transientStyleSheetNodes != null) {
1316:                    for (int i = 0; i < transientStyleSheetNodes.size(); i++) {
1317:                        CSSStyleSheetNode ssn = (CSSStyleSheetNode) transientStyleSheetNodes
1318:                                .get(i);
1319:                        StyleSheet ss = ssn.getCSSStyleSheet();
1320:                        if (ss != null
1321:                                && (!ss.isAlternate() || ss.getTitle() == null || ss
1322:                                        .getTitle().equals(alternateStyleSheet))
1323:                                && mediaMatch(ss.getMedia())) {
1324:                            List rules = new ArrayList();
1325:                            addMatchingRules(rules, ss, elt, pseudo);
1326:                            Iterator it = rules.iterator();
1327:                            if (it.hasNext()) {
1328:                                sb.append(ss.getTitle() + ":\n");
1329:                            }
1330:                            while (it.hasNext()) {
1331:                                Rule rule = (Rule) it.next();
1332:                                sb.append(rule.toString(this ));
1333:                                sb.append("\n");
1334:                            }
1335:                        }
1336:                    }
1337:                }
1338:
1339:                String style = elt.getAttribute(styleLocalName);
1340:                if (style.length() > 0) {
1341:                    sb.append("style=\"" + style + "\"\n");
1342:                }
1343:
1344:                return sb.toString();
1345:            }
1346:
1347:            /**
1348:             * Updates the local styles for an element. First any style settings
1349:             * in the set parameter array are applied, then any properties
1350:             * pointed to by the remove array are applied.
1351:             * @return The new style string
1352:             */
1353:            public String getUpdatedLocalStyleValues(CSSStylableElement elt,
1354:                    StyleSetting[] stylesToSet, StyleSetting[] stylesToRemove)
1355:                    throws Exception {
1356:                String style = elt.getAttributeNS(styleNamespaceURI,
1357:                        styleLocalName);
1358:                StringBuffer styleBuffer = new StringBuffer(200);
1359:                if (style.length() > 0) {
1360:                    styleBuffer.append(style);
1361:                }
1362:                if (stylesToSet != null) {
1363:                    for (int i = 0; i < stylesToSet.length; i++) {
1364:                        StyleSetting setting = stylesToSet[i];
1365:                        if (styleBuffer.length() > 0) {
1366:                            styleBuffer.append("; ");
1367:                        }
1368:                        styleBuffer.append(getPropertyName(setting.getIndex()));
1369:                        styleBuffer.append(":");
1370:                        styleBuffer.append(setting.getValue());
1371:                    }
1372:                }
1373:                style = styleBuffer.toString();
1374:
1375:                CSSStylableElement old = element;
1376:                try {
1377:                    int props = getNumberOfProperties();
1378:                    StyleMap result = new StyleMap(props);
1379:                    element = (CSSStylableElement) elt;
1380:
1381:                    unknownPropertyNames = new ArrayList();
1382:                    unknownPropertyValues = new ArrayList();
1383:                    parser.setSelectorFactory(CSSSelectorFactory.INSTANCE);
1384:                    parser.setConditionFactory(cssConditionFactory);
1385:                    styleDeclarationDocumentHandler.styleMap = result;
1386:                    parser.setDocumentHandler(styleDeclarationDocumentHandler);
1387:                    styleDeclarationDocumentHandler.location = elt;
1388:                    styleDeclarationDocumentHandler.lineno = -1;
1389:                    parser.parseStyleDeclaration(style);
1390:                    styleDeclarationDocumentHandler.styleMap = null;
1391:
1392:                    // Perform deletions
1393:                    if (stylesToRemove != null) {
1394:                        StyleMap sm = elt.getComputedStyleMap(null); // XXX what do we use for pseudo?
1395:                        for (int i = 0; i < stylesToRemove.length; i++) {
1396:                            StyleSetting setting = stylesToRemove[i];
1397:                            // Remove properties
1398:                            result.putValue(setting.getIndex(), null);
1399:                            if (sm != null) {
1400:                                sm.putValue(setting.getIndex(), null);
1401:                            }
1402:                        }
1403:                    }
1404:
1405:                    // Get stylemap back as a string...
1406:                    //String s = result.toStyleString(this);
1407:                    String s = toMinimalStyleString(result);
1408:
1409:                    // Append "unknown" styles
1410:                    if (unknownPropertyNames.size() > 0) {
1411:                        StringBuffer sb = new StringBuffer(s.length()
1412:                                + unknownPropertyNames.size() * 30);
1413:                        sb.append(s);
1414:                        for (int i = 0, n = unknownPropertyNames.size(); i < n; i++) {
1415:                            if (sb.length() > 0) {
1416:                                sb.append(';');
1417:                                sb.append(' ');
1418:                            }
1419:                            sb.append(unknownPropertyNames.get(i).toString());
1420:                            sb.append(':');
1421:                            sb.append(' ');
1422:                            sb.append(unknownPropertyValues.get(i).toString());
1423:                        }
1424:                        s = sb.toString();
1425:                    }
1426:
1427:                    if (s.length() == 0) {
1428:                        s = null;
1429:                    }
1430:
1431:                    // <removing design bean manipulation in engine>
1432:                    //            setAttributeValue(elt, styleLocalName, s);
1433:                    // </removing design bean manipulation in engine>
1434:
1435:                    return s;
1436:
1437:                } catch (Exception e) {
1438:                    String m = e.getMessage();
1439:                    if (m == null)
1440:                        m = "";
1441:                    String u = ((documentURI == null) ? "<unknown>"
1442:                            : documentURI.toString());
1443:                    String s = Messages.formatMessage("style.syntax.error.at",
1444:                            new Object[] { u, styleLocalName, style, m });
1445:                    DOMException de = new DOMException(DOMException.SYNTAX_ERR,
1446:                            s);
1447:                    de.initCause(e);
1448:                    if (userAgent == null)
1449:                        throw de;
1450:                    userAgent.displayError(de);
1451:
1452:                    // <removing design bean manipulation in engine>
1453:                    //            return null;
1454:                    // ====
1455:                    throw de;
1456:                    // </removing design bean manipulation in engine>
1457:                } finally {
1458:                    unknownPropertyNames = null;
1459:                    unknownPropertyValues = null;
1460:                    element = old;
1461:                }
1462:            }
1463:
1464:            /** When non null, stores a list of properties that were not recognized.
1465:             * This is only currently done for parsing of style expressions, not style
1466:             * sheets, since it's used for local style element manipulation.
1467:             */
1468:            protected List unknownPropertyNames;
1469:            protected List unknownPropertyValues;
1470:
1471:            /** Given a lexical unit value, produce its CSS value expression
1472:             * string by appending into the given StringBuffer. This is a
1473:             * "toString()" like method I think LexicalUnit should have
1474:             * offered. I really just want the "r-value" from a style
1475:             * declaration, but the parser doesn't keep it around so we have to
1476:             * reconstruct it from lexical tokens.
1477:             */
1478:            private void appendCss(StringBuffer sb, LexicalUnit value) {
1479:                while (value != null) {
1480:                    switch (value.getLexicalUnitType()) {
1481:
1482:                    case LexicalUnit.SAC_OPERATOR_COMMA:
1483:                        sb.append(",");
1484:                        break; // NOI18N
1485:                    case LexicalUnit.SAC_OPERATOR_PLUS:
1486:                        sb.append("+");
1487:                        break; // NOI18N
1488:                    case LexicalUnit.SAC_OPERATOR_MINUS:
1489:                        sb.append("-");
1490:                        break; // NOI18N
1491:                    case LexicalUnit.SAC_OPERATOR_MULTIPLY:
1492:                        sb.append("*");
1493:                        break; // NOI18N
1494:                    case LexicalUnit.SAC_OPERATOR_SLASH:
1495:                        sb.append("/");
1496:                        break; // NOI18N
1497:                    case LexicalUnit.SAC_OPERATOR_MOD:
1498:                        sb.append("%");
1499:                        break; // NOI18N
1500:                    case LexicalUnit.SAC_OPERATOR_EXP:
1501:                        sb.append("^");
1502:                        break; // NOI18N
1503:                    case LexicalUnit.SAC_OPERATOR_LT:
1504:                        sb.append("<");
1505:                        break; // NOI18N
1506:                    case LexicalUnit.SAC_OPERATOR_GT:
1507:                        sb.append(">");
1508:                        break; // NOI18N
1509:                    case LexicalUnit.SAC_OPERATOR_LE:
1510:                        sb.append("<=");
1511:                        break; // NOI18N
1512:                    case LexicalUnit.SAC_OPERATOR_GE:
1513:                        sb.append(">=");
1514:                        break; // NOI18N
1515:                    case LexicalUnit.SAC_OPERATOR_TILDE:
1516:                        sb.append("~");
1517:                        break; // NOI18N
1518:                    case LexicalUnit.SAC_INHERIT:
1519:                        sb.append("inherit");
1520:                        break; // NOI18N
1521:                    case LexicalUnit.SAC_INTEGER:
1522:                        sb.append(Integer.toString(value.getIntegerValue()));
1523:                        break;
1524:                    case LexicalUnit.SAC_REAL:
1525:                        sb.append(Float.toString(value.getFloatValue()));
1526:                        break;
1527:                    case LexicalUnit.SAC_EM:
1528:                        sb.append(Float.toString(value.getFloatValue())
1529:                                + value.getDimensionUnitText());
1530:                        break;
1531:                    case LexicalUnit.SAC_EX:
1532:                        sb.append(Float.toString(value.getFloatValue())
1533:                                + value.getDimensionUnitText());
1534:                        break;
1535:                    case LexicalUnit.SAC_PIXEL:
1536:                        sb.append(Float.toString(value.getFloatValue())
1537:                                + value.getDimensionUnitText());
1538:                        break;
1539:                    case LexicalUnit.SAC_INCH:
1540:                        sb.append(Float.toString(value.getFloatValue())
1541:                                + value.getDimensionUnitText());
1542:                        break;
1543:                    case LexicalUnit.SAC_CENTIMETER:
1544:                        sb.append(Float.toString(value.getFloatValue())
1545:                                + value.getDimensionUnitText());
1546:                        break;
1547:                    case LexicalUnit.SAC_MILLIMETER:
1548:                        sb.append(Float.toString(value.getFloatValue())
1549:                                + value.getDimensionUnitText());
1550:                        break;
1551:                    case LexicalUnit.SAC_POINT:
1552:                        sb.append(Float.toString(value.getFloatValue())
1553:                                + value.getDimensionUnitText());
1554:                        break;
1555:                    case LexicalUnit.SAC_PICA:
1556:                        sb.append(Float.toString(value.getFloatValue())
1557:                                + value.getDimensionUnitText());
1558:                        break;
1559:                    case LexicalUnit.SAC_PERCENTAGE:
1560:                        sb.append(Float.toString(value.getFloatValue())
1561:                                + value.getDimensionUnitText());
1562:                        break;
1563:                    case LexicalUnit.SAC_URI:
1564:                        sb.append("uri(" + value.getStringValue() + ")");
1565:                        break; // NOI18N
1566:                    case LexicalUnit.SAC_DEGREE:
1567:                        sb.append(Float.toString(value.getFloatValue())
1568:                                + value.getDimensionUnitText());
1569:                        break;
1570:                    case LexicalUnit.SAC_GRADIAN:
1571:                        sb.append(Float.toString(value.getFloatValue())
1572:                                + value.getDimensionUnitText());
1573:                        break;
1574:                    case LexicalUnit.SAC_RADIAN:
1575:                        sb.append(Float.toString(value.getFloatValue())
1576:                                + value.getDimensionUnitText());
1577:                        break;
1578:                    case LexicalUnit.SAC_MILLISECOND:
1579:                        sb.append(Float.toString(value.getFloatValue())
1580:                                + value.getDimensionUnitText());
1581:                        break;
1582:                    case LexicalUnit.SAC_SECOND:
1583:                        sb.append(Float.toString(value.getFloatValue())
1584:                                + value.getDimensionUnitText());
1585:                        break;
1586:                    case LexicalUnit.SAC_HERTZ:
1587:                        sb.append(Float.toString(value.getFloatValue())
1588:                                + value.getDimensionUnitText());
1589:                        break;
1590:                    case LexicalUnit.SAC_KILOHERTZ:
1591:                        sb.append(Float.toString(value.getFloatValue())
1592:                                + value.getDimensionUnitText());
1593:                        break;
1594:                    case LexicalUnit.SAC_IDENT:
1595:                        sb.append(value.getStringValue());
1596:                        break;
1597:                    case LexicalUnit.SAC_STRING_VALUE:
1598:                        sb.append("\"" + value.getStringValue() + "\"");
1599:                        break;
1600:                    case LexicalUnit.SAC_ATTR:
1601:                        sb.append(value.getStringValue());
1602:                        break;
1603:                    case LexicalUnit.SAC_DIMENSION:
1604:                        sb.append(Float.toString(value.getFloatValue()));
1605:                        break;
1606:
1607:                    // XXX not yet supported, SAC doesn't yet handle
1608:                    case LexicalUnit.SAC_UNICODERANGE:
1609:                        break; // NOI18N
1610:
1611:                    case LexicalUnit.SAC_SUB_EXPRESSION:
1612:                        sb.append("("); // NOI18N
1613:                        appendCss(sb, value.getSubValues());
1614:                        sb.append(")"); // NOI18N
1615:                        break;
1616:
1617:                    case LexicalUnit.SAC_RGBCOLOR:
1618:                        // TODO  - convert to hex instead? e.g. #FFFFFF
1619:                        sb.append("rgb"); // NOI18N
1620:                        sb.append("("); // NOI18N
1621:                        appendCss(sb, value.getParameters());
1622:                        sb.append(")"); // NOI18N
1623:                        break;
1624:                    case LexicalUnit.SAC_COUNTER_FUNCTION:
1625:                        sb.append("counter"); // NOI18N
1626:                        sb.append("("); // NOI18N
1627:                        appendCss(sb, value.getParameters());
1628:                        sb.append(")"); // NOI18N
1629:                        break;
1630:                    case LexicalUnit.SAC_COUNTERS_FUNCTION:
1631:                        sb.append("counters"); // NOI18N
1632:                        sb.append("("); // NOI18N
1633:                        appendCss(sb, value.getParameters());
1634:                        sb.append(")"); // NOI18N
1635:                        break;
1636:                    case LexicalUnit.SAC_RECT_FUNCTION:
1637:                        sb.append("rect"); // NOI18N
1638:                        sb.append("("); // NOI18N
1639:                        appendCss(sb, value.getParameters());
1640:                        sb.append(")"); // NOI18N
1641:                        break;
1642:                    case LexicalUnit.SAC_FUNCTION:
1643:                        sb.append(value.getFunctionName());
1644:                        sb.append("("); // NOI18N
1645:                        appendCss(sb, value.getParameters());
1646:                        sb.append(")"); // NOI18N
1647:                        break;
1648:                    }
1649:
1650:                    value = value.getNextLexicalUnit();
1651:                    if (value != null) {
1652:                        sb.append(' ');
1653:                    }
1654:                }
1655:            }
1656:
1657:            /** Notify the engine that a new style element has been 
1658:             * created
1659:             */
1660:            public void addTransientStyleSheetNode(CSSStyleSheetNode elt) {
1661:                if (transientStyleSheetNodes == null) {
1662:                    transientStyleSheetNodes = new ArrayList();
1663:                }
1664:                transientStyleSheetNodes.add(elt);
1665:            }
1666:
1667:            public void clearTransientStyleSheetNodes() {
1668:                transientStyleSheetNodes = null;
1669:            }
1670:
1671:            private ArrayList transientStyleSheetNodes;
1672:
1673:            protected void warnCircularReference(URL uri, Object location) {
1674:                System.err.println("Circular reference: " + uri);
1675:            }
1676:
1677:            /** For statistics gathering during development */
1678:            public static int styleLookupCount = 0;
1679:
1680:            /**
1681:             * Constant which indicates that the given stylesheet is being parsed. Used
1682:             * to avoid circular references.
1683:             */
1684:            public final static StyleSheet PARSING_SHEET = new StyleSheet();
1685:
1686:            // END RAVE MODIFICATIONS
1687:            // </rave>
1688:            /**
1689:             * Returns the computed style of the given element/pseudo for the
1690:             * property corresponding to the given index.
1691:             */
1692:            public Value getComputedStyle(CSSStylableElement elt,
1693:                    String pseudo, int propidx) {
1694:                // <rave>
1695:                // BEGIN RAVE MODIFICATIONS
1696:                styleLookupCount++;
1697:                // END RAVE MODIFICATIONS
1698:                // </rave>
1699:
1700:                StyleMap sm = elt.getComputedStyleMap(pseudo);
1701:                if (sm == null) {
1702:                    sm = getCascadedStyleMap(elt, pseudo);
1703:                    elt.setComputedStyleMap(pseudo, sm);
1704:                }
1705:
1706:                Value value = sm.getValue(propidx);
1707:                if (!sm.isComputed(propidx)) {
1708:                    Value result = value;
1709:                    ValueManager vm = valueManagers[propidx];
1710:                    CSSStylableElement p = getParentCSSStylableElement(elt);
1711:                    if (value == null
1712:                            && (!vm.isInheritedProperty() || p == null)) {
1713:                        result = vm.getDefaultValue();
1714:                    } else if (value != null
1715:                            && (value == InheritValue.INSTANCE) && p != null) {
1716:                        result = null;
1717:                    }
1718:                    if (result == null) {
1719:                        // Value is 'inherit' and p != null.
1720:                        // The pseudo class is not propagated.
1721:                        result = getComputedStyle(p, null, propidx);
1722:                        sm.putParentRelative(propidx, true);
1723:                        // <rave>
1724:                        // BEGIN RAVE MODIFICATIONS
1725:                        sm.putInherited(propidx, true);
1726:                        // END RAVE MODIFICATIONS
1727:                        // </rave>
1728:                    } else {
1729:                        // Maybe is it a relative value.
1730:                        result = vm.computeValue(elt, pseudo, this , propidx,
1731:                                sm, result);
1732:                    }
1733:                    if (value == null) {
1734:                        sm.putValue(propidx, result);
1735:                        sm.putNullCascaded(propidx, true);
1736:                        // <rave>
1737:                        // BEGIN RAVE MODIFICATIONS
1738:                    } else if (value == InheritValue.INSTANCE) {
1739:                        // Do nothing; rather than produce a new ComputedValue,
1740:                        // just inherit the value directly. That way we don't
1741:                        // end up with "wrapped" versions of values that are
1742:                        // part of an IDENT list, such as Vertical Alignments.
1743:                        // This breaks checking value == CssValueConstants.FOO_VALUE
1744:                        // for example.
1745:                        sm.putValue(propidx, result);
1746:                        sm.putInherited(propidx, true);
1747:                        // END RAVE MODIFICATIONS
1748:                        // </rave>
1749:                    } else if (result != value) {
1750:                        ComputedValue cv = new ComputedValue(value);
1751:                        cv.setComputedValue(result);
1752:                        sm.putValue(propidx, cv);
1753:                        result = cv;
1754:                    }
1755:                    sm.putComputed(propidx, true);
1756:                    value = result;
1757:                }
1758:                return value;
1759:            }
1760:
1761:            /**
1762:             * Returns the document CSSStyleSheetNodes in a list. This list is
1763:             * updated as the document is modified.
1764:             */
1765:            // <nb>
1766:            //    public List getStyleSheetNodes() {
1767:            // ===
1768:            public List<WeakReference<CSSStyleSheetNode>> getStyleSheetNodes() {
1769:                // </nb>
1770:                // XXX #126462 Checking style sheet nodes cache.
1771:                boolean discardOldCache = false;
1772:                if (styleSheetNodes != null) {
1773:                    for (WeakReference<CSSStyleSheetNode> styleSheetNodeWRef : styleSheetNodes) {
1774:                        CSSStyleSheetNode ssnode = styleSheetNodeWRef == null ? null
1775:                                : styleSheetNodeWRef.get();
1776:                        if (ssnode == null) {
1777:                            // The node was garbaged, refresh.
1778:                            discardOldCache = true;
1779:                            break;
1780:                        } else if (ssnode instanceof  Element) {
1781:                            Element ssElement = (Element) ssnode;
1782:                            if (ssElement.getParentNode() == null) {
1783:                                // The node was probably removed from the document, refresh.
1784:                                discardOldCache = true;
1785:                                break;
1786:                            }
1787:                            // XXX TODO It seems there is always source document present,
1788:                            // even the rendered elements are computed here. (Investigate!).
1789:                            //                        else if (ssElement.getOwnerDocument() != document) {
1790:                            //                            // The node doesn't belong to this document, refresh.
1791:                            //                            discardOldCache = true;
1792:                            //                            break;
1793:                            //                        }
1794:                        }
1795:                    }
1796:                }
1797:                if (discardOldCache) {
1798:                    styleSheetNodes = null;
1799:                }
1800:
1801:                if (styleSheetNodes == null) {
1802:                    // <nb>
1803:                    //            styleSheetNodes = new ArrayList();
1804:                    // ===
1805:                    styleSheetNodes = new ArrayList<WeakReference<CSSStyleSheetNode>>();
1806:                    // </nb>
1807:                    // <rave>
1808:                    if (document == null) {
1809:                        return styleSheetNodes;
1810:                    }
1811:                    // </rave>
1812:                    selectorAttributes = new HashSet();
1813:                    // Find all the style-sheets in the document.
1814:                    // <rave>
1815:                    //            findSylesSheetNodes(document);
1816:                    findStyleSheetNodes();
1817:                    // </rave>
1818:                    int len = styleSheetNodes.size();
1819:                    for (int i = 0; i < len; i++) {
1820:                        CSSStyleSheetNode ssn;
1821:                        // <nb>
1822:                        //                ssn = (CSSStyleSheetNode)styleSheetNodes.get(i);
1823:                        // ===
1824:                        WeakReference<CSSStyleSheetNode> ssnWRef = styleSheetNodes
1825:                                .get(i);
1826:                        ssn = ssnWRef == null ? null : ssnWRef.get();
1827:                        // </nb
1828:                        StyleSheet ss = ssn.getCSSStyleSheet();
1829:                        if (ss != null) {
1830:                            findSelectorAttributes(selectorAttributes, ss);
1831:                        }
1832:                    }
1833:                }
1834:                return styleSheetNodes;
1835:            }
1836:
1837:            // <rave>
1838:            protected void findStyleSheetNodes() {
1839:                findStyleSheetNodes(document);
1840:            }
1841:
1842:            /**
1843:             * Try to create a minimal (as short as possible) style string
1844:             * from this map, by using shortcuts when possible.
1845:             * This will for example compress border-color-left/right/bottom/top
1846:             * into border-color: one two three four, and so on.
1847:             *
1848:             * The default implementation just passes serializes the map directly.
1849:             */
1850:            protected String toMinimalStyleString(StyleMap map) {
1851:                return map.toStyleString(this );
1852:            }
1853:
1854:            // </rave>
1855:            /**
1856:             * An auxiliary method for getStyleSheets().
1857:             */
1858:            protected void findStyleSheetNodes(Node n) {
1859:                if (n instanceof  CSSStyleSheetNode) {
1860:                    // <nb>
1861:                    //            styleSheetNodes.add(n);
1862:                    // ===
1863:                    styleSheetNodes.add(new WeakReference<CSSStyleSheetNode>(
1864:                            (CSSStyleSheetNode) n));
1865:                    // </nb>
1866:                }
1867:                for (Node nd = n.getFirstChild(); nd != null; nd = nd
1868:                        .getNextSibling()) {
1869:                    findStyleSheetNodes(nd);
1870:                }
1871:            }
1872:
1873:            /**
1874:             * Finds the selector attributes in the given stylesheet.
1875:             */
1876:            protected void findSelectorAttributes(Set attrs, StyleSheet ss) {
1877:                int len = ss.getSize();
1878:                for (int i = 0; i < len; i++) {
1879:                    Rule r = ss.getRule(i);
1880:                    switch (r.getType()) {
1881:                    case StyleRule.TYPE:
1882:                        StyleRule style = (StyleRule) r;
1883:                        SelectorList sl = style.getSelectorList();
1884:                        int slen = sl.getLength();
1885:                        for (int j = 0; j < slen; j++) {
1886:                            ExtendedSelector s = (ExtendedSelector) sl.item(j);
1887:                            s.fillAttributeSet(attrs);
1888:                        }
1889:                        break;
1890:
1891:                    case MediaRule.TYPE:
1892:                    case ImportRule.TYPE:
1893:                        MediaRule mr = (MediaRule) r;
1894:                        if (mediaMatch(mr.getMediaList())) {
1895:                            findSelectorAttributes(attrs, mr);
1896:                        }
1897:                        break;
1898:                    }
1899:                }
1900:            }
1901:
1902:            /**
1903:             * Interface for people interesting in having 'primary' properties
1904:             * set.  Shorthand properties will be expanded "automatically".
1905:             */
1906:            public interface MainPropertyReceiver {
1907:                /**
1908:                 * Called with a non-shorthand property name and it's value.
1909:                 */
1910:                public void setMainProperty(String name, Value v,
1911:                        boolean important);
1912:            };
1913:
1914:            public void setMainProperties(CSSStylableElement elt,
1915:                    final MainPropertyReceiver dst, String pname, String value,
1916:                    boolean important) {
1917:                try {
1918:                    element = elt;
1919:                    LexicalUnit lu = parser.parsePropertyValue(value);
1920:                    ShorthandManager.PropertyHandler ph = new ShorthandManager.PropertyHandler() {
1921:                        public void property(String pname, LexicalUnit lu,
1922:                                boolean important) {
1923:                            int idx = getPropertyIndex(pname);
1924:                            if (idx != -1) {
1925:                                ValueManager vm = valueManagers[idx];
1926:                                Value v = vm.createValue(lu, CSSEngine.this );
1927:                                dst.setMainProperty(pname, v, important);
1928:                                return;
1929:                            }
1930:                            idx = getShorthandIndex(pname);
1931:                            if (idx == -1)
1932:                                return; // Unknown property...
1933:                            // Shorthand value
1934:                            // <rave>
1935:                            // BEGIN RAVE MODIFICATIONS
1936:                            expandingShorthandProperty = idx;
1937:                            // END RAVE MODIFICATIONS
1938:                            // </rave>
1939:                            shorthandManagers[idx].setValues(CSSEngine.this ,
1940:                                    this , lu, important);
1941:                            // <rave>
1942:                            // BEGIN RAVE MODIFICATIONS
1943:                            expandingShorthandProperty = -1;
1944:                            // END RAVE MODIFICATIONS
1945:                            // </rave>
1946:                        }
1947:                    };
1948:                    ph.property(pname, lu, important);
1949:                } catch (Exception e) {
1950:                    String m = e.getMessage();
1951:                    if (m == null)
1952:                        m = "";
1953:                    String u = ((documentURI == null) ? "<unknown>"
1954:                            : documentURI.toString());
1955:                    String s = Messages.formatMessage(
1956:                            "property.syntax.error.at", new Object[] { u,
1957:                                    pname, value, m });
1958:                    DOMException de = new DOMException(DOMException.SYNTAX_ERR,
1959:                            s);
1960:                    // <rave>
1961:                    // BEGIN RAVE MODIFICATIONS
1962:                    de.initCause(e);
1963:                    // END RAVE MODIFICATIONS
1964:                    // </rave>
1965:                    if (userAgent == null)
1966:                        throw de;
1967:                    userAgent.displayError(de);
1968:                } finally {
1969:                    element = null;
1970:                    cssBaseURI = null;
1971:                }
1972:            }
1973:
1974:            /**
1975:             * Parses and creates a property value from elt.
1976:             * @param elt  The element property is from.
1977:             * @param prop The property name.
1978:             * @param value The property value.
1979:             */
1980:            public Value parsePropertyValue(CSSStylableElement elt,
1981:                    String prop, String value) {
1982:                int idx = getPropertyIndex(prop);
1983:                if (idx == -1)
1984:                    return null;
1985:                ValueManager vm = valueManagers[idx];
1986:                try {
1987:                    element = elt;
1988:                    LexicalUnit lu;
1989:                    lu = parser.parsePropertyValue(value);
1990:                    return vm.createValue(lu, this );
1991:                    // BEGIN RAVE MODIFICATIONS
1992:                    // XXX when is this used?
1993:                    // END RAVE MODIFICATIONS
1994:                } catch (Exception e) {
1995:                    String m = e.getMessage();
1996:                    if (m == null)
1997:                        m = "";
1998:                    String u = ((documentURI == null) ? "<unknown>"
1999:                            : documentURI.toString());
2000:                    String s = Messages.formatMessage(
2001:                            "property.syntax.error.at", new Object[] { u, prop,
2002:                                    value, m });
2003:                    DOMException de = new DOMException(DOMException.SYNTAX_ERR,
2004:                            s);
2005:                    // <rave>
2006:                    // BEGIN RAVE MODIFICATIONS
2007:                    de.initCause(e);
2008:                    // END RAVE MODIFICATIONS
2009:                    // </rave>
2010:                    if (userAgent == null)
2011:                        throw de;
2012:                    userAgent.displayError(de);
2013:                } finally {
2014:                    element = null;
2015:                    cssBaseURI = null;
2016:                }
2017:                return vm.getDefaultValue();
2018:            }
2019:
2020:            /**
2021:             * Parses and creates a style declaration.
2022:             * @param value The style declaration text.
2023:             */
2024:            public StyleDeclaration parseStyleDeclaration(
2025:                    CSSStylableElement elt, String value) {
2026:                styleDeclarationBuilder.styleDeclaration = new StyleDeclaration();
2027:                try {
2028:                    element = elt;
2029:                    parser.setSelectorFactory(CSSSelectorFactory.INSTANCE);
2030:                    parser.setConditionFactory(cssConditionFactory);
2031:                    parser.setDocumentHandler(styleDeclarationBuilder);
2032:                    // <rave>
2033:                    // BEGIN RAVE MODIFICATIONS
2034:                    styleDeclarationBuilder.location = elt;
2035:                    styleDeclarationBuilder.lineno = -1;
2036:                    // END RAVE MODIFICATIONS
2037:                    // </rave>
2038:                    parser.parseStyleDeclaration(value);
2039:                } catch (Exception e) {
2040:                    String m = e.getMessage();
2041:                    if (m == null)
2042:                        m = "";
2043:                    String u = ((documentURI == null) ? "<unknown>"
2044:                            : documentURI.toString());
2045:                    String s = Messages.formatMessage("syntax.error.at",
2046:                            new Object[] { u, m });
2047:                    DOMException de = new DOMException(DOMException.SYNTAX_ERR,
2048:                            s);
2049:                    // <rave>
2050:                    // BEGIN RAVE MODIFICATIONS
2051:                    de.initCause(e);
2052:                    // END RAVE MODIFICATIONS
2053:                    // </rave>
2054:                    if (userAgent == null)
2055:                        throw de;
2056:                    userAgent.displayError(de);
2057:                } finally {
2058:                    element = null;
2059:                    cssBaseURI = null;
2060:                }
2061:                return styleDeclarationBuilder.styleDeclaration;
2062:            }
2063:
2064:            /**
2065:             * Parses and creates a new style-sheet.
2066:             * @param uri The style-sheet URI.
2067:             * @param media The target media of the style-sheet.
2068:             */
2069:            // <rave>
2070:            // BEGIN RAVE MODIFICATIONS
2071:            //    public StyleSheet parseStyleSheet(URL uri, String media)
2072:            public StyleSheet parseStyleSheet(URL uri, String media,
2073:                    Object location)
2074:            // END RAVE MODIFICATIONS
2075:                    // </rave>
2076:                    throws DOMException {
2077:                // <rave>
2078:                // BEGIN RAVE MODIFICATIONS
2079:                //StyleSheet ss = new StyleSheet();
2080:                StyleSheetCache cache = StyleSheetCache.getInstance();
2081:                StyleSheet ss = cache.get(uri);
2082:                if (ss == PARSING_SHEET) {
2083:                    warnCircularReference(uri, location);
2084:                    return new StyleSheet();
2085:                } else if (ss != null) {
2086:                    return ss;
2087:                }
2088:                StyleSheet parsedSheet = null;
2089:                ss = new StyleSheet();
2090:                try {
2091:                    cache.put(uri, PARSING_SHEET);
2092:                    // END RAVE MODIFICATIONS
2093:                    // </rave>
2094:                    try {
2095:                        ss.setMedia(parser.parseMedia(media));
2096:                    } catch (Exception e) {
2097:                        String m = e.getMessage();
2098:                        if (m == null)
2099:                            m = "";
2100:                        String u = ((documentURI == null) ? "<unknown>"
2101:                                : documentURI.toString());
2102:                        String s = Messages.formatMessage("syntax.error.at",
2103:                                new Object[] { u, m });
2104:                        DOMException de = new DOMException(
2105:                                DOMException.SYNTAX_ERR, s);
2106:                        // <rave>
2107:                        // BEGIN RAVE MODIFICATIONS
2108:                        de.initCause(e);
2109:                        // END RAVE MODIFICATIONS
2110:                        // </rave>
2111:                        if (userAgent == null)
2112:                            throw de;
2113:                        userAgent.displayError(de);
2114:                        return ss;
2115:                    }
2116:                    // <rave>
2117:                    // BEGIN RAVE MODIFICATIONS
2118:                    //        parseStyleSheet(ss, uri);
2119:                    parseStyleSheet(ss, uri, location);
2120:                    parsedSheet = ss;
2121:                } finally {
2122:                    cache.put(uri, parsedSheet);
2123:                }
2124:                // END RAVE MODIFICATIONS
2125:                // </rave>
2126:                return ss;
2127:            }
2128:
2129:            /**
2130:             * Parses and creates a new style-sheet.
2131:             * @param is The input source used to read the document.
2132:             * @param uri The base URI.
2133:             * @param media The target media of the style-sheet.
2134:             */
2135:            // <rave>
2136:            // BEGIN RAVE MODIFICATIONS
2137:            //    public StyleSheet parseStyleSheet(InputSource is, URL uri, String media)
2138:            public StyleSheet parseStyleSheet(InputSource is, URL uri,
2139:                    String media, Object location)
2140:            // END RAVE MODIFICATIONS
2141:                    // </rave>
2142:                    throws DOMException {
2143:
2144:                // <rave>
2145:                // BEGIN RAVE MODIFICATIONS
2146:                //StyleSheet ss = new StyleSheet();
2147:                StyleSheetCache cache = StyleSheetCache.getInstance();
2148:                StyleSheet ss = cache.get(uri);
2149:                if (ss == PARSING_SHEET) {
2150:                    warnCircularReference(uri, location);
2151:                    return new StyleSheet();
2152:                } else if (ss != null) {
2153:                    return ss;
2154:                }
2155:                StyleSheet parsedSheet = null;
2156:                ss = new StyleSheet();
2157:                cache.put(uri, PARSING_SHEET);
2158:                // END RAVE MODIFICATIONS
2159:                // </rave>
2160:                try {
2161:                    ss.setMedia(parser.parseMedia(media));
2162:                    // <rave>
2163:                    // BEGIN RAVE MODIFICATIONS
2164:                    //            parseStyleSheet(ss, is, uri);
2165:                    parseStyleSheet(ss, is, uri, location);
2166:                    parsedSheet = ss;
2167:                    // END RAVE MODIFICATIONS
2168:                    // </rave>
2169:                } catch (Exception e) {
2170:                    String m = e.getMessage();
2171:                    if (m == null)
2172:                        m = "";
2173:                    String u = ((documentURI == null) ? "<unknown>"
2174:                            : documentURI.toString());
2175:                    String s = Messages.formatMessage("syntax.error.at",
2176:                            new Object[] { u, m });
2177:                    DOMException de = new DOMException(DOMException.SYNTAX_ERR,
2178:                            s);
2179:                    // <rave>
2180:                    // BEGIN RAVE MODIFICATIONS
2181:                    de.initCause(e);
2182:                    // END RAVE MODIFICATIONS
2183:                    // </rave>
2184:                    if (userAgent == null)
2185:                        throw de;
2186:                    userAgent.displayError(de);
2187:                    // <rave>
2188:                } finally {
2189:                    cache.put(uri, parsedSheet);
2190:                    // </rave>
2191:                }
2192:                return ss;
2193:            }
2194:
2195:            /**
2196:             * Parses and fills the given style-sheet.
2197:             * @param ss The stylesheet to fill.
2198:             * @param uri The base URI.
2199:             */
2200:            // <rave>
2201:            // BEGIN RAVE MODIFICATIONS
2202:            //    public void parseStyleSheet(StyleSheet ss, URL uri) throws DOMException {
2203:            public void parseStyleSheet(StyleSheet ss, URL uri, Object location)
2204:                    throws DOMException {
2205:                // END RAVE MODIFICATIONS
2206:                // </rave>
2207:                if (uri == null) {
2208:                    String s = Messages.formatMessage("syntax.error.at",
2209:                            new Object[] { "Null Document reference", "" });
2210:                    DOMException de = new DOMException(DOMException.SYNTAX_ERR,
2211:                            s);
2212:                    if (userAgent == null)
2213:                        throw de;
2214:                    userAgent.displayError(de);
2215:                    return;
2216:                }
2217:
2218:                try {
2219:                    // Check that access to the uri is allowed
2220:                    // <rave>
2221:                    // BEGIN RAVE MODIFICATIONS
2222:                    // We don't check external resources so no need to parse
2223:                    // and process url
2224:                    //             ParsedURL pDocURL = null;
2225:                    //             if (documentURI != null) {
2226:                    //                 pDocURL = new ParsedURL(documentURI);
2227:                    //             }
2228:                    //             ParsedURL pURL = new ParsedURL(uri);
2229:                    //             cssContext.checkLoadExternalResource(pURL, pDocURL);
2230:                    // END RAVE MODIFICATIONS
2231:                    // </rave>
2232:
2233:                    // <rave>
2234:                    // BEGIN RAVE MODIFICATIONS
2235:                    //             parseStyleSheet(ss, new InputSource(uri.toString()), uri);
2236:                    parseStyleSheet(ss, new InputSource(uri.toString()), uri,
2237:                            location);
2238:                    // END RAVE MODIFICATIONS
2239:                    // </rave>
2240:                } catch (SecurityException e) {
2241:                    throw e;
2242:                } catch (Exception e) {
2243:                    // <rave>
2244:                    if (e instanceof  CSSException
2245:                            && ((CSSException) e).getException() instanceof  java.io.IOException) {
2246:                        displayMissingStyleSheet(uri.toString());
2247:                        return;
2248:                    }
2249:                    // </rave>
2250:                    String m = e.getMessage();
2251:                    if (m == null)
2252:                        m = "";
2253:                    String s = Messages.formatMessage("syntax.error.at",
2254:                            new Object[] { uri.toString(), m });
2255:                    DOMException de = new DOMException(DOMException.SYNTAX_ERR,
2256:                            s);
2257:                    // <rave>
2258:                    // BEGIN RAVE MODIFICATIONS
2259:                    de.initCause(e);
2260:                    // END RAVE MODIFICATIONS
2261:                    // </rave>
2262:                    if (userAgent == null)
2263:                        throw de;
2264:                    userAgent.displayError(de);
2265:                }
2266:            }
2267:
2268:            /**
2269:             * Parses and creates a new style-sheet.
2270:             * @param rules The style-sheet rules to parse.
2271:             * @param uri The style-sheet URI.
2272:             * @param media The target media of the style-sheet.
2273:             */
2274:            // <rave>
2275:            // BEGIN RAVE MODIFICATIONS
2276:            //    public StyleSheet parseStyleSheet(String rules, URL uri, String media)
2277:            public StyleSheet parseStyleSheet(String rules, URL uri,
2278:                    String media, Object location)
2279:            // END RAVE MODIFICATIONS
2280:                    // </rave>
2281:                    throws DOMException {
2282:                StyleSheet ss = new StyleSheet();
2283:                // <rave>
2284:                // BEGIN RAVE MODIFICATIONS
2285:                // Can we cache by string values too?
2286:                //StyleSheet ss = StyleSheetCache.getInstance().get(rules);
2287:                //if (ss != null) {
2288:                //    return ss;
2289:                //}
2290:                //ss = new StyleSheet();
2291:                // END RAVE MODIFICATIONS
2292:                // </rave>
2293:                try {
2294:                    ss.setMedia(parser.parseMedia(media));
2295:                } catch (Exception e) {
2296:                    String m = e.getMessage();
2297:                    if (m == null)
2298:                        m = "";
2299:                    String u = ((documentURI == null) ? "<unknown>"
2300:                            : documentURI.toString());
2301:                    String s = Messages.formatMessage("syntax.error.at",
2302:                            new Object[] { u, m });
2303:                    DOMException de = new DOMException(DOMException.SYNTAX_ERR,
2304:                            s);
2305:                    // <rave>
2306:                    // BEGIN RAVE MODIFICATIONS
2307:                    de.initCause(e);
2308:                    // END RAVE MODIFICATIONS
2309:                    // </rave>
2310:                    if (userAgent == null)
2311:                        throw de;
2312:                    userAgent.displayError(de);
2313:                    return ss;
2314:                }
2315:                // <rave>
2316:                // BEGIN RAVE MODIFICATIONS
2317:                //        parseStyleSheet(ss, rules, uri);
2318:                parseStyleSheet(ss, rules, uri, location);
2319:                //StyleSheetCache.getInstance().put(rules, ss);
2320:                // END RAVE MODIFICATIONS
2321:                // </rave>
2322:                return ss;
2323:            }
2324:
2325:            /**
2326:             * Parses and fills the given style-sheet.
2327:             * @param ss The stylesheet to fill.
2328:             * @param rules The style-sheet rules to parse.
2329:             * @param uri The base URI.
2330:             */
2331:            public void parseStyleSheet(StyleSheet ss, String rules,
2332:            // <rave>
2333:                    // BEGIN RAVE MODIFICATIONS
2334:                    //                                URL uri) throws DOMException {
2335:                    URL uri, Object location) throws DOMException {
2336:                // END RAVE MODIFICATIONS
2337:                // </rave>
2338:                try {
2339:                    parseStyleSheet(ss,
2340:                            new InputSource(new StringReader(rules)), uri
2341:                            // BEGIN RAVE MODIFICATIONS
2342:                            , location
2343:                    // END RAVE MODIFICATIONS
2344:                    );
2345:                } catch (Exception e) {
2346:                    String m = e.getMessage();
2347:                    if (m == null)
2348:                        m = "";
2349:
2350:                    // <rave>
2351:                    //            String s = Messages.formatMessage
2352:                    //                    ("stylesheet.syntax.error",
2353:                    //                    new Object[] { uri.toString(), rules, m });
2354:                    String s = "";
2355:                    if (uri == null) {
2356:                        s = Messages.formatMessage("stylesheet.syntax.error",
2357:                                new Object[] { "None", rules, m });
2358:                    } else {
2359:                        s = Messages.formatMessage("stylesheet.syntax.error",
2360:                                new Object[] { uri.toString(), rules, m });
2361:                    }
2362:                    // </rave>
2363:                    DOMException de = new DOMException(DOMException.SYNTAX_ERR,
2364:                            s);
2365:                    // <rave>
2366:                    // BEGIN RAVE MODIFICATIONS
2367:                    de.initCause(e);
2368:                    // END RAVE MODIFICATIONS
2369:                    // </rave>
2370:                    if (userAgent == null)
2371:                        throw de;
2372:                    userAgent.displayError(de);
2373:                }
2374:            }
2375:
2376:            /**
2377:             * Parses and fills the given style-sheet.
2378:             * @param ss The stylesheet to fill.
2379:             * @param uri The base URI.
2380:             */
2381:            // <rave>
2382:            // BEGIN RAVE MODIFICATIONS
2383:            //    protected void parseStyleSheet(StyleSheet ss, InputSource is, URL uri)
2384:            protected void parseStyleSheet(StyleSheet ss, InputSource is,
2385:                    URL uri, Object location)
2386:            // END RAVE MODIFICATIONS
2387:                    // </rave>
2388:                    throws IOException {
2389:                parser.setSelectorFactory(CSSSelectorFactory.INSTANCE);
2390:                parser.setConditionFactory(cssConditionFactory);
2391:                try {
2392:                    cssBaseURI = uri;
2393:                    styleSheetDocumentHandler.styleSheet = ss;
2394:                    parser.setDocumentHandler(styleSheetDocumentHandler);
2395:                    // BEGIN RAVE MODIFICATIONS
2396:                    // Set up some context. This will allow values to track their
2397:                    // source file and line number
2398:                    //styleSheetDocumentHandler.location = uri;
2399:                    styleSheetDocumentHandler.location = location;
2400:                    styleSheetDocumentHandler.lineno = 0;
2401:                    // END RAVE MODIFICATIONS
2402:                    parser.parseStyleSheet(is);
2403:
2404:                    // Load the imported sheets.
2405:                    int len = ss.getSize();
2406:                    for (int i = 0; i < len; i++) {
2407:                        Rule r = ss.getRule(i);
2408:                        if (r.getType() != ImportRule.TYPE) {
2409:                            // @import rules must be the first rules.
2410:                            break;
2411:                        }
2412:                        ImportRule ir = (ImportRule) r;
2413:                        // <rave>
2414:                        // BEGIN RAVE MODIFICATIONS
2415:                        StyleSheetCache cache = StyleSheetCache.getInstance();
2416:                        StyleSheet sheet = cache.get(ir.getURI());
2417:                        if (sheet == PARSING_SHEET) {
2418:                            warnCircularReference(ir.getURI(), location);
2419:                            continue;
2420:                        }
2421:                        // TODO - just populate the cached styles from
2422:                        // sheet into this stylesheet? (ss)
2423:                        //                parseStyleSheet(ir, ir.getURI());
2424:                        parseStyleSheet(ir, ir.getURI(), ir.getURI());
2425:                        // END RAVE MODIFICATIONS
2426:                        // </rave>
2427:                    }
2428:                } finally {
2429:                    cssBaseURI = null;
2430:                }
2431:            }
2432:
2433:            /**
2434:             * Puts an author property from a style-map in another style-map,
2435:             * if possible.
2436:             */
2437:            protected void putAuthorProperty(StyleMap dest, int idx,
2438:                    Value sval, boolean imp, short origin) {
2439:                Value dval = dest.getValue(idx);
2440:                short dorg = dest.getOrigin(idx);
2441:                boolean dimp = dest.isImportant(idx);
2442:
2443:                boolean cond = dval == null;
2444:                if (!cond) {
2445:                    switch (dorg) {
2446:                    case StyleMap.USER_ORIGIN:
2447:                        cond = !dimp;
2448:                        break;
2449:                    case StyleMap.AUTHOR_ORIGIN:
2450:                        cond = !dimp || imp;
2451:                        break;
2452:                    default:
2453:                        cond = true;
2454:                    }
2455:                }
2456:
2457:                if (cond) {
2458:                    dest.putValue(idx, sval);
2459:                    dest.putImportant(idx, imp);
2460:                    dest.putOrigin(idx, origin);
2461:                }
2462:            }
2463:
2464:            // <rave>    
2465:            // BEGIN RAVE MODIFICATIONS
2466:            private void addCandidateRules(List rules, Map map, String key,
2467:                    Element elt, String pseudo) {
2468:                ExtendedSelector[] rs = (ExtendedSelector[]) map.get(key);
2469:                if (rs != null) {
2470:                    for (int i = 0; i < rs.length; i++) {
2471:                        ExtendedSelector s = rs[i];
2472:                        if (s.match(elt, pseudo)) {
2473:                            Rule r = s.getRule();
2474:                            assert r.getType() == StyleRule.TYPE;
2475:                            rules.add(r);
2476:                        }
2477:                    }
2478:                }
2479:            }
2480:
2481:            private Comparator ruleComparator = new Comparator() {
2482:                public int compare(Object object1, Object object2) {
2483:                    Rule rule1 = (Rule) object1;
2484:                    Rule rule2 = (Rule) object2;
2485:                    return rule1.getPosition() - rule2.getPosition();
2486:                }
2487:            };
2488:
2489:            // END RAVE MODIFICATIONS
2490:            // </rave>
2491:            /**
2492:             * Adds the rules matching the element/pseudo-element of given style
2493:             * sheet to the list.
2494:             */
2495:            protected void addMatchingRules(List rules, StyleSheet ss,
2496:                    Element elt, String pseudo) {
2497:                // <rave>
2498:                // BEGIN RAVE MODIFICATIONS
2499:                // addMatchingRules was the hottest method in a full page refresh.
2500:                // On a Braveheart page, it's extremely long. The reason for that
2501:                // of course is that there's a huge number of rules in the stylesheet -
2502:                // over 700, where EACH has a number of selectors, and each selector
2503:                // may even do node iteration, and these are then checked for every
2504:                // document element! For complicated html pages like MyYahoo, it
2505:                // spent 40 seconds in rule matching for the dom elements!
2506:                // This clearly requires an optimization. I'm using one described by
2507:                // David Hyatt in a blog, where the rule set is partitioned into
2508:                // rules that can be quickly checked based on the tag name, the class
2509:                // attribute, and the element id. Rules that don't fit in these buckets
2510:                // are then checked in the normal, linear way. For the tag/class/id
2511:                // rules, they are stored in hashmaps keyed by the tagname/class/id,
2512:                // so for a given element we can quickly look up all rules that affect
2513:                // that tag - and more importantly, ignore rules that pertain only
2514:                // to OTHER tags!
2515:                // This yields a huge performance benefit -- 7x-8x in my measurements.
2516:                // There are some complications to worry about, such as needing to
2517:                // sort the rules according to their stylesheet order, to preserve the
2518:                // right cascade semantics. These are handled below.
2519:                // Note that the stylesheet initialization code, which sets up these
2520:                // data structures, is run only once. I've deliberately done more 
2521:                // computation there which should help speed up this hot method; e.g.
2522:                // the data structures are typed arrays rather than generic Object
2523:                // collections, etc.
2524:                if (RULE_FILTERING) {
2525:                    List newRules = new ArrayList(ss.getSize());
2526:
2527:                    Map tagMap = ss.getTagMap();
2528:                    if (tagMap != null) {
2529:                        String tagName = elt.getTagName();
2530:                        addCandidateRules(newRules, tagMap, tagName, elt,
2531:                                pseudo);
2532:                    }
2533:
2534:                    Map classMap = ss.getClassMap();
2535:                    if (classMap != null) {
2536:                        String styleClass = elt.getAttribute("class");
2537:                        if (styleClass.length() == 0) {
2538:                        } else if (styleClass.indexOf(' ') == -1) {
2539:                            addCandidateRules(newRules, classMap, styleClass,
2540:                                    elt, pseudo);
2541:                        } else {
2542:                            int begin = 0;
2543:                            int length = styleClass.length();
2544:                            while (begin < length) {
2545:                                while (begin < length
2546:                                        && Character.isSpace(styleClass
2547:                                                .charAt(begin))) {
2548:                                    begin++;
2549:                                }
2550:                                int end = begin + 1;
2551:                                while (end < length
2552:                                        && !Character.isSpace(styleClass
2553:                                                .charAt(end))) {
2554:                                    end++;
2555:                                }
2556:                                if (begin < length && end > begin) {
2557:                                    addCandidateRules(newRules, classMap,
2558:                                            styleClass.substring(begin, end),
2559:                                            elt, pseudo);
2560:                                }
2561:                                begin = end + 1;
2562:                            }
2563:                        }
2564:                    }
2565:
2566:                    Map idMap = ss.getIdMap();
2567:                    if (idMap != null) {
2568:                        String id = elt.getAttribute("id");
2569:                        if (id.length() > 0) {
2570:                            addCandidateRules(newRules, idMap, id, elt, pseudo);
2571:                        }
2572:                    }
2573:
2574:                    Rule[] rs = ss.getRemainingRules();
2575:                    if (rs != null) {
2576:                        for (int i = 0; i < rs.length; i++) {
2577:                            Rule r = rs[i];
2578:                            switch (r.getType()) {
2579:                            case StyleRule.TYPE:
2580:                                StyleRule style = (StyleRule) r;
2581:                                SelectorList sl = style.getSelectorList();
2582:                                int slen = sl.getLength();
2583:                                for (int j = 0; j < slen; j++) {
2584:                                    ExtendedSelector s = (ExtendedSelector) sl
2585:                                            .item(j);
2586:                                    if (s.match(elt, pseudo)) {
2587:                                        newRules.add(style);
2588:                                    }
2589:                                }
2590:                                break;
2591:
2592:                            case MediaRule.TYPE:
2593:                            case ImportRule.TYPE:
2594:                                MediaRule mr = (MediaRule) r;
2595:                                if (mediaMatch(mr.getMediaList())) {
2596:                                    addMatchingRules(newRules, mr, elt, pseudo);
2597:                                }
2598:                                break;
2599:                            }
2600:                        }
2601:
2602:                        // Sort the rules by order, since we've split up the order when
2603:                        // separating out tag name, attributes, etc.
2604:                        int size = newRules.size();
2605:                        if (size > 0) {
2606:                            if (size > 1) {
2607:                                Collections.sort(newRules, ruleComparator);
2608:                            }
2609:
2610:                            Object prev = null;
2611:                            Iterator it = newRules.iterator();
2612:                            while (it.hasNext()) {
2613:                                Object o = it.next();
2614:                                if (o != prev) {
2615:                                    rules.add(o);
2616:                                    prev = o;
2617:                                }
2618:                            }
2619:                        }
2620:
2621:                        return;
2622:                    }
2623:                }
2624:                // END RAVE MODIFICATIONS
2625:                // </rave>
2626:                int len = ss.getSize();
2627:                for (int i = 0; i < len; i++) {
2628:                    Rule r = ss.getRule(i);
2629:                    switch (r.getType()) {
2630:                    case StyleRule.TYPE:
2631:                        StyleRule style = (StyleRule) r;
2632:                        SelectorList sl = style.getSelectorList();
2633:                        int slen = sl.getLength();
2634:                        for (int j = 0; j < slen; j++) {
2635:                            ExtendedSelector s = (ExtendedSelector) sl.item(j);
2636:                            if (s.match(elt, pseudo)) {
2637:                                rules.add(style);
2638:                            }
2639:                        }
2640:                        break;
2641:
2642:                    case MediaRule.TYPE:
2643:                    case ImportRule.TYPE:
2644:                        MediaRule mr = (MediaRule) r;
2645:                        if (mediaMatch(mr.getMediaList())) {
2646:                            addMatchingRules(rules, mr, elt, pseudo);
2647:                        }
2648:                        break;
2649:                    }
2650:                }
2651:            }
2652:
2653:            /**
2654:             * Adds the rules contained in the given list to a stylemap.
2655:             */
2656:            protected void addRules(Element elt, String pseudo, StyleMap sm,
2657:                    List rules, short origin) {
2658:                sortRules(rules, elt, pseudo);
2659:                int rlen = rules.size();
2660:
2661:                if (origin == StyleMap.AUTHOR_ORIGIN) {
2662:                    for (int r = 0; r < rlen; r++) {
2663:                        StyleRule sr = (StyleRule) rules.get(r);
2664:                        StyleDeclaration sd = sr.getStyleDeclaration();
2665:                        int len = sd.size();
2666:                        for (int i = 0; i < len; i++) {
2667:                            putAuthorProperty(sm, sd.getIndex(i), sd
2668:                                    .getValue(i), sd.getPriority(i), origin);
2669:                        }
2670:                    }
2671:                } else {
2672:                    for (int r = 0; r < rlen; r++) {
2673:                        StyleRule sr = (StyleRule) rules.get(r);
2674:                        StyleDeclaration sd = sr.getStyleDeclaration();
2675:                        int len = sd.size();
2676:                        for (int i = 0; i < len; i++) {
2677:                            int idx = sd.getIndex(i);
2678:                            sm.putValue(idx, sd.getValue(i));
2679:                            sm.putImportant(idx, sd.getPriority(i));
2680:                            sm.putOrigin(idx, origin);
2681:                        }
2682:                    }
2683:                }
2684:            }
2685:
2686:            /**
2687:             * Sorts the rules matching the element/pseudo-element of given style
2688:             * sheet to the list.
2689:             */
2690:            protected void sortRules(List rules, Element elt, String pseudo) {
2691:                int len = rules.size();
2692:                for (int i = 0; i < len - 1; i++) {
2693:                    int idx = i;
2694:                    int min = Integer.MAX_VALUE;
2695:                    for (int j = i; j < len; j++) {
2696:                        StyleRule r = (StyleRule) rules.get(j);
2697:                        SelectorList sl = r.getSelectorList();
2698:                        int spec = 0;
2699:                        int slen = sl.getLength();
2700:                        for (int k = 0; k < slen; k++) {
2701:                            ExtendedSelector s = (ExtendedSelector) sl.item(k);
2702:                            if (s.match(elt, pseudo)) {
2703:                                int sp = s.getSpecificity();
2704:                                if (sp > spec) {
2705:                                    spec = sp;
2706:                                }
2707:                            }
2708:                        }
2709:                        if (spec < min) {
2710:                            min = spec;
2711:                            idx = j;
2712:                        }
2713:                    }
2714:                    if (i != idx) {
2715:                        Object tmp = rules.get(i);
2716:                        rules.set(i, rules.get(idx));
2717:                        rules.set(idx, tmp);
2718:                    }
2719:                }
2720:            }
2721:
2722:            /**
2723:             * Whether the given media list matches the media list of this
2724:             * CSSEngine object.
2725:             */
2726:            protected boolean mediaMatch(SACMediaList ml) {
2727:                if (media == null || ml == null || media.getLength() == 0
2728:                        || ml.getLength() == 0) {
2729:                    return true;
2730:                }
2731:                for (int i = 0; i < ml.getLength(); i++) {
2732:                    if (ml.item(i).equalsIgnoreCase("all"))
2733:                        return true;
2734:                    for (int j = 0; j < media.getLength(); j++) {
2735:                        if (media.item(j).equalsIgnoreCase("all")
2736:                                || ml.item(i).equalsIgnoreCase(media.item(j))) {
2737:                            return true;
2738:                        }
2739:                    }
2740:                }
2741:                return false;
2742:            }
2743:
2744:            /**
2745:             * To parse a style declaration.
2746:             */
2747:            protected class StyleDeclarationDocumentHandler extends
2748:                    DocumentAdapter implements  ShorthandManager.PropertyHandler {
2749:                public StyleMap styleMap;
2750:
2751:                // <rave>
2752:                // BEGIN RAVE MODIFICATIONS
2753:                Object location;
2754:                int lineno;
2755:
2756:                // END RAVE MOFIFICATIONS
2757:                // </rave>
2758:                /**
2759:                 * <b>SAC</b>: Implements {@link
2760:                 * DocumentHandler#property(String,LexicalUnit,boolean)}.
2761:                 */
2762:                public void property(String name, LexicalUnit value,
2763:                        boolean important) throws CSSException {
2764:                    int i = getPropertyIndex(name);
2765:                    if (i == -1) {
2766:                        i = getShorthandIndex(name);
2767:                        if (i == -1) {
2768:                            // Unknown property
2769:                            // <rave>
2770:                            // BEGIN RAVE MODIFICATIONS
2771:                            if (unknownPropertyNames != null) {
2772:                                unknownPropertyNames.add(name);
2773:                                StringBuffer sb = new StringBuffer(50);
2774:                                appendCss(sb, value);
2775:                                unknownPropertyValues.add(sb.toString());
2776:                            }
2777:                            // END RAVE MODIFICATIONS
2778:                            // </rave>
2779:                            return;
2780:                        }
2781:                        // <rave>
2782:                        // BEGIN RAVE MODIFICATIONS
2783:                        try {
2784:                            expandingShorthandProperty = i;
2785:                            // END RAVE MODIFICATIONS
2786:                            // </rave>
2787:                            shorthandManagers[i].setValues(CSSEngine.this ,
2788:                                    this , value, important);
2789:                            // <rave>
2790:                            // BEGIN RAVE MODIFICATIONS
2791:                            expandingShorthandProperty = -1;
2792:                        } catch (DOMException e) {
2793:                            // Something bad happened
2794:                            displayError(e, location, lineno + parser.getLine()
2795:                                    - 1, parser.getColumn());
2796:                            // Continue processing - we're supposed to ignore
2797:                            // errant declarations!!!
2798:                        }
2799:                        // END RAVE MODIFICATIONS
2800:                        // </rave>
2801:                    } else {
2802:                        // <rave>
2803:                        // BEGIN RAVE MODIFICATIONS
2804:                        // Add error handling: don't abort, and send errors to
2805:                        // an output window instead via the engine
2806:                        try {
2807:                            // END RAVE MODIFICATIONS
2808:                            // </rave>
2809:
2810:                            Value v = valueManagers[i].createValue(value,
2811:                                    CSSEngine.this );
2812:                            // <rave>
2813:                            // BEGIN RAVE MODIFICATIONS
2814:                            // Track the value source
2815:                            if (v instanceof  AbstractValue) { // Should I add to Value interface???
2816:                                AbstractValue av = (AbstractValue) v;
2817:                                av.setLocation(location);
2818:                                av.setLineNumber(lineno + parser.getLine() - 1);
2819:                            }
2820:                            // END RAVE MODIFICATIONS
2821:                            // </rave>
2822:                            putAuthorProperty(styleMap, i, v, important,
2823:                                    StyleMap.INLINE_AUTHOR_ORIGIN);
2824:                            // <rave>
2825:                            // BEGIN RAVE MODIFICATIONS
2826:                        } catch (DOMException e) {
2827:                            // Something bad happened
2828:                            displayError(e, location, lineno + parser.getLine()
2829:                                    - 1, parser.getColumn());
2830:                            // Continue processing - we're supposed to ignore
2831:                            // errant declarations!!!
2832:                        }
2833:                        // END RAVE MODIFICATIONS
2834:                        // </rave>
2835:                    }
2836:                }
2837:            }
2838:
2839:            /**
2840:             * To build a StyleDeclaration object.
2841:             */
2842:            protected class StyleDeclarationBuilder extends DocumentAdapter
2843:                    implements  ShorthandManager.PropertyHandler {
2844:                public StyleDeclaration styleDeclaration;
2845:                // <rave>
2846:                // BEGIN RAVE MODIFICATIONS
2847:                Object location;
2848:                int lineno;
2849:
2850:                // ENBD RAVE MODIFICATIONS
2851:                // </rave>
2852:                /**
2853:                 * <b>SAC</b>: Implements {@link
2854:                 * DocumentHandler#property(String,LexicalUnit,boolean)}.
2855:                 */
2856:                public void property(String name, LexicalUnit value,
2857:                        boolean important) throws CSSException {
2858:                    int i = getPropertyIndex(name);
2859:                    if (i == -1) {
2860:                        i = getShorthandIndex(name);
2861:                        if (i == -1) {
2862:                            // Unknown property
2863:                            // <rave>
2864:                            // BEGIN RAVE MODIFICATIONS
2865:                            if (unknownPropertyNames != null) {
2866:                                unknownPropertyNames.add(name);
2867:                                StringBuffer sb = new StringBuffer(50);
2868:                                appendCss(sb, value);
2869:                                unknownPropertyValues.add(sb.toString());
2870:                            }
2871:                            // END RAVE MODIFICATIONS
2872:                            // </rave>
2873:                            return;
2874:                        }
2875:                        // <rave>
2876:                        // BEGIN RAVE MODIFICATIONS
2877:                        try {
2878:                            expandingShorthandProperty = i;
2879:                            // END RAVE MODIFICATIONS
2880:                            // </rave>
2881:                            shorthandManagers[i].setValues(CSSEngine.this ,
2882:                                    this , value, important);
2883:                            // <rave>
2884:                            // BEGIN RAVE MODIFICATIONS
2885:                            expandingShorthandProperty = -1;
2886:                        } catch (DOMException e) {
2887:                            // Something bad happened
2888:                            displayError(e, location, lineno + parser.getLine()
2889:                                    - 1, parser.getColumn());
2890:                            // Continue processing - we're supposed to ignore
2891:                            // errant declarations!!!
2892:                        }
2893:                        // END RAVE MODIFICATIONS
2894:                        // </rave>                
2895:                    } else {
2896:                        // <rave>
2897:                        // BEGIN RAVE MODIFICATIONS
2898:                        // Add error handling: don't abort, and send errors to
2899:                        // an output window instead via the engine
2900:                        try {
2901:                            // END RAVE MODIFICATIONS
2902:                            // </rave>
2903:
2904:                            Value v = valueManagers[i].createValue(value,
2905:                                    CSSEngine.this );
2906:                            // <rave>
2907:                            // BEGIN RAVE MODIFICATIONS
2908:                            // Track the value source
2909:                            if (v instanceof  AbstractValue) { // Should I add to Value interface???
2910:                                AbstractValue av = (AbstractValue) v;
2911:                                av.setLocation(location);
2912:                                av.setLineNumber(lineno + parser.getLine() - 1);
2913:                            }
2914:                            // END RAVE MODIFICATIONS
2915:                            // </rave>
2916:                            styleDeclaration.append(v, i, important);
2917:                            // <rave>
2918:                            // BEGIN RAVE MODIFICATIONS
2919:                        } catch (DOMException e) {
2920:                            // Something bad happened
2921:                            displayError(e, location, lineno + parser.getLine()
2922:                                    - 1, parser.getColumn());
2923:                            // Continue processing - we're supposed to ignore
2924:                            // errant declarations!!!
2925:                        }
2926:                        // END RAVE MODIFICATIONS
2927:                        // </rave>
2928:                    }
2929:                }
2930:            }
2931:
2932:            /**
2933:             * To parse a style sheet.
2934:             */
2935:            protected class StyleSheetDocumentHandler extends DocumentAdapter
2936:                    implements  ShorthandManager.PropertyHandler {
2937:                public StyleSheet styleSheet;
2938:                // <rave>
2939:                // BEGIN RAVE MODIFICATIONS
2940:                Object location;
2941:                int lineno;
2942:                // END RAVE MODIFICATIONS
2943:                // </rave>
2944:                protected StyleRule styleRule;
2945:                protected StyleDeclaration styleDeclaration;
2946:
2947:                /**
2948:                 * <b>SAC</b>: Implements {@link
2949:                 * DocumentHandler#startDocument(InputSource)}.
2950:                 */
2951:                public void startDocument(InputSource source)
2952:                        throws CSSException {
2953:                }
2954:
2955:                /**
2956:                 * <b>SAC</b>: Implements {@link
2957:                 * DocumentHandler#endDocument(InputSource)}.
2958:                 */
2959:                public void endDocument(InputSource source) throws CSSException {
2960:                }
2961:
2962:                /**
2963:                 * <b>SAC</b>: Implements {@link
2964:                 * org.w3c.css.sac.DocumentHandler#ignorableAtRule(String)}.
2965:                 */
2966:                public void ignorableAtRule(String atRule) throws CSSException {
2967:                }
2968:
2969:                /**
2970:                 * <b>SAC</b>: Implements {@link
2971:                 * DocumentHandler#importStyle(String,SACMediaList,String)}.
2972:                 */
2973:                public void importStyle(String uri, SACMediaList media,
2974:                        String defaultNamespaceURI) throws CSSException {
2975:                    ImportRule ir = new ImportRule();
2976:                    // <rave>
2977:                    // BEGIN RAVE MODIFICATIONS
2978:                    ir.setRelativeUri(uri);
2979:                    // END RAVE MODIFICATIONS
2980:                    // </rave>
2981:                    ir.setMediaList(media);
2982:                    ir.setParent(styleSheet);
2983:                    try {
2984:                        URL base = getCSSBaseURI();
2985:                        URL url;
2986:                        if (base == null)
2987:                            url = new URL(uri);
2988:                        else
2989:                            url = new URL(base, uri);
2990:                        ir.setURI(url);
2991:                    } catch (MalformedURLException e) {
2992:                    }
2993:                    styleSheet.append(ir);
2994:                }
2995:
2996:                /**
2997:                 * <b>SAC</b>: Implements {@link
2998:                 * org.w3c.css.sac.DocumentHandler#startMedia(SACMediaList)}.
2999:                 */
3000:                public void startMedia(SACMediaList media) throws CSSException {
3001:                    MediaRule mr = new MediaRule();
3002:                    mr.setMediaList(media);
3003:                    mr.setParent(styleSheet);
3004:                    styleSheet.append(mr);
3005:                    styleSheet = mr;
3006:                }
3007:
3008:                /**
3009:                 * <b>SAC</b>: Implements {@link
3010:                 * org.w3c.css.sac.DocumentHandler#endMedia(SACMediaList)}.
3011:                 */
3012:                public void endMedia(SACMediaList media) throws CSSException {
3013:                    styleSheet = styleSheet.getParent();
3014:                }
3015:
3016:                /**
3017:                 * <b>SAC</b>: Implements {@link
3018:                 * org.w3c.css.sac.DocumentHandler#startPage(String,String)}.
3019:                 */
3020:                public void startPage(String name, String pseudo_page)
3021:                        throws CSSException {
3022:                }
3023:
3024:                /**
3025:                 * <b>SAC</b>: Implements {@link
3026:                 * org.w3c.css.sac.DocumentHandler#endPage(String,String)}.
3027:                 */
3028:                public void endPage(String name, String pseudo_page)
3029:                        throws CSSException {
3030:                }
3031:
3032:                /**
3033:                 * <b>SAC</b>: Implements {@link
3034:                 * org.w3c.css.sac.DocumentHandler#startFontFace()}.
3035:                 */
3036:                public void startFontFace() throws CSSException {
3037:                    styleDeclaration = new StyleDeclaration();
3038:                }
3039:
3040:                /**
3041:                 * <b>SAC</b>: Implements {@link
3042:                 * org.w3c.css.sac.DocumentHandler#endFontFace()}.
3043:                 */
3044:                public void endFontFace() throws CSSException {
3045:                    // <rave>
3046:                    // BEGIN RAVE MODIFICATIONS
3047:                    // Add error handling: don't abort, and send errors to
3048:                    // an output window instead via the engine
3049:                    try {
3050:                        // END RAVE MODIFICATIONS
3051:                        // </rave>
3052:
3053:                        StyleMap sm = new StyleMap(getNumberOfProperties());
3054:                        int len = styleDeclaration.size();
3055:                        for (int i = 0; i < len; i++) {
3056:                            int idx = styleDeclaration.getIndex(i);
3057:                            sm.putValue(idx, styleDeclaration.getValue(i));
3058:                            sm.putImportant(idx, styleDeclaration
3059:                                    .getPriority(i));
3060:                            // Not sure on this..
3061:                            sm.putOrigin(idx, StyleMap.AUTHOR_ORIGIN);
3062:                        }
3063:                        styleDeclaration = null;
3064:
3065:                        int pidx = getPropertyIndex(CSSConstants.CSS_FONT_FAMILY_PROPERTY);
3066:                        Value fontFamily = sm.getValue(pidx);
3067:                        if (fontFamily == null)
3068:                            return;
3069:
3070:                        URL base = getCSSBaseURI();
3071:                        ParsedURL purl = null;
3072:                        if (base != null)
3073:                            purl = new ParsedURL(base);
3074:                        fontFaces.add(new FontFaceRule(sm, purl));
3075:                        // <rave>
3076:                        // BEGIN RAVE MODIFICATIONS
3077:                    } catch (DOMException e) {
3078:                        // Something bad happened
3079:                        //displayError(e, location, lineno);
3080:                        displayError(e, location,
3081:                                lineno + parser.getLine() - 1, parser
3082:                                        .getColumn());
3083:
3084:                        // Continue processing - we're supposed to ignore
3085:                        // errant declarations!!!
3086:                    }
3087:                    // END RAVE MODIFICATIONS
3088:                    // </rave>
3089:                }
3090:
3091:                /**
3092:                 * <b>SAC</b>: Implements {@link
3093:                 * org.w3c.css.sac.DocumentHandler#startSelector(SelectorList)}.
3094:                 */
3095:                public void startSelector(SelectorList selectors)
3096:                        throws CSSException {
3097:                    styleRule = new StyleRule();
3098:                    styleRule.setSelectorList(selectors);
3099:                    styleDeclaration = new StyleDeclaration();
3100:                    styleRule.setStyleDeclaration(styleDeclaration);
3101:                    styleSheet.append(styleRule);
3102:                }
3103:
3104:                /**
3105:                 * <b>SAC</b>: Implements {@link
3106:                 * org.w3c.css.sac.DocumentHandler#endSelector(SelectorList)}.
3107:                 */
3108:                public void endSelector(SelectorList selectors)
3109:                        throws CSSException {
3110:                    styleRule = null;
3111:                    styleDeclaration = null;
3112:                }
3113:
3114:                /**
3115:                 * <b>SAC</b>: Implements {@link
3116:                 * DocumentHandler#property(String,LexicalUnit,boolean)}.
3117:                 */
3118:                public void property(String name, LexicalUnit value,
3119:                        boolean important) throws CSSException {
3120:                    int i = getPropertyIndex(name);
3121:                    if (i == -1) {
3122:                        i = getShorthandIndex(name);
3123:                        if (i == -1) {
3124:                            // Unknown property
3125:                            return;
3126:                        }
3127:                        // <rave>
3128:                        // BEGIN RAVE MODIFICATIONS
3129:                        try {
3130:                            expandingShorthandProperty = i;
3131:                            // END RAVE MODIFICATIONS
3132:                            // </rave>
3133:                            shorthandManagers[i].setValues(CSSEngine.this ,
3134:                                    this , value, important);
3135:                            // <rave>
3136:                            // BEGIN RAVE MODIFICATIONS
3137:                            expandingShorthandProperty = -1;
3138:                        } catch (DOMException e) {
3139:                            // Something bad happened
3140:                            displayError(e, location, lineno + parser.getLine()
3141:                                    - 1, parser.getColumn());
3142:                            // Continue processing - we're supposed to ignore
3143:                            // errant declarations!!!
3144:                        }
3145:                        // END RAVE MODIFICATIONS
3146:                        // </rave>
3147:                    } else {
3148:                        // <rave>
3149:                        // BEGIN RAVE MODIFICATIONS
3150:                        // Add error handling: don't abort, and send errors to
3151:                        // an output window instead via the engine
3152:                        try {
3153:                            // END RAVE MODIFICATIONS
3154:                            // </rave>
3155:
3156:                            Value v = valueManagers[i].createValue(value,
3157:                                    CSSEngine.this );
3158:                            // <rave>
3159:                            // BEGIN RAVE MODIFICATIONS
3160:                            // Track the value source
3161:                            if (v instanceof  AbstractValue) { // Should I add to Value interface???
3162:                                AbstractValue av = (AbstractValue) v;
3163:                                av.setLocation(location);
3164:                                av.setLineNumber(lineno + parser.getLine() - 1);
3165:                            }
3166:                            // END RAVE MODIFICATIONS
3167:                            // </rave>
3168:                            styleDeclaration.append(v, i, important);
3169:
3170:                            // <rave>
3171:                            // BEGIN RAVE MODIFICATIONS
3172:                        } catch (DOMException e) {
3173:                            // Something bad happened
3174:                            displayError(e, location, lineno + parser.getLine()
3175:                                    - 1, parser.getColumn());
3176:                            // Continue processing - we're supposed to ignore
3177:                            // errant declarations!!!
3178:                        }
3179:                        // END RAVE MODIFICATIONS
3180:                        // </rave>
3181:                    }
3182:                }
3183:            }
3184:
3185:            /**
3186:             * Provides an adapter for the DocumentHandler interface.
3187:             */
3188:            protected static class DocumentAdapter implements  DocumentHandler {
3189:
3190:                /**
3191:                 * <b>SAC</b>: Implements {@link
3192:                 * DocumentHandler#startDocument(InputSource)}.
3193:                 */
3194:                public void startDocument(InputSource source)
3195:                        throws CSSException {
3196:                    throw new InternalError();
3197:                }
3198:
3199:                /**
3200:                 * <b>SAC</b>: Implements {@link
3201:                 * DocumentHandler#endDocument(InputSource)}.
3202:                 */
3203:                public void endDocument(InputSource source) throws CSSException {
3204:                    throw new InternalError();
3205:                }
3206:
3207:                /**
3208:                 * <b>SAC</b>: Implements {@link
3209:                 * DocumentHandler#comment(String)}.
3210:                 */
3211:                public void comment(String text) throws CSSException {
3212:                    // We always ignore the comments.
3213:                }
3214:
3215:                /**
3216:                 * <b>SAC</b>: Implements {@link
3217:                 * DocumentHandler#ignorableAtRule(String)}.
3218:                 */
3219:                public void ignorableAtRule(String atRule) throws CSSException {
3220:                    throw new InternalError();
3221:                }
3222:
3223:                /**
3224:                 * <b>SAC</b>: Implements {@link
3225:                 * DocumentHandler#namespaceDeclaration(String,String)}.
3226:                 */
3227:                public void namespaceDeclaration(String prefix, String uri)
3228:                        throws CSSException {
3229:                    throw new InternalError();
3230:                }
3231:
3232:                /**
3233:                 * <b>SAC</b>: Implements {@link
3234:                 * DocumentHandler#importStyle(String,SACMediaList,String)}.
3235:                 */
3236:                public void importStyle(String uri, SACMediaList media,
3237:                        String defaultNamespaceURI) throws CSSException {
3238:                    throw new InternalError();
3239:                }
3240:
3241:                /**
3242:                 * <b>SAC</b>: Implements {@link
3243:                 * DocumentHandler#startMedia(SACMediaList)}.
3244:                 */
3245:                public void startMedia(SACMediaList media) throws CSSException {
3246:                    throw new InternalError();
3247:                }
3248:
3249:                /**
3250:                 * <b>SAC</b>: Implements {@link
3251:                 * DocumentHandler#endMedia(SACMediaList)}.
3252:                 */
3253:                public void endMedia(SACMediaList media) throws CSSException {
3254:                    throw new InternalError();
3255:                }
3256:
3257:                /**
3258:                 * <b>SAC</b>: Implements {@link
3259:                 * DocumentHandler#startPage(String,String)}.
3260:                 */
3261:                public void startPage(String name, String pseudo_page)
3262:                        throws CSSException {
3263:                    throw new InternalError();
3264:                }
3265:
3266:                /**
3267:                 * <b>SAC</b>: Implements {@link
3268:                 * DocumentHandler#endPage(String,String)}.
3269:                 */
3270:                public void endPage(String name, String pseudo_page)
3271:                        throws CSSException {
3272:                    throw new InternalError();
3273:                }
3274:
3275:                /**
3276:                 * <b>SAC</b>: Implements {@link DocumentHandler#startFontFace()}.
3277:                 */
3278:                public void startFontFace() throws CSSException {
3279:                    throw new InternalError();
3280:                }
3281:
3282:                /**
3283:                 * <b>SAC</b>: Implements {@link DocumentHandler#endFontFace()}.
3284:                 */
3285:                public void endFontFace() throws CSSException {
3286:                    throw new InternalError();
3287:                }
3288:
3289:                /**
3290:                 * <b>SAC</b>: Implements {@link
3291:                 * DocumentHandler#startSelector(SelectorList)}.
3292:                 */
3293:                public void startSelector(SelectorList selectors)
3294:                        throws CSSException {
3295:                    throw new InternalError();
3296:                }
3297:
3298:                /**
3299:                 * <b>SAC</b>: Implements {@link
3300:                 * DocumentHandler#endSelector(SelectorList)}.
3301:                 */
3302:                public void endSelector(SelectorList selectors)
3303:                        throws CSSException {
3304:                    throw new InternalError();
3305:                }
3306:
3307:                /**
3308:                 * <b>SAC</b>: Implements {@link
3309:                 * DocumentHandler#property(String,LexicalUnit,boolean)}.
3310:                 */
3311:                public void property(String name, LexicalUnit value,
3312:                        boolean important) throws CSSException {
3313:                    throw new InternalError();
3314:                }
3315:            }
3316:
3317:            // CSS events /////////////////////////////////////////////////////////
3318:
3319:            protected final static CSSEngineListener[] LISTENER_ARRAY = new CSSEngineListener[0];
3320:
3321:            /**
3322:             * Adds a CSS engine listener.
3323:             */
3324:            public void addCSSEngineListener(CSSEngineListener l) {
3325:                listeners.add(l);
3326:            }
3327:
3328:            /**
3329:             * Removes a CSS engine listener.
3330:             */
3331:            public void removeCSSEngineListener(CSSEngineListener l) {
3332:                listeners.remove(l);
3333:            }
3334:
3335:            /**
3336:             * Fires a CSSEngineEvent, given a list of modified properties.
3337:             */
3338:            protected void firePropertiesChangedEvent(Element target,
3339:                    int[] props) {
3340:                CSSEngineListener[] ll = (CSSEngineListener[]) listeners
3341:                        .toArray(LISTENER_ARRAY);
3342:
3343:                int len = ll.length;
3344:                if (len > 0) {
3345:                    CSSEngineEvent evt = new CSSEngineEvent(this , target, props);
3346:                    for (int i = 0; i < len; i++) {
3347:                        ll[i].propertiesChanged(evt);
3348:                    }
3349:                }
3350:            }
3351:
3352:            // Dynamic updates ////////////////////////////////////////////////////
3353:
3354:            /**
3355:             * Called when the inline style of the given element has been updated.
3356:             */
3357:            protected void inlineStyleAttributeUpdated(CSSStylableElement elt,
3358:                    StyleMap style, MutationEvent evt) {
3359:                boolean[] updated = styleDeclarationUpdateHandler.updatedProperties;
3360:                for (int i = getNumberOfProperties() - 1; i >= 0; --i) {
3361:                    updated[i] = false;
3362:                }
3363:
3364:                switch (evt.getAttrChange()) {
3365:                case MutationEvent.ADDITION:
3366:                case MutationEvent.MODIFICATION:
3367:                    String decl = evt.getNewValue();
3368:                    // System.err.println("Inline Style Update: '" + decl + "'");
3369:                    if (decl.length() > 0) {
3370:                        element = elt;
3371:                        try {
3372:                            parser
3373:                                    .setSelectorFactory(CSSSelectorFactory.INSTANCE);
3374:                            parser.setConditionFactory(cssConditionFactory);
3375:                            styleDeclarationUpdateHandler.styleMap = style;
3376:                            parser
3377:                                    .setDocumentHandler(styleDeclarationUpdateHandler);
3378:                            // <rave>
3379:                            // BEGIN RAVE MODIFICATIONS
3380:                            styleDeclarationUpdateHandler.location = elt;
3381:                            styleDeclarationUpdateHandler.lineno = -1;
3382:                            // END RAVE MODIFICATIONS
3383:                            // </rave>
3384:                            parser.parseStyleDeclaration(decl);
3385:                            styleDeclarationUpdateHandler.styleMap = null;
3386:                        } catch (Exception e) {
3387:                            String m = e.getMessage();
3388:                            if (m == null)
3389:                                m = "";
3390:                            String u = ((documentURI == null) ? "<unknown>"
3391:                                    : documentURI.toString());
3392:                            String s = Messages.formatMessage(
3393:                                    "style.syntax.error.at", new Object[] { u,
3394:                                            styleLocalName, decl, m });
3395:                            DOMException de = new DOMException(
3396:                                    DOMException.SYNTAX_ERR, s);
3397:                            // <rave>
3398:                            // BEGIN RAVE MODIFICATIONS
3399:                            de.initCause(e);
3400:                            // END RAVE MODIFICATIONS
3401:                            // </rave>
3402:                            if (userAgent == null)
3403:                                throw de;
3404:                            userAgent.displayError(de);
3405:                        } finally {
3406:                            element = null;
3407:                            cssBaseURI = null;
3408:                        }
3409:                    }
3410:
3411:                    // Fall through
3412:                case MutationEvent.REMOVAL:
3413:                    boolean removed = false;
3414:
3415:                    if (evt.getPrevValue() != null
3416:                            && evt.getPrevValue().length() > 0) {
3417:                        // Check if the style map has cascaded styles which
3418:                        // come from the inline style attribute.
3419:                        for (int i = getNumberOfProperties() - 1; i >= 0; --i) {
3420:                            if (style.isComputed(i)
3421:                                    && style.getOrigin(i) == StyleMap.INLINE_AUTHOR_ORIGIN
3422:                                    && !updated[i]) {
3423:                                removed = true;
3424:                                updated[i] = true;
3425:                            }
3426:                        }
3427:                    }
3428:
3429:                    if (removed) {
3430:                        invalidateProperties(elt, null, updated, true);
3431:                    } else {
3432:                        int count = 0;
3433:                        // Invalidate the relative values
3434:                        boolean fs = (fontSizeIndex == -1) ? false
3435:                                : updated[fontSizeIndex];
3436:                        boolean lh = (lineHeightIndex == -1) ? false
3437:                                : updated[lineHeightIndex];
3438:                        boolean cl = (colorIndex == -1) ? false
3439:                                : updated[colorIndex];
3440:
3441:                        for (int i = getNumberOfProperties() - 1; i >= 0; --i) {
3442:                            if (updated[i]) {
3443:                                count++;
3444:                            } else if ((fs && style.isFontSizeRelative(i))
3445:                                    || (lh && style.isLineHeightRelative(i))
3446:                                    || (cl && style.isColorRelative(i))) {
3447:                                updated[i] = true;
3448:                                clearComputedValue(style, i);
3449:                                count++;
3450:                            }
3451:                        }
3452:
3453:                        if (count > 0) {
3454:                            int[] props = new int[count];
3455:                            count = 0;
3456:                            for (int i = getNumberOfProperties() - 1; i >= 0; --i) {
3457:                                if (updated[i]) {
3458:                                    props[count++] = i;
3459:                                }
3460:                            }
3461:                            invalidateProperties(elt, props, null, true);
3462:                        }
3463:                    }
3464:                    break;
3465:
3466:                default:
3467:                    // Must not happen
3468:                    throw new InternalError("Invalid attrChangeType");
3469:                }
3470:            }
3471:
3472:            private static void clearComputedValue(StyleMap style, int n) {
3473:                if (style.isNullCascaded(n)) {
3474:                    style.putValue(n, null);
3475:                } else {
3476:                    Value v = style.getValue(n);
3477:                    if (v instanceof  ComputedValue) {
3478:                        ComputedValue cv = (ComputedValue) v;
3479:                        v = cv.getCascadedValue();
3480:                        style.putValue(n, v);
3481:                    }
3482:                }
3483:                style.putComputed(n, false);
3484:            }
3485:
3486:            /**
3487:             * Invalidates all the properties of the given node.
3488:             * 
3489:             */
3490:            protected void invalidateProperties(Node node, int[] properties,
3491:                    boolean[] updated, boolean recascade) {
3492:
3493:                if (!(node instanceof  CSSStylableElement))
3494:                    return; // Not Stylable sub tree
3495:
3496:                CSSStylableElement elt = (CSSStylableElement) node;
3497:                StyleMap style = elt.getComputedStyleMap(null);
3498:                if (style == null)
3499:                    return; // Nothing to invalidate.
3500:
3501:                boolean[] diffs = new boolean[getNumberOfProperties()];
3502:                if (updated != null) {
3503:                    for (int i = 0; i < updated.length; i++) {
3504:                        diffs[i] = updated[i];
3505:                    }
3506:                }
3507:                if (properties != null) {
3508:                    for (int i = 0; i < properties.length; i++) {
3509:                        diffs[properties[i]] = true;
3510:                    }
3511:                }
3512:                int count = 0;
3513:                if (!recascade) {
3514:                    for (int i = 0; i < diffs.length; i++) {
3515:                        if (diffs[i])
3516:                            count++;
3517:                    }
3518:                } else {
3519:                    StyleMap newStyle = getCascadedStyleMap(elt, null);
3520:                    elt.setComputedStyleMap(null, newStyle);
3521:                    for (int i = 0; i < diffs.length; i++) {
3522:                        if (diffs[i]) {
3523:                            count++;
3524:                            continue; // Already marked changed.
3525:                        }
3526:
3527:                        // Value nv = getComputedStyle(elt, null, i);
3528:                        Value nv = newStyle.getValue(i);
3529:                        Value ov = null;
3530:                        if (!style.isNullCascaded(i)) {
3531:                            ov = style.getValue(i);
3532:                            if (ov instanceof  ComputedValue) {
3533:                                ov = ((ComputedValue) ov).getCascadedValue();
3534:                            }
3535:                        }
3536:
3537:                        if (nv == ov)
3538:                            continue;
3539:                        if ((nv != null) && (ov != null)) {
3540:                            if (nv.equals(ov))
3541:                                continue;
3542:                            String ovCssText = ov.getCssText();
3543:                            String nvCssText = nv.getCssText();
3544:                            if ((nvCssText == ovCssText)
3545:                                    || ((nvCssText != null) && nvCssText
3546:                                            .equals(ovCssText)))
3547:                                continue;
3548:                        }
3549:                        count++;
3550:                        diffs[i] = true;
3551:                    }
3552:                }
3553:                int[] props = null;
3554:                if (count != 0) {
3555:                    props = new int[count];
3556:                    count = 0;
3557:                    for (int i = 0; i < diffs.length; i++) {
3558:                        if (diffs[i])
3559:                            props[count++] = i;
3560:                    }
3561:                }
3562:                propagateChanges(elt, props, recascade);
3563:            }
3564:
3565:            /**
3566:             * Propagates the changes that occurs on the parent of the given node.
3567:             * Props is a list of known 'changed' properties.
3568:             * If recascade is true then the stylesheets will be applied
3569:             * again to see if the any new rules apply (or old rules don't
3570:             * apply).
3571:             */
3572:            protected void propagateChanges(Node node, int[] props,
3573:                    boolean recascade) {
3574:                if (!(node instanceof  CSSStylableElement))
3575:                    return;
3576:                CSSStylableElement elt = (CSSStylableElement) node;
3577:                StyleMap style = elt.getComputedStyleMap(null);
3578:                if (style != null) {
3579:                    boolean[] updated = styleDeclarationUpdateHandler.updatedProperties;
3580:                    for (int i = getNumberOfProperties() - 1; i >= 0; --i) {
3581:                        updated[i] = false;
3582:                    }
3583:                    if (props != null) {
3584:                        for (int i = props.length - 1; i >= 0; --i) {
3585:                            int idx = props[i];
3586:                            updated[idx] = true;
3587:                        }
3588:                    }
3589:
3590:                    // Invalidate the relative values
3591:                    boolean fs = (fontSizeIndex == -1) ? false
3592:                            : updated[fontSizeIndex];
3593:                    boolean lh = (lineHeightIndex == -1) ? false
3594:                            : updated[lineHeightIndex];
3595:                    boolean cl = (colorIndex == -1) ? false
3596:                            : updated[colorIndex];
3597:
3598:                    int count = 0;
3599:                    for (int i = getNumberOfProperties() - 1; i >= 0; --i) {
3600:                        if (updated[i]) {
3601:                            count++;
3602:                        } else if ((fs && style.isFontSizeRelative(i))
3603:                                || (lh && style.isLineHeightRelative(i))
3604:                                || (cl && style.isColorRelative(i))) {
3605:                            updated[i] = true;
3606:                            clearComputedValue(style, i);
3607:                            count++;
3608:                        }
3609:                    }
3610:
3611:                    if (count == 0) {
3612:                        props = null;
3613:                    } else {
3614:                        props = new int[count];
3615:                        count = 0;
3616:                        for (int i = getNumberOfProperties() - 1; i >= 0; --i) {
3617:                            if (updated[i]) {
3618:                                props[count++] = i;
3619:                            }
3620:                        }
3621:                        firePropertiesChangedEvent(elt, props);
3622:                    }
3623:                }
3624:
3625:                int[] inherited = props;
3626:                if (props != null) {
3627:                    // Filter out uninheritable properties when we 
3628:                    // propogate to children.
3629:                    int count = 0;
3630:                    for (int i = 0; i < props.length; i++) {
3631:                        ValueManager vm = valueManagers[props[i]];
3632:                        if (vm.isInheritedProperty())
3633:                            count++;
3634:                        else
3635:                            props[i] = -1;
3636:                    }
3637:
3638:                    if (count == 0) {
3639:                        // nothing to propogate for sure
3640:                        inherited = null;
3641:                    } else {
3642:                        inherited = new int[count];
3643:                        count = 0;
3644:                        for (int i = 0; i < props.length; i++)
3645:                            if (props[i] != -1)
3646:                                inherited[count++] = props[i];
3647:                    }
3648:                }
3649:
3650:                CSSImportedElementRoot ier = getImportedChild(node);
3651:                if (ier != null) {
3652:                    Node c = ier.getFirstChild();
3653:                    // Don't recascade trees that have been imported.
3654:                    // If you do it will use the stylesheets from this
3655:                    // document instead of the original document.  Also
3656:                    // currently there isn't any supported way to modify
3657:                    // the content imported from the other document so
3658:                    // the cascade can't change.
3659:                    invalidateProperties(c, inherited, null, ier.getIsLocal());
3660:                }
3661:                for (Node n = node.getFirstChild(); n != null; n = n
3662:                        .getNextSibling()) {
3663:                    invalidateProperties(n, inherited, null, recascade);
3664:                }
3665:            }
3666:
3667:            /**
3668:             * To parse a style declaration and update a StyleMap.
3669:             */
3670:            protected class StyleDeclarationUpdateHandler extends
3671:                    DocumentAdapter implements  ShorthandManager.PropertyHandler {
3672:                public StyleMap styleMap;
3673:                public boolean[] updatedProperties = new boolean[getNumberOfProperties()];
3674:
3675:                // <rave>
3676:                // BEGIN RAVE MODIFICATIONS
3677:                Object location;
3678:                int lineno;
3679:
3680:                // ENBD RAVE MODIFICATIONS
3681:                // </rave>
3682:                /**
3683:                 * <b>SAC</b>: Implements {@link
3684:                 * DocumentHandler#property(String,LexicalUnit,boolean)}.
3685:                 */
3686:                public void property(String name, LexicalUnit value,
3687:                        boolean important) throws CSSException {
3688:                    int i = getPropertyIndex(name);
3689:                    if (i == -1) {
3690:                        i = getShorthandIndex(name);
3691:                        if (i == -1) {
3692:                            // Unknown property
3693:                            return;
3694:                        }
3695:                        // <rave>
3696:                        // BEGIN RAVE MODIFICATIONS
3697:                        try {
3698:                            expandingShorthandProperty = i;
3699:                            // END RAVE MODIFICATIONS
3700:                            // </rave>
3701:                            shorthandManagers[i].setValues(CSSEngine.this ,
3702:                                    this , value, important);
3703:                            // <rave>
3704:                            // BEGIN RAVE MODIFICATIONS
3705:                            expandingShorthandProperty = -1;
3706:                        } catch (DOMException e) {
3707:                            // Something bad happened
3708:                            displayError(e, location, lineno + parser.getLine()
3709:                                    - 1, parser.getColumn());
3710:                            // Continue processing - we're supposed to ignore
3711:                            // errant declarations!!!
3712:                        }
3713:                        // END RAVE MODIFICATIONS
3714:                        // </rave>
3715:                    } else {
3716:                        if (styleMap.isImportant(i)) {
3717:                            // The previous value is important, and a value
3718:                            // from a style attribute cannot be important...
3719:                            return;
3720:                        }
3721:
3722:                        updatedProperties[i] = true;
3723:
3724:                        Value v = valueManagers[i].createValue(value,
3725:                                CSSEngine.this );
3726:                        // <rave>
3727:                        // BEGIN RAVE MODIFICATIONS
3728:                        // Track the value source
3729:                        if (v instanceof  AbstractValue) { // Should I add to Value interface???
3730:                            AbstractValue av = (AbstractValue) v;
3731:                            av.setLocation(location);
3732:                            av.setLineNumber(lineno + parser.getLine() - 1);
3733:                        }
3734:                        // END RAVE MODIFICATIONS
3735:                        // </rave>
3736:                        styleMap.putMask(i, (short) 0);
3737:                        styleMap.putValue(i, v);
3738:                        styleMap.putOrigin(i, StyleMap.INLINE_AUTHOR_ORIGIN);
3739:                    }
3740:                }
3741:            }
3742:
3743:            /**
3744:             * Called when a non-CSS presentational hint has been updated.
3745:             */
3746:            protected void nonCSSPresentationalHintUpdated(
3747:                    CSSStylableElement elt, StyleMap style, String property,
3748:                    MutationEvent evt) {
3749:                // System.err.println("update: " + property);
3750:                int idx = getPropertyIndex(property);
3751:
3752:                if (style.isImportant(idx)) {
3753:                    // The current value is important, and a value
3754:                    // from an XML attribute cannot be important...
3755:                    return;
3756:                }
3757:
3758:                switch (style.getOrigin(idx)) {
3759:                case StyleMap.AUTHOR_ORIGIN:
3760:                case StyleMap.INLINE_AUTHOR_ORIGIN:
3761:                    // The current value has a greater priority
3762:                    return;
3763:                }
3764:
3765:                switch (evt.getAttrChange()) {
3766:                case MutationEvent.ADDITION:
3767:                case MutationEvent.MODIFICATION:
3768:                    element = elt;
3769:                    try {
3770:                        LexicalUnit lu;
3771:                        lu = parser.parsePropertyValue(evt.getNewValue());
3772:                        ValueManager vm = valueManagers[idx];
3773:                        Value v = vm.createValue(lu, CSSEngine.this );
3774:                        style.putMask(idx, (short) 0);
3775:                        style.putValue(idx, v);
3776:                        style.putOrigin(idx, StyleMap.NON_CSS_ORIGIN);
3777:                    } catch (Exception e) {
3778:                        String m = e.getMessage();
3779:                        if (m == null)
3780:                            m = "";
3781:                        String u = ((documentURI == null) ? "<unknown>"
3782:                                : documentURI.toString());
3783:                        String s = Messages.formatMessage(
3784:                                "property.syntax.error.at", new Object[] { u,
3785:                                        property, evt.getNewValue(), m });
3786:                        DOMException de = new DOMException(
3787:                                DOMException.SYNTAX_ERR, s);
3788:                        // <rave>
3789:                        // BEGIN RAVE MODIFICATIONS
3790:                        de.initCause(e);
3791:                        // END RAVE MODIFICATIONS
3792:                        // </rave>
3793:                        if (userAgent == null)
3794:                            throw de;
3795:                        userAgent.displayError(de);
3796:                    } finally {
3797:                        element = null;
3798:                        cssBaseURI = null;
3799:                    }
3800:                    break;
3801:
3802:                case MutationEvent.REMOVAL: {
3803:                    int[] invalid = { idx };
3804:                    invalidateProperties(elt, invalid, null, true);
3805:                    return;
3806:                }
3807:                }
3808:
3809:                boolean[] updated = styleDeclarationUpdateHandler.updatedProperties;
3810:                for (int i = getNumberOfProperties() - 1; i >= 0; --i) {
3811:                    updated[i] = false;
3812:                }
3813:                updated[idx] = true;
3814:
3815:                // Invalidate the relative values
3816:                boolean fs = idx == fontSizeIndex;
3817:                boolean lh = idx == lineHeightIndex;
3818:                boolean cl = idx == colorIndex;
3819:                int count = 0;
3820:
3821:                for (int i = getNumberOfProperties() - 1; i >= 0; --i) {
3822:                    if (updated[i]) {
3823:                        count++;
3824:                    } else if ((fs && style.isFontSizeRelative(i))
3825:                            || (lh && style.isLineHeightRelative(i))
3826:                            || (cl && style.isColorRelative(i))) {
3827:                        updated[i] = true;
3828:                        clearComputedValue(style, i);
3829:                        count++;
3830:                    }
3831:                }
3832:
3833:                int[] props = new int[count];
3834:                count = 0;
3835:                for (int i = getNumberOfProperties() - 1; i >= 0; --i) {
3836:                    if (updated[i]) {
3837:                        props[count++] = i;
3838:                    }
3839:                }
3840:
3841:                invalidateProperties(elt, props, null, true);
3842:            }
3843:
3844:            /**
3845:             * To handle the insertion of a CSSStyleSheetNode in the
3846:             * associated document.
3847:             */
3848:            protected class DOMNodeInsertedListener implements  EventListener {
3849:                public void handleEvent(Event evt) {
3850:                    EventTarget et = evt.getTarget();
3851:                    if (et instanceof  CSSStyleSheetNode) {
3852:                        styleSheetNodes = null;
3853:                        // Invalidate all the CSSStylableElements in the document.
3854:                        invalidateProperties(document.getDocumentElement(),
3855:                                null, null, true);
3856:                        return;
3857:                    }
3858:                    if (et instanceof  CSSStylableElement) {
3859:                        // Invalidate the CSSStylableElement siblings, to
3860:                        // correctly match the adjacent selectors and
3861:                        // first-child pseudo-class.
3862:                        for (Node n = ((Node) evt.getTarget()).getNextSibling(); n != null; n = n
3863:                                .getNextSibling()) {
3864:                            invalidateProperties(n, null, null, true);
3865:                        }
3866:                    }
3867:                }
3868:            }
3869:
3870:            /**
3871:             * To handle the removal of a CSSStyleSheetNode from the
3872:             * associated document.
3873:             */
3874:            protected class DOMNodeRemovedListener implements  EventListener {
3875:                public void handleEvent(Event evt) {
3876:                    EventTarget et = evt.getTarget();
3877:                    if (et instanceof  CSSStyleSheetNode) {
3878:                        // Wait for the DOMSubtreeModified to do the invalidations
3879:                        // because at this time the node is in the tree.
3880:                        styleSheetRemoved = true;
3881:                    } else if (et instanceof  CSSStylableElement) {
3882:                        // Wait for the DOMSubtreeModified to do the invalidations
3883:                        // because at this time the node is in the tree.
3884:                        removedStylableElementSibling = ((Node) et)
3885:                                .getNextSibling();
3886:                    }
3887:                    // Clears the computed styles in the removed tree.
3888:                    disposeStyleMaps((Node) et);
3889:                }
3890:            }
3891:
3892:            /**
3893:             * To handle the removal of a CSSStyleSheetNode from the
3894:             * associated document.
3895:             */
3896:            protected class DOMSubtreeModifiedListener implements  EventListener {
3897:                public void handleEvent(Event evt) {
3898:                    if (styleSheetRemoved) {
3899:                        styleSheetRemoved = false;
3900:                        styleSheetNodes = null;
3901:
3902:                        // Invalidate all the CSSStylableElements in the document.
3903:                        invalidateProperties(document.getDocumentElement(),
3904:                                null, null, true);
3905:                    } else if (removedStylableElementSibling != null) {
3906:                        // Invalidate the CSSStylableElement siblings, to
3907:                        // correctly match the adjacent selectors and
3908:                        // first-child pseudo-class.
3909:                        for (Node n = removedStylableElementSibling; n != null; n = n
3910:                                .getNextSibling()) {
3911:                            invalidateProperties(n, null, null, true);
3912:                        }
3913:                        removedStylableElementSibling = null;
3914:                    }
3915:                }
3916:            }
3917:
3918:            /**
3919:             * To handle the modification of a CSSStyleSheetNode.
3920:             */
3921:            protected class DOMCharacterDataModifiedListener implements 
3922:                    EventListener {
3923:                public void handleEvent(Event evt) {
3924:                    Node n = (Node) evt.getTarget();
3925:                    if (n.getParentNode() instanceof  CSSStyleSheetNode) {
3926:                        styleSheetNodes = null;
3927:                        // Invalidate all the CSSStylableElements in the document.
3928:                        invalidateProperties(document.getDocumentElement(),
3929:                                null, null, true);
3930:                    }
3931:                }
3932:            }
3933:
3934:            /**
3935:             * To handle the element attributes modification in the associated
3936:             * document.
3937:             */
3938:            protected class DOMAttrModifiedListener implements  EventListener {
3939:                public void handleEvent(Event evt) {
3940:                    EventTarget et = evt.getTarget();
3941:                    if (!(et instanceof  CSSStylableElement)) {
3942:                        // Not a stylable element.
3943:                        return;
3944:                    }
3945:
3946:                    MutationEvent mevt = (MutationEvent) evt;
3947:                    if (mevt.getNewValue().equals(mevt.getPrevValue()))
3948:                        return; // no change really...
3949:
3950:                    Node attr = mevt.getRelatedNode();
3951:                    String attrNS = attr.getNamespaceURI();
3952:                    String name = (attrNS == null) ? attr.getNodeName() : attr
3953:                            .getLocalName();
3954:
3955:                    CSSStylableElement elt = (CSSStylableElement) et;
3956:                    // <rave>
3957:                    // BEGIN RAVE MODIFICATIONS
3958:
3959:                    try {
3960:
3961:                        // END RAVE MODIFICATIONS
3962:                        // </rave>
3963:                        StyleMap style = elt.getComputedStyleMap(null);
3964:                        if (style != null) {
3965:                            if ((attrNS == null && styleNamespaceURI == null)
3966:                                    || (attrNS != null && attrNS
3967:                                            .equals(styleNamespaceURI))) {
3968:                                if (name.equals(styleLocalName)) {
3969:                                    // The style declaration attribute has been modified.
3970:                                    inlineStyleAttributeUpdated(elt, style,
3971:                                            mevt);
3972:                                    return;
3973:                                }
3974:                            }
3975:                            // <rave>
3976:                            // BEGIN RAVE MODIFICATIONS
3977:                            // Note - we've gotta update this code to do proper
3978:                            // nonpresentational hints updates!
3979:                            // END RAVE MODIFICATIONS
3980:                            // </rave>
3981:                            if (nonCSSPresentationalHints != null) {
3982:                                if ((attrNS == null && nonCSSPresentationalHintsNamespaceURI == null)
3983:                                        || (attrNS != null && attrNS
3984:                                                .equals(nonCSSPresentationalHintsNamespaceURI))) {
3985:                                    if (nonCSSPresentationalHints
3986:                                            .contains(name)) {
3987:                                        // The 'name' attribute which represents a non CSS
3988:                                        // presentational hint has been modified.
3989:                                        nonCSSPresentationalHintUpdated(elt,
3990:                                                style, name, mevt);
3991:                                        return;
3992:                                    }
3993:                                }
3994:                            }
3995:                        }
3996:
3997:                        if (selectorAttributes != null
3998:                                && selectorAttributes.contains(name)) {
3999:                            // An attribute has been modified, invalidate all the
4000:                            // properties to correctly match attribute selectors.
4001:                            invalidateProperties(elt, null, null, true);
4002:                            for (Node n = elt.getNextSibling(); n != null; n = n
4003:                                    .getNextSibling()) {
4004:                                invalidateProperties(n, null, null, true);
4005:                            }
4006:                        }
4007:                        // <rave>
4008:                        // BEGIN RAVE MODIFICATIONS
4009:                    } catch (DOMException e) {
4010:                        // Something bad happened
4011:                        displayError(e, elt, parser.getLine() - 1, parser
4012:                                .getColumn());
4013:                        // Continue processing - we're supposed to ignore
4014:                        // errant declarations!!!
4015:
4016:                    }
4017:                    // END RAVE MODIFICATIONS
4018:                    // </rave>
4019:                }
4020:            }
4021:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.