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, 2010, 2011 Apple Inc. All rights reserved.
6 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
7 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
26 #include "core/dom/Node.h"
28 #include "bindings/core/v8/DOMDataStore.h"
29 #include "bindings/core/v8/ExceptionState.h"
30 #include "bindings/core/v8/V8DOMWrapper.h"
31 #include "core/HTMLNames.h"
32 #include "core/css/resolver/StyleResolver.h"
33 #include "core/dom/AXObjectCache.h"
34 #include "core/dom/Attr.h"
35 #include "core/dom/Attribute.h"
36 #include "core/dom/ChildListMutationScope.h"
37 #include "core/dom/ChildNodeList.h"
38 #include "core/dom/DOMNodeIds.h"
39 #include "core/dom/Document.h"
40 #include "core/dom/DocumentFragment.h"
41 #include "core/dom/DocumentType.h"
42 #include "core/dom/Element.h"
43 #include "core/dom/ElementRareData.h"
44 #include "core/dom/ElementTraversal.h"
45 #include "core/dom/ExceptionCode.h"
46 #include "core/dom/LayoutTreeBuilderTraversal.h"
47 #include "core/dom/NodeRareData.h"
48 #include "core/dom/NodeTraversal.h"
49 #include "core/dom/ProcessingInstruction.h"
50 #include "core/dom/Range.h"
51 #include "core/dom/StaticNodeList.h"
52 #include "core/dom/StyleEngine.h"
53 #include "core/dom/TemplateContentDocumentFragment.h"
54 #include "core/dom/Text.h"
55 #include "core/dom/TreeScopeAdopter.h"
56 #include "core/dom/UserActionElementSet.h"
57 #include "core/dom/shadow/ComposedTreeTraversal.h"
58 #include "core/dom/shadow/ElementShadow.h"
59 #include "core/dom/shadow/InsertionPoint.h"
60 #include "core/dom/shadow/ShadowRoot.h"
61 #include "core/editing/EditingUtilities.h"
62 #include "core/editing/markers/DocumentMarkerController.h"
63 #include "core/events/Event.h"
64 #include "core/events/EventDispatchMediator.h"
65 #include "core/events/EventDispatcher.h"
66 #include "core/events/EventListener.h"
67 #include "core/events/GestureEvent.h"
68 #include "core/events/KeyboardEvent.h"
69 #include "core/events/MouseEvent.h"
70 #include "core/events/MutationEvent.h"
71 #include "core/events/PointerEvent.h"
72 #include "core/events/TextEvent.h"
73 #include "core/events/TouchEvent.h"
74 #include "core/events/UIEvent.h"
75 #include "core/events/WheelEvent.h"
76 #include "core/frame/EventHandlerRegistry.h"
77 #include "core/frame/LocalDOMWindow.h"
78 #include "core/frame/LocalFrame.h"
79 #include "core/html/HTMLDialogElement.h"
80 #include "core/html/HTMLFrameOwnerElement.h"
81 #include "core/input/EventHandler.h"
82 #include "core/layout/LayoutBox.h"
83 #include "core/page/ContextMenuController.h"
84 #include "core/page/Page.h"
85 #include "core/svg/graphics/SVGImage.h"
86 #include "platform/EventDispatchForbiddenScope.h"
87 #include "platform/TraceEvent.h"
88 #include "platform/TracedValue.h"
89 #include "wtf/HashSet.h"
90 #include "wtf/Partitions.h"
91 #include "wtf/PassOwnPtr.h"
92 #include "wtf/Vector.h"
93 #include "wtf/text/CString.h"
94 #include "wtf/text/StringBuilder.h"
98 using namespace HTMLNames
;
100 struct SameSizeAsNode
: NODE_BASE_CLASSES
{
101 uint32_t m_nodeFlags
;
105 static_assert(sizeof(Node
) <= sizeof(SameSizeAsNode
), "Node should stay small");
108 void* Node::operator new(size_t size
)
110 ASSERT(isMainThread());
111 return partitionAlloc(WTF::Partitions::nodePartition(), size
);
114 void Node::operator delete(void* ptr
)
116 ASSERT(isMainThread());
121 #if DUMP_NODE_STATISTICS
122 using WeakNodeSet
= WillBeHeapHashSet
<RawPtrWillBeWeakMember
<Node
>>;
123 static WeakNodeSet
& liveNodeSet()
125 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent
<WeakNodeSet
>, set
, (adoptPtrWillBeNoop(new WeakNodeSet())));
130 void Node::dumpStatistics()
132 #if DUMP_NODE_STATISTICS
133 size_t nodesWithRareData
= 0;
135 size_t elementNodes
= 0;
136 size_t attrNodes
= 0;
137 size_t textNodes
= 0;
138 size_t cdataNodes
= 0;
139 size_t commentNodes
= 0;
141 size_t documentNodes
= 0;
142 size_t docTypeNodes
= 0;
143 size_t fragmentNodes
= 0;
144 size_t shadowRootNodes
= 0;
146 HashMap
<String
, size_t> perTagCount
;
148 size_t attributes
= 0;
149 size_t elementsWithAttributeStorage
= 0;
150 size_t elementsWithRareData
= 0;
151 size_t elementsWithNamedNodeMap
= 0;
153 for (Node
* node
: liveNodeSet()) {
154 if (node
->hasRareData()) {
156 if (node
->isElementNode()) {
157 ++elementsWithRareData
;
158 if (toElement(node
)->hasNamedNodeMap())
159 ++elementsWithNamedNodeMap
;
163 switch (node
->nodeType()) {
168 Element
* element
= toElement(node
);
169 HashMap
<String
, size_t>::AddResult result
= perTagCount
.add(element
->tagName(), 1);
170 if (!result
.isNewEntry
)
171 result
.storedValue
->value
++;
173 if (const ElementData
* elementData
= element
->elementData()) {
174 attributes
+= elementData
->attributes().size();
175 ++elementsWithAttributeStorage
;
179 case ATTRIBUTE_NODE
: {
187 case CDATA_SECTION_NODE
: {
195 case PROCESSING_INSTRUCTION_NODE
: {
199 case DOCUMENT_NODE
: {
203 case DOCUMENT_TYPE_NODE
: {
207 case DOCUMENT_FRAGMENT_NODE
: {
208 if (node
->isShadowRoot())
217 printf("Number of Nodes: %d\n\n", liveNodeSet().size());
218 printf("Number of Nodes with RareData: %zu\n\n", nodesWithRareData
);
220 printf("NodeType distribution:\n");
221 printf(" Number of Element nodes: %zu\n", elementNodes
);
222 printf(" Number of Attribute nodes: %zu\n", attrNodes
);
223 printf(" Number of Text nodes: %zu\n", textNodes
);
224 printf(" Number of CDATASection nodes: %zu\n", cdataNodes
);
225 printf(" Number of Comment nodes: %zu\n", commentNodes
);
226 printf(" Number of ProcessingInstruction nodes: %zu\n", piNodes
);
227 printf(" Number of Document nodes: %zu\n", documentNodes
);
228 printf(" Number of DocumentType nodes: %zu\n", docTypeNodes
);
229 printf(" Number of DocumentFragment nodes: %zu\n", fragmentNodes
);
230 printf(" Number of ShadowRoot nodes: %zu\n", shadowRootNodes
);
232 printf("Element tag name distibution:\n");
233 for (const auto& entry
: perTagCount
)
234 printf(" Number of <%s> tags: %zu\n", entry
.key
.utf8().data(), entry
.value
);
236 printf("Attributes:\n");
237 printf(" Number of Attributes (non-Node and Node): %zu [%zu]\n", attributes
, sizeof(Attribute
));
238 printf(" Number of Elements with attribute storage: %zu [%zu]\n", elementsWithAttributeStorage
, sizeof(ElementData
));
239 printf(" Number of Elements with RareData: %zu\n", elementsWithRareData
);
240 printf(" Number of Elements with NamedNodeMap: %zu [%zu]\n", elementsWithNamedNodeMap
, sizeof(NamedNodeMap
));
244 void Node::trackForDebugging()
246 #if DUMP_NODE_STATISTICS
247 liveNodeSet().add(this);
251 Node::Node(TreeScope
* treeScope
, ConstructionType type
)
253 , m_parentOrShadowHostNode(nullptr)
254 , m_treeScope(treeScope
)
255 , m_previous(nullptr)
258 ASSERT(m_treeScope
|| type
== CreateDocument
|| type
== CreateShadowRoot
);
261 m_treeScope
->guardRef();
264 #if !defined(NDEBUG) || (defined(DUMP_NODE_STATISTICS) && DUMP_NODE_STATISTICS)
267 InstanceCounters::incrementCounter(InstanceCounters::NodeCounter
);
273 #if DUMP_NODE_STATISTICS
274 liveNodeSet().remove(this);
280 RELEASE_ASSERT(!layoutObject());
282 if (!isContainerNode())
283 willBeDeletedFromDocument();
286 m_previous
->setNextSibling(nullptr);
288 m_next
->setPreviousSibling(nullptr);
291 m_treeScope
->guardDeref();
293 if (getFlag(HasWeakReferencesFlag
))
294 WeakIdentifierMap
<Node
>::notifyObjectDestroyed(this);
296 // clearEventTargetData() must be always done,
297 // or eventTargetDataMap() may keep a raw pointer to a deleted object.
298 ASSERT(!hasEventTargetData());
300 // With Oilpan, the rare data finalizer also asserts for
301 // this condition (we cannot directly access it here.)
302 RELEASE_ASSERT(hasRareData() || !layoutObject());
305 InstanceCounters::decrementCounter(InstanceCounters::NodeCounter
);
309 // With Oilpan all of this is handled with weak processing of the document.
310 void Node::willBeDeletedFromDocument()
312 if (hasEventTargetData())
313 clearEventTargetData();
315 if (!isTreeScopeInitialized())
318 Document
& document
= this->document();
320 if (document
.frameHost())
321 document
.frameHost()->eventHandlerRegistry().didRemoveAllEventHandlers(*this);
323 document
.markers().removeMarkers(this);
327 NodeRareData
* Node::rareData() const
329 ASSERT_WITH_SECURITY_IMPLICATION(hasRareData());
330 return static_cast<NodeRareData
*>(m_data
.m_rareData
);
333 NodeRareData
& Node::ensureRareData()
339 m_data
.m_rareData
= ElementRareData::create(m_data
.m_layoutObject
);
341 m_data
.m_rareData
= NodeRareData::create(m_data
.m_layoutObject
);
343 ASSERT(m_data
.m_rareData
);
345 setFlag(HasRareDataFlag
);
350 void Node::clearRareData()
352 ASSERT(hasRareData());
353 ASSERT(!transientMutationObserverRegistry() || transientMutationObserverRegistry()->isEmpty());
355 LayoutObject
* layoutObject
= m_data
.m_rareData
->layoutObject();
357 delete static_cast<ElementRareData
*>(m_data
.m_rareData
);
359 delete static_cast<NodeRareData
*>(m_data
.m_rareData
);
360 m_data
.m_layoutObject
= layoutObject
;
361 clearFlag(HasRareDataFlag
);
370 short Node::tabIndex() const
375 String
Node::nodeValue() const
380 void Node::setNodeValue(const String
&)
382 // By default, setting nodeValue has no effect.
385 PassRefPtrWillBeRawPtr
<NodeList
> Node::childNodes()
387 if (isContainerNode())
388 return ensureRareData().ensureNodeLists().ensureChildNodeList(toContainerNode(*this));
389 return ensureRareData().ensureNodeLists().ensureEmptyChildNodeList(*this);
392 Node
* Node::pseudoAwarePreviousSibling() const
394 if (parentElement() && !previousSibling()) {
395 Element
* parent
= parentElement();
396 if (isAfterPseudoElement() && parent
->lastChild())
397 return parent
->lastChild();
398 if (!isBeforePseudoElement())
399 return parent
->pseudoElement(BEFORE
);
401 return previousSibling();
404 Node
* Node::pseudoAwareNextSibling() const
406 if (parentElement() && !nextSibling()) {
407 Element
* parent
= parentElement();
408 if (isBeforePseudoElement() && parent
->hasChildren())
409 return parent
->firstChild();
410 if (!isAfterPseudoElement())
411 return parent
->pseudoElement(AFTER
);
413 return nextSibling();
416 Node
* Node::pseudoAwareFirstChild() const
418 if (isElementNode()) {
419 const Element
* currentElement
= toElement(this);
420 Node
* first
= currentElement
->pseudoElement(BEFORE
);
423 first
= currentElement
->firstChild();
425 first
= currentElement
->pseudoElement(AFTER
);
432 Node
* Node::pseudoAwareLastChild() const
434 if (isElementNode()) {
435 const Element
* currentElement
= toElement(this);
436 Node
* last
= currentElement
->pseudoElement(AFTER
);
439 last
= currentElement
->lastChild();
441 last
= currentElement
->pseudoElement(BEFORE
);
448 PassRefPtrWillBeRawPtr
<Node
> Node::insertBefore(PassRefPtrWillBeRawPtr
<Node
> newChild
, Node
* refChild
, ExceptionState
& exceptionState
)
450 if (isContainerNode())
451 return toContainerNode(this)->insertBefore(newChild
, refChild
, exceptionState
);
453 exceptionState
.throwDOMException(HierarchyRequestError
, "This node type does not support this method.");
457 PassRefPtrWillBeRawPtr
<Node
> Node::replaceChild(PassRefPtrWillBeRawPtr
<Node
> newChild
, PassRefPtrWillBeRawPtr
<Node
> oldChild
, ExceptionState
& exceptionState
)
459 if (isContainerNode())
460 return toContainerNode(this)->replaceChild(newChild
, oldChild
, exceptionState
);
462 exceptionState
.throwDOMException(HierarchyRequestError
, "This node type does not support this method.");
466 PassRefPtrWillBeRawPtr
<Node
> Node::removeChild(PassRefPtrWillBeRawPtr
<Node
> oldChild
, ExceptionState
& exceptionState
)
468 if (isContainerNode())
469 return toContainerNode(this)->removeChild(oldChild
, exceptionState
);
471 exceptionState
.throwDOMException(NotFoundError
, "This node type does not support this method.");
475 PassRefPtrWillBeRawPtr
<Node
> Node::appendChild(PassRefPtrWillBeRawPtr
<Node
> newChild
, ExceptionState
& exceptionState
)
477 if (isContainerNode())
478 return toContainerNode(this)->appendChild(newChild
, exceptionState
);
480 exceptionState
.throwDOMException(HierarchyRequestError
, "This node type does not support this method.");
484 void Node::remove(ExceptionState
& exceptionState
)
486 if (ContainerNode
* parent
= parentNode())
487 parent
->removeChild(this, exceptionState
);
490 void Node::normalize()
492 updateDistribution();
494 // Go through the subtree beneath us, normalizing all nodes. This means that
495 // any two adjacent text nodes are merged and any empty text nodes are removed.
497 RefPtrWillBeRawPtr
<Node
> node
= this;
498 while (Node
* firstChild
= node
->firstChild())
504 if (node
->nodeType() == TEXT_NODE
)
505 node
= toText(node
)->mergeNextSiblingNodesIfPossible();
507 node
= NodeTraversal::nextPostOrder(*node
);
511 bool Node::isContentEditable(UserSelectAllTreatment treatment
) const
513 document().updateLayoutTreeIfNeeded();
514 return hasEditableStyle(Editable
, treatment
);
517 bool Node::isContentRichlyEditable() const
519 document().updateLayoutTreeIfNeeded();
520 return hasEditableStyle(RichlyEditable
, UserSelectAllIsAlwaysNonEditable
);
523 bool Node::hasEditableStyle(EditableLevel editableLevel
, UserSelectAllTreatment treatment
) const
525 if (isPseudoElement())
528 // Ideally we'd call ASSERT(!needsStyleRecalc()) here, but
529 // ContainerNode::setFocus() calls setNeedsStyleRecalc(), so the assertion
530 // would fire in the middle of Document::setFocusedNode().
532 for (const Node
* node
= this; node
; node
= node
->parentNode()) {
533 if ((node
->isHTMLElement() || node
->isDocumentNode()) && node
->layoutObject()) {
534 // Elements with user-select: all style are considered atomic
535 // therefore non editable.
536 if (nodeIsUserSelectAll(node
) && treatment
== UserSelectAllIsAlwaysNonEditable
)
538 switch (node
->layoutObject()->style()->userModify()) {
543 case READ_WRITE_PLAINTEXT_ONLY
:
544 return editableLevel
!= RichlyEditable
;
546 ASSERT_NOT_REACHED();
554 bool Node::isEditableToAccessibility(EditableLevel editableLevel
) const
556 if (hasEditableStyle(editableLevel
))
559 // FIXME: Respect editableLevel for ARIA editable elements.
560 if (editableLevel
== RichlyEditable
)
563 // FIXME(dmazzoni): support ScopedAXObjectCache (crbug/489851).
564 if (AXObjectCache
* cache
= document().existingAXObjectCache())
565 return cache
->rootAXEditableElement(this);
570 LayoutBox
* Node::layoutBox() const
572 LayoutObject
* layoutObject
= this->layoutObject();
573 return layoutObject
&& layoutObject
->isBox() ? toLayoutBox(layoutObject
) : nullptr;
576 LayoutBoxModelObject
* Node::layoutBoxModelObject() const
578 LayoutObject
* layoutObject
= this->layoutObject();
579 return layoutObject
&& layoutObject
->isBoxModelObject() ? toLayoutBoxModelObject(layoutObject
) : nullptr;
582 LayoutRect
Node::boundingBox() const
585 return LayoutRect(layoutObject()->absoluteBoundingBoxRect());
590 inline static ShadowRoot
* oldestShadowRootFor(const Node
* node
)
592 if (!node
->isElementNode())
594 if (ElementShadow
* shadow
= toElement(node
)->shadow())
595 return shadow
->oldestShadowRoot();
600 inline static Node
& rootInTreeOfTrees(const Node
& node
)
602 if (node
.inDocument())
603 return node
.document();
604 Node
* root
= const_cast<Node
*>(&node
);
605 while (Node
* host
= root
->shadowHost())
607 while (Node
* ancestor
= root
->parentNode())
609 ASSERT(!root
->shadowHost());
614 bool Node::needsDistributionRecalc() const
616 return rootInTreeOfTrees(*this).childNeedsDistributionRecalc();
620 void Node::updateDistribution()
622 // Extra early out to avoid spamming traces.
623 if (inDocument() && !document().childNeedsDistributionRecalc())
625 TRACE_EVENT0("blink", "Node::updateDistribution");
626 ScriptForbiddenScope forbidScript
;
627 Node
& root
= rootInTreeOfTrees(*this);
628 if (root
.childNeedsDistributionRecalc())
629 root
.recalcDistribution();
632 void Node::recalcDistribution()
634 ASSERT(childNeedsDistributionRecalc());
636 if (isElementNode()) {
637 if (ElementShadow
* shadow
= toElement(this)->shadow())
638 shadow
->distributeIfNeeded();
641 for (Node
* child
= firstChild(); child
; child
= child
->nextSibling()) {
642 if (child
->childNeedsDistributionRecalc())
643 child
->recalcDistribution();
646 for (ShadowRoot
* root
= youngestShadowRoot(); root
; root
= root
->olderShadowRoot()) {
647 if (root
->childNeedsDistributionRecalc())
648 root
->recalcDistribution();
651 clearChildNeedsDistributionRecalc();
654 void Node::setIsLink(bool isLink
)
656 setFlag(isLink
&& !SVGImage::isInSVGImage(toElement(this)), IsLinkFlag
);
659 void Node::setNeedsStyleInvalidation()
661 ASSERT(isElementNode());
662 setFlag(NeedsStyleInvalidationFlag
);
663 markAncestorsWithChildNeedsStyleInvalidation();
666 void Node::markAncestorsWithChildNeedsStyleInvalidation()
668 for (Node
* node
= parentOrShadowHostNode(); node
&& !node
->childNeedsStyleInvalidation(); node
= node
->parentOrShadowHostNode())
669 node
->setChildNeedsStyleInvalidation();
670 document().scheduleLayoutTreeUpdateIfNeeded();
673 void Node::markAncestorsWithChildNeedsDistributionRecalc()
675 for (Node
* node
= this; node
&& !node
->childNeedsDistributionRecalc(); node
= node
->parentOrShadowHostNode())
676 node
->setChildNeedsDistributionRecalc();
677 document().scheduleLayoutTreeUpdateIfNeeded();
680 inline void Node::setStyleChange(StyleChangeType changeType
)
682 m_nodeFlags
= (m_nodeFlags
& ~StyleChangeMask
) | changeType
;
685 void Node::markAncestorsWithChildNeedsStyleRecalc()
687 for (ContainerNode
* p
= parentOrShadowHostNode(); p
&& !p
->childNeedsStyleRecalc(); p
= p
->parentOrShadowHostNode())
688 p
->setChildNeedsStyleRecalc();
689 document().scheduleLayoutTreeUpdateIfNeeded();
692 void Node::setNeedsStyleRecalc(StyleChangeType changeType
, const StyleChangeReasonForTracing
& reason
)
694 ASSERT(changeType
!= NoStyleChange
);
695 if (!inActiveDocument())
698 TRACE_EVENT_INSTANT1(
699 TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"),
700 "StyleRecalcInvalidationTracking",
701 TRACE_EVENT_SCOPE_THREAD
,
703 InspectorStyleRecalcInvalidationTrackingEvent::data(this, reason
));
705 StyleChangeType existingChangeType
= styleChangeType();
706 if (changeType
> existingChangeType
)
707 setStyleChange(changeType
);
709 if (existingChangeType
== NoStyleChange
)
710 markAncestorsWithChildNeedsStyleRecalc();
712 if (isElementNode() && hasRareData())
713 toElement(*this).setAnimationStyleChange(false);
716 void Node::clearNeedsStyleRecalc()
718 m_nodeFlags
&= ~StyleChangeMask
;
720 clearSVGFilterNeedsLayerUpdate();
722 if (isElementNode() && hasRareData())
723 toElement(*this).setAnimationStyleChange(false);
726 bool Node::inActiveDocument() const
728 return inDocument() && document().isActive();
731 Node
* Node::focusDelegate()
736 bool Node::shouldHaveFocusAppearance() const
742 bool Node::isInert() const
744 const HTMLDialogElement
* dialog
= document().activeModalDialog();
745 if (dialog
&& this != document() && (!canParticipateInComposedTree() || !ComposedTreeTraversal::containsIncludingPseudoElement(*dialog
, *this)))
747 return document().ownerElement() && document().ownerElement()->isInert();
750 unsigned Node::nodeIndex() const
752 Node
* tempNode
= previousSibling();
754 for (count
= 0; tempNode
; count
++)
755 tempNode
= tempNode
->previousSibling();
759 NodeListsNodeData
* Node::nodeLists()
761 return hasRareData() ? rareData()->nodeLists() : nullptr;
764 void Node::clearNodeLists()
766 rareData()->clearNodeLists();
769 bool Node::isDescendantOf(const Node
*other
) const
771 // Return true if other is an ancestor of this, otherwise false
772 if (!other
|| !other
->hasChildren() || inDocument() != other
->inDocument())
774 if (other
->treeScope() != treeScope())
776 if (other
->isTreeScope())
777 return !isTreeScope();
778 for (const ContainerNode
* n
= parentNode(); n
; n
= n
->parentNode()) {
785 bool Node::contains(const Node
* node
) const
789 return this == node
|| node
->isDescendantOf(this);
792 bool Node::containsIncludingShadowDOM(const Node
* node
) const
800 if (document() != node
->document())
803 if (inDocument() != node
->inDocument())
806 bool hasChildren
= isContainerNode() && toContainerNode(this)->hasChildren();
807 bool hasShadow
= isElementNode() && toElement(this)->shadow();
808 if (!hasChildren
&& !hasShadow
)
811 for (; node
; node
= node
->shadowHost()) {
812 if (treeScope() == node
->treeScope())
813 return contains(node
);
819 bool Node::containsIncludingHostElements(const Node
& node
) const
821 const Node
* current
= &node
;
825 if (current
->isDocumentFragment() && toDocumentFragment(current
)->isTemplateContent())
826 current
= static_cast<const TemplateContentDocumentFragment
*>(current
)->host();
828 current
= current
->parentOrShadowHostNode();
833 Node
* Node::commonAncestor(const Node
& other
, ContainerNode
* (*parent
)(const Node
&)) const
836 return const_cast<Node
*>(this);
837 if (document() != other
.document())
840 for (const Node
* node
= this; node
; node
= parent(*node
)) {
842 return const_cast<Node
*>(node
);
846 for (const Node
* node
= &other
; node
; node
= parent(*node
)) {
848 return const_cast<Node
*>(this);
851 const Node
* thisIterator
= this;
852 const Node
* otherIterator
= &other
;
853 if (thisDepth
> otherDepth
) {
854 for (int i
= thisDepth
; i
> otherDepth
; --i
)
855 thisIterator
= parent(*thisIterator
);
856 } else if (otherDepth
> thisDepth
) {
857 for (int i
= otherDepth
; i
> thisDepth
; --i
)
858 otherIterator
= parent(*otherIterator
);
860 while (thisIterator
) {
861 if (thisIterator
== otherIterator
)
862 return const_cast<Node
*>(thisIterator
);
863 thisIterator
= parent(*thisIterator
);
864 otherIterator
= parent(*otherIterator
);
866 ASSERT(!otherIterator
);
870 void Node::reattach(const AttachContext
& context
)
872 AttachContext
reattachContext(context
);
873 reattachContext
.performingReattach
= true;
875 // We only need to detach if the node has already been through attach().
876 if (styleChangeType() < NeedsReattachStyleChange
)
877 detach(reattachContext
);
878 attach(reattachContext
);
881 void Node::attach(const AttachContext
&)
883 ASSERT(document().inStyleRecalc() || isDocumentNode());
884 ASSERT(!document().lifecycle().inDetach());
885 ASSERT(needsAttach());
886 ASSERT(!layoutObject() || (layoutObject()->style() && (layoutObject()->parent() || layoutObject()->isLayoutView())));
888 clearNeedsStyleRecalc();
890 if (AXObjectCache
* cache
= document().axObjectCache())
891 cache
->updateCacheAfterNodeIsAttached(this);
894 void Node::detach(const AttachContext
& context
)
896 ASSERT(document().lifecycle().stateAllowsDetach());
897 DocumentLifecycle::DetachScope
willDetach(document().lifecycle());
900 layoutObject()->destroyAndCleanupAnonymousWrappers();
901 setLayoutObject(nullptr);
903 setStyleChange(NeedsReattachStyleChange
);
904 clearChildNeedsStyleInvalidation();
907 void Node::reattachWhitespaceSiblingsIfNeeded(Text
* start
)
909 for (Node
* sibling
= start
; sibling
; sibling
= sibling
->nextSibling()) {
910 if (sibling
->isTextNode() && toText(sibling
)->containsOnlyWhitespace()) {
911 bool hadLayoutObject
= !!sibling
->layoutObject();
912 toText(sibling
)->reattachIfNeeded();
913 // If sibling's layout object status didn't change we don't need to continue checking
914 // other siblings since their layout object status won't change either.
915 if (!!sibling
->layoutObject() == hadLayoutObject
)
917 } else if (sibling
->layoutObject()) {
923 const ComputedStyle
* Node::virtualEnsureComputedStyle(PseudoId pseudoElementSpecifier
)
925 return parentOrShadowHostNode() ? parentOrShadowHostNode()->ensureComputedStyle(pseudoElementSpecifier
) : nullptr;
928 int Node::maxCharacterOffset() const
930 ASSERT_NOT_REACHED();
934 // FIXME: Shouldn't these functions be in the editing code? Code that asks questions about HTML in the core DOM class
935 // is obviously misplaced.
936 bool Node::canStartSelection() const
938 if (hasEditableStyle())
941 if (layoutObject()) {
942 const ComputedStyle
& style
= layoutObject()->styleRef();
943 // We allow selections to begin within an element that has -webkit-user-select: none set,
944 // but if the element is draggable then dragging should take priority over selection.
945 if (style
.userDrag() == DRAG_ELEMENT
&& style
.userSelect() == SELECT_NONE
)
948 return parentOrShadowHostNode() ? parentOrShadowHostNode()->canStartSelection() : true;
951 bool Node::canParticipateInComposedTree() const
953 return !isShadowRoot() && !isActiveInsertionPoint(*this);
956 Element
* Node::shadowHost() const
958 if (ShadowRoot
* root
= containingShadowRoot())
963 ShadowRoot
* Node::containingShadowRoot() const
965 Node
& root
= treeScope().rootNode();
966 return root
.isShadowRoot() ? toShadowRoot(&root
) : nullptr;
969 Node
* Node::nonBoundaryShadowTreeRootNode()
971 ASSERT(!isShadowRoot());
974 if (root
->isShadowRoot())
976 Node
* parent
= root
->parentOrShadowHostNode();
977 if (parent
&& parent
->isShadowRoot())
984 ContainerNode
* Node::nonShadowBoundaryParentNode() const
986 ContainerNode
* parent
= parentNode();
987 return parent
&& !parent
->isShadowRoot() ? parent
: nullptr;
990 Element
* Node::parentOrShadowHostElement() const
992 ContainerNode
* parent
= parentOrShadowHostNode();
996 if (parent
->isShadowRoot())
997 return toShadowRoot(parent
)->host();
999 if (!parent
->isElementNode())
1002 return toElement(parent
);
1005 ContainerNode
* Node::parentOrShadowHostOrTemplateHostNode() const
1007 if (isDocumentFragment() && toDocumentFragment(this)->isTemplateContent())
1008 return static_cast<const TemplateContentDocumentFragment
*>(this)->host();
1009 return parentOrShadowHostNode();
1012 bool Node::isRootEditableElement() const
1014 return hasEditableStyle() && isElementNode() && (!parentNode() || !parentNode()->hasEditableStyle()
1015 || !parentNode()->isElementNode() || isHTMLBodyElement((*this)));
1018 Element
* Node::rootEditableElement(EditableType editableType
) const
1020 if (editableType
== HasEditableAXRole
) {
1021 if (AXObjectCache
* cache
= document().existingAXObjectCache())
1022 return const_cast<Element
*>(cache
->rootAXEditableElement(this));
1025 return rootEditableElement();
1028 Element
* Node::rootEditableElement() const
1030 Element
* result
= nullptr;
1031 for (Node
* n
= const_cast<Node
*>(this); n
&& n
->hasEditableStyle(); n
= n
->parentNode()) {
1032 if (n
->isElementNode())
1033 result
= toElement(n
);
1034 if (isHTMLBodyElement(*n
))
1040 // FIXME: End of obviously misplaced HTML editing functions. Try to move these out of Node.
1042 Document
* Node::ownerDocument() const
1044 Document
* doc
= &document();
1045 return doc
== this ? nullptr : doc
;
1048 KURL
Node::baseURI() const
1050 return parentNode() ? parentNode()->baseURI() : KURL();
1053 bool Node::isEqualNode(Node
* other
) const
1058 NodeType nodeType
= this->nodeType();
1059 if (nodeType
!= other
->nodeType())
1062 if (nodeName() != other
->nodeName())
1065 if (nodeValue() != other
->nodeValue())
1068 if (isAttributeNode()) {
1069 if (toAttr(this)->localName() != toAttr(other
)->localName())
1072 if (toAttr(this)->namespaceURI() != toAttr(other
)->namespaceURI())
1074 } else if (isElementNode()) {
1075 if (toElement(this)->localName() != toElement(other
)->localName())
1078 if (toElement(this)->namespaceURI() != toElement(other
)->namespaceURI())
1081 if (!toElement(this)->hasEquivalentAttributes(toElement(other
)))
1085 Node
* child
= firstChild();
1086 Node
* otherChild
= other
->firstChild();
1089 if (!child
->isEqualNode(otherChild
))
1092 child
= child
->nextSibling();
1093 otherChild
= otherChild
->nextSibling();
1099 if (isDocumentTypeNode()) {
1100 const DocumentType
* documentTypeThis
= toDocumentType(this);
1101 const DocumentType
* documentTypeOther
= toDocumentType(other
);
1103 if (documentTypeThis
->publicId() != documentTypeOther
->publicId())
1106 if (documentTypeThis
->systemId() != documentTypeOther
->systemId())
1113 bool Node::isDefaultNamespace(const AtomicString
& namespaceURIMaybeEmpty
) const
1115 const AtomicString
& namespaceURI
= namespaceURIMaybeEmpty
.isEmpty() ? nullAtom
: namespaceURIMaybeEmpty
;
1117 switch (nodeType()) {
1118 case ELEMENT_NODE
: {
1119 const Element
& element
= toElement(*this);
1121 if (element
.prefix().isNull())
1122 return element
.namespaceURI() == namespaceURI
;
1124 AttributeCollection attributes
= element
.attributes();
1125 for (const Attribute
& attr
: attributes
) {
1126 if (attr
.localName() == xmlnsAtom
)
1127 return attr
.value() == namespaceURI
;
1130 if (Element
* parent
= parentElement())
1131 return parent
->isDefaultNamespace(namespaceURI
);
1136 if (Element
* de
= toDocument(this)->documentElement())
1137 return de
->isDefaultNamespace(namespaceURI
);
1139 case DOCUMENT_TYPE_NODE
:
1140 case DOCUMENT_FRAGMENT_NODE
:
1142 case ATTRIBUTE_NODE
: {
1143 const Attr
* attr
= toAttr(this);
1144 if (attr
->ownerElement())
1145 return attr
->ownerElement()->isDefaultNamespace(namespaceURI
);
1149 if (Element
* parent
= parentElement())
1150 return parent
->isDefaultNamespace(namespaceURI
);
1155 const AtomicString
& Node::lookupPrefix(const AtomicString
& namespaceURI
) const
1157 // Implemented according to
1158 // http://dom.spec.whatwg.org/#dom-node-lookupprefix
1160 if (namespaceURI
.isEmpty() || namespaceURI
.isNull())
1163 const Element
* context
;
1165 switch (nodeType()) {
1167 context
= toElement(this);
1170 context
= toDocument(this)->documentElement();
1172 case DOCUMENT_FRAGMENT_NODE
:
1173 case DOCUMENT_TYPE_NODE
:
1176 // FIXME: Remove this when Attr no longer extends Node (CR305105)
1177 case ATTRIBUTE_NODE
:
1178 context
= toAttr(this)->ownerElement();
1181 context
= parentElement();
1188 return context
->locateNamespacePrefix(namespaceURI
);
1191 const AtomicString
& Node::lookupNamespaceURI(const String
& prefix
) const
1193 // Implemented according to
1194 // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html#lookupNamespaceURIAlgo
1196 if (!prefix
.isNull() && prefix
.isEmpty())
1199 switch (nodeType()) {
1200 case ELEMENT_NODE
: {
1201 const Element
& element
= toElement(*this);
1203 if (!element
.namespaceURI().isNull() && element
.prefix() == prefix
)
1204 return element
.namespaceURI();
1206 AttributeCollection attributes
= element
.attributes();
1207 for (const Attribute
& attr
: attributes
) {
1208 if (attr
.prefix() == xmlnsAtom
&& attr
.localName() == prefix
) {
1209 if (!attr
.value().isEmpty())
1210 return attr
.value();
1213 if (attr
.localName() == xmlnsAtom
&& prefix
.isNull()) {
1214 if (!attr
.value().isEmpty())
1215 return attr
.value();
1220 if (Element
* parent
= parentElement())
1221 return parent
->lookupNamespaceURI(prefix
);
1225 if (Element
* de
= toDocument(this)->documentElement())
1226 return de
->lookupNamespaceURI(prefix
);
1228 case DOCUMENT_TYPE_NODE
:
1229 case DOCUMENT_FRAGMENT_NODE
:
1231 case ATTRIBUTE_NODE
: {
1232 const Attr
*attr
= toAttr(this);
1233 if (attr
->ownerElement())
1234 return attr
->ownerElement()->lookupNamespaceURI(prefix
);
1238 if (Element
* parent
= parentElement())
1239 return parent
->lookupNamespaceURI(prefix
);
1244 String
Node::textContent(bool convertBRsToNewlines
) const
1246 // This covers ProcessingInstruction and Comment that should return their
1247 // value when .textContent is accessed on them, but should be ignored when
1248 // iterated over as a descendant of a ContainerNode.
1249 if (isCharacterDataNode())
1250 return toCharacterData(this)->data();
1252 // Documents and non-container nodes (that are not CharacterData)
1253 // have null textContent.
1254 if (isDocumentNode() || !isContainerNode())
1257 StringBuilder content
;
1258 for (Node
& node
: NodeTraversal::inclusiveDescendantsOf(*this)) {
1259 if (isHTMLBRElement(node
) && convertBRsToNewlines
) {
1260 content
.append('\n');
1261 } else if (node
.isTextNode()) {
1262 content
.append(toText(node
).data());
1265 return content
.toString();
1268 void Node::setTextContent(const String
& text
)
1270 switch (nodeType()) {
1272 case CDATA_SECTION_NODE
:
1274 case PROCESSING_INSTRUCTION_NODE
:
1278 case DOCUMENT_FRAGMENT_NODE
: {
1279 // FIXME: Merge this logic into replaceChildrenWithText.
1280 RefPtrWillBeRawPtr
<ContainerNode
> container
= toContainerNode(this);
1282 // Note: This is an intentional optimization.
1283 // See crbug.com/352836 also.
1284 // No need to do anything if the text is identical.
1285 if (container
->hasOneTextChild() && toText(container
->firstChild())->data() == text
)
1288 ChildListMutationScope
mutation(*this);
1289 // Note: This API will not insert empty text nodes:
1290 // http://dom.spec.whatwg.org/#dom-node-textcontent
1291 if (text
.isEmpty()) {
1292 container
->removeChildren(DispatchSubtreeModifiedEvent
);
1294 container
->removeChildren(OmitSubtreeModifiedEvent
);
1295 container
->appendChild(document().createTextNode(text
), ASSERT_NO_EXCEPTION
);
1299 case ATTRIBUTE_NODE
:
1301 case DOCUMENT_TYPE_NODE
:
1305 ASSERT_NOT_REACHED();
1308 bool Node::offsetInCharacters() const
1310 return isCharacterDataNode();
1313 unsigned short Node::compareDocumentPosition(const Node
* otherNode
, ShadowTreesTreatment treatment
) const
1315 if (otherNode
== this)
1316 return DOCUMENT_POSITION_EQUIVALENT
;
1318 const Attr
* attr1
= nodeType() == ATTRIBUTE_NODE
? toAttr(this) : nullptr;
1319 const Attr
* attr2
= otherNode
->nodeType() == ATTRIBUTE_NODE
? toAttr(otherNode
) : nullptr;
1321 const Node
* start1
= attr1
? attr1
->ownerElement() : this;
1322 const Node
* start2
= attr2
? attr2
->ownerElement() : otherNode
;
1324 // If either of start1 or start2 is null, then we are disconnected, since one of the nodes is
1325 // an orphaned attribute node.
1326 if (!start1
|| !start2
) {
1327 unsigned short direction
= (this > otherNode
) ? DOCUMENT_POSITION_PRECEDING
: DOCUMENT_POSITION_FOLLOWING
;
1328 return DOCUMENT_POSITION_DISCONNECTED
| DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
| direction
;
1331 Vector
<const Node
*, 16> chain1
;
1332 Vector
<const Node
*, 16> chain2
;
1334 chain1
.append(attr1
);
1336 chain2
.append(attr2
);
1338 if (attr1
&& attr2
&& start1
== start2
&& start1
) {
1339 // We are comparing two attributes on the same node. Crawl our attribute map and see which one we hit first.
1340 const Element
* owner1
= attr1
->ownerElement();
1341 AttributeCollection attributes
= owner1
->attributes();
1342 for (const Attribute
& attr
: attributes
) {
1343 // If neither of the two determining nodes is a child node and nodeType is the same for both determining nodes, then an
1344 // implementation-dependent order between the determining nodes is returned. This order is stable as long as no nodes of
1345 // the same nodeType are inserted into or removed from the direct container. This would be the case, for example,
1346 // when comparing two attributes of the same element, and inserting or removing additional attributes might change
1347 // the order between existing attributes.
1348 if (attr1
->qualifiedName() == attr
.name())
1349 return DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
| DOCUMENT_POSITION_FOLLOWING
;
1350 if (attr2
->qualifiedName() == attr
.name())
1351 return DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
| DOCUMENT_POSITION_PRECEDING
;
1354 ASSERT_NOT_REACHED();
1355 return DOCUMENT_POSITION_DISCONNECTED
;
1358 // If one node is in the document and the other is not, we must be disconnected.
1359 // If the nodes have different owning documents, they must be disconnected. Note that we avoid
1360 // comparing Attr nodes here, since they return false from inDocument() all the time (which seems like a bug).
1361 if (start1
->inDocument() != start2
->inDocument() || (treatment
== TreatShadowTreesAsDisconnected
&& start1
->treeScope() != start2
->treeScope())) {
1362 unsigned short direction
= (this > otherNode
) ? DOCUMENT_POSITION_PRECEDING
: DOCUMENT_POSITION_FOLLOWING
;
1363 return DOCUMENT_POSITION_DISCONNECTED
| DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
| direction
;
1366 // We need to find a common ancestor container, and then compare the indices of the two immediate children.
1367 const Node
* current
;
1368 for (current
= start1
; current
; current
= current
->parentOrShadowHostNode())
1369 chain1
.append(current
);
1370 for (current
= start2
; current
; current
= current
->parentOrShadowHostNode())
1371 chain2
.append(current
);
1373 unsigned index1
= chain1
.size();
1374 unsigned index2
= chain2
.size();
1376 // If the two elements don't have a common root, they're not in the same tree.
1377 if (chain1
[index1
- 1] != chain2
[index2
- 1]) {
1378 unsigned short direction
= (this > otherNode
) ? DOCUMENT_POSITION_PRECEDING
: DOCUMENT_POSITION_FOLLOWING
;
1379 return DOCUMENT_POSITION_DISCONNECTED
| DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
| direction
;
1382 unsigned connection
= start1
->treeScope() != start2
->treeScope() ? DOCUMENT_POSITION_DISCONNECTED
| DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
: 0;
1384 // Walk the two chains backwards and look for the first difference.
1385 for (unsigned i
= std::min(index1
, index2
); i
; --i
) {
1386 const Node
* child1
= chain1
[--index1
];
1387 const Node
* child2
= chain2
[--index2
];
1388 if (child1
!= child2
) {
1389 // If one of the children is an attribute, it wins.
1390 if (child1
->nodeType() == ATTRIBUTE_NODE
)
1391 return DOCUMENT_POSITION_FOLLOWING
| connection
;
1392 if (child2
->nodeType() == ATTRIBUTE_NODE
)
1393 return DOCUMENT_POSITION_PRECEDING
| connection
;
1395 // If one of the children is a shadow root,
1396 if (child1
->isShadowRoot() || child2
->isShadowRoot()) {
1397 if (!child2
->isShadowRoot())
1398 return Node::DOCUMENT_POSITION_FOLLOWING
| connection
;
1399 if (!child1
->isShadowRoot())
1400 return Node::DOCUMENT_POSITION_PRECEDING
| connection
;
1402 for (ShadowRoot
* child
= toShadowRoot(child2
)->olderShadowRoot(); child
; child
= child
->olderShadowRoot()) {
1403 if (child
== child1
) {
1404 return Node::DOCUMENT_POSITION_FOLLOWING
| connection
;
1408 return Node::DOCUMENT_POSITION_PRECEDING
| connection
;
1411 if (!child2
->nextSibling())
1412 return DOCUMENT_POSITION_FOLLOWING
| connection
;
1413 if (!child1
->nextSibling())
1414 return DOCUMENT_POSITION_PRECEDING
| connection
;
1416 // Otherwise we need to see which node occurs first. Crawl backwards from child2 looking for child1.
1417 for (Node
* child
= child2
->previousSibling(); child
; child
= child
->previousSibling()) {
1418 if (child
== child1
)
1419 return DOCUMENT_POSITION_FOLLOWING
| connection
;
1421 return DOCUMENT_POSITION_PRECEDING
| connection
;
1425 // There was no difference between the two parent chains, i.e., one was a subset of the other. The shorter
1426 // chain is the ancestor.
1427 return index1
< index2
?
1428 DOCUMENT_POSITION_FOLLOWING
| DOCUMENT_POSITION_CONTAINED_BY
| connection
:
1429 DOCUMENT_POSITION_PRECEDING
| DOCUMENT_POSITION_CONTAINS
| connection
;
1432 String
Node::debugName() const
1435 name
.append(nodeName());
1437 if (isElementNode()) {
1438 const Element
& thisElement
= toElement(*this);
1439 if (thisElement
.hasID()) {
1440 name
.appendLiteral(" id=\'");
1441 name
.append(thisElement
.getIdAttribute());
1445 if (thisElement
.hasClass()) {
1446 name
.appendLiteral(" class=\'");
1447 for (size_t i
= 0; i
< thisElement
.classNames().size(); ++i
) {
1450 name
.append(thisElement
.classNames()[i
]);
1456 return name
.toString();
1461 static void appendAttributeDesc(const Node
* node
, StringBuilder
& stringBuilder
, const QualifiedName
& name
, const char* attrDesc
)
1463 if (!node
->isElementNode())
1466 String attr
= toElement(node
)->getAttribute(name
);
1470 stringBuilder
.append(attrDesc
);
1471 stringBuilder
.appendLiteral("=\"");
1472 stringBuilder
.append(attr
);
1473 stringBuilder
.appendLiteral("\"");
1476 void Node::showNode(const char* prefix
) const
1481 String value
= nodeValue();
1482 value
.replaceWithLiteral('\\', "\\\\");
1483 value
.replaceWithLiteral('\n', "\\n");
1484 WTFLogAlways("%s%s\t%p \"%s\"\n", prefix
, nodeName().utf8().data(), this, value
.utf8().data());
1486 StringBuilder attrs
;
1487 appendAttributeDesc(this, attrs
, idAttr
, " ID");
1488 appendAttributeDesc(this, attrs
, classAttr
, " CLASS");
1489 appendAttributeDesc(this, attrs
, styleAttr
, " STYLE");
1490 WTFLogAlways("%s%s\t%p%s\n", prefix
, nodeName().utf8().data(), this, attrs
.toString().utf8().data());
1494 void Node::showTreeForThis() const
1496 showTreeAndMark(this, "*");
1499 void Node::showTreeForThisInComposedTree() const
1501 showTreeAndMarkInComposedTree(this, "*");
1504 void Node::showNodePathForThis() const
1506 Vector
<const Node
*, 16> chain
;
1507 const Node
* node
= this;
1508 while (node
->parentOrShadowHostNode()) {
1510 node
= node
->parentOrShadowHostNode();
1512 for (unsigned index
= chain
.size(); index
> 0; --index
) {
1513 const Node
* node
= chain
[index
- 1];
1514 if (node
->isShadowRoot()) {
1516 for (ShadowRoot
* shadowRoot
= toShadowRoot(node
)->olderShadowRoot(); shadowRoot
; shadowRoot
= shadowRoot
->olderShadowRoot())
1518 WTFLogAlways("/#shadow-root[%d]", count
);
1522 switch (node
->nodeType()) {
1523 case ELEMENT_NODE
: {
1524 WTFLogAlways("/%s", node
->nodeName().utf8().data());
1526 const Element
* element
= toElement(node
);
1527 const AtomicString
& idattr
= element
->getIdAttribute();
1528 bool hasIdAttr
= !idattr
.isNull() && !idattr
.isEmpty();
1529 if (node
->previousSibling() || node
->nextSibling()) {
1531 for (Node
* previous
= node
->previousSibling(); previous
; previous
= previous
->previousSibling()) {
1532 if (previous
->nodeName() == node
->nodeName()) {
1537 WTFLogAlways("[@id=\"%s\" and position()=%d]", idattr
.utf8().data(), count
);
1539 WTFLogAlways("[%d]", count
);
1540 } else if (hasIdAttr
) {
1541 WTFLogAlways("[@id=\"%s\"]", idattr
.utf8().data());
1546 WTFLogAlways("/text()");
1548 case ATTRIBUTE_NODE
:
1549 WTFLogAlways("/@%s", node
->nodeName().utf8().data());
1558 static void traverseTreeAndMark(const String
& baseIndent
, const Node
* rootNode
, const Node
* markedNode1
, const char* markedLabel1
, const Node
* markedNode2
, const char* markedLabel2
)
1560 for (Node
& node
: NodeTraversal::inclusiveDescendantsOf(*rootNode
)) {
1561 StringBuilder indent
;
1562 if (node
== markedNode1
)
1563 indent
.append(markedLabel1
);
1564 if (node
== markedNode2
)
1565 indent
.append(markedLabel2
);
1566 indent
.append(baseIndent
);
1567 for (const Node
* tmpNode
= &node
; tmpNode
&& tmpNode
!= rootNode
; tmpNode
= tmpNode
->parentOrShadowHostNode())
1568 indent
.append('\t');
1569 node
.showNode(indent
.toString().utf8().data());
1570 indent
.append('\t');
1572 if (node
.isElementNode()) {
1573 const Element
& element
= toElement(node
);
1574 if (Element
* pseudo
= element
.pseudoElement(BEFORE
))
1575 traverseTreeAndMark(indent
.toString(), pseudo
, markedNode1
, markedLabel1
, markedNode2
, markedLabel2
);
1576 if (Element
* pseudo
= element
.pseudoElement(AFTER
))
1577 traverseTreeAndMark(indent
.toString(), pseudo
, markedNode1
, markedLabel1
, markedNode2
, markedLabel2
);
1578 if (Element
* pseudo
= element
.pseudoElement(FIRST_LETTER
))
1579 traverseTreeAndMark(indent
.toString(), pseudo
, markedNode1
, markedLabel1
, markedNode2
, markedLabel2
);
1580 if (Element
* pseudo
= element
.pseudoElement(BACKDROP
))
1581 traverseTreeAndMark(indent
.toString(), pseudo
, markedNode1
, markedLabel1
, markedNode2
, markedLabel2
);
1584 if (node
.isShadowRoot()) {
1585 if (ShadowRoot
* youngerShadowRoot
= toShadowRoot(node
).youngerShadowRoot())
1586 traverseTreeAndMark(indent
.toString(), youngerShadowRoot
, markedNode1
, markedLabel1
, markedNode2
, markedLabel2
);
1587 } else if (ShadowRoot
* oldestShadowRoot
= oldestShadowRootFor(&node
)) {
1588 traverseTreeAndMark(indent
.toString(), oldestShadowRoot
, markedNode1
, markedLabel1
, markedNode2
, markedLabel2
);
1593 static void traverseTreeAndMarkInComposedTree(const String
& baseIndent
, const Node
* rootNode
, const Node
* markedNode1
, const char* markedLabel1
, const Node
* markedNode2
, const char* markedLabel2
)
1595 for (const Node
* node
= rootNode
; node
; node
= ComposedTreeTraversal::nextSibling(*node
)) {
1596 StringBuilder indent
;
1597 if (node
== markedNode1
)
1598 indent
.append(markedLabel1
);
1599 if (node
== markedNode2
)
1600 indent
.append(markedLabel2
);
1601 indent
.append(baseIndent
);
1602 node
->showNode(indent
.toString().utf8().data());
1603 indent
.append('\t');
1605 Node
* child
= ComposedTreeTraversal::firstChild(*node
);
1607 traverseTreeAndMarkInComposedTree(indent
.toString(), child
, markedNode1
, markedLabel1
, markedNode2
, markedLabel2
);
1611 void Node::showTreeAndMark(const Node
* markedNode1
, const char* markedLabel1
, const Node
* markedNode2
, const char* markedLabel2
) const
1613 const Node
* rootNode
;
1614 const Node
* node
= this;
1615 while (node
->parentOrShadowHostNode() && !isHTMLBodyElement(*node
))
1616 node
= node
->parentOrShadowHostNode();
1619 String startingIndent
;
1620 traverseTreeAndMark(startingIndent
, rootNode
, markedNode1
, markedLabel1
, markedNode2
, markedLabel2
);
1623 void Node::showTreeAndMarkInComposedTree(const Node
* markedNode1
, const char* markedLabel1
, const Node
* markedNode2
, const char* markedLabel2
) const
1625 const Node
* rootNode
;
1626 const Node
* node
= this;
1627 while (node
->parentOrShadowHostNode() && !isHTMLBodyElement(*node
))
1628 node
= node
->parentOrShadowHostNode();
1631 String startingIndent
;
1632 traverseTreeAndMarkInComposedTree(startingIndent
, rootNode
, markedNode1
, markedLabel1
, markedNode2
, markedLabel2
);
1635 void Node::formatForDebugger(char* buffer
, unsigned length
) const
1646 strncpy(buffer
, result
.utf8().data(), length
- 1);
1649 static ContainerNode
* parentOrShadowHostOrFrameOwner(const Node
* node
)
1651 ContainerNode
* parent
= node
->parentOrShadowHostNode();
1652 if (!parent
&& node
->document().frame())
1653 parent
= node
->document().frame()->deprecatedLocalOwner();
1657 static void showSubTreeAcrossFrame(const Node
* node
, const Node
* markedNode
, const String
& indent
)
1659 if (node
== markedNode
)
1661 fputs(indent
.utf8().data(), stderr
);
1663 if (node
->isShadowRoot()) {
1664 if (ShadowRoot
* youngerShadowRoot
= toShadowRoot(node
)->youngerShadowRoot())
1665 showSubTreeAcrossFrame(youngerShadowRoot
, markedNode
, indent
+ "\t");
1667 if (node
->isFrameOwnerElement())
1668 showSubTreeAcrossFrame(toHTMLFrameOwnerElement(node
)->contentDocument(), markedNode
, indent
+ "\t");
1669 if (ShadowRoot
* oldestShadowRoot
= oldestShadowRootFor(node
))
1670 showSubTreeAcrossFrame(oldestShadowRoot
, markedNode
, indent
+ "\t");
1672 for (Node
* child
= node
->firstChild(); child
; child
= child
->nextSibling())
1673 showSubTreeAcrossFrame(child
, markedNode
, indent
+ "\t");
1676 void Node::showTreeForThisAcrossFrame() const
1678 Node
* rootNode
= const_cast<Node
*>(this);
1679 while (parentOrShadowHostOrFrameOwner(rootNode
))
1680 rootNode
= parentOrShadowHostOrFrameOwner(rootNode
);
1681 showSubTreeAcrossFrame(rootNode
, this, "");
1688 Element
* Node::enclosingLinkEventParentOrSelf() const
1690 for (Node
* node
= const_cast<Node
*>(this); node
; node
= ComposedTreeTraversal::parent(*node
)) {
1691 // For imagemaps, the enclosing link node is the associated area element not the image itself.
1692 // So we don't let images be the enclosingLinkNode, even though isLink sometimes returns true
1694 if (node
->isLink() && !isHTMLImageElement(*node
)) {
1695 // Casting to Element is safe because only HTMLAnchorElement, HTMLImageElement and
1696 // SVGAElement can return true for isLink().
1697 return toElement(node
);
1704 const AtomicString
& Node::interfaceName() const
1706 return EventTargetNames::Node
;
1709 ExecutionContext
* Node::executionContext() const
1711 return document().contextDocument().get();
1714 void Node::didMoveToNewDocument(Document
& oldDocument
)
1716 TreeScopeAdopter::ensureDidMoveToNewDocumentWasCalled(oldDocument
);
1718 if (const EventTargetData
* eventTargetData
= this->eventTargetData()) {
1719 const EventListenerMap
& listenerMap
= eventTargetData
->eventListenerMap
;
1720 if (!listenerMap
.isEmpty()) {
1721 Vector
<AtomicString
> types
= listenerMap
.eventTypes();
1722 for (unsigned i
= 0; i
< types
.size(); ++i
)
1723 document().addListenerTypeIfNeeded(types
[i
]);
1727 oldDocument
.markers().removeMarkers(this);
1728 oldDocument
.updateRangesAfterNodeMovedToAnotherDocument(*this);
1729 if (oldDocument
.frameHost() && !document().frameHost())
1730 oldDocument
.frameHost()->eventHandlerRegistry().didMoveOutOfFrameHost(*this);
1731 else if (document().frameHost() && !oldDocument
.frameHost())
1732 document().frameHost()->eventHandlerRegistry().didMoveIntoFrameHost(*this);
1733 else if (oldDocument
.frameHost() != document().frameHost())
1734 EventHandlerRegistry::didMoveBetweenFrameHosts(*this, oldDocument
.frameHost(), document().frameHost());
1736 if (WillBeHeapVector
<OwnPtrWillBeMember
<MutationObserverRegistration
>>* registry
= mutationObserverRegistry()) {
1737 for (size_t i
= 0; i
< registry
->size(); ++i
) {
1738 document().addMutationObserverTypes(registry
->at(i
)->mutationTypes());
1742 if (transientMutationObserverRegistry()) {
1743 for (MutationObserverRegistration
* registration
: *transientMutationObserverRegistry())
1744 document().addMutationObserverTypes(registration
->mutationTypes());
1748 static inline bool tryAddEventListener(Node
* targetNode
, const AtomicString
& eventType
, PassRefPtrWillBeRawPtr
<EventListener
> listener
, bool useCapture
)
1750 if (!targetNode
->EventTarget::addEventListener(eventType
, listener
, useCapture
))
1753 Document
& document
= targetNode
->document();
1754 document
.addListenerTypeIfNeeded(eventType
);
1755 if (document
.frameHost())
1756 document
.frameHost()->eventHandlerRegistry().didAddEventHandler(*targetNode
, eventType
);
1761 bool Node::addEventListener(const AtomicString
& eventType
, PassRefPtrWillBeRawPtr
<EventListener
> listener
, bool useCapture
)
1763 return tryAddEventListener(this, eventType
, listener
, useCapture
);
1766 static inline bool tryRemoveEventListener(Node
* targetNode
, const AtomicString
& eventType
, PassRefPtrWillBeRawPtr
<EventListener
> listener
, bool useCapture
)
1768 if (!targetNode
->EventTarget::removeEventListener(eventType
, listener
, useCapture
))
1771 // FIXME: Notify Document that the listener has vanished. We need to keep track of a number of
1772 // listeners for each type, not just a bool - see https://bugs.webkit.org/show_bug.cgi?id=33861
1773 Document
& document
= targetNode
->document();
1774 if (document
.frameHost())
1775 document
.frameHost()->eventHandlerRegistry().didRemoveEventHandler(*targetNode
, eventType
);
1780 bool Node::removeEventListener(const AtomicString
& eventType
, PassRefPtrWillBeRawPtr
<EventListener
> listener
, bool useCapture
)
1782 return tryRemoveEventListener(this, eventType
, listener
, useCapture
);
1785 void Node::removeAllEventListeners()
1787 if (hasEventListeners() && document().frameHost())
1788 document().frameHost()->eventHandlerRegistry().didRemoveAllEventHandlers(*this);
1789 EventTarget::removeAllEventListeners();
1792 void Node::removeAllEventListenersRecursively()
1794 for (Node
& node
: NodeTraversal::startsAt(this)) {
1795 node
.removeAllEventListeners();
1796 for (ShadowRoot
* root
= node
.youngestShadowRoot(); root
; root
= root
->olderShadowRoot())
1797 root
->removeAllEventListenersRecursively();
1801 using EventTargetDataMap
= WillBeHeapHashMap
<RawPtrWillBeWeakMember
<Node
>, OwnPtrWillBeMember
<EventTargetData
>>;
1802 static EventTargetDataMap
& eventTargetDataMap()
1804 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent
<EventTargetDataMap
>, map
, (adoptPtrWillBeNoop(new EventTargetDataMap())));
1808 EventTargetData
* Node::eventTargetData()
1810 return hasEventTargetData() ? eventTargetDataMap().get(this) : nullptr;
1813 EventTargetData
& Node::ensureEventTargetData()
1815 if (hasEventTargetData())
1816 return *eventTargetDataMap().get(this);
1817 ASSERT(!eventTargetDataMap().contains(this));
1818 setHasEventTargetData(true);
1819 OwnPtrWillBeRawPtr
<EventTargetData
> data
= adoptPtrWillBeNoop(new EventTargetData
);
1820 EventTargetData
* dataPtr
= data
.get();
1821 eventTargetDataMap().set(this, data
.release());
1826 void Node::clearEventTargetData()
1828 eventTargetDataMap().remove(this);
1830 setHasEventTargetData(false);
1835 WillBeHeapVector
<OwnPtrWillBeMember
<MutationObserverRegistration
>>* Node::mutationObserverRegistry()
1839 NodeMutationObserverData
* data
= rareData()->mutationObserverData();
1842 return &data
->registry
;
1845 WillBeHeapHashSet
<RawPtrWillBeMember
<MutationObserverRegistration
>>* Node::transientMutationObserverRegistry()
1849 NodeMutationObserverData
* data
= rareData()->mutationObserverData();
1852 return &data
->transientRegistry
;
1855 template<typename Registry
>
1856 static inline void collectMatchingObserversForMutation(WillBeHeapHashMap
<RawPtrWillBeMember
<MutationObserver
>, MutationRecordDeliveryOptions
>& observers
, Registry
* registry
, Node
& target
, MutationObserver::MutationType type
, const QualifiedName
* attributeName
)
1861 for (const auto& registration
: *registry
) {
1862 if (registration
->shouldReceiveMutationFrom(target
, type
, attributeName
)) {
1863 MutationRecordDeliveryOptions deliveryOptions
= registration
->deliveryOptions();
1864 WillBeHeapHashMap
<RawPtrWillBeMember
<MutationObserver
>, MutationRecordDeliveryOptions
>::AddResult result
= observers
.add(®istration
->observer(), deliveryOptions
);
1865 if (!result
.isNewEntry
)
1866 result
.storedValue
->value
|= deliveryOptions
;
1871 void Node::getRegisteredMutationObserversOfType(WillBeHeapHashMap
<RawPtrWillBeMember
<MutationObserver
>, MutationRecordDeliveryOptions
>& observers
, MutationObserver::MutationType type
, const QualifiedName
* attributeName
)
1873 ASSERT((type
== MutationObserver::Attributes
&& attributeName
) || !attributeName
);
1874 collectMatchingObserversForMutation(observers
, mutationObserverRegistry(), *this, type
, attributeName
);
1875 collectMatchingObserversForMutation(observers
, transientMutationObserverRegistry(), *this, type
, attributeName
);
1876 for (Node
* node
= parentNode(); node
; node
= node
->parentNode()) {
1877 collectMatchingObserversForMutation(observers
, node
->mutationObserverRegistry(), *this, type
, attributeName
);
1878 collectMatchingObserversForMutation(observers
, node
->transientMutationObserverRegistry(), *this, type
, attributeName
);
1882 void Node::registerMutationObserver(MutationObserver
& observer
, MutationObserverOptions options
, const HashSet
<AtomicString
>& attributeFilter
)
1884 MutationObserverRegistration
* registration
= nullptr;
1885 WillBeHeapVector
<OwnPtrWillBeMember
<MutationObserverRegistration
>>& registry
= ensureRareData().ensureMutationObserverData().registry
;
1886 for (size_t i
= 0; i
< registry
.size(); ++i
) {
1887 if (®istry
[i
]->observer() == &observer
) {
1888 registration
= registry
[i
].get();
1889 registration
->resetObservation(options
, attributeFilter
);
1893 if (!registration
) {
1894 registry
.append(MutationObserverRegistration::create(observer
, this, options
, attributeFilter
));
1895 registration
= registry
.last().get();
1898 document().addMutationObserverTypes(registration
->mutationTypes());
1901 void Node::unregisterMutationObserver(MutationObserverRegistration
* registration
)
1903 WillBeHeapVector
<OwnPtrWillBeMember
<MutationObserverRegistration
>>* registry
= mutationObserverRegistry();
1908 size_t index
= registry
->find(registration
);
1909 ASSERT(index
!= kNotFound
);
1910 if (index
== kNotFound
)
1913 // Deleting the registration may cause this node to be derefed, so we must make sure the Vector operation completes
1914 // before that, in case |this| is destroyed (see MutationObserverRegistration::m_registrationNodeKeepAlive).
1915 // FIXME: Simplify the registration/transient registration logic to make this understandable by humans.
1916 RefPtrWillBeRawPtr
<Node
> protect(this);
1918 // The explicit dispose() is needed to have the registration
1919 // object unregister itself promptly.
1920 registration
->dispose();
1922 registry
->remove(index
);
1925 void Node::registerTransientMutationObserver(MutationObserverRegistration
* registration
)
1927 ensureRareData().ensureMutationObserverData().transientRegistry
.add(registration
);
1930 void Node::unregisterTransientMutationObserver(MutationObserverRegistration
* registration
)
1932 WillBeHeapHashSet
<RawPtrWillBeMember
<MutationObserverRegistration
>>* transientRegistry
= transientMutationObserverRegistry();
1933 ASSERT(transientRegistry
);
1934 if (!transientRegistry
)
1937 ASSERT(transientRegistry
->contains(registration
));
1938 transientRegistry
->remove(registration
);
1941 void Node::notifyMutationObserversNodeWillDetach()
1943 if (!document().hasMutationObservers())
1946 for (Node
* node
= parentNode(); node
; node
= node
->parentNode()) {
1947 if (WillBeHeapVector
<OwnPtrWillBeMember
<MutationObserverRegistration
>>* registry
= node
->mutationObserverRegistry()) {
1948 const size_t size
= registry
->size();
1949 for (size_t i
= 0; i
< size
; ++i
)
1950 registry
->at(i
)->observedSubtreeNodeWillDetach(*this);
1953 if (WillBeHeapHashSet
<RawPtrWillBeMember
<MutationObserverRegistration
>>* transientRegistry
= node
->transientMutationObserverRegistry()) {
1954 for (auto& registration
: *transientRegistry
)
1955 registration
->observedSubtreeNodeWillDetach(*this);
1960 void Node::handleLocalEvents(Event
& event
)
1962 if (!hasEventTargetData())
1965 if (isDisabledFormControl(this) && event
.isMouseEvent())
1968 fireEventListeners(&event
);
1971 void Node::dispatchScopedEvent(PassRefPtrWillBeRawPtr
<Event
> event
)
1973 event
->setTrusted(true);
1974 EventDispatcher::dispatchScopedEvent(*this, event
->createMediator());
1977 bool Node::dispatchEventInternal(PassRefPtrWillBeRawPtr
<Event
> event
)
1979 return EventDispatcher::dispatchEvent(*this, event
->createMediator());
1982 void Node::dispatchSubtreeModifiedEvent()
1984 if (isInShadowTree())
1987 ASSERT(!EventDispatchForbiddenScope::isEventDispatchForbidden());
1989 if (!document().hasListenerType(Document::DOMSUBTREEMODIFIED_LISTENER
))
1992 dispatchScopedEvent(MutationEvent::create(EventTypeNames::DOMSubtreeModified
, true));
1995 bool Node::dispatchDOMActivateEvent(int detail
, PassRefPtrWillBeRawPtr
<Event
> underlyingEvent
)
1997 ASSERT(!EventDispatchForbiddenScope::isEventDispatchForbidden());
1998 RefPtrWillBeRawPtr
<UIEvent
> event
= UIEvent::create(EventTypeNames::DOMActivate
, true, true, document().domWindow(), detail
);
1999 event
->setUnderlyingEvent(underlyingEvent
);
2000 dispatchScopedEvent(event
);
2001 return event
->defaultHandled();
2004 bool Node::dispatchKeyEvent(const PlatformKeyboardEvent
& nativeEvent
)
2006 return dispatchEvent(KeyboardEvent::create(nativeEvent
, document().domWindow()));
2009 bool Node::dispatchMouseEvent(const PlatformMouseEvent
& nativeEvent
, const AtomicString
& eventType
,
2010 int detail
, Node
* relatedTarget
)
2012 RefPtrWillBeRawPtr
<MouseEvent
> event
= MouseEvent::create(eventType
, document().domWindow(), nativeEvent
, detail
, relatedTarget
);
2013 return dispatchEvent(event
);
2016 bool Node::dispatchGestureEvent(const PlatformGestureEvent
& event
)
2018 RefPtrWillBeRawPtr
<GestureEvent
> gestureEvent
= GestureEvent::create(document().domWindow(), event
);
2019 if (!gestureEvent
.get())
2021 return dispatchEvent(gestureEvent
);
2024 void Node::dispatchSimulatedClick(Event
* underlyingEvent
, SimulatedClickMouseEventOptions eventOptions
, SimulatedClickCreationScope scope
)
2026 EventDispatcher::dispatchSimulatedClick(*this, underlyingEvent
, eventOptions
, scope
);
2029 bool Node::dispatchWheelEvent(const PlatformWheelEvent
& event
)
2031 return dispatchEvent(WheelEvent::create(event
, document().domWindow()));
2034 void Node::dispatchInputEvent()
2036 dispatchScopedEvent(Event::createBubble(EventTypeNames::input
));
2039 void Node::defaultEventHandler(Event
* event
)
2041 if (event
->target() != this)
2043 const AtomicString
& eventType
= event
->type();
2044 if (eventType
== EventTypeNames::keydown
|| eventType
== EventTypeNames::keypress
) {
2045 if (event
->isKeyboardEvent()) {
2046 if (LocalFrame
* frame
= document().frame())
2047 frame
->eventHandler().defaultKeyboardEventHandler(toKeyboardEvent(event
));
2049 } else if (eventType
== EventTypeNames::click
) {
2050 int detail
= event
->isUIEvent() ? static_cast<UIEvent
*>(event
)->detail() : 0;
2051 if (dispatchDOMActivateEvent(detail
, event
))
2052 event
->setDefaultHandled();
2053 } else if (eventType
== EventTypeNames::contextmenu
) {
2054 if (Page
* page
= document().page())
2055 page
->contextMenuController().handleContextMenuEvent(event
);
2056 } else if (eventType
== EventTypeNames::textInput
) {
2057 if (event
->hasInterface(EventNames::TextEvent
)) {
2058 if (LocalFrame
* frame
= document().frame())
2059 frame
->eventHandler().defaultTextInputEventHandler(toTextEvent(event
));
2062 } else if (eventType
== EventTypeNames::mousedown
&& event
->isMouseEvent()) {
2063 MouseEvent
* mouseEvent
= toMouseEvent(event
);
2064 if (mouseEvent
->button() == MiddleButton
) {
2065 if (enclosingLinkEventParentOrSelf())
2068 // Avoid that canBeScrolledAndHasScrollableArea changes layout tree
2070 // FIXME: We should avoid synchronous layout if possible. We can
2071 // remove this synchronous layout if we avoid synchronous layout in
2072 // LayoutTextControlSingleLine::scrollHeight
2073 document().updateLayoutIgnorePendingStylesheets();
2074 LayoutObject
* layoutObject
= this->layoutObject();
2075 while (layoutObject
&& (!layoutObject
->isBox() || !toLayoutBox(layoutObject
)->canBeScrolledAndHasScrollableArea()))
2076 layoutObject
= layoutObject
->parent();
2079 if (LocalFrame
* frame
= document().frame())
2080 frame
->eventHandler().startPanScrolling(layoutObject
);
2084 } else if ((eventType
== EventTypeNames::wheel
|| eventType
== EventTypeNames::mousewheel
) && event
->hasInterface(EventNames::WheelEvent
)) {
2085 WheelEvent
* wheelEvent
= toWheelEvent(event
);
2087 // If we don't have a layoutObject, send the wheel event to the first node we find with a layoutObject.
2088 // This is needed for <option> and <optgroup> elements so that <select>s get a wheel scroll.
2089 Node
* startNode
= this;
2090 while (startNode
&& !startNode
->layoutObject())
2091 startNode
= startNode
->parentOrShadowHostNode();
2093 if (startNode
&& startNode
->layoutObject()) {
2094 if (LocalFrame
* frame
= document().frame())
2095 frame
->eventHandler().defaultWheelEventHandler(startNode
, wheelEvent
);
2097 } else if (event
->type() == EventTypeNames::webkitEditableContentChanged
) {
2098 dispatchInputEvent();
2102 void Node::willCallDefaultEventHandler(const Event
&)
2106 bool Node::willRespondToMouseMoveEvents()
2108 if (isDisabledFormControl(this))
2110 return hasEventListeners(EventTypeNames::mousemove
) || hasEventListeners(EventTypeNames::mouseover
) || hasEventListeners(EventTypeNames::mouseout
);
2113 bool Node::willRespondToMouseClickEvents()
2115 if (isDisabledFormControl(this))
2117 return isContentEditable(UserSelectAllIsAlwaysNonEditable
) || hasEventListeners(EventTypeNames::mouseup
) || hasEventListeners(EventTypeNames::mousedown
) || hasEventListeners(EventTypeNames::click
) || hasEventListeners(EventTypeNames::DOMActivate
);
2120 bool Node::willRespondToTouchEvents()
2122 if (isDisabledFormControl(this))
2124 return hasEventListeners(EventTypeNames::touchstart
) || hasEventListeners(EventTypeNames::touchmove
) || hasEventListeners(EventTypeNames::touchcancel
) || hasEventListeners(EventTypeNames::touchend
);
2128 // This is here for inlining
2129 inline void TreeScope::removedLastRefToScope()
2131 ASSERT_WITH_SECURITY_IMPLICATION(!deletionHasBegun());
2132 if (m_guardRefCount
) {
2133 // If removing a child removes the last self-only ref, we don't
2134 // want the scope to be destructed until after
2135 // removeDetachedChildren returns, so we guard ourselves with an
2136 // extra self-only ref.
2140 // We need to do this right now since guardDeref() can delete this.
2141 rootNode().m_inRemovedLastRefFunction
= false;
2146 rootNode().m_inRemovedLastRefFunction
= false;
2148 #if ENABLE(SECURITY_ASSERT)
2155 // It's important not to inline removedLastRef, because we don't want to inline the code to
2156 // delete a Node at each deref call site.
2157 void Node::removedLastRef()
2159 // An explicit check for Document here is better than a virtual function since it is
2160 // faster for non-Document nodes, and because the call to removedLastRef that is inlined
2161 // at all deref call sites is smaller if it's a non-virtual function.
2162 if (isTreeScope()) {
2163 treeScope().removedLastRefToScope();
2167 #if ENABLE(SECURITY_ASSERT)
2168 m_deletionHasBegun
= true;
2174 unsigned Node::connectedSubframeCount() const
2176 return hasRareData() ? rareData()->connectedSubframeCount() : 0;
2179 void Node::incrementConnectedSubframeCount(unsigned amount
)
2181 ASSERT(isContainerNode());
2182 ensureRareData().incrementConnectedSubframeCount(amount
);
2185 void Node::decrementConnectedSubframeCount(unsigned amount
)
2187 rareData()->decrementConnectedSubframeCount(amount
);
2190 void Node::updateAncestorConnectedSubframeCountForInsertion() const
2192 unsigned count
= connectedSubframeCount();
2197 for (Node
* node
= parentOrShadowHostNode(); node
; node
= node
->parentOrShadowHostNode())
2198 node
->incrementConnectedSubframeCount(count
);
2201 PassRefPtrWillBeRawPtr
<StaticNodeList
> Node::getDestinationInsertionPoints()
2203 updateDistribution();
2204 WillBeHeapVector
<RawPtrWillBeMember
<InsertionPoint
>, 8> insertionPoints
;
2205 collectDestinationInsertionPoints(*this, insertionPoints
);
2206 WillBeHeapVector
<RefPtrWillBeMember
<Node
>> filteredInsertionPoints
;
2207 for (size_t i
= 0; i
< insertionPoints
.size(); ++i
) {
2208 InsertionPoint
* insertionPoint
= insertionPoints
[i
];
2209 ASSERT(insertionPoint
->containingShadowRoot());
2210 if (!insertionPoint
->containingShadowRoot()->isOpen())
2212 filteredInsertionPoints
.append(insertionPoint
);
2214 return StaticNodeList::adopt(filteredInsertionPoints
);
2217 void Node::setFocus(bool flag
)
2219 document().userActionElements().setFocused(this, flag
);
2222 void Node::setActive(bool flag
)
2224 document().userActionElements().setActive(this, flag
);
2227 void Node::setHovered(bool flag
)
2229 document().userActionElements().setHovered(this, flag
);
2232 bool Node::isUserActionElementActive() const
2234 ASSERT(isUserActionElement());
2235 return document().userActionElements().isActive(this);
2238 bool Node::isUserActionElementInActiveChain() const
2240 ASSERT(isUserActionElement());
2241 return document().userActionElements().isInActiveChain(this);
2244 bool Node::isUserActionElementHovered() const
2246 ASSERT(isUserActionElement());
2247 return document().userActionElements().isHovered(this);
2250 bool Node::isUserActionElementFocused() const
2252 ASSERT(isUserActionElement());
2253 return document().userActionElements().isFocused(this);
2256 void Node::setCustomElementState(CustomElementState newState
)
2258 CustomElementState oldState
= customElementState();
2261 case NotCustomElement
:
2262 ASSERT_NOT_REACHED(); // Everything starts in this state
2265 case WaitingForUpgrade
:
2266 ASSERT(NotCustomElement
== oldState
);
2270 ASSERT(WaitingForUpgrade
== oldState
);
2274 ASSERT(isHTMLElement() || isSVGElement());
2275 setFlag(CustomElementFlag
);
2276 setFlag(newState
== Upgraded
, CustomElementUpgradedFlag
);
2278 if (oldState
== NotCustomElement
|| newState
== Upgraded
)
2279 setNeedsStyleRecalc(SubtreeStyleChange
, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass
, StyleChangeExtraData::Unresolved
)); // :unresolved has changed
2285 visitor
->trace(m_parentOrShadowHostNode
);
2286 visitor
->trace(m_previous
);
2287 visitor
->trace(m_next
);
2288 // rareData() and m_data.m_layoutObject share their storage. We have to trace
2289 // only one of them.
2291 visitor
->trace(rareData());
2293 visitor
->trace(m_treeScope
);
2295 EventTarget::trace(visitor
);
2298 unsigned Node::lengthOfContents() const
2300 // This switch statement must be consistent with that of Range::processContentsBetweenOffsets.
2301 switch (nodeType()) {
2302 case Node::TEXT_NODE
:
2303 case Node::CDATA_SECTION_NODE
:
2304 case Node::COMMENT_NODE
:
2305 return toCharacterData(this)->length();
2306 case Node::PROCESSING_INSTRUCTION_NODE
:
2307 return toProcessingInstruction(this)->data().length();
2308 case Node::ELEMENT_NODE
:
2309 case Node::DOCUMENT_NODE
:
2310 case Node::DOCUMENT_FRAGMENT_NODE
:
2311 return toContainerNode(this)->countChildren();
2312 case Node::ATTRIBUTE_NODE
:
2313 case Node::DOCUMENT_TYPE_NODE
:
2316 ASSERT_NOT_REACHED();
2320 v8::Local
<v8::Object
> Node::wrap(v8::Isolate
* isolate
, v8::Local
<v8::Object
> creationContext
)
2322 // It's possible that no one except for the new wrapper owns this object at
2323 // this moment, so we have to prevent GC to collect this object until the
2324 // object gets associated with the wrapper.
2325 RefPtrWillBeRawPtr
<Node
> protect(this);
2327 ASSERT(!DOMDataStore::containsWrapper(this, isolate
));
2329 const WrapperTypeInfo
* wrapperType
= wrapperTypeInfo();
2331 v8::Local
<v8::Object
> wrapper
= V8DOMWrapper::createWrapper(isolate
, creationContext
, wrapperType
, this);
2332 if (UNLIKELY(wrapper
.IsEmpty()))
2335 wrapperType
->installConditionallyEnabledProperties(wrapper
, isolate
);
2336 return associateWithWrapper(isolate
, wrapperType
, wrapper
);
2339 v8::Local
<v8::Object
> Node::associateWithWrapper(v8::Isolate
* isolate
, const WrapperTypeInfo
* wrapperType
, v8::Local
<v8::Object
> wrapper
)
2341 return V8DOMWrapper::associateObjectWithWrapper(isolate
, this, wrapperType
, wrapper
);
2344 } // namespace blink
2348 void showNode(const blink::Node
* node
)
2353 fprintf(stderr
, "Cannot showNode for (nil)\n");
2356 void showTree(const blink::Node
* node
)
2359 node
->showTreeForThis();
2361 fprintf(stderr
, "Cannot showTree for (nil)\n");
2364 void showNodePath(const blink::Node
* node
)
2367 node
->showNodePathForThis();
2369 fprintf(stderr
, "Cannot showNodePath for (nil)\n");