bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec) { // Check that this node is not "floating". // If it is, it can be deleted as a side effect of sending mutation events. ASSERT(refCount() || parentOrShadowHostNode()); RefPtr<Node> protect(this); ec = 0; // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. if (isReadOnlyNode()) { ec = NO_MODIFICATION_ALLOWED_ERR; return false; } // NOT_FOUND_ERR: Raised if oldChild is not a child of this node. if (!oldChild || oldChild->parentNode() != this) { ec = NOT_FOUND_ERR; return false; } RefPtr<Node> child = oldChild; document().removeFocusedNodeOfSubtree(child.get()); #if ENABLE(FULLSCREEN_API) document().removeFullScreenElementOfSubtree(child.get()); #endif // Events fired when blurring currently focused node might have moved this // child into a different parent. if (child->parentNode() != this) { ec = NOT_FOUND_ERR; return false; } willRemoveChild(child.get()); // Mutation events might have moved this child into a different parent. if (child->parentNode() != this) { ec = NOT_FOUND_ERR; return false; } { WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; Node* prev = child->previousSibling(); Node* next = child->nextSibling(); removeBetween(prev, next, child.get()); childrenChanged(false, prev, next, -1); ChildNodeRemovalNotifier(this).notify(child.get()); } dispatchSubtreeModifiedEvent(); return child; }
bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, AttachBehavior attachBehavior) { RefPtr<ContainerNode> protect(this); // Check that this node is not "floating". // If it is, it can be deleted as a side effect of sending mutation events. ASSERT(refCount() || parentOrShadowHostNode()); ec = 0; // Make sure adding the new child is ok if (!checkAddChild(this, newChild.get(), ec)) return false; if (newChild == m_lastChild) // nothing to do return newChild; NodeVector targets; collectChildrenAndRemoveFromOldParent(newChild.get(), targets, ec); if (ec) return false; if (targets.isEmpty()) return true; // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events. if (!checkAcceptChildGuaranteedNodeTypes(this, newChild.get(), ec)) return false; InspectorInstrumentation::willInsertDOMNode(document(), this); // Now actually add the child(ren) ChildListMutationScope mutation(this); for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) { Node* child = it->get(); // If the child has a parent again, just stop what we're doing, because // that means someone is doing something with DOM mutation -- can't re-parent // a child that already has a parent. if (child->parentNode()) break; treeScope()->adoptIfNeeded(child); // Append child to the end of the list { NoEventDispatchAssertion assertNoEventDispatch; appendChildToContainer(child, this); } updateTreeAfterInsertion(this, child, attachBehavior); } dispatchSubtreeModifiedEvent(); return true; }
SVGSVGElement* SVGElement::ownerSVGElement() const { ContainerNode* n = parentOrShadowHostNode(); while (n) { if (isSVGSVGElement(*n)) return toSVGSVGElement(n); n = n->parentOrShadowHostNode(); } return nullptr; }
SVGSVGElement* SVGElement::ownerSVGElement() const { ContainerNode* n = parentOrShadowHostNode(); while (n) { if (n->hasTagName(SVGNames::svgTag)) return toSVGSVGElement(n); n = n->parentOrShadowHostNode(); } return 0; }
SVGElement* SVGElement::viewportElement() const { // This function needs shadow tree support - as LayoutSVGContainer uses this function // to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise. ContainerNode* n = parentOrShadowHostNode(); while (n) { if (isSVGSVGElement(*n) || isSVGImageElement(*n) || isSVGSymbolElement(*n)) return toSVGElement(n); n = n->parentOrShadowHostNode(); } return nullptr; }
SVGElement* SVGElement::viewportElement() const { // This function needs shadow tree support - as RenderSVGContainer uses this function // to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise. ContainerNode* n = parentOrShadowHostNode(); while (n) { if (n->hasTagName(SVGNames::svgTag) || isSVGImageElement(n) || n->hasTagName(SVGNames::symbolTag)) return toSVGElement(n); n = n->parentOrShadowHostNode(); } return 0; }
// With PseudoElements the DOM tree and Layout tree can differ. When you attach // a, first-letter for example, into the DOM we walk down the Layout // tree to find the correct insertion point for the LayoutObject. But, this // means if we ask for the parentOrShadowHost Node from the first-letter // pseudo element we will get some arbitrary ancestor of the LayoutObject. // // For hit testing, we need the parent Node of the LayoutObject for the // first-letter pseudo element. So, by walking up the Layout tree we know // we will get the parent and not some other ancestor. Node* PseudoElement::findAssociatedNode() const { // The ::backdrop element is parented to the LayoutView, not to the node // that it's associated with. We need to make sure ::backdrop sends the // events to the parent node correctly. if (pseudoId() == BACKDROP) return parentOrShadowHostNode(); ASSERT(layoutObject()); ASSERT(layoutObject()->parent()); // We can have any number of anonymous layout objects inserted between // us and our parent so make sure we skip over them. LayoutObject* ancestor = layoutObject()->parent(); while (ancestor->isAnonymous() || (ancestor->node() && ancestor->node()->isPseudoElement())) { ASSERT(ancestor->parent()); ancestor = ancestor->parent(); } return ancestor->node(); }
bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec, AttachBehavior attachBehavior) { // Check that this node is not "floating". // If it is, it can be deleted as a side effect of sending mutation events. ASSERT(refCount() || parentOrShadowHostNode()); RefPtr<Node> protect(this); ec = 0; if (oldChild == newChild) // nothing to do return true; if (!oldChild) { ec = NOT_FOUND_ERR; return false; } // Make sure replacing the old child with the new is ok if (!checkReplaceChild(this, newChild.get(), oldChild, ec)) return false; // NOT_FOUND_ERR: Raised if oldChild is not a child of this node. if (oldChild->parentNode() != this) { ec = NOT_FOUND_ERR; return false; } ChildListMutationScope mutation(this); RefPtr<Node> next = oldChild->nextSibling(); // Remove the node we're replacing RefPtr<Node> removedChild = oldChild; removeChild(oldChild, ec); if (ec) return false; if (next && (next->previousSibling() == newChild || next == newChild)) // nothing to do return true; // Does this one more time because removeChild() fires a MutationEvent. if (!checkReplaceChild(this, newChild.get(), oldChild, ec)) return false; NodeVector targets; collectChildrenAndRemoveFromOldParent(newChild.get(), targets, ec); if (ec) return false; // Does this yet another check because collectChildrenAndRemoveFromOldParent() fires a MutationEvent. if (!checkReplaceChild(this, newChild.get(), oldChild, ec)) return false; InspectorInstrumentation::willInsertDOMNode(document(), this); // Add the new child(ren) for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) { Node* child = it->get(); // Due to arbitrary code running in response to a DOM mutation event it's // possible that "next" is no longer a child of "this". // It's also possible that "child" has been inserted elsewhere. // In either of those cases, we'll just stop. if (next && next->parentNode() != this) break; if (child->parentNode()) break; treeScope()->adoptIfNeeded(child); // Add child before "next". { NoEventDispatchAssertion assertNoEventDispatch; if (next) insertBeforeCommon(next.get(), child); else appendChildToContainer(child, this); } updateTreeAfterInsertion(this, child, attachBehavior); } dispatchSubtreeModifiedEvent(); return true; }
bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec, AttachBehavior attachBehavior) { // Check that this node is not "floating". // If it is, it can be deleted as a side effect of sending mutation events. ASSERT(refCount() || parentOrShadowHostNode()); RefPtr<Node> protect(this); ec = 0; // insertBefore(node, 0) is equivalent to appendChild(node) if (!refChild) return appendChild(newChild, ec, attachBehavior); // Make sure adding the new child is OK. if (!checkAddChild(this, newChild.get(), ec)) return false; // NOT_FOUND_ERR: Raised if refChild is not a child of this node if (refChild->parentNode() != this) { ec = NOT_FOUND_ERR; return false; } if (refChild->previousSibling() == newChild || refChild == newChild) // nothing to do return true; RefPtr<Node> next = refChild; NodeVector targets; collectChildrenAndRemoveFromOldParent(newChild.get(), targets, ec); if (ec) return false; if (targets.isEmpty()) return true; // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events. if (!checkAcceptChildGuaranteedNodeTypes(this, newChild.get(), ec)) return false; InspectorInstrumentation::willInsertDOMNode(document(), this); ChildListMutationScope mutation(this); for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) { Node* child = it->get(); // Due to arbitrary code running in response to a DOM mutation event it's // possible that "next" is no longer a child of "this". // It's also possible that "child" has been inserted elsewhere. // In either of those cases, we'll just stop. if (next->parentNode() != this) break; if (child->parentNode()) break; treeScope()->adoptIfNeeded(child); insertBeforeCommon(next.get(), child); updateTreeAfterInsertion(this, child, attachBehavior); } dispatchSubtreeModifiedEvent(); return true; }
bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec) { // Check that this node is not "floating". // If it is, it can be deleted as a side effect of sending mutation events. ASSERT(refCount() || parentOrShadowHostNode()); Ref<ContainerNode> protect(*this); ec = 0; // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. if (isReadOnlyNode()) { ec = NO_MODIFICATION_ALLOWED_ERR; return false; } // NOT_FOUND_ERR: Raised if oldChild is not a child of this node. if (!oldChild || oldChild->parentNode() != this) { ec = NOT_FOUND_ERR; return false; } Ref<Node> child(*oldChild); document().removeFocusedNodeOfSubtree(&child.get()); #if ENABLE(FULLSCREEN_API) document().removeFullScreenElementOfSubtree(&child.get()); #endif // Events fired when blurring currently focused node might have moved this // child into a different parent. if (child->parentNode() != this) { ec = NOT_FOUND_ERR; return false; } willRemoveChild(child.get()); // Mutation events might have moved this child into a different parent. if (child->parentNode() != this) { ec = NOT_FOUND_ERR; return false; } { WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; Node* prev = child->previousSibling(); Node* next = child->nextSibling(); removeBetween(prev, next, child.get()); notifyChildRemoved(child.get(), prev, next, ChildChangeSourceAPI); ChildNodeRemovalNotifier(*this).notify(child.get()); } if (document().svgExtensions()) { Element* shadowHost = this->shadowHost(); if (!shadowHost || !shadowHost->hasTagName(SVGNames::useTag)) document().accessSVGExtensions()->rebuildElements(); } dispatchSubtreeModifiedEvent(); return true; }