void AttrImpl::cloneChildren(const NodeImpl &other) { // for (NodeImpl *mykid = other.getFirstChild(); for (NodeImpl *mykid = ((NodeImpl&)other).getFirstChild(); mykid != null; mykid = mykid->getNextSibling()) { this->appendChild(mykid->cloneNode(true)); } }
// NodeImpl::deleteIf is called when a node's reference count goes // to 0. It is separate function from removeRef because removeRef // is likely to be in-lined. // // See comments at RefCountedImpl::removeRef(). // void NodeImpl::deleteIf(NodeImpl *thisNode) { if (thisNode == 0) return; if (thisNode->isOwned()) return; // Delete this node. There should be no siblings, as the DOM // supports no node operations that would detach a node from // its parent while retaining siblings. // The target node may have children, in which case they must // be removed from this node before deleting this node. // First, if this node is an ID attribute, we need to remove it // from the hashtable of element IDs before removing the Attrs // children. This is because the Attr's children Text nodes // contain the attr's value, which is the hash table key. // if (thisNode->isAttrImpl() && ((AttrImpl *)thisNode->isIdAttr())) { ((AttrImpl *)thisNode)->getOwnerDocument() -> getNodeIDMap()->remove((AttrImpl *)thisNode); } thisNode->isReadOnly(false); // removeChild requires node not be readonly. NodeImpl *theNextChild; for (NodeImpl *child = thisNode->getFirstChild(); child != 0; child=theNextChild) { theNextChild = child->getNextSibling(); thisNode->removeChild(child); if (child->nodeRefCount == 0) deleteIf(child); } delete thisNode; };
NodeImpl *ParentNode::insertBefore(NodeImpl *newChild, NodeImpl *refChild) { bool errorChecking = ownerDocument->getErrorChecking(); if (newChild->isDocumentFragmentImpl()) { // SLOW BUT SAFE: We could insert the whole subtree without // juggling so many next/previous pointers. (Wipe out the // parent's child-list, patch the parent pointers, set the // ends of the list.) But we know some subclasses have special- // case behavior they add to insertBefore(), so we don't risk it. // This approch also takes fewer bytecodes. // NOTE: If one of the children is not a legal child of this // node, throw HIERARCHY_REQUEST_ERR before _any_ of the children // have been transferred. (Alternative behaviors would be to // reparent up to the first failure point or reparent all those // which are acceptable to the target node, neither of which is // as robust. PR-DOM-0818 isn't entirely clear on which it // recommends????? // No need to check kids for right-document; if they weren't, // they wouldn't be kids of that DocFrag. if (errorChecking) { for (NodeImpl *kid = newChild->getFirstChild(); // Prescan kid != null; kid = kid->getNextSibling()) { if (!DocumentImpl::isKidOK(this, kid)) { throw DOM_DOMException( DOM_DOMException::HIERARCHY_REQUEST_ERR, null); } } } while (newChild->hasChildNodes()) { // Move insertBefore(newChild->getFirstChild(),refChild); } return newChild; } // it's a no-op if refChild is the same as newChild if (refChild == newChild) { return newChild; } if (errorChecking) { if (isReadOnly()) { throw DOM_DOMException( DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null); } if (newChild->getOwnerDocument() != ownerDocument) { throw DOM_DOMException(DOM_DOMException::WRONG_DOCUMENT_ERR, null); } if (!DocumentImpl::isKidOK(this, newChild)) { throw DOM_DOMException(DOM_DOMException::HIERARCHY_REQUEST_ERR, null); } // refChild must be a child of this node (or null) if (refChild != null && refChild->getParentNode() != this) { throw DOM_DOMException(DOM_DOMException::NOT_FOUND_ERR, null); } // Prevent cycles in the tree // newChild cannot be ancestor of this Node, // and actually cannot be this bool treeSafe = true; for (NodeImpl *a = this; treeSafe && a != null; a = a->getParentNode()) { treeSafe = (newChild != a); } if (!treeSafe) { throw DOM_DOMException(DOM_DOMException::HIERARCHY_REQUEST_ERR, null); } } // Convert to internal type, to avoid repeated casting ChildNode * newInternal = (ChildNode *)newChild; NodeImpl *oldparent = newInternal->getParentNode(); if (oldparent != null) { oldparent->removeChild(newInternal); } // Convert to internal type, to avoid repeated casting ChildNode *refInternal = (ChildNode *)refChild; // Attach up newInternal->ownerNode = this; newInternal->isOwned(true); // Attach before and after // Note: firstChild.previousSibling == lastChild!! if (firstChild == null) { // this our first and only child firstChild = newInternal; newInternal->isFirstChild(true); newInternal->previousSibling = newInternal; } else { if (refInternal == null) { // this is an append ChildNode *lastChild = firstChild->previousSibling; lastChild->nextSibling = newInternal; newInternal->previousSibling = lastChild; firstChild->previousSibling = newInternal; } else { // this is an insert if (refChild == firstChild) { // at the head of the list firstChild->isFirstChild(false); newInternal->nextSibling = firstChild; newInternal->previousSibling = firstChild->previousSibling; firstChild->previousSibling = newInternal; firstChild = newInternal; newInternal->isFirstChild(true); } else { // somewhere in the middle ChildNode *prev = refInternal->previousSibling; newInternal->nextSibling = refInternal; prev->nextSibling = newInternal; refInternal->previousSibling = newInternal; newInternal->previousSibling = prev; } } } changed(); // update cached length if we have any if (fCachedLength != -1) { fCachedLength++; } if (fCachedChildIndex != -1) { // if we happen to insert just before the cached node, update // the cache to the new node to match the cached index if (fCachedChild == refInternal) { fCachedChild = newInternal; } else { // otherwise just invalidate the cache fCachedChildIndex = -1; } } if (this->getOwnerDocument() != null) { typedef RefVectorOf<RangeImpl> RangeImpls; RangeImpls* ranges = this->getOwnerDocument()->getRanges(); if ( ranges != null) { unsigned int sz = ranges->size(); for (unsigned int i =0; i<sz; i++) { ranges->elementAt(i)->updateRangeForInsertedNode(newInternal); } } } return newInternal; };