1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 2001, 2002 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xerces" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, International
  53. * Business Machines, Inc., http://www.apache.org. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package com.sun.org.apache.xerces.internal.dom;
  58. import java.io.Serializable;
  59. import java.util.Hashtable;
  60. import java.util.Vector;
  61. import com.sun.org.apache.xerces.internal.dom.events.EventImpl;
  62. import com.sun.org.apache.xerces.internal.dom.events.MutationEventImpl;
  63. import org.w3c.dom.UserDataHandler;
  64. import org.w3c.dom.Attr;
  65. import org.w3c.dom.DOMException;
  66. import org.w3c.dom.DOMImplementation;
  67. import org.w3c.dom.DocumentType;
  68. import org.w3c.dom.Element;
  69. import org.w3c.dom.NamedNodeMap;
  70. import org.w3c.dom.Node;
  71. import org.w3c.dom.events.DocumentEvent;
  72. import org.w3c.dom.events.Event;
  73. import org.w3c.dom.events.EventException;
  74. import org.w3c.dom.events.EventListener;
  75. import org.w3c.dom.events.MutationEvent;
  76. import org.w3c.dom.ranges.DocumentRange;
  77. import org.w3c.dom.ranges.Range;
  78. import org.w3c.dom.traversal.DocumentTraversal;
  79. import org.w3c.dom.traversal.NodeFilter;
  80. import org.w3c.dom.traversal.NodeIterator;
  81. import org.w3c.dom.traversal.TreeWalker;
  82. /**
  83. * The Document interface represents the entire HTML or XML document.
  84. * Conceptually, it is the root of the document tree, and provides the
  85. * primary access to the document's data.
  86. * <P>
  87. * Since elements, text nodes, comments, processing instructions,
  88. * etc. cannot exist outside the context of a Document, the Document
  89. * interface also contains the factory methods needed to create these
  90. * objects. The Node objects created have a ownerDocument attribute
  91. * which associates them with the Document within whose context they
  92. * were created.
  93. * <p>
  94. * The DocumentImpl class also implements the DOM Level 2 DocumentTraversal
  95. * interface. This interface is comprised of factory methods needed to
  96. * create NodeIterators and TreeWalkers. The process of creating NodeIterator
  97. * objects also adds these references to this document.
  98. * After finishing with an iterator it is important to remove the object
  99. * using the remove methods in this implementation. This allows the release of
  100. * the references from the iterator objects to the DOM Nodes.
  101. * <p>
  102. * <b>Note:</b> When any node in the document is serialized, the
  103. * entire document is serialized along with it.
  104. *
  105. * @author Arnaud Le Hors, IBM
  106. * @author Joe Kesselman, IBM
  107. * @author Andy Clark, IBM
  108. * @author Ralf Pfeiffer, IBM
  109. * @version $Id: DocumentImpl.java,v 1.78 2003/07/29 18:24:05 elena Exp $
  110. * @since PR-DOM-Level-1-19980818.
  111. */
  112. public class DocumentImpl
  113. extends CoreDocumentImpl
  114. implements DocumentTraversal, DocumentEvent, DocumentRange {
  115. //
  116. // Constants
  117. //
  118. /** Serialization version. */
  119. static final long serialVersionUID = 515687835542616694L;
  120. //
  121. // Data
  122. //
  123. /** Iterators */
  124. // REVISIT: Should this be transient? -Ac
  125. protected Vector iterators;
  126. /** Ranges */
  127. // REVISIT: Should this be transient? -Ac
  128. protected Vector ranges;
  129. /** Table for event listeners registered to this document nodes. */
  130. protected Hashtable eventListeners;
  131. /** Bypass mutation events firing. */
  132. protected boolean mutationEvents = false;
  133. //
  134. // Constructors
  135. //
  136. /**
  137. * NON-DOM: Actually creating a Document is outside the DOM's spec,
  138. * since it has to operate in terms of a particular implementation.
  139. */
  140. public DocumentImpl() {
  141. super();
  142. }
  143. /** Constructor. */
  144. public DocumentImpl(boolean grammarAccess) {
  145. super(grammarAccess);
  146. }
  147. /**
  148. * For DOM2 support.
  149. * The createDocument factory method is in DOMImplementation.
  150. */
  151. public DocumentImpl(DocumentType doctype)
  152. {
  153. super(doctype);
  154. }
  155. /** For DOM2 support. */
  156. public DocumentImpl(DocumentType doctype, boolean grammarAccess) {
  157. super(doctype, grammarAccess);
  158. }
  159. //
  160. // Node methods
  161. //
  162. /**
  163. * Deep-clone a document, including fixing ownerDoc for the cloned
  164. * children. Note that this requires bypassing the WRONG_DOCUMENT_ERR
  165. * protection. I've chosen to implement it by calling importNode
  166. * which is DOM Level 2.
  167. *
  168. * @return org.w3c.dom.Node
  169. * @param deep boolean, iff true replicate children
  170. */
  171. public Node cloneNode(boolean deep) {
  172. DocumentImpl newdoc = new DocumentImpl();
  173. callUserDataHandlers(this, newdoc, UserDataHandler.NODE_CLONED);
  174. cloneNode(newdoc, deep);
  175. // experimental
  176. newdoc.mutationEvents = mutationEvents;
  177. return newdoc;
  178. } // cloneNode(boolean):Node
  179. /**
  180. * Retrieve information describing the abilities of this particular
  181. * DOM implementation. Intended to support applications that may be
  182. * using DOMs retrieved from several different sources, potentially
  183. * with different underlying representations.
  184. */
  185. public DOMImplementation getImplementation() {
  186. // Currently implemented as a singleton, since it's hardcoded
  187. // information anyway.
  188. return DOMImplementationImpl.getDOMImplementation();
  189. }
  190. //
  191. // DocumentTraversal methods
  192. //
  193. /**
  194. * NON-DOM extension:
  195. * Create and return a NodeIterator. The NodeIterator is
  196. * added to a list of NodeIterators so that it can be
  197. * removed to free up the DOM Nodes it references.
  198. *
  199. * @param root The root of the iterator.
  200. * @param whatToShow The whatToShow mask.
  201. * @param filter The NodeFilter installed. Null means no filter.
  202. */
  203. public NodeIterator createNodeIterator(Node root,
  204. short whatToShow,
  205. NodeFilter filter)
  206. {
  207. return createNodeIterator(root, whatToShow, filter, true);
  208. }
  209. /**
  210. * Create and return a NodeIterator. The NodeIterator is
  211. * added to a list of NodeIterators so that it can be
  212. * removed to free up the DOM Nodes it references.
  213. *
  214. * @param root The root of the iterator.
  215. * @param whatToShow The whatToShow mask.
  216. * @param filter The NodeFilter installed. Null means no filter.
  217. * @param entityReferenceExpansion true to expand the contents of
  218. * EntityReference nodes
  219. * @since WD-DOM-Level-2-19990923
  220. */
  221. public NodeIterator createNodeIterator(Node root,
  222. int whatToShow,
  223. NodeFilter filter,
  224. boolean entityReferenceExpansion)
  225. {
  226. if (root == null) {
  227. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
  228. throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
  229. }
  230. NodeIterator iterator = new NodeIteratorImpl(this,
  231. root,
  232. whatToShow,
  233. filter,
  234. entityReferenceExpansion);
  235. if (iterators == null) {
  236. iterators = new Vector();
  237. }
  238. iterators.addElement(iterator);
  239. return iterator;
  240. }
  241. /**
  242. * NON-DOM extension:
  243. * Create and return a TreeWalker.
  244. *
  245. * @param root The root of the iterator.
  246. * @param whatToShow The whatToShow mask.
  247. * @param filter The NodeFilter installed. Null means no filter.
  248. */
  249. public TreeWalker createTreeWalker(Node root,
  250. short whatToShow,
  251. NodeFilter filter)
  252. {
  253. return createTreeWalker(root, whatToShow, filter, true);
  254. }
  255. /**
  256. * Create and return a TreeWalker.
  257. *
  258. * @param root The root of the iterator.
  259. * @param whatToShow The whatToShow mask.
  260. * @param filter The NodeFilter installed. Null means no filter.
  261. * @param entityReferenceExpansion true to expand the contents of
  262. * EntityReference nodes
  263. * @since WD-DOM-Level-2-19990923
  264. */
  265. public TreeWalker createTreeWalker(Node root,
  266. int whatToShow,
  267. NodeFilter filter,
  268. boolean entityReferenceExpansion)
  269. {
  270. if (root == null) {
  271. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
  272. throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
  273. }
  274. return new TreeWalkerImpl(root, whatToShow, filter,
  275. entityReferenceExpansion);
  276. }
  277. //
  278. // Not DOM Level 2. Support DocumentTraversal methods.
  279. //
  280. /** This is not called by the developer client. The
  281. * developer client uses the detach() function on the
  282. * NodeIterator itself. <p>
  283. *
  284. * This function is called from the NodeIterator#detach().
  285. */
  286. void removeNodeIterator(NodeIterator nodeIterator) {
  287. if (nodeIterator == null) return;
  288. if (iterators == null) return;
  289. iterators.removeElement(nodeIterator);
  290. }
  291. //
  292. // DocumentRange methods
  293. //
  294. /**
  295. */
  296. public Range createRange() {
  297. if (ranges == null) {
  298. ranges = new Vector();
  299. }
  300. Range range = new RangeImpl(this);
  301. ranges.addElement(range);
  302. return range;
  303. }
  304. /** Not a client function. Called by Range.detach(),
  305. * so a Range can remove itself from the list of
  306. * Ranges.
  307. */
  308. void removeRange(Range range) {
  309. if (range == null) return;
  310. if (ranges == null) return;
  311. ranges.removeElement(range);
  312. }
  313. /**
  314. * A method to be called when some text was changed in a text node,
  315. * so that live objects can be notified.
  316. */
  317. void replacedText(NodeImpl node) {
  318. // notify ranges
  319. if (ranges != null) {
  320. int size = ranges.size();
  321. for (int i = 0; i != size; i++) {
  322. ((RangeImpl)ranges.elementAt(i)).receiveReplacedText(node);
  323. }
  324. }
  325. }
  326. /**
  327. * A method to be called when some text was deleted from a text node,
  328. * so that live objects can be notified.
  329. */
  330. void deletedText(NodeImpl node, int offset, int count) {
  331. // notify ranges
  332. if (ranges != null) {
  333. int size = ranges.size();
  334. for (int i = 0; i != size; i++) {
  335. ((RangeImpl)ranges.elementAt(i)).receiveDeletedText(node,
  336. offset, count);
  337. }
  338. }
  339. }
  340. /**
  341. * A method to be called when some text was inserted into a text node,
  342. * so that live objects can be notified.
  343. */
  344. void insertedText(NodeImpl node, int offset, int count) {
  345. // notify ranges
  346. if (ranges != null) {
  347. int size = ranges.size();
  348. for (int i = 0; i != size; i++) {
  349. ((RangeImpl)ranges.elementAt(i)).receiveInsertedText(node,
  350. offset, count);
  351. }
  352. }
  353. }
  354. /**
  355. * A method to be called when a text node has been split,
  356. * so that live objects can be notified.
  357. */
  358. void splitData(Node node, Node newNode, int offset) {
  359. // notify ranges
  360. if (ranges != null) {
  361. int size = ranges.size();
  362. for (int i = 0; i != size; i++) {
  363. ((RangeImpl)ranges.elementAt(i)).receiveSplitData(node,
  364. newNode, offset);
  365. }
  366. }
  367. }
  368. //
  369. // DocumentEvent methods
  370. //
  371. /**
  372. * Introduced in DOM Level 2. Optional. <p>
  373. * Create and return Event objects.
  374. *
  375. * @param type The eventType parameter specifies the type of Event
  376. * interface to be created. If the Event interface specified is supported
  377. * by the implementation this method will return a new Event of the
  378. * interface type requested. If the Event is to be dispatched via the
  379. * dispatchEvent method the appropriate event init method must be called
  380. * after creation in order to initialize the Event's values. As an
  381. * example, a user wishing to synthesize some kind of Event would call
  382. * createEvent with the parameter "Events". The initEvent method could then
  383. * be called on the newly created Event to set the specific type of Event
  384. * to be dispatched and set its context information.
  385. * @return Newly created Event
  386. * @exception DOMException NOT_SUPPORTED_ERR: Raised if the implementation
  387. * does not support the type of Event interface requested
  388. * @since WD-DOM-Level-2-19990923
  389. */
  390. public Event createEvent(String type)
  391. throws DOMException {
  392. if (type.equalsIgnoreCase("Events") || "Event".equals(type))
  393. return new EventImpl();
  394. if (type.equalsIgnoreCase("MutationEvents") ||
  395. "MutationEvent".equals(type))
  396. return new MutationEventImpl();
  397. else {
  398. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
  399. throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
  400. }
  401. }
  402. /**
  403. * Sets whether the DOM implementation generates mutation events
  404. * upon operations.
  405. */
  406. void setMutationEvents(boolean set) {
  407. mutationEvents = set;
  408. }
  409. /**
  410. * Returns true if the DOM implementation generates mutation events.
  411. */
  412. boolean getMutationEvents() {
  413. return mutationEvents;
  414. }
  415. /**
  416. * Store event listener registered on a given node
  417. * This is another place where we could use weak references! Indeed, the
  418. * node here won't be GC'ed as long as some listener is registered on it,
  419. * since the eventsListeners table will have a reference to the node.
  420. */
  421. protected void setEventListeners(NodeImpl n, Vector listeners) {
  422. if (eventListeners == null) {
  423. eventListeners = new Hashtable();
  424. }
  425. if (listeners == null) {
  426. eventListeners.remove(n);
  427. if (eventListeners.isEmpty()) {
  428. // stop firing events when there isn't any listener
  429. mutationEvents = false;
  430. }
  431. } else {
  432. eventListeners.put(n, listeners);
  433. // turn mutation events on
  434. mutationEvents = true;
  435. }
  436. }
  437. /**
  438. * Retreive event listener registered on a given node
  439. */
  440. protected Vector getEventListeners(NodeImpl n) {
  441. if (eventListeners == null) {
  442. return null;
  443. }
  444. return (Vector) eventListeners.get(n);
  445. }
  446. //
  447. // EventTarget support (public and internal)
  448. //
  449. //
  450. // Constants
  451. //
  452. /*
  453. * NON-DOM INTERNAL: Class LEntry is just a struct used to represent
  454. * event listeners registered with this node. Copies of this object
  455. * are hung from the nodeListeners Vector.
  456. * <p>
  457. * I considered using two vectors -- one for capture,
  458. * one for bubble -- but decided that since the list of listeners
  459. * is probably short in most cases, it might not be worth spending
  460. * the space. ***** REVISIT WHEN WE HAVE MORE EXPERIENCE.
  461. */
  462. class LEntry implements Serializable
  463. {
  464. String type;
  465. EventListener listener;
  466. boolean useCapture;
  467. /** NON-DOM INTERNAL: Constructor for Listener list Entry
  468. * @param type Event name (NOT event group!) to listen for.
  469. * @param listener Who gets called when event is dispatched
  470. * @param useCaptue True iff listener is registered on
  471. * capturing phase rather than at-target or bubbling
  472. */
  473. LEntry(String type, EventListener listener, boolean useCapture)
  474. {
  475. this.type = type;
  476. this.listener = listener;
  477. this.useCapture = useCapture;
  478. }
  479. } // LEntry
  480. /**
  481. * Introduced in DOM Level 2. <p> Register an event listener with this
  482. * Node. A listener may be independently registered as both Capturing and
  483. * Bubbling, but may only be registered once per role; redundant
  484. * registrations are ignored.
  485. * @param node node to add listener to
  486. * @param type Event name (NOT event group!) to listen for.
  487. * @param listener Who gets called when event is dispatched
  488. * @param useCapture True iff listener is registered on
  489. * capturing phase rather than at-target or bubbling
  490. */
  491. protected void addEventListener(NodeImpl node, String type,
  492. EventListener listener, boolean useCapture)
  493. {
  494. // We can't dispatch to blank type-name, and of course we need
  495. // a listener to dispatch to
  496. if (type == null || type.equals("") || listener == null)
  497. return;
  498. // Each listener may be registered only once per type per phase.
  499. // Simplest way to code that is to zap the previous entry, if any.
  500. removeEventListener(node, type, listener, useCapture);
  501. Vector nodeListeners = getEventListeners(node);
  502. if(nodeListeners == null) {
  503. nodeListeners = new Vector();
  504. setEventListeners(node, nodeListeners);
  505. }
  506. nodeListeners.addElement(new LEntry(type, listener, useCapture));
  507. // Record active listener
  508. LCount lc = LCount.lookup(type);
  509. if (useCapture)
  510. ++lc.captures;
  511. else
  512. ++lc.bubbles;
  513. } // addEventListener(NodeImpl,String,EventListener,boolean) :void
  514. /**
  515. * Introduced in DOM Level 2. <p> Deregister an event listener previously
  516. * registered with this Node. A listener must be independently removed
  517. * from the Capturing and Bubbling roles. Redundant removals (of listeners
  518. * not currently registered for this role) are ignored.
  519. * @param node node to remove listener from
  520. * @param type Event name (NOT event group!) to listen for.
  521. * @param listener Who gets called when event is dispatched
  522. * @param useCapture True iff listener is registered on
  523. * capturing phase rather than at-target or bubbling
  524. */
  525. protected void removeEventListener(NodeImpl node, String type,
  526. EventListener listener,
  527. boolean useCapture)
  528. {
  529. // If this couldn't be a valid listener registration, ignore request
  530. if (type == null || type.equals("") || listener == null)
  531. return;
  532. Vector nodeListeners = getEventListeners(node);
  533. if (nodeListeners == null)
  534. return;
  535. // Note that addListener has previously ensured that
  536. // each listener may be registered only once per type per phase.
  537. // count-down is OK for deletions!
  538. for (int i = nodeListeners.size() - 1; i >= 0; --i) {
  539. LEntry le = (LEntry) nodeListeners.elementAt(i);
  540. if (le.useCapture == useCapture && le.listener == listener &&
  541. le.type.equals(type)) {
  542. nodeListeners.removeElementAt(i);
  543. // Storage management: Discard empty listener lists
  544. if (nodeListeners.size() == 0)
  545. setEventListeners(node, null);
  546. // Remove active listener
  547. LCount lc = LCount.lookup(type);
  548. if (useCapture)
  549. --lc.captures;
  550. else
  551. --lc.bubbles;
  552. break; // Found it; no need to loop farther.
  553. }
  554. }
  555. } // removeEventListener(NodeImpl,String,EventListener,boolean) :void
  556. protected void copyEventListeners(NodeImpl src, NodeImpl tgt) {
  557. Vector nodeListeners = getEventListeners(src);
  558. if (nodeListeners == null) {
  559. return;
  560. }
  561. setEventListeners(tgt, (Vector) nodeListeners.clone());
  562. }
  563. /**
  564. * Introduced in DOM Level 2. <p>
  565. * Distribution engine for DOM Level 2 Events.
  566. * <p>
  567. * Event propagation runs as follows:
  568. * <ol>
  569. * <li>Event is dispatched to a particular target node, which invokes
  570. * this code. Note that the event's stopPropagation flag is
  571. * cleared when dispatch begins; thereafter, if it has
  572. * been set before processing of a node commences, we instead
  573. * immediately advance to the DEFAULT phase.
  574. * <li>The node's ancestors are established as destinations for events.
  575. * For capture and bubble purposes, node ancestry is determined at
  576. * the time dispatch starts. If an event handler alters the document
  577. * tree, that does not change which nodes will be informed of the event.
  578. * <li>CAPTURING_PHASE: Ancestors are scanned, root to target, for
  579. * Capturing listeners. If found, they are invoked (see below).
  580. * <li>AT_TARGET:
  581. * Event is dispatched to NON-CAPTURING listeners on the
  582. * target node. Note that capturing listeners on this node are _not_
  583. * invoked.
  584. * <li>BUBBLING_PHASE: Ancestors are scanned, target to root, for
  585. * non-capturing listeners.
  586. * <li>Default processing: Some DOMs have default behaviors bound to
  587. * specific nodes. If this DOM does, and if the event's preventDefault
  588. * flag has not been set, we now return to the target node and process
  589. * its default handler for this event, if any.
  590. * </ol>
  591. * <p>
  592. * Note that registration of handlers during processing of an event does
  593. * not take effect during this phase of this event; they will not be called
  594. * until the next time this node is visited by dispatchEvent. On the other
  595. * hand, removals take effect immediately.
  596. * <p>
  597. * If an event handler itself causes events to be dispatched, they are
  598. * processed synchronously, before processing resumes
  599. * on the event which triggered them. Please be aware that this may
  600. * result in events arriving at listeners "out of order" relative
  601. * to the actual sequence of requests.
  602. * <p>
  603. * Note that our implementation resets the event's stop/prevent flags
  604. * when dispatch begins.
  605. * I believe the DOM's intent is that event objects be redispatchable,
  606. * though it isn't stated in those terms.
  607. * @param node node to dispatch to
  608. * @param event the event object to be dispatched to
  609. * registered EventListeners
  610. * @return true if the event's <code>preventDefault()</code>
  611. * method was invoked by an EventListener; otherwise false.
  612. */
  613. protected boolean dispatchEvent(NodeImpl node, Event event) {
  614. if (event == null) return false;
  615. // Can't use anyone else's implementation, since there's no public
  616. // API for setting the event's processing-state fields.
  617. EventImpl evt = (EventImpl)event;
  618. // VALIDATE -- must have been initialized at least once, must have
  619. // a non-null non-blank name.
  620. if(!evt.initialized || evt.type == null || evt.type.equals("")) {
  621. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "UNSPECIFIED_EVENT_TYPE_ERR", null);
  622. throw new EventException(EventException.UNSPECIFIED_EVENT_TYPE_ERR, msg);
  623. }
  624. // If nobody is listening for this event, discard immediately
  625. LCount lc = LCount.lookup(evt.getType());
  626. if (lc.captures + lc.bubbles + lc.defaults == 0)
  627. return evt.preventDefault;
  628. // INITIALIZE THE EVENT'S DISPATCH STATUS
  629. // (Note that Event objects are reusable in our implementation;
  630. // that doesn't seem to be explicitly guaranteed in the DOM, but
  631. // I believe it is the intent.)
  632. evt.target = node;
  633. evt.stopPropagation = false;
  634. evt.preventDefault = false;
  635. // Capture pre-event parentage chain, not including target;
  636. // use pre-event-dispatch ancestors even if event handlers mutate
  637. // document and change the target's context.
  638. // Note that this is parents ONLY; events do not
  639. // cross the Attr/Element "blood/brain barrier".
  640. // DOMAttrModified. which looks like an exception,
  641. // is issued to the Element rather than the Attr
  642. // and causes a _second_ DOMSubtreeModified in the Element's
  643. // tree.
  644. Vector pv = new Vector(10,10);
  645. Node p = node;
  646. Node n = p.getParentNode();
  647. while (n != null) {
  648. pv.addElement(n);
  649. p = n;
  650. n = n.getParentNode();
  651. }
  652. // CAPTURING_PHASE:
  653. if (lc.captures > 0) {
  654. evt.eventPhase = Event.CAPTURING_PHASE;
  655. // Ancestors are scanned, root to target, for
  656. // Capturing listeners.
  657. for (int j = pv.size() - 1; j >= 0; --j) {
  658. if (evt.stopPropagation)
  659. break; // Someone set the flag. Phase ends.
  660. // Handle all capturing listeners on this node
  661. NodeImpl nn = (NodeImpl) pv.elementAt(j);
  662. evt.currentTarget = nn;
  663. Vector nodeListeners = getEventListeners(nn);
  664. if (nodeListeners != null) {
  665. Vector nl = (Vector) nodeListeners.clone();
  666. // call listeners in the order in which they got registered
  667. int nlsize = nl.size();
  668. for (int i = 0; i < nlsize; i++) {
  669. LEntry le = (LEntry) nl.elementAt(i);
  670. if (le.useCapture && le.type.equals(evt.type) &&
  671. nodeListeners.contains(le)) {
  672. try {
  673. le.listener.handleEvent(evt);
  674. }
  675. catch (Exception e) {
  676. // All exceptions are ignored.
  677. }
  678. }
  679. }
  680. }
  681. }
  682. }
  683. // Both AT_TARGET and BUBBLE use non-capturing listeners.
  684. if (lc.bubbles > 0) {
  685. // AT_TARGET PHASE: Event is dispatched to NON-CAPTURING listeners
  686. // on the target node. Note that capturing listeners on the target
  687. // node are _not_ invoked, even during the capture phase.
  688. evt.eventPhase = Event.AT_TARGET;
  689. evt.currentTarget = node;
  690. Vector nodeListeners = getEventListeners(node);
  691. if (!evt.stopPropagation && nodeListeners != null) {
  692. Vector nl = (Vector) nodeListeners.clone();
  693. // call listeners in the order in which they got registered
  694. int nlsize = nl.size();
  695. for (int i = 0; i < nlsize; i++) {
  696. LEntry le = (LEntry) nl.elementAt(i);
  697. if (!le.useCapture && le.type.equals(evt.type) &&
  698. nodeListeners.contains(le)) {
  699. try {
  700. le.listener.handleEvent(evt);
  701. }
  702. catch (Exception e) {
  703. // All exceptions are ignored.
  704. }
  705. }
  706. }
  707. }
  708. // BUBBLING_PHASE: Ancestors are scanned, target to root, for
  709. // non-capturing listeners. If the event's preventBubbling flag
  710. // has been set before processing of a node commences, we
  711. // instead immediately advance to the default phase.
  712. // Note that not all events bubble.
  713. if (evt.bubbles) {
  714. evt.eventPhase = Event.BUBBLING_PHASE;
  715. int pvsize = pv.size();
  716. for (int j = 0; j < pvsize; j++) {
  717. if (evt.stopPropagation)
  718. break; // Someone set the flag. Phase ends.
  719. // Handle all bubbling listeners on this node
  720. NodeImpl nn = (NodeImpl) pv.elementAt(j);
  721. evt.currentTarget = nn;
  722. nodeListeners = getEventListeners(nn);
  723. if (nodeListeners != null) {
  724. Vector nl = (Vector) nodeListeners.clone();
  725. // call listeners in the order in which they got
  726. // registered
  727. int nlsize = nl.size();
  728. for (int i = 0; i < nlsize; i++) {
  729. LEntry le = (LEntry) nl.elementAt(i);
  730. if (!le.useCapture && le.type.equals(evt.type) &&
  731. nodeListeners.contains(le)) {
  732. try {
  733. le.listener.handleEvent(evt);
  734. }
  735. catch (Exception e) {
  736. // All exceptions are ignored.
  737. }
  738. }
  739. }
  740. }
  741. }
  742. }
  743. }
  744. // DEFAULT PHASE: Some DOMs have default behaviors bound to specific
  745. // nodes. If this DOM does, and if the event's preventDefault flag has
  746. // not been set, we now return to the target node and process its
  747. // default handler for this event, if any.
  748. // No specific phase value defined, since this is DOM-internal
  749. if (lc.defaults > 0 && (!evt.cancelable || !evt.preventDefault)) {
  750. // evt.eventPhase = Event.DEFAULT_PHASE;
  751. // evt.currentTarget = node;
  752. // DO_DEFAULT_OPERATION
  753. }
  754. return evt.preventDefault;
  755. } // dispatchEvent(NodeImpl,Event) :boolean
  756. /**
  757. * NON-DOM INTERNAL: DOMNodeInsertedIntoDocument and ...RemovedFrom...
  758. * are dispatched to an entire subtree. This is the distribution code
  759. * therefor. They DO NOT bubble, thanks be, but may be captured.
  760. * <p>
  761. * ***** At the moment I'm being sloppy and using the normal
  762. * capture dispatcher on every node. This could be optimized hugely
  763. * by writing a capture engine that tracks our position in the tree to
  764. * update the capture chain without repeated chases up to root.
  765. * @param node node to dispatch to
  766. * @param n node which was directly inserted or removed
  767. * @param e event to be sent to that node and its subtree
  768. */
  769. protected void dispatchEventToSubtree(NodeImpl node, Node n, Event e) {
  770. Vector nodeListeners = getEventListeners(node);
  771. if (nodeListeners == null || n == null)
  772. return;
  773. // ***** Recursive implementation. This is excessively expensive,
  774. // and should be replaced in conjunction with optimization
  775. // mentioned above.
  776. ((NodeImpl) n).dispatchEvent(e);
  777. if (n.getNodeType() == Node.ELEMENT_NODE) {
  778. NamedNodeMap a = n.getAttributes();
  779. for (int i = a.getLength() - 1; i >= 0; --i)
  780. dispatchEventToSubtree(node, a.item(i), e);
  781. }
  782. dispatchEventToSubtree(node, n.getFirstChild(), e);
  783. dispatchEventToSubtree(node, n.getNextSibling(), e);
  784. } // dispatchEventToSubtree(NodeImpl,Node,Event) :void
  785. /**
  786. * NON-DOM INTERNAL: Return object for getEnclosingAttr. Carries
  787. * (two values, the Attr node affected (if any) and its previous
  788. * string value. Simple struct, no methods.
  789. */
  790. class EnclosingAttr implements Serializable
  791. {
  792. AttrImpl node;
  793. String oldvalue;
  794. }
  795. EnclosingAttr savedEnclosingAttr;
  796. /**
  797. * NON-DOM INTERNAL: Convenience wrapper for calling
  798. * dispatchAggregateEvents when the context was established
  799. * by <code>savedEnclosingAttr</code>.
  800. * @param node node to dispatch to
  801. * @param ea description of Attr affected by current operation
  802. */
  803. protected void dispatchAggregateEvents(NodeImpl node, EnclosingAttr ea) {
  804. if (ea != null)
  805. dispatchAggregateEvents(node, ea.node, ea.oldvalue,
  806. MutationEvent.MODIFICATION);
  807. else
  808. dispatchAggregateEvents(node, null, null, (short) 0);
  809. } // dispatchAggregateEvents(NodeImpl,EnclosingAttr) :void
  810. /**
  811. * NON-DOM INTERNAL: Generate the "aggregated" post-mutation events
  812. * DOMAttrModified and DOMSubtreeModified.
  813. * Both of these should be issued only once for each user-requested
  814. * mutation operation, even if that involves multiple changes to
  815. * the DOM.
  816. * For example, if a DOM operation makes multiple changes to a single
  817. * Attr before returning, it would be nice to generate only one
  818. * DOMAttrModified, and multiple changes over larger scope but within
  819. * a recognizable single subtree might want to generate only one
  820. * DOMSubtreeModified, sent to their lowest common ancestor.
  821. * <p>
  822. * To manage this, use the "internal" versions of insert and remove
  823. * with MUTATION_LOCAL, then make an explicit call to this routine
  824. * at the higher level. Some examples now exist in our code.
  825. *
  826. * @param node The node to dispatch to
  827. * @param enclosingAttr The Attr node (if any) whose value has been changed
  828. * as a result of the DOM operation. Null if none such.
  829. * @param oldValue The String value previously held by the
  830. * enclosingAttr. Ignored if none such.
  831. * @param change Type of modification to the attr. See
  832. * MutationEvent.attrChange
  833. */
  834. protected void dispatchAggregateEvents(NodeImpl node,
  835. AttrImpl enclosingAttr,
  836. String oldvalue, short change) {
  837. // We have to send DOMAttrModified.
  838. NodeImpl owner = null;
  839. if (enclosingAttr != null) {
  840. LCount lc = LCount.lookup(MutationEventImpl.DOM_ATTR_MODIFIED);
  841. owner = (NodeImpl) enclosingAttr.getOwnerElement();
  842. if (lc.captures + lc.bubbles + lc.defaults > 0) {
  843. if (owner != null) {
  844. MutationEventImpl me = new MutationEventImpl();
  845. me.initMutationEvent(MutationEventImpl.DOM_ATTR_MODIFIED,
  846. true, false, enclosingAttr,
  847. oldvalue,
  848. enclosingAttr.getNodeValue(),
  849. enclosingAttr.getNodeName(),
  850. change);
  851. owner.dispatchEvent(me);
  852. }
  853. }
  854. }
  855. // DOMSubtreeModified gets sent to the lowest common root of a
  856. // set of changes.
  857. // "This event is dispatched after all other events caused by the
  858. // mutation have been fired."
  859. LCount lc = LCount.lookup(MutationEventImpl.DOM_SUBTREE_MODIFIED);
  860. if (lc.captures + lc.bubbles + lc.defaults > 0) {
  861. MutationEvent me = new MutationEventImpl();
  862. me.initMutationEvent(MutationEventImpl.DOM_SUBTREE_MODIFIED,
  863. true, false, null, null,
  864. null, null, (short) 0);
  865. // If we're within an Attr, DStM gets sent to the Attr
  866. // and to its owningElement. Otherwise we dispatch it
  867. // locally.
  868. if (enclosingAttr != null) {
  869. dispatchEvent(enclosingAttr, me);
  870. if (owner != null)
  871. dispatchEvent(owner, me);
  872. }
  873. else
  874. dispatchEvent(node, me);
  875. }
  876. } // dispatchAggregateEvents(NodeImpl, AttrImpl,String) :void
  877. /**
  878. * NON-DOM INTERNAL: Pre-mutation context check, in
  879. * preparation for later generating DOMAttrModified events.
  880. * Determines whether this node is within an Attr
  881. * @param node node to get enclosing attribute for
  882. * @return either a description of that Attr, or null if none such.
  883. */
  884. protected void saveEnclosingAttr(NodeImpl node) {
  885. savedEnclosingAttr = null;
  886. // MUTATION PREPROCESSING AND PRE-EVENTS:
  887. // If we're within the scope of an Attr and DOMAttrModified
  888. // was requested, we need to preserve its previous value for
  889. // that event.
  890. LCount lc = LCount.lookup(MutationEventImpl.DOM_ATTR_MODIFIED);
  891. if (lc.captures + lc.bubbles + lc.defaults > 0) {
  892. NodeImpl eventAncestor = node;
  893. while (true) {
  894. if (eventAncestor == null)
  895. return;
  896. int type = eventAncestor.getNodeType();
  897. if (type == Node.ATTRIBUTE_NODE) {
  898. EnclosingAttr retval = new EnclosingAttr();
  899. retval.node = (AttrImpl) eventAncestor;
  900. retval.oldvalue = retval.node.getNodeValue();
  901. savedEnclosingAttr = retval;
  902. return;
  903. }
  904. else if (type == Node.ENTITY_REFERENCE_NODE)
  905. eventAncestor = eventAncestor.parentNode();
  906. else
  907. return;
  908. // Any other parent means we're not in an Attr
  909. }
  910. }
  911. } // saveEnclosingAttr(NodeImpl) :void
  912. /**
  913. * A method to be called when a character data node has been modified
  914. */
  915. void modifyingCharacterData(NodeImpl node) {
  916. if (mutationEvents) {
  917. saveEnclosingAttr(node);
  918. }
  919. }
  920. /**
  921. * A method to be called when a character data node has been modified
  922. */
  923. void modifiedCharacterData(NodeImpl node, String oldvalue, String value) {
  924. if (mutationEvents) {
  925. // MUTATION POST-EVENTS:
  926. LCount lc =
  927. LCount.lookup(MutationEventImpl.DOM_CHARACTER_DATA_MODIFIED);
  928. if (lc.captures + lc.bubbles + lc.defaults > 0) {
  929. MutationEvent me = new MutationEventImpl();
  930. me.initMutationEvent(
  931. MutationEventImpl.DOM_CHARACTER_DATA_MODIFIED,
  932. true, false, null,
  933. oldvalue, value, null, (short) 0);
  934. dispatchEvent(node, me);
  935. }
  936. // Subroutine: Transmit DOMAttrModified and DOMSubtreeModified,
  937. // if required. (Common to most kinds of mutation)
  938. dispatchAggregateEvents(node, savedEnclosingAttr);
  939. } // End mutation postprocessing
  940. }
  941. /**
  942. * A method to be called when a node is about to be inserted in the tree.
  943. */
  944. void insertingNode(NodeImpl node, boolean replace) {
  945. if (mutationEvents) {
  946. if (!replace) {
  947. saveEnclosingAttr(node);
  948. }
  949. }
  950. }
  951. /**
  952. * A method to be called when a node has been inserted in the tree.
  953. */
  954. void insertedNode(NodeImpl node, NodeImpl newInternal, boolean replace) {
  955. if (mutationEvents) {
  956. // MUTATION POST-EVENTS:
  957. // "Local" events (non-aggregated)
  958. // New child is told it was inserted, and where
  959. LCount lc = LCount.lookup(MutationEventImpl.DOM_NODE_INSERTED);
  960. if (lc.captures + lc.bubbles + lc.defaults > 0) {
  961. MutationEventImpl me = new MutationEventImpl();
  962. me.initMutationEvent(MutationEventImpl.DOM_NODE_INSERTED,
  963. true, false, node,
  964. null, null, null, (short) 0);
  965. dispatchEvent(newInternal, me);
  966. }
  967. // If within the Document, tell the subtree it's been added
  968. // to the Doc.
  969. lc = LCount.lookup(
  970. MutationEventImpl.DOM_NODE_INSERTED_INTO_DOCUMENT);
  971. if (lc.captures + lc.bubbles + lc.defaults > 0) {
  972. NodeImpl eventAncestor = node;
  973. if (savedEnclosingAttr != null)
  974. eventAncestor = (NodeImpl)
  975. savedEnclosingAttr.node.getOwnerElement();
  976. if (eventAncestor != null) { // Might have been orphan Attr
  977. NodeImpl p = eventAncestor;
  978. while (p != null) {
  979. eventAncestor = p; // Last non-null ancestor
  980. // In this context, ancestry includes
  981. // walking back from Attr to Element
  982. if (p.getNodeType() == ATTRIBUTE_NODE) {
  983. p = (NodeImpl) ((AttrImpl)p).getOwnerElement();
  984. }
  985. else {
  986. p = p.parentNode();
  987. }
  988. }
  989. if (eventAncestor.getNodeType() == Node.DOCUMENT_NODE){
  990. MutationEventImpl me = new MutationEventImpl();
  991. me.initMutationEvent(MutationEventImpl
  992. .DOM_NODE_INSERTED_INTO_DOCUMENT,
  993. false,false,null,null,
  994. null,null,(short)0);
  995. dispatchEventToSubtree(node, newInternal, me);
  996. }
  997. }
  998. }
  999. if (!replace) {
  1000. // Subroutine: Transmit DOMAttrModified and DOMSubtreeModified
  1001. // (Common to most kinds of mutation)
  1002. dispatchAggregateEvents(node, savedEnclosingAttr);
  1003. }
  1004. }
  1005. }
  1006. /**
  1007. * A method to be called when a node is about to be removed from the tree.
  1008. */
  1009. void removingNode(NodeImpl node, NodeImpl oldChild, boolean replace) {
  1010. // notify iterators
  1011. if (iterators != null) {
  1012. int size = iterators.size();
  1013. for (int i = 0; i != size; i++) {
  1014. ((NodeIteratorImpl)iterators.elementAt(i)).removeNode(oldChild);
  1015. }
  1016. }
  1017. // notify ranges
  1018. if (ranges != null) {
  1019. int size = ranges.size();
  1020. for (int i = 0; i != size; i++) {
  1021. ((RangeImpl)ranges.elementAt(i)).removeNode(oldChild);
  1022. }
  1023. }
  1024. // mutation events
  1025. if (mutationEvents) {
  1026. // MUTATION PREPROCESSING AND PRE-EVENTS:
  1027. // If we're within the scope of an Attr and DOMAttrModified
  1028. // was requested, we need to preserve its previous value for
  1029. // that event.
  1030. if (!replace) {
  1031. saveEnclosingAttr(node);
  1032. }
  1033. // Child is told that it is about to be removed
  1034. LCount lc = LCount.lookup(MutationEventImpl.DOM_NODE_REMOVED);
  1035. if (lc.captures + lc.bubbles + lc.defaults > 0) {
  1036. MutationEventImpl me= new MutationEventImpl();
  1037. me.initMutationEvent(MutationEventImpl.DOM_NODE_REMOVED,
  1038. true, false, node, null,
  1039. null, null, (short) 0);
  1040. dispatchEvent(oldChild, me);
  1041. }
  1042. // If within Document, child's subtree is informed that it's
  1043. // losing that status
  1044. lc = LCount.lookup(
  1045. MutationEventImpl.DOM_NODE_REMOVED_FROM_DOCUMENT);
  1046. if (lc.captures + lc.bubbles + lc.defaults > 0) {
  1047. NodeImpl eventAncestor = this;
  1048. if(savedEnclosingAttr != null)
  1049. eventAncestor = (NodeImpl)
  1050. savedEnclosingAttr.node.getOwnerElement();
  1051. if (eventAncestor != null) { // Might have been orphan Attr
  1052. for (NodeImpl p = eventAncestor.parentNode();
  1053. p != null; p = p.parentNode()) {
  1054. eventAncestor = p; // Last non-null ancestor
  1055. }
  1056. if (eventAncestor.getNodeType() == Node.DOCUMENT_NODE){
  1057. MutationEventImpl me = new MutationEventImpl();
  1058. me.initMutationEvent(
  1059. MutationEventImpl.DOM_NODE_REMOVED_FROM_DOCUMENT,
  1060. false, false, null,
  1061. null, null, null, (short) 0);
  1062. dispatchEventToSubtree(node, oldChild, me);
  1063. }
  1064. }
  1065. }
  1066. } // End mutation preprocessing
  1067. }
  1068. /**
  1069. * A method to be called when a node has been removed from the tree.
  1070. */
  1071. void removedNode(NodeImpl node, boolean replace) {
  1072. if (mutationEvents) {
  1073. // MUTATION POST-EVENTS:
  1074. // Subroutine: Transmit DOMAttrModified and DOMSubtreeModified,
  1075. // if required. (Common to most kinds of mutation)
  1076. if (!replace) {
  1077. dispatchAggregateEvents(node, savedEnclosingAttr);
  1078. }
  1079. } // End mutation postprocessing
  1080. }
  1081. /**
  1082. * A method to be called when a node is about to be replaced in the tree.
  1083. */
  1084. void replacingNode(NodeImpl node) {
  1085. if (mutationEvents) {
  1086. saveEnclosingAttr(node);
  1087. }
  1088. }
  1089. /**
  1090. * A method to be called when a node has been replaced in the tree.
  1091. */
  1092. void replacedNode(NodeImpl node) {
  1093. if (mutationEvents) {
  1094. dispatchAggregateEvents(node, savedEnclosingAttr);
  1095. }
  1096. }
  1097. /**
  1098. * A method to be called when an attribute value has been modified
  1099. */
  1100. void modifiedAttrValue(AttrImpl attr, String oldvalue) {
  1101. if (mutationEvents) {
  1102. // MUTATION POST-EVENTS:
  1103. dispatchAggregateEvents(attr, attr, oldvalue,
  1104. MutationEvent.MODIFICATION);
  1105. }
  1106. }
  1107. /**
  1108. * A method to be called when an attribute node has been set
  1109. */
  1110. void setAttrNode(AttrImpl attr, AttrImpl previous) {
  1111. if (mutationEvents) {
  1112. // MUTATION POST-EVENTS:
  1113. if (previous == null) {
  1114. dispatchAggregateEvents(attr.ownerNode, attr, null,
  1115. MutationEvent.ADDITION);
  1116. }
  1117. else {
  1118. dispatchAggregateEvents(attr.ownerNode, attr,
  1119. previous.getNodeValue(),
  1120. MutationEvent.MODIFICATION);
  1121. }
  1122. }
  1123. }
  1124. /**
  1125. * A method to be called when an attribute node has been removed
  1126. */
  1127. void removedAttrNode(AttrImpl attr, NodeImpl oldOwner, String name) {
  1128. // We can't use the standard dispatchAggregate, since it assumes
  1129. // that the Attr is still attached to an owner. This code is
  1130. // similar but dispatches to the previous owner, "element".
  1131. if (mutationEvents) {
  1132. // If we have to send DOMAttrModified (determined earlier),
  1133. // do so.
  1134. LCount lc = LCount.lookup(MutationEventImpl.DOM_ATTR_MODIFIED);
  1135. if (lc.captures + lc.bubbles + lc.defaults > 0) {
  1136. MutationEventImpl me= new MutationEventImpl();
  1137. me.initMutationEvent(MutationEventImpl.DOM_ATTR_MODIFIED,
  1138. true, false, attr,
  1139. attr.getNodeValue(), null, name,
  1140. MutationEvent.REMOVAL);
  1141. dispatchEvent(oldOwner, me);
  1142. }
  1143. // We can hand off to process DOMSubtreeModified, though.
  1144. // Note that only the Element needs to be informed; the
  1145. // Attr's subtree has not been changed by this operation.
  1146. dispatchAggregateEvents(oldOwner, null, null, (short) 0);
  1147. }
  1148. }
  1149. /**
  1150. * A method to be called when an attribute node has been renamed
  1151. */
  1152. void renamedAttrNode(Attr oldAt, Attr newAt) {
  1153. // REVISIT: To be implemented!!!
  1154. }
  1155. /**
  1156. * A method to be called when an element has been renamed
  1157. */
  1158. void renamedElement(Element oldEl, Element newEl) {
  1159. // REVISIT: To be implemented!!!
  1160. }
  1161. } // class DocumentImpl