[kaffe] CVS kaffe (robilad): Resynced with GNU Classpath: DomNode fix

Kaffe CVS cvs-commits at kaffe.org
Sun Apr 17 17:30:46 PDT 2005


PatchSet 5686 
Date: 2005/04/18 00:06:24
Author: robilad
Branch: HEAD
Tag: (none) 
Log:
Resynced with GNU Classpath: DomNode fix

2005-04-17  Dalibor Topic  <robilad at kaffe.org>

        Resynced with GNU Classpath.

        2005-03-26  Chris Burdess  <dog at gnu.org>

        * gnu/xml/dom/DomNode.java (notifyNode): grow listener array as
        required.

Members: 
	ChangeLog:1.3852->1.3853 
	libraries/javalib/gnu/xml/dom/DomNode.java:INITIAL->1.14 

Index: kaffe/ChangeLog
diff -u kaffe/ChangeLog:1.3852 kaffe/ChangeLog:1.3853
--- kaffe/ChangeLog:1.3852	Mon Apr 18 00:02:16 2005
+++ kaffe/ChangeLog	Mon Apr 18 00:06:24 2005
@@ -2,6 +2,15 @@
 
 	Resynced with GNU Classpath.
 
+	2005-03-26  Chris Burdess  <dog at gnu.org>
+
+        * gnu/xml/dom/DomNode.java (notifyNode): grow listener array as
+        required.
+
+2005-04-17  Dalibor Topic  <robilad at kaffe.org>
+
+	Resynced with GNU Classpath.
+
 	2005-03-26  Jeroen Frijters  <jeroen at frijters.net>
 
         * java/awt/image/PixelGrabber.java (setPixels(int,int,int,int,
===================================================================
Checking out kaffe/libraries/javalib/gnu/xml/dom/DomNode.java
RCS:  /home/cvs/kaffe/kaffe/libraries/javalib/gnu/xml/dom/DomNode.java,v
VERS: 1.14
***************
--- /dev/null	Sun Aug  4 19:57:58 2002
+++ kaffe/libraries/javalib/gnu/xml/dom/DomNode.java	Mon Apr 18 00:30:45 2005
@@ -0,0 +1,2189 @@
+/* DomNode.java -- 
+   Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.dom;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+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.EventTarget;
+import org.w3c.dom.events.MutationEvent;
+import org.w3c.dom.traversal.NodeFilter;
+import org.w3c.dom.traversal.NodeIterator;
+
+/**
+ * <p> "Node", "EventTarget", and "DocumentEvent" implementation.
+ * This provides most of the core DOM functionality; only more
+ * specialized features are provided by subclasses.  Those subclasses may
+ * have some particular constraints they must implement, by overriding
+ * methods defined here.  Such constraints are noted here in the method
+ * documentation. </p>
+ *
+ * <p> Note that you can create events with type names prefixed with "USER-",
+ * and pass them through this DOM.  This lets you use the DOM event scheme
+ * for application specific purposes, although you must use a predefined event
+ * structure (such as MutationEvent) to pass data along with those events.
+ * Test for existence of this feature with the "USER-Events" DOM feature
+ * name.</p>
+ *
+ * <p> Other kinds of events you can send include the "html" events,
+ * like "load", "unload", "abort", "error", and "blur"; and the mutation
+ * events.  If this DOM has been compiled with mutation event support
+ * enabled, it will send mutation events when you change parts of the
+ * tree; otherwise you may create and send such events yourself, but
+ * they won't be generated by the DOM itself. </p>
+ *
+ * <p> Note that there is a namespace-aware name comparison method,
+ * <em>nameAndTypeEquals</em>, which compares the names (and types) of
+ * two nodes in conformance with the "Namespaces in XML" specification.
+ * While mostly intended for use with elements and attributes, this should
+ * also be helpful for ProcessingInstruction nodes and some others which
+ * do not have namespace URIs.
+ *
+ * @author David Brownell
+ * @author <a href='mailto:dog at gnu.org'>Chris Burdess</a>
+ */
+public abstract class DomNode
+  implements Node, NodeList, EventTarget, DocumentEvent, Cloneable, Comparable
+{
+
+  // package private
+  //final static String xmlNamespace = "http://www.w3.org/XML/1998/namespace";
+  //final static String xmlnsURI = "http://www.w3.org/2000/xmlns/";
+
+  // tunable
+  //	NKIDS_* affects arrays of children (which grow)
+  // (currently) fixed size:
+  //	ANCESTORS_* is for event capture/bubbling, # ancestors
+  //	NOTIFICATIONS_* is for per-node event delivery, # events
+  private static final int NKIDS_DELTA = 8;
+  private static final int ANCESTORS_INIT = 20;
+  private static final int NOTIFICATIONS_INIT = 10;
+
+  // tunable: enable mutation events or not?  Enabling it costs about
+  // 10-15% in DOM construction time, last time it was measured.
+
+  // package private !!!
+  static final boolean reportMutations = true;
+
+  // locking protocol changeable only within this class
+  private static final Object lockNode = new Object();
+
+  // NON-FINAL class data
+
+  // Optimize event dispatch by not allocating memory each time
+  private static boolean dispatchDataLock;
+  private static DomNode[] ancestors = new DomNode[ANCESTORS_INIT];
+  private static ListenerRecord[] notificationSet
+    = new ListenerRecord[NOTIFICATIONS_INIT];
+
+  // Ditto for the (most common) event object itself!
+  private static boolean eventDataLock;
+  private static DomEvent.DomMutationEvent mutationEvent
+    = new DomEvent.DomMutationEvent(null);
+
+  //
+  // PER-INSTANCE DATA
+  //
+
+  DomDocument owner;
+  DomNode parent; // parent node;
+  DomNode previous; // previous sibling node
+  DomNode next; // next sibling node
+  DomNode first; // first child node
+  DomNode last; // last child node
+  int index; // index of this node in its parent's children
+  int depth; // depth of the node in the document
+  int length; // number of children
+  final short nodeType;
+
+  // Bleech ... "package private" so a builder can populate entity refs.
+  // writable during construction.  DOM spec is nasty.
+  boolean readonly;
+
+  // event registrations
+  private ListenerRecord[] listeners;
+  private int nListeners;
+
+  // DOM Level 3 userData dictionary.
+  private HashMap userData;
+  private HashMap userDataHandlers;
+
+  //
+  // Some of the methods here are declared 'final' because
+  // knowledge about their implementation is built into this
+  // class -- for both integrity and performance.
+  //
+
+  /**
+   * Reduces space utilization for this node.
+   */
+  public void compact()
+  {
+    if (listeners != null && listeners.length != nListeners)
+      {
+        if (nListeners == 0)
+          {
+            listeners = null;
+          }
+        else
+          {
+            ListenerRecord[] l = new ListenerRecord[nListeners];
+            System.arraycopy(listeners, 0, l, 0, nListeners);
+            listeners = l;
+          }
+      }
+  }
+
+  /**
+   * Constructs a node and associates it with its owner.  Only
+   * Document and DocumentType nodes may be created with no owner,
+   * and DocumentType nodes get an owner as soon as they are
+   * associated with a document.
+   */
+  protected DomNode(short nodeType, DomDocument owner)
+  {
+    this.nodeType = nodeType;
+
+    if (owner == null)
+      {
+        // DOM calls never go down this path
+        if (nodeType != DOCUMENT_NODE && nodeType != DOCUMENT_TYPE_NODE)
+          {
+            throw new IllegalArgumentException ("no owner!");
+          }
+      }
+    this.owner = owner;
+  }
+  
+
+  /**
+   * <b>DOM L1</b>
+   * Returns null; Element subclasses must override this method.
+   */
+  public NamedNodeMap getAttributes()
+  {
+    return null;
+  }
+
+  /**
+   * <b>DOM L2></b>
+   * Returns true iff this is an element node with attributes.
+   */
+  public boolean hasAttributes()
+  {
+    return false;
+  }
+
+  /**
+   * <b>DOM L1</b>
+   * Returns a list, possibly empty, of the children of this node.
+   * In this implementation, to conserve memory, nodes are the same
+   * as their list of children.  This can have ramifications for
+   * subclasses, which may need to provide their own getLength method
+   * for reasons unrelated to the NodeList method of the same name.
+   */
+  public NodeList getChildNodes()
+  {
+    return this;
+  }
+
+  /**
+   * <b>DOM L1</b>
+   * Returns the first child of this node, or null if there are none.
+   */
+  public Node getFirstChild()
+  {
+    return first;
+  }
+
+  /**
+   * <b>DOM L1</b>
+   * Returns the last child of this node, or null if there are none.
+   */
+  public Node getLastChild()
+  {
+    return last;
+  }
+
+  /**
+   * <b>DOM L1</b>
+   * Returns true if this node has children.
+   */
+  public boolean hasChildNodes()
+  {
+    return length != 0;
+  }
+
+
+  /**
+   * Exposes the internal "readonly" flag.  In DOM, children of
+   * entities and entity references are readonly, as are the
+   * objects associated with DocumentType objets.
+   */
+  public final boolean isReadonly()
+  {
+    return readonly;
+  }
+
+  /**
+   * Sets the internal "readonly" flag so this subtree can't be changed.
+   * Subclasses need to override this method for any associated content
+   * that's not a child node, such as an element's attributes or the
+   * (few) declarations associated with a DocumentType.
+   */
+  public void makeReadonly()
+  {
+    readonly = true;
+    for (DomNode child = first; child != null; child = child.next)
+      {
+        child.makeReadonly();
+      }
+  }
+
+  /**
+   * Used to adopt a node to a new document.
+   */
+  void setOwner(DomDocument doc)
+  {
+    this.owner = doc;
+    for (DomNode ctx = first; ctx != null; ctx = ctx.next)
+      {
+        ctx.setOwner(doc);
+      }
+  }
+
+  // just checks the node for inclusion -- may be called many
+  // times (docfrag) before anything is allowed to change
+  private void checkMisc(DomNode child)
+  {
+    if (readonly && !owner.building)
+      {
+        throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
+                                  null, this, 0);
+      }
+    for (DomNode ctx = this; ctx != null; ctx = ctx.parent)
+      {
+        if (child == ctx)
+          {
+            throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR,
+                                      "can't make ancestor into a child",
+                                      this, 0);
+          }
+      }
+
+    DomDocument owner = (nodeType == DOCUMENT_NODE) ? (DomDocument) this :
+      this.owner;
+    DomDocument childOwner = child.owner;
+    short childNodeType = child.nodeType;
+    
+    if (childOwner != owner)
+      {
+        // new in DOM L2, this case -- patch it up later, in reparent()
+        if (!(childNodeType == DOCUMENT_TYPE_NODE && childOwner == null))
+          {
+            throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR,
+                                      null, child, 0);
+          }
+      }
+
+    // enforce various structural constraints
+    switch (nodeType)
+      {
+      case DOCUMENT_NODE:
+        switch (childNodeType)
+          {
+          case ELEMENT_NODE:
+          case PROCESSING_INSTRUCTION_NODE:
+          case COMMENT_NODE:
+          case DOCUMENT_TYPE_NODE:
+            return;
+          }
+        break;
+        
+      case ATTRIBUTE_NODE:
+        switch (childNodeType)
+          {
+          case TEXT_NODE:
+          case ENTITY_REFERENCE_NODE:
+            return;
+          }
+        break;
+        
+      case DOCUMENT_FRAGMENT_NODE:
+      case ENTITY_REFERENCE_NODE:
+      case ELEMENT_NODE:
+      case ENTITY_NODE:
+        switch (childNodeType)
+          {
+          case ELEMENT_NODE:
+          case TEXT_NODE:
+          case COMMENT_NODE:
+          case PROCESSING_INSTRUCTION_NODE:
+          case CDATA_SECTION_NODE:
+          case ENTITY_REFERENCE_NODE:
+            return;
+          }
+        break;
+      }
+    if (owner.checkingWellformedness)
+      {
+        throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR,
+                                  "can't append " +
+                                  nodeTypeToString(childNodeType) +
+                                  " to node of type " +
+                                  nodeTypeToString(nodeType),
+                                  this, 0);
+      }
+  }
+  
+  // Here's hoping a good optimizer will detect the case when the
+  // next several methods are never called, and won't allocate
+  // object code space of any kind.  (Case:  not reporting any
+  // mutation events.  We can also remove some static variables
+  // listed above.)
+
+  private void insertionEvent(DomEvent.DomMutationEvent event,
+                              DomNode target)
+  {
+    if (owner == null || owner.building)
+      {
+        return;
+      }
+    boolean doFree = false;
+    
+    if (event == null)
+      {
+        event = getMutationEvent();
+      }
+    if (event != null)
+      {
+        doFree = true;
+      }
+    else
+      {
+        event = new DomEvent.DomMutationEvent(null);
+      }
+    event.initMutationEvent("DOMNodeInserted",
+                            true /* bubbles */, false /* nocancel */,
+                            this /* related */, null, null, null, (short) 0);
+    target.dispatchEvent(event);
+
+    // XXX should really visit every descendant of 'target'
+    // and sent a DOMNodeInsertedIntoDocument event to it...
+    // bleech, there's no way to keep that acceptably fast.
+
+    if (doFree)
+      {
+        event.target = null;
+        event.relatedNode = null;
+        event.currentNode = null;
+        eventDataLock = false;
+      } // else we created work for the GC
+  }
+
+  private void removalEvent(DomEvent.DomMutationEvent event,
+                            DomNode target)
+  {
+    if (owner == null || owner.building)
+      {
+        return;
+      }
+    boolean doFree = false;
+
+    if (event == null)
+      {
+        event = getMutationEvent();
+      }
+    if (event != null)
+      {
+        doFree = true;
+      }
+    else
+      {
+        event = new DomEvent.DomMutationEvent(null);
+      }
+    event.initMutationEvent("DOMNodeRemoved",
+                            true /* bubbles */, false /* nocancel */,
+                            this /* related */, null, null, null, (short) 0);
+    target.dispatchEvent(event);
+
+    // XXX should really visit every descendant of 'target'
+    // and sent a DOMNodeRemovedFromDocument event to it...
+    // bleech, there's no way to keep that acceptably fast.
+
+    event.target = null;
+    event.relatedNode = null;
+    event.currentNode = null;
+    if (doFree)
+      {
+        eventDataLock = false;
+      }
+    // else we created more work for the GC
+  }
+
+  //
+  // Avoid creating lots of memory management work, by using a simple
+  // allocation strategy for the mutation event objects that get used
+  // at least once per tree modification.  We can't use stack allocation,
+  // so we do the next simplest thing -- more or less, static allocation.
+  // Concurrent notifications should be rare, anyway.
+  //
+  // Returns the preallocated object, which needs to be carefully freed,
+  // or null to indicate the caller needs to allocate their own.
+  //
+  static private DomEvent.DomMutationEvent getMutationEvent()
+  {
+    synchronized (lockNode)
+      {
+        if (eventDataLock)
+          {
+            return null;
+          }
+        eventDataLock = true;
+        return mutationEvent;
+      }
+  }
+
+  // NOTE:  this is manually inlined in the insertion
+  // and removal event methods above; change in sync.
+  static private void freeMutationEvent()
+  {
+    // clear fields to enable GC
+    mutationEvent.clear();
+    eventDataLock = false;
+  }
+
+  void setDepth(int depth)
+  {
+    this.depth = depth;
+    for (DomNode ctx = first; ctx != null; ctx = ctx.next)
+      {
+        ctx.setDepth(depth + 1);
+      }
+  }
+
+  /**
+   * <b>DOM L1</b>
+   * Appends the specified node to this node's list of children.
+   * Document subclasses must override this to enforce the restrictions
+   * that there be only one element and document type child.
+   *
+   * <p> Causes a DOMNodeInserted mutation event to be reported.
+   * Will first cause a DOMNodeRemoved event to be reported if the
+   * parameter already has a parent.  If the new child is a document
+   * fragment node, both events will be reported for each child of
+   * the fragment; the order in which children are removed and
+   * inserted is implementation-specific.
+   *
+   * <p> If this DOM has been compiled without mutation event support,
+   * these events will not be reported.
+   */
+  public Node appendChild(Node newChild)
+  {
+    try
+      {
+        DomNode	child = (DomNode) newChild;
+
+        if (child.nodeType == DOCUMENT_FRAGMENT_NODE)
+          {
+            // Append all nodes in the fragment to this node
+            for (DomNode ctx = child.first; ctx != null; ctx = ctx.next)
+              {
+                checkMisc(ctx);
+              }
+            for (DomNode ctx = child.first; ctx != null; )
+              {
+                DomNode ctxNext = ctx.next;
+                appendChild(ctx);
+                ctx = ctxNext;
+              }
+          }
+        else
+          {
+            checkMisc(child);
+            if (child.parent != null)
+              {
+                child.parent.removeChild(child);
+              }
+            child.parent = this;
+            child.index = length++;
+            child.setDepth(depth + 1);
+            child.next = null;
+            if (last == null)
+              {
+                first = child;
+                child.previous = null;
+              }
+            else
+              {
+                last.next = child;
+                child.previous = last;
+              }
+            last = child;
+
+            if (reportMutations)
+              {
+                insertionEvent(null, child);
+              }
+          }
+
+        return child;
+      }
+    catch (ClassCastException e)
+      {
+        throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR,
+                                  null, newChild, 0);
+    }
+  }
+
+  /**
+   * <b>DOM L1</b>
+   * Inserts the specified node in this node's list of children.
+   * Document subclasses must override this to enforce the restrictions
+   * that there be only one element and document type child.
+   *
+   * <p> Causes a DOMNodeInserted mutation event to be reported.  Will
+   * first cause a DOMNodeRemoved event to be reported if the newChild
+   * parameter already has a parent. If the new child is a document
+   * fragment node, both events will be reported for each child of
+   * the fragment; the order in which children are removed and inserted
+   * is implementation-specific.
+   *
+   * <p> If this DOM has been compiled without mutation event support,
+   * these events will not be reported.
+   */
+  public Node insertBefore(Node newChild, Node refChild)
+  {
+    if (refChild == null)
+      {
+        return appendChild(newChild);
+      }
+
+    try
+      {
+        DomNode	child = (DomNode) newChild;
+        DomNode ref = (DomNode) refChild;
+        
+        if (child.nodeType == DOCUMENT_FRAGMENT_NODE)
+          {
+            // Append all nodes in the fragment to this node
+            for (DomNode ctx = child.first; ctx != null; ctx = ctx.next)
+              {
+                checkMisc(ctx);
+              }
+            for (DomNode ctx = child.first; ctx != null; )
+              {
+                DomNode ctxNext = ctx.next;
+                insertBefore(ctx, ref);
+                ctx = ctxNext;
+              }
+          }
+        else
+          {
+            checkMisc(child);
+            if (ref == null || ref.parent != this)
+              {
+                throw new DomDOMException(DOMException.NOT_FOUND_ERR,
+                                          null, ref, 0);
+              }
+            if (ref == child)
+              {
+                throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR,
+                                          "can't insert node before itself",
+                                          ref, 0);
+              }
+        
+            if (child.parent != null)
+              {
+                child.parent.removeChild(child);
+              }
+            child.parent = this;
+            int i = ref.index;
+            child.setDepth(depth + 1);
+            child.next = ref;
+            if (ref.previous != null)
+              {
+                ref.previous.next = child;
+              }
+            child.previous = ref.previous;
+            ref.previous = child;
+            if (first == ref)
+              {
+                first = child;
+              }
+            // index renumbering
+            for (DomNode ctx = child; ctx != null; ctx = ctx.next)
+              {
+                ctx.index = i++;
+              }
+
+            if (reportMutations)
+              {
+                insertionEvent(null, child);
+              }
+          }
+        
+        return child;
+      }
+    catch (ClassCastException e)
+      {
+        throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR,
+                                  null, newChild, 0);
+      }
+  }
+
+  /**
+   * <b>DOM L1</b>
+   * Replaces the specified node in this node's list of children.
+   * Document subclasses must override this to test the restrictions
+   * that there be only one element and document type child.
+   *
+   * <p> Causes DOMNodeRemoved and DOMNodeInserted mutation event to be
+   * reported.  Will cause another DOMNodeRemoved event to be reported if
+   * the newChild parameter already has a parent.  These events may be
+   * delivered in any order, except that the event reporting removal
+   * from such an existing parent will always be delivered before the
+   * event reporting its re-insertion as a child of some other node.
+   * The order in which children are removed and inserted is implementation
+   * specific.
+   *
+   * <p> If your application needs to depend on the in which those removal
+   * and insertion events are delivered, don't use this API.  Instead,
+   * invoke the removeChild and insertBefore methods directly, to guarantee
+   * a specific delivery order.  Similarly, don't use document fragments,
+   * Otherwise your application code may not work on a DOM which implements
+   * this method differently.
+   *
+   * <p> If this DOM has been compiled without mutation event support,
+   * these events will not be reported.
+   */
+  public Node replaceChild(Node newChild, Node refChild)
+  {
+    try
+      {
+        DomNode child = (DomNode) newChild;
+        DomNode ref = (DomNode) refChild;
+        
+        DomEvent.DomMutationEvent event = getMutationEvent();
+        boolean doFree = (event != null);
+            
+        if (child.nodeType == DOCUMENT_FRAGMENT_NODE)
+          {
+            // Append all nodes in the fragment to this node
+            for (DomNode ctx = child.first; ctx != null; ctx = ctx.next)
+              {
+                checkMisc(ctx);
+              }
+            if (ref == null || ref.parent != this)
+              {
+                throw new DomDOMException(DOMException.NOT_FOUND_ERR,
+                                          null, ref, 0);
+              }
+            
+            if (reportMutations)
+              {
+                removalEvent(event, ref);
+              }
+            length--;
+            length += child.length;
+            
+            if (child.length == 0)
+              {
+                // Removal
+                if (ref.previous != null)
+                  {
+                    ref.previous.next = ref.next;
+                  }
+                if (ref.next != null)
+                  {
+                    ref.next.previous = ref.previous;
+                  }
+                if (first == ref)
+                  {
+                    first = ref.next;
+                  }
+                if (last == ref)
+                  {
+                    last = ref.previous;
+                  }
+              }
+            else
+              {
+                int i = ref.index;
+                for (DomNode ctx = child.first; ctx != null; ctx = ctx.next)
+                  {
+                    // Insertion
+                    ctx.parent = this;
+                    ctx.index = i++;
+                    ctx.setDepth(ref.depth);
+                    if (ctx == child.first)
+                      {
+                        ctx.previous = ref.previous;
+                      }
+                    if (ctx == child.last)
+                      {
+                        ctx.next = ref.next;
+                      }
+                  }
+                if (first == ref)
+                  {
+                    first = child.first;
+                  }
+                if (last == ref)
+                  {
+                    last = child.last;
+                  }
+              }
+          }
+        else
+          {
+            checkMisc(child);
+            if (ref == null || ref.parent != this)
+              {
+                throw new DomDOMException(DOMException.NOT_FOUND_ERR,
+                                          null, ref, 0);
+              }
+        
+            if (reportMutations)
+              {
+                removalEvent(event, ref);
+              }
+            
+            if (child.parent != null)
+              {
+                child.parent.removeChild(child);
+              }
+            child.parent = this;
+            child.index = ref.index;
+            child.setDepth(ref.depth);
+            if (ref.previous != null)
+              {
+                ref.previous.next = child;
+              }
+            child.previous = ref.previous;
+            if (ref.next != null)
+              {
+                ref.next.previous = child;
+              }
+            child.next = ref.next;
+            if (first == ref)
+              {
+                first = child;
+              }
+            if (last == ref)
+              {
+                last = child;
+              }
+
+            if (reportMutations)
+              {
+                insertionEvent(event, child);
+              }
+            if (doFree)
+              {
+                freeMutationEvent();
+              }
+          }
+        ref.parent = null;
+        ref.index = 0;
+        ref.setDepth(0);
+        ref.previous = null;
+        ref.next = null;
+        
+        return ref;
+      }
+    catch (ClassCastException e)
+      {
+        throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR,
+                                  null, newChild, 0);
+      }
+  }
+
+  /**
+   * <b>DOM L1</b>
+   * Removes the specified child from this node's list of children,
+   * or else reports an exception.
+   *
+   * <p> Causes a DOMNodeRemoved mutation event to be reported.
+   *
+   * <p> If this DOM has been compiled without mutation event support,
+   * these events will not be reported.
+   */
+  public Node removeChild(Node refChild)
+  {
+    try
+      {
+        DomNode ref = (DomNode) refChild;
+
+        if (ref == null || ref.parent != this)
+          {
+            throw new DomDOMException(DOMException.NOT_FOUND_ERR,
+                                      null, ref, 0);
+          }
+        if (readonly && !owner.building)
+          {
+            throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
+                                      null, this, 0);
+          }
+        
+        for (DomNode child = first; child != null; child = child.next)
+          {
+            if (child == ref)
+              {
+                if (reportMutations)
+                  {
+                    removalEvent(null, child);
+                  }
+
+                length--;
+                if (ref.previous != null)
+                  {
+                    ref.previous.next = ref.next;
+                  }
+                if (ref.next != null)
+                  {
+                    ref.next.previous = ref.previous;
+                  }
+                if (first == ref)
+                  {
+                    first = ref.next;
+                  }
+                if (last == ref)
+                  {
+                    last = ref.previous;
+                  }
+                // renumber indices
+                int i = 0;
+                for (DomNode ctx = first; ctx != null; ctx = ctx.next)
+                  {
+                    ctx.index = i++;
+                  }
+                ref.parent = null;
+                ref.setDepth(0);
+                ref.index = 0;
+                ref.previous = null;
+                ref.next = null;
+                
+                return ref;
+              }
+          }
+        throw new DomDOMException(DOMException.NOT_FOUND_ERR,
+                                  "that's no child of mine", refChild, 0);
+      }
+    catch (ClassCastException e)
+      {
+        throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR,
+                                  null, refChild, 0);
+      }
+  }
+
+  /**
+   * <b>DOM L1 (NodeList)</b>
+   * Returns the item with the specified index in this NodeList,
+   * else null.
+   */
+  public Node item(int index)
+  {
+    DomNode child = first;
+    int count = 0;
+    while (child != null && count < index)
+      {
+        child = child.next;
+        count++;
+      }
+    return child;
+  }
+
+  /**
+   * <b>DOM L1 (NodeList)</b>
+   * Returns the number of elements in this NodeList.
+   * (Note that many interfaces have a "Length" property, not just
+   * NodeList, and if a node subtype must implement one of those,
+   * it will also need to override getChildNodes.)
+   */

*** Patch too long, truncated ***




More information about the kaffe mailing list