2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
24 #include "core/dom/ContainerNode.h"
26 #include "bindings/core/v8/ExceptionState.h"
27 #include "core/dom/ChildFrameDisconnector.h"
28 #include "core/dom/ChildListMutationScope.h"
29 #include "core/dom/ClassCollection.h"
30 #include "core/dom/ElementTraversal.h"
31 #include "core/dom/ExceptionCode.h"
32 #include "core/dom/NameNodeList.h"
33 #include "core/dom/NodeChildRemovalTracker.h"
34 #include "core/dom/NodeRareData.h"
35 #include "core/dom/NodeRenderStyle.h"
36 #include "core/dom/NodeTraversal.h"
37 #include "core/dom/SelectorQuery.h"
38 #include "core/dom/StaticNodeList.h"
39 #include "core/dom/StyleEngine.h"
40 #include "core/dom/shadow/ElementShadow.h"
41 #include "core/dom/shadow/ShadowRoot.h"
42 #include "core/events/MutationEvent.h"
43 #include "core/html/HTMLCollection.h"
44 #include "core/html/HTMLFrameOwnerElement.h"
45 #include "core/html/HTMLTagCollection.h"
46 #include "core/html/RadioNodeList.h"
47 #include "core/inspector/InspectorInstrumentation.h"
48 #include "core/rendering/InlineTextBox.h"
49 #include "core/rendering/RenderText.h"
50 #include "core/rendering/RenderTheme.h"
51 #include "core/rendering/RenderView.h"
52 #include "platform/EventDispatchForbiddenScope.h"
53 #include "platform/ScriptForbiddenScope.h"
57 using namespace HTMLNames;
59 static void dispatchChildInsertionEvents(Node&);
60 static void dispatchChildRemovalEvents(Node&);
63 unsigned EventDispatchForbiddenScope::s_count = 0;
66 static void collectChildrenAndRemoveFromOldParent(Node& node, NodeVector& nodes, ExceptionState& exceptionState)
68 if (node.isDocumentFragment()) {
69 DocumentFragment& fragment = toDocumentFragment(node);
70 getChildNodes(fragment, nodes);
71 fragment.removeChildren();
75 if (ContainerNode* oldParent = node.parentNode())
76 oldParent->removeChild(&node, exceptionState);
80 void ContainerNode::removeDetachedChildren()
82 ASSERT(!connectedSubframeCount());
83 ASSERT(needsAttach());
84 removeDetachedChildrenInContainer(*this);
88 void ContainerNode::parserTakeAllChildrenFrom(ContainerNode& oldParent)
90 while (RefPtrWillBeRawPtr<Node> child = oldParent.firstChild()) {
91 oldParent.parserRemoveChild(*child);
92 treeScope().adoptIfNeeded(*child);
93 parserAppendChild(child.get());
97 ContainerNode::~ContainerNode()
99 ASSERT(needsAttach());
101 willBeDeletedFromDocument();
102 removeDetachedChildren();
106 bool ContainerNode::isChildTypeAllowed(const Node& child) const
108 if (!child.isDocumentFragment())
109 return childTypeAllowed(child.nodeType());
111 for (Node* node = toDocumentFragment(child).firstChild(); node; node = node->nextSibling()) {
112 if (!childTypeAllowed(node->nodeType()))
118 bool ContainerNode::containsConsideringHostElements(const Node& newChild) const
120 if (isInShadowTree() || document().isTemplateDocument())
121 return newChild.containsIncludingHostElements(*this);
122 return newChild.contains(this);
125 bool ContainerNode::checkAcceptChild(const Node* newChild, const Node* oldChild, ExceptionState& exceptionState) const
127 // Not mentioned in spec: throw NotFoundError if newChild is null
129 exceptionState.throwDOMException(NotFoundError, "The new child element is null.");
133 // Use common case fast path if possible.
134 if ((newChild->isElementNode() || newChild->isTextNode()) && isElementNode()) {
135 ASSERT(isChildTypeAllowed(*newChild));
136 if (containsConsideringHostElements(*newChild)) {
137 exceptionState.throwDOMException(HierarchyRequestError, "The new child element contains the parent.");
143 // This should never happen, but also protect release builds from tree corruption.
144 ASSERT(!newChild->isPseudoElement());
145 if (newChild->isPseudoElement()) {
146 exceptionState.throwDOMException(HierarchyRequestError, "The new child element is a pseudo-element.");
150 if (containsConsideringHostElements(*newChild)) {
151 exceptionState.throwDOMException(HierarchyRequestError, "The new child element contains the parent.");
155 if (oldChild && isDocumentNode()) {
156 if (!toDocument(this)->canReplaceChild(*newChild, *oldChild)) {
157 // FIXME: Adjust 'Document::canReplaceChild' to return some additional detail (or an error message).
158 exceptionState.throwDOMException(HierarchyRequestError, "Failed to replace child.");
161 } else if (!isChildTypeAllowed(*newChild)) {
162 exceptionState.throwDOMException(HierarchyRequestError, "Nodes of type '" + newChild->nodeName() + "' may not be inserted inside nodes of type '" + nodeName() + "'.");
169 bool ContainerNode::checkAcceptChildGuaranteedNodeTypes(const Node& newChild, ExceptionState& exceptionState) const
171 ASSERT(isChildTypeAllowed(newChild));
172 if (newChild.contains(this)) {
173 exceptionState.throwDOMException(HierarchyRequestError, "The new child element contains the parent.");
179 PassRefPtrWillBeRawPtr<Node> ContainerNode::insertBefore(PassRefPtrWillBeRawPtr<Node> newChild, Node* refChild, ExceptionState& exceptionState)
182 // Check that this node is not "floating".
183 // If it is, it can be deleted as a side effect of sending mutation events.
184 ASSERT(refCount() || parentOrShadowHostNode());
187 RefPtrWillBeRawPtr<Node> protect(this);
189 // insertBefore(node, 0) is equivalent to appendChild(node)
191 return appendChild(newChild, exceptionState);
194 // Make sure adding the new child is OK.
195 if (!checkAcceptChild(newChild.get(), 0, exceptionState)) {
196 if (exceptionState.hadException())
202 // NotFoundError: Raised if refChild is not a child of this node
203 if (refChild->parentNode() != this) {
204 exceptionState.throwDOMException(NotFoundError, "The node before which the new node is to be inserted is not a child of this node.");
209 if (refChild->previousSibling() == newChild || refChild == newChild)
212 RefPtrWillBeRawPtr<Node> next = refChild;
215 collectChildrenAndRemoveFromOldParent(*newChild, targets, exceptionState);
216 if (exceptionState.hadException())
218 if (targets.isEmpty())
221 // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events.
222 if (!checkAcceptChildGuaranteedNodeTypes(*newChild, exceptionState)) {
223 if (exceptionState.hadException())
228 InspectorInstrumentation::willInsertDOMNode(this);
230 ChildListMutationScope mutation(*this);
231 for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) {
235 // Due to arbitrary code running in response to a DOM mutation event it's
236 // possible that "next" is no longer a child of "this".
237 // It's also possible that "child" has been inserted elsewhere.
238 // In either of those cases, we'll just stop.
239 if (next->parentNode() != this)
241 if (child.parentNode())
244 treeScope().adoptIfNeeded(child);
246 insertBeforeCommon(*next, child);
248 updateTreeAfterInsertion(child);
251 dispatchSubtreeModifiedEvent();
256 void ContainerNode::insertBeforeCommon(Node& nextChild, Node& newChild)
258 EventDispatchForbiddenScope assertNoEventDispatch;
259 ScriptForbiddenScope forbidScript;
261 ASSERT(!newChild.parentNode()); // Use insertBefore if you need to handle reparenting (and want DOM mutation events).
262 ASSERT(!newChild.nextSibling());
263 ASSERT(!newChild.previousSibling());
264 ASSERT(!newChild.isShadowRoot());
266 Node* prev = nextChild.previousSibling();
267 ASSERT(m_lastChild != prev);
268 nextChild.setPreviousSibling(&newChild);
270 ASSERT(firstChild() != nextChild);
271 ASSERT(prev->nextSibling() == nextChild);
272 prev->setNextSibling(&newChild);
274 ASSERT(firstChild() == nextChild);
275 m_firstChild = &newChild;
277 newChild.setParentOrShadowHostNode(this);
278 newChild.setPreviousSibling(prev);
279 newChild.setNextSibling(&nextChild);
282 void ContainerNode::appendChildCommon(Node& child)
284 child.setParentOrShadowHostNode(this);
287 child.setPreviousSibling(m_lastChild);
288 m_lastChild->setNextSibling(&child);
290 setFirstChild(&child);
293 setLastChild(&child);
296 void ContainerNode::parserInsertBefore(PassRefPtrWillBeRawPtr<Node> newChild, Node& nextChild)
299 ASSERT(nextChild.parentNode() == this);
300 ASSERT(!newChild->isDocumentFragment());
301 ASSERT(!isHTMLTemplateElement(this));
303 if (nextChild.previousSibling() == newChild || &nextChild == newChild) // nothing to do
306 RefPtrWillBeRawPtr<Node> protect(this);
308 if (document() != newChild->document())
309 document().adoptNode(newChild.get(), ASSERT_NO_EXCEPTION);
311 insertBeforeCommon(nextChild, *newChild);
313 newChild->updateAncestorConnectedSubframeCountForInsertion();
315 ChildListMutationScope(*this).childAdded(*newChild);
317 notifyNodeInserted(*newChild, ChildrenChangeSourceParser);
320 PassRefPtrWillBeRawPtr<Node> ContainerNode::replaceChild(PassRefPtrWillBeRawPtr<Node> newChild, PassRefPtrWillBeRawPtr<Node> oldChild, ExceptionState& exceptionState)
323 // Check that this node is not "floating".
324 // If it is, it can be deleted as a side effect of sending mutation events.
325 ASSERT(refCount() || parentOrShadowHostNode());
328 RefPtrWillBeRawPtr<Node> protect(this);
330 if (oldChild == newChild) // nothing to do
334 exceptionState.throwDOMException(NotFoundError, "The node to be replaced is null.");
338 RefPtrWillBeRawPtr<Node> child = oldChild;
340 // Make sure replacing the old child with the new is ok
341 if (!checkAcceptChild(newChild.get(), child.get(), exceptionState)) {
342 if (exceptionState.hadException())
347 // NotFoundError: Raised if oldChild is not a child of this node.
348 if (child->parentNode() != this) {
349 exceptionState.throwDOMException(NotFoundError, "The node to be replaced is not a child of this node.");
353 ChildListMutationScope mutation(*this);
355 RefPtrWillBeRawPtr<Node> next = child->nextSibling();
357 // Remove the node we're replacing
358 removeChild(child, exceptionState);
359 if (exceptionState.hadException())
362 if (next && (next->previousSibling() == newChild || next == newChild)) // nothing to do
365 // Does this one more time because removeChild() fires a MutationEvent.
366 if (!checkAcceptChild(newChild.get(), child.get(), exceptionState)) {
367 if (exceptionState.hadException())
373 collectChildrenAndRemoveFromOldParent(*newChild, targets, exceptionState);
374 if (exceptionState.hadException())
377 // Does this yet another check because collectChildrenAndRemoveFromOldParent() fires a MutationEvent.
378 if (!checkAcceptChild(newChild.get(), child.get(), exceptionState)) {
379 if (exceptionState.hadException())
384 InspectorInstrumentation::willInsertDOMNode(this);
386 // Add the new child(ren)
387 for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) {
391 // Due to arbitrary code running in response to a DOM mutation event it's
392 // possible that "next" is no longer a child of "this".
393 // It's also possible that "child" has been inserted elsewhere.
394 // In either of those cases, we'll just stop.
395 if (next && next->parentNode() != this)
397 if (child.parentNode())
400 treeScope().adoptIfNeeded(child);
402 // Add child before "next".
404 EventDispatchForbiddenScope assertNoEventDispatch;
406 insertBeforeCommon(*next, child);
408 appendChildCommon(child);
411 updateTreeAfterInsertion(child);
414 dispatchSubtreeModifiedEvent();
418 void ContainerNode::willRemoveChild(Node& child)
420 ASSERT(child.parentNode() == this);
421 ChildListMutationScope(*this).willRemoveChild(child);
422 child.notifyMutationObserversNodeWillDetach();
423 dispatchChildRemovalEvents(child);
424 document().nodeWillBeRemoved(child); // e.g. mutation event listener can create a new range.
425 ChildFrameDisconnector(child).disconnect();
428 void ContainerNode::willRemoveChildren()
431 getChildNodes(*this, children);
433 ChildListMutationScope mutation(*this);
434 for (NodeVector::const_iterator it = children.begin(); it != children.end(); ++it) {
437 mutation.willRemoveChild(child);
438 child.notifyMutationObserversNodeWillDetach();
439 dispatchChildRemovalEvents(child);
442 ChildFrameDisconnector(*this).disconnect(ChildFrameDisconnector::DescendantsOnly);
446 void ContainerNode::removeDetachedChildrenInContainer(ContainerNode& container)
448 // List of nodes to be deleted.
452 addChildNodesToDeletionQueue(head, tail, container);
456 while ((n = head) != 0) {
457 ASSERT_WITH_SECURITY_IMPLICATION(n->m_deletionHasBegun);
459 next = n->nextSibling();
460 n->setNextSibling(0);
466 if (n->hasChildren())
467 addChildNodesToDeletionQueue(head, tail, toContainerNode(*n));
473 void ContainerNode::addChildNodesToDeletionQueue(Node*& head, Node*& tail, ContainerNode& container)
475 // We have to tell all children that their parent has died.
477 for (Node* n = container.firstChild(); n; n = next) {
478 ASSERT_WITH_SECURITY_IMPLICATION(!n->m_deletionHasBegun);
480 next = n->nextSibling();
481 n->setNextSibling(0);
482 n->setParentOrShadowHostNode(0);
483 container.setFirstChild(next);
485 next->setPreviousSibling(0);
487 if (!n->refCount()) {
488 #if ENABLE(SECURITY_ASSERT)
489 n->m_deletionHasBegun = true;
491 // Add the node to the list of nodes to be deleted.
492 // Reuse the nextSibling pointer for this purpose.
494 tail->setNextSibling(n);
500 RefPtrWillBeRawPtr<Node> protect(n); // removedFromDocument may remove all references to this node.
501 container.document().adoptIfNeeded(*n);
503 container.notifyNodeRemoved(*n);
507 container.setLastChild(0);
511 void ContainerNode::disconnectDescendantFrames()
513 ChildFrameDisconnector(*this).disconnect();
516 void ContainerNode::trace(Visitor* visitor)
518 visitor->trace(m_firstChild);
519 visitor->trace(m_lastChild);
520 Node::trace(visitor);
523 PassRefPtrWillBeRawPtr<Node> ContainerNode::removeChild(PassRefPtrWillBeRawPtr<Node> oldChild, ExceptionState& exceptionState)
526 // Check that this node is not "floating".
527 // If it is, it can be deleted as a side effect of sending mutation events.
528 ASSERT(refCount() || parentOrShadowHostNode());
531 RefPtrWillBeRawPtr<Node> protect(this);
533 // NotFoundError: Raised if oldChild is not a child of this node.
534 // FIXME: We should never really get PseudoElements in here, but editing will sometimes
535 // attempt to remove them still. We should fix that and enable this ASSERT.
536 // ASSERT(!oldChild->isPseudoElement())
537 if (!oldChild || oldChild->parentNode() != this || oldChild->isPseudoElement()) {
538 exceptionState.throwDOMException(NotFoundError, "The node to be removed is not a child of this node.");
542 RefPtrWillBeRawPtr<Node> child = oldChild;
544 document().removeFocusedElementOfSubtree(child.get());
546 // Events fired when blurring currently focused node might have moved this
547 // child into a different parent.
548 if (child->parentNode() != this) {
549 exceptionState.throwDOMException(NotFoundError, "The node to be removed is no longer a child of this node. Perhaps it was moved in a 'blur' event handler?");
553 willRemoveChild(*child);
555 // Mutation events might have moved this child into a different parent.
556 if (child->parentNode() != this) {
557 exceptionState.throwDOMException(NotFoundError, "The node to be removed is no longer a child of this node. Perhaps it was moved in response to a mutation?");
562 HTMLFrameOwnerElement::UpdateSuspendScope suspendWidgetHierarchyUpdates;
564 Node* prev = child->previousSibling();
565 Node* next = child->nextSibling();
566 removeBetween(prev, next, *child);
567 notifyNodeRemoved(*child);
568 childrenChanged(ChildrenChange::forRemoval(*child, prev, next, ChildrenChangeSourceAPI));
570 dispatchSubtreeModifiedEvent();
574 void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node& oldChild)
576 EventDispatchForbiddenScope assertNoEventDispatch;
578 ASSERT(oldChild.parentNode() == this);
580 if (!oldChild.needsAttach())
584 nextChild->setPreviousSibling(previousChild);
586 previousChild->setNextSibling(nextChild);
587 if (m_firstChild == &oldChild)
588 m_firstChild = nextChild;
589 if (m_lastChild == &oldChild)
590 m_lastChild = previousChild;
592 oldChild.setPreviousSibling(0);
593 oldChild.setNextSibling(0);
594 oldChild.setParentOrShadowHostNode(0);
596 document().adoptIfNeeded(oldChild);
599 void ContainerNode::parserRemoveChild(Node& oldChild)
601 ASSERT(oldChild.parentNode() == this);
602 ASSERT(!oldChild.isDocumentFragment());
604 Node* prev = oldChild.previousSibling();
605 Node* next = oldChild.nextSibling();
607 oldChild.updateAncestorConnectedSubframeCountForRemoval();
609 ChildListMutationScope(*this).willRemoveChild(oldChild);
610 oldChild.notifyMutationObserversNodeWillDetach();
612 removeBetween(prev, next, oldChild);
614 notifyNodeRemoved(oldChild);
615 childrenChanged(ChildrenChange::forRemoval(oldChild, prev, next, ChildrenChangeSourceParser));
618 // this differs from other remove functions because it forcibly removes all the children,
619 // regardless of read-only status or event exceptions, e.g.
620 void ContainerNode::removeChildren()
625 // The container node can be removed from event handlers.
626 RefPtrWillBeRawPtr<ContainerNode> protect(this);
628 // Do any prep work needed before actually starting to detach
629 // and remove... e.g. stop loading frames, fire unload events.
630 willRemoveChildren();
633 // Removing focus can cause frames to load, either via events (focusout, blur)
634 // or widget updates (e.g., for <embed>).
635 SubframeLoadingDisabler disabler(*this);
637 // Exclude this node when looking for removed focusedElement since only
638 // children will be removed.
639 // This must be later than willRemoveChildren, which might change focus
641 document().removeFocusedElementOfSubtree(this, true);
643 // Removing a node from a selection can cause widget updates.
644 document().nodeChildrenWillBeRemoved(*this);
647 // FIXME: Remove this NodeVector. Right now WebPluginContainerImpl::m_element is a
648 // raw ptr which means the code below can drop the last ref to a plugin element and
649 // then the code in UpdateSuspendScope::performDeferredWidgetTreeOperations will
650 // try to destroy the plugin which will be a use-after-free. We should use a RefPtr
651 // in the WebPluginContainerImpl instead.
652 NodeVector removedChildren;
654 HTMLFrameOwnerElement::UpdateSuspendScope suspendWidgetHierarchyUpdates;
657 EventDispatchForbiddenScope assertNoEventDispatch;
658 ScriptForbiddenScope forbidScript;
660 removedChildren.reserveInitialCapacity(countChildren());
662 while (RefPtrWillBeRawPtr<Node> child = m_firstChild) {
663 removeBetween(0, child->nextSibling(), *child);
664 removedChildren.append(child.get());
665 notifyNodeRemoved(*child);
669 ChildrenChange change = {AllChildrenRemoved, nullptr, nullptr, ChildrenChangeSourceAPI};
670 childrenChanged(change);
673 // We don't fire the DOMSubtreeModified event for Attr Nodes. This matches the behavior
674 // of IE and Firefox. This event is fired synchronously and is a source of trouble for
675 // attributes as the JS callback could alter the attributes and leave us in a bad state.
676 if (!isAttributeNode())
677 dispatchSubtreeModifiedEvent();
680 PassRefPtrWillBeRawPtr<Node> ContainerNode::appendChild(PassRefPtrWillBeRawPtr<Node> newChild, ExceptionState& exceptionState)
682 RefPtrWillBeRawPtr<ContainerNode> protect(this);
685 // Check that this node is not "floating".
686 // If it is, it can be deleted as a side effect of sending mutation events.
687 ASSERT(refCount() || parentOrShadowHostNode());
690 // Make sure adding the new child is ok
691 if (!checkAcceptChild(newChild.get(), 0, exceptionState)) {
692 if (exceptionState.hadException())
698 if (newChild == m_lastChild) // nothing to do
702 collectChildrenAndRemoveFromOldParent(*newChild, targets, exceptionState);
703 if (exceptionState.hadException())
706 if (targets.isEmpty())
709 // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events.
710 if (!checkAcceptChildGuaranteedNodeTypes(*newChild, exceptionState)) {
711 if (exceptionState.hadException())
716 InspectorInstrumentation::willInsertDOMNode(this);
718 // Now actually add the child(ren)
719 ChildListMutationScope mutation(*this);
720 for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) {
724 // If the child has a parent again, just stop what we're doing, because
725 // that means someone is doing something with DOM mutation -- can't re-parent
726 // a child that already has a parent.
727 if (child.parentNode())
731 EventDispatchForbiddenScope assertNoEventDispatch;
732 ScriptForbiddenScope forbidScript;
734 treeScope().adoptIfNeeded(child);
735 appendChildCommon(child);
738 updateTreeAfterInsertion(child);
741 dispatchSubtreeModifiedEvent();
745 void ContainerNode::parserAppendChild(PassRefPtrWillBeRawPtr<Node> newChild)
748 ASSERT(!newChild->parentNode()); // Use appendChild if you need to handle reparenting (and want DOM mutation events).
749 ASSERT(!newChild->isDocumentFragment());
750 ASSERT(!isHTMLTemplateElement(this));
752 RefPtrWillBeRawPtr<Node> protect(this);
754 if (document() != newChild->document())
755 document().adoptNode(newChild.get(), ASSERT_NO_EXCEPTION);
758 EventDispatchForbiddenScope assertNoEventDispatch;
759 ScriptForbiddenScope forbidScript;
761 treeScope().adoptIfNeeded(*newChild);
762 appendChildCommon(*newChild);
763 newChild->updateAncestorConnectedSubframeCountForInsertion();
764 ChildListMutationScope(*this).childAdded(*newChild);
767 notifyNodeInserted(*newChild, ChildrenChangeSourceParser);
770 void ContainerNode::notifyNodeInserted(Node& root, ChildrenChangeSource source)
772 ASSERT(!EventDispatchForbiddenScope::isEventDispatchForbidden());
773 ASSERT(!root.isShadowRoot());
775 InspectorInstrumentation::didInsertDOMNode(&root);
777 RefPtrWillBeRawPtr<Node> protect(this);
778 RefPtrWillBeRawPtr<Node> protectNode(root);
780 NodeVector postInsertionNotificationTargets;
781 notifyNodeInsertedInternal(root, postInsertionNotificationTargets);
783 childrenChanged(ChildrenChange::forInsertion(root, source));
785 for (size_t i = 0; i < postInsertionNotificationTargets.size(); ++i) {
786 Node* targetNode = postInsertionNotificationTargets[i].get();
787 if (targetNode->inDocument())
788 targetNode->didNotifySubtreeInsertionsToDocument();
792 void ContainerNode::notifyNodeInsertedInternal(Node& root, NodeVector& postInsertionNotificationTargets)
794 EventDispatchForbiddenScope assertNoEventDispatch;
795 ScriptForbiddenScope forbidScript;
797 for (Node* node = &root; node; node = NodeTraversal::next(*node, &root)) {
798 // As an optimization we don't notify leaf nodes when when inserting
799 // into detached subtrees.
800 if (!inDocument() && !node->isContainerNode())
802 if (Node::InsertionShouldCallDidNotifySubtreeInsertions == node->insertedInto(this))
803 postInsertionNotificationTargets.append(node);
804 for (ShadowRoot* shadowRoot = node->youngestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->olderShadowRoot())
805 notifyNodeInsertedInternal(*shadowRoot, postInsertionNotificationTargets);
809 void ContainerNode::notifyNodeRemoved(Node& root)
811 ScriptForbiddenScope forbidScript;
812 EventDispatchForbiddenScope assertNoEventDispatch;
814 Document& document = root.document();
815 for (Node* node = &root; node; node = NodeTraversal::next(*node, &root)) {
816 // As an optimization we skip notifying Text nodes and other leaf nodes
817 // of removal when they're not in the Document tree since the virtual
818 // call to removedFrom is not needed.
819 if (!node->inDocument() && !node->isContainerNode())
821 if (document.cssTarget() == node)
822 document.setCSSTarget(nullptr);
823 node->removedFrom(this);
824 for (ShadowRoot* shadowRoot = node->youngestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->olderShadowRoot())
825 notifyNodeRemoved(*shadowRoot);
829 void ContainerNode::attach(const AttachContext& context)
831 attachChildren(context);
832 clearChildNeedsStyleRecalc();
833 Node::attach(context);
836 void ContainerNode::detach(const AttachContext& context)
838 detachChildren(context);
839 clearChildNeedsStyleRecalc();
840 Node::detach(context);
843 void ContainerNode::childrenChanged(const ChildrenChange& change)
845 document().incDOMTreeVersion();
846 if (!change.byParser && change.type != TextChanged)
847 document().updateRangesAfterChildrenChanged(this);
848 invalidateNodeListCachesInAncestors();
849 if (change.isChildInsertion() && !childNeedsStyleRecalc()) {
850 setChildNeedsStyleRecalc();
851 markAncestorsWithChildNeedsStyleRecalc();
855 void ContainerNode::cloneChildNodes(ContainerNode *clone)
857 TrackExceptionState exceptionState;
858 for (Node* n = firstChild(); n && !exceptionState.hadException(); n = n->nextSibling())
859 clone->appendChild(n->cloneNode(true), exceptionState);
863 bool ContainerNode::getUpperLeftCorner(FloatPoint& point) const
867 // What is this code really trying to do?
868 RenderObject* o = renderer();
870 if (!o->isInline() || o->isReplaced()) {
871 point = o->localToAbsolute(FloatPoint(), UseTransforms);
875 // find the next text/image child, to get a position
878 if (RenderObject* oFirstChild = o->slowFirstChild()) {
880 } else if (o->nextSibling()) {
881 o = o->nextSibling();
883 RenderObject* next = 0;
884 while (!next && o->parent()) {
886 next = o->nextSibling();
895 if (!o->isInline() || o->isReplaced()) {
896 point = o->localToAbsolute(FloatPoint(), UseTransforms);
900 if (p->node() && p->node() == this && o->isText() && !o->isBR() && !toRenderText(o)->firstTextBox()) {
901 // do nothing - skip unrendered whitespace that is a child or next sibling of the anchor
902 } else if ((o->isText() && !o->isBR()) || o->isReplaced()) {
903 point = FloatPoint();
904 if (o->isText() && toRenderText(o)->firstTextBox()) {
905 point.move(toRenderText(o)->linesBoundingBox().x(), toRenderText(o)->firstTextBox()->root().lineTop().toFloat());
906 } else if (o->isBox()) {
907 RenderBox* box = toRenderBox(o);
908 point.moveBy(box->location());
910 point = o->container()->localToAbsolute(point, UseTransforms);
915 // If the target doesn't have any children or siblings that could be used to calculate the scroll position, we must be
916 // at the end of the document. Scroll to the bottom. FIXME: who said anything about scrolling?
917 if (!o && document().view()) {
918 point = FloatPoint(0, document().view()->contentsHeight());
924 bool ContainerNode::getLowerRightCorner(FloatPoint& point) const
929 RenderObject* o = renderer();
930 if (!o->isInline() || o->isReplaced()) {
931 RenderBox* box = toRenderBox(o);
932 point = o->localToAbsolute(LayoutPoint(box->size()), UseTransforms);
936 // find the last text/image child, to get a position
938 if (RenderObject* oLastChild = o->slowLastChild()) {
940 } else if (o->previousSibling()) {
941 o = o->previousSibling();
943 RenderObject* prev = 0;
948 prev = o->previousSibling();
953 if (o->isText() || o->isReplaced()) {
954 point = FloatPoint();
956 RenderText* text = toRenderText(o);
957 IntRect linesBox = text->linesBoundingBox();
958 if (!linesBox.maxX() && !linesBox.maxY())
960 point.moveBy(linesBox.maxXMaxYCorner());
962 RenderBox* box = toRenderBox(o);
963 point.moveBy(box->frameRect().maxXMaxYCorner());
965 point = o->container()->localToAbsolute(point, UseTransforms);
972 // FIXME: This override is only needed for inline anchors without an
973 // InlineBox and it does not belong in ContainerNode as it reaches into
974 // the render and line box trees.
975 // https://code.google.com/p/chromium/issues/detail?id=248354
976 LayoutRect ContainerNode::boundingBox() const
978 FloatPoint upperLeft, lowerRight;
979 bool foundUpperLeft = getUpperLeftCorner(upperLeft);
980 bool foundLowerRight = getLowerRightCorner(lowerRight);
982 // If we've found one corner, but not the other,
983 // then we should just return a point at the corner that we did find.
984 if (foundUpperLeft != foundLowerRight) {
986 lowerRight = upperLeft;
988 upperLeft = lowerRight;
991 return enclosingLayoutRect(FloatRect(upperLeft, lowerRight.expandedTo(upperLeft) - upperLeft));
994 // This is used by FrameSelection to denote when the active-state of the page has changed
995 // independent of the focused element changing.
996 void ContainerNode::focusStateChanged()
998 // If we're just changing the window's active state and the focused node has no
999 // renderer we can just ignore the state change.
1003 if (styleChangeType() < SubtreeStyleChange) {
1004 if (renderStyle()->affectedByFocus() && renderStyle()->hasPseudoStyle(FIRST_LETTER))
1005 setNeedsStyleRecalc(SubtreeStyleChange);
1006 else if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByFocus())
1007 document().ensureStyleResolver().ensureUpdatedRuleFeatureSet().scheduleStyleInvalidationForPseudoChange(CSSSelector::PseudoFocus, *toElement(this));
1008 else if (renderStyle()->affectedByFocus())
1009 setNeedsStyleRecalc(LocalStyleChange);
1012 if (renderer() && renderer()->style()->hasAppearance())
1013 RenderTheme::theme().stateChanged(renderer(), FocusControlState);
1016 void ContainerNode::setFocus(bool received)
1018 if (focused() == received)
1021 Node::setFocus(received);
1023 focusStateChanged();
1025 if (renderer() || received)
1028 // If :focus sets display: none, we lose focus but still need to recalc our style.
1029 if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByFocus() && styleChangeType() < SubtreeStyleChange)
1030 document().ensureStyleResolver().ensureUpdatedRuleFeatureSet().scheduleStyleInvalidationForPseudoChange(CSSSelector::PseudoFocus, *toElement(this));
1032 setNeedsStyleRecalc(LocalStyleChange);
1035 void ContainerNode::setActive(bool down)
1037 if (down == active())
1040 Node::setActive(down);
1042 // FIXME: Why does this not need to handle the display: none transition like :hover does?
1044 if (styleChangeType() < SubtreeStyleChange) {
1045 if (renderStyle()->affectedByActive() && renderStyle()->hasPseudoStyle(FIRST_LETTER))
1046 setNeedsStyleRecalc(SubtreeStyleChange);
1047 else if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByActive())
1048 document().ensureStyleResolver().ensureUpdatedRuleFeatureSet().scheduleStyleInvalidationForPseudoChange(CSSSelector::PseudoActive, *toElement(this));
1049 else if (renderStyle()->affectedByActive())
1050 setNeedsStyleRecalc(LocalStyleChange);
1053 if (renderStyle()->hasAppearance())
1054 RenderTheme::theme().stateChanged(renderer(), PressedControlState);
1058 void ContainerNode::setHovered(bool over)
1060 if (over == hovered())
1063 Node::setHovered(over);
1065 // If :hover sets display: none we lose our hover but still need to recalc our style.
1069 if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByHover() && styleChangeType() < SubtreeStyleChange)
1070 document().ensureStyleResolver().ensureUpdatedRuleFeatureSet().scheduleStyleInvalidationForPseudoChange(CSSSelector::PseudoHover, *toElement(this));
1072 setNeedsStyleRecalc(LocalStyleChange);
1076 if (styleChangeType() < SubtreeStyleChange) {
1077 if (renderStyle()->affectedByHover() && renderStyle()->hasPseudoStyle(FIRST_LETTER))
1078 setNeedsStyleRecalc(SubtreeStyleChange);
1079 else if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByHover())
1080 document().ensureStyleResolver().ensureUpdatedRuleFeatureSet().scheduleStyleInvalidationForPseudoChange(CSSSelector::PseudoHover, *toElement(this));
1081 else if (renderStyle()->affectedByHover())
1082 setNeedsStyleRecalc(LocalStyleChange);
1085 if (renderer()->style()->hasAppearance())
1086 RenderTheme::theme().stateChanged(renderer(), HoverControlState);
1089 PassRefPtrWillBeRawPtr<HTMLCollection> ContainerNode::children()
1091 return ensureCachedCollection<HTMLCollection>(NodeChildren);
1094 unsigned ContainerNode::countChildren() const
1098 for (n = firstChild(); n; n = n->nextSibling())
1103 PassRefPtrWillBeRawPtr<Element> ContainerNode::querySelector(const AtomicString& selectors, ExceptionState& exceptionState)
1105 if (selectors.isEmpty()) {
1106 exceptionState.throwDOMException(SyntaxError, "The provided selector is empty.");
1110 SelectorQuery* selectorQuery = document().selectorQueryCache().add(selectors, document(), exceptionState);
1113 return selectorQuery->queryFirst(*this);
1116 PassRefPtrWillBeRawPtr<StaticElementList> ContainerNode::querySelectorAll(const AtomicString& selectors, ExceptionState& exceptionState)
1118 if (selectors.isEmpty()) {
1119 exceptionState.throwDOMException(SyntaxError, "The provided selector is empty.");
1123 SelectorQuery* selectorQuery = document().selectorQueryCache().add(selectors, document(), exceptionState);
1127 return selectorQuery->queryAll(*this);
1130 static void dispatchChildInsertionEvents(Node& child)
1132 if (child.isInShadowTree())
1135 ASSERT(!EventDispatchForbiddenScope::isEventDispatchForbidden());
1137 RefPtrWillBeRawPtr<Node> c(child);
1138 RefPtrWillBeRawPtr<Document> document(child.document());
1140 if (c->parentNode() && document->hasListenerType(Document::DOMNODEINSERTED_LISTENER))
1141 c->dispatchScopedEvent(MutationEvent::create(EventTypeNames::DOMNodeInserted, true, c->parentNode()));
1143 // dispatch the DOMNodeInsertedIntoDocument event to all descendants
1144 if (c->inDocument() && document->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER)) {
1145 for (; c; c = NodeTraversal::next(*c, &child))
1146 c->dispatchScopedEvent(MutationEvent::create(EventTypeNames::DOMNodeInsertedIntoDocument, false));
1150 static void dispatchChildRemovalEvents(Node& child)
1152 if (child.isInShadowTree()) {
1153 InspectorInstrumentation::willRemoveDOMNode(&child);
1157 ASSERT(!EventDispatchForbiddenScope::isEventDispatchForbidden());
1159 InspectorInstrumentation::willRemoveDOMNode(&child);
1161 RefPtrWillBeRawPtr<Node> c(child);
1162 RefPtrWillBeRawPtr<Document> document(child.document());
1164 // dispatch pre-removal mutation events
1165 if (c->parentNode() && document->hasListenerType(Document::DOMNODEREMOVED_LISTENER)) {
1166 NodeChildRemovalTracker scope(child);
1167 c->dispatchScopedEvent(MutationEvent::create(EventTypeNames::DOMNodeRemoved, true, c->parentNode()));
1170 // dispatch the DOMNodeRemovedFromDocument event to all descendants
1171 if (c->inDocument() && document->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER)) {
1172 NodeChildRemovalTracker scope(child);
1173 for (; c; c = NodeTraversal::next(*c, &child))
1174 c->dispatchScopedEvent(MutationEvent::create(EventTypeNames::DOMNodeRemovedFromDocument, false));
1178 void ContainerNode::updateTreeAfterInsertion(Node& child)
1182 ASSERT(child.refCount());
1185 ChildListMutationScope(*this).childAdded(child);
1187 notifyNodeInserted(child);
1189 dispatchChildInsertionEvents(child);
1192 bool ContainerNode::hasRestyleFlagInternal(DynamicRestyleFlags mask) const
1194 return rareData()->hasRestyleFlag(mask);
1197 bool ContainerNode::hasRestyleFlagsInternal() const
1199 return rareData()->hasRestyleFlags();
1202 void ContainerNode::setRestyleFlag(DynamicRestyleFlags mask)
1204 ASSERT(isElementNode() || isShadowRoot());
1205 ensureRareData().setRestyleFlag(mask);
1208 void ContainerNode::recalcChildStyle(StyleRecalcChange change)
1210 ASSERT(document().inStyleRecalc());
1211 ASSERT(change >= UpdatePseudoElements || childNeedsStyleRecalc());
1212 ASSERT(!needsStyleRecalc());
1214 if (change < Force && hasRareData() && childNeedsStyleRecalc())
1215 checkForChildrenAdjacentRuleChanges();
1217 // This loop is deliberately backwards because we use insertBefore in the rendering tree, and want to avoid
1218 // a potentially n^2 loop to find the insertion point while resolving style. Having us start from the last
1219 // child and work our way back means in the common case, we'll find the insertion point in O(1) time.
1220 // See crbug.com/288225
1221 StyleResolver& styleResolver = document().ensureStyleResolver();
1222 Text* lastTextNode = 0;
1223 for (Node* child = lastChild(); child; child = child->previousSibling()) {
1224 if (child->isTextNode()) {
1225 toText(child)->recalcTextStyle(change, lastTextNode);
1226 lastTextNode = toText(child);
1227 } else if (child->isElementNode()) {
1228 Element* element = toElement(child);
1229 if (element->shouldCallRecalcStyle(change))
1230 element->recalcStyle(change, lastTextNode);
1231 else if (element->supportsStyleSharing())
1232 styleResolver.addToStyleSharingList(*element);
1233 if (element->renderer())
1239 void ContainerNode::checkForChildrenAdjacentRuleChanges()
1241 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
1242 bool hasIndirectAdjacentRules = childrenAffectedByIndirectAdjacentRules();
1244 if (!hasDirectAdjacentRules && !hasIndirectAdjacentRules)
1247 unsigned forceCheckOfNextElementCount = 0;
1248 bool forceCheckOfAnyElementSibling = false;
1249 Document& document = this->document();
1251 for (Element* child = ElementTraversal::firstChild(*this); child; child = ElementTraversal::nextSibling(*child)) {
1252 bool childRulesChanged = child->needsStyleRecalc() && child->styleChangeType() >= SubtreeStyleChange;
1254 if (forceCheckOfNextElementCount || forceCheckOfAnyElementSibling)
1255 child->setNeedsStyleRecalc(SubtreeStyleChange);
1257 if (childRulesChanged && hasDirectAdjacentRules)
1258 forceCheckOfNextElementCount = document.styleEngine()->maxDirectAdjacentSelectors();
1259 else if (forceCheckOfNextElementCount)
1260 --forceCheckOfNextElementCount;
1262 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
1266 void ContainerNode::checkForSiblingStyleChanges(SiblingCheckType changeType, Node* nodeBeforeChange, Node* nodeAfterChange)
1268 if (!inActiveDocument() || document().hasPendingForcedStyleRecalc() || styleChangeType() >= SubtreeStyleChange)
1271 if (needsStyleRecalc() && childrenAffectedByPositionalRules())
1274 // Forward positional selectors include nth-child, nth-of-type, first-of-type and only-of-type.
1275 // The indirect adjacent selector is the ~ selector.
1276 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1277 // We have to invalidate everything following the insertion point in the forward and indirect adjacent case,
1278 // and everything before the insertion point in the backward case.
1279 // |afterChange| is 0 in the parser callback case, so we won't do any work for the forward case if we don't have to.
1280 // For performance reasons we just mark the parent node as changed, since we don't want to make childrenChanged O(n^2) by crawling all our kids
1281 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
1282 if (((childrenAffectedByForwardPositionalRules() || childrenAffectedByIndirectAdjacentRules()) && nodeAfterChange)
1283 || (childrenAffectedByBackwardPositionalRules() && nodeBeforeChange)) {
1284 setNeedsStyleRecalc(SubtreeStyleChange);
1288 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1289 // In the DOM case, we only need to do something if |afterChange| is not 0.
1290 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
1291 if (childrenAffectedByFirstChildRules() && nodeAfterChange) {
1292 ASSERT(changeType != FinishedParsingChildren);
1293 // Find our new first child element.
1294 Element* firstChildElement = ElementTraversal::firstChild(*this);
1295 RenderStyle* firstChildElementStyle = firstChildElement ? firstChildElement->renderStyle() : 0;
1297 // Find the first element after the change.
1298 Element* elementAfterChange = nodeAfterChange->isElementNode() ? toElement(nodeAfterChange) : ElementTraversal::nextSibling(*nodeAfterChange);
1299 RenderStyle* elementAfterChangeStyle = elementAfterChange ? elementAfterChange->renderStyle() : 0;
1301 // This is the element insertion as first child element case.
1302 if (firstChildElement != elementAfterChange && elementAfterChangeStyle && elementAfterChangeStyle->firstChildState()) {
1303 ASSERT(changeType == SiblingElementInserted);
1304 elementAfterChange->setNeedsStyleRecalc(SubtreeStyleChange);
1307 // This is the first child element removal case.
1308 if (changeType == SiblingElementRemoved && firstChildElement == elementAfterChange && firstChildElement && (!firstChildElementStyle || !firstChildElementStyle->firstChildState()))
1309 firstChildElement->setNeedsStyleRecalc(SubtreeStyleChange);
1312 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1313 // In the DOM case, we only need to do something if |afterChange| is not 0.
1314 if (childrenAffectedByLastChildRules() && nodeBeforeChange) {
1315 // Find our new last child element.
1316 Element* lastChildElement = ElementTraversal::lastChild(*this);
1317 RenderStyle* lastChildElementStyle = lastChildElement ? lastChildElement->renderStyle() : 0;
1319 // Find the last element before the change.
1320 Element* elementBeforeChange = nodeBeforeChange->isElementNode() ? toElement(nodeBeforeChange) : ElementTraversal::previousSibling(*nodeBeforeChange);
1321 RenderStyle* elementBeforeChangeStyle = elementBeforeChange ? elementBeforeChange->renderStyle() : 0;
1323 // This is the element insertion as last child element case.
1324 if (lastChildElement != elementBeforeChange && elementBeforeChangeStyle && elementBeforeChangeStyle->lastChildState()) {
1325 ASSERT(SiblingElementInserted);
1326 elementBeforeChange->setNeedsStyleRecalc(SubtreeStyleChange);
1329 // This is the last child element removal case. The parser callback case is similar to node removal as well in that we need to change the last child
1331 if ((changeType == SiblingElementRemoved || changeType == FinishedParsingChildren) && lastChildElement == elementBeforeChange && lastChildElement && (!lastChildElementStyle || !lastChildElementStyle->lastChildState()))
1332 lastChildElement->setNeedsStyleRecalc(SubtreeStyleChange);
1335 // The + selector. We need to invalidate the first element following the change. It is the only possible element
1336 // that could be affected by this DOM change.
1337 if (childrenAffectedByDirectAdjacentRules() && nodeAfterChange) {
1338 if (Element* elementAfterChange = nodeAfterChange->isElementNode() ? toElement(nodeAfterChange) : ElementTraversal::nextSibling(*nodeAfterChange))
1339 elementAfterChange->setNeedsStyleRecalc(SubtreeStyleChange);
1343 void ContainerNode::invalidateNodeListCachesInAncestors(const QualifiedName* attrName, Element* attributeOwnerElement)
1345 if (hasRareData() && (!attrName || isAttributeNode())) {
1346 if (NodeListsNodeData* lists = rareData()->nodeLists()) {
1347 if (ChildNodeList* childNodeList = lists->childNodeList(*this))
1348 childNodeList->invalidateCache();
1352 // Modifications to attributes that are not associated with an Element can't invalidate NodeList caches.
1353 if (attrName && !attributeOwnerElement)
1356 if (!document().shouldInvalidateNodeListCaches(attrName))
1359 document().invalidateNodeListCaches(attrName);
1361 for (ContainerNode* node = this; node; node = node->parentNode()) {
1362 if (NodeListsNodeData* lists = node->nodeLists())
1363 lists->invalidateCaches(attrName);
1367 PassRefPtrWillBeRawPtr<TagCollection> ContainerNode::getElementsByTagName(const AtomicString& localName)
1369 if (localName.isNull())
1372 if (document().isHTMLDocument())
1373 return ensureCachedCollection<HTMLTagCollection>(HTMLTagCollectionType, localName);
1374 return ensureCachedCollection<TagCollection>(TagCollectionType, localName);
1377 PassRefPtrWillBeRawPtr<TagCollection> ContainerNode::getElementsByTagNameNS(const AtomicString& namespaceURI, const AtomicString& localName)
1379 if (localName.isNull())
1382 if (namespaceURI == starAtom)
1383 return getElementsByTagName(localName);
1385 return ensureCachedCollection<TagCollection>(TagCollectionType, namespaceURI.isEmpty() ? nullAtom : namespaceURI, localName);
1388 // Takes an AtomicString in argument because it is common for elements to share the same name attribute.
1389 // Therefore, the NameNodeList factory function expects an AtomicString type.
1390 PassRefPtrWillBeRawPtr<NameNodeList> ContainerNode::getElementsByName(const AtomicString& elementName)
1392 return ensureCachedCollection<NameNodeList>(NameNodeListType, elementName);
1395 // Takes an AtomicString in argument because it is common for elements to share the same set of class names.
1396 // Therefore, the ClassNodeList factory function expects an AtomicString type.
1397 PassRefPtrWillBeRawPtr<ClassCollection> ContainerNode::getElementsByClassName(const AtomicString& classNames)
1399 return ensureCachedCollection<ClassCollection>(ClassCollectionType, classNames);
1402 PassRefPtrWillBeRawPtr<RadioNodeList> ContainerNode::radioNodeList(const AtomicString& name, bool onlyMatchImgElements)
1404 ASSERT(isHTMLFormElement(this) || isHTMLFieldSetElement(this));
1405 CollectionType type = onlyMatchImgElements ? RadioImgNodeListType : RadioNodeListType;
1406 return ensureCachedCollection<RadioNodeList>(type, name);
1409 Element* ContainerNode::getElementById(const AtomicString& id) const
1411 if (isInTreeScope()) {
1412 // Fast path if we are in a tree scope: call getElementById() on tree scope
1413 // and check if the matching element is in our subtree.
1414 Element* element = treeScope().getElementById(id);
1417 if (element->isDescendantOf(this))
1421 // Fall back to traversing our subtree. In case of duplicate ids, the first element found will be returned.
1422 for (Element* element = ElementTraversal::firstWithin(*this); element; element = ElementTraversal::next(*element, this)) {
1423 if (element->getIdAttribute() == id)
1429 NodeListsNodeData& ContainerNode::ensureNodeLists()
1431 return ensureRareData().ensureNodeLists();
1435 bool childAttachedAllowedWhenAttachingChildren(ContainerNode* node)
1437 if (node->isShadowRoot())
1440 if (node->isInsertionPoint())
1443 if (node->isElementNode() && toElement(node)->shadow())
1450 } // namespace blink