diff options
Diffstat (limited to 'src/com/sun/org/apache/xerces/internal/dom/DocumentImpl.java')
-rw-r--r-- | src/com/sun/org/apache/xerces/internal/dom/DocumentImpl.java | 1379 |
1 files changed, 0 insertions, 1379 deletions
diff --git a/src/com/sun/org/apache/xerces/internal/dom/DocumentImpl.java b/src/com/sun/org/apache/xerces/internal/dom/DocumentImpl.java deleted file mode 100644 index a5fe4b8..0000000 --- a/src/com/sun/org/apache/xerces/internal/dom/DocumentImpl.java +++ /dev/null @@ -1,1379 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - */ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.sun.org.apache.xerces.internal.dom; - -import com.sun.org.apache.xerces.internal.dom.events.EventImpl; -import com.sun.org.apache.xerces.internal.dom.events.MutationEventImpl; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.ObjectStreamField; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.List; -import java.util.Map; -import java.util.Vector; -import org.w3c.dom.Attr; -import org.w3c.dom.DOMException; -import org.w3c.dom.DOMImplementation; -import org.w3c.dom.DocumentType; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.UserDataHandler; -import org.w3c.dom.events.DocumentEvent; -import org.w3c.dom.events.Event; -import org.w3c.dom.events.EventException; -import org.w3c.dom.events.EventListener; -import org.w3c.dom.events.MutationEvent; -import org.w3c.dom.ranges.DocumentRange; -import org.w3c.dom.ranges.Range; -import org.w3c.dom.traversal.DocumentTraversal; -import org.w3c.dom.traversal.NodeFilter; -import org.w3c.dom.traversal.NodeIterator; -import org.w3c.dom.traversal.TreeWalker; - - -/** - * The Document interface represents the entire HTML or XML document. - * Conceptually, it is the root of the document tree, and provides the - * primary access to the document's data. - * <P> - * Since elements, text nodes, comments, processing instructions, - * etc. cannot exist outside the context of a Document, the Document - * interface also contains the factory methods needed to create these - * objects. The Node objects created have a ownerDocument attribute - * which associates them with the Document within whose context they - * were created. - * <p> - * The DocumentImpl class also implements the DOM Level 2 DocumentTraversal - * interface. This interface is comprised of factory methods needed to - * create NodeIterators and TreeWalkers. The process of creating NodeIterator - * objects also adds these references to this document. - * After finishing with an iterator it is important to remove the object - * using the remove methods in this implementation. This allows the release of - * the references from the iterator objects to the DOM Nodes. - * <p> - * <b>Note:</b> When any node in the document is serialized, the - * entire document is serialized along with it. - * - * @xerces.internal - * - * @author Arnaud Le Hors, IBM - * @author Joe Kesselman, IBM - * @author Andy Clark, IBM - * @author Ralf Pfeiffer, IBM - * @version $Id: DocumentImpl.java,v 1.6 2010/07/20 20:25:24 joehw Exp $ - * @since PR-DOM-Level-1-19980818. - */ -public class DocumentImpl - extends CoreDocumentImpl - implements DocumentTraversal, DocumentEvent, DocumentRange { - - // - // Constants - // - - /** Serialization version. */ - static final long serialVersionUID = 515687835542616694L; - - // - // Data - // - - /** Iterators */ - // REVISIT: Should this be transient? -Ac - protected List<NodeIterator> iterators; - - /** Ranges */ - // REVISIT: Should this be transient? -Ac - protected List<Range> ranges; - - /** Table for event listeners registered to this document nodes. */ - protected Map<NodeImpl, List<LEntry>> eventListeners; - - /** Bypass mutation events firing. */ - protected boolean mutationEvents = false; - - - /** - * @serialField iterators Vector Node iterators - * @serialField ranges Vector ranges - * @serialField eventListeners Hashtable Event listeners - * @serialField mutationEvents boolean Bypass mutation events firing - */ - private static final ObjectStreamField[] serialPersistentFields = - new ObjectStreamField[] { - new ObjectStreamField("iterators", Vector.class), - new ObjectStreamField("ranges", Vector.class), - new ObjectStreamField("eventListeners", Hashtable.class), - new ObjectStreamField("mutationEvents", boolean.class), - }; - - // - // Constructors - // - - /** - * NON-DOM: Actually creating a Document is outside the DOM's spec, - * since it has to operate in terms of a particular implementation. - */ - public DocumentImpl() { - super(); - } - - /** Constructor. */ - public DocumentImpl(boolean grammarAccess) { - super(grammarAccess); - } - - /** - * For DOM2 support. - * The createDocument factory method is in DOMImplementation. - */ - public DocumentImpl(DocumentType doctype) - { - super(doctype); - } - - /** For DOM2 support. */ - public DocumentImpl(DocumentType doctype, boolean grammarAccess) { - super(doctype, grammarAccess); - } - - // - // Node methods - // - - /** - * Deep-clone a document, including fixing ownerDoc for the cloned - * children. Note that this requires bypassing the WRONG_DOCUMENT_ERR - * protection. I've chosen to implement it by calling importNode - * which is DOM Level 2. - * - * @return org.w3c.dom.Node - * @param deep boolean, iff true replicate children - */ - public Node cloneNode(boolean deep) { - - DocumentImpl newdoc = new DocumentImpl(); - callUserDataHandlers(this, newdoc, UserDataHandler.NODE_CLONED); - cloneNode(newdoc, deep); - - // experimental - newdoc.mutationEvents = mutationEvents; - - return newdoc; - - } // cloneNode(boolean):Node - - /** - * Retrieve information describing the abilities of this particular - * DOM implementation. Intended to support applications that may be - * using DOMs retrieved from several different sources, potentially - * with different underlying representations. - */ - public DOMImplementation getImplementation() { - // Currently implemented as a singleton, since it's hardcoded - // information anyway. - return DOMImplementationImpl.getDOMImplementation(); - } - - // - // DocumentTraversal methods - // - - /** - * NON-DOM extension: - * Create and return a NodeIterator. The NodeIterator is - * added to a list of NodeIterators so that it can be - * removed to free up the DOM Nodes it references. - * - * @param root The root of the iterator. - * @param whatToShow The whatToShow mask. - * @param filter The NodeFilter installed. Null means no filter. - */ - public NodeIterator createNodeIterator(Node root, - short whatToShow, - NodeFilter filter) - { - return createNodeIterator(root, whatToShow, filter, true); - } - - /** - * Create and return a NodeIterator. The NodeIterator is - * added to a list of NodeIterators so that it can be - * removed to free up the DOM Nodes it references. - * - * @param root The root of the iterator. - * @param whatToShow The whatToShow mask. - * @param filter The NodeFilter installed. Null means no filter. - * @param entityReferenceExpansion true to expand the contents of - * EntityReference nodes - * @since WD-DOM-Level-2-19990923 - */ - public NodeIterator createNodeIterator(Node root, - int whatToShow, - NodeFilter filter, - boolean entityReferenceExpansion) - { - - if (root == null) { - String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); - throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); - } - - NodeIterator iterator = new NodeIteratorImpl(this, - root, - whatToShow, - filter, - entityReferenceExpansion); - if (iterators == null) { - iterators = new ArrayList<>(); - } - - iterators.add(iterator); - - return iterator; - } - - /** - * NON-DOM extension: - * Create and return a TreeWalker. - * - * @param root The root of the iterator. - * @param whatToShow The whatToShow mask. - * @param filter The NodeFilter installed. Null means no filter. - */ - public TreeWalker createTreeWalker(Node root, - short whatToShow, - NodeFilter filter) - { - return createTreeWalker(root, whatToShow, filter, true); - } - /** - * Create and return a TreeWalker. - * - * @param root The root of the iterator. - * @param whatToShow The whatToShow mask. - * @param filter The NodeFilter installed. Null means no filter. - * @param entityReferenceExpansion true to expand the contents of - * EntityReference nodes - * @since WD-DOM-Level-2-19990923 - */ - public TreeWalker createTreeWalker(Node root, - int whatToShow, - NodeFilter filter, - boolean entityReferenceExpansion) - { - if (root == null) { - String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); - throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); - } - return new TreeWalkerImpl(root, whatToShow, filter, - entityReferenceExpansion); - } - - // - // Not DOM Level 2. Support DocumentTraversal methods. - // - - /** This is not called by the developer client. The - * developer client uses the detach() function on the - * NodeIterator itself. <p> - * - * This function is called from the NodeIterator#detach(). - */ - void removeNodeIterator(NodeIterator nodeIterator) { - - if (nodeIterator == null) return; - if (iterators == null) return; - - iterators.remove(nodeIterator); - } - - // - // DocumentRange methods - // - /** - */ - public Range createRange() { - - if (ranges == null) { - ranges = new ArrayList<>(); - } - - Range range = new RangeImpl(this); - ranges.add(range); - - return range; - - } - - /** Not a client function. Called by Range.detach(), - * so a Range can remove itself from the list of - * Ranges. - */ - void removeRange(Range range) { - - if (range == null) return; - if (ranges == null) return; - - ranges.remove(range); - } - - /** - * A method to be called when some text was changed in a text node, - * so that live objects can be notified. - */ - void replacedText(NodeImpl node) { - // notify ranges - if (ranges != null) { - int size = ranges.size(); - for (int i = 0; i != size; i++) { - ((RangeImpl)ranges.get(i)).receiveReplacedText(node); - } - } - } - - /** - * A method to be called when some text was deleted from a text node, - * so that live objects can be notified. - */ - void deletedText(NodeImpl node, int offset, int count) { - // notify ranges - if (ranges != null) { - int size = ranges.size(); - for (int i = 0; i != size; i++) { - ((RangeImpl)ranges.get(i)).receiveDeletedText(node, - offset, count); - } - } - } - - /** - * A method to be called when some text was inserted into a text node, - * so that live objects can be notified. - */ - void insertedText(NodeImpl node, int offset, int count) { - // notify ranges - if (ranges != null) { - int size = ranges.size(); - for (int i = 0; i != size; i++) { - ((RangeImpl)ranges.get(i)).receiveInsertedText(node, - offset, count); - } - } - } - - /** - * A method to be called when a text node has been split, - * so that live objects can be notified. - */ - void splitData(Node node, Node newNode, int offset) { - // notify ranges - if (ranges != null) { - int size = ranges.size(); - for (int i = 0; i != size; i++) { - ((RangeImpl)ranges.get(i)).receiveSplitData(node, - newNode, offset); - } - } - } - - // - // DocumentEvent methods - // - - /** - * Introduced in DOM Level 2. Optional. <p> - * Create and return Event objects. - * - * @param type The eventType parameter specifies the type of Event - * interface to be created. If the Event interface specified is supported - * by the implementation this method will return a new Event of the - * interface type requested. If the Event is to be dispatched via the - * dispatchEvent method the appropriate event init method must be called - * after creation in order to initialize the Event's values. As an - * example, a user wishing to synthesize some kind of Event would call - * createEvent with the parameter "Events". The initEvent method could then - * be called on the newly created Event to set the specific type of Event - * to be dispatched and set its context information. - * @return Newly created Event - * @exception DOMException NOT_SUPPORTED_ERR: Raised if the implementation - * does not support the type of Event interface requested - * @since WD-DOM-Level-2-19990923 - */ - public Event createEvent(String type) - throws DOMException { - if (type.equalsIgnoreCase("Events") || "Event".equals(type)) - return new EventImpl(); - if (type.equalsIgnoreCase("MutationEvents") || - "MutationEvent".equals(type)) - return new MutationEventImpl(); - else { - String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); - throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); - } - } - - /** - * Sets whether the DOM implementation generates mutation events - * upon operations. - */ - void setMutationEvents(boolean set) { - mutationEvents = set; - } - - /** - * Returns true if the DOM implementation generates mutation events. - */ - boolean getMutationEvents() { - return mutationEvents; - } - - /** - * Store event listener registered on a given node - * This is another place where we could use weak references! Indeed, the - * node here won't be GC'ed as long as some listener is registered on it, - * since the eventsListeners table will have a reference to the node. - */ - private void setEventListeners(NodeImpl n, List<LEntry> listeners) { - if (eventListeners == null) { - eventListeners = new HashMap<>(); - } - if (listeners == null) { - eventListeners.remove(n); - if (eventListeners.isEmpty()) { - // stop firing events when there isn't any listener - mutationEvents = false; - } - } else { - eventListeners.put(n, listeners); - // turn mutation events on - mutationEvents = true; - } - } - - /** - * Retreive event listener registered on a given node - */ - private List<LEntry> getEventListeners(NodeImpl n) { - if (eventListeners == null) { - return null; - } - return eventListeners.get(n); - } - - // - // EventTarget support (public and internal) - // - - // - // Constants - // - - /* - * NON-DOM INTERNAL: Class LEntry is just a struct used to represent - * event listeners registered with this node. Copies of this object - * are hung from the nodeListeners Vector. - * <p> - * I considered using two vectors -- one for capture, - * one for bubble -- but decided that since the list of listeners - * is probably short in most cases, it might not be worth spending - * the space. ***** REVISIT WHEN WE HAVE MORE EXPERIENCE. - */ - class LEntry implements Serializable { - - private static final long serialVersionUID = -8426757059492421631L; - String type; - EventListener listener; - boolean useCapture; - - /** NON-DOM INTERNAL: Constructor for Listener list Entry - * @param type Event name (NOT event group!) to listen for. - * @param listener Who gets called when event is dispatched - * @param useCaptue True iff listener is registered on - * capturing phase rather than at-target or bubbling - */ - LEntry(String type, EventListener listener, boolean useCapture) - { - this.type = type; - this.listener = listener; - this.useCapture = useCapture; - } - - } // LEntry - - /** - * Introduced in DOM Level 2. <p> Register an event listener with this - * Node. A listener may be independently registered as both Capturing and - * Bubbling, but may only be registered once per role; redundant - * registrations are ignored. - * @param node node to add listener to - * @param type Event name (NOT event group!) to listen for. - * @param listener Who gets called when event is dispatched - * @param useCapture True iff listener is registered on - * capturing phase rather than at-target or bubbling - */ - @Override - protected void addEventListener(NodeImpl node, String type, - EventListener listener, boolean useCapture) - { - // We can't dispatch to blank type-name, and of course we need - // a listener to dispatch to - if (type == null || type.equals("") || listener == null) - return; - - // Each listener may be registered only once per type per phase. - // Simplest way to code that is to zap the previous entry, if any. - removeEventListener(node, type, listener, useCapture); - - List<LEntry> nodeListeners = getEventListeners(node); - if(nodeListeners == null) { - nodeListeners = new ArrayList<>(); - setEventListeners(node, nodeListeners); - } - nodeListeners.add(new LEntry(type, listener, useCapture)); - - // Record active listener - LCount lc = LCount.lookup(type); - if (useCapture) { - ++lc.captures; - ++lc.total; - } - else { - ++lc.bubbles; - ++lc.total; - } - - } // addEventListener(NodeImpl,String,EventListener,boolean) :void - - /** - * Introduced in DOM Level 2. <p> Deregister an event listener previously - * registered with this Node. A listener must be independently removed - * from the Capturing and Bubbling roles. Redundant removals (of listeners - * not currently registered for this role) are ignored. - * @param node node to remove listener from - * @param type Event name (NOT event group!) to listen for. - * @param listener Who gets called when event is dispatched - * @param useCapture True iff listener is registered on - * capturing phase rather than at-target or bubbling - */ - @Override - protected void removeEventListener(NodeImpl node, String type, - EventListener listener, - boolean useCapture) - { - // If this couldn't be a valid listener registration, ignore request - if (type == null || type.equals("") || listener == null) - return; - List<LEntry> nodeListeners = getEventListeners(node); - if (nodeListeners == null) - return; - - // Note that addListener has previously ensured that - // each listener may be registered only once per type per phase. - // count-down is OK for deletions! - for (int i = nodeListeners.size() - 1; i >= 0; --i) { - LEntry le = nodeListeners.get(i); - if (le.useCapture == useCapture && le.listener == listener && - le.type.equals(type)) { - nodeListeners.remove(i); - // Storage management: Discard empty listener lists - if (nodeListeners.isEmpty()) - setEventListeners(node, null); - - // Remove active listener - LCount lc = LCount.lookup(type); - if (useCapture) { - --lc.captures; - --lc.total; - } - else { - --lc.bubbles; - --lc.total; - } - - break; // Found it; no need to loop farther. - } - } - } // removeEventListener(NodeImpl,String,EventListener,boolean) :void - - @Override - protected void copyEventListeners(NodeImpl src, NodeImpl tgt) { - List<LEntry> nodeListeners = getEventListeners(src); - if (nodeListeners == null) { - return; - } - setEventListeners(tgt, new ArrayList<>(nodeListeners)); - } - - /** - * Introduced in DOM Level 2. <p> - * Distribution engine for DOM Level 2 Events. - * <p> - * Event propagation runs as follows: - * <ol> - * <li>Event is dispatched to a particular target node, which invokes - * this code. Note that the event's stopPropagation flag is - * cleared when dispatch begins; thereafter, if it has - * been set before processing of a node commences, we instead - * immediately advance to the DEFAULT phase. - * <li>The node's ancestors are established as destinations for events. - * For capture and bubble purposes, node ancestry is determined at - * the time dispatch starts. If an event handler alters the document - * tree, that does not change which nodes will be informed of the event. - * <li>CAPTURING_PHASE: Ancestors are scanned, root to target, for - * Capturing listeners. If found, they are invoked (see below). - * <li>AT_TARGET: - * Event is dispatched to NON-CAPTURING listeners on the - * target node. Note that capturing listeners on this node are _not_ - * invoked. - * <li>BUBBLING_PHASE: Ancestors are scanned, target to root, for - * non-capturing listeners. - * <li>Default processing: Some DOMs have default behaviors bound to - * specific nodes. If this DOM does, and if the event's preventDefault - * flag has not been set, we now return to the target node and process - * its default handler for this event, if any. - * </ol> - * <p> - * Note that registration of handlers during processing of an event does - * not take effect during this phase of this event; they will not be called - * until the next time this node is visited by dispatchEvent. On the other - * hand, removals take effect immediately. - * <p> - * If an event handler itself causes events to be dispatched, they are - * processed synchronously, before processing resumes - * on the event which triggered them. Please be aware that this may - * result in events arriving at listeners "out of order" relative - * to the actual sequence of requests. - * <p> - * Note that our implementation resets the event's stop/prevent flags - * when dispatch begins. - * I believe the DOM's intent is that event objects be redispatchable, - * though it isn't stated in those terms. - * @param node node to dispatch to - * @param event the event object to be dispatched to - * registered EventListeners - * @return true if the event's <code>preventDefault()</code> - * method was invoked by an EventListener; otherwise false. - */ - @Override - protected boolean dispatchEvent(NodeImpl node, Event event) { - if (event == null) return false; - - // Can't use anyone else's implementation, since there's no public - // API for setting the event's processing-state fields. - EventImpl evt = (EventImpl)event; - - // VALIDATE -- must have been initialized at least once, must have - // a non-null non-blank name. - if(!evt.initialized || evt.type == null || evt.type.equals("")) { - String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "UNSPECIFIED_EVENT_TYPE_ERR", null); - throw new EventException(EventException.UNSPECIFIED_EVENT_TYPE_ERR, msg); - } - - // If nobody is listening for this event, discard immediately - LCount lc = LCount.lookup(evt.getType()); - if (lc.total == 0) - return evt.preventDefault; - - // INITIALIZE THE EVENT'S DISPATCH STATUS - // (Note that Event objects are reusable in our implementation; - // that doesn't seem to be explicitly guaranteed in the DOM, but - // I believe it is the intent.) - evt.target = node; - evt.stopPropagation = false; - evt.preventDefault = false; - - // Capture pre-event parentage chain, not including target; - // use pre-event-dispatch ancestors even if event handlers mutate - // document and change the target's context. - // Note that this is parents ONLY; events do not - // cross the Attr/Element "blood/brain barrier". - // DOMAttrModified. which looks like an exception, - // is issued to the Element rather than the Attr - // and causes a _second_ DOMSubtreeModified in the Element's - // tree. - List<Node> pv = new ArrayList<>(10); - Node p = node; - Node n = p.getParentNode(); - while (n != null) { - pv.add(n); - p = n; - n = n.getParentNode(); - } - - // CAPTURING_PHASE: - if (lc.captures > 0) { - evt.eventPhase = Event.CAPTURING_PHASE; - // Ancestors are scanned, root to target, for - // Capturing listeners. - for (int j = pv.size() - 1; j >= 0; --j) { - if (evt.stopPropagation) - break; // Someone set the flag. Phase ends. - - // Handle all capturing listeners on this node - NodeImpl nn = (NodeImpl) pv.get(j); - evt.currentTarget = nn; - List<LEntry> nodeListeners = getEventListeners(nn); - if (nodeListeners != null) { - List<LEntry> nl = (List)((ArrayList)nodeListeners).clone(); - // call listeners in the order in which they got registered - int nlsize = nl.size(); - for (int i = 0; i < nlsize; i++) { - LEntry le = nl.get(i); - if (le.useCapture && le.type.equals(evt.type) && - nodeListeners.contains(le)) { - try { - le.listener.handleEvent(evt); - } - catch (Exception e) { - // All exceptions are ignored. - } - } - } - } - } - } - - - // Both AT_TARGET and BUBBLE use non-capturing listeners. - if (lc.bubbles > 0) { - // AT_TARGET PHASE: Event is dispatched to NON-CAPTURING listeners - // on the target node. Note that capturing listeners on the target - // node are _not_ invoked, even during the capture phase. - evt.eventPhase = Event.AT_TARGET; - evt.currentTarget = node; - List<LEntry> nodeListeners = getEventListeners(node); - if (!evt.stopPropagation && nodeListeners != null) { - List<LEntry> nl = (List)((ArrayList)nodeListeners).clone(); - // call listeners in the order in which they got registered - int nlsize = nl.size(); - for (int i = 0; i < nlsize; i++) { - LEntry le = (LEntry) nl.get(i); - if (!le.useCapture && le.type.equals(evt.type) && - nodeListeners.contains(le)) { - try { - le.listener.handleEvent(evt); - } - catch (Exception e) { - // All exceptions are ignored. - } - } - } - } - // BUBBLING_PHASE: Ancestors are scanned, target to root, for - // non-capturing listeners. If the event's preventBubbling flag - // has been set before processing of a node commences, we - // instead immediately advance to the default phase. - // Note that not all events bubble. - if (evt.bubbles) { - evt.eventPhase = Event.BUBBLING_PHASE; - int pvsize = pv.size(); - for (int j = 0; j < pvsize; j++) { - if (evt.stopPropagation) - break; // Someone set the flag. Phase ends. - - // Handle all bubbling listeners on this node - NodeImpl nn = (NodeImpl) pv.get(j); - evt.currentTarget = nn; - nodeListeners = getEventListeners(nn); - if (nodeListeners != null) { - List<LEntry> nl = (List)((ArrayList)nodeListeners).clone(); - // call listeners in the order in which they got - // registered - int nlsize = nl.size(); - for (int i = 0; i < nlsize; i++) { - LEntry le = nl.get(i); - if (!le.useCapture && le.type.equals(evt.type) && - nodeListeners.contains(le)) { - try { - le.listener.handleEvent(evt); - } - catch (Exception e) { - // All exceptions are ignored. - } - } - } - } - } - } - } - - // DEFAULT PHASE: Some DOMs have default behaviors bound to specific - // nodes. If this DOM does, and if the event's preventDefault flag has - // not been set, we now return to the target node and process its - // default handler for this event, if any. - // No specific phase value defined, since this is DOM-internal - if (lc.defaults > 0 && (!evt.cancelable || !evt.preventDefault)) { - // evt.eventPhase = Event.DEFAULT_PHASE; - // evt.currentTarget = node; - // DO_DEFAULT_OPERATION - } - - return evt.preventDefault; - } // dispatchEvent(NodeImpl,Event) :boolean - - /** - * NON-DOM INTERNAL: DOMNodeInsertedIntoDocument and ...RemovedFrom... - * are dispatched to an entire subtree. This is the distribution code - * therefor. They DO NOT bubble, thanks be, but may be captured. - * <p> - * Similar to code in dispatchingEventToSubtree however this method - * is only used on the target node and does not start a dispatching chain - * on the sibling of the target node as this is not part of the subtree - * ***** At the moment I'm being sloppy and using the normal - * capture dispatcher on every node. This could be optimized hugely - * by writing a capture engine that tracks our position in the tree to - * update the capture chain without repeated chases up to root. - * @param n target node (that was directly inserted or removed) - * @param e event to be sent to that node and its subtree - */ - protected void dispatchEventToSubtree(Node n, Event e) { - - ((NodeImpl) n).dispatchEvent(e); - if (n.getNodeType() == Node.ELEMENT_NODE) { - NamedNodeMap a = n.getAttributes(); - for (int i = a.getLength() - 1; i >= 0; --i) - dispatchingEventToSubtree(a.item(i), e); - } - dispatchingEventToSubtree(n.getFirstChild(), e); - - } // dispatchEventToSubtree(NodeImpl,Node,Event) :void - - - /** - * Dispatches event to the target node's descendents recursively - * - * @param n node to dispatch to - * @param e event to be sent to that node and its subtree - */ - protected void dispatchingEventToSubtree(Node n, Event e) { - if (n==null) - return; - - // ***** Recursive implementation. This is excessively expensive, - // and should be replaced in conjunction with optimization - // mentioned above. - ((NodeImpl) n).dispatchEvent(e); - if (n.getNodeType() == Node.ELEMENT_NODE) { - NamedNodeMap a = n.getAttributes(); - for (int i = a.getLength() - 1; i >= 0; --i) - dispatchingEventToSubtree(a.item(i), e); - } - dispatchingEventToSubtree(n.getFirstChild(), e); - dispatchingEventToSubtree(n.getNextSibling(), e); - } - - /** - * NON-DOM INTERNAL: Return object for getEnclosingAttr. Carries - * (two values, the Attr node affected (if any) and its previous - * string value. Simple struct, no methods. - */ - class EnclosingAttr implements Serializable { - private static final long serialVersionUID = 5208387723391647216L; - AttrImpl node; - String oldvalue; - } - - EnclosingAttr savedEnclosingAttr; - - /** - * NON-DOM INTERNAL: Convenience wrapper for calling - * dispatchAggregateEvents when the context was established - * by <code>savedEnclosingAttr</code>. - * @param node node to dispatch to - * @param ea description of Attr affected by current operation - */ - protected void dispatchAggregateEvents(NodeImpl node, EnclosingAttr ea) { - if (ea != null) - dispatchAggregateEvents(node, ea.node, ea.oldvalue, - MutationEvent.MODIFICATION); - else - dispatchAggregateEvents(node, null, null, (short) 0); - - } // dispatchAggregateEvents(NodeImpl,EnclosingAttr) :void - - /** - * NON-DOM INTERNAL: Generate the "aggregated" post-mutation events - * DOMAttrModified and DOMSubtreeModified. - * Both of these should be issued only once for each user-requested - * mutation operation, even if that involves multiple changes to - * the DOM. - * For example, if a DOM operation makes multiple changes to a single - * Attr before returning, it would be nice to generate only one - * DOMAttrModified, and multiple changes over larger scope but within - * a recognizable single subtree might want to generate only one - * DOMSubtreeModified, sent to their lowest common ancestor. - * <p> - * To manage this, use the "internal" versions of insert and remove - * with MUTATION_LOCAL, then make an explicit call to this routine - * at the higher level. Some examples now exist in our code. - * - * @param node The node to dispatch to - * @param enclosingAttr The Attr node (if any) whose value has been changed - * as a result of the DOM operation. Null if none such. - * @param oldValue The String value previously held by the - * enclosingAttr. Ignored if none such. - * @param change Type of modification to the attr. See - * MutationEvent.attrChange - */ - protected void dispatchAggregateEvents(NodeImpl node, - AttrImpl enclosingAttr, - String oldvalue, short change) { - // We have to send DOMAttrModified. - NodeImpl owner = null; - if (enclosingAttr != null) { - LCount lc = LCount.lookup(MutationEventImpl.DOM_ATTR_MODIFIED); - owner = (NodeImpl) enclosingAttr.getOwnerElement(); - if (lc.total > 0) { - if (owner != null) { - MutationEventImpl me = new MutationEventImpl(); - me.initMutationEvent(MutationEventImpl.DOM_ATTR_MODIFIED, - true, false, enclosingAttr, - oldvalue, - enclosingAttr.getNodeValue(), - enclosingAttr.getNodeName(), - change); - owner.dispatchEvent(me); - } - } - } - // DOMSubtreeModified gets sent to the lowest common root of a - // set of changes. - // "This event is dispatched after all other events caused by the - // mutation have been fired." - LCount lc = LCount.lookup(MutationEventImpl.DOM_SUBTREE_MODIFIED); - if (lc.total > 0) { - MutationEvent me = new MutationEventImpl(); - me.initMutationEvent(MutationEventImpl.DOM_SUBTREE_MODIFIED, - true, false, null, null, - null, null, (short) 0); - - // If we're within an Attr, DStM gets sent to the Attr - // and to its owningElement. Otherwise we dispatch it - // locally. - if (enclosingAttr != null) { - dispatchEvent(enclosingAttr, me); - if (owner != null) - dispatchEvent(owner, me); - } - else - dispatchEvent(node, me); - } - } // dispatchAggregateEvents(NodeImpl, AttrImpl,String) :void - - /** - * NON-DOM INTERNAL: Pre-mutation context check, in - * preparation for later generating DOMAttrModified events. - * Determines whether this node is within an Attr - * @param node node to get enclosing attribute for - * @return either a description of that Attr, or null if none such. - */ - protected void saveEnclosingAttr(NodeImpl node) { - savedEnclosingAttr = null; - // MUTATION PREPROCESSING AND PRE-EVENTS: - // If we're within the scope of an Attr and DOMAttrModified - // was requested, we need to preserve its previous value for - // that event. - LCount lc = LCount.lookup(MutationEventImpl.DOM_ATTR_MODIFIED); - if (lc.total > 0) { - NodeImpl eventAncestor = node; - while (true) { - if (eventAncestor == null) - return; - int type = eventAncestor.getNodeType(); - if (type == Node.ATTRIBUTE_NODE) { - EnclosingAttr retval = new EnclosingAttr(); - retval.node = (AttrImpl) eventAncestor; - retval.oldvalue = retval.node.getNodeValue(); - savedEnclosingAttr = retval; - return; - } - else if (type == Node.ENTITY_REFERENCE_NODE) - eventAncestor = eventAncestor.parentNode(); - else if (type == Node.TEXT_NODE) - eventAncestor = eventAncestor.parentNode(); - else - return; - // Any other parent means we're not in an Attr - } - } - } // saveEnclosingAttr(NodeImpl) :void - - /** - * A method to be called when a character data node has been modified - */ - void modifyingCharacterData(NodeImpl node, boolean replace) { - if (mutationEvents) { - if (!replace) { - saveEnclosingAttr(node); - } - } - } - - /** - * A method to be called when a character data node has been modified - */ - void modifiedCharacterData(NodeImpl node, String oldvalue, String value, boolean replace) { - if (mutationEvents) { - if (!replace) { - // MUTATION POST-EVENTS: - LCount lc = - LCount.lookup(MutationEventImpl.DOM_CHARACTER_DATA_MODIFIED); - if (lc.total > 0) { - MutationEvent me = new MutationEventImpl(); - me.initMutationEvent( - MutationEventImpl.DOM_CHARACTER_DATA_MODIFIED, - true, false, null, - oldvalue, value, null, (short) 0); - dispatchEvent(node, me); - } - - // Subroutine: Transmit DOMAttrModified and DOMSubtreeModified, - // if required. (Common to most kinds of mutation) - dispatchAggregateEvents(node, savedEnclosingAttr); - } // End mutation postprocessing - } - } - - /** - * A method to be called when a character data node has been replaced - */ - void replacedCharacterData(NodeImpl node, String oldvalue, String value) { - //now that we have finished replacing data, we need to perform the same actions - //that are required after a character data node has been modified - //send the value of false for replace parameter so that mutation - //events if appropriate will be initiated - modifiedCharacterData(node, oldvalue, value, false); - } - - - - /** - * A method to be called when a node is about to be inserted in the tree. - */ - void insertingNode(NodeImpl node, boolean replace) { - if (mutationEvents) { - if (!replace) { - saveEnclosingAttr(node); - } - } - } - - /** - * A method to be called when a node has been inserted in the tree. - */ - void insertedNode(NodeImpl node, NodeImpl newInternal, boolean replace) { - if (mutationEvents) { - // MUTATION POST-EVENTS: - // "Local" events (non-aggregated) - // New child is told it was inserted, and where - LCount lc = LCount.lookup(MutationEventImpl.DOM_NODE_INSERTED); - if (lc.total > 0) { - MutationEventImpl me = new MutationEventImpl(); - me.initMutationEvent(MutationEventImpl.DOM_NODE_INSERTED, - true, false, node, - null, null, null, (short) 0); - dispatchEvent(newInternal, me); - } - - // If within the Document, tell the subtree it's been added - // to the Doc. - lc = LCount.lookup( - MutationEventImpl.DOM_NODE_INSERTED_INTO_DOCUMENT); - if (lc.total > 0) { - NodeImpl eventAncestor = node; - if (savedEnclosingAttr != null) - eventAncestor = (NodeImpl) - savedEnclosingAttr.node.getOwnerElement(); - if (eventAncestor != null) { // Might have been orphan Attr - NodeImpl p = eventAncestor; - while (p != null) { - eventAncestor = p; // Last non-null ancestor - // In this context, ancestry includes - // walking back from Attr to Element - if (p.getNodeType() == ATTRIBUTE_NODE) { - p = (NodeImpl) ((AttrImpl)p).getOwnerElement(); - } - else { - p = p.parentNode(); - } - } - if (eventAncestor.getNodeType() == Node.DOCUMENT_NODE){ - MutationEventImpl me = new MutationEventImpl(); - me.initMutationEvent(MutationEventImpl - .DOM_NODE_INSERTED_INTO_DOCUMENT, - false,false,null,null, - null,null,(short)0); - dispatchEventToSubtree(newInternal, me); - } - } - } - if (!replace) { - // Subroutine: Transmit DOMAttrModified and DOMSubtreeModified - // (Common to most kinds of mutation) - dispatchAggregateEvents(node, savedEnclosingAttr); - } - } - - // notify the range of insertions - if (ranges != null) { - int size = ranges.size(); - for (int i = 0; i != size; i++) { - ((RangeImpl)ranges.get(i)).insertedNodeFromDOM(newInternal); - } - } - } - - /** - * A method to be called when a node is about to be removed from the tree. - */ - void removingNode(NodeImpl node, NodeImpl oldChild, boolean replace) { - - // notify iterators - if (iterators != null) { - int size = iterators.size(); - for (int i = 0; i != size; i++) { - ((NodeIteratorImpl)iterators.get(i)).removeNode(oldChild); - } - } - - // notify ranges - if (ranges != null) { - int size = ranges.size(); - for (int i = 0; i != size; i++) { - ((RangeImpl)ranges.get(i)).removeNode(oldChild); - } - } - - // mutation events - if (mutationEvents) { - // MUTATION PREPROCESSING AND PRE-EVENTS: - // If we're within the scope of an Attr and DOMAttrModified - // was requested, we need to preserve its previous value for - // that event. - if (!replace) { - saveEnclosingAttr(node); - } - // Child is told that it is about to be removed - LCount lc = LCount.lookup(MutationEventImpl.DOM_NODE_REMOVED); - if (lc.total > 0) { - MutationEventImpl me= new MutationEventImpl(); - me.initMutationEvent(MutationEventImpl.DOM_NODE_REMOVED, - true, false, node, null, - null, null, (short) 0); - dispatchEvent(oldChild, me); - } - - // If within Document, child's subtree is informed that it's - // losing that status - lc = LCount.lookup( - MutationEventImpl.DOM_NODE_REMOVED_FROM_DOCUMENT); - if (lc.total > 0) { - NodeImpl eventAncestor = this; - if(savedEnclosingAttr != null) - eventAncestor = (NodeImpl) - savedEnclosingAttr.node.getOwnerElement(); - if (eventAncestor != null) { // Might have been orphan Attr - for (NodeImpl p = eventAncestor.parentNode(); - p != null; p = p.parentNode()) { - eventAncestor = p; // Last non-null ancestor - } - if (eventAncestor.getNodeType() == Node.DOCUMENT_NODE){ - MutationEventImpl me = new MutationEventImpl(); - me.initMutationEvent( - MutationEventImpl.DOM_NODE_REMOVED_FROM_DOCUMENT, - false, false, null, - null, null, null, (short) 0); - dispatchEventToSubtree(oldChild, me); - } - } - } - } // End mutation preprocessing - } - - /** - * A method to be called when a node has been removed from the tree. - */ - void removedNode(NodeImpl node, boolean replace) { - if (mutationEvents) { - // MUTATION POST-EVENTS: - // Subroutine: Transmit DOMAttrModified and DOMSubtreeModified, - // if required. (Common to most kinds of mutation) - if (!replace) { - dispatchAggregateEvents(node, savedEnclosingAttr); - } - } // End mutation postprocessing - } - - /** - * A method to be called when a node is about to be replaced in the tree. - */ - void replacingNode(NodeImpl node) { - if (mutationEvents) { - saveEnclosingAttr(node); - } - } - - /** - * A method to be called when character data is about to be replaced in the tree. - */ - void replacingData (NodeImpl node) { - if (mutationEvents) { - saveEnclosingAttr(node); - } - } - - /** - * A method to be called when a node has been replaced in the tree. - */ - void replacedNode(NodeImpl node) { - if (mutationEvents) { - dispatchAggregateEvents(node, savedEnclosingAttr); - } - } - - /** - * A method to be called when an attribute value has been modified - */ - void modifiedAttrValue(AttrImpl attr, String oldvalue) { - if (mutationEvents) { - // MUTATION POST-EVENTS: - dispatchAggregateEvents(attr, attr, oldvalue, - MutationEvent.MODIFICATION); - } - } - - /** - * A method to be called when an attribute node has been set - */ - void setAttrNode(AttrImpl attr, AttrImpl previous) { - if (mutationEvents) { - // MUTATION POST-EVENTS: - if (previous == null) { - dispatchAggregateEvents(attr.ownerNode, attr, null, - MutationEvent.ADDITION); - } - else { - dispatchAggregateEvents(attr.ownerNode, attr, - previous.getNodeValue(), - MutationEvent.MODIFICATION); - } - } - } - - /** - * A method to be called when an attribute node has been removed - */ - void removedAttrNode(AttrImpl attr, NodeImpl oldOwner, String name) { - // We can't use the standard dispatchAggregate, since it assumes - // that the Attr is still attached to an owner. This code is - // similar but dispatches to the previous owner, "element". - if (mutationEvents) { - // If we have to send DOMAttrModified (determined earlier), - // do so. - LCount lc = LCount.lookup(MutationEventImpl.DOM_ATTR_MODIFIED); - if (lc.total > 0) { - MutationEventImpl me= new MutationEventImpl(); - me.initMutationEvent(MutationEventImpl.DOM_ATTR_MODIFIED, - true, false, attr, - attr.getNodeValue(), null, name, - MutationEvent.REMOVAL); - dispatchEvent(oldOwner, me); - } - - // We can hand off to process DOMSubtreeModified, though. - // Note that only the Element needs to be informed; the - // Attr's subtree has not been changed by this operation. - dispatchAggregateEvents(oldOwner, null, null, (short) 0); - } - } - - - /** - * A method to be called when an attribute node has been renamed - */ - void renamedAttrNode(Attr oldAt, Attr newAt) { - // REVISIT: To be implemented!!! - } - - /** - * A method to be called when an element has been renamed - */ - void renamedElement(Element oldEl, Element newEl) { - // REVISIT: To be implemented!!! - } - - - /** - * @serialData Serialized fields. Convert Maps to Hashtables and Lists - * to Vectors for backward compatibility. - */ - private void writeObject(ObjectOutputStream out) throws IOException { - // Convert Maps to Hashtables, Lists to Vectors - Vector<NodeIterator> it = (iterators == null)? null : new Vector<>(iterators); - Vector<Range> r = (ranges == null)? null : new Vector<>(ranges); - - Hashtable<NodeImpl, Vector<LEntry>> el = null; - if (eventListeners != null) { - el = new Hashtable<>(); - for (Map.Entry<NodeImpl, List<LEntry>> e : eventListeners.entrySet()) { - el.put(e.getKey(), new Vector<>(e.getValue())); - } - } - - // Write serialized fields - ObjectOutputStream.PutField pf = out.putFields(); - pf.put("iterators", it); - pf.put("ranges", r); - pf.put("eventListeners", el); - pf.put("mutationEvents", mutationEvents); - out.writeFields(); - } - - @SuppressWarnings("unchecked") - private void readObject(ObjectInputStream in) - throws IOException, ClassNotFoundException { - // We have to read serialized fields first. - ObjectInputStream.GetField gf = in.readFields(); - Vector<NodeIterator> it = (Vector<NodeIterator>)gf.get("iterators", null); - Vector<Range> r = (Vector<Range>)gf.get("ranges", null); - Hashtable<NodeImpl, Vector<LEntry>> el = - (Hashtable<NodeImpl, Vector<LEntry>>)gf.get("eventListeners", null); - - mutationEvents = gf.get("mutationEvents", false); - - //convert Hashtables back to HashMaps and Vectors to Lists - if (it != null) iterators = new ArrayList<>(it); - if (r != null) ranges = new ArrayList<>(r); - if (el != null) { - eventListeners = new HashMap<>(); - for (Map.Entry<NodeImpl, Vector<LEntry>> e : el.entrySet()) { - eventListeners.put(e.getKey(), new ArrayList<>(e.getValue())); - } - } - } -} // class DocumentImpl |