Source Code Cross Referenced for DocumentNode.java in  » 6.0-JDK-Modules » j2me » com » sun » perseus » model » 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 » 6.0 JDK Modules » j2me » com.sun.perseus.model 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *
0003:         *
0004:         * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0005:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006:         * 
0007:         * This program is free software; you can redistribute it and/or
0008:         * modify it under the terms of the GNU General Public License version
0009:         * 2 only, as published by the Free Software Foundation.
0010:         * 
0011:         * This program is distributed in the hope that it will be useful, but
0012:         * WITHOUT ANY WARRANTY; without even the implied warranty of
0013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014:         * General Public License version 2 for more details (a copy is
0015:         * included at /legal/license.txt).
0016:         * 
0017:         * You should have received a copy of the GNU General Public License
0018:         * version 2 along with this work; if not, write to the Free Software
0019:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020:         * 02110-1301 USA
0021:         * 
0022:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023:         * Clara, CA 95054 or visit www.sun.com if you need additional
0024:         * information or have any questions.
0025:         */
0026:        package com.sun.perseus.model;
0027:
0028:        import com.sun.perseus.util.RunnableQueue;
0029:        import com.sun.perseus.util.RunnableQueue.RunnableHandler;
0030:
0031:        import com.sun.perseus.j2d.GraphicsProperties;
0032:        import com.sun.perseus.j2d.RenderGraphics;
0033:        import com.sun.perseus.j2d.TextProperties;
0034:        import com.sun.perseus.j2d.Transform;
0035:
0036:        import com.sun.perseus.builder.DefaultFontFace;
0037:
0038:        import com.sun.perseus.parser.ColorParser;
0039:        import com.sun.perseus.parser.ClockParser;
0040:        import com.sun.perseus.parser.LengthParser;
0041:        import com.sun.perseus.parser.NumberListParser;
0042:        import com.sun.perseus.parser.PathParser;
0043:        import com.sun.perseus.parser.TimeConditionParser;
0044:        import com.sun.perseus.parser.TransformListParser;
0045:        import com.sun.perseus.parser.UnicodeParser;
0046:        import com.sun.perseus.parser.ViewBoxParser;
0047:
0048:        import org.w3c.dom.Document;
0049:        import org.w3c.dom.Element;
0050:        import org.w3c.dom.Node;
0051:        import org.w3c.dom.DOMException;
0052:
0053:        import java.io.PrintStream;
0054:
0055:        import java.util.Enumeration;
0056:        import java.util.Hashtable;
0057:        import java.util.Hashtable;
0058:        import java.util.Vector;
0059:
0060:        import com.sun.perseus.util.SVGConstants;
0061:
0062:        /**
0063:         * A <code>DocumentNode</code> represents the root of an SVG document model.
0064:         * A DocumentNode is a <code>Viewport</code> and centralizes some functions such
0065:         * as the font data base, tree updates management and event dispatching.
0066:         * The <code>DocumentNode</code> also manages the <code>RunnableQueue</code>
0067:         * used to synchronize all access to the SVG document.
0068:         *
0069:         * @version $Id: DocumentNode.java,v 1.24 2006/06/29 10:47:30 ln156897 Exp $
0070:         */
0071:        public class DocumentNode extends Viewport implements  Document {
0072:            /**
0073:             * Default spatial resolution value (96dpi);
0074:             */
0075:            public static final float DEFAULT_PIXEL_MM_SIZE = 0.26458333333333333333333333333333f; // 96dpi
0076:
0077:            /**
0078:             * Size of a pixel, in millimeters. This is needed in unit
0079:             * conversion as well.
0080:             */
0081:            protected float pxMMSize = DEFAULT_PIXEL_MM_SIZE;
0082:
0083:            /**
0084:             * Coordinate in user space coordinates. This value is used as a working
0085:             * array for all nodes in the document tree.
0086:             */
0087:            protected float[] upt = { 0, 0 };
0088:
0089:            /**
0090:             * A map itself containing map of ElementHandlers
0091:             * namespaceURI -> Hashtable
0092:             *
0093:             * the contained Hashtable maps:
0094:             * localName -> ElementNode prototype.
0095:             */
0096:            protected Hashtable namespaceMap = new Hashtable();
0097:
0098:            /**
0099:             * Used to store additional traits NS., i.e., traits
0100:             * which are not naturally supported by the element.
0101:             * elt -> Hashtable.
0102:             * 
0103:             * The contained Hashtable maps:
0104:             * namespace -> Hashtable.
0105:             *
0106:             * The contained Hashtable maps:
0107:             * localname -> value.
0108:             */
0109:            protected Hashtable unknownTraitsNS = null;
0110:
0111:            /**
0112:             * Parser used to convert clock values
0113:             */
0114:            protected final ClockParser clockParser = new ClockParser();
0115:
0116:            /**
0117:             * Parser used to convert unit and unitless floating point
0118:             * values to floats. 
0119:             */
0120:            protected final LengthParser lengthParser = new LengthParser();
0121:
0122:            /**
0123:             * Parser used to convert time condition values
0124:             */
0125:            protected final TimeConditionParser timeConditionParser = new TimeConditionParser();
0126:
0127:            /**
0128:             * Parser used to convert number list values
0129:             */
0130:            protected NumberListParser numberListParser = new NumberListParser();
0131:
0132:            /**
0133:             * Parser used to convert transform values
0134:             */
0135:            protected TransformListParser transformListParser = new TransformListParser();
0136:
0137:            /**
0138:             * Parser used to convert color values
0139:             */
0140:            protected final ColorParser colorParser = new ColorParser();
0141:
0142:            /**
0143:             * Parser used to convert viewBox values
0144:             */
0145:            protected final ViewBoxParser viewBoxParser = new ViewBoxParser();
0146:
0147:            /**
0148:             * Parser used to convert path data
0149:             */
0150:            protected final PathParser pathParser = new PathParser();
0151:
0152:            /**
0153:             * Parser used to convert unicode ranges.
0154:             */
0155:            protected UnicodeParser unicodeParser = new UnicodeParser();
0156:
0157:            /**
0158:             * The <code>ImageLoader</code> handles the desired policy
0159:             * for loading image resources.
0160:             */
0161:            protected ImageLoader imageLoader;
0162:
0163:            /**
0164:             * The default FontFace used by this RenderGraphics. 
0165:             * @see com.sun.perseus.builder.DefaultFontFace
0166:             */
0167:            protected FontFace defaultFontFace;
0168:
0169:            /**
0170:             * Exceptions can be delayed and later thrown. This is used, for example,
0171:             * to keep processing an invalid d attribute on a <path> element and only
0172:             * throw the exception after the corresponding model node has been hooked
0173:             * to the tree (while the exception was thrown by the path parser during the
0174:             * processing of the d attribute). This is only used when loading a document
0175:             * to comply to the error processing required for <path>, <polyline> and 
0176:             * <polygon> processing of the 'd' and 'points' attributes.
0177:             */
0178:            protected DOMException delayedException;
0179:
0180:            /**
0181:             * The default namespace URI for elements created in that document,
0182:             * in case the namespace URI in createElementNS is empty.
0183:             */
0184:            protected String defaultNamespaceURI = SVGConstants.SVG_NAMESPACE_URI;
0185:
0186:            /**
0187:             * The Document URI
0188:             */
0189:            protected String docURI;
0190:
0191:            /**
0192:             * The set of initial <code>FontFace</code> used by this 
0193:             * <code>RenderingGraphics</code>.
0194:             * <br />
0195:             * <b>NOTE</b><br />It is the responsibility of the user of the 
0196:             * Perseus software to make sure that the <code>RenderGraphics</code>
0197:             * initial <code>fontFamiliy</code> value is indeed the same as that 
0198:             * of the various fonts in the <code>initialFontFaces</code> array.
0199:             * <br />
0200:             * If there is a mismatch, then text content that does not
0201:             * specify the <code>font-family</code> property will not match against the
0202:             * <code>initialFontFaces</code> instances and only the defaultFont will be
0203:             * used.
0204:             *
0205:             * @see com.sun.perseus.builder.DefaultFontFace
0206:             */
0207:            protected FontFace[] initialFontFaces;
0208:
0209:            /**
0210:             * The FontFace data base used by this RenderGraphics.
0211:             * The Hashtable maps font-family names to a Vector 
0212:             * of fonts with that font-family value.
0213:             */
0214:            protected Hashtable fontFaceDB = null;
0215:
0216:            /**
0217:             * Set of currently active TraitAnimations.
0218:             */
0219:            protected Vector activeTraitAnims = new Vector(0);
0220:
0221:            /**
0222:             * Set of currently active MediaElements.
0223:             */
0224:            protected Vector activeMediaElements = new Vector(0);
0225:
0226:            /**
0227:             * Controls whether the document is 'playing'. This is used to disable the 
0228:             * media elements like audio when the document is not playing and allows
0229:             * sampling the document without having the audio stream played.
0230:             */
0231:            protected boolean playing;
0232:
0233:            /**
0234:             * EventSupport is used for listener registration and event
0235:             * dispatching.
0236:             */
0237:            protected EventSupport eventSupport = new EventSupport();
0238:
0239:            /**
0240:             * The associated <code>UpdateListener</code> is notified of
0241:             * all mutation events on this <code>DocumentNode</code> tree
0242:             */
0243:            protected UpdateListener updateListener;
0244:
0245:            /**
0246:             * The associated <code>RunnableQueue</code>, if any, is
0247:             * managing updates to the <code>DocumentNode</code> and any of
0248:             * its descendants. In effect, the updateQueue provides the 
0249:             * synchronization needed for updates to a document tree.
0250:             */
0251:            protected RunnableQueue updateQueue;
0252:
0253:            /**
0254:             * The associated <code>RunnableHandler</code> which should be 
0255:             * notified when Runnable acting on this DocumentNode tree are
0256:             * run.
0257:             */
0258:            protected RunnableHandler runHandler;
0259:
0260:            /**
0261:             * Maps ids to ElementNode instances
0262:             */
0263:            protected Hashtable idToElement = new Hashtable();
0264:
0265:            /**
0266:             * Used to store nodes with ids before they are inserted into 
0267:             * the document tree.
0268:             */
0269:            protected Hashtable reservedIds = new Hashtable();
0270:
0271:            /**
0272:             * Maps prefixes to namespace entries.
0273:             */
0274:            protected Hashtable prefixes = new Hashtable();
0275:
0276:            /**
0277:             * Maps namespaces to prefixes.
0278:             */
0279:            protected Hashtable namespaces = new Hashtable();
0280:
0281:            /**
0282:             * A DocumentNode is a root container. This object provides
0283:             * support for root time container behavior.
0284:             */
0285:            protected TimeContainerRootSupport timeContainerRootSupport = new TimeContainerRootSupport();
0286:
0287:            /**
0288:             * Map of unresolved IDRefs (id -> Vector of referencing IDRefs)
0289:             */
0290:            protected Hashtable unresolvedIDRefs = new Hashtable();
0291:
0292:            /**
0293:             * Vector of animations. This is used only at parse time.
0294:             * @see #validate
0295:             */
0296:            protected Vector animations = new Vector(0);
0297:
0298:            /**
0299:             * We use a single instance of ModelEvent per DocumentNode instance.
0300:             * This allows multiple instances of DocumentNodes to co-exist.
0301:             */
0302:            protected ModelEvent engineEvent = null;
0303:
0304:            /**
0305:             * Transform used to perform hit detection on text chunks.
0306:             */
0307:            protected Transform hitChunkTxf = new Transform(null);
0308:
0309:            /**
0310:             * Transform used to compute bounding boxes on text chunks.
0311:             */
0312:            protected Transform bboxChunkTxf = new Transform(null);
0313:
0314:            /**
0315:             * Transform used to render text chunks.
0316:             */
0317:            protected Transform paintChunkTxf = new Transform(null);
0318:
0319:            /**
0320:             * Transform used to render glyphs.
0321:             */
0322:            protected Transform paintGlyphTxf = new Transform(null);
0323:
0324:            /**
0325:             * Transform used to compute bounding boxes on glyphs.
0326:             */
0327:            protected Transform bboxGlyphTxf = new Transform(null);
0328:
0329:            /**
0330:             * Transform used to perform hit testing on glyphs
0331:             */
0332:            protected Transform hitGlyphTxf = new Transform(null);
0333:
0334:            /**
0335:             * Default constructor
0336:             */
0337:            public DocumentNode() {
0338:                ownerDocument = this ;
0339:                engineEvent = new ModelEvent("", this );
0340:
0341:                // Clear the 'in document tree' bit
0342:                canRenderState &= CAN_RENDER_IN_DOCUMENT_TREE_MASK;
0343:
0344:                // Clear the renderable bit
0345:                canRenderState &= CAN_RENDER_RENDERABLE_MASK;
0346:            }
0347:
0348:            /**
0349:             * Returns the initial value of the given Object-valued property.
0350:             * @return the initial value of the given property, null if the property is
0351:             * unknown.
0352:             */
0353:            protected Object getInitialPropertyState(final int propertyIndex) {
0354:                switch (propertyIndex) {
0355:                case GraphicsNode.PROPERTY_FILL:
0356:                    return GraphicsProperties.INITIAL_FILL;
0357:                case GraphicsNode.PROPERTY_STROKE:
0358:                    return GraphicsProperties.INITIAL_STROKE;
0359:                case GraphicsNode.PROPERTY_COLOR:
0360:                    return GraphicsProperties.INITIAL_COLOR;
0361:                case GraphicsNode.PROPERTY_STROKE_DASH_ARRAY:
0362:                    return GraphicsProperties.INITIAL_STROKE_DASH_ARRAY;
0363:                case TextNode.PROPERTY_FONT_FAMILY:
0364:                    return TextNode.INITIAL_FONT_FAMILY;
0365:                default:
0366:                    return null;
0367:                }
0368:            }
0369:
0370:            /**
0371:             * Returns the initial value of the given float-valued property.
0372:             * @return the initial value of the given property, 0 if the property is
0373:             * unknown.
0374:             */
0375:            protected float getInitialFloatPropertyState(final int propertyIndex) {
0376:                switch (propertyIndex) {
0377:                case GraphicsNode.PROPERTY_STROKE_WIDTH:
0378:                    return GraphicsNode.INITIAL_STROKE_WIDTH;
0379:                case GraphicsNode.PROPERTY_STROKE_MITER_LIMIT:
0380:                    return GraphicsNode.INITIAL_STROKE_MITER_LIMIT;
0381:                case GraphicsNode.PROPERTY_STROKE_DASH_OFFSET:
0382:                    return GraphicsNode.INITIAL_STROKE_DASH_OFFSET;
0383:                case TextNode.PROPERTY_FONT_SIZE:
0384:                    return TextNode.INITIAL_FONT_SIZE;
0385:                default:
0386:                    return 0;
0387:                }
0388:            }
0389:
0390:            /**
0391:             * Returns the initial value of the given packed property.
0392:             * @return the initial value of the given packed property, zero if the 
0393:             *         property is unknown.
0394:             */
0395:            protected int getInitialPackedPropertyState(final int propertyIndex) {
0396:                switch (propertyIndex) {
0397:                case GraphicsNode.PROPERTY_FILL_RULE:
0398:                    return CompositeGraphicsNode.INITIAL_FILL_RULE_IMPL;
0399:                case GraphicsNode.PROPERTY_STROKE_LINE_JOIN:
0400:                    return CompositeGraphicsNode.INITIAL_STROKE_LINE_JOIN_IMPL;
0401:                case GraphicsNode.PROPERTY_STROKE_LINE_CAP:
0402:                    return CompositeGraphicsNode.INITIAL_STROKE_LINE_CAP_IMPL;
0403:                case GraphicsNode.PROPERTY_DISPLAY:
0404:                    return CompositeGraphicsNode.INITIAL_DISPLAY_IMPL;
0405:                case GraphicsNode.PROPERTY_VISIBILITY:
0406:                    return CompositeGraphicsNode.INITIAL_VISIBILITY_IMPL;
0407:                case GraphicsNode.PROPERTY_FILL_OPACITY:
0408:                    return CompositeGraphicsNode.INITIAL_FILL_OPACITY_IMPL;
0409:                case GraphicsNode.PROPERTY_STROKE_OPACITY:
0410:                    return CompositeGraphicsNode.INITIAL_STROKE_OPACITY_IMPL;
0411:                case GraphicsNode.PROPERTY_OPACITY:
0412:                    return CompositeGraphicsNode.INITIAL_OPACITY_IMPL;
0413:                case TextNode.PROPERTY_FONT_STYLE:
0414:                    return StructureNode.INITIAL_FONT_STYLE_IMPL;
0415:                case TextNode.PROPERTY_FONT_WEIGHT:
0416:                    return StructureNode.INITIAL_FONT_WEIGHT_IMPL;
0417:                case TextNode.PROPERTY_TEXT_ANCHOR:
0418:                    return StructureNode.INITIAL_TEXT_ANCHOR_IMPL;
0419:
0420:                default:
0421:                    return 0;
0422:                }
0423:            }
0424:
0425:            /**
0426:             * Returns the value of the given Object-valued property.
0427:             *
0428:             * @return the value of the given property, null if the property is 
0429:             *         unknown.
0430:             */
0431:            protected Object getPropertyState(final int propertyIndex) {
0432:                return getInitialPropertyState(propertyIndex);
0433:            }
0434:
0435:            /**
0436:             * Returns the value of the given float property.
0437:             *
0438:             * @return the value of the given property, null if the property is 
0439:             *         unknown.
0440:             */
0441:            protected float getFloatPropertyState(final int propertyIndex) {
0442:                return getInitialFloatPropertyState(propertyIndex);
0443:            }
0444:
0445:            /**
0446:             * Returns the value of the given packed property.
0447:             *
0448:             * @return the value of the given property, null if the property is 
0449:             *         unknown.
0450:             */
0451:            protected int getPackedPropertyState(final int propertyIndex) {
0452:                return getInitialPackedPropertyState(propertyIndex);
0453:            }
0454:
0455:            /**
0456:             * Paints this node into the input <code>RenderGraphics</code>.
0457:             *
0458:             * @param rg the <tt>RenderGraphics</tt> where the node should paint itself
0459:             */
0460:            public void paint(final RenderGraphics rg) {
0461:                if (canRenderState != 0) {
0462:                    return;
0463:                }
0464:
0465:                paint(getFirstChildNode(), rg);
0466:            }
0467:
0468:            /**
0469:             * Initializes the ModelEvent's singleton object with the input data.
0470:             *
0471:             * @param type the event type
0472:             * @param target the event target
0473:             * @param time the event time
0474:             */
0475:            ModelEvent initEngineEvent(final String type, final ModelNode target) {
0476:                ModelEvent engineEvent = new ModelEvent(type, target);
0477:                engineEvent.type = type;
0478:                engineEvent.target = target;
0479:                engineEvent.currentTarget = null;
0480:                engineEvent.anchor = null;
0481:                engineEvent.stopPropagation = false;
0482:                engineEvent.repeatCount = 0;
0483:                engineEvent.keyChar = ModelEvent.CHAR_UNDEFINED;
0484:
0485:                return engineEvent;
0486:            }
0487:
0488:            /**
0489:             * When the document finishes loading, it notifies the ImageLoader so that 
0490:             * it can start loading raster images, in case it waited for the load 
0491:             * completion to start (e.g., as in SVGImageLoader).
0492:             *
0493:             * @param isLoaded the new loaded state
0494:             */
0495:            public final void setLoaded(final boolean isLoaded) {
0496:                super .setLoaded(isLoaded);
0497:                if (isLoaded == true) {
0498:                    getImageLoader().documentLoaded(this );
0499:                }
0500:            }
0501:
0502:            /**
0503:             * @return true if the DocumentNode is in the playing state.
0504:             */
0505:            public boolean isPlaying() {
0506:                return playing;
0507:            }
0508:
0509:            /**
0510:             * @param isPlaying the new playing state.
0511:             */
0512:            public void setPlaying(final boolean isPlaying) {
0513:                this .playing = isPlaying;
0514:            }
0515:
0516:            /**
0517:             * @throws DOMException the delayed exception if one was set.
0518:             */
0519:            public void checkDelayedException() throws DOMException {
0520:                if (delayedException != null) {
0521:                    throw delayedException;
0522:                }
0523:            }
0524:
0525:            /**
0526:             * @return the delayed exception, if any
0527:             */
0528:            public DOMException getDelayedException() {
0529:                return delayedException;
0530:            }
0531:
0532:            /**
0533:             * @param de the new delayedException
0534:             */
0535:            protected void setDelayedException(DOMException de) {
0536:                delayedException = de;
0537:            }
0538:
0539:            /**
0540:             * @return the size of a px CSS unit in millimeters.
0541:             */
0542:            public float getPixelMMSize() {
0543:                return pxMMSize;
0544:            }
0545:
0546:            /**
0547:             * Controls the size of a pixel in millimeters
0548:             * @param newPxMMSize the new pixel size value, in millimeter
0549:             */
0550:            public void setPixelMMSize(final float newPxMMSize) {
0551:                this .pxMMSize = newPxMMSize;
0552:            }
0553:
0554:            /**
0555:             * @return true if this node is hooked to the document tree, i.e., if it top
0556:             * most ancestor is the DocumentNode.
0557:             */
0558:            boolean inDocumentTree() {
0559:                return true;
0560:            }
0561:
0562:            /**
0563:             * Invoked by <code>IDRef</code> instances when they need the given
0564:             * input id reference to be resolved to an <code>ElementNode</code>
0565:             * reference. If there is a known <code>ElementNode</code> with the
0566:             * requested id, the <code>IDRef</code>'s <code>resolve()</code> 
0567:             * method is invoked immediately. Otherwise, the method will be called
0568:             * as soon as the id reference is resolved.
0569:             *
0570:             * @param idRef the IDRef which needs to be resolved.
0571:             * @param id the id the IDRef needs to resolve to an
0572:             *        <code>ElementNode</code> reference.
0573:             */
0574:            public void resolveIDRef(final IDRef idRef, final String id) {
0575:                ElementNode ref = (ElementNode) getElementById(id);
0576:                if (ref != null) {
0577:                    idRef.resolveTo(ref);
0578:                } else {
0579:                    if (unresolvedIDRefs != null) {
0580:                        Vector idRefs = (Vector) unresolvedIDRefs.get(id);
0581:                        if (idRefs == null) {
0582:                            idRefs = new Vector(1);
0583:                            unresolvedIDRefs.put(id, idRefs);
0584:                        }
0585:                        idRefs.addElement(idRef);
0586:                    }
0587:                }
0588:            }
0589:
0590:            /**
0591:             * Should be called when a document node is no longer needed 
0592:             * and could be garbage collected.
0593:             */
0594:            public void dispose() {
0595:                clearLayouts();
0596:            }
0597:
0598:            /**
0599:             * Gets the <code>ImageLoader</code> instance.
0600:             *
0601:             * @return the <code>ImageLoader</code> associated to this
0602:             *         <code>DocumentNode</code>.
0603:             */
0604:            public ImageLoader getImageLoader() {
0605:                if (imageLoader == null) {
0606:                    imageLoader = new DefaultImageLoader();
0607:                }
0608:                return imageLoader;
0609:            }
0610:
0611:            /**
0612:             * Sets the <code>ImageLoader</code> for this document.
0613:             *
0614:             * @param imageLoader the new <code>ImageLoader</code> this
0615:             *        <code>DocumentNode</code> should use.
0616:             */
0617:            public void setImageLoader(final ImageLoader imageLoader) {
0618:                this .imageLoader = imageLoader;
0619:            }
0620:
0621:            /**
0622:             * A <code>DocumentNode</code> has no expanded content, so this 
0623:             * returns null.    
0624:             *
0625:             * @return a reference to the node's last expanded child, or null if there
0626:             *         are no expanded children. This forces the computation of expanded
0627:             *         content if needed.
0628:             */
0629:            ModelNode getLastExpandedChild() {
0630:                return null;
0631:            }
0632:
0633:            /**
0634:             * A <code>DocumentNode</code> has no expanded content, so this 
0635:             * returns null.    
0636:             *
0637:             * @return a reference to the node's first expanded child, or null if there
0638:             *         are no expanded children. This forces the computation of expanded
0639:             *         content if needed.
0640:             */
0641:            ModelNode getFirstExpandedChild() {
0642:                return null;
0643:            }
0644:
0645:            /**
0646:             * Some node types (such as <code>ElementNodeProxy</code>) have
0647:             * expanded children that they compute in some specific
0648:             * way depending on the implementation.     
0649:             *
0650:             * @return a reference to the node's first expanded child, or null if there
0651:             *         are no expanded children. 
0652:             */
0653:            public ModelNode getFirstComputedExpandedChild() {
0654:                return null;
0655:            }
0656:
0657:            /**
0658:             * Utility method. Unhooks the expanded content.
0659:             */
0660:            protected void unhookExpandedQuiet() {
0661:            }
0662:
0663:            /**
0664:             * The node's URI base to use to resolve URI references
0665:             * If a URI base value was set on this node, then that value
0666:             * is returned. Otherwise, this method returns the parent's 
0667:             * URI base. If there is not URI base on this node and if there
0668:             * is not parent, then this method returns null.
0669:             *
0670:             * @return the node's URI base to use to resolve relative URI references.
0671:             */
0672:            public String getURIBase() {
0673:                return docURI;
0674:            }
0675:
0676:            /**
0677:             * Sets this document's URI
0678:             * 
0679:             * @param docURI the new document URI
0680:             */
0681:            public void setDocumentURI(final String docURI) {
0682:                if (ElementNode.equal(docURI, this .docURI)) {
0683:                    return;
0684:                }
0685:                modifyingNode();
0686:                this .docURI = docURI;
0687:                modifiedNode();
0688:            }
0689:
0690:            /**
0691:             * @return the <code>UpdateListener</code> associated with this viewport.
0692:             * @see #setUpdateListener
0693:             */
0694:            public UpdateListener getUpdateListener() {
0695:                if (parent == null || parent == this ) {
0696:                    return updateListener;
0697:                } else {
0698:                    return parent.getUpdateListener();
0699:                }
0700:            }
0701:
0702:            /**
0703:             * @return the <code>RunnableQueue</code> which managers updates to this
0704:             *         <code>DocumentNode</code> hierarchy.
0705:             */
0706:            public RunnableQueue getUpdateQueue() {
0707:                return updateQueue;
0708:            }
0709:
0710:            /**
0711:             * @return the <code>RunnableQueue.RunnableHandler</code> which is notified
0712:             *         of <code>Runnable</code> instances ran against this DocumentNode.
0713:             */
0714:            public RunnableHandler getRunnableHandler() {
0715:                return runHandler;
0716:            }
0717:
0718:            /**
0719:             * @param updateQueue the <code>RunnableQueue</code> which manages 
0720:             *        updates to this document tree.
0721:             */
0722:            public void setUpdateQueue(final RunnableQueue updateQueue) {
0723:                this .updateQueue = updateQueue;
0724:            }
0725:
0726:            /**
0727:             * @param runHandler the <code>RunnableHandler</code> which listens to 
0728:             *        <code>Runnable</code> execution for this 
0729:             *        <code>DocumentNode</code>.
0730:             */
0731:            public void setRunnableHandler(final RunnableHandler runHandler) {
0732:                this .runHandler = runHandler;
0733:            }
0734:
0735:            /**
0736:             * Sets the <code>UpdateListener</code> associated with this viewport.
0737:             * All updates made to this tree will be reported to the input
0738:             * <code>UpdateListener</code>
0739:             *
0740:             * @param updateListener the new <code>UpdateListener</code> which will
0741:             *        receive notifications for updates on this tree.
0742:             */
0743:            public void setUpdateListener(final UpdateListener updateListener) {
0744:                this .updateListener = updateListener;
0745:            }
0746:
0747:            /**
0748:             * @return The <code>EventSupport</code> instance associated
0749:             *         with this <code>DocumentNode</code>
0750:             */
0751:            public EventSupport getEventSupport() {
0752:                return eventSupport;
0753:            }
0754:
0755:            /**
0756:             * If no such element exists, this returns null.
0757:             * If more than one element has an id attribute with that value, what
0758:             * is returned is undefined.
0759:             *
0760:             */
0761:            public Element getElementById(final String id) {
0762:                return (ElementNode) idToElement.get(id);
0763:            }
0764:
0765:            /**
0766:             * Return the <code>Element</code> in the current document with
0767:             * the given unique ID. The difference with getElementById is 
0768:             * that this method may return a node that is not inserted in
0769:             * the document tree. This is used in ElementNode.setId().
0770:             *
0771:             * @param id the ID of the object to be retrieved.
0772:             * @return the Element that matches with the given ID or
0773:             * <code>null</code> if the ID is not present.
0774:             *
0775:             * @throws NullPointerException if id is null
0776:             */
0777:            Element getElementByIdAll(final String id) {
0778:                ElementNode n = (ElementNode) idToElement.get(id);
0779:                if (n == null) {
0780:                    n = (ElementNode) reservedIds.get(id);
0781:                }
0782:
0783:                return n;
0784:            }
0785:
0786:            /**
0787:             * Adds the input element to the list of identified nodes.
0788:             *
0789:             * @param element the new element with a non-null identifier
0790:             * 
0791:             * @throws NullPointerException if the input element is null or if its
0792:             *         id is null.
0793:             */
0794:            void addIdentifiedNode(final ElementNode element) {
0795:                // Add element to id map
0796:                idToElement.put(element.getId(), element);
0797:
0798:                // Check if there are any unresolved references for 
0799:                // the newly identified node.
0800:                if (unresolvedIDRefs != null) {
0801:                    Vector idRefs = (Vector) unresolvedIDRefs.get(element
0802:                            .getId());
0803:                    if (idRefs != null) {
0804:                        int n = idRefs.size();
0805:                        for (int i = 0; i < n; i++) {
0806:                            IDRef idRef = (IDRef) idRefs.elementAt(i);
0807:                            idRef.resolveTo(element);
0808:                        }
0809:                        unresolvedIDRefs.remove(element.getId());
0810:                    }
0811:                }
0812:
0813:                // If the id was in the reserved map, remove it.
0814:                reservedIds.remove(element.getId());
0815:            }
0816:
0817:            /**
0818:             * Reserves the given id. This is used to be able to check for 
0819:             * duplicate identifiers.
0820:             *
0821:             * @param element the element reserving the id. Should not be null.
0822:             *        The element id should not be null.
0823:             */
0824:            void reserveId(final ElementNode element) {
0825:                reservedIds.put(element.getId(), element);
0826:            }
0827:
0828:            /**
0829:             * Remove element from the list of identified nodes
0830:             *
0831:             * @param element the element to remove from the list of identified nodes
0832:             * @throws NullPointerException if element is null or if its id is null.
0833:             */
0834:            void removeIdentifiedNode(final ElementNode element) {
0835:                String id = element.getId();
0836:                if (idToElement.get(id) == element) {
0837:                    idToElement.remove(element.getId());
0838:                }
0839:            }
0840:
0841:            /**
0842:             * Schedules the given Runnable object for a later invocation in
0843:             * the document's update thread, and returns.
0844:             * <br />
0845:             * If there is no <code>updateQueue</code> the <code>Runnable</code>
0846:             * is run before returning. Otherwise, the <code>Runnable</code>
0847:             * is scheduled in the associated <code>updateQueue</code>
0848:             *
0849:             * @param r the <code>Runnable</code> to put at the end of the
0850:             *        execution list.
0851:             * @throws IllegalStateException if there is an associated 
0852:             *         <code>RunnableQueue</code> but that one has exited
0853:             *         or was not started.
0854:             */
0855:            public void invokeLater(final Runnable r) {
0856:                if (updateQueue == null) {
0857:                    r.run();
0858:                } else {
0859:                    updateQueue.invokeLater(r, runHandler);
0860:                }
0861:            }
0862:
0863:            /**
0864:             * Waits until the given Runnable's <tt>run()</tt> has returned.
0865:             * <em>Note: <tt>invokeAndWait()</tt> must not be called from the
0866:             * current thread (for example from the <tt>run()</tt> method of the
0867:             * argument)</em>.
0868:             *
0869:             * @param r the <code>Runnable</code> to put at the end of the 
0870:             *        execution list.
0871:             * @throws IllegalStateException if there is an associated RunnableQueue
0872:             *         which has exited or was not started.
0873:             * @throws InterruptedException if the thread is interrupted while 
0874:             *         waiting for the input <code>Runnable</code> to complete
0875:             *         its execution.
0876:             */
0877:            public void invokeAndWait(final Runnable r)
0878:                    throws InterruptedException {
0879:
0880:                if (updateQueue == null) {
0881:                    r.run();
0882:                } else {
0883:                    updateQueue.invokeAndWait(r, runHandler);
0884:                }
0885:            }
0886:
0887:            /**
0888:             * Waits until the given Runnable's <tt>run()</tt> has returned.
0889:             * <em>Note: <tt>safeInvokeAndWait()</tt> may be called from any thread.
0890:             * This method checks if this thread is the update thread, in which case
0891:             * the Runnable is invoked directly. Otherwise, it delegates to the 
0892:             * invokeAndWait method.
0893:             *
0894:             * @param r the <code>Runnable</code> to put at the end of the 
0895:             *        execution list. Should not be null.
0896:             * @param runHandler the <code>RunnableHandler</code> to notify 
0897:             *        once the <code>Runnable</code> has finished executing.
0898:             *        Should not be null.
0899:             * @throws IllegalStateException if getThread() is null or if the
0900:             *         thread returned by getThread() is the current one.
0901:             */
0902:            public void safeInvokeAndWait(final Runnable r) {
0903:                if (updateQueue == null) {
0904:                    r.run();
0905:                } else {
0906:                    updateQueue.safeInvokeAndWait(r, runHandler);
0907:                }
0908:            }
0909:
0910:            /**
0911:             * This is where font matching happens. This method compares the 
0912:             * font attributes (such as 'font-family' or 'font-weight') with
0913:             * the corresponding attributes in the FontFace set. At a minimum,
0914:             * this method returns a single font in the list: the defaultFontFace.
0915:             *
0916:             * This process follows the algorithm described in section
0917:             * 15.5 of the CSS2 specification (http://www.w3.org/TR/REC-CSS2/)
0918:             *
0919:             * In SVG Tiny, the font attributes on Text are:
0920:             * - font-family
0921:             * - font-size
0922:             * - font-style
0923:             * - font-weight
0924:             *
0925:             * Therefore, font matching is limited to these attributes (i.e.,
0926:             * font-variant is not used). 
0927:             *
0928:             * IMPORTANT NOTE: The FontFaces data base is built when the 
0929:             * setFontFaceSet method is invoked, from the input array. The
0930:             * input array is expected to be in document order and the 
0931:             * fontFaceDB hashtable's value Vectors contain values which are
0932:             * in the same order as in the array passed to setFontFaceSet.
0933:             * Therefore, the resolveFontFaces returns matches in document 
0934:             * order. This is important for situations where a less specific
0935:             * FontFace (font-family:Arial, font-style: any) would appear 
0936:             * before (in document order) a more specific FontFace (font-family:Arial,
0937:             * font-style: italic). In that case, only the less specific FontFace
0938:             * will be the match for a text with font-family set to Arial
0939:             * and font-style set to italic.
0940:             *
0941:             * @param tp The <code>TextProperties</code> containing the font selection
0942:             *        properties.
0943:             * @return a chain of <code>FontFace.Match</code>. The first element is
0944:             *         <b>always</b> the default font face. The next element (if any),
0945:             *         is the first match, ordered according to the CSS2 font matching
0946:             *         rules.
0947:             */
0948:            protected FontFace.Match resolveFontFaces(final TextProperties tp) {
0949:                // If no default font face has been set, set the default one now.
0950:                if (defaultFontFace == null) {
0951:                    setDefaultFontFace(DefaultFontFace.getDefaultFontFace());
0952:                }
0953:
0954:                // If no initial font face has been set, set the default one now.
0955:                if (initialFontFaces == null) {
0956:                    setInitialFontFaces(DefaultFontFace.getInitialFontFaces());
0957:                }
0958:
0959:                // Build the font face data base if it has not been
0960:                // built already
0961:                if (fontFaceDB == null) {
0962:                    setFontFaceSetSilent(null);
0963:                }
0964:
0965:                // Iterate over each matching font-family name
0966:                Vector fontFamilyMatch = null;
0967:                String[] fontFamily = tp.getFontFamily();
0968:                int nff = 0;
0969:                if (fontFamily != null) {
0970:                    nff = fontFamily.length;
0971:                }
0972:
0973:                FontFace.Match firstMatch = new FontFace.Match(defaultFontFace);
0974:                FontFace.Match lastMatch = firstMatch;
0975:                for (int i = 0; i < nff; i++) {
0976:                    fontFamilyMatch = (Vector) fontFaceDB.get(fontFamily[i]);
0977:                    lastMatch = matchFontFaces(fontFamilyMatch, lastMatch, tp);
0978:                }
0979:
0980:                return firstMatch;
0981:            }
0982:
0983:            /**
0984:             * Matches values in the input fontFamily map against the 
0985:             * current context values.
0986:             * 
0987:             * @param fontFamily the 'candidate' <tt>FontFace</tt>s
0988:             * @param lastMatch the last <code>FontFace.Match</code>. Any new
0989:             *        match sub-chain (i.e., for the input fontFamily) will be 
0990:             *        chained after <code>lastMatch</code>
0991:             * @param tp the <tt>TextProperties</tt> defining the applicable
0992:             *        font selection properties
0993:             *
0994:             * @return the first <code>FontFace.Match</code> node, head of
0995:             *         the chain of matches, linked in precedence order.
0996:             *
0997:             * @see #resolveFontFaces
0998:             */
0999:            protected FontFace.Match matchFontFaces(final Vector fontFamily,
1000:                    final FontFace.Match lastMatch, final TextProperties tp) {
1001:                if (fontFamily == null) {
1002:                    return lastMatch;
1003:                }
1004:
1005:                int n = fontFamily.size();
1006:                int fontStyle = tp.getFontStyle();
1007:                float fontSize = tp.getFontSize();
1008:                int fontWeight = tp.getFontWeight();
1009:
1010:                FontFace.Match match = null, firstMatch = null;
1011:                for (int i = 0; i < n; i++) {
1012:                    FontFace ff = (FontFace) fontFamily.elementAt(i);
1013:
1014:                    // First, match on font-style. 
1015:                    if ((ff.getFontStyles() & fontStyle) != 0
1016:                            || ((fontStyle == TextNode.FONT_STYLE_ITALIC) && ((ff
1017:                                    .getFontStyles() & TextNode.FONT_STYLE_OBLIQUE) != 0))) {
1018:
1019:                        // Match on font-size
1020:                        if (ff.getFontSizes() == null) {
1021:                            match = new FontFace.Match(ff);
1022:                            match.distance = ff.fontWeightDistance(fontWeight);
1023:                            firstMatch = addMatch(firstMatch, match);
1024:                        } else {
1025:                            float[] fs = ff.getFontSizes();
1026:                            for (int j = 0; j < fs.length; j++) {
1027:                                if (fs[j] == fontSize) {
1028:                                    match = new FontFace.Match(ff);
1029:                                    match.distance = ff
1030:                                            .fontWeightDistance(fontWeight);
1031:                                    firstMatch = addMatch(firstMatch, match);
1032:                                    break;
1033:                                }
1034:                            }
1035:                        }
1036:                    }
1037:                }
1038:
1039:                if (match == null) {
1040:                    return lastMatch;
1041:                } else {
1042:                    if (lastMatch != null) {
1043:                        lastMatch.next = firstMatch;
1044:                    }
1045:
1046:                    while (match.next != null) {
1047:                        match = match.next;
1048:                    }
1049:                    return match;
1050:                }
1051:            }
1052:
1053:            /**
1054:             * Chains <code>newMatch</code> into the chain starting with
1055:             * <code>firstMatch. This inserts the new matching font face
1056:             * according to the CSS2 font matching rules.
1057:             *
1058:             * @param firstMatch the first match in the chain of matching
1059:             *        <code>FontFace.Match</code> instances.
1060:             * @param newMatch the new <code>FontFace.Match</code> object to
1061:             *        insert into the chain.
1062:             * @return the head of the <code>FontFace.Match</code> chain after
1063:             *         insertion of the new match.
1064:             */
1065:            protected FontFace.Match addMatch(final FontFace.Match firstMatch,
1066:                    final FontFace.Match newMatch) {
1067:                if (firstMatch == null) {
1068:                    return newMatch;
1069:                }
1070:
1071:                FontFace.Match curMatch = firstMatch;
1072:                FontFace.Match prevMatch = null;
1073:                while (curMatch != null
1074:                        && curMatch.distance <= newMatch.distance) {
1075:                    prevMatch = curMatch;
1076:                    curMatch = curMatch.next;
1077:                }
1078:
1079:                if (curMatch == null) {
1080:                    // We reached the end of the list, simply append newMatch
1081:                    prevMatch.next = newMatch;
1082:                    return firstMatch;
1083:                } else {
1084:                    // We need to insert newMatch before curMatch
1085:                    if (prevMatch == null) {
1086:                        // Inserted at the start of the list
1087:                        newMatch.next = firstMatch;
1088:                        return newMatch;
1089:                    } else {
1090:                        // Insert somewhere in the middle of the list
1091:                        prevMatch.next = newMatch;
1092:                        newMatch.next = curMatch;
1093:                        return firstMatch;
1094:                    }
1095:                }
1096:            }
1097:
1098:            /**
1099:             * Sets the default FontFace, i.e., the FontFace which 
1100:             * will always be the last element in the 
1101:             * FontFace array returned from <code>resolveFontFaces</code>
1102:             *
1103:             * @param newDefaultFontFace the fall back font
1104:             * @throws IllegalArgumentException if defaultFontFace is null
1105:             */
1106:            public void setDefaultFontFace(final FontFace newDefaultFontFace) {
1107:                if (newDefaultFontFace == null) {
1108:                    throw new IllegalArgumentException();
1109:                }
1110:
1111:                if (defaultFontFace == newDefaultFontFace) {
1112:                    return;
1113:                }
1114:
1115:                this .defaultFontFace = newDefaultFontFace;
1116:                clearLayouts();
1117:            }
1118:
1119:            /**
1120:             * Sets the intial set of FontFaces. The intent for this property
1121:             * is to provide a set of FontFaces that match the initial 
1122:             * font-family property for varying values of font-weight and 
1123:             * font-style. However, this can also be used to provide support
1124:             * for the logical font-faces.
1125:             *
1126:             * The RenderGraphics will keep a reference to the input array which
1127:             * should not be modified after it has been passed to this RenderGraphics.
1128:             *
1129:             * @param newInitialFontFaces should not be null and should not contain
1130:             *        null values
1131:             *
1132:             * @throws IllegalArgumentException if initialFontFaces is null or if
1133:             *         one of the array values is null.
1134:             */
1135:            public void setInitialFontFaces(final FontFace[] newInitialFontFaces) {
1136:                if (newInitialFontFaces == null) {
1137:                    throw new IllegalArgumentException();
1138:                }
1139:
1140:                if (initialFontFaces == newInitialFontFaces) {
1141:                    return;
1142:                }
1143:
1144:                for (int i = 0; i < newInitialFontFaces.length; i++) {
1145:                    if (newInitialFontFaces[i] == null) {
1146:                        throw new IllegalArgumentException();
1147:                    }
1148:                }
1149:
1150:                this .initialFontFaces = newInitialFontFaces;
1151:                clearLayouts();
1152:            }
1153:
1154:            /**
1155:             * @return The default FontFace used by this RenderGraphics
1156:             */
1157:            public FontFace getDefaultFontFace() {
1158:                return defaultFontFace;
1159:            }
1160:
1161:            /**
1162:             * @return The set of FontFaces used to match the initial font-family
1163:             * value
1164:             */
1165:            public FontFace[] getInitialFontFaces() {
1166:                return initialFontFaces;
1167:            }
1168:
1169:            /**
1170:             * Sets the set of FontFaces that this Document uses
1171:             * to display text.
1172:             *
1173:             * @param fontFaceSet the set of font faces to use
1174:             */
1175:            public void setFontFaceSet(final FontFace[] fontFaceSet) {
1176:                setFontFaceSetSilent(fontFaceSet);
1177:                clearLayouts();
1178:            }
1179:
1180:            /**
1181:             * Sets the set of FontFaces this document uses but does
1182:             * not generate a modifyingNode notification.
1183:             *
1184:             * @param fontFaceSet the set of font faces to use
1185:             */
1186:            protected void setFontFaceSetSilent(final FontFace[] fontFaceSet) {
1187:                fontFaceDB = new Hashtable();
1188:                growFontFaceDB(fontFaceDB, fontFaceSet);
1189:                growFontFaceDB(fontFaceDB, initialFontFaces);
1190:            }
1191:
1192:            /**
1193:             * Adds a new <code>FontFace</code> to the data base
1194:             * available to the document.
1195:             *
1196:             * @param fontFace the new <code>FontFace</code> which is 
1197:             *        now available.
1198:             */
1199:            public void addFontFace(final FontFace fontFace) {
1200:                if (fontFaceDB == null) {
1201:                    // This initializes the data base
1202:                    setFontFaceSetSilent(null);
1203:                }
1204:
1205:                growFontFaceDB(fontFaceDB, new FontFace[] { fontFace });
1206:                clearLayouts();
1207:            }
1208:
1209:            /**
1210:             * Builds a Hashtable of font faces to map font family 
1211:             * names to FontFace instances.
1212:             * 
1213:             * @param ffDB the font data base to grow
1214:             * @param fontFaceSet array of <tt>FontFace</tt> instances to add
1215:             *        to the font data base.
1216:             * @see #setFontFaceSet
1217:             */
1218:            protected void growFontFaceDB(final Hashtable ffDB,
1219:                    final FontFace[] fontFaceSet) {
1220:                if (fontFaceSet == null) {
1221:                    return;
1222:                }
1223:
1224:                // Grow the font data base from the new fontFaceSet
1225:                for (int i = 0; i < fontFaceSet.length; i++) {
1226:                    FontFace ff = fontFaceSet[i];
1227:                    String[] fontFamilies = ff.getFontFamilies();
1228:                    if (fontFamilies != null) {
1229:                        // null is actually a CSS error. But CSS is silent
1230:                        // about errors, so we should not break or halt on
1231:                        // such a condition which should be expected
1232:                        for (int j = 0; j < fontFamilies.length; j++) {
1233:                            Vector v = (Vector) ffDB.get(fontFamilies[j]);
1234:                            if (v == null) {
1235:                                v = new Vector(1);
1236:                                ffDB.put(fontFamilies[j], v);
1237:                                v.addElement(ff);
1238:                            } else {
1239:                                if (!v.contains(ff)) {
1240:                                    v.addElement(ff);
1241:                                }
1242:                            }
1243:                        }
1244:                    }
1245:                }
1246:            }
1247:
1248:            /**
1249:             * Returns the current time for the document, i.e., the time at which the 
1250:             * document was last sampled.
1251:             *
1252:             * @return the time at which the container was last sampled.
1253:             */
1254:            public Time getCurrentTime() {
1255:                return timeContainerRootSupport.lastSampleTime;
1256:            }
1257:
1258:            /**
1259:             * Applies all currently active animations.
1260:             */
1261:            public void applyAnimations() {
1262:                int n = activeTraitAnims.size();
1263:                // System.err.println(">>>>>>>>>>>>>>>>>> There are : " + n 
1264:                //                      + " active animations");
1265:                for (int i = 0; i < n; i++) {
1266:                    // System.err.println("Applying TraitAnim [" + i + "]");
1267:                    ((TraitAnim) activeTraitAnims.elementAt(i)).apply();
1268:                }
1269:            }
1270:
1271:            /**
1272:             * Applies all currently active media if this document is playing.
1273:             */
1274:            void applyMedia() {
1275:                /*
1276:                if (playing) {
1277:                    int n = activeMediaElements.size();
1278:                    for (int i = n - 1; i >= 0; i--) {
1279:                        ((MediaElement) activeMediaElements.elementAt(i)).playMedia();
1280:                    }
1281:                } else {
1282:                    int n = activeMediaElements.size();
1283:                    for (int i = n - 1; i >= 0; i--) {
1284:                        ((MediaElement) activeMediaElements.elementAt(i)).endMedia();
1285:                    }
1286:                }
1287:                 */
1288:            }
1289:
1290:            /**
1291:             * This method is typically called by this element's time container
1292:             * when it samples.
1293:             *
1294:             * Note that if this element is not in the waiting or playing
1295:             * state, this does nothing. This method assumes that successive
1296:             * calls are made with increasing time values.
1297:             *
1298:             * @param currentTime the time at which this element should be 
1299:             *        sampled. 
1300:             */
1301:            public void sample(final Time currentTime) {
1302:                timeContainerRootSupport.sample(currentTime);
1303:                // System.err.println(">>>>>>>>>>>>>>>>>> currentTime : " 
1304:                //                      + currentTime);
1305:                // timeContainerRootSupport.dump();
1306:            }
1307:
1308:            /**
1309:             * Increments the animation or media timeline for this SVGImage (in
1310:             * seconds). As the name implies, this method is intended to move only
1311:             * forward in the timeline and typically should be used to animate SVG
1312:             * content in the "one-shot" rendering mode. Setting negative values will
1313:             * throw an Exception. It is important to note that setting large increments
1314:             * of time would result in dropping or skipping of frames as per the SVG
1315:             * animation model.
1316:             *
1317:             * @throws IllegalArgumentException if the specified time is negative.
1318:             */
1319:            public void incrementTime(float seconds) {
1320:                if (seconds < 0) {
1321:                    throw new IllegalArgumentException();
1322:                }
1323:
1324:                long lastSampleTime = timeContainerRootSupport.lastSampleTime.value;
1325:                timeContainerRootSupport.sample(new Time(lastSampleTime
1326:                        + (long) (seconds * 1000)));
1327:            }
1328:
1329:            /**
1330:             * Initializes the timing engine.
1331:             */
1332:            public void initializeTimingEngine() {
1333:                timeContainerRootSupport.initialize();
1334:            }
1335:
1336:            /**
1337:             * Debug helper
1338:             * 
1339:             * @return a textual description of this viewport object
1340:             */
1341:            /*
1342:            public String toString() {
1343:                return "[Document(zoomPan=" + zoomAndPan + ", width=" 
1344:                    + width + " height=" + height 
1345:                    + " txf=" + transform
1346:                    + "]";
1347:            }
1348:             */
1349:
1350:            /**
1351:             * Traces this viewport tree
1352:             */
1353:            public void dump() {
1354:                dump(this , "", System.err);
1355:            }
1356:
1357:            /**
1358:             * Debug: traces the input ModelNode, using the input prefix
1359:             * 
1360:             * @param n the node to dump
1361:             * @param prefix the string used to prefix the node information
1362:             * @param out the stream where the node structure is dumped.
1363:             */
1364:            static void dump(final ModelNode n, final String prefix,
1365:                    final PrintStream out) {
1366:                out.print(prefix + " " + n);
1367:                if (n instanceof  ElementNode) {
1368:                    ElementNode e = (ElementNode) n;
1369:                    String pfx = n.ownerDocument.toPrefix(e.getNamespaceURI(),
1370:                            e);
1371:                    if (pfx == null || pfx.length() == 0) {
1372:                        out.println(" <" + e.getLocalName() + ">");
1373:                    } else {
1374:                        out.println(" <" + pfx + ":" + e.getLocalName() + ">");
1375:                    }
1376:                } else {
1377:                    out.println();
1378:                }
1379:                ModelNode child = n.getFirstChildNode();
1380:                while (child != null) {
1381:                    dump(child, prefix + "+-->", out);
1382:                    child = child.nextSibling;
1383:                }
1384:
1385:                child = n.getFirstExpandedChild();
1386:                while (child != null) {
1387:                    dump(child, prefix + "*~~>", out);
1388:                    child = child.nextSibling;
1389:                }
1390:            }
1391:
1392:            /**
1393:             * @return null as per the DOM Level 2 specification for Document
1394:             *         nodes.
1395:             */
1396:            public String getNamespaceURI() {
1397:                return null;
1398:            }
1399:
1400:            /**
1401:             * @return returns the unprefixed node name. For an SVGElement, this returns
1402:             * the tag name without a prefix.  In case of the Document node, string
1403:             * <code>null/code> is returned.
1404:             */
1405:            public String getLocalName() {
1406:                return null;
1407:            }
1408:
1409:            // JAVADOC COMMENT ELIDED
1410:            public Element createElementNS(String namespaceURI,
1411:                    final String qualifiedName) throws DOMException {
1412:                if (namespaceURI == null || qualifiedName == null) {
1413:                    throw new NullPointerException();
1414:                }
1415:
1416:                // Extract qualified name from the local name.
1417:                String localName = qualifiedName;
1418:                int pi = qualifiedName.indexOf(':');
1419:                if (pi != -1) {
1420:                    if (pi == localName.length() - 1) {
1421:                        // Namepace prefix separator is at the end of the qualified name
1422:                        localName = "";
1423:                    } else {
1424:                        localName = qualifiedName.substring(pi + 1);
1425:                    }
1426:                }
1427:
1428:                //
1429:                // If the namespaceURI is empty, we have two cases:
1430:                // 1. (extremely rare) the content maps some prefix, or the default
1431:                //    namespace, to the "" namespace URI.
1432:                // 2. (extremely common) the content does not have an xmlns declaration
1433:                //    on its root element and the parser reported the root element 
1434:                //    and children as being in the "" namespace URI.
1435:                //
1436:                // The following code means that the situation 1. is _not_ handled. If
1437:                // the author mapped a prefix or the default prefix to the 
1438:                // empty string URI, that will be overriddent by the default namespace.
1439:                if (namespaceURI.length() == 0) {
1440:                    namespaceURI = defaultNamespaceURI;
1441:                }
1442:
1443:                Hashtable lmap = (Hashtable) namespaceMap.get(namespaceURI);
1444:                ElementNode en = null;
1445:                if (lmap != null) {
1446:                    en = (ElementNode) lmap.get(localName);
1447:                    if (en != null) {
1448:                        en = en.newInstance(this );
1449:                    }
1450:                }
1451:
1452:                if (en == null) {
1453:                    checkNCName(localName);
1454:                    en = new GenericElementNode(namespaceURI, localName, this );
1455:                }
1456:
1457:                return en;
1458:            }
1459:
1460:            /**
1461:             * @param name the trait name
1462:             * @return a DOMException describing the unsupported trait error.
1463:             */
1464:            protected DOMException unsupportedTrait(final String name) {
1465:                return new DOMException(DOMException.NOT_SUPPORTED_ERR,
1466:                        Messages.formatMessage(
1467:                                Messages.ERROR_UNSUPPORTED_TRAIT, new String[] {
1468:                                        name, null, getLocalName(),
1469:                                        getNamespaceURI() }));
1470:            }
1471:
1472:            /**
1473:             * Checks if the input trait name is valid and throws a DOMException 
1474:             * with error code NOT_SUPPORTED_ERR if not.
1475:             *
1476:             * @param name the name whose syntax should be checked.
1477:             * @throws DOMException with error code NOT_SUPPORTED_ERR if the 
1478:             * trait name is syntactically incorrect (e.g., null or containing
1479:             * characters not conforming to the Namespaces in XML specification.
1480:             *
1481:             * @see http://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-NCName
1482:             */
1483:            final void checkNCName(final String name) throws DOMException {
1484:                if (name == null || name.length() == 0) {
1485:                    throw unsupportedTrait(name);
1486:                }
1487:
1488:                // NCName        ::=  (Letter | '_') (NCNameChar)*
1489:                // NCNameChar 	 ::=  Letter | Digit | '.' | '-' | '_' | CombiningChar 
1490:                //                      | Extender
1491:                char c = name.charAt(0);
1492:                if (!isLetter(c) && c != '_') {
1493:                    throw unsupportedTrait(name);
1494:                }
1495:
1496:                for (int i = 1; i < name.length(); i++) {
1497:                    c = name.charAt(i);
1498:                    if (!isNCNameChar(c)) {
1499:                        throw unsupportedTrait(name);
1500:                    }
1501:                }
1502:            }
1503:
1504:            final static boolean isNCNameChar(final char c) {
1505:                return isLetter(c) || Character.isDigit(c) || c == '.'
1506:                        || c == '-' || c == '_' || isCombiningChar(c)
1507:                        || isExtender(c);
1508:            }
1509:
1510:            final static boolean isExtender(final int c) {
1511:                return c == 0x00B7 || c == 0x02D0 || c == 0x02D1 || c == 0x0387
1512:                        || c == 0x0640 || c == 0x0E46 || c == 0x0EC6
1513:                        || c == 0x3005 || (c >= 0x3031 && c <= 0x3035)
1514:                        || (c >= 0x309D && c <= 0x309E)
1515:                        || (c >= 0x30FC && c <= 0x30FE);
1516:            }
1517:
1518:            final static boolean isCombiningChar(final int c) {
1519:                return (c >= 0x0300 && c <= 0x0345)
1520:                        || (c >= 0x0360 && c <= 0x0361)
1521:                        || (c >= 0x0483 && c <= 0x0486)
1522:                        || (c >= 0x0591 && c <= 0x05A1)
1523:                        || (c >= 0x05A3 && c <= 0x05B9)
1524:                        || (c >= 0x05BB && c <= 0x05BD) || c == 0x05BF
1525:                        || (c >= 0x05C1 && c <= 0x05C2) || c == 0x05C4
1526:                        || (c >= 0x064B && c <= 0x0652) || c == 0x0670
1527:                        || (c >= 0x06D6 && c <= 0x06DC)
1528:                        || (c >= 0x06DD && c <= 0x06DF)
1529:                        || (c >= 0x06E0 && c <= 0x06E4)
1530:                        || (c >= 0x06E7 && c <= 0x06E8)
1531:                        || (c >= 0x06EA && c <= 0x06ED)
1532:                        || (c >= 0x0901 && c <= 0x0903) || c == 0x093C
1533:                        || (c >= 0x093E && c <= 0x094C) || c == 0x094D
1534:                        || (c >= 0x0951 && c <= 0x0954)
1535:                        || (c >= 0x0962 && c <= 0x0963)
1536:                        || (c >= 0x0981 && c <= 0x0983) || c == 0x09BC
1537:                        || c == 0x09BE || c == 0x09BF
1538:                        || (c >= 0x09C0 && c <= 0x09C4)
1539:                        || (c >= 0x09C7 && c <= 0x09C8)
1540:                        || (c >= 0x09CB && c <= 0x09CD) || c == 0x09D7
1541:                        || (c >= 0x09E2 && c <= 0x09E3) || c == 0x0A02
1542:                        || c == 0x0A3C || c == 0x0A3E || c == 0x0A3F
1543:                        || (c >= 0x0A40 && c <= 0x0A42)
1544:                        || (c >= 0x0A47 && c <= 0x0A48)
1545:                        || (c >= 0x0A4B && c <= 0x0A4D)
1546:                        || (c >= 0x0A70 && c <= 0x0A71)
1547:                        || (c >= 0x0A81 && c <= 0x0A83) || c == 0x0ABC
1548:                        || (c >= 0x0ABE && c <= 0x0AC5)
1549:                        || (c >= 0x0AC7 && c <= 0x0AC9)
1550:                        || (c >= 0x0ACB && c <= 0x0ACD)
1551:                        || (c >= 0x0B01 && c <= 0x0B03) || c == 0x0B3C
1552:                        || (c >= 0x0B3E && c <= 0x0B43)
1553:                        || (c >= 0x0B47 && c <= 0x0B48)
1554:                        || (c >= 0x0B4B && c <= 0x0B4D)
1555:                        || (c >= 0x0B56 && c <= 0x0B57)
1556:                        || (c >= 0x0B82 && c <= 0x0B83)
1557:                        || (c >= 0x0BBE && c <= 0x0BC2)
1558:                        || (c >= 0x0BC6 && c <= 0x0BC8)
1559:                        || (c >= 0x0BCA && c <= 0x0BCD) || c == 0x0BD7
1560:                        || (c >= 0x0C01 && c <= 0x0C03)
1561:                        || (c >= 0x0C3E && c <= 0x0C44)
1562:                        || (c >= 0x0C46 && c <= 0x0C48)
1563:                        || (c >= 0x0C4A && c <= 0x0C4D)
1564:                        || (c >= 0x0C55 && c <= 0x0C56)
1565:                        || (c >= 0x0C82 && c <= 0x0C83)
1566:                        || (c >= 0x0CBE && c <= 0x0CC4)
1567:                        || (c >= 0x0CC6 && c <= 0x0CC8)
1568:                        || (c >= 0x0CCA && c <= 0x0CCD)
1569:                        || (c >= 0x0CD5 && c <= 0x0CD6)
1570:                        || (c >= 0x0D02 && c <= 0x0D03)
1571:                        || (c >= 0x0D3E && c <= 0x0D43)
1572:                        || (c >= 0x0D46 && c <= 0x0D48)
1573:                        || (c >= 0x0D4A && c <= 0x0D4D) || c == 0x0D57
1574:                        || c == 0x0E31 || (c >= 0x0E34 && c <= 0x0E3A)
1575:                        || (c >= 0x0E47 && c <= 0x0E4E) || c == 0x0EB1
1576:                        || (c >= 0x0EB4 && c <= 0x0EB9)
1577:                        || (c >= 0x0EBB && c <= 0x0EBC)
1578:                        || (c >= 0x0EC8 && c <= 0x0ECD)
1579:                        || (c >= 0x0F18 && c <= 0x0F19) || c == 0x0F35
1580:                        || c == 0x0F37 || c == 0x0F39 || c == 0x0F3E
1581:                        || c == 0x0F3F || (c >= 0x0F71 && c <= 0x0F84)
1582:                        || (c >= 0x0F86 && c <= 0x0F8B)
1583:                        || (c >= 0x0F90 && c <= 0x0F95) || c == 0x0F97
1584:                        || (c >= 0x0F99 && c <= 0x0FAD)
1585:                        || (c >= 0x0FB1 && c <= 0x0FB7) || c == 0x0FB9
1586:                        || (c >= 0x20D0 && c <= 0x20DC) || c == 0x20E1
1587:                        || (c >= 0x302A && c <= 0x302F) || c == 0x3099
1588:                        || c == 0x309A;
1589:            }
1590:
1591:            final static boolean isLetter(final int c) {
1592:                return isIdeographic(c) || isBaseChar(c);
1593:            }
1594:
1595:            final static boolean isIdeographic(final int c) {
1596:                return (c >= 0x4E00 && c <= 0x9FA5) || c == 0x3007
1597:                        || (c >= 0x3021 && c <= 0x3029);
1598:            }
1599:
1600:            final static boolean isBaseChar(final int c) {
1601:                return (c >= 0x0041 && c <= 0x005A)
1602:                        || (c >= 0x0061 && c <= 0x007A)
1603:                        || (c >= 0x00C0 && c <= 0x00D6)
1604:                        || (c >= 0x00D8 && c <= 0x00F6)
1605:                        || (c >= 0x00F8 && c <= 0x00FF)
1606:                        || (c >= 0x0100 && c <= 0x0131)
1607:                        || (c >= 0x0134 && c <= 0x013E)
1608:                        || (c >= 0x0141 && c <= 0x0148)
1609:                        || (c >= 0x014A && c <= 0x017E)
1610:                        || (c >= 0x0180 && c <= 0x01C3)
1611:                        || (c >= 0x01CD && c <= 0x01F0)
1612:                        || (c >= 0x01F4 && c <= 0x01F5)
1613:                        || (c >= 0x01FA && c <= 0x0217)
1614:                        || (c >= 0x0250 && c <= 0x02A8)
1615:                        || (c >= 0x02BB && c <= 0x02C1) || c == 0x0386
1616:                        || (c >= 0x0388 && c <= 0x038A) || c == 0x038C
1617:                        || (c >= 0x038E && c <= 0x03A1)
1618:                        || (c >= 0x03A3 && c <= 0x03CE)
1619:                        || (c >= 0x03D0 && c <= 0x03D6) || c == 0x03DA
1620:                        || c == 0x03DC || c == 0x03DE || c == 0x03E0
1621:                        || (c >= 0x03E2 && c <= 0x03F3)
1622:                        || (c >= 0x0401 && c <= 0x040C)
1623:                        || (c >= 0x040E && c <= 0x044F)
1624:                        || (c >= 0x0451 && c <= 0x045C)
1625:                        || (c >= 0x045E && c <= 0x0481)
1626:                        || (c >= 0x0490 && c <= 0x04C4)
1627:                        || (c >= 0x04C7 && c <= 0x04C8)
1628:                        || (c >= 0x04CB && c <= 0x04CC)
1629:                        || (c >= 0x04D0 && c <= 0x04EB)
1630:                        || (c >= 0x04EE && c <= 0x04F5)
1631:                        || (c >= 0x04F8 && c <= 0x04F9)
1632:                        || (c >= 0x0531 && c <= 0x0556) || c == 0x0559
1633:                        || (c >= 0x0561 && c <= 0x0586)
1634:                        || (c >= 0x05D0 && c <= 0x05EA)
1635:                        || (c >= 0x05F0 && c <= 0x05F2)
1636:                        || (c >= 0x0621 && c <= 0x063A)
1637:                        || (c >= 0x0641 && c <= 0x064A)
1638:                        || (c >= 0x0671 && c <= 0x06B7)
1639:                        || (c >= 0x06BA && c <= 0x06BE)
1640:                        || (c >= 0x06C0 && c <= 0x06CE)
1641:                        || (c >= 0x06D0 && c <= 0x06D3) || c == 0x06D5
1642:                        || (c >= 0x06E5 && c <= 0x06E6)
1643:                        || (c >= 0x0905 && c <= 0x0939) || c == 0x093D
1644:                        || (c >= 0x0958 && c <= 0x0961)
1645:                        || (c >= 0x0985 && c <= 0x098C)
1646:                        || (c >= 0x098F && c <= 0x0990)
1647:                        || (c >= 0x0993 && c <= 0x09A8)
1648:                        || (c >= 0x09AA && c <= 0x09B0) || c == 0x09B2
1649:                        || (c >= 0x09B6 && c <= 0x09B9)
1650:                        || (c >= 0x09DC && c <= 0x09DD)
1651:                        || (c >= 0x09DF && c <= 0x09E1)
1652:                        || (c >= 0x09F0 && c <= 0x09F1)
1653:                        || (c >= 0x0A05 && c <= 0x0A0A)
1654:                        || (c >= 0x0A0F && c <= 0x0A10)
1655:                        || (c >= 0x0A13 && c <= 0x0A28)
1656:                        || (c >= 0x0A2A && c <= 0x0A30)
1657:                        || (c >= 0x0A32 && c <= 0x0A33)
1658:                        || (c >= 0x0A35 && c <= 0x0A36)
1659:                        || (c >= 0x0A38 && c <= 0x0A39)
1660:                        || (c >= 0x0A59 && c <= 0x0A5C) || c == 0x0A5E
1661:                        || (c >= 0x0A72 && c <= 0x0A74)
1662:                        || (c >= 0x0A85 && c <= 0x0A8B) || c == 0x0A8D
1663:                        || (c >= 0x0A8F && c <= 0x0A91)
1664:                        || (c >= 0x0A93 && c <= 0x0AA8)
1665:                        || (c >= 0x0AAA && c <= 0x0AB0)
1666:                        || (c >= 0x0AB2 && c <= 0x0AB3)
1667:                        || (c >= 0x0AB5 && c <= 0x0AB9) || c == 0x0ABD
1668:                        || c == 0x0AE0 || (c >= 0x0B05 && c <= 0x0B0C)
1669:                        || (c >= 0x0B0F && c <= 0x0B10)
1670:                        || (c >= 0x0B13 && c <= 0x0B28)
1671:                        || (c >= 0x0B2A && c <= 0x0B30)
1672:                        || (c >= 0x0B32 && c <= 0x0B33)
1673:                        || (c >= 0x0B36 && c <= 0x0B39) || c == 0x0B3D
1674:                        || (c >= 0x0B5C && c <= 0x0B5D)
1675:                        || (c >= 0x0B5F && c <= 0x0B61)
1676:                        || (c >= 0x0B85 && c <= 0x0B8A)
1677:                        || (c >= 0x0B8E && c <= 0x0B90)
1678:                        || (c >= 0x0B92 && c <= 0x0B95)
1679:                        || (c >= 0x0B99 && c <= 0x0B9A) || c == 0x0B9C
1680:                        || (c >= 0x0B9E && c <= 0x0B9F)
1681:                        || (c >= 0x0BA3 && c <= 0x0BA4)
1682:                        || (c >= 0x0BA8 && c <= 0x0BAA)
1683:                        || (c >= 0x0BAE && c <= 0x0BB5)
1684:                        || (c >= 0x0BB7 && c <= 0x0BB9)
1685:                        || (c >= 0x0C05 && c <= 0x0C0C)
1686:                        || (c >= 0x0C0E && c <= 0x0C10)
1687:                        || (c >= 0x0C12 && c <= 0x0C28)
1688:                        || (c >= 0x0C2A && c <= 0x0C33)
1689:                        || (c >= 0x0C35 && c <= 0x0C39)
1690:                        || (c >= 0x0C60 && c <= 0x0C61)
1691:                        || (c >= 0x0C85 && c <= 0x0C8C)
1692:                        || (c >= 0x0C8E && c <= 0x0C90)
1693:                        || (c >= 0x0C92 && c <= 0x0CA8)
1694:                        || (c >= 0x0CAA && c <= 0x0CB3)
1695:                        || (c >= 0x0CB5 && c <= 0x0CB9) || c == 0x0CDE
1696:                        || (c >= 0x0CE0 && c <= 0x0CE1)
1697:                        || (c >= 0x0D05 && c <= 0x0D0C)
1698:                        || (c >= 0x0D0E && c <= 0x0D10)
1699:                        || (c >= 0x0D12 && c <= 0x0D28)
1700:                        || (c >= 0x0D2A && c <= 0x0D39)
1701:                        || (c >= 0x0D60 && c <= 0x0D61)
1702:                        || (c >= 0x0E01 && c <= 0x0E2E) || c == 0x0E30
1703:                        || (c >= 0x0E32 && c <= 0x0E33)
1704:                        || (c >= 0x0E40 && c <= 0x0E45)
1705:                        || (c >= 0x0E81 && c <= 0x0E82) || c == 0x0E84
1706:                        || (c >= 0x0E87 && c <= 0x0E88) || c == 0x0E8A
1707:                        || c == 0x0E8D || (c >= 0x0E94 && c <= 0x0E97)
1708:                        || (c >= 0x0E99 && c <= 0x0E9F)
1709:                        || (c >= 0x0EA1 && c <= 0x0EA3) || c == 0x0EA5
1710:                        || c == 0x0EA7 || (c >= 0x0EAA && c <= 0x0EAB)
1711:                        || (c >= 0x0EAD && c <= 0x0EAE) || c == 0x0EB0
1712:                        || (c >= 0x0EB2 && c <= 0x0EB3) || c == 0x0EBD
1713:                        || (c >= 0x0EC0 && c <= 0x0EC4)
1714:                        || (c >= 0x0F40 && c <= 0x0F47)
1715:                        || (c >= 0x0F49 && c <= 0x0F69)
1716:                        || (c >= 0x10A0 && c <= 0x10C5)
1717:                        || (c >= 0x10D0 && c <= 0x10F6) || c == 0x1100
1718:                        || (c >= 0x1102 && c <= 0x1103)
1719:                        || (c >= 0x1105 && c <= 0x1107) || c == 0x1109
1720:                        || (c >= 0x110B && c <= 0x110C)
1721:                        || (c >= 0x110E && c <= 0x1112) || c == 0x113C
1722:                        || c == 0x113E || c == 0x1140 || c == 0x114C
1723:                        || c == 0x114E || c == 0x1150
1724:                        || (c >= 0x1154 && c <= 0x1155) || c == 0x1159
1725:                        || (c >= 0x115F && c <= 0x1161) || c == 0x1163
1726:                        || c == 0x1165 || c == 0x1167 || c == 0x1169
1727:                        || (c >= 0x116D && c <= 0x116E)
1728:                        || (c >= 0x1172 && c <= 0x1173) || c == 0x1175
1729:                        || c == 0x119E || c == 0x11A8 || c == 0x11AB
1730:                        || (c >= 0x11AE && c <= 0x11AF)
1731:                        || (c >= 0x11B7 && c <= 0x11B8) || c == 0x11BA
1732:                        || (c >= 0x11BC && c <= 0x11C2) || c == 0x11EB
1733:                        || c == 0x11F0 || c == 0x11F9
1734:                        || (c >= 0x1E00 && c <= 0x1E9B)
1735:                        || (c >= 0x1EA0 && c <= 0x1EF9)
1736:                        || (c >= 0x1F00 && c <= 0x1F15)
1737:                        || (c >= 0x1F18 && c <= 0x1F1D)
1738:                        || (c >= 0x1F20 && c <= 0x1F45)
1739:                        || (c >= 0x1F48 && c <= 0x1F4D)
1740:                        || (c >= 0x1F50 && c <= 0x1F57) || c == 0x1F59
1741:                        || c == 0x1F5B || c == 0x1F5D
1742:                        || (c >= 0x1F5F && c <= 0x1F7D)
1743:                        || (c >= 0x1F80 && c <= 0x1FB4)
1744:                        || (c >= 0x1FB6 && c <= 0x1FBC) || c == 0x1FBE
1745:                        || (c >= 0x1FC2 && c <= 0x1FC4)
1746:                        || (c >= 0x1FC6 && c <= 0x1FCC)
1747:                        || (c >= 0x1FD0 && c <= 0x1FD3)
1748:                        || (c >= 0x1FD6 && c <= 0x1FDB)
1749:                        || (c >= 0x1FE0 && c <= 0x1FEC)
1750:                        || (c >= 0x1FF2 && c <= 0x1FF4)
1751:                        || (c >= 0x1FF6 && c <= 0x1FFC) || c == 0x2126
1752:                        || (c >= 0x212A && c <= 0x212B) || c == 0x212E
1753:                        || (c >= 0x2180 && c <= 0x2182)
1754:                        || (c >= 0x3041 && c <= 0x3094)
1755:                        || (c >= 0x30A1 && c <= 0x30FA)
1756:                        || (c >= 0x3105 && c <= 0x312C)
1757:                        || (c >= 0xAC00 && c <= 0xD7A3);
1758:            }
1759:
1760:            /**
1761:             * To support the creation of elements in the <code>createElementNS</code>
1762:             * method, we supply prototypes to the <code>DocumentNode</code> so that it
1763:             * can create nodes of specific data types for the prototype's namespaceURI
1764:             * and localName.
1765:             *
1766:             * @param prototypeElement the <code>ElementNode</code> which will be used
1767:             * as a prototype in <code>createElementNS</code>. Should not be null.
1768:             * @throws IllegalArgumentException If there is already a prototype node for
1769:             * the given namespace and local name.
1770:             */
1771:            public void addPrototype(final ElementNode prototypeElement) {
1772:                // Get the namespace map
1773:                String namespaceURI = prototypeElement.getNamespaceURI();
1774:
1775:                Hashtable lmap = (Hashtable) namespaceMap.get(namespaceURI);
1776:
1777:                if (lmap == null) {
1778:                    lmap = new Hashtable();
1779:                    namespaceMap.put(namespaceURI, lmap);
1780:                }
1781:
1782:                lmap.put(prototypeElement.getLocalName(), prototypeElement);
1783:            }
1784:
1785:            /**
1786:             * For SVG files this must be
1787:             * <code>SVGSVGElement</code>, but return type is Element for DOM Core
1788:             * compatibility and to allow for future extensions.  Return null if
1789:             * document does not have an element child.
1790:             *
1791:             */
1792:
1793:            public Element getDocumentElement() {
1794:                return firstChild;
1795:            }
1796:
1797:            /**
1798:             * Returns the parent <code>Node</code> of this <code>Node</code>.
1799:             *
1800:             * @return the parent node or null if there is no parent (i.e. if a node has
1801:             * just been created and not yet added to the tree, or if it has been
1802:             * removed from the tree, this is null).
1803:             */
1804:            public Node getParentNode() {
1805:                return null;
1806:            }
1807:
1808:            /**
1809:             * @return false, as DocumentNode does not support removing children.
1810:             */
1811:            protected boolean isRemoveChildSupported() {
1812:                return false;
1813:            }
1814:
1815:            /**
1816:             * Only and SVG child is allowed under a DocumentNode.
1817:             *
1818:             * @param node the candidate child node.
1819:             * @return true if the input node can be inserted under this CompositeNode
1820:             */
1821:            protected boolean isAllowedChild(final ElementNode node) {
1822:                if (node instanceof  SVG) {
1823:                    return true;
1824:                }
1825:                return false;
1826:            }
1827:
1828:            // =========================================================================
1829:            // Namespace prefix management. Note that this is designed to be minimal
1830:            // in terms of memory and is not optimized for speed.
1831:            // =========================================================================
1832:
1833:            /**
1834:             * Adds a new prefix to namespace mapping. The scope is provided by 
1835:             * the node parameter.
1836:             *
1837:             * @param prefix the new namespace prefix.
1838:             * @param uri the new namespace URI which maps to the prefix.
1839:             * @param node the scope of the namespace prefix mapping. The mapping 
1840:             *        applies to all children, unless overridden.
1841:             */
1842:            public void addNamespacePrefix(final String prefix,
1843:                    final String namespaceURI, final ModelNode node) {
1844:                if (prefix == null) {
1845:                    throw new NullPointerException();
1846:                }
1847:
1848:                // First, check if there are already mappings for the 
1849:                // prefix.
1850:                Object[][] namespaceEntry = (Object[][]) prefixes.get(prefix);
1851:
1852:                if (namespaceEntry == null) {
1853:                    // Simple case: there is not entry yet. Create a new one.
1854:                    namespaceEntry = new Object[][] { { namespaceURI, node } };
1855:                } else {
1856:                    // There is an existing entry. Add the new one ahead of the
1857:                    // other ones.
1858:                    Object[][] newNamespaceEntry = new Object[namespaceEntry.length + 1][];
1859:                    newNamespaceEntry[0] = new Object[] { namespaceURI, node };
1860:                    System.arraycopy(namespaceEntry, 0, newNamespaceEntry, 1,
1861:                            namespaceEntry.length);
1862:                    namespaceEntry = newNamespaceEntry;
1863:                }
1864:
1865:                prefixes.put(prefix, namespaceEntry);
1866:
1867:                // Now, update the namespaces map.
1868:                Object[][] prefixEntry = (Object[][]) namespaces
1869:                        .get(namespaceURI);
1870:
1871:                if (prefixEntry == null) {
1872:                    // Simple case: there is no entry yet. Create a new one.
1873:                    prefixEntry = new Object[][] { { prefix, node } };
1874:                } else {
1875:                    // There is an existing entry. Add the new one ahead of the other
1876:                    // ones.
1877:                    Object[][] newPrefixEntry = new Object[prefixEntry.length + 1][];
1878:                    newPrefixEntry[0] = new Object[] { prefix, node };
1879:                    System.arraycopy(prefixEntry, 0, newPrefixEntry, 1,
1880:                            prefixEntry.length);
1881:                    prefixEntry = newPrefixEntry;
1882:                }
1883:
1884:                namespaces.put(namespaceURI, prefixEntry);
1885:            }
1886:
1887:            /**
1888:             * Maps the input prefix name to a namespace value.
1889:             *
1890:             * @param prefix the prefix to map.
1891:             * @param node the node for which the prefix needs to be mapped.
1892:             * @return the namespace the prefix maps to for the node, or null if 
1893:             *         there is no such namespace prefix.
1894:             */
1895:            String toNamespace(final String prefix, final ModelNode node) {
1896:                Object[][] namespaceEntry = (Object[][]) prefixes.get(prefix);
1897:                if (namespaceEntry == null) {
1898:                    // No namespace entry
1899:                    return null;
1900:                } else {
1901:                    // Note that namespaceEntry.length == 0 should _never_ happen.
1902:
1903:                    // There are multiple prefix that map to entries. 
1904:                    // Walk up the parent tree and match with the 
1905:                    // first parent that is found in an entry.
1906:                    ModelNode cur = node;
1907:                    final int n = namespaceEntry.length;
1908:                    while (cur != null && cur != this ) {
1909:                        for (int i = 0; i < n; i++) {
1910:                            if (namespaceEntry[i][1] == cur) {
1911:                                return (String) namespaceEntry[i][0];
1912:                            }
1913:                        }
1914:                        cur = cur.parent;
1915:                    }
1916:
1917:                    // If we are here, it means we have not found a 
1918:                    // matching namespace in the document tree. Check
1919:                    // if there are any default mapping on the document
1920:                    // node itself.
1921:                    for (int i = 0; i < n; i++) {
1922:                        if (namespaceEntry[i][1] == this ) {
1923:                            return (String) namespaceEntry[i][0];
1924:                        }
1925:                    }
1926:
1927:                    // Did not find any matching namespace prefix.
1928:                    return null;
1929:                }
1930:            }
1931:
1932:            /**
1933:             * Maps the input namespace value to a prefix.
1934:             *
1935:             * @param namespaceURI the URI to map.
1936:             * @param node the node for which the namespace needs to be mapped.
1937:             * @return the namespace the prefix maps to for the node, or null if 
1938:             *         there is no such namespace prefix.
1939:             */
1940:            public String toPrefix(final String namespaceURI, final Element node) {
1941:                Object[][] prefixEntry = (Object[][]) namespaces
1942:                        .get(namespaceURI);
1943:                if (prefixEntry == null) {
1944:                    // No prefix entry
1945:                    return null;
1946:                } else {
1947:                    // Note that prefixEntry.length == 0 should _never_ happen.
1948:
1949:                    // There are multiple prefixEntries that map to entries. 
1950:                    // Walk up the parent tree and match with the 
1951:                    // first parent that is found in an entry.
1952:                    ModelNode cur = (ElementNode) node;
1953:                    final int n = prefixEntry.length;
1954:                    while (cur != null && cur != this ) {
1955:                        for (int i = 0; i < n; i++) {
1956:                            if (prefixEntry[i][1] == cur) {
1957:                                return (String) prefixEntry[i][0];
1958:                            }
1959:                        }
1960:                        cur = cur.parent;
1961:                    }
1962:
1963:                    // If we are here, it means we have not found a 
1964:                    // matching prefix in the document tree. Check
1965:                    // if there are any default mapping on the document
1966:                    // node itself.
1967:                    for (int i = 0; i < n; i++) {
1968:                        if (prefixEntry[i][1] == this ) {
1969:                            return (String) prefixEntry[i][0];
1970:                        }
1971:                    }
1972:
1973:                    // Did not find any matching prefix.
1974:                    return null;
1975:                }
1976:            }
1977:
1978:            /**
1979:             * Invoked at the end of the parsing stage to validate things which cannot
1980:             * be validated earlier, such as unresolved use references or invalid
1981:             * animation settings.
1982:             *
1983:             * @throws DOMException if there are validation errors.
1984:             */
1985:            public void validate() throws DOMException {
1986:                // First, check unresolved ID references.
1987:                if (unresolvedIDRefs != null && unresolvedIDRefs.size() > 0) {
1988:                    // There are unresolved ID references, this is a validation error.
1989:                    Enumeration iter = unresolvedIDRefs.keys();
1990:                    StringBuffer buf = new StringBuffer();
1991:                    while (iter.hasMoreElements()) {
1992:                        buf.append('[');
1993:                        buf.append(iter.nextElement());
1994:                        buf.append(']');
1995:                    }
1996:
1997:                    String message = Messages.formatMessage(
1998:                            Messages.ERROR_UNRESOLVED_REFERENCES,
1999:                            new Object[] { buf.toString() });
2000:
2001:                    throw new DOMException(DOMException.INVALID_ACCESS_ERR,
2002:                            message);
2003:                }
2004:
2005:                unresolvedIDRefs = null;
2006:
2007:                // Now, validate animation elements. At this stage, we know that the 
2008:                // animation elements either had no xlink:href or had one which has
2009:                // been resolved.
2010:                if (animations != null) {
2011:                    int n = animations.size();
2012:                    for (int i = 0; i < n; i++) {
2013:                        Animation animation = (Animation) animations
2014:                                .elementAt(i);
2015:                        if (animation.parent != null) {
2016:                            // The prototypes Set may have a null parent, so we account
2017:                            // for that situation here.
2018:                            animation.validate();
2019:                        }
2020:                    }
2021:                }
2022:
2023:                animations = null;
2024:            }
2025:
2026:            /**
2027:             * Implementation helper. Checks that the unknownTraitNS map is not null for
2028:             * the given ElementNode before using it, for the requested namespaceURI.
2029:             *
2030:             * @param element the ElementNode for which a table should be created for 
2031:             *        the given namespace URI.
2032:             * @param namespaceURI the trait's namespace URI
2033:             * @param traitName the trait's local name.
2034:             * @param value the trait value.
2035:             * @return the namespaceURI's unknown traits table.
2036:             */
2037:            void setUnknownTraitsNS(final ElementNode element,
2038:                    final String namespaceURI, final String traitName,
2039:                    final String value) {
2040:                // Make sure we do have a table for storing unknown traits.        
2041:                if (unknownTraitsNS == null) {
2042:                    unknownTraitsNS = new Hashtable();
2043:                }
2044:
2045:                // Make sure we do have a table for storing unknown traits for
2046:                // the requested element.
2047:                Hashtable eltMap = (Hashtable) unknownTraitsNS.get(element);
2048:                if (eltMap == null) {
2049:                    eltMap = new Hashtable();
2050:                    unknownTraitsNS.put(element, eltMap);
2051:                }
2052:
2053:                // If there is already a map for the given namespace, use that.
2054:                // Otherwise, create a new map.
2055:                Hashtable nsMap = (Hashtable) eltMap.get(namespaceURI);
2056:                if (nsMap == null) {
2057:                    nsMap = new Hashtable();
2058:                    eltMap.put(namespaceURI, nsMap);
2059:                }
2060:
2061:                nsMap.put(traitName, value);
2062:            }
2063:
2064:            /**
2065:             * Implementation helper. Returns the ElementNode's trait value if
2066:             * it was ever set.
2067:             *
2068:             * @param element the ElementNode on which the trait might be set.
2069:             * @param namespaceURI the trait's namespace URI
2070:             * @param traitName the trait's local name.
2071:             * @return the trait value or null if the value was never set.
2072:             */
2073:            String getUnknownTraitsNS(final ElementNode element,
2074:                    final String namespaceURI, final String traitName) {
2075:                if (unknownTraitsNS == null) {
2076:                    return null;
2077:                }
2078:
2079:                Hashtable eltMap = (Hashtable) unknownTraitsNS.get(element);
2080:                if (eltMap == null) {
2081:                    return null;
2082:                }
2083:
2084:                Hashtable nsMap = (Hashtable) eltMap.get(namespaceURI);
2085:                if (nsMap == null) {
2086:                    return null;
2087:                }
2088:
2089:                return (String) nsMap.get(traitName);
2090:            }
2091:
2092:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.