DOMNode *DOMParentNode::insertBefore(DOMNode *newChild, DOMNode *refChild) { //not really in the specs, but better than nothing if(newChild==NULL) throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMParentNodeMemoryManager); DOMNodeImpl *thisNodeImpl = castToNodeImpl(this); if (thisNodeImpl->isReadOnly()) throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMParentNodeMemoryManager); if (newChild->getOwnerDocument() != fOwnerDocument) throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0, GetDOMParentNodeMemoryManager); // Prevent cycles in the tree //only need to do this if the node has children if(newChild->hasChildNodes()) { bool treeSafe=true; for(DOMNode *a=castToNode(this)->getParentNode(); treeSafe && a!=0; a=a->getParentNode()) treeSafe=(newChild!=a); if(!treeSafe) throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMParentNodeMemoryManager); } // refChild must in fact be a child of this node (or 0) if (refChild!=0 && refChild->getParentNode() != castToNode(this)) throw DOMException(DOMException::NOT_FOUND_ERR,0, GetDOMParentNodeMemoryManager); // if the new node has to be placed before itself, we don't have to do anything // (even worse, we would crash if we continue, as we assume they are two distinct nodes) if (refChild!=0 && newChild->isSameNode(refChild)) return newChild; if (newChild->getNodeType() == DOMNode::DOCUMENT_FRAGMENT_NODE) { // 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. for(DOMNode *kid=newChild->getFirstChild(); // Prescan kid!=0; kid=kid->getNextSibling()) { if (!DOMDocumentImpl::isKidOK(castToNode(this), kid)) throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMParentNodeMemoryManager); } while(newChild->hasChildNodes()) // Move insertBefore(newChild->getFirstChild(),refChild); } else if (!DOMDocumentImpl::isKidOK(castToNode(this), newChild)) throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, GetDOMParentNodeMemoryManager); else { DOMNode *oldparent=newChild->getParentNode(); if(oldparent!=0) oldparent->removeChild(newChild); // Attach up castToNodeImpl(newChild)->fOwnerNode = castToNode(this); castToNodeImpl(newChild)->isOwned(true); // Attach before and after // Note: fFirstChild.previousSibling == lastChild!! if (fFirstChild == 0) { // this our first and only child fFirstChild = newChild; castToNodeImpl(newChild)->isFirstChild(true); // castToChildImpl(newChild)->previousSibling = newChild; DOMChildNode *newChild_ci = castToChildImpl(newChild); newChild_ci->previousSibling = newChild; } else { if (refChild == 0) { // this is an append DOMNode *lastChild = castToChildImpl(fFirstChild)->previousSibling; castToChildImpl(lastChild)->nextSibling = newChild; castToChildImpl(newChild)->previousSibling = lastChild; castToChildImpl(fFirstChild)->previousSibling = newChild; } else { // this is an insert if (refChild == fFirstChild) { // at the head of the list castToNodeImpl(fFirstChild)->isFirstChild(false); castToChildImpl(newChild)->nextSibling = fFirstChild; castToChildImpl(newChild)->previousSibling = castToChildImpl(fFirstChild)->previousSibling; castToChildImpl(fFirstChild)->previousSibling = newChild; fFirstChild = newChild; castToNodeImpl(newChild)->isFirstChild(true); } else { // somewhere in the middle DOMNode *prev = castToChildImpl(refChild)->previousSibling; castToChildImpl(newChild)->nextSibling = refChild; castToChildImpl(prev)->nextSibling = newChild; castToChildImpl(refChild)->previousSibling = newChild; castToChildImpl(newChild)->previousSibling = prev; } } } } changed(); if (this->getOwnerDocument() != 0) { Ranges* ranges = ((DOMDocumentImpl *)this->getOwnerDocument())->getRanges(); if ( ranges != 0) { XMLSize_t sz = ranges->size(); if (sz != 0) { for (XMLSize_t i =0; i<sz; i++) { ranges->elementAt(i)->updateRangeForInsertedNode(newChild); } } } } return newChild; }
DOMNode *XPathDocumentImpl::insertBefore(DOMNode *newChild, DOMNode *refChild) { // if the newChild is a documenttype node created from domimplementation, set the ownerDoc first if ((newChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE) && !newChild->getOwnerDocument()) ((DOMDocumentTypeImpl*)newChild)->setOwnerDocument(this); if(newChild==NULL) throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0, getMemoryManager()); DOMNodeImpl *thisNodeImpl = castToNodeImpl(this); if (thisNodeImpl->isReadOnly()) throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, getMemoryManager()); DOMNode* thisNode = castToNode(&fParent); if (newChild->getOwnerDocument() != thisNode) throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0, getMemoryManager()); // refChild must in fact be a child of this node (or 0) if (refChild!=0 && refChild->getParentNode() != thisNode) throw DOMException(DOMException::NOT_FOUND_ERR,0, getMemoryManager()); // if the new node has to be placed before itself, we don't have to do anything // (even worse, we would crash if we continue, as we assume they are two distinct nodes) if (refChild!=0 && newChild->isSameNode(refChild)) return newChild; if (newChild->getNodeType() == DOMNode::DOCUMENT_FRAGMENT_NODE) { // 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. while(newChild->hasChildNodes()) // Move insertBefore(newChild->getFirstChild(),refChild); } else { DOMNode *oldparent=newChild->getParentNode(); if(oldparent!=0) oldparent->removeChild(newChild); // Attach up castToNodeImpl(newChild)->fOwnerNode = thisNode; castToNodeImpl(newChild)->isOwned(true); // Attach before and after // Note: fFirstChild.previousSibling == lastChild!! if (fParent.fFirstChild == 0) { // this our first and only child fParent.fFirstChild = newChild; castToNodeImpl(newChild)->isFirstChild(true); // castToChildImpl(newChild)->previousSibling = newChild; DOMChildNode *newChild_ci = castToChildImpl(newChild); newChild_ci->previousSibling = newChild; } else { if (refChild == 0) { // this is an append DOMNode *lastChild = castToChildImpl(fParent.fFirstChild)->previousSibling; castToChildImpl(lastChild)->nextSibling = newChild; castToChildImpl(newChild)->previousSibling = lastChild; castToChildImpl(fParent.fFirstChild)->previousSibling = newChild; } else { // this is an insert if (refChild == fParent.fFirstChild) { // at the head of the list castToNodeImpl(fParent.fFirstChild)->isFirstChild(false); castToChildImpl(newChild)->nextSibling = fParent.fFirstChild; castToChildImpl(newChild)->previousSibling = castToChildImpl(fParent.fFirstChild)->previousSibling; castToChildImpl(fParent.fFirstChild)->previousSibling = newChild; fParent.fFirstChild = newChild; castToNodeImpl(newChild)->isFirstChild(true); } else { // somewhere in the middle DOMNode *prev = castToChildImpl(refChild)->previousSibling; castToChildImpl(newChild)->nextSibling = refChild; castToChildImpl(prev)->nextSibling = newChild; castToChildImpl(refChild)->previousSibling = newChild; castToChildImpl(newChild)->previousSibling = prev; } } } } changed(); Ranges* ranges = getRanges(); if ( ranges != 0) { XMLSize_t sz = ranges->size(); if (sz != 0) { for (XMLSize_t i =0; i<sz; i++) { ranges->elementAt(i)->updateRangeForInsertedNode(newChild); } } } // If insert succeeded, cache the kid appropriately if(newChild->getNodeType() == DOMNode::ELEMENT_NODE) fMyDocElement=(DOMElement *)newChild; else if(newChild->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE) fMyDocType=(DOMDocumentType *)newChild; return newChild; }