1 /*
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
6 * rights reserved.
7 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
8 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved.
9 * (http://www.torchmobile.com/)
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public License
22 * along with this library; see the file COPYING.LIB. If not, write to
23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
25 */
26
27 #include "third_party/blink/renderer/core/dom/node.h"
28
29 #include <algorithm>
30
31 #include "third_party/blink/public/mojom/input/focus_type.mojom-blink.h"
32 #include "third_party/blink/renderer/bindings/core/v8/node_or_string_or_trusted_script.h"
33 #include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_script.h"
34 #include "third_party/blink/renderer/bindings/core/v8/v8_get_root_node_options.h"
35 #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
36 #include "third_party/blink/renderer/core/animation/scroll_timeline.h"
37 #include "third_party/blink/renderer/core/css/css_selector.h"
38 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
39 #include "third_party/blink/renderer/core/css/style_change_reason.h"
40 #include "third_party/blink/renderer/core/css/style_engine.h"
41 #include "third_party/blink/renderer/core/display_lock/display_lock_document_state.h"
42 #include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
43 #include "third_party/blink/renderer/core/dom/attr.h"
44 #include "third_party/blink/renderer/core/dom/attribute.h"
45 #include "third_party/blink/renderer/core/dom/child_list_mutation_scope.h"
46 #include "third_party/blink/renderer/core/dom/child_node_list.h"
47 #include "third_party/blink/renderer/core/dom/document.h"
48 #include "third_party/blink/renderer/core/dom/document_fragment.h"
49 #include "third_party/blink/renderer/core/dom/document_type.h"
50 #include "third_party/blink/renderer/core/dom/dom_node_ids.h"
51 #include "third_party/blink/renderer/core/dom/element.h"
52 #include "third_party/blink/renderer/core/dom/element_rare_data.h"
53 #include "third_party/blink/renderer/core/dom/element_traversal.h"
54 #include "third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.h"
55 #include "third_party/blink/renderer/core/dom/events/event.h"
56 #include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h"
57 #include "third_party/blink/renderer/core/dom/events/event_dispatcher.h"
58 #include "third_party/blink/renderer/core/dom/events/event_listener.h"
59 #include "third_party/blink/renderer/core/dom/events/event_path.h"
60 #include "third_party/blink/renderer/core/dom/flat_tree_node_data.h"
61 #include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
62 #include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
63 #include "third_party/blink/renderer/core/dom/mutation_observer_registration.h"
64 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
65 #include "third_party/blink/renderer/core/dom/node_lists_node_data.h"
66 #include "third_party/blink/renderer/core/dom/node_rare_data.h"
67 #include "third_party/blink/renderer/core/dom/node_traversal.h"
68 #include "third_party/blink/renderer/core/dom/processing_instruction.h"
69 #include "third_party/blink/renderer/core/dom/range.h"
70 #include "third_party/blink/renderer/core/dom/shadow_root.h"
71 #include "third_party/blink/renderer/core/dom/slot_assignment.h"
72 #include "third_party/blink/renderer/core/dom/slot_assignment_engine.h"
73 #include "third_party/blink/renderer/core/dom/static_node_list.h"
74 #include "third_party/blink/renderer/core/dom/template_content_document_fragment.h"
75 #include "third_party/blink/renderer/core/dom/text.h"
76 #include "third_party/blink/renderer/core/dom/tree_scope_adopter.h"
77 #include "third_party/blink/renderer/core/dom/user_action_element_set.h"
78 #include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
79 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
80 #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
81 #include "third_party/blink/renderer/core/events/event_util.h"
82 #include "third_party/blink/renderer/core/events/gesture_event.h"
83 #include "third_party/blink/renderer/core/events/input_event.h"
84 #include "third_party/blink/renderer/core/events/keyboard_event.h"
85 #include "third_party/blink/renderer/core/events/mouse_event.h"
86 #include "third_party/blink/renderer/core/events/mutation_event.h"
87 #include "third_party/blink/renderer/core/events/pointer_event.h"
88 #include "third_party/blink/renderer/core/events/pointer_event_factory.h"
89 #include "third_party/blink/renderer/core/events/text_event.h"
90 #include "third_party/blink/renderer/core/events/touch_event.h"
91 #include "third_party/blink/renderer/core/events/ui_event.h"
92 #include "third_party/blink/renderer/core/events/wheel_event.h"
93 #include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
94 #include "third_party/blink/renderer/core/frame/event_handler_registry.h"
95 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
96 #include "third_party/blink/renderer/core/frame/local_frame.h"
97 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
98 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
99 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
100 #include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
101 #include "third_party/blink/renderer/core/html/custom/custom_element.h"
102 #include "third_party/blink/renderer/core/html/html_dialog_element.h"
103 #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
104 #include "third_party/blink/renderer/core/html/html_slot_element.h"
105 #include "third_party/blink/renderer/core/html_names.h"
106 #include "third_party/blink/renderer/core/input/event_handler.h"
107 #include "third_party/blink/renderer/core/input/input_device_capabilities.h"
108 #include "third_party/blink/renderer/core/layout/layout_box.h"
109 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
110 #include "third_party/blink/renderer/core/layout/layout_shift_tracker.h"
111 #include "third_party/blink/renderer/core/layout/layout_view.h"
112 #include "third_party/blink/renderer/core/mathml_names.h"
113 #include "third_party/blink/renderer/core/page/context_menu_controller.h"
114 #include "third_party/blink/renderer/core/page/page.h"
115 #include "third_party/blink/renderer/core/page/scrolling/scroll_customization_callbacks.h"
116 #include "third_party/blink/renderer/core/page/scrolling/scroll_state.h"
117 #include "third_party/blink/renderer/core/page/scrolling/scroll_state_callback.h"
118 #include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
119 #include "third_party/blink/renderer/core/paint/paint_layer.h"
120 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
121 #include "third_party/blink/renderer/core/probe/core_probes.h"
122 #include "third_party/blink/renderer/core/svg/graphics/svg_image.h"
123 #include "third_party/blink/renderer/core/svg/svg_element.h"
124 #include "third_party/blink/renderer/core/trustedtypes/trusted_script.h"
125 #include "third_party/blink/renderer/platform/bindings/dom_data_store.h"
126 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
127 #include "third_party/blink/renderer/platform/bindings/microtask.h"
128 #include "third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h"
129 #include "third_party/blink/renderer/platform/heap/heap.h"
130 #include "third_party/blink/renderer/platform/instrumentation/instance_counters.h"
131 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
132 #include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h"
133 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
134 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
135 #include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
136 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
137 #include "third_party/blink/renderer/platform/wtf/size_assertions.h"
138 #include "third_party/blink/renderer/platform/wtf/text/character_visitor.h"
139 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
140 #include "third_party/blink/renderer/platform/wtf/vector.h"
141
142 namespace blink {
143
144 namespace {
145
146 // We need to retain the scroll customization callbacks until the element
147 // they're associated with is destroyed. It would be simplest if the callbacks
148 // could be stored in ElementRareData, but we can't afford the space increase.
149 // Instead, keep the scroll customization callbacks here. The other option would
150 // be to store these callbacks on the Page or document, but that necessitates a
151 // bunch more logic for transferring the callbacks between Pages when elements
152 // are moved around.
GetScrollCustomizationCallbacks()153 ScrollCustomizationCallbacks& GetScrollCustomizationCallbacks() {
154 DEFINE_STATIC_LOCAL(Persistent<ScrollCustomizationCallbacks>,
155 scroll_customization_callbacks,
156 (MakeGarbageCollected<ScrollCustomizationCallbacks>()));
157 return *scroll_customization_callbacks;
158 }
159
160 // TODO(crbug.com/545926): Unsafe hack to avoid triggering the
161 // ThreadRestrictionVerifier on StringImpl. This should be fixed completely, and
162 // we should always avoid accessing these strings from the impl thread.
163 // Currently code that calls into this method from the impl thread tries to make
164 // sure that the main thread is not running at this time.
AppendUnsafe(StringBuilder & builder,const String & off_thread_string)165 void AppendUnsafe(StringBuilder& builder, const String& off_thread_string) {
166 StringImpl* impl = off_thread_string.Impl();
167 if (impl) {
168 WTF::VisitCharacters(*impl, [&](const auto* chars, unsigned length) {
169 builder.Append(chars, length);
170 });
171 }
172 }
173
174 } // namespace
175
176 using ReattachHookScope = LayoutShiftTracker::ReattachHookScope;
177
178 struct SameSizeAsNode : EventTarget {
179 uint32_t node_flags_;
180 Member<void*> willbe_member_[4];
181 Member<NodeData> member_;
182 #if !DCHECK_IS_ON()
183 // Increasing size of Member increases size of Node.
184 ASSERT_SIZE(Member<NodeData>, void*);
185 #endif // !DCHECK_IS_ON()
186 };
187
188 ASSERT_SIZE(Node, SameSizeAsNode);
189
190 #if DUMP_NODE_STATISTICS
191 using WeakNodeSet = HeapHashSet<WeakMember<Node>>;
liveNodeSet()192 static WeakNodeSet& liveNodeSet() {
193 DEFINE_STATIC_LOCAL(WeakNodeSet, set, (new WeakNodeSet));
194 return set;
195 }
196 #endif
197
DumpStatistics()198 void Node::DumpStatistics() {
199 #if DUMP_NODE_STATISTICS
200 size_t nodesWithRareData = 0;
201
202 size_t elementNodes = 0;
203 size_t attrNodes = 0;
204 size_t textNodes = 0;
205 size_t cdataNodes = 0;
206 size_t commentNodes = 0;
207 size_t piNodes = 0;
208 size_t documentNodes = 0;
209 size_t docTypeNodes = 0;
210 size_t fragmentNodes = 0;
211 size_t shadowRootNodes = 0;
212
213 HashMap<String, size_t> perTagCount;
214
215 size_t attributes = 0;
216 size_t elementsWithAttributeStorage = 0;
217 size_t elementsWithRareData = 0;
218 size_t elementsWithNamedNodeMap = 0;
219
220 {
221 ScriptForbiddenScope forbidScriptDuringRawIteration;
222 for (Node* node : liveNodeSet()) {
223 if (node->hasRareData()) {
224 ++nodesWithRareData;
225 if (auto* element = DynamicTo<Element>(node)) {
226 ++elementsWithRareData;
227 if (element->hasNamedNodeMap())
228 ++elementsWithNamedNodeMap;
229 }
230 }
231
232 switch (node->getNodeType()) {
233 case kElementNode: {
234 ++elementNodes;
235
236 // Tag stats
237 auto* element = To<Element>(node);
238 HashMap<String, size_t>::AddResult result =
239 perTagCount.add(element->tagName(), 1);
240 if (!result.isNewEntry)
241 result.storedValue->value++;
242
243 size_t attributeCount = element->attributesWithoutUpdate().size();
244 if (attributeCount) {
245 attributes += attributeCount;
246 ++elementsWithAttributeStorage;
247 }
248 break;
249 }
250 case kAttributeNode: {
251 ++attrNodes;
252 break;
253 }
254 case kTextNode: {
255 ++textNodes;
256 break;
257 }
258 case kCdataSectionNode: {
259 ++cdataNodes;
260 break;
261 }
262 case kCommentNode: {
263 ++commentNodes;
264 break;
265 }
266 case kProcessingInstructionNode: {
267 ++piNodes;
268 break;
269 }
270 case kDocumentNode: {
271 ++documentNodes;
272 break;
273 }
274 case kDocumentTypeNode: {
275 ++docTypeNodes;
276 break;
277 }
278 case kDocumentFragmentNode: {
279 if (node->isShadowRoot())
280 ++shadowRootNodes;
281 else
282 ++fragmentNodes;
283 break;
284 }
285 }
286 }
287 }
288
289 std::stringstream perTagStream;
290 for (const auto& entry : perTagCount)
291 perTagStream << " Number of <" << entry.key.utf8().data()
292 << "> tags: " << entry.value << "\n";
293
294 LOG(INFO) << "\n"
295 << "Number of Nodes: " << liveNodeSet().size() << "\n"
296 << "Number of Nodes with RareData: " << nodesWithRareData << "\n\n"
297
298 << "NodeType distribution:\n"
299 << " Number of Element nodes: " << elementNodes << "\n"
300 << " Number of Attribute nodes: " << attrNodes << "\n"
301 << " Number of Text nodes: " << textNodes << "\n"
302 << " Number of CDATASection nodes: " << cdataNodes << "\n"
303 << " Number of Comment nodes: " << commentNodes << "\n"
304 << " Number of ProcessingInstruction nodes: " << piNodes << "\n"
305 << " Number of Document nodes: " << documentNodes << "\n"
306 << " Number of DocumentType nodes: " << docTypeNodes << "\n"
307 << " Number of DocumentFragment nodes: " << fragmentNodes << "\n"
308 << " Number of ShadowRoot nodes: " << shadowRootNodes << "\n"
309
310 << "Element tag name distibution:\n"
311 << perTagStream.str()
312
313 << "Attributes:\n"
314 << " Number of Attributes (non-Node and Node): " << attributes
315 << " x " << sizeof(Attribute) << "Bytes\n"
316 << " Number of Elements with attribute storage: "
317 << elementsWithAttributeStorage << " x " << sizeof(ElementData)
318 << "Bytes\n"
319 << " Number of Elements with RareData: " << elementsWithRareData
320 << "\n"
321 << " Number of Elements with NamedNodeMap: "
322 << elementsWithNamedNodeMap << " x " << sizeof(NamedNodeMap)
323 << "Bytes";
324 #endif
325 }
326
TrackForDebugging()327 void Node::TrackForDebugging() {
328 #if DUMP_NODE_STATISTICS
329 liveNodeSet().add(this);
330 #endif
331 }
332
Node(TreeScope * tree_scope,ConstructionType type)333 Node::Node(TreeScope* tree_scope, ConstructionType type)
334 : node_flags_(type),
335 parent_or_shadow_host_node_(nullptr),
336 tree_scope_(tree_scope),
337 previous_(nullptr),
338 next_(nullptr),
339 data_(&NodeRenderingData::SharedEmptyData()) {
340 DCHECK(tree_scope_ || type == kCreateDocument || type == kCreateShadowRoot);
341 #if !defined(NDEBUG) || (defined(DUMP_NODE_STATISTICS) && DUMP_NODE_STATISTICS)
342 TrackForDebugging();
343 #endif
344 InstanceCounters::IncrementCounter(InstanceCounters::kNodeCounter);
345 // Document is required for probe sink.
346 if (tree_scope_)
347 probe::NodeCreated(this);
348 }
349
~Node()350 Node::~Node() {
351 InstanceCounters::DecrementCounter(InstanceCounters::kNodeCounter);
352 }
353
CreateRareData()354 NodeRareData& Node::CreateRareData() {
355 if (IsElementNode()) {
356 data_ = MakeGarbageCollected<ElementRareData>(DataAsNodeRenderingData());
357 } else {
358 data_ = MakeGarbageCollected<NodeRareData>(DataAsNodeRenderingData());
359 }
360
361 DCHECK(data_);
362 SetFlag(kHasRareDataFlag);
363 return *RareData();
364 }
365
ToNode()366 Node* Node::ToNode() {
367 return this;
368 }
369
nodeValue() const370 String Node::nodeValue() const {
371 return String();
372 }
373
setNodeValue(const String &)374 void Node::setNodeValue(const String&) {
375 // By default, setting nodeValue has no effect.
376 }
377
parentNode() const378 ContainerNode* Node::parentNode() const {
379 return IsShadowRoot() ? nullptr : ParentOrShadowHostNode();
380 }
381
childNodes()382 NodeList* Node::childNodes() {
383 auto* this_node = DynamicTo<ContainerNode>(this);
384 if (this_node)
385 return EnsureRareData().EnsureNodeLists().EnsureChildNodeList(*this_node);
386 return EnsureRareData().EnsureNodeLists().EnsureEmptyChildNodeList(*this);
387 }
388
PseudoAwarePreviousSibling() const389 Node* Node::PseudoAwarePreviousSibling() const {
390 Element* parent = parentElement();
391 if (!parent || previousSibling())
392 return previousSibling();
393 switch (GetPseudoId()) {
394 case kPseudoIdAfter:
395 if (Node* previous = parent->lastChild())
396 return previous;
397 FALLTHROUGH;
398 case kPseudoIdNone:
399 if (Node* previous = parent->GetPseudoElement(kPseudoIdBefore))
400 return previous;
401 FALLTHROUGH;
402 case kPseudoIdBefore:
403 if (Node* previous = parent->GetPseudoElement(kPseudoIdMarker))
404 return previous;
405 FALLTHROUGH;
406 case kPseudoIdMarker:
407 break;
408 default:
409 NOTREACHED();
410 }
411 return nullptr;
412 }
413
PseudoAwareNextSibling() const414 Node* Node::PseudoAwareNextSibling() const {
415 Element* parent = parentElement();
416 if (!parent || nextSibling())
417 return nextSibling();
418 switch (GetPseudoId()) {
419 case kPseudoIdMarker:
420 if (Node* next = parent->GetPseudoElement(kPseudoIdBefore))
421 return next;
422 FALLTHROUGH;
423 case kPseudoIdBefore:
424 if (parent->HasChildren())
425 return parent->firstChild();
426 FALLTHROUGH;
427 case kPseudoIdNone:
428 if (Node* next = parent->GetPseudoElement(kPseudoIdAfter))
429 return next;
430 FALLTHROUGH;
431 case kPseudoIdAfter:
432 break;
433 default:
434 NOTREACHED();
435 }
436 return nullptr;
437 }
438
PseudoAwareFirstChild() const439 Node* Node::PseudoAwareFirstChild() const {
440 if (const auto* current_element = DynamicTo<Element>(this)) {
441 if (Node* first = current_element->GetPseudoElement(kPseudoIdMarker))
442 return first;
443 if (Node* first = current_element->GetPseudoElement(kPseudoIdBefore))
444 return first;
445 if (Node* first = current_element->firstChild())
446 return first;
447 return current_element->GetPseudoElement(kPseudoIdAfter);
448 }
449
450 return firstChild();
451 }
452
PseudoAwareLastChild() const453 Node* Node::PseudoAwareLastChild() const {
454 if (const auto* current_element = DynamicTo<Element>(this)) {
455 if (Node* last = current_element->GetPseudoElement(kPseudoIdAfter))
456 return last;
457 if (Node* last = current_element->lastChild())
458 return last;
459 if (Node* last = current_element->GetPseudoElement(kPseudoIdBefore))
460 return last;
461 return current_element->GetPseudoElement(kPseudoIdMarker);
462 }
463
464 return lastChild();
465 }
466
TreeRoot() const467 Node& Node::TreeRoot() const {
468 if (IsInTreeScope())
469 return ContainingTreeScope().RootNode();
470 const Node* node = this;
471 while (node->parentNode())
472 node = node->parentNode();
473 return const_cast<Node&>(*node);
474 }
475
getRootNode(const GetRootNodeOptions * options) const476 Node* Node::getRootNode(const GetRootNodeOptions* options) const {
477 return (options->hasComposed() && options->composed())
478 ? &ShadowIncludingRoot()
479 : &TreeRoot();
480 }
481
setDistributeScroll(V8ScrollStateCallback * scroll_state_callback,const String & native_scroll_behavior)482 void Node::setDistributeScroll(V8ScrollStateCallback* scroll_state_callback,
483 const String& native_scroll_behavior) {
484 GetScrollCustomizationCallbacks().SetDistributeScroll(
485 this, ScrollStateCallbackV8Impl::Create(scroll_state_callback,
486 native_scroll_behavior));
487 }
488
setApplyScroll(V8ScrollStateCallback * scroll_state_callback,const String & native_scroll_behavior)489 void Node::setApplyScroll(V8ScrollStateCallback* scroll_state_callback,
490 const String& native_scroll_behavior) {
491 SetApplyScroll(ScrollStateCallbackV8Impl::Create(scroll_state_callback,
492 native_scroll_behavior));
493 }
494
SetApplyScroll(ScrollStateCallback * scroll_state_callback)495 void Node::SetApplyScroll(ScrollStateCallback* scroll_state_callback) {
496 GetScrollCustomizationCallbacks().SetApplyScroll(this, scroll_state_callback);
497 }
498
RemoveApplyScroll()499 void Node::RemoveApplyScroll() {
500 GetScrollCustomizationCallbacks().RemoveApplyScroll(this);
501 }
502
GetApplyScroll()503 ScrollStateCallback* Node::GetApplyScroll() {
504 return GetScrollCustomizationCallbacks().GetApplyScroll(this);
505 }
506
NativeDistributeScroll(ScrollState & scroll_state)507 void Node::NativeDistributeScroll(ScrollState& scroll_state) {
508 if (scroll_state.FullyConsumed())
509 return;
510
511 scroll_state.distributeToScrollChainDescendant();
512
513 // The scroll doesn't propagate, and we're currently scrolling an element
514 // other than this one, prevent the scroll from propagating to this element.
515 if (scroll_state.DeltaConsumedForScrollSequence() &&
516 scroll_state.CurrentNativeScrollingNode() != this) {
517 return;
518 }
519
520 const double delta_x = scroll_state.deltaX();
521 const double delta_y = scroll_state.deltaY();
522
523 CallApplyScroll(scroll_state);
524
525 if (delta_x != scroll_state.deltaX() || delta_y != scroll_state.deltaY())
526 scroll_state.SetCurrentNativeScrollingNode(this);
527 }
528
NativeApplyScroll(ScrollState & scroll_state)529 void Node::NativeApplyScroll(ScrollState& scroll_state) {
530 if (!GetLayoutObject())
531 return;
532
533 // All elements in the scroll chain should be boxes. However, in a scroll
534 // gesture sequence, the scroll chain is only computed on GestureScrollBegin.
535 // The type of layout object of the nodes in the scroll chain can change
536 // between GestureScrollUpdate and GestureScrollBegin (e.g. from script
537 // setting one of the nodes to display:inline). If there is no box there will
538 // not be a scrollable area to scroll, so just return.
539 if (!GetLayoutObject()->IsBox())
540 return;
541
542 if (scroll_state.FullyConsumed())
543 return;
544
545 FloatSize delta(scroll_state.deltaX(), scroll_state.deltaY());
546
547 if (delta.IsZero())
548 return;
549
550 // TODO: This should use updateStyleAndLayoutForNode.
551 GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kScroll);
552
553 ScrollableArea* scrollable_area =
554 ScrollableArea::GetForScrolling(To<LayoutBox>(GetLayoutObject()));
555 if (!scrollable_area)
556 return;
557 LayoutBox* box_to_scroll = scrollable_area->GetLayoutBox();
558
559 // TODO(bokan): This is a hack to fix https://crbug.com/977954. If we have a
560 // non-default root scroller, scrolling from one of its siblings or a fixed
561 // element will chain up to the root node without passing through the root
562 // scroller. This should scroll the visual viewport (so we can still pan
563 // while zoomed) but not by using the RootFrameViewport, which would cause
564 // scrolling in the root scroller element. Implementing this on the main
565 // thread is awkward since we assume only Nodes are scrollable but the
566 // VisualViewport isn't a Node. See LTHI::ApplyScroll for the equivalent
567 // behavior in CC.
568 bool also_scroll_visual_viewport = GetDocument().GetFrame() &&
569 GetDocument().GetFrame()->IsMainFrame() &&
570 IsA<LayoutView>(box_to_scroll);
571 DCHECK(!also_scroll_visual_viewport ||
572 !box_to_scroll->IsGlobalRootScroller());
573
574 ScrollResult result =
575 scrollable_area->UserScroll(scroll_state.delta_granularity(), delta,
576 ScrollableArea::ScrollCallback());
577
578 // Also try scrolling the visual viewport if we're at the end of the scroll
579 // chain.
580 if (!result.DidScroll() && also_scroll_visual_viewport) {
581 result = GetDocument().GetPage()->GetVisualViewport().UserScroll(
582 scroll_state.delta_granularity(), delta,
583 ScrollableArea::ScrollCallback());
584 }
585
586 if (!result.DidScroll())
587 return;
588
589 // FIXME: Native scrollers should only consume the scroll they
590 // apply. See crbug.com/457765.
591 scroll_state.ConsumeDeltaNative(delta.Width(), delta.Height());
592
593 // We need to setCurrentNativeScrollingElement in both the
594 // distributeScroll and applyScroll default implementations so
595 // that if JS overrides one of these methods, but not the
596 // other, this bookkeeping remains accurate.
597 scroll_state.SetCurrentNativeScrollingNode(this);
598 }
599
CallDistributeScroll(ScrollState & scroll_state)600 void Node::CallDistributeScroll(ScrollState& scroll_state) {
601 TRACE_EVENT0("input", "Node::CallDistributeScroll");
602 ScrollStateCallback* callback =
603 GetScrollCustomizationCallbacks().GetDistributeScroll(this);
604
605 // TODO(bokan): Need to add tests before we allow calling custom callbacks
606 // for non-touch modalities. For now, just call into the native callback but
607 // allow the viewport scroll callback so we don't disable overscroll.
608 // crbug.com/623079.
609 bool disable_custom_callbacks = !scroll_state.isDirectManipulation() &&
610 !GetDocument()
611 .GetPage()
612 ->GlobalRootScrollerController()
613 .IsViewportScrollCallback(callback);
614
615 bool is_global_root_scroller =
616 GetLayoutObject() && GetLayoutObject()->IsGlobalRootScroller();
617
618 disable_custom_callbacks |=
619 !is_global_root_scroller &&
620 RuntimeEnabledFeatures::ScrollCustomizationEnabled() &&
621 !GetScrollCustomizationCallbacks().InScrollPhase(this);
622
623 if (!callback || disable_custom_callbacks) {
624 NativeDistributeScroll(scroll_state);
625 return;
626 }
627 if (callback->GetNativeScrollBehavior() !=
628 NativeScrollBehavior::kPerformAfterNativeScroll)
629 callback->Invoke(&scroll_state);
630 if (callback->GetNativeScrollBehavior() !=
631 NativeScrollBehavior::kDisableNativeScroll)
632 NativeDistributeScroll(scroll_state);
633 if (callback->GetNativeScrollBehavior() ==
634 NativeScrollBehavior::kPerformAfterNativeScroll)
635 callback->Invoke(&scroll_state);
636 }
637
CallApplyScroll(ScrollState & scroll_state)638 void Node::CallApplyScroll(ScrollState& scroll_state) {
639 TRACE_EVENT0("input", "Node::CallApplyScroll");
640
641 if (!GetDocument().GetPage()) {
642 // We should always have a Page if we're scrolling. See
643 // crbug.com/689074 for details.
644 NOTREACHED();
645 return;
646 }
647
648 ScrollStateCallback* callback =
649 GetScrollCustomizationCallbacks().GetApplyScroll(this);
650
651 // TODO(bokan): Need to add tests before we allow calling custom callbacks
652 // for non-touch modalities. For now, just call into the native callback but
653 // allow the viewport scroll callback so we don't disable overscroll.
654 // crbug.com/623079.
655 bool disable_custom_callbacks = !scroll_state.isDirectManipulation() &&
656 !GetDocument()
657 .GetPage()
658 ->GlobalRootScrollerController()
659 .IsViewportScrollCallback(callback);
660
661 bool is_global_root_scroller =
662 GetLayoutObject() && GetLayoutObject()->IsGlobalRootScroller();
663
664 disable_custom_callbacks |=
665 !is_global_root_scroller &&
666 RuntimeEnabledFeatures::ScrollCustomizationEnabled() &&
667 !GetScrollCustomizationCallbacks().InScrollPhase(this);
668
669 if (!callback || disable_custom_callbacks) {
670 NativeApplyScroll(scroll_state);
671 return;
672 }
673 if (callback->GetNativeScrollBehavior() !=
674 NativeScrollBehavior::kPerformAfterNativeScroll)
675 callback->Invoke(&scroll_state);
676 if (callback->GetNativeScrollBehavior() !=
677 NativeScrollBehavior::kDisableNativeScroll)
678 NativeApplyScroll(scroll_state);
679 if (callback->GetNativeScrollBehavior() ==
680 NativeScrollBehavior::kPerformAfterNativeScroll)
681 callback->Invoke(&scroll_state);
682 }
683
WillBeginCustomizedScrollPhase(scroll_customization::ScrollDirection direction)684 void Node::WillBeginCustomizedScrollPhase(
685 scroll_customization::ScrollDirection direction) {
686 DCHECK(!GetScrollCustomizationCallbacks().InScrollPhase(this));
687 LayoutBox* box = GetLayoutBox();
688 if (!box)
689 return;
690
691 scroll_customization::ScrollDirection scroll_customization =
692 box->Style()->ScrollCustomization();
693
694 GetScrollCustomizationCallbacks().SetInScrollPhase(
695 this, direction & scroll_customization);
696 }
697
DidEndCustomizedScrollPhase()698 void Node::DidEndCustomizedScrollPhase() {
699 GetScrollCustomizationCallbacks().SetInScrollPhase(this, false);
700 }
701
insertBefore(Node * new_child,Node * ref_child,ExceptionState & exception_state)702 Node* Node::insertBefore(Node* new_child,
703 Node* ref_child,
704 ExceptionState& exception_state) {
705 auto* this_node = DynamicTo<ContainerNode>(this);
706 if (this_node)
707 return this_node->InsertBefore(new_child, ref_child, exception_state);
708
709 exception_state.ThrowDOMException(
710 DOMExceptionCode::kHierarchyRequestError,
711 "This node type does not support this method.");
712 return nullptr;
713 }
714
insertBefore(Node * new_child,Node * ref_child)715 Node* Node::insertBefore(Node* new_child, Node* ref_child) {
716 return insertBefore(new_child, ref_child, ASSERT_NO_EXCEPTION);
717 }
718
replaceChild(Node * new_child,Node * old_child,ExceptionState & exception_state)719 Node* Node::replaceChild(Node* new_child,
720 Node* old_child,
721 ExceptionState& exception_state) {
722 auto* this_node = DynamicTo<ContainerNode>(this);
723 if (this_node)
724 return this_node->ReplaceChild(new_child, old_child, exception_state);
725
726 exception_state.ThrowDOMException(
727 DOMExceptionCode::kHierarchyRequestError,
728 "This node type does not support this method.");
729 return nullptr;
730 }
731
replaceChild(Node * new_child,Node * old_child)732 Node* Node::replaceChild(Node* new_child, Node* old_child) {
733 return replaceChild(new_child, old_child, ASSERT_NO_EXCEPTION);
734 }
735
removeChild(Node * old_child,ExceptionState & exception_state)736 Node* Node::removeChild(Node* old_child, ExceptionState& exception_state) {
737 auto* this_node = DynamicTo<ContainerNode>(this);
738 if (this_node)
739 return this_node->RemoveChild(old_child, exception_state);
740
741 exception_state.ThrowDOMException(
742 DOMExceptionCode::kNotFoundError,
743 "This node type does not support this method.");
744 return nullptr;
745 }
746
removeChild(Node * old_child)747 Node* Node::removeChild(Node* old_child) {
748 return removeChild(old_child, ASSERT_NO_EXCEPTION);
749 }
750
appendChild(Node * new_child,ExceptionState & exception_state)751 Node* Node::appendChild(Node* new_child, ExceptionState& exception_state) {
752 auto* this_node = DynamicTo<ContainerNode>(this);
753 if (this_node)
754 return this_node->AppendChild(new_child, exception_state);
755
756 exception_state.ThrowDOMException(
757 DOMExceptionCode::kHierarchyRequestError,
758 "This node type does not support this method.");
759 return nullptr;
760 }
761
appendChild(Node * new_child)762 Node* Node::appendChild(Node* new_child) {
763 return appendChild(new_child, ASSERT_NO_EXCEPTION);
764 }
765
IsNodeInNodes(const Node * const node,const HeapVector<NodeOrStringOrTrustedScript> & nodes)766 static bool IsNodeInNodes(
767 const Node* const node,
768 const HeapVector<NodeOrStringOrTrustedScript>& nodes) {
769 for (const NodeOrStringOrTrustedScript& node_or_string : nodes) {
770 if (node_or_string.IsNode() && node_or_string.GetAsNode() == node)
771 return true;
772 }
773 return false;
774 }
775
FindViablePreviousSibling(const Node & node,const HeapVector<NodeOrStringOrTrustedScript> & nodes)776 static Node* FindViablePreviousSibling(
777 const Node& node,
778 const HeapVector<NodeOrStringOrTrustedScript>& nodes) {
779 for (Node* sibling = node.previousSibling(); sibling;
780 sibling = sibling->previousSibling()) {
781 if (!IsNodeInNodes(sibling, nodes))
782 return sibling;
783 }
784 return nullptr;
785 }
786
FindViableNextSibling(const Node & node,const HeapVector<NodeOrStringOrTrustedScript> & nodes)787 static Node* FindViableNextSibling(
788 const Node& node,
789 const HeapVector<NodeOrStringOrTrustedScript>& nodes) {
790 for (Node* sibling = node.nextSibling(); sibling;
791 sibling = sibling->nextSibling()) {
792 if (!IsNodeInNodes(sibling, nodes))
793 return sibling;
794 }
795 return nullptr;
796 }
797
NodeOrStringToNode(const NodeOrStringOrTrustedScript & node_or_string,Document & document,bool needs_trusted_types_check,ExceptionState & exception_state)798 static Node* NodeOrStringToNode(
799 const NodeOrStringOrTrustedScript& node_or_string,
800 Document& document,
801 bool needs_trusted_types_check,
802 ExceptionState& exception_state) {
803 if (!needs_trusted_types_check) {
804 // Without trusted type checks, we simply extract the string from whatever
805 // constituent type we find.
806 if (node_or_string.IsNode())
807 return node_or_string.GetAsNode();
808 if (node_or_string.IsTrustedScript()) {
809 return Text::Create(document,
810 node_or_string.GetAsTrustedScript()->toString());
811 }
812 return Text::Create(document, node_or_string.GetAsString());
813 }
814
815 // With trusted type checks, we can process trusted script or non-text nodes
816 // directly. Strings or text nodes need to be checked.
817 if (node_or_string.IsNode() && !node_or_string.GetAsNode()->IsTextNode())
818 return node_or_string.GetAsNode();
819
820 if (node_or_string.IsTrustedScript()) {
821 return Text::Create(document,
822 node_or_string.GetAsTrustedScript()->toString());
823 }
824
825 String string_value = node_or_string.IsString()
826 ? node_or_string.GetAsString()
827 : node_or_string.GetAsNode()->textContent();
828
829 string_value = TrustedTypesCheckForScript(
830 string_value, document.GetExecutionContext(), exception_state);
831 if (exception_state.HadException())
832 return nullptr;
833 return Text::Create(document, string_value);
834 }
835
836 // Returns nullptr if an exception was thrown.
ConvertNodesIntoNode(const Node * parent,const HeapVector<NodeOrStringOrTrustedScript> & nodes,Document & document,ExceptionState & exception_state)837 static Node* ConvertNodesIntoNode(
838 const Node* parent,
839 const HeapVector<NodeOrStringOrTrustedScript>& nodes,
840 Document& document,
841 ExceptionState& exception_state) {
842 bool needs_check = IsA<HTMLScriptElement>(parent) &&
843 document.GetExecutionContext() &&
844 document.GetExecutionContext()->RequireTrustedTypes();
845
846 if (nodes.size() == 1)
847 return NodeOrStringToNode(nodes[0], document, needs_check, exception_state);
848
849 Node* fragment = DocumentFragment::Create(document);
850 for (const NodeOrStringOrTrustedScript& node_or_string_or_trusted_script :
851 nodes) {
852 Node* node = NodeOrStringToNode(node_or_string_or_trusted_script, document,
853 needs_check, exception_state);
854 if (node)
855 fragment->appendChild(node, exception_state);
856 if (exception_state.HadException())
857 return nullptr;
858 }
859 return fragment;
860 }
861
Prepend(const HeapVector<NodeOrStringOrTrustedScript> & nodes,ExceptionState & exception_state)862 void Node::Prepend(const HeapVector<NodeOrStringOrTrustedScript>& nodes,
863 ExceptionState& exception_state) {
864 auto* this_node = DynamicTo<ContainerNode>(this);
865 if (!this_node) {
866 exception_state.ThrowDOMException(
867 DOMExceptionCode::kHierarchyRequestError,
868 "This node type does not support this method.");
869 return;
870 }
871
872 if (Node* node =
873 ConvertNodesIntoNode(this, nodes, GetDocument(), exception_state))
874 this_node->InsertBefore(node, firstChild(), exception_state);
875 }
876
Append(const HeapVector<NodeOrStringOrTrustedScript> & nodes,ExceptionState & exception_state)877 void Node::Append(const HeapVector<NodeOrStringOrTrustedScript>& nodes,
878 ExceptionState& exception_state) {
879 auto* this_node = DynamicTo<ContainerNode>(this);
880 if (!this_node) {
881 exception_state.ThrowDOMException(
882 DOMExceptionCode::kHierarchyRequestError,
883 "This node type does not support this method.");
884 return;
885 }
886
887 if (Node* node =
888 ConvertNodesIntoNode(this, nodes, GetDocument(), exception_state))
889 this_node->AppendChild(node, exception_state);
890 }
891
Before(const HeapVector<NodeOrStringOrTrustedScript> & nodes,ExceptionState & exception_state)892 void Node::Before(const HeapVector<NodeOrStringOrTrustedScript>& nodes,
893 ExceptionState& exception_state) {
894 Node* parent = parentNode();
895 if (!parent)
896 return;
897 auto* parent_node = DynamicTo<ContainerNode>(parent);
898 if (!parent_node) {
899 exception_state.ThrowDOMException(
900 DOMExceptionCode::kHierarchyRequestError,
901 "This node type does not support this method.");
902 return;
903 }
904 Node* viable_previous_sibling = FindViablePreviousSibling(*this, nodes);
905 if (Node* node =
906 ConvertNodesIntoNode(parent, nodes, GetDocument(), exception_state)) {
907 parent_node->InsertBefore(node,
908 viable_previous_sibling
909 ? viable_previous_sibling->nextSibling()
910 : parent->firstChild(),
911 exception_state);
912 }
913 }
914
After(const HeapVector<NodeOrStringOrTrustedScript> & nodes,ExceptionState & exception_state)915 void Node::After(const HeapVector<NodeOrStringOrTrustedScript>& nodes,
916 ExceptionState& exception_state) {
917 Node* parent = parentNode();
918 if (!parent)
919 return;
920 auto* parent_node = DynamicTo<ContainerNode>(parent);
921 if (!parent_node) {
922 exception_state.ThrowDOMException(
923 DOMExceptionCode::kHierarchyRequestError,
924 "This node type does not support this method.");
925 return;
926 }
927 Node* viable_next_sibling = FindViableNextSibling(*this, nodes);
928 if (Node* node =
929 ConvertNodesIntoNode(parent, nodes, GetDocument(), exception_state))
930 parent_node->InsertBefore(node, viable_next_sibling, exception_state);
931 }
932
ReplaceWith(const HeapVector<NodeOrStringOrTrustedScript> & nodes,ExceptionState & exception_state)933 void Node::ReplaceWith(const HeapVector<NodeOrStringOrTrustedScript>& nodes,
934 ExceptionState& exception_state) {
935 Node* parent = parentNode();
936 if (!parent)
937 return;
938 auto* parent_node = DynamicTo<ContainerNode>(parent);
939 if (!parent_node) {
940 exception_state.ThrowDOMException(
941 DOMExceptionCode::kHierarchyRequestError,
942 "This node type does not support this method.");
943 return;
944 }
945
946 Node* viable_next_sibling = FindViableNextSibling(*this, nodes);
947 Node* node =
948 ConvertNodesIntoNode(parent, nodes, GetDocument(), exception_state);
949 if (exception_state.HadException())
950 return;
951 if (parent_node == parentNode())
952 parent_node->ReplaceChild(node, this, exception_state);
953 else
954 parent_node->InsertBefore(node, viable_next_sibling, exception_state);
955 }
956
957 // https://dom.spec.whatwg.org/#dom-parentnode-replacechildren
ReplaceChildren(const HeapVector<NodeOrStringOrTrustedScript> & nodes,ExceptionState & exception_state)958 void Node::ReplaceChildren(const HeapVector<NodeOrStringOrTrustedScript>& nodes,
959 ExceptionState& exception_state) {
960 auto* this_node = DynamicTo<ContainerNode>(this);
961 if (!this_node) {
962 exception_state.ThrowDOMException(
963 DOMExceptionCode::kHierarchyRequestError,
964 "This node type does not support this method.");
965 return;
966 }
967
968 // 1. Let node be the result of converting nodes into a node given nodes and
969 // this’s node document.
970 Node* node =
971 ConvertNodesIntoNode(this, nodes, GetDocument(), exception_state);
972 if (exception_state.HadException())
973 return;
974
975 // 2. Ensure pre-insertion validity of node into this before null.
976 if (!this_node->EnsurePreInsertionValidity(*node, nullptr, nullptr,
977 exception_state))
978 return;
979
980 // 3. Replace all with node within this.
981 ChildListMutationScope mutation(*this);
982 while (Node* first_child = firstChild()) {
983 removeChild(first_child, exception_state);
984 if (exception_state.HadException())
985 return;
986 }
987
988 appendChild(node, exception_state);
989 }
990
remove(ExceptionState & exception_state)991 void Node::remove(ExceptionState& exception_state) {
992 if (ContainerNode* parent = parentNode())
993 parent->RemoveChild(this, exception_state);
994 }
995
remove()996 void Node::remove() {
997 remove(ASSERT_NO_EXCEPTION);
998 }
999
cloneNode(bool deep,ExceptionState & exception_state) const1000 Node* Node::cloneNode(bool deep, ExceptionState& exception_state) const {
1001 // https://dom.spec.whatwg.org/#dom-node-clonenode
1002
1003 // 1. If this is a shadow root, then throw a "NotSupportedError" DOMException.
1004 if (IsShadowRoot()) {
1005 exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
1006 "ShadowRoot nodes are not clonable.");
1007 return nullptr;
1008 }
1009
1010 // 2. Return a clone of this, with the clone children flag set if deep is
1011 // true, and the clone shadows flag set if this is a DocumentFragment whose
1012 // host is an HTML template element.
1013 auto* fragment = DynamicTo<DocumentFragment>(this);
1014 bool clone_shadows_flag = fragment && fragment->IsTemplateContent() &&
1015 RuntimeEnabledFeatures::DeclarativeShadowDOMEnabled(
1016 GetExecutionContext());
1017 return Clone(GetDocument(),
1018 deep ? (clone_shadows_flag ? CloneChildrenFlag::kCloneWithShadows
1019 : CloneChildrenFlag::kClone)
1020 : CloneChildrenFlag::kSkip);
1021 }
1022
cloneNode(bool deep) const1023 Node* Node::cloneNode(bool deep) const {
1024 return cloneNode(deep, ASSERT_NO_EXCEPTION);
1025 }
1026
normalize()1027 void Node::normalize() {
1028 UpdateDistributionForFlatTreeTraversal();
1029
1030 // Go through the subtree beneath us, normalizing all nodes. This means that
1031 // any two adjacent text nodes are merged and any empty text nodes are
1032 // removed.
1033
1034 Node* node = this;
1035 while (Node* first_child = node->firstChild())
1036 node = first_child;
1037 while (node) {
1038 if (node == this)
1039 break;
1040
1041 if (node->getNodeType() == kTextNode)
1042 node = To<Text>(node)->MergeNextSiblingNodesIfPossible();
1043 else
1044 node = NodeTraversal::NextPostOrder(*node);
1045 }
1046 }
1047
GetLayoutBox() const1048 LayoutBox* Node::GetLayoutBox() const {
1049 return DynamicTo<LayoutBox>(GetLayoutObject());
1050 }
1051
SetLayoutObject(LayoutObject * layout_object)1052 void Node::SetLayoutObject(LayoutObject* layout_object) {
1053 NodeRenderingData* node_layout_data =
1054 HasRareData() ? DataAsNodeRareData()->GetNodeRenderingData()
1055 : DataAsNodeRenderingData();
1056
1057 // Already pointing to a non empty NodeRenderingData so just set the pointer
1058 // to the new LayoutObject.
1059 if (!node_layout_data->IsSharedEmptyData()) {
1060 node_layout_data->SetLayoutObject(layout_object);
1061 return;
1062 }
1063
1064 if (!layout_object)
1065 return;
1066
1067 // Swap the NodeRenderingData to point to a new NodeRenderingData instead of
1068 // the static SharedEmptyData instance.
1069 DCHECK(!node_layout_data->GetComputedStyle());
1070 node_layout_data =
1071 MakeGarbageCollected<NodeRenderingData>(layout_object, nullptr);
1072 if (HasRareData()) {
1073 DataAsNodeRareData()->SetNodeRenderingData(node_layout_data);
1074 } else {
1075 data_ = node_layout_data;
1076 }
1077 }
1078
SetComputedStyle(scoped_refptr<const ComputedStyle> computed_style)1079 void Node::SetComputedStyle(scoped_refptr<const ComputedStyle> computed_style) {
1080 // We don't set computed style for text nodes.
1081 DCHECK(IsElementNode());
1082
1083 NodeRenderingData* node_layout_data =
1084 HasRareData() ? DataAsNodeRareData()->GetNodeRenderingData()
1085 : DataAsNodeRenderingData();
1086
1087 // Already pointing to a non empty NodeRenderingData so just set the pointer
1088 // to the new LayoutObject.
1089 if (!node_layout_data->IsSharedEmptyData()) {
1090 node_layout_data->SetComputedStyle(computed_style);
1091 return;
1092 }
1093
1094 if (!computed_style)
1095 return;
1096
1097 // Ensure we only set computed style for elements which are not part of the
1098 // flat tree unless it's enforced for getComputedStyle().
1099 DCHECK(computed_style->IsEnsuredInDisplayNone() ||
1100 LayoutTreeBuilderTraversal::Parent(*this));
1101
1102 // Swap the NodeRenderingData to point to a new NodeRenderingData instead of
1103 // the static SharedEmptyData instance.
1104 DCHECK(!node_layout_data->GetLayoutObject());
1105 node_layout_data =
1106 MakeGarbageCollected<NodeRenderingData>(nullptr, computed_style);
1107 if (HasRareData()) {
1108 DataAsNodeRareData()->SetNodeRenderingData(node_layout_data);
1109 } else {
1110 data_ = node_layout_data;
1111 }
1112 }
1113
GetLayoutBoxModelObject() const1114 LayoutBoxModelObject* Node::GetLayoutBoxModelObject() const {
1115 return DynamicTo<LayoutBoxModelObject>(GetLayoutObject());
1116 }
1117
BoundingBox() const1118 PhysicalRect Node::BoundingBox() const {
1119 if (GetLayoutObject())
1120 return PhysicalRect(GetLayoutObject()->AbsoluteBoundingBoxRect());
1121 return PhysicalRect();
1122 }
1123
PixelSnappedBoundingBox() const1124 IntRect Node::PixelSnappedBoundingBox() const {
1125 return PixelSnappedIntRect(BoundingBox());
1126 }
1127
BoundingBoxForScrollIntoView() const1128 PhysicalRect Node::BoundingBoxForScrollIntoView() const {
1129 if (GetLayoutObject()) {
1130 return GetLayoutObject()->AbsoluteBoundingBoxRectForScrollIntoView();
1131 }
1132
1133 return PhysicalRect();
1134 }
1135
ShadowIncludingRoot() const1136 Node& Node::ShadowIncludingRoot() const {
1137 if (isConnected())
1138 return GetDocument();
1139 Node* root = const_cast<Node*>(this);
1140 while (Node* host = root->OwnerShadowHost())
1141 root = host;
1142 while (Node* ancestor = root->parentNode())
1143 root = ancestor;
1144 DCHECK(!root->OwnerShadowHost());
1145 return *root;
1146 }
1147
IsClosedShadowHiddenFrom(const Node & other) const1148 bool Node::IsClosedShadowHiddenFrom(const Node& other) const {
1149 if (!IsInShadowTree() || GetTreeScope() == other.GetTreeScope())
1150 return false;
1151
1152 const TreeScope* scope = &GetTreeScope();
1153 for (; scope->ParentTreeScope(); scope = scope->ParentTreeScope()) {
1154 const ContainerNode& root = scope->RootNode();
1155 auto* shadow_root = DynamicTo<ShadowRoot>(root);
1156 if (shadow_root && !shadow_root->IsOpenOrV0())
1157 break;
1158 }
1159
1160 for (TreeScope* other_scope = &other.GetTreeScope(); other_scope;
1161 other_scope = other_scope->ParentTreeScope()) {
1162 if (other_scope == scope)
1163 return false;
1164 }
1165 return true;
1166 }
1167
NeedsDistributionRecalc() const1168 bool Node::NeedsDistributionRecalc() const {
1169 return ShadowIncludingRoot().ChildNeedsDistributionRecalc();
1170 }
1171
MayContainLegacyNodeTreeWhereDistributionShouldBeSupported() const1172 bool Node::MayContainLegacyNodeTreeWhereDistributionShouldBeSupported() const {
1173 if (isConnected() && !GetDocument().MayContainV0Shadow()) {
1174 // TODO(crbug.com/787717): Some built-in elements still use <content>
1175 // elements in their user-agent shadow roots. DCHECK() fails if such an
1176 // element is used.
1177 DCHECK(!GetDocument().ChildNeedsDistributionRecalc());
1178 return false;
1179 }
1180 return true;
1181 }
1182
UpdateDistributionForUnknownReasons()1183 void Node::UpdateDistributionForUnknownReasons() {
1184 UpdateDistributionInternal();
1185 // For the sake of safety, call RecalcSlotAssignments as well as
1186 // UpdateDistribution().
1187 if (isConnected())
1188 GetDocument().GetSlotAssignmentEngine().RecalcSlotAssignments();
1189 }
1190
UpdateDistributionInternal()1191 void Node::UpdateDistributionInternal() {
1192 if (!MayContainLegacyNodeTreeWhereDistributionShouldBeSupported())
1193 return;
1194 // Extra early out to avoid spamming traces.
1195 if (isConnected() && !GetDocument().ChildNeedsDistributionRecalc())
1196 return;
1197 TRACE_EVENT0("blink", "Node::updateDistribution");
1198 ScriptForbiddenScope forbid_script;
1199 Node& root = ShadowIncludingRoot();
1200 if (root.ChildNeedsDistributionRecalc())
1201 root.RecalcDistribution();
1202 }
1203
RecalcDistribution()1204 void Node::RecalcDistribution() {
1205 DCHECK(ChildNeedsDistributionRecalc());
1206
1207 if (GetShadowRoot())
1208 GetShadowRoot()->DistributeIfNeeded();
1209
1210 DCHECK(ScriptForbiddenScope::IsScriptForbidden());
1211 for (Node* child = firstChild(); child; child = child->nextSibling()) {
1212 if (child->ChildNeedsDistributionRecalc())
1213 child->RecalcDistribution();
1214 }
1215
1216 if (ShadowRoot* root = GetShadowRoot()) {
1217 if (root->ChildNeedsDistributionRecalc())
1218 root->RecalcDistribution();
1219 }
1220
1221 ClearChildNeedsDistributionRecalc();
1222 }
1223
SetIsLink(bool is_link)1224 void Node::SetIsLink(bool is_link) {
1225 SetFlag(is_link && !SVGImage::IsInSVGImage(To<Element>(this)), kIsLinkFlag);
1226 }
1227
SetNeedsStyleInvalidation()1228 void Node::SetNeedsStyleInvalidation() {
1229 DCHECK(IsContainerNode());
1230 SetFlag(kNeedsStyleInvalidationFlag);
1231 MarkAncestorsWithChildNeedsStyleInvalidation();
1232 }
1233
MarkAncestorsWithChildNeedsStyleInvalidation()1234 void Node::MarkAncestorsWithChildNeedsStyleInvalidation() {
1235 ScriptForbiddenScope forbid_script_during_raw_iteration;
1236 ContainerNode* ancestor = ParentOrShadowHostNode();
1237 bool parent_dirty = ancestor && ancestor->NeedsStyleInvalidation();
1238 for (; ancestor && !ancestor->ChildNeedsStyleInvalidation();
1239 ancestor = ancestor->ParentOrShadowHostNode()) {
1240 if (!ancestor->isConnected())
1241 return;
1242 ancestor->SetChildNeedsStyleInvalidation();
1243 if (ancestor->NeedsStyleInvalidation())
1244 break;
1245 }
1246 if (!isConnected())
1247 return;
1248 // If the parent node is already dirty, we can keep the same invalidation
1249 // root. The early return here is a performance optimization.
1250 if (parent_dirty)
1251 return;
1252 GetDocument().GetStyleEngine().UpdateStyleInvalidationRoot(ancestor, this);
1253 GetDocument().ScheduleLayoutTreeUpdateIfNeeded();
1254 }
1255
MarkAncestorsWithChildNeedsDistributionRecalc()1256 void Node::MarkAncestorsWithChildNeedsDistributionRecalc() {
1257 ScriptForbiddenScope forbid_script_during_raw_iteration;
1258 for (Node* node = this; node && !node->ChildNeedsDistributionRecalc();
1259 node = node->ParentOrShadowHostNode()) {
1260 node->SetChildNeedsDistributionRecalc();
1261 }
1262 GetDocument().ScheduleLayoutTreeUpdateIfNeeded();
1263 }
1264
MarkSubtreeNeedsStyleRecalcForFontUpdates()1265 void Node::MarkSubtreeNeedsStyleRecalcForFontUpdates() {
1266 if (GetStyleChangeType() == kSubtreeStyleChange)
1267 return;
1268
1269 if (IsElementNode()) {
1270 const ComputedStyle* style = GetComputedStyle();
1271 if (!style)
1272 return;
1273
1274 // We require font-specific metrics to resolve length units 'ex' and 'ch',
1275 // and to compute the adjusted font size when 'font-size-adjust' is set. All
1276 // other style computations are unaffected by font loading.
1277 if (!NeedsStyleRecalc()) {
1278 if (style->DependsOnFontMetrics() ||
1279 To<Element>(this)->PseudoElementStylesDependOnFontMetrics()) {
1280 SetNeedsStyleRecalc(
1281 kLocalStyleChange,
1282 StyleChangeReasonForTracing::Create(style_change_reason::kFonts));
1283 }
1284 }
1285
1286 if (Node* shadow_root = GetShadowRoot())
1287 shadow_root->MarkSubtreeNeedsStyleRecalcForFontUpdates();
1288 }
1289
1290 for (Node* child = firstChild(); child; child = child->nextSibling())
1291 child->MarkSubtreeNeedsStyleRecalcForFontUpdates();
1292 }
1293
1294 #if DCHECK_IS_ON()
1295 namespace {
1296 class AllowDirtyShadowV0TraversalScope {
1297 STACK_ALLOCATED();
1298
1299 public:
AllowDirtyShadowV0TraversalScope(Document & document)1300 explicit AllowDirtyShadowV0TraversalScope(Document& document)
1301 : document_(&document),
1302 old_value_(document.AllowDirtyShadowV0Traversal()) {
1303 document.SetAllowDirtyShadowV0Traversal(true);
1304 }
~AllowDirtyShadowV0TraversalScope()1305 ~AllowDirtyShadowV0TraversalScope() {
1306 document_->SetAllowDirtyShadowV0Traversal(old_value_);
1307 }
1308
1309 private:
1310 Document* document_;
1311 bool old_value_;
1312 };
1313 } // namespace
1314 #define ALLOW_DIRTY_SHADOW_V0_TRAVERSAL_SCOPE(document) \
1315 AllowDirtyShadowV0TraversalScope traversal_scope(document)
1316 #else // DCHECK_IS_ON()
1317 #define ALLOW_DIRTY_SHADOW_V0_TRAVERSAL_SCOPE(document)
1318 #endif // DCHECK_IS_ON()
1319
ShouldSkipMarkingStyleDirty() const1320 bool Node::ShouldSkipMarkingStyleDirty() const {
1321 if (GetComputedStyle())
1322 return false;
1323
1324 ALLOW_DIRTY_SHADOW_V0_TRAVERSAL_SCOPE(GetDocument());
1325
1326 // If we don't have a computed style, and our parent element does not have a
1327 // computed style it's not necessary to mark this node for style recalc.
1328 if (auto* parent = GetStyleRecalcParent()) {
1329 while (parent && !parent->CanParticipateInFlatTree())
1330 parent = parent->GetStyleRecalcParent();
1331 return !parent || !parent->GetComputedStyle();
1332 }
1333 // If this is the root element, and it does not have a computed style, we
1334 // still need to mark it for style recalc since it may change from
1335 // display:none. Otherwise, the node is not in the flat tree, and we can
1336 // skip marking it dirty.
1337 auto* root_element = GetDocument().documentElement();
1338 return root_element && root_element != this;
1339 }
1340
MarkAncestorsWithChildNeedsStyleRecalc()1341 void Node::MarkAncestorsWithChildNeedsStyleRecalc() {
1342 ALLOW_DIRTY_SHADOW_V0_TRAVERSAL_SCOPE(GetDocument());
1343 ContainerNode* style_parent = GetStyleRecalcParent();
1344 bool parent_dirty = style_parent && style_parent->IsDirtyForStyleRecalc();
1345 ContainerNode* ancestor = style_parent;
1346 for (; ancestor && !ancestor->ChildNeedsStyleRecalc();
1347 ancestor = ancestor->GetStyleRecalcParent()) {
1348 if (!ancestor->isConnected())
1349 return;
1350 ancestor->SetChildNeedsStyleRecalc();
1351 if (ancestor->IsDirtyForStyleRecalc())
1352 break;
1353 // If we reach a locked ancestor, we should abort since the ancestor marking
1354 // will be done when the lock is committed.
1355 if (RuntimeEnabledFeatures::CSSContentVisibilityEnabled()) {
1356 auto* ancestor_element = DynamicTo<Element>(ancestor);
1357 if (ancestor_element &&
1358 ancestor_element->ChildStyleRecalcBlockedByDisplayLock()) {
1359 break;
1360 }
1361 }
1362 }
1363 if (!isConnected())
1364 return;
1365 // If the parent node is already dirty, we can keep the same recalc root. The
1366 // early return here is a performance optimization.
1367 if (parent_dirty)
1368 return;
1369 // If we are outside the flat tree we should not update the recalc root
1370 // because we should not traverse those nodes from StyleEngine::RecalcStyle().
1371 if (const ComputedStyle* current_style = GetComputedStyle()) {
1372 if (current_style->IsEnsuredOutsideFlatTree())
1373 return;
1374 } else {
1375 while (style_parent && !style_parent->CanParticipateInFlatTree())
1376 style_parent = style_parent->GetStyleRecalcParent();
1377 if (style_parent) {
1378 if (const auto* parent_style = style_parent->GetComputedStyle()) {
1379 if (parent_style->IsEnsuredOutsideFlatTree())
1380 return;
1381 }
1382 }
1383 }
1384 // If we're in a locked subtree, then we should not update the style recalc
1385 // roots. These would be updated when we commit the lock. If we have locked
1386 // display locks somewhere in the document, we iterate up the ancestor chain
1387 // to check if we're in one such subtree.
1388 if (RuntimeEnabledFeatures::CSSContentVisibilityEnabled() &&
1389 GetDocument().GetDisplayLockDocumentState().LockedDisplayLockCount() >
1390 0) {
1391 for (auto* ancestor_copy = ancestor; ancestor_copy;
1392 ancestor_copy = ancestor_copy->GetStyleRecalcParent()) {
1393 auto* ancestor_copy_element = DynamicTo<Element>(ancestor_copy);
1394 if (ancestor_copy_element &&
1395 ancestor_copy_element->ChildStyleRecalcBlockedByDisplayLock()) {
1396 return;
1397 }
1398 }
1399 }
1400
1401 GetDocument().GetStyleEngine().UpdateStyleRecalcRoot(ancestor, this);
1402 GetDocument().ScheduleLayoutTreeUpdateIfNeeded();
1403 }
1404
FlatTreeParentForChildDirty() const1405 Element* Node::FlatTreeParentForChildDirty() const {
1406 if (IsPseudoElement())
1407 return ParentOrShadowHostElement();
1408 if (IsChildOfV1ShadowHost()) {
1409 if (auto* data = GetFlatTreeNodeData())
1410 return data->AssignedSlot();
1411 return nullptr;
1412 }
1413 if (IsInV0ShadowTree() || IsChildOfV0ShadowHost()) {
1414 if (ShadowRootWhereNodeCanBeDistributedForV0(*this)) {
1415 if (V0InsertionPoint* insertion_point =
1416 const_cast<V0InsertionPoint*>(ResolveReprojection(this))) {
1417 return insertion_point;
1418 }
1419 return nullptr;
1420 }
1421 }
1422 return ParentOrShadowHostElement();
1423 }
1424
MarkAncestorsWithChildNeedsReattachLayoutTree()1425 void Node::MarkAncestorsWithChildNeedsReattachLayoutTree() {
1426 DCHECK(isConnected());
1427 Element* ancestor = GetReattachParent();
1428 bool parent_dirty = ancestor && ancestor->NeedsReattachLayoutTree();
1429 for (; ancestor && !ancestor->ChildNeedsReattachLayoutTree();
1430 ancestor = ancestor->GetReattachParent()) {
1431 ancestor->SetChildNeedsReattachLayoutTree();
1432 if (ancestor->NeedsReattachLayoutTree())
1433 break;
1434 }
1435 // If the parent node is already dirty, we can keep the same rebuild root. The
1436 // early return here is a performance optimization.
1437 if (parent_dirty)
1438 return;
1439 GetDocument().GetStyleEngine().UpdateLayoutTreeRebuildRoot(ancestor, this);
1440 }
1441
SetNeedsReattachLayoutTree()1442 void Node::SetNeedsReattachLayoutTree() {
1443 DCHECK(GetDocument().InStyleRecalc());
1444 DCHECK(!GetDocument().ChildNeedsDistributionRecalc());
1445 DCHECK(IsElementNode() || IsTextNode());
1446 DCHECK(InActiveDocument());
1447 SetFlag(kNeedsReattachLayoutTree);
1448 MarkAncestorsWithChildNeedsReattachLayoutTree();
1449 }
1450
SetNeedsStyleRecalc(StyleChangeType change_type,const StyleChangeReasonForTracing & reason)1451 void Node::SetNeedsStyleRecalc(StyleChangeType change_type,
1452 const StyleChangeReasonForTracing& reason) {
1453 DCHECK(!GetDocument().GetStyleEngine().InRebuildLayoutTree());
1454 DCHECK(change_type != kNoStyleChange);
1455 DCHECK(IsElementNode() || IsTextNode());
1456
1457 if (!InActiveDocument())
1458 return;
1459 if (ShouldSkipMarkingStyleDirty())
1460 return;
1461
1462 TRACE_EVENT_INSTANT1(
1463 TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"),
1464 "StyleRecalcInvalidationTracking", TRACE_EVENT_SCOPE_THREAD, "data",
1465 inspector_style_recalc_invalidation_tracking_event::Data(
1466 this, change_type, reason));
1467
1468 StyleChangeType existing_change_type = GetStyleChangeType();
1469 if (change_type > existing_change_type)
1470 SetStyleChange(change_type);
1471
1472 auto* this_element = DynamicTo<Element>(this);
1473 if (existing_change_type == kNoStyleChange)
1474 MarkAncestorsWithChildNeedsStyleRecalc();
1475
1476 if (this_element && HasRareData())
1477 this_element->SetAnimationStyleChange(false);
1478
1479 if (auto* svg_element = DynamicTo<SVGElement>(this))
1480 svg_element->SetNeedsStyleRecalcForInstances(change_type, reason);
1481 }
1482
ClearNeedsStyleRecalc()1483 void Node::ClearNeedsStyleRecalc() {
1484 node_flags_ &= ~kStyleChangeMask;
1485 ClearFlag(kForceReattachLayoutTree);
1486
1487 auto* element = DynamicTo<Element>(this);
1488 if (element && HasRareData())
1489 element->SetAnimationStyleChange(false);
1490 }
1491
InActiveDocument() const1492 bool Node::InActiveDocument() const {
1493 return isConnected() && GetDocument().IsActive();
1494 }
1495
ShouldHaveFocusAppearance() const1496 bool Node::ShouldHaveFocusAppearance() const {
1497 DCHECK(IsFocused());
1498 return true;
1499 }
1500
IsInert() const1501 bool Node::IsInert() const {
1502 if (!isConnected() || !CanParticipateInFlatTree())
1503 return true;
1504
1505 DCHECK(!ChildNeedsDistributionRecalc());
1506
1507 if (this != GetDocument() && this != GetDocument().documentElement()) {
1508 const Element* modal_element = GetDocument().ActiveModalDialog();
1509 if (!modal_element)
1510 modal_element = Fullscreen::FullscreenElementFrom(GetDocument());
1511 if (modal_element && !FlatTreeTraversal::ContainsIncludingPseudoElement(
1512 *modal_element, *this)) {
1513 return true;
1514 }
1515 }
1516
1517 if (RuntimeEnabledFeatures::InertAttributeEnabled()) {
1518 const auto* element = DynamicTo<Element>(this);
1519 if (!element)
1520 element = FlatTreeTraversal::ParentElement(*this);
1521
1522 while (element) {
1523 if (element->FastHasAttribute(html_names::kInertAttr))
1524 return true;
1525 element = FlatTreeTraversal::ParentElement(*element);
1526 }
1527 }
1528 return GetDocument().GetFrame() && GetDocument().GetFrame()->IsInert();
1529 }
1530
NodeIndex() const1531 unsigned Node::NodeIndex() const {
1532 const Node* temp_node = previousSibling();
1533 unsigned count = 0;
1534 for (count = 0; temp_node; count++)
1535 temp_node = temp_node->previousSibling();
1536 return count;
1537 }
1538
NodeLists()1539 NodeListsNodeData* Node::NodeLists() {
1540 return HasRareData() ? RareData()->NodeLists() : nullptr;
1541 }
1542
ClearNodeLists()1543 void Node::ClearNodeLists() {
1544 RareData()->ClearNodeLists();
1545 }
1546
EnsureFlatTreeNodeData()1547 FlatTreeNodeData& Node::EnsureFlatTreeNodeData() {
1548 return EnsureRareData().EnsureFlatTreeNodeData();
1549 }
1550
GetFlatTreeNodeData() const1551 FlatTreeNodeData* Node::GetFlatTreeNodeData() const {
1552 if (!HasRareData())
1553 return nullptr;
1554 return RareData()->GetFlatTreeNodeData();
1555 }
1556
ClearFlatTreeNodeData()1557 void Node::ClearFlatTreeNodeData() {
1558 if (FlatTreeNodeData* data = GetFlatTreeNodeData())
1559 data->Clear();
1560 }
1561
ClearFlatTreeNodeDataIfHostChanged(const ContainerNode & parent)1562 void Node::ClearFlatTreeNodeDataIfHostChanged(const ContainerNode& parent) {
1563 if (FlatTreeNodeData* data = GetFlatTreeNodeData()) {
1564 if (data->AssignedSlot() &&
1565 data->AssignedSlot()->OwnerShadowHost() != &parent) {
1566 data->Clear();
1567 }
1568 }
1569 }
1570
IsDescendantOf(const Node * other) const1571 bool Node::IsDescendantOf(const Node* other) const {
1572 DCHECK(this); // Necessary for clusterfuzz tooling to get a useful backtrace
1573
1574 // Return true if other is an ancestor of this, otherwise false
1575 if (!other || isConnected() != other->isConnected())
1576 return false;
1577 if (other->GetTreeScope() != GetTreeScope())
1578 return false;
1579 if (other->IsTreeScope())
1580 return !IsTreeScope();
1581 for (const ContainerNode* n = parentNode(); n; n = n->parentNode()) {
1582 if (n == other)
1583 return true;
1584 }
1585 return false;
1586 }
1587
contains(const Node * node) const1588 bool Node::contains(const Node* node) const {
1589 if (!node)
1590 return false;
1591 return this == node || node->IsDescendantOf(this);
1592 }
1593
IsShadowIncludingInclusiveAncestorOf(const Node & node) const1594 bool Node::IsShadowIncludingInclusiveAncestorOf(const Node& node) const {
1595 return this == &node || IsShadowIncludingAncestorOf(node);
1596 }
1597
IsShadowIncludingAncestorOf(const Node & node) const1598 bool Node::IsShadowIncludingAncestorOf(const Node& node) const {
1599 // In the following case, contains(host) below returns true.
1600 if (this == &node)
1601 return false;
1602
1603 if (GetDocument() != node.GetDocument())
1604 return false;
1605
1606 if (isConnected() != node.isConnected())
1607 return false;
1608
1609 auto* this_node = DynamicTo<ContainerNode>(this);
1610 bool has_children = this_node ? this_node->HasChildren() : false;
1611 bool has_shadow = IsShadowHost(this);
1612 if (!has_children && !has_shadow)
1613 return false;
1614
1615 for (const Node* host = &node; host; host = host->OwnerShadowHost()) {
1616 if (GetTreeScope() == host->GetTreeScope())
1617 return contains(host);
1618 }
1619
1620 return false;
1621 }
1622
ContainsIncludingHostElements(const Node & node) const1623 bool Node::ContainsIncludingHostElements(const Node& node) const {
1624 const Node* current = &node;
1625 do {
1626 if (current == this)
1627 return true;
1628 auto* curr_fragment = DynamicTo<DocumentFragment>(current);
1629 if (curr_fragment && curr_fragment->IsTemplateContent())
1630 current =
1631 static_cast<const TemplateContentDocumentFragment*>(current)->Host();
1632 else
1633 current = current->ParentOrShadowHostNode();
1634 } while (current);
1635 return false;
1636 }
1637
CommonAncestor(const Node & other,ContainerNode * (* parent)(const Node &)) const1638 Node* Node::CommonAncestor(const Node& other,
1639 ContainerNode* (*parent)(const Node&)) const {
1640 if (this == other)
1641 return const_cast<Node*>(this);
1642 if (GetDocument() != other.GetDocument())
1643 return nullptr;
1644 int this_depth = 0;
1645 for (const Node* node = this; node; node = parent(*node)) {
1646 if (node == &other)
1647 return const_cast<Node*>(node);
1648 this_depth++;
1649 }
1650 int other_depth = 0;
1651 for (const Node* node = &other; node; node = parent(*node)) {
1652 if (node == this)
1653 return const_cast<Node*>(this);
1654 other_depth++;
1655 }
1656 const Node* this_iterator = this;
1657 const Node* other_iterator = &other;
1658 if (this_depth > other_depth) {
1659 for (int i = this_depth; i > other_depth; --i)
1660 this_iterator = parent(*this_iterator);
1661 } else if (other_depth > this_depth) {
1662 for (int i = other_depth; i > this_depth; --i)
1663 other_iterator = parent(*other_iterator);
1664 }
1665 while (this_iterator) {
1666 if (this_iterator == other_iterator)
1667 return const_cast<Node*>(this_iterator);
1668 this_iterator = parent(*this_iterator);
1669 other_iterator = parent(*other_iterator);
1670 }
1671 DCHECK(!other_iterator);
1672 return nullptr;
1673 }
1674
ReattachLayoutTree(AttachContext & context)1675 void Node::ReattachLayoutTree(AttachContext& context) {
1676 context.performing_reattach = true;
1677 ReattachHookScope reattach_scope(*this);
1678
1679 DetachLayoutTree(context.performing_reattach);
1680 AttachLayoutTree(context);
1681 DCHECK(!NeedsReattachLayoutTree());
1682 }
1683
AttachLayoutTree(AttachContext & context)1684 void Node::AttachLayoutTree(AttachContext& context) {
1685 DCHECK(GetDocument().InStyleRecalc() || IsDocumentNode());
1686 DCHECK(!GetDocument().Lifecycle().InDetach());
1687 DCHECK(!context.performing_reattach ||
1688 GetDocument().GetStyleEngine().InRebuildLayoutTree());
1689
1690 LayoutObject* layout_object = GetLayoutObject();
1691 DCHECK(!layout_object ||
1692 (layout_object->Style() &&
1693 (layout_object->Parent() || IsA<LayoutView>(layout_object))));
1694
1695 ClearNeedsReattachLayoutTree();
1696
1697 if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
1698 cache->UpdateCacheAfterNodeIsAttached(this);
1699
1700 if (context.performing_reattach)
1701 ReattachHookScope::NotifyAttach(*this);
1702 }
1703
DetachLayoutTree(bool performing_reattach)1704 void Node::DetachLayoutTree(bool performing_reattach) {
1705 DCHECK(GetDocument().Lifecycle().StateAllowsDetach());
1706 DCHECK(!performing_reattach ||
1707 GetDocument().GetStyleEngine().InRebuildLayoutTree());
1708 DocumentLifecycle::DetachScope will_detach(GetDocument().Lifecycle());
1709
1710 if (performing_reattach)
1711 ReattachHookScope::NotifyDetach(*this);
1712
1713 if (GetLayoutObject())
1714 GetLayoutObject()->DestroyAndCleanupAnonymousWrappers();
1715 SetLayoutObject(nullptr);
1716 if (!performing_reattach) {
1717 // We are clearing the ComputedStyle for elements, which means we should not
1718 // need to recalc style. Also, this way we can detect if we need to remove
1719 // this Node as a StyleRecalcRoot if this detach is because the node is
1720 // removed from the flat tree. That is necessary because we are not allowed
1721 // to have a style recalc root outside the flat tree when traversing the
1722 // flat tree for style recalc (see StyleRecalcRoot::RemovedFromFlatTree()).
1723 ClearNeedsStyleRecalc();
1724 ClearChildNeedsStyleRecalc();
1725 }
1726 }
1727
VirtualEnsureComputedStyle(PseudoId pseudo_element_specifier)1728 const ComputedStyle* Node::VirtualEnsureComputedStyle(
1729 PseudoId pseudo_element_specifier) {
1730 return ParentOrShadowHostNode()
1731 ? ParentOrShadowHostNode()->EnsureComputedStyle(
1732 pseudo_element_specifier)
1733 : nullptr;
1734 }
1735
SetForceReattachLayoutTree()1736 void Node::SetForceReattachLayoutTree() {
1737 DCHECK(!GetDocument().GetStyleEngine().InRebuildLayoutTree());
1738 DCHECK(IsElementNode() || IsTextNode());
1739 if (GetForceReattachLayoutTree())
1740 return;
1741 if (!InActiveDocument())
1742 return;
1743 if (IsElementNode()) {
1744 if (!GetComputedStyle()) {
1745 DCHECK(!GetLayoutObject());
1746 return;
1747 }
1748 } else {
1749 DCHECK(IsTextNode());
1750 if (!GetLayoutObject() && ShouldSkipMarkingStyleDirty())
1751 return;
1752 }
1753 SetFlag(kForceReattachLayoutTree);
1754 if (!NeedsStyleRecalc()) {
1755 // Make sure we traverse down to this node during style recalc.
1756 MarkAncestorsWithChildNeedsStyleRecalc();
1757 }
1758 }
1759
1760 // FIXME: Shouldn't these functions be in the editing code? Code that asks
1761 // questions about HTML in the core DOM class is obviously misplaced.
CanStartSelection() const1762 bool Node::CanStartSelection() const {
1763 if (DisplayLockUtilities::NearestLockedExclusiveAncestor(*this))
1764 GetDocument().UpdateStyleAndLayoutTreeForNode(this);
1765 if (HasEditableStyle(*this))
1766 return true;
1767
1768 if (GetLayoutObject()) {
1769 const ComputedStyle& style = GetLayoutObject()->StyleRef();
1770 if (style.UserSelect() == EUserSelect::kNone)
1771 return false;
1772 // We allow selections to begin within |user-select: text/all| sub trees
1773 // but not if the element is draggable.
1774 if (style.UserDrag() != EUserDrag::kElement &&
1775 (style.UserSelect() == EUserSelect::kText ||
1776 style.UserSelect() == EUserSelect::kAll))
1777 return true;
1778 }
1779 ContainerNode* parent = FlatTreeTraversal::Parent(*this);
1780 return parent ? parent->CanStartSelection() : true;
1781 }
1782
NotifyPriorityScrollAnchorStatusChanged()1783 void Node::NotifyPriorityScrollAnchorStatusChanged() {
1784 auto* node = this;
1785 while (node && !node->GetLayoutObject())
1786 node = FlatTreeTraversal::Parent(*node);
1787 if (node) {
1788 DCHECK(node->GetLayoutObject());
1789 node->GetLayoutObject()->NotifyPriorityScrollAnchorStatusChanged();
1790 }
1791 }
1792
1793 // StyledElements allow inline style (style="border: 1px"), presentational
1794 // attributes (ex. color), class names (ex. class="foo bar") and other non-basic
1795 // styling features. They also control if this element can participate in style
1796 // sharing.
1797 //
1798 // FIXME: The only things that ever go through StyleResolver that aren't
1799 // StyledElements are PseudoElements and VTTElements. It's possible we can just
1800 // eliminate all the checks since those elements will never have class names,
1801 // inline style, or other things that this apparently guards against.
IsStyledElement() const1802 bool Node::IsStyledElement() const {
1803 auto* this_element = DynamicTo<Element>(this);
1804 return IsHTMLElement() || IsSVGElement() || IsMathMLElement() ||
1805 (!RuntimeEnabledFeatures::MathMLCoreEnabled() && this_element &&
1806 this_element->namespaceURI() == mathml_names::kNamespaceURI);
1807 }
1808
CanParticipateInFlatTree() const1809 bool Node::CanParticipateInFlatTree() const {
1810 // TODO(hayato): Return false for pseudo elements.
1811 return !IsShadowRoot() && !IsActiveV0InsertionPoint(*this);
1812 }
1813
IsActiveSlotOrActiveV0InsertionPoint() const1814 bool Node::IsActiveSlotOrActiveV0InsertionPoint() const {
1815 return ToHTMLSlotElementIfSupportsAssignmentOrNull(*this) ||
1816 IsActiveV0InsertionPoint(*this);
1817 }
1818
SlotName() const1819 AtomicString Node::SlotName() const {
1820 DCHECK(IsSlotable());
1821 if (IsElementNode()) {
1822 return HTMLSlotElement::NormalizeSlotName(
1823 To<Element>(*this).FastGetAttribute(html_names::kSlotAttr));
1824 }
1825 DCHECK(IsTextNode());
1826 return g_empty_atom;
1827 }
1828
IsInV1ShadowTree() const1829 bool Node::IsInV1ShadowTree() const {
1830 ShadowRoot* shadow_root = ContainingShadowRoot();
1831 return shadow_root && shadow_root->IsV1();
1832 }
1833
IsInV0ShadowTree() const1834 bool Node::IsInV0ShadowTree() const {
1835 ShadowRoot* shadow_root = ContainingShadowRoot();
1836 return shadow_root && !shadow_root->IsV1();
1837 }
1838
ParentElementShadowRoot() const1839 ShadowRoot* Node::ParentElementShadowRoot() const {
1840 Element* parent = parentElement();
1841 return parent ? parent->GetShadowRoot() : nullptr;
1842 }
1843
IsChildOfV1ShadowHost() const1844 bool Node::IsChildOfV1ShadowHost() const {
1845 ShadowRoot* parent_shadow_root = ParentElementShadowRoot();
1846 return parent_shadow_root && parent_shadow_root->IsV1();
1847 }
1848
IsChildOfV0ShadowHost() const1849 bool Node::IsChildOfV0ShadowHost() const {
1850 ShadowRoot* parent_shadow_root = ParentElementShadowRoot();
1851 return parent_shadow_root && !parent_shadow_root->IsV1();
1852 }
1853
V1ShadowRootOfParent() const1854 ShadowRoot* Node::V1ShadowRootOfParent() const {
1855 if (Element* parent = parentElement())
1856 return parent->ShadowRootIfV1();
1857 return nullptr;
1858 }
1859
OwnerShadowHost() const1860 Element* Node::OwnerShadowHost() const {
1861 if (ShadowRoot* root = ContainingShadowRoot())
1862 return &root->host();
1863 return nullptr;
1864 }
1865
ContainingShadowRoot() const1866 ShadowRoot* Node::ContainingShadowRoot() const {
1867 Node& root = GetTreeScope().RootNode();
1868 return DynamicTo<ShadowRoot>(root);
1869 }
1870
NonBoundaryShadowTreeRootNode()1871 Node* Node::NonBoundaryShadowTreeRootNode() {
1872 DCHECK(!IsShadowRoot());
1873 Node* root = this;
1874 while (root) {
1875 if (root->IsShadowRoot())
1876 return root;
1877 Node* parent = root->ParentOrShadowHostNode();
1878 if (parent && parent->IsShadowRoot())
1879 return root;
1880 root = parent;
1881 }
1882 return nullptr;
1883 }
1884
NonShadowBoundaryParentNode() const1885 ContainerNode* Node::NonShadowBoundaryParentNode() const {
1886 ContainerNode* parent = parentNode();
1887 return parent && !parent->IsShadowRoot() ? parent : nullptr;
1888 }
1889
ParentOrShadowHostElement() const1890 Element* Node::ParentOrShadowHostElement() const {
1891 ContainerNode* parent = ParentOrShadowHostNode();
1892 if (!parent)
1893 return nullptr;
1894
1895 if (auto* shadow_root = DynamicTo<ShadowRoot>(parent))
1896 return &shadow_root->host();
1897
1898 return DynamicTo<Element>(parent);
1899 }
1900
ParentOrShadowHostOrTemplateHostNode() const1901 ContainerNode* Node::ParentOrShadowHostOrTemplateHostNode() const {
1902 auto* this_fragment = DynamicTo<DocumentFragment>(this);
1903 if (this_fragment && this_fragment->IsTemplateContent())
1904 return static_cast<const TemplateContentDocumentFragment*>(this)->Host();
1905 return ParentOrShadowHostNode();
1906 }
1907
OriginatingTreeScope() const1908 TreeScope& Node::OriginatingTreeScope() const {
1909 if (const SVGElement* svg_element = DynamicTo<SVGElement>(this)) {
1910 if (const SVGElement* corr_element = svg_element->CorrespondingElement()) {
1911 DCHECK(!corr_element->CorrespondingElement());
1912 return corr_element->GetTreeScope();
1913 }
1914 }
1915 return GetTreeScope();
1916 }
1917
ownerDocument() const1918 Document* Node::ownerDocument() const {
1919 Document* doc = &GetDocument();
1920 return doc == this ? nullptr : doc;
1921 }
1922
baseURI() const1923 const KURL& Node::baseURI() const {
1924 return GetDocument().BaseURL();
1925 }
1926
isEqualNode(Node * other) const1927 bool Node::isEqualNode(Node* other) const {
1928 if (!other)
1929 return false;
1930
1931 NodeType node_type = getNodeType();
1932 if (node_type != other->getNodeType())
1933 return false;
1934
1935 if (nodeValue() != other->nodeValue())
1936 return false;
1937
1938 if (auto* this_attr = DynamicTo<Attr>(this)) {
1939 auto* other_attr = To<Attr>(other);
1940 if (this_attr->localName() != other_attr->localName())
1941 return false;
1942
1943 if (this_attr->namespaceURI() != other_attr->namespaceURI())
1944 return false;
1945 } else if (auto* this_element = DynamicTo<Element>(this)) {
1946 auto* other_element = DynamicTo<Element>(other);
1947 if (this_element->TagQName() != other_element->TagQName())
1948 return false;
1949
1950 if (!this_element->HasEquivalentAttributes(*other_element))
1951 return false;
1952 } else if (nodeName() != other->nodeName()) {
1953 return false;
1954 }
1955
1956 Node* child = firstChild();
1957 Node* other_child = other->firstChild();
1958
1959 while (child) {
1960 if (!child->isEqualNode(other_child))
1961 return false;
1962
1963 child = child->nextSibling();
1964 other_child = other_child->nextSibling();
1965 }
1966
1967 if (other_child)
1968 return false;
1969
1970 if (const auto* document_type_this = DynamicTo<DocumentType>(this)) {
1971 const auto* document_type_other = To<DocumentType>(other);
1972
1973 if (document_type_this->publicId() != document_type_other->publicId())
1974 return false;
1975
1976 if (document_type_this->systemId() != document_type_other->systemId())
1977 return false;
1978 }
1979
1980 return true;
1981 }
1982
isDefaultNamespace(const AtomicString & namespace_uri_maybe_empty) const1983 bool Node::isDefaultNamespace(
1984 const AtomicString& namespace_uri_maybe_empty) const {
1985 // https://dom.spec.whatwg.org/#dom-node-isdefaultnamespace
1986
1987 // 1. If namespace is the empty string, then set it to null.
1988 const AtomicString& namespace_uri = namespace_uri_maybe_empty.IsEmpty()
1989 ? g_null_atom
1990 : namespace_uri_maybe_empty;
1991
1992 // 2. Let defaultNamespace be the result of running locate a namespace for
1993 // context object using null.
1994 const AtomicString& default_namespace = lookupNamespaceURI(String());
1995
1996 // 3. Return true if defaultNamespace is the same as namespace, and false
1997 // otherwise.
1998 return namespace_uri == default_namespace;
1999 }
2000
lookupPrefix(const AtomicString & namespace_uri) const2001 const AtomicString& Node::lookupPrefix(
2002 const AtomicString& namespace_uri) const {
2003 // Implemented according to
2004 // https://dom.spec.whatwg.org/#dom-node-lookupprefix
2005
2006 if (namespace_uri.IsEmpty() || namespace_uri.IsNull())
2007 return g_null_atom;
2008
2009 const Element* context;
2010
2011 switch (getNodeType()) {
2012 case kElementNode:
2013 context = To<Element>(this);
2014 break;
2015 case kDocumentNode:
2016 context = To<Document>(this)->documentElement();
2017 break;
2018 case kDocumentFragmentNode:
2019 case kDocumentTypeNode:
2020 context = nullptr;
2021 break;
2022 case kAttributeNode:
2023 context = To<Attr>(this)->ownerElement();
2024 break;
2025 default:
2026 context = parentElement();
2027 break;
2028 }
2029
2030 if (!context)
2031 return g_null_atom;
2032
2033 return context->LocateNamespacePrefix(namespace_uri);
2034 }
2035
lookupNamespaceURI(const String & specified_prefix) const2036 const AtomicString& Node::lookupNamespaceURI(
2037 const String& specified_prefix) const {
2038 // Implemented according to
2039 // https://dom.spec.whatwg.org/#dom-node-lookupnamespaceuri
2040
2041 // 1. If prefix is the empty string, then set it to null.
2042 String prefix = specified_prefix;
2043 if (!specified_prefix.IsNull() && specified_prefix.IsEmpty())
2044 prefix = String();
2045
2046 // 2. Return the result of running locate a namespace for the context object
2047 // using prefix.
2048
2049 // https://dom.spec.whatwg.org/#locate-a-namespace
2050 switch (getNodeType()) {
2051 case kElementNode: {
2052 const auto& element = To<Element>(*this);
2053
2054 // 1. If its namespace is not null and its namespace prefix is prefix,
2055 // then return namespace.
2056 if (!element.namespaceURI().IsNull() && element.prefix() == prefix)
2057 return element.namespaceURI();
2058
2059 // 2. If it has an attribute whose namespace is the XMLNS namespace,
2060 // namespace prefix is "xmlns", and local name is prefix, or if prefix is
2061 // null and it has an attribute whose namespace is the XMLNS namespace,
2062 // namespace prefix is null, and local name is "xmlns", then return its
2063 // value if it is not the empty string, and null otherwise.
2064 AttributeCollection attributes = element.Attributes();
2065 for (const Attribute& attr : attributes) {
2066 if (attr.Prefix() == g_xmlns_atom && attr.LocalName() == prefix) {
2067 if (!attr.Value().IsEmpty())
2068 return attr.Value();
2069 return g_null_atom;
2070 }
2071 if (attr.LocalName() == g_xmlns_atom && prefix.IsNull()) {
2072 if (!attr.Value().IsEmpty())
2073 return attr.Value();
2074 return g_null_atom;
2075 }
2076 }
2077
2078 // 3. If its parent element is null, then return null.
2079 // 4. Return the result of running locate a namespace on its parent
2080 // element using prefix.
2081 if (Element* parent = parentElement())
2082 return parent->lookupNamespaceURI(prefix);
2083 return g_null_atom;
2084 }
2085 case kDocumentNode:
2086 if (Element* de = To<Document>(this)->documentElement())
2087 return de->lookupNamespaceURI(prefix);
2088 return g_null_atom;
2089 case kDocumentTypeNode:
2090 case kDocumentFragmentNode:
2091 return g_null_atom;
2092 case kAttributeNode: {
2093 const auto* attr = To<Attr>(this);
2094 if (attr->ownerElement())
2095 return attr->ownerElement()->lookupNamespaceURI(prefix);
2096 return g_null_atom;
2097 }
2098 default:
2099 if (Element* parent = parentElement())
2100 return parent->lookupNamespaceURI(prefix);
2101 return g_null_atom;
2102 }
2103 }
2104
textContent(bool convert_brs_to_newlines) const2105 String Node::textContent(bool convert_brs_to_newlines) const {
2106 // This covers ProcessingInstruction and Comment that should return their
2107 // value when .textContent is accessed on them, but should be ignored when
2108 // iterated over as a descendant of a ContainerNode.
2109 if (auto* character_data = DynamicTo<CharacterData>(this))
2110 return character_data->data();
2111
2112 // Attribute nodes have their attribute values as textContent.
2113 if (auto* attr = DynamicTo<Attr>(this))
2114 return attr->value();
2115
2116 // Documents and non-container nodes (that are not CharacterData)
2117 // have null textContent.
2118 if (IsDocumentNode() || !IsContainerNode())
2119 return String();
2120
2121 StringBuilder content;
2122 for (const Node& node : NodeTraversal::InclusiveDescendantsOf(*this)) {
2123 if (IsA<HTMLBRElement>(node) && convert_brs_to_newlines) {
2124 content.Append('\n');
2125 } else if (auto* text_node = DynamicTo<Text>(node)) {
2126 content.Append(text_node->data());
2127 }
2128 }
2129 return content.ToString();
2130 }
2131
setTextContent(const StringOrTrustedScript & string_or_trusted_script,ExceptionState & exception_state)2132 void Node::setTextContent(const StringOrTrustedScript& string_or_trusted_script,
2133 ExceptionState& exception_state) {
2134 String value =
2135 string_or_trusted_script.IsString()
2136 ? string_or_trusted_script.GetAsString()
2137 : string_or_trusted_script.IsTrustedScript()
2138 ? string_or_trusted_script.GetAsTrustedScript()->toString()
2139 : g_empty_string;
2140 setTextContent(value);
2141 }
2142
textContent(StringOrTrustedScript & result)2143 void Node::textContent(StringOrTrustedScript& result) {
2144 String value = textContent();
2145 if (!value.IsNull())
2146 result.SetString(value);
2147 }
2148
setTextContent(const String & text)2149 void Node::setTextContent(const String& text) {
2150 switch (getNodeType()) {
2151 case kAttributeNode:
2152 case kTextNode:
2153 case kCdataSectionNode:
2154 case kCommentNode:
2155 case kProcessingInstructionNode:
2156 setNodeValue(text);
2157 return;
2158 case kElementNode:
2159 case kDocumentFragmentNode: {
2160 // FIXME: Merge this logic into replaceChildrenWithText.
2161 auto* container = To<ContainerNode>(this);
2162
2163 // Note: This is an intentional optimization.
2164 // See crbug.com/352836 also.
2165 // No need to do anything if the text is identical.
2166 if (container->HasOneTextChild() &&
2167 To<Text>(container->firstChild())->data() == text && !text.IsEmpty())
2168 return;
2169
2170 ChildListMutationScope mutation(*this);
2171 // Note: This API will not insert empty text nodes:
2172 // https://dom.spec.whatwg.org/#dom-node-textcontent
2173 if (text.IsEmpty()) {
2174 container->RemoveChildren(kDispatchSubtreeModifiedEvent);
2175 } else {
2176 container->RemoveChildren(kOmitSubtreeModifiedEvent);
2177 container->AppendChild(GetDocument().createTextNode(text),
2178 ASSERT_NO_EXCEPTION);
2179 }
2180 return;
2181 }
2182 case kDocumentNode:
2183 case kDocumentTypeNode:
2184 // Do nothing.
2185 return;
2186 }
2187 NOTREACHED();
2188 }
2189
compareDocumentPosition(const Node * other_node,ShadowTreesTreatment treatment) const2190 uint16_t Node::compareDocumentPosition(const Node* other_node,
2191 ShadowTreesTreatment treatment) const {
2192 if (other_node == this)
2193 return kDocumentPositionEquivalent;
2194
2195 const auto* attr1 = DynamicTo<Attr>(this);
2196 const Attr* attr2 = DynamicTo<Attr>(other_node);
2197
2198 const Node* start1 = attr1 ? attr1->ownerElement() : this;
2199 const Node* start2 = attr2 ? attr2->ownerElement() : other_node;
2200
2201 // If either of start1 or start2 is null, then we are disconnected, since one
2202 // of the nodes is an orphaned attribute node.
2203 if (!start1 || !start2) {
2204 uint16_t direction = (this > other_node) ? kDocumentPositionPreceding
2205 : kDocumentPositionFollowing;
2206 return kDocumentPositionDisconnected |
2207 kDocumentPositionImplementationSpecific | direction;
2208 }
2209
2210 HeapVector<Member<const Node>, 16> chain1;
2211 HeapVector<Member<const Node>, 16> chain2;
2212 if (attr1)
2213 chain1.push_back(attr1);
2214 if (attr2)
2215 chain2.push_back(attr2);
2216
2217 if (attr1 && attr2 && start1 == start2 && start1) {
2218 // We are comparing two attributes on the same node. Crawl our attribute map
2219 // and see which one we hit first.
2220 const Element* owner1 = attr1->ownerElement();
2221 AttributeCollection attributes = owner1->Attributes();
2222 for (const Attribute& attr : attributes) {
2223 // If neither of the two determining nodes is a child node and nodeType is
2224 // the same for both determining nodes, then an implementation-dependent
2225 // order between the determining nodes is returned. This order is stable
2226 // as long as no nodes of the same nodeType are inserted into or removed
2227 // from the direct container. This would be the case, for example, when
2228 // comparing two attributes of the same element, and inserting or removing
2229 // additional attributes might change the order between existing
2230 // attributes.
2231 if (attr1->GetQualifiedName() == attr.GetName())
2232 return kDocumentPositionImplementationSpecific |
2233 kDocumentPositionFollowing;
2234 if (attr2->GetQualifiedName() == attr.GetName())
2235 return kDocumentPositionImplementationSpecific |
2236 kDocumentPositionPreceding;
2237 }
2238
2239 NOTREACHED();
2240 return kDocumentPositionDisconnected;
2241 }
2242
2243 // If one node is in the document and the other is not, we must be
2244 // disconnected. If the nodes have different owning documents, they must be
2245 // disconnected. Note that we avoid comparing Attr nodes here, since they
2246 // return false from isConnected() all the time (which seems like a bug).
2247 if (start1->isConnected() != start2->isConnected() ||
2248 (treatment == kTreatShadowTreesAsDisconnected &&
2249 start1->GetTreeScope() != start2->GetTreeScope())) {
2250 uint16_t direction = (this > other_node) ? kDocumentPositionPreceding
2251 : kDocumentPositionFollowing;
2252 return kDocumentPositionDisconnected |
2253 kDocumentPositionImplementationSpecific | direction;
2254 }
2255
2256 // We need to find a common ancestor container, and then compare the indices
2257 // of the two immediate children.
2258 const Node* current;
2259 for (current = start1; current; current = current->ParentOrShadowHostNode())
2260 chain1.push_back(current);
2261 for (current = start2; current; current = current->ParentOrShadowHostNode())
2262 chain2.push_back(current);
2263
2264 unsigned index1 = chain1.size();
2265 unsigned index2 = chain2.size();
2266
2267 // If the two elements don't have a common root, they're not in the same tree.
2268 if (chain1[index1 - 1] != chain2[index2 - 1]) {
2269 uint16_t direction = (this > other_node) ? kDocumentPositionPreceding
2270 : kDocumentPositionFollowing;
2271 return kDocumentPositionDisconnected |
2272 kDocumentPositionImplementationSpecific | direction;
2273 }
2274
2275 unsigned connection = start1->GetTreeScope() != start2->GetTreeScope()
2276 ? kDocumentPositionDisconnected |
2277 kDocumentPositionImplementationSpecific
2278 : 0;
2279
2280 // Walk the two chains backwards and look for the first difference.
2281 for (unsigned i = std::min(index1, index2); i; --i) {
2282 const Node* child1 = chain1[--index1];
2283 const Node* child2 = chain2[--index2];
2284 if (child1 != child2) {
2285 // If one of the children is an attribute, it wins.
2286 if (child1->getNodeType() == kAttributeNode)
2287 return kDocumentPositionFollowing | connection;
2288 if (child2->getNodeType() == kAttributeNode)
2289 return kDocumentPositionPreceding | connection;
2290
2291 // If one of the children is a shadow root,
2292 if (child1->IsShadowRoot() || child2->IsShadowRoot()) {
2293 if (!child2->IsShadowRoot())
2294 return Node::kDocumentPositionFollowing | connection;
2295 if (!child1->IsShadowRoot())
2296 return Node::kDocumentPositionPreceding | connection;
2297
2298 return Node::kDocumentPositionPreceding | connection;
2299 }
2300
2301 if (!child2->nextSibling())
2302 return kDocumentPositionFollowing | connection;
2303 if (!child1->nextSibling())
2304 return kDocumentPositionPreceding | connection;
2305
2306 // Otherwise we need to see which node occurs first. Crawl backwards from
2307 // child2 looking for child1.
2308 for (const Node* child = child2->previousSibling(); child;
2309 child = child->previousSibling()) {
2310 if (child == child1)
2311 return kDocumentPositionFollowing | connection;
2312 }
2313 return kDocumentPositionPreceding | connection;
2314 }
2315 }
2316
2317 // There was no difference between the two parent chains, i.e., one was a
2318 // subset of the other. The shorter chain is the ancestor.
2319 return index1 < index2 ? kDocumentPositionFollowing |
2320 kDocumentPositionContainedBy | connection
2321 : kDocumentPositionPreceding |
2322 kDocumentPositionContains | connection;
2323 }
2324
InvalidateIfHasEffectiveAppearance() const2325 void Node::InvalidateIfHasEffectiveAppearance() const {
2326 auto* layout_object = GetLayoutObject();
2327 if (!layout_object)
2328 return;
2329
2330 if (!layout_object->StyleRef().HasEffectiveAppearance())
2331 return;
2332
2333 layout_object->SetSubtreeShouldDoFullPaintInvalidation();
2334 }
2335
DebugName() const2336 String Node::DebugName() const {
2337 StringBuilder name;
2338 AppendUnsafe(name, DebugNodeName());
2339 if (const auto* this_element = DynamicTo<Element>(this)) {
2340 if (this_element->HasID()) {
2341 name.Append(" id=\'");
2342 AppendUnsafe(name, this_element->GetIdAttribute());
2343 name.Append('\'');
2344 }
2345
2346 if (this_element->HasClass()) {
2347 name.Append(" class=\'");
2348 for (wtf_size_t i = 0; i < this_element->ClassNames().size(); ++i) {
2349 if (i > 0)
2350 name.Append(' ');
2351 AppendUnsafe(name, this_element->ClassNames()[i]);
2352 }
2353 name.Append('\'');
2354 }
2355 }
2356 return name.ToString();
2357 }
2358
DebugNodeName() const2359 String Node::DebugNodeName() const {
2360 return nodeName();
2361 }
2362
DumpAttributeDesc(const Node & node,const QualifiedName & name,StringBuilder & builder)2363 static void DumpAttributeDesc(const Node& node,
2364 const QualifiedName& name,
2365 StringBuilder& builder) {
2366 auto* element = DynamicTo<Element>(node);
2367 if (!element)
2368 return;
2369 const AtomicString& value = element->getAttribute(name);
2370 if (value.IsEmpty())
2371 return;
2372 builder.Append(' ');
2373 builder.Append(name.ToString());
2374 builder.Append("=");
2375 builder.Append(String(value).EncodeForDebugging());
2376 }
2377
operator <<(std::ostream & ostream,const Node & node)2378 std::ostream& operator<<(std::ostream& ostream, const Node& node) {
2379 return ostream << node.ToString().Utf8();
2380 }
2381
operator <<(std::ostream & ostream,const Node * node)2382 std::ostream& operator<<(std::ostream& ostream, const Node* node) {
2383 if (!node)
2384 return ostream << "null";
2385 return ostream << *node;
2386 }
2387
ToString() const2388 String Node::ToString() const {
2389 if (getNodeType() == Node::kProcessingInstructionNode)
2390 return "?" + nodeName();
2391 if (auto* shadow_root = DynamicTo<ShadowRoot>(this)) {
2392 // nodeName of ShadowRoot is #document-fragment. It's confused with
2393 // DocumentFragment.
2394 std::stringstream shadow_root_type;
2395 shadow_root_type << shadow_root->GetType();
2396 String shadow_root_type_str(shadow_root_type.str().c_str());
2397 return "#shadow-root(" + shadow_root_type_str + ")";
2398 }
2399 if (IsDocumentTypeNode())
2400 return "DOCTYPE " + nodeName();
2401
2402 StringBuilder builder;
2403 builder.Append(nodeName());
2404 if (IsTextNode()) {
2405 builder.Append(" ");
2406 builder.Append(nodeValue().EncodeForDebugging());
2407 return builder.ToString();
2408 }
2409 DumpAttributeDesc(*this, html_names::kIdAttr, builder);
2410 DumpAttributeDesc(*this, html_names::kClassAttr, builder);
2411 DumpAttributeDesc(*this, html_names::kStyleAttr, builder);
2412 if (HasEditableStyle(*this))
2413 builder.Append(" (editable)");
2414 if (GetDocument().FocusedElement() == this)
2415 builder.Append(" (focused)");
2416 return builder.ToString();
2417 }
2418
2419 #if DCHECK_IS_ON()
2420
ToTreeStringForThis() const2421 String Node::ToTreeStringForThis() const {
2422 return ToMarkedTreeString(this, "*");
2423 }
2424
ToFlatTreeStringForThis() const2425 String Node::ToFlatTreeStringForThis() const {
2426 return ToMarkedFlatTreeString(this, "*");
2427 }
2428
PrintNodePathTo(std::ostream & stream) const2429 void Node::PrintNodePathTo(std::ostream& stream) const {
2430 HeapVector<Member<const Node>, 16> chain;
2431 const Node* parent_node = this;
2432 while (parent_node->ParentOrShadowHostNode()) {
2433 chain.push_back(parent_node);
2434 parent_node = parent_node->ParentOrShadowHostNode();
2435 }
2436 for (unsigned index = chain.size(); index > 0; --index) {
2437 const Node* node = chain[index - 1];
2438 if (node->IsShadowRoot()) {
2439 stream << "/#shadow-root";
2440 continue;
2441 }
2442
2443 switch (node->getNodeType()) {
2444 case kElementNode: {
2445 stream << "/" << node->nodeName().Utf8();
2446
2447 const auto* element = To<Element>(node);
2448 const AtomicString& idattr = element->GetIdAttribute();
2449 bool has_id_attr = !idattr.IsNull() && !idattr.IsEmpty();
2450 if (node->previousSibling() || node->nextSibling()) {
2451 int count = 0;
2452 for (const Node* previous = node->previousSibling(); previous;
2453 previous = previous->previousSibling()) {
2454 if (previous->nodeName() == node->nodeName()) {
2455 ++count;
2456 }
2457 }
2458 if (has_id_attr)
2459 stream << "[@id=\"" << idattr.Utf8()
2460 << "\" and position()=" << count << "]";
2461 else
2462 stream << "[" << count << "]";
2463 } else if (has_id_attr) {
2464 stream << "[@id=\"" << idattr.Utf8() << "\"]";
2465 }
2466 break;
2467 }
2468 case kTextNode:
2469 stream << "/text()";
2470 break;
2471 case kAttributeNode:
2472 stream << "/@" << node->nodeName().Utf8();
2473 break;
2474 default:
2475 break;
2476 }
2477 }
2478 }
2479
AppendMarkedTree(const String & base_indent,const Node * root_node,const Node * marked_node1,const char * marked_label1,const Node * marked_node2,const char * marked_label2,StringBuilder & builder)2480 static void AppendMarkedTree(const String& base_indent,
2481 const Node* root_node,
2482 const Node* marked_node1,
2483 const char* marked_label1,
2484 const Node* marked_node2,
2485 const char* marked_label2,
2486 StringBuilder& builder) {
2487 for (const Node& node : NodeTraversal::InclusiveDescendantsOf(*root_node)) {
2488 StringBuilder indent;
2489 if (node == marked_node1)
2490 indent.Append(marked_label1);
2491 if (node == marked_node2)
2492 indent.Append(marked_label2);
2493 indent.Append(base_indent);
2494 for (const Node* tmp_node = &node; tmp_node && tmp_node != root_node;
2495 tmp_node = tmp_node->ParentOrShadowHostNode())
2496 indent.Append('\t');
2497 builder.Append(indent);
2498 builder.Append(node.ToString());
2499 builder.Append("\n");
2500 indent.Append('\t');
2501
2502 if (const auto* element = DynamicTo<Element>(node)) {
2503 if (Element* pseudo = element->GetPseudoElement(kPseudoIdMarker)) {
2504 AppendMarkedTree(indent.ToString(), pseudo, marked_node1, marked_label1,
2505 marked_node2, marked_label2, builder);
2506 }
2507 if (Element* pseudo = element->GetPseudoElement(kPseudoIdBefore))
2508 AppendMarkedTree(indent.ToString(), pseudo, marked_node1, marked_label1,
2509 marked_node2, marked_label2, builder);
2510 if (Element* pseudo = element->GetPseudoElement(kPseudoIdAfter))
2511 AppendMarkedTree(indent.ToString(), pseudo, marked_node1, marked_label1,
2512 marked_node2, marked_label2, builder);
2513 if (Element* pseudo = element->GetPseudoElement(kPseudoIdFirstLetter))
2514 AppendMarkedTree(indent.ToString(), pseudo, marked_node1, marked_label1,
2515 marked_node2, marked_label2, builder);
2516 if (Element* pseudo = element->GetPseudoElement(kPseudoIdBackdrop))
2517 AppendMarkedTree(indent.ToString(), pseudo, marked_node1, marked_label1,
2518 marked_node2, marked_label2, builder);
2519 }
2520
2521 if (ShadowRoot* shadow_root = node.GetShadowRoot()) {
2522 AppendMarkedTree(indent.ToString(), shadow_root, marked_node1,
2523 marked_label1, marked_node2, marked_label2, builder);
2524 }
2525 }
2526 }
2527
AppendMarkedFlatTree(const String & base_indent,const Node * root_node,const Node * marked_node1,const char * marked_label1,const Node * marked_node2,const char * marked_label2,StringBuilder & builder)2528 static void AppendMarkedFlatTree(const String& base_indent,
2529 const Node* root_node,
2530 const Node* marked_node1,
2531 const char* marked_label1,
2532 const Node* marked_node2,
2533 const char* marked_label2,
2534 StringBuilder& builder) {
2535 for (const Node* node = root_node; node;
2536 node = FlatTreeTraversal::NextSibling(*node)) {
2537 StringBuilder indent;
2538 if (node == marked_node1)
2539 indent.Append(marked_label1);
2540 if (node == marked_node2)
2541 indent.Append(marked_label2);
2542 indent.Append(base_indent);
2543 builder.Append(indent);
2544 builder.Append(node->ToString());
2545 builder.Append("\n");
2546 indent.Append('\t');
2547
2548 if (Node* child = FlatTreeTraversal::FirstChild(*node))
2549 AppendMarkedFlatTree(indent.ToString(), child, marked_node1,
2550 marked_label1, marked_node2, marked_label2, builder);
2551 }
2552 }
2553
ToMarkedTreeString(const Node * marked_node1,const char * marked_label1,const Node * marked_node2,const char * marked_label2) const2554 String Node::ToMarkedTreeString(const Node* marked_node1,
2555 const char* marked_label1,
2556 const Node* marked_node2,
2557 const char* marked_label2) const {
2558 const Node* root_node;
2559 const Node* node = this;
2560 while (node->ParentOrShadowHostNode() && !IsA<HTMLBodyElement>(*node))
2561 node = node->ParentOrShadowHostNode();
2562 root_node = node;
2563
2564 StringBuilder builder;
2565 String starting_indent;
2566 AppendMarkedTree(starting_indent, root_node, marked_node1, marked_label1,
2567 marked_node2, marked_label2, builder);
2568 return builder.ToString();
2569 }
2570
ToMarkedFlatTreeString(const Node * marked_node1,const char * marked_label1,const Node * marked_node2,const char * marked_label2) const2571 String Node::ToMarkedFlatTreeString(const Node* marked_node1,
2572 const char* marked_label1,
2573 const Node* marked_node2,
2574 const char* marked_label2) const {
2575 const Node* root_node;
2576 const Node* node = this;
2577 while (node->ParentOrShadowHostNode() && !IsA<HTMLBodyElement>(*node))
2578 node = node->ParentOrShadowHostNode();
2579 root_node = node;
2580
2581 StringBuilder builder;
2582 String starting_indent;
2583 AppendMarkedFlatTree(starting_indent, root_node, marked_node1, marked_label1,
2584 marked_node2, marked_label2, builder);
2585 return builder.ToString();
2586 }
2587
ParentOrShadowHostOrFrameOwner(const Node * node)2588 static ContainerNode* ParentOrShadowHostOrFrameOwner(const Node* node) {
2589 ContainerNode* parent = node->ParentOrShadowHostNode();
2590 if (!parent && node->GetDocument().GetFrame())
2591 parent = node->GetDocument().GetFrame()->DeprecatedLocalOwner();
2592 return parent;
2593 }
2594
PrintSubTreeAcrossFrame(const Node * node,const Node * marked_node,const String & indent,std::ostream & stream)2595 static void PrintSubTreeAcrossFrame(const Node* node,
2596 const Node* marked_node,
2597 const String& indent,
2598 std::ostream& stream) {
2599 if (node == marked_node)
2600 stream << "*";
2601 stream << indent.Utf8() << *node << "\n";
2602 if (auto* frame_owner_element = DynamicTo<HTMLFrameOwnerElement>(node)) {
2603 PrintSubTreeAcrossFrame(frame_owner_element->contentDocument(), marked_node,
2604 indent + "\t", stream);
2605 }
2606 if (ShadowRoot* shadow_root = node->GetShadowRoot())
2607 PrintSubTreeAcrossFrame(shadow_root, marked_node, indent + "\t", stream);
2608 for (const Node* child = node->firstChild(); child;
2609 child = child->nextSibling())
2610 PrintSubTreeAcrossFrame(child, marked_node, indent + "\t", stream);
2611 }
2612
ShowTreeForThisAcrossFrame() const2613 void Node::ShowTreeForThisAcrossFrame() const {
2614 const Node* root_node = this;
2615 while (ParentOrShadowHostOrFrameOwner(root_node))
2616 root_node = ParentOrShadowHostOrFrameOwner(root_node);
2617 std::stringstream stream;
2618 PrintSubTreeAcrossFrame(root_node, this, "", stream);
2619 LOG(INFO) << "\n" << stream.str();
2620 }
2621
2622 #endif
2623
2624 // --------
2625
EnclosingLinkEventParentOrSelf() const2626 Element* Node::EnclosingLinkEventParentOrSelf() const {
2627 // https://crbug.com/784492
2628 DCHECK(this);
2629
2630 for (const Node* node = this; node; node = FlatTreeTraversal::Parent(*node)) {
2631 // For imagemaps, the enclosing link node is the associated area element not
2632 // the image itself. So we don't let images be the enclosingLinkNode, even
2633 // though isLink sometimes returns true for them.
2634 if (node->IsLink() && !IsA<HTMLImageElement>(*node)) {
2635 // Casting to Element is safe because only HTMLAnchorElement,
2636 // HTMLImageElement and SVGAElement can return true for isLink().
2637 return To<Element>(const_cast<Node*>(node));
2638 }
2639 }
2640
2641 return nullptr;
2642 }
2643
InterfaceName() const2644 const AtomicString& Node::InterfaceName() const {
2645 return event_target_names::kNode;
2646 }
2647
GetExecutionContext() const2648 ExecutionContext* Node::GetExecutionContext() const {
2649 return GetDocument().GetExecutionContext();
2650 }
2651
WillMoveToNewDocument(Document & old_document,Document & new_document)2652 void Node::WillMoveToNewDocument(Document& old_document,
2653 Document& new_document) {
2654 if (!old_document.GetPage() ||
2655 old_document.GetPage() == new_document.GetPage())
2656 return;
2657
2658 old_document.GetFrame()->GetEventHandlerRegistry().DidMoveOutOfPage(*this);
2659
2660 if (auto* this_element = DynamicTo<Element>(this)) {
2661 StylePropertyMapReadOnly* computed_style_map_item =
2662 old_document.RemoveComputedStyleMapItem(this_element);
2663 if (computed_style_map_item) {
2664 new_document.AddComputedStyleMapItem(this_element,
2665 computed_style_map_item);
2666 }
2667 }
2668 }
2669
DidMoveToNewDocument(Document & old_document)2670 void Node::DidMoveToNewDocument(Document& old_document) {
2671 TreeScopeAdopter::EnsureDidMoveToNewDocumentWasCalled(old_document);
2672
2673 if (const EventTargetData* event_target_data = GetEventTargetData()) {
2674 const EventListenerMap& listener_map =
2675 event_target_data->event_listener_map;
2676 if (!listener_map.IsEmpty()) {
2677 for (const auto& type : listener_map.EventTypes())
2678 GetDocument().AddListenerTypeIfNeeded(type, *this);
2679 }
2680 }
2681 if (auto* text_node = DynamicTo<Text>(this))
2682 old_document.Markers().RemoveMarkersForNode(*text_node);
2683 if (GetDocument().GetPage() &&
2684 GetDocument().GetPage() != old_document.GetPage()) {
2685 GetDocument().GetFrame()->GetEventHandlerRegistry().DidMoveIntoPage(*this);
2686 }
2687
2688 if (const HeapVector<Member<MutationObserverRegistration>>* registry =
2689 MutationObserverRegistry()) {
2690 for (const auto& registration : *registry) {
2691 GetDocument().AddMutationObserverTypes(registration->MutationTypes());
2692 }
2693 }
2694
2695 if (TransientMutationObserverRegistry()) {
2696 for (MutationObserverRegistration* registration :
2697 *TransientMutationObserverRegistry())
2698 GetDocument().AddMutationObserverTypes(registration->MutationTypes());
2699 }
2700 }
2701
AddedEventListener(const AtomicString & event_type,RegisteredEventListener & registered_listener)2702 void Node::AddedEventListener(const AtomicString& event_type,
2703 RegisteredEventListener& registered_listener) {
2704 EventTarget::AddedEventListener(event_type, registered_listener);
2705 GetDocument().AddListenerTypeIfNeeded(event_type, *this);
2706 if (auto* frame = GetDocument().GetFrame()) {
2707 frame->GetEventHandlerRegistry().DidAddEventHandler(
2708 *this, event_type, registered_listener.Options());
2709 // We need to track the existence of the visibilitychange event listeners to
2710 // enable/disable sudden terminations.
2711 if (IsDocumentNode() && event_type == event_type_names::kVisibilitychange) {
2712 frame->AddedSuddenTerminationDisablerListener(*this, event_type);
2713 }
2714 }
2715 if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
2716 cache->HandleEventListenerAdded(*this, event_type);
2717 }
2718
RemovedEventListener(const AtomicString & event_type,const RegisteredEventListener & registered_listener)2719 void Node::RemovedEventListener(
2720 const AtomicString& event_type,
2721 const RegisteredEventListener& registered_listener) {
2722 EventTarget::RemovedEventListener(event_type, registered_listener);
2723 // FIXME: Notify Document that the listener has vanished. We need to keep
2724 // track of a number of listeners for each type, not just a bool - see
2725 // https://bugs.webkit.org/show_bug.cgi?id=33861
2726 if (auto* frame = GetDocument().GetFrame()) {
2727 frame->GetEventHandlerRegistry().DidRemoveEventHandler(
2728 *this, event_type, registered_listener.Options());
2729 // We need to track the existence of the visibilitychange event listeners to
2730 // enable/disable sudden terminations.
2731 if (IsDocumentNode() && event_type == event_type_names::kVisibilitychange) {
2732 frame->RemovedSuddenTerminationDisablerListener(*this, event_type);
2733 }
2734 }
2735 if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
2736 cache->HandleEventListenerRemoved(*this, event_type);
2737 }
2738
RemoveAllEventListeners()2739 void Node::RemoveAllEventListeners() {
2740 Vector<AtomicString> event_types = EventTypes();
2741 if (HasEventListeners() && GetDocument().GetPage())
2742 GetDocument()
2743 .GetFrame()
2744 ->GetEventHandlerRegistry()
2745 .DidRemoveAllEventHandlers(*this);
2746 EventTarget::RemoveAllEventListeners();
2747 if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache()) {
2748 for (const AtomicString& event_type : event_types)
2749 cache->HandleEventListenerRemoved(*this, event_type);
2750 }
2751 }
2752
RemoveAllEventListenersRecursively()2753 void Node::RemoveAllEventListenersRecursively() {
2754 ScriptForbiddenScope forbid_script_during_raw_iteration;
2755 for (Node& node : NodeTraversal::StartsAt(*this)) {
2756 node.RemoveAllEventListeners();
2757 if (ShadowRoot* root = node.GetShadowRoot())
2758 root->RemoveAllEventListenersRecursively();
2759 }
2760 }
2761
2762 using EventTargetDataMap =
2763 HeapHashMap<WeakMember<Node>, Member<EventTargetData>>;
GetEventTargetDataMap()2764 static EventTargetDataMap& GetEventTargetDataMap() {
2765 DEFINE_STATIC_LOCAL(Persistent<EventTargetDataMap>, map,
2766 (MakeGarbageCollected<EventTargetDataMap>()));
2767 return *map;
2768 }
2769
GetEventTargetData()2770 EventTargetData* Node::GetEventTargetData() {
2771 return HasEventTargetData() ? GetEventTargetDataMap().at(this) : nullptr;
2772 }
2773
EnsureEventTargetData()2774 EventTargetData& Node::EnsureEventTargetData() {
2775 if (HasEventTargetData())
2776 return *GetEventTargetDataMap().at(this);
2777 DCHECK(!GetEventTargetDataMap().Contains(this));
2778 EventTargetData* data = MakeGarbageCollected<EventTargetData>();
2779 GetEventTargetDataMap().Set(this, data);
2780 SetHasEventTargetData(true);
2781 return *data;
2782 }
2783
2784 const HeapVector<Member<MutationObserverRegistration>>*
MutationObserverRegistry()2785 Node::MutationObserverRegistry() {
2786 if (!HasRareData())
2787 return nullptr;
2788 NodeMutationObserverData* data = RareData()->MutationObserverData();
2789 if (!data)
2790 return nullptr;
2791 return &data->Registry();
2792 }
2793
2794 const HeapHashSet<Member<MutationObserverRegistration>>*
TransientMutationObserverRegistry()2795 Node::TransientMutationObserverRegistry() {
2796 if (!HasRareData())
2797 return nullptr;
2798 NodeMutationObserverData* data = RareData()->MutationObserverData();
2799 if (!data)
2800 return nullptr;
2801 return &data->TransientRegistry();
2802 }
2803
2804 template <typename Registry>
CollectMatchingObserversForMutation(HeapHashMap<Member<MutationObserver>,MutationRecordDeliveryOptions> & observers,Registry * registry,Node & target,MutationType type,const QualifiedName * attribute_name)2805 static inline void CollectMatchingObserversForMutation(
2806 HeapHashMap<Member<MutationObserver>, MutationRecordDeliveryOptions>&
2807 observers,
2808 Registry* registry,
2809 Node& target,
2810 MutationType type,
2811 const QualifiedName* attribute_name) {
2812 if (!registry)
2813 return;
2814
2815 for (const auto& registration : *registry) {
2816 if (registration->ShouldReceiveMutationFrom(target, type, attribute_name)) {
2817 MutationRecordDeliveryOptions delivery_options =
2818 registration->DeliveryOptions();
2819 HeapHashMap<Member<MutationObserver>,
2820 MutationRecordDeliveryOptions>::AddResult result =
2821 observers.insert(®istration->Observer(), delivery_options);
2822 if (!result.is_new_entry)
2823 result.stored_value->value |= delivery_options;
2824 }
2825 }
2826 }
2827
GetRegisteredMutationObserversOfType(HeapHashMap<Member<MutationObserver>,MutationRecordDeliveryOptions> & observers,MutationType type,const QualifiedName * attribute_name)2828 void Node::GetRegisteredMutationObserversOfType(
2829 HeapHashMap<Member<MutationObserver>, MutationRecordDeliveryOptions>&
2830 observers,
2831 MutationType type,
2832 const QualifiedName* attribute_name) {
2833 DCHECK((type == kMutationTypeAttributes && attribute_name) ||
2834 !attribute_name);
2835 CollectMatchingObserversForMutation(observers, MutationObserverRegistry(),
2836 *this, type, attribute_name);
2837 CollectMatchingObserversForMutation(observers,
2838 TransientMutationObserverRegistry(),
2839 *this, type, attribute_name);
2840 ScriptForbiddenScope forbid_script_during_raw_iteration;
2841 for (Node* node = parentNode(); node; node = node->parentNode()) {
2842 CollectMatchingObserversForMutation(observers,
2843 node->MutationObserverRegistry(), *this,
2844 type, attribute_name);
2845 CollectMatchingObserversForMutation(
2846 observers, node->TransientMutationObserverRegistry(), *this, type,
2847 attribute_name);
2848 }
2849 }
2850
RegisterMutationObserver(MutationObserver & observer,MutationObserverOptions options,const HashSet<AtomicString> & attribute_filter)2851 void Node::RegisterMutationObserver(
2852 MutationObserver& observer,
2853 MutationObserverOptions options,
2854 const HashSet<AtomicString>& attribute_filter) {
2855 MutationObserverRegistration* registration = nullptr;
2856 for (const auto& item :
2857 EnsureRareData().EnsureMutationObserverData().Registry()) {
2858 if (&item->Observer() == &observer) {
2859 registration = item.Get();
2860 registration->ResetObservation(options, attribute_filter);
2861 }
2862 }
2863
2864 if (!registration) {
2865 registration = MakeGarbageCollected<MutationObserverRegistration>(
2866 observer, this, options, attribute_filter);
2867 EnsureRareData().EnsureMutationObserverData().AddRegistration(registration);
2868 }
2869
2870 GetDocument().AddMutationObserverTypes(registration->MutationTypes());
2871 }
2872
UnregisterMutationObserver(MutationObserverRegistration * registration)2873 void Node::UnregisterMutationObserver(
2874 MutationObserverRegistration* registration) {
2875 const HeapVector<Member<MutationObserverRegistration>>* registry =
2876 MutationObserverRegistry();
2877 DCHECK(registry);
2878 if (!registry)
2879 return;
2880
2881 // FIXME: Simplify the registration/transient registration logic to make this
2882 // understandable by humans. The explicit dispose() is needed to have the
2883 // registration object unregister itself promptly.
2884 registration->Dispose();
2885 EnsureRareData().EnsureMutationObserverData().RemoveRegistration(
2886 registration);
2887 }
2888
RegisterTransientMutationObserver(MutationObserverRegistration * registration)2889 void Node::RegisterTransientMutationObserver(
2890 MutationObserverRegistration* registration) {
2891 EnsureRareData().EnsureMutationObserverData().AddTransientRegistration(
2892 registration);
2893 }
2894
UnregisterTransientMutationObserver(MutationObserverRegistration * registration)2895 void Node::UnregisterTransientMutationObserver(
2896 MutationObserverRegistration* registration) {
2897 const HeapHashSet<Member<MutationObserverRegistration>>* transient_registry =
2898 TransientMutationObserverRegistry();
2899 DCHECK(transient_registry);
2900 if (!transient_registry)
2901 return;
2902
2903 EnsureRareData().EnsureMutationObserverData().RemoveTransientRegistration(
2904 registration);
2905 }
2906
NotifyMutationObserversNodeWillDetach()2907 void Node::NotifyMutationObserversNodeWillDetach() {
2908 if (!GetDocument().HasMutationObservers())
2909 return;
2910
2911 ScriptForbiddenScope forbid_script_during_raw_iteration;
2912 for (Node* node = parentNode(); node; node = node->parentNode()) {
2913 if (const HeapVector<Member<MutationObserverRegistration>>* registry =
2914 node->MutationObserverRegistry()) {
2915 for (const auto& registration : *registry)
2916 registration->ObservedSubtreeNodeWillDetach(*this);
2917 }
2918
2919 if (const HeapHashSet<Member<MutationObserverRegistration>>*
2920 transient_registry = node->TransientMutationObserverRegistry()) {
2921 for (auto& registration : *transient_registry)
2922 registration->ObservedSubtreeNodeWillDetach(*this);
2923 }
2924 }
2925 }
2926
HandleLocalEvents(Event & event)2927 void Node::HandleLocalEvents(Event& event) {
2928 if (!HasEventTargetData())
2929 return;
2930
2931 if (IsDisabledFormControl(this) && IsA<MouseEvent>(event) &&
2932 !RuntimeEnabledFeatures::SendMouseEventsDisabledFormControlsEnabled()) {
2933 if (HasEventListeners(event.type())) {
2934 UseCounter::Count(GetDocument(),
2935 WebFeature::kDispatchMouseEventOnDisabledFormControl);
2936 if (event.type() == event_type_names::kMousedown ||
2937 event.type() == event_type_names::kMouseup) {
2938 UseCounter::Count(
2939 GetDocument(),
2940 WebFeature::kDispatchMouseUpDownEventOnDisabledFormControl);
2941 }
2942 }
2943 return;
2944 }
2945
2946 FireEventListeners(event);
2947 }
2948
DispatchScopedEvent(Event & event)2949 void Node::DispatchScopedEvent(Event& event) {
2950 event.SetTrusted(true);
2951 EventDispatcher::DispatchScopedEvent(*this, event);
2952 }
2953
DispatchEventInternal(Event & event)2954 DispatchEventResult Node::DispatchEventInternal(Event& event) {
2955 return EventDispatcher::DispatchEvent(*this, event);
2956 }
2957
DispatchSubtreeModifiedEvent()2958 void Node::DispatchSubtreeModifiedEvent() {
2959 if (IsInShadowTree())
2960 return;
2961
2962 #if DCHECK_IS_ON()
2963 DCHECK(!EventDispatchForbiddenScope::IsEventDispatchForbidden());
2964 #endif
2965
2966 if (!GetDocument().HasListenerType(Document::kDOMSubtreeModifiedListener))
2967 return;
2968
2969 DispatchScopedEvent(*MutationEvent::Create(
2970 event_type_names::kDOMSubtreeModified, Event::Bubbles::kYes));
2971 }
2972
DispatchDOMActivateEvent(int detail,Event & underlying_event)2973 DispatchEventResult Node::DispatchDOMActivateEvent(int detail,
2974 Event& underlying_event) {
2975 #if DCHECK_IS_ON()
2976 DCHECK(!EventDispatchForbiddenScope::IsEventDispatchForbidden());
2977 #endif
2978 UIEvent& event = *UIEvent::Create();
2979 event.initUIEvent(event_type_names::kDOMActivate, true, true,
2980 GetDocument().domWindow(), detail);
2981 event.SetUnderlyingEvent(&underlying_event);
2982 event.SetComposed(underlying_event.composed());
2983 if (!isConnected())
2984 event.SetCopyEventPathFromUnderlyingEvent();
2985 DispatchScopedEvent(event);
2986
2987 // TODO(dtapuska): Dispatching scoped events shouldn't check the return
2988 // type because the scoped event could get put off in the delayed queue.
2989 return EventTarget::GetDispatchEventResult(event);
2990 }
2991
DispatchSimulatedClick(const Event * underlying_event,SimulatedClickMouseEventOptions event_options,SimulatedClickCreationScope scope)2992 void Node::DispatchSimulatedClick(const Event* underlying_event,
2993 SimulatedClickMouseEventOptions event_options,
2994 SimulatedClickCreationScope scope) {
2995 if (auto* element = IsElementNode() ? To<Element>(this) : parentElement()) {
2996 element->ActivateDisplayLockIfNeeded(
2997 DisplayLockActivationReason::kSimulatedClick);
2998 }
2999 EventDispatcher::DispatchSimulatedClick(*this, underlying_event,
3000 event_options, scope);
3001 }
3002
DefaultEventHandler(Event & event)3003 void Node::DefaultEventHandler(Event& event) {
3004 if (event.target() != this)
3005 return;
3006 const AtomicString& event_type = event.type();
3007 if (event_type == event_type_names::kKeydown ||
3008 event_type == event_type_names::kKeypress ||
3009 event_type == event_type_names::kKeyup) {
3010 if (auto* keyboard_event = DynamicTo<KeyboardEvent>(&event)) {
3011 if (LocalFrame* frame = GetDocument().GetFrame()) {
3012 frame->GetEventHandler().DefaultKeyboardEventHandler(keyboard_event);
3013 }
3014 }
3015 } else if (event_type == event_type_names::kClick) {
3016 auto* ui_event = DynamicTo<UIEvent>(event);
3017 int detail = ui_event ? ui_event->detail() : 0;
3018 if (DispatchDOMActivateEvent(detail, event) !=
3019 DispatchEventResult::kNotCanceled)
3020 event.SetDefaultHandled();
3021 } else if (event_type == event_type_names::kContextmenu &&
3022 IsA<MouseEvent>(event)) {
3023 if (Page* page = GetDocument().GetPage()) {
3024 page->GetContextMenuController().HandleContextMenuEvent(
3025 To<MouseEvent>(&event));
3026 }
3027 } else if (event_type == event_type_names::kTextInput) {
3028 if (event.HasInterface(event_interface_names::kTextEvent)) {
3029 if (LocalFrame* frame = GetDocument().GetFrame()) {
3030 frame->GetEventHandler().DefaultTextInputEventHandler(
3031 To<TextEvent>(&event));
3032 }
3033 }
3034 } else if (RuntimeEnabledFeatures::MiddleClickAutoscrollEnabled() &&
3035 event_type == event_type_names::kMousedown &&
3036 IsA<MouseEvent>(event)) {
3037 auto& mouse_event = To<MouseEvent>(event);
3038 if (mouse_event.button() ==
3039 static_cast<int16_t>(WebPointerProperties::Button::kMiddle)) {
3040 if (EnclosingLinkEventParentOrSelf())
3041 return;
3042
3043 // Avoid that canBeScrolledAndHasScrollableArea changes layout tree
3044 // structure.
3045 // FIXME: We should avoid synchronous layout if possible. We can
3046 // remove this synchronous layout if we avoid synchronous layout in
3047 // LayoutTextControlSingleLine::scrollHeight
3048 GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kInput);
3049 LayoutObject* layout_object = GetLayoutObject();
3050 while (layout_object && (!layout_object->IsBox() ||
3051 !To<LayoutBox>(layout_object)
3052 ->CanBeScrolledAndHasScrollableArea())) {
3053 if (auto* document = DynamicTo<Document>(layout_object->GetNode())) {
3054 Element* owner = document->LocalOwner();
3055 layout_object = owner ? owner->GetLayoutObject() : nullptr;
3056 } else {
3057 layout_object = layout_object->Parent();
3058 }
3059 }
3060 if (layout_object) {
3061 if (LocalFrame* frame = GetDocument().GetFrame())
3062 frame->GetEventHandler().StartMiddleClickAutoscroll(layout_object);
3063 }
3064 }
3065 }
3066 }
3067
UpdateHadKeyboardEvent(const Event & event)3068 void Node::UpdateHadKeyboardEvent(const Event& event) {
3069 if (GetDocument().HadKeyboardEvent())
3070 return;
3071
3072 GetDocument().SetHadKeyboardEvent(true);
3073
3074 // Changes to HadKeyboardEvent may affect :focus-visible matching,
3075 // ShouldHaveFocusAppearance and theme painting.
3076 if (GetLayoutObject()) {
3077 InvalidateIfHasEffectiveAppearance();
3078
3079 auto* this_node = DynamicTo<ContainerNode>(this);
3080 if (RuntimeEnabledFeatures::CSSFocusVisibleEnabled() && this_node)
3081 this_node->FocusVisibleStateChanged();
3082 }
3083 }
3084
HasActivationBehavior() const3085 bool Node::HasActivationBehavior() const {
3086 return false;
3087 }
3088
WillRespondToMouseMoveEvents()3089 bool Node::WillRespondToMouseMoveEvents() {
3090 if (IsDisabledFormControl(this))
3091 return false;
3092 return HasEventListeners(event_type_names::kMousemove) ||
3093 HasEventListeners(event_type_names::kMouseover) ||
3094 HasEventListeners(event_type_names::kMouseout);
3095 }
3096
WillRespondToMouseClickEvents()3097 bool Node::WillRespondToMouseClickEvents() {
3098 if (IsDisabledFormControl(this))
3099 return false;
3100 GetDocument().UpdateStyleAndLayoutTree();
3101 return HasEditableStyle(*this) ||
3102 HasAnyEventListeners(event_util::MouseButtonEventTypes());
3103 }
3104
ConnectedSubframeCount() const3105 unsigned Node::ConnectedSubframeCount() const {
3106 return HasRareData() ? RareData()->ConnectedSubframeCount() : 0;
3107 }
3108
IncrementConnectedSubframeCount()3109 void Node::IncrementConnectedSubframeCount() {
3110 DCHECK(IsContainerNode());
3111 EnsureRareData().IncrementConnectedSubframeCount();
3112 }
3113
DecrementConnectedSubframeCount()3114 void Node::DecrementConnectedSubframeCount() {
3115 RareData()->DecrementConnectedSubframeCount();
3116 }
3117
getDestinationInsertionPoints()3118 StaticNodeList* Node::getDestinationInsertionPoints() {
3119 // TODO(crbug.com/937746): Anything caught by this DCHECK is using the
3120 // now-removed Shadow DOM v0 API.
3121 DCHECK(false)
3122 << "Shadow DOM v0 has been removed (getDestinationInsertionPoints).";
3123
3124 UpdateDistributionForLegacyDistributedNodes();
3125 HeapVector<Member<V0InsertionPoint>, 8> insertion_points;
3126 CollectDestinationInsertionPoints(*this, insertion_points);
3127 HeapVector<Member<Node>> filtered_insertion_points;
3128 for (const auto& insertion_point : insertion_points) {
3129 DCHECK(insertion_point->ContainingShadowRoot());
3130 if (!insertion_point->ContainingShadowRoot()->IsOpenOrV0())
3131 break;
3132 filtered_insertion_points.push_back(insertion_point);
3133 }
3134 return StaticNodeList::Adopt(filtered_insertion_points);
3135 }
3136
AssignedSlot() const3137 HTMLSlotElement* Node::AssignedSlot() const {
3138 DCHECK(!IsPseudoElement());
3139 ShadowRoot* root = V1ShadowRootOfParent();
3140 if (!root)
3141 return nullptr;
3142
3143 if (!root->HasSlotAssignment())
3144 return nullptr;
3145
3146 // TODO(hayato): Node::AssignedSlot() shouldn't be called while
3147 // in executing RecalcAssignment(), however, unfortunately,
3148 // that could happen as follows:
3149 //
3150 // 1. RecalcAssignment() can detach a node
3151 // 2. Then, DetachLayoutTree() may use FlatTreeTraversal via the hook of
3152 // AXObjectCacheImpl::ChildrenChanged().
3153 //
3154 // Note that using FlatTreeTraversal in detaching layout tree should be banned
3155 // in the long term.
3156 //
3157 // If we can remove such code path, we don't need to check
3158 // IsInSlotAssignmentRecalc() here.
3159 if (GetDocument().IsInSlotAssignmentRecalc()) {
3160 // FlatTreeNodeData is not realiable here. Entering slow path.
3161 return root->AssignedSlotFor(*this);
3162 }
3163
3164 // Recalc assignment, if necessary, to make sure the FlatTreeNodeData is not
3165 // dirty. RecalcAssignment() is almost no-op if we don't need to recalc.
3166 root->GetSlotAssignment().RecalcAssignment();
3167 if (FlatTreeNodeData* data = GetFlatTreeNodeData()) {
3168 DCHECK_EQ(root->AssignedSlotFor(*this), data->AssignedSlot());
3169 return data->AssignedSlot();
3170 }
3171 return nullptr;
3172 }
3173
assignedSlotForBinding()3174 HTMLSlotElement* Node::assignedSlotForBinding() {
3175 // assignedSlot doesn't need to recalc slot assignment
3176 if (ShadowRoot* root = V1ShadowRootOfParent()) {
3177 if (root->GetType() == ShadowRootType::kOpen)
3178 return AssignedSlot();
3179 }
3180 return nullptr;
3181 }
3182
SetFocused(bool flag,mojom::blink::FocusType focus_type)3183 void Node::SetFocused(bool flag, mojom::blink::FocusType focus_type) {
3184 if (focus_type == mojom::blink::FocusType::kMouse)
3185 GetDocument().SetHadKeyboardEvent(false);
3186 GetDocument().UserActionElements().SetFocused(this, flag);
3187 }
3188
SetHasFocusWithin(bool flag)3189 void Node::SetHasFocusWithin(bool flag) {
3190 GetDocument().UserActionElements().SetHasFocusWithin(this, flag);
3191 }
3192
SetDragged(bool flag)3193 void Node::SetDragged(bool flag) {
3194 GetDocument().UserActionElements().SetDragged(this, flag);
3195 }
3196
IsUserActionElementActive() const3197 bool Node::IsUserActionElementActive() const {
3198 DCHECK(IsUserActionElement());
3199 return GetDocument().UserActionElements().IsActive(this);
3200 }
3201
IsUserActionElementInActiveChain() const3202 bool Node::IsUserActionElementInActiveChain() const {
3203 DCHECK(IsUserActionElement());
3204 return GetDocument().UserActionElements().IsInActiveChain(this);
3205 }
3206
IsUserActionElementDragged() const3207 bool Node::IsUserActionElementDragged() const {
3208 DCHECK(IsUserActionElement());
3209 return GetDocument().UserActionElements().IsDragged(this);
3210 }
3211
IsUserActionElementHovered() const3212 bool Node::IsUserActionElementHovered() const {
3213 DCHECK(IsUserActionElement());
3214 return GetDocument().UserActionElements().IsHovered(this);
3215 }
3216
IsUserActionElementFocused() const3217 bool Node::IsUserActionElementFocused() const {
3218 DCHECK(IsUserActionElement());
3219 return GetDocument().UserActionElements().IsFocused(this);
3220 }
3221
IsUserActionElementHasFocusWithin() const3222 bool Node::IsUserActionElementHasFocusWithin() const {
3223 DCHECK(IsUserActionElement());
3224 return GetDocument().UserActionElements().HasFocusWithin(this);
3225 }
3226
SetCustomElementState(CustomElementState new_state)3227 void Node::SetCustomElementState(CustomElementState new_state) {
3228 CustomElementState old_state = GetCustomElementState();
3229
3230 switch (new_state) {
3231 case CustomElementState::kUncustomized:
3232 NOTREACHED(); // Everything starts in this state
3233 return;
3234
3235 case CustomElementState::kUndefined:
3236 DCHECK_EQ(CustomElementState::kUncustomized, old_state);
3237 break;
3238
3239 case CustomElementState::kCustom:
3240 DCHECK(old_state == CustomElementState::kUndefined ||
3241 old_state == CustomElementState::kFailed ||
3242 old_state == CustomElementState::kPreCustomized);
3243 break;
3244
3245 case CustomElementState::kFailed:
3246 DCHECK_NE(CustomElementState::kFailed, old_state);
3247 break;
3248
3249 case CustomElementState::kPreCustomized:
3250 DCHECK_EQ(CustomElementState::kFailed, old_state);
3251 break;
3252 }
3253
3254 DCHECK(IsHTMLElement());
3255 DCHECK_NE(kV0Upgraded, GetV0CustomElementState());
3256
3257 auto* element = To<Element>(this);
3258 bool was_defined = element->IsDefined();
3259
3260 node_flags_ = (node_flags_ & ~kCustomElementStateMask) |
3261 static_cast<NodeFlags>(new_state);
3262 DCHECK(new_state == GetCustomElementState());
3263
3264 if (element->IsDefined() != was_defined) {
3265 element->PseudoStateChanged(CSSSelector::kPseudoDefined);
3266 if (RuntimeEnabledFeatures::CustomElementsV0Enabled())
3267 element->PseudoStateChanged(CSSSelector::kPseudoUnresolved);
3268 }
3269 }
3270
SetV0CustomElementState(V0CustomElementState new_state)3271 void Node::SetV0CustomElementState(V0CustomElementState new_state) {
3272 DCHECK(RuntimeEnabledFeatures::CustomElementsV0Enabled());
3273 V0CustomElementState old_state = GetV0CustomElementState();
3274
3275 switch (new_state) {
3276 case kV0NotCustomElement:
3277 NOTREACHED(); // Everything starts in this state
3278 return;
3279
3280 case kV0WaitingForUpgrade:
3281 DCHECK_EQ(kV0NotCustomElement, old_state);
3282 break;
3283
3284 case kV0Upgraded:
3285 DCHECK_EQ(kV0WaitingForUpgrade, old_state);
3286 break;
3287 }
3288
3289 DCHECK(IsHTMLElement() || IsSVGElement());
3290 DCHECK(CustomElementState::kCustom != GetCustomElementState());
3291 SetFlag(kV0CustomElementFlag);
3292 SetFlag(new_state == kV0Upgraded, kV0CustomElementUpgradedFlag);
3293
3294 if (old_state == kV0NotCustomElement || new_state == kV0Upgraded) {
3295 To<Element>(this)->PseudoStateChanged(CSSSelector::kPseudoUnresolved);
3296 To<Element>(this)->PseudoStateChanged(CSSSelector::kPseudoDefined);
3297 }
3298 }
3299
CheckSlotChange(SlotChangeType slot_change_type)3300 void Node::CheckSlotChange(SlotChangeType slot_change_type) {
3301 // Common check logic is used in both cases, "after inserted" and "before
3302 // removed".
3303
3304 // Relevant DOM Standard:
3305 // https://dom.spec.whatwg.org/#concept-node-insert
3306 // https://dom.spec.whatwg.org/#concept-node-remove
3307
3308 // This function is usually called while DOM Mutation is still in-progress.
3309 // For "after inserted" case, we assume that a parent and a child have been
3310 // already connected. For "before removed" case, we assume that a parent and a
3311 // child have not been disconnected yet.
3312
3313 if (!IsSlotable())
3314 return;
3315
3316 if (ShadowRoot* root = V1ShadowRootOfParent()) {
3317 // A shadow host's child can be assigned to a slot in the host's shadow
3318 // tree.
3319
3320 // Although DOM Standard requires "assign a slot for node / run assign
3321 // slotables" at this timing, we skip it as an optimization.
3322 if (HTMLSlotElement* slot = root->AssignedSlotFor(*this))
3323 slot->DidSlotChange(slot_change_type);
3324 } else if (IsInV1ShadowTree()) {
3325 // Checking for fallback content if the node is in a v1 shadow tree.
3326 if (auto* parent_slot = DynamicTo<HTMLSlotElement>(parentElement())) {
3327 DCHECK(parent_slot->SupportsAssignment());
3328 // The parent_slot's assigned nodes might not be calculated because they
3329 // are lazy evaluated later at UpdateDistribution() so we have to check it
3330 // here.
3331 if (!parent_slot->HasAssignedNodesSlow())
3332 parent_slot->DidSlotChange(slot_change_type);
3333 }
3334 }
3335 }
3336
IsEffectiveRootScroller() const3337 bool Node::IsEffectiveRootScroller() const {
3338 return GetLayoutObject() ? GetLayoutObject()->IsEffectiveRootScroller()
3339 : false;
3340 }
3341
AutoscrollBox()3342 LayoutBox* Node::AutoscrollBox() {
3343 return nullptr;
3344 }
3345
StopAutoscroll()3346 void Node::StopAutoscroll() {}
3347
GetWebPluginContainer() const3348 WebPluginContainerImpl* Node::GetWebPluginContainer() const {
3349 if (!IsA<HTMLObjectElement>(this) && !IsA<HTMLEmbedElement>(this)) {
3350 return nullptr;
3351 }
3352
3353 if (auto* embedded = DynamicTo<LayoutEmbeddedContent>(GetLayoutObject()))
3354 return embedded->Plugin();
3355 return nullptr;
3356 }
3357
HasMediaControlAncestor() const3358 bool Node::HasMediaControlAncestor() const {
3359 const Node* current = this;
3360
3361 while (current) {
3362 if (current->IsMediaControls() || current->IsMediaControlElement())
3363 return true;
3364
3365 if (current->IsShadowRoot())
3366 current = current->OwnerShadowHost();
3367 else
3368 current = current->ParentOrShadowHostElement();
3369 }
3370
3371 return false;
3372 }
3373
FlatTreeParentChanged()3374 void Node::FlatTreeParentChanged() {
3375 if (!isConnected())
3376 return;
3377 // TODO(futhark): Replace with DCHECK(IsSlotable()) when Shadow DOM V0 support
3378 // is removed.
3379 if (!IsElementNode() && !IsTextNode()) {
3380 DCHECK(GetDocument().MayContainV0Shadow());
3381 return;
3382 }
3383 if (const ComputedStyle* style = GetComputedStyle()) {
3384 // We are moving a node with ensured computed style into the flat tree.
3385 // Clear ensured styles so that we can use IsEnsuredOutsideFlatTree() to
3386 // determine that we are outside the flat tree before updating the style
3387 // recalc root in MarkAncestorsWithChildNeedsStyleRecalc().
3388 if (style->IsEnsuredOutsideFlatTree())
3389 DetachLayoutTree();
3390 }
3391 // The node changed the flat tree position by being slotted to a new slot or
3392 // slotted for the first time. We need to recalc style since the inheritance
3393 // parent may have changed.
3394 if (NeedsStyleRecalc()) {
3395 // The ancestor chain may have changed. We need to make sure that the
3396 // child-dirty flags are updated, but the SetNeedsStyleRecalc() call below
3397 // will skip MarkAncestorsWithChildNeedsStyleRecalc() if the node was
3398 // already dirty.
3399 MarkAncestorsWithChildNeedsStyleRecalc();
3400 }
3401 SetNeedsStyleRecalc(kLocalStyleChange,
3402 StyleChangeReasonForTracing::Create(
3403 style_change_reason::kFlatTreeChange));
3404 // We also need to force a layout tree re-attach since the layout tree parent
3405 // box may have changed.
3406 SetForceReattachLayoutTree();
3407 }
3408
RemovedFromFlatTree()3409 void Node::RemovedFromFlatTree() {
3410 // This node was previously part of the flat tree, but due to slot re-
3411 // assignment it no longer is. We need to detach the layout tree and notify
3412 // the StyleEngine in case the StyleRecalcRoot is removed from the flat tree.
3413 DetachLayoutTree();
3414 GetDocument().GetStyleEngine().RemovedFromFlatTree(*this);
3415 }
3416
RegisterScrollTimeline(ScrollTimeline * timeline)3417 void Node::RegisterScrollTimeline(ScrollTimeline* timeline) {
3418 EnsureRareData().RegisterScrollTimeline(timeline);
3419 }
UnregisterScrollTimeline(ScrollTimeline * timeline)3420 void Node::UnregisterScrollTimeline(ScrollTimeline* timeline) {
3421 EnsureRareData().UnregisterScrollTimeline(timeline);
3422 }
3423
Trace(Visitor * visitor) const3424 void Node::Trace(Visitor* visitor) const {
3425 visitor->Trace(parent_or_shadow_host_node_);
3426 visitor->Trace(previous_);
3427 visitor->Trace(next_);
3428 visitor->Trace(data_);
3429 visitor->Trace(tree_scope_);
3430 EventTarget::Trace(visitor);
3431 }
3432
3433 } // namespace blink
3434
3435 #if DCHECK_IS_ON()
3436
showNode(const blink::Node * node)3437 void showNode(const blink::Node* node) {
3438 if (node)
3439 LOG(INFO) << *node;
3440 else
3441 LOG(INFO) << "Cannot showNode for <null>";
3442 }
3443
showTree(const blink::Node * node)3444 void showTree(const blink::Node* node) {
3445 if (node)
3446 LOG(INFO) << "\n" << node->ToTreeStringForThis().Utf8();
3447 else
3448 LOG(INFO) << "Cannot showTree for <null>";
3449 }
3450
showNodePath(const blink::Node * node)3451 void showNodePath(const blink::Node* node) {
3452 if (node) {
3453 std::stringstream stream;
3454 node->PrintNodePathTo(stream);
3455 LOG(INFO) << stream.str();
3456 } else {
3457 LOG(INFO) << "Cannot showNodePath for <null>";
3458 }
3459 }
3460
3461 #endif
3462