void ShadowTree::removeAllShadowRoots() { if (!hasShadowRoot()) return; // Dont protect this ref count. Element* shadowHost = host(); while (RefPtr<ShadowRoot> oldRoot = m_shadowRoots.removeHead()) { InspectorInstrumentation::willPopShadowRoot(shadowHost, oldRoot.get()); shadowHost->document()->removeFocusedNodeOfSubtree(oldRoot.get()); if (oldRoot->attached()) oldRoot->detach(); oldRoot->setShadowHost(0); oldRoot->setPrev(0); oldRoot->setNext(0); shadowHost->document()->adoptIfNeeded(oldRoot.get()); ChildNodeRemovalNotifier(shadowHost).notify(oldRoot.get()); } if (shadowHost->attached()) shadowHost->attachChildrenLazily(); }
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; }
void ContainerNode::parserRemoveChild(Node* oldChild) { ASSERT(oldChild); ASSERT(oldChild->parentNode() == this); Node* prev = oldChild->previousSibling(); Node* next = oldChild->nextSibling(); removeBetween(prev, next, oldChild); childrenChanged(true, prev, next, -1); ChildNodeRemovalNotifier(this).notify(oldChild); }
// this differs from other remove functions because it forcibly removes all the children, // regardless of read-only status or event exceptions, e.g. void ContainerNode::removeChildren() { if (!m_firstChild) return; // The container node can be removed from event handlers. RefPtr<ContainerNode> protect(this); // Exclude this node when looking for the focused or full screen Node since // only children will be removed. // FIXME: We should call these inside the loop below. Right now you can focus // a node with mutation events and it'll never get blured. document()->removeFocusedNodeOfSubtree(this, true); document()->removeFullScreenElementOfSubtree(this, true); ChildListMutationScope mutation(this); NodeVector removedChildren; { WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; while (RefPtr<Node> child = m_firstChild) { // Dispatch synchronous events like mutation and unload events. dispatchChildRemovalEvents(child.get()); ChildFrameDisconnector(child.get()).disconnect(); // FIXME: In theory this can fire focus events when the selection // changes, but there's no obvious way to test it. document()->nodeWillBeRemoved(child.get()); // If an event moved the child start over. if (child != m_firstChild) continue; mutation.willRemoveChild(child.get()); child->notifyMutationObserversNodeWillDetach(); removeBetween(0, child->nextSibling(), child.get()); removedChildren.append(child.release()); } // FIXME: We could avoid walking all the children twice by calling // notify inside the loop and childrenChanged after but that would mean // calling childrenChanged in a different order than all other methods. // Figure out if this is safe. childrenChanged(false, 0, 0, -static_cast<int>(removedChildren.size())); for (size_t i = 0; i < removedChildren.size(); ++i) ChildNodeRemovalNotifier(this).notify(removedChildren[i].get()); } dispatchSubtreeModifiedEvent(); }
// this differs from other remove functions because it forcibly removes all the children, // regardless of read-only status or event exceptions, e.g. void ContainerNode::removeChildren() { if (!m_firstChild) return; // The container node can be removed from event handlers. Ref<ContainerNode> protect(*this); // exclude this node when looking for removed focusedNode since only children will be removed document().removeFocusedNodeOfSubtree(this, true); #if ENABLE(FULLSCREEN_API) document().removeFullScreenElementOfSubtree(this, true); #endif // Do any prep work needed before actually starting to detach // and remove... e.g. stop loading frames, fire unload events. willRemoveChildren(*this); NodeVector removedChildren; { WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; { NoEventDispatchAssertion assertNoEventDispatch; removedChildren.reserveInitialCapacity(countChildNodes()); while (RefPtr<Node> n = m_firstChild) { removedChildren.append(*m_firstChild); removeBetween(0, m_firstChild->nextSibling(), *m_firstChild); } } ChildChange change = { AllChildrenRemoved, nullptr, nullptr, ChildChangeSourceAPI }; childrenChanged(change); for (size_t i = 0; i < removedChildren.size(); ++i) ChildNodeRemovalNotifier(*this).notify(removedChildren[i].get()); } if (document().svgExtensions()) { Element* shadowHost = this->shadowHost(); if (!shadowHost || !shadowHost->hasTagName(SVGNames::useTag)) document().accessSVGExtensions()->rebuildElements(); } dispatchSubtreeModifiedEvent(); }
void ElementShadow::removeAllShadowRoots() { // Dont protect this ref count. Element* shadowHost = host(); ASSERT(shadowHost); while (RefPtr<ShadowRoot> oldRoot = m_shadowRoots.head()) { InspectorInstrumentation::willPopShadowRoot(shadowHost, oldRoot.get()); shadowHost->document().removeFocusedElementOfSubtree(oldRoot.get()); m_shadowRoots.removeHead(); oldRoot->setParentOrShadowHostNode(0); oldRoot->setParentTreeScope(&shadowHost->document()); oldRoot->setPrev(0); oldRoot->setNext(0); ChildNodeRemovalNotifier(*shadowHost).notify(*oldRoot); } }
void ContainerNode::parserRemoveChild(Node* oldChild) { ASSERT(oldChild); ASSERT(oldChild->parentNode() == this); ASSERT(!oldChild->isDocumentFragment()); Node* prev = oldChild->previousSibling(); Node* next = oldChild->nextSibling(); oldChild->updateAncestorConnectedSubframeCountForRemoval(); ChildListMutationScope(this).willRemoveChild(oldChild); oldChild->notifyMutationObserversNodeWillDetach(); removeBetween(prev, next, oldChild); childrenChanged(true, prev, next, -1); ChildNodeRemovalNotifier(this).notify(oldChild); }
void ContainerNode::parserRemoveChild(Node& oldChild) { ASSERT(oldChild.parentNode() == this); ASSERT(!oldChild.isDocumentFragment()); Node* prev = oldChild.previousSibling(); Node* next = oldChild.nextSibling(); oldChild.updateAncestorConnectedSubframeCountForRemoval(); ChildListMutationScope(*this).willRemoveChild(oldChild); oldChild.notifyMutationObserversNodeWillDetach(); removeBetween(prev, next, oldChild); notifyChildRemoved(oldChild, prev, next, ChildChangeSourceParser); ChildNodeRemovalNotifier(*this).notify(oldChild); }
void ElementShadow::removeShadowRoot() { // Dont protect this ref count. Element* shadowHost = host(); if (RefPtr<ShadowRoot> oldRoot = m_shadowRoot) { InspectorInstrumentation::willPopShadowRoot(shadowHost, oldRoot.get()); shadowHost->document()->removeFocusedNodeOfSubtree(oldRoot.get()); if (oldRoot->attached()) oldRoot->detach(); m_shadowRoot = 0; oldRoot->setParentOrShadowHostNode(0); oldRoot->setParentTreeScope(shadowHost->document()); ChildNodeRemovalNotifier(shadowHost).notify(oldRoot.get()); } m_distributor.invalidateDistribution(shadowHost); }
// this differs from other remove functions because it forcibly removes all the children, // regardless of read-only status or event exceptions, e.g. void ContainerNode::removeChildren() { if (!m_firstChild) return; // The container node can be removed from event handlers. RefPtr<ContainerNode> protect(this); // exclude this node when looking for removed focusedNode since only children will be removed document().removeFocusedNodeOfSubtree(this, true); #if ENABLE(FULLSCREEN_API) document().removeFullScreenElementOfSubtree(this, true); #endif // Do any prep work needed before actually starting to detach // and remove... e.g. stop loading frames, fire unload events. willRemoveChildren(protect.get()); NodeVector removedChildren; { WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; { NoEventDispatchAssertion assertNoEventDispatch; removedChildren.reserveInitialCapacity(childNodeCount()); while (RefPtr<Node> n = m_firstChild) { removedChildren.append(m_firstChild); removeBetween(0, m_firstChild->nextSibling(), m_firstChild); } } childrenChanged(false, 0, 0, -static_cast<int>(removedChildren.size())); for (size_t i = 0; i < removedChildren.size(); ++i) ChildNodeRemovalNotifier(this).notify(removedChildren[i].get()); } dispatchSubtreeModifiedEvent(); }
// this differs from other remove functions because it forcibly removes all the children, // regardless of read-only status or event exceptions, e.g. void ContainerNode::removeChildren() { if (!m_firstChild) return; // The container node can be removed from event handlers. RefPtr<ContainerNode> protect(this); // exclude this node when looking for removed focusedNode since only children will be removed document()->removeFocusedNodeOfSubtree(this, true); #if ENABLE(FULLSCREEN_API) document()->removeFullScreenElementOfSubtree(this, true); #endif // Do any prep work needed before actually starting to detach // and remove... e.g. stop loading frames, fire unload events. willRemoveChildren(protect.get()); Vector<RefPtr<Node>, 10> removedChildren; { WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; NoEventDispatchAssertion assertNoEventDispatch; removedChildren.reserveInitialCapacity(childNodeCount()); while (RefPtr<Node> n = m_firstChild) { Node* next = n->nextSibling(); // Remove the node from the tree before calling detach or removedFromDocument (4427024, 4129744). // removeChild() does this after calling detach(). There is no explanation for // this discrepancy between removeChild() and its optimized version removeChildren(). n->setPreviousSibling(0); n->setNextSibling(0); n->setParentOrHostNode(0); document()->adoptIfNeeded(n.get()); m_firstChild = next; if (n == m_lastChild) m_lastChild = 0; removedChildren.append(n.release()); } size_t removedChildrenCount = removedChildren.size(); size_t i; // Detach the nodes only after properly removed from the tree because // a. detaching requires a proper DOM tree (for counters and quotes for // example) and during the previous loop the next sibling still points to // the node being removed while the node being removed does not point back // and does not point to the same parent as its next sibling. // b. destroying Renderers of standalone nodes is sometimes faster. for (i = 0; i < removedChildrenCount; ++i) { Node* removedChild = removedChildren[i].get(); if (removedChild->attached()) removedChild->detach(); } childrenChanged(false, 0, 0, -static_cast<int>(removedChildrenCount)); for (i = 0; i < removedChildrenCount; ++i) ChildNodeRemovalNotifier(this).notify(removedChildren[i].get()); } dispatchSubtreeModifiedEvent(); }
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; }