1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2000 Dirk Mueller (mueller@kde.org)
5 * (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2011 Apple Inc.
7 * All rights reserved.
8 * Copyright (C) 2009 Google Inc. All rights reserved.
9 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved.
10 * (http://www.torchmobile.com/)
11 *
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public License
23 * along with this library; see the file COPYING.LIB. If not, write to
24 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 * Boston, MA 02110-1301, USA.
26 *
27 */
28
29 #include "third_party/blink/renderer/core/layout/layout_object.h"
30
31 #include <algorithm>
32 #include <memory>
33 #include <utility>
34
35 #include "base/allocator/partition_allocator/partition_alloc.h"
36 #include "cc/base/features.h"
37 #include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink.h"
38 #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
39 #include "third_party/blink/renderer/core/animation/element_animations.h"
40 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
41 #include "third_party/blink/renderer/core/css/style_change_reason.h"
42 #include "third_party/blink/renderer/core/css/style_engine.h"
43 #include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
44 #include "third_party/blink/renderer/core/dom/element_traversal.h"
45 #include "third_party/blink/renderer/core/dom/first_letter_pseudo_element.h"
46 #include "third_party/blink/renderer/core/dom/shadow_root.h"
47 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
48 #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
49 #include "third_party/blink/renderer/core/editing/frame_selection.h"
50 #include "third_party/blink/renderer/core/editing/layout_selection.h"
51 #include "third_party/blink/renderer/core/editing/position_with_affinity.h"
52 #include "third_party/blink/renderer/core/editing/text_affinity.h"
53 #include "third_party/blink/renderer/core/editing/visible_units.h"
54 #include "third_party/blink/renderer/core/frame/deprecated_schedule_style_recalc_during_layout.h"
55 #include "third_party/blink/renderer/core/frame/event_handler_registry.h"
56 #include "third_party/blink/renderer/core/frame/local_frame.h"
57 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
58 #include "third_party/blink/renderer/core/frame/settings.h"
59 #include "third_party/blink/renderer/core/html/forms/html_select_element.h"
60 #include "third_party/blink/renderer/core/html/html_element.h"
61 #include "third_party/blink/renderer/core/html/html_html_element.h"
62 #include "third_party/blink/renderer/core/html/html_table_cell_element.h"
63 #include "third_party/blink/renderer/core/html/html_table_element.h"
64 #include "third_party/blink/renderer/core/html/image_document.h"
65 #include "third_party/blink/renderer/core/input/event_handler.h"
66 #include "third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.h"
67 #include "third_party/blink/renderer/core/layout/geometry/transform_state.h"
68 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
69 #include "third_party/blink/renderer/core/layout/layout_counter.h"
70 #include "third_party/blink/renderer/core/layout/layout_custom_scrollbar_part.h"
71 #include "third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h"
72 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
73 #include "third_party/blink/renderer/core/layout/layout_fieldset.h"
74 #include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
75 #include "third_party/blink/renderer/core/layout/layout_flow_thread.h"
76 #include "third_party/blink/renderer/core/layout/layout_grid.h"
77 #include "third_party/blink/renderer/core/layout/layout_image.h"
78 #include "third_party/blink/renderer/core/layout/layout_image_resource_style_image.h"
79 #include "third_party/blink/renderer/core/layout/layout_inline.h"
80 #include "third_party/blink/renderer/core/layout/layout_list_item.h"
81 #include "third_party/blink/renderer/core/layout/layout_list_marker.h"
82 #include "third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h"
83 #include "third_party/blink/renderer/core/layout/layout_object_factory.h"
84 #include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
85 #include "third_party/blink/renderer/core/layout/layout_theme.h"
86 #include "third_party/blink/renderer/core/layout/layout_view.h"
87 #include "third_party/blink/renderer/core/layout/ng/custom/layout_ng_custom.h"
88 #include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
89 #include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
90 #include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
91 #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
92 #include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
93 #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h"
94 #include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
95 #include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
96 #include "third_party/blink/renderer/core/page/autoscroll_controller.h"
97 #include "third_party/blink/renderer/core/page/page.h"
98 #include "third_party/blink/renderer/core/paint/image_element_timing.h"
99 #include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
100 #include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
101 #include "third_party/blink/renderer/core/paint/paint_layer.h"
102 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
103 #include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
104 #include "third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h"
105 #include "third_party/blink/renderer/core/style/content_data.h"
106 #include "third_party/blink/renderer/core/style/cursor_data.h"
107 #include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
108 #include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
109 #include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h"
110 #include "third_party/blink/renderer/platform/graphics/touch_action.h"
111 #include "third_party/blink/renderer/platform/instrumentation/instance_counters.h"
112 #include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h"
113 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
114 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
115 #include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
116 #include "third_party/blink/renderer/platform/wtf/size_assertions.h"
117 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
118 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
119
120 namespace blink {
121
122 namespace {
123
124 // In order for an image to be rendered from the content property, there can be
125 // at most one piece of image content data, followed by some optional
126 // alternative text.
ShouldUseContentData(const ContentData * content_data)127 bool ShouldUseContentData(const ContentData* content_data) {
128 if (!content_data)
129 return false;
130 if (!content_data->IsImage())
131 return false;
132 if (content_data->Next() && !content_data->Next()->IsAltText())
133 return false;
134
135 return true;
136 }
137
138 template <typename Predicate>
FindAncestorByPredicate(const LayoutObject * descendant,LayoutObject::AncestorSkipInfo * skip_info,Predicate predicate)139 LayoutObject* FindAncestorByPredicate(const LayoutObject* descendant,
140 LayoutObject::AncestorSkipInfo* skip_info,
141 Predicate predicate) {
142 for (auto* object = descendant->Parent(); object; object = object->Parent()) {
143 if (predicate(object))
144 return object;
145 if (skip_info)
146 skip_info->Update(*object);
147
148 // According to the HTML standard, a rendered legend is a child of a
149 // fieldset. However a rendered legend is a child of an anonymous fieldset
150 // content box in a LayoutObject tree. NG fragment trees follow the
151 // structure of the standard.
152 //
153 // The following code resolves this inconsistency, and we skip anonymous
154 // fieldset content boxes if |descendant| is in a rendered legend.
155 if (UNLIKELY(object->IsRenderedLegend())) {
156 LayoutObject* legend_parent = object->Parent();
157 if (legend_parent->IsAnonymous()) {
158 if (skip_info)
159 skip_info->Update(*legend_parent);
160 object = legend_parent;
161 }
162 }
163 }
164 return nullptr;
165 }
166
167 } // namespace
168
169 static int g_allow_destroying_layout_object_in_finalizer = 0;
170
171 AllowDestroyingLayoutObjectInFinalizerScope::
AllowDestroyingLayoutObjectInFinalizerScope()172 AllowDestroyingLayoutObjectInFinalizerScope() {
173 ++g_allow_destroying_layout_object_in_finalizer;
174 }
175 AllowDestroyingLayoutObjectInFinalizerScope::
~AllowDestroyingLayoutObjectInFinalizerScope()176 ~AllowDestroyingLayoutObjectInFinalizerScope() {
177 CHECK_GT(g_allow_destroying_layout_object_in_finalizer, 0);
178 --g_allow_destroying_layout_object_in_finalizer;
179 }
180
181 #if DCHECK_IS_ON()
182
SetLayoutNeededForbiddenScope(LayoutObject & layout_object)183 LayoutObject::SetLayoutNeededForbiddenScope::SetLayoutNeededForbiddenScope(
184 LayoutObject& layout_object)
185 : layout_object_(layout_object),
186 preexisting_forbidden_(layout_object_.IsSetNeedsLayoutForbidden()) {
187 layout_object_.SetNeedsLayoutIsForbidden(true);
188 }
189
~SetLayoutNeededForbiddenScope()190 LayoutObject::SetLayoutNeededForbiddenScope::~SetLayoutNeededForbiddenScope() {
191 layout_object_.SetNeedsLayoutIsForbidden(preexisting_forbidden_);
192 }
193 #endif
194
195 struct SameSizeAsLayoutObject : ImageResourceObserver, DisplayItemClient {
196 // Normally this field uses the gap between DisplayItemClient and
197 // LayoutObject's other fields.
198 uint8_t paint_invalidation_reason_;
199 #if DCHECK_IS_ON()
200 unsigned debug_bitfields_;
201 #endif
202 unsigned bitfields_;
203 unsigned bitfields2_;
204 unsigned bitfields3_;
205 void* pointers[4];
206 Member<void*> members[1];
207 // The following fields are in FragmentData.
208 PhysicalOffset paint_offset_;
209 std::unique_ptr<int> rare_data_;
210 #if DCHECK_IS_ON()
211 bool is_destroyed_;
212 #endif
213 };
214
215 ASSERT_SIZE(LayoutObject, SameSizeAsLayoutObject);
216
217 bool LayoutObject::affects_parent_block_ = false;
218
operator new(size_t sz)219 void* LayoutObject::operator new(size_t sz) {
220 DCHECK(IsMainThread());
221 return WTF::Partitions::LayoutPartition()->Alloc(
222 sz, WTF_HEAP_PROFILER_TYPE_NAME(LayoutObject));
223 }
224
operator delete(void * ptr)225 void LayoutObject::operator delete(void* ptr) {
226 DCHECK(IsMainThread());
227 WTF::Partitions::LayoutPartition()->Free(ptr);
228 }
229
CreateObject(Element * element,const ComputedStyle & style,LegacyLayout legacy)230 LayoutObject* LayoutObject::CreateObject(Element* element,
231 const ComputedStyle& style,
232 LegacyLayout legacy) {
233 DCHECK(IsAllowedToModifyLayoutTreeStructure(element->GetDocument()));
234
235 // Minimal support for content properties replacing an entire element.
236 // Works only if we have exactly one piece of content and it's a URL, with
237 // some optional alternative text. Otherwise acts as if we didn't support this
238 // feature.
239 const ContentData* content_data = style.GetContentData();
240 if (!element->IsPseudoElement() && ShouldUseContentData(content_data)) {
241 LayoutImage* image = new LayoutImage(element);
242 // LayoutImageResourceStyleImage requires a style being present on the
243 // image but we don't want to trigger a style change now as the node is
244 // not fully attached. Moving this code to style change doesn't make sense
245 // as it should be run once at layoutObject creation.
246 image->SetStyleInternal(const_cast<ComputedStyle*>(&style));
247 if (const StyleImage* style_image =
248 To<ImageContentData>(content_data)->GetImage()) {
249 image->SetImageResource(
250 MakeGarbageCollected<LayoutImageResourceStyleImage>(
251 const_cast<StyleImage*>(style_image)));
252 image->SetIsGeneratedContent();
253 } else {
254 image->SetImageResource(MakeGarbageCollected<LayoutImageResource>());
255 }
256 image->SetStyleInternal(nullptr);
257 return image;
258 } else if (element->GetPseudoId() == kPseudoIdMarker) {
259 return LayoutObjectFactory::CreateListMarker(*element, style, legacy);
260 }
261
262 switch (style.Display()) {
263 case EDisplay::kNone:
264 case EDisplay::kContents:
265 return nullptr;
266 case EDisplay::kInline:
267 return new LayoutInline(element);
268 case EDisplay::kBlock:
269 case EDisplay::kFlowRoot:
270 case EDisplay::kInlineBlock:
271 case EDisplay::kListItem:
272 return LayoutObjectFactory::CreateBlockFlow(*element, style, legacy);
273 case EDisplay::kTable:
274 case EDisplay::kInlineTable:
275 return LayoutObjectFactory::CreateTable(*element, style, legacy);
276 case EDisplay::kTableRowGroup:
277 case EDisplay::kTableHeaderGroup:
278 case EDisplay::kTableFooterGroup:
279 return LayoutObjectFactory::CreateTableSection(*element, style, legacy);
280 case EDisplay::kTableRow:
281 return LayoutObjectFactory::CreateTableRow(*element, style, legacy);
282 case EDisplay::kTableColumnGroup:
283 case EDisplay::kTableColumn:
284 return LayoutObjectFactory::CreateTableColumn(*element, style, legacy);
285 case EDisplay::kTableCell:
286 return LayoutObjectFactory::CreateTableCell(*element, style, legacy);
287 case EDisplay::kTableCaption:
288 return LayoutObjectFactory::CreateTableCaption(*element, style, legacy);
289 case EDisplay::kWebkitBox:
290 case EDisplay::kWebkitInlineBox:
291 if (style.IsDeprecatedWebkitBoxWithVerticalLineClamp()) {
292 return LayoutObjectFactory::CreateBlockForLineClamp(*element, style,
293 legacy);
294 }
295 if (RuntimeEnabledFeatures::LayoutNGWebkitBoxEnabled())
296 return LayoutObjectFactory::CreateFlexibleBox(*element, style, legacy);
297 UseCounter::Count(element->GetDocument(),
298 WebFeature::kLegacyLayoutByFlexBox);
299 return new LayoutFlexibleBox(element);
300 case EDisplay::kFlex:
301 case EDisplay::kInlineFlex:
302 UseCounter::Count(element->GetDocument(), WebFeature::kCSSFlexibleBox);
303 return LayoutObjectFactory::CreateFlexibleBox(*element, style, legacy);
304 case EDisplay::kGrid:
305 case EDisplay::kInlineGrid:
306 UseCounter::Count(element->GetDocument(), WebFeature::kCSSGridLayout);
307 return LayoutObjectFactory::CreateGrid(*element, style, legacy);
308 case EDisplay::kMath:
309 case EDisplay::kBlockMath:
310 return LayoutObjectFactory::CreateMath(*element, style, legacy);
311 case EDisplay::kLayoutCustom:
312 case EDisplay::kInlineLayoutCustom:
313 DCHECK(RuntimeEnabledFeatures::LayoutNGEnabled());
314 return new LayoutNGCustom(element);
315 }
316
317 NOTREACHED();
318 return nullptr;
319 }
320
LayoutObject(Node * node)321 LayoutObject::LayoutObject(Node* node)
322 : full_paint_invalidation_reason_(PaintInvalidationReason::kNone),
323 #if DCHECK_IS_ON()
324 has_ax_object_(false),
325 set_needs_layout_forbidden_(false),
326 as_image_observer_count_(0),
327 #endif
328 bitfields_(node),
329 style_(nullptr),
330 node_(node),
331 parent_(nullptr),
332 previous_(nullptr),
333 next_(nullptr) {
334 InstanceCounters::IncrementCounter(InstanceCounters::kLayoutObjectCounter);
335 if (node_)
336 GetFrameView()->IncrementLayoutObjectCount();
337
338 if (UNLIKELY(!IsLayoutNGObject())) {
339 if (const auto* element = DynamicTo<Element>(GetNode())) {
340 if (element->ShouldForceLegacyLayout())
341 SetForceLegacyLayout();
342 }
343 }
344 }
345
~LayoutObject()346 LayoutObject::~LayoutObject() {
347 #if DCHECK_IS_ON()
348 DCHECK(!has_ax_object_);
349 DCHECK(BeingDestroyed());
350 #endif
351 InstanceCounters::DecrementCounter(InstanceCounters::kLayoutObjectCounter);
352 #if DCHECK_IS_ON()
353 is_destroyed_ = true;
354 #endif
355 }
356
IsDescendantOf(const LayoutObject * obj) const357 bool LayoutObject::IsDescendantOf(const LayoutObject* obj) const {
358 NOT_DESTROYED();
359 for (const LayoutObject* r = this; r; r = r->parent_) {
360 if (r == obj)
361 return true;
362 }
363 return false;
364 }
365
IsHR() const366 bool LayoutObject::IsHR() const {
367 NOT_DESTROYED();
368 return IsA<HTMLHRElement>(GetNode());
369 }
370
IsStyleGenerated() const371 bool LayoutObject::IsStyleGenerated() const {
372 NOT_DESTROYED();
373 if (const auto* layout_text_fragment = DynamicTo<LayoutTextFragment>(this))
374 return !layout_text_fragment->AssociatedTextNode();
375
376 const Node* node = GetNode();
377 return !node || node->IsPseudoElement();
378 }
379
SetIsInsideFlowThreadIncludingDescendants(bool inside_flow_thread)380 void LayoutObject::SetIsInsideFlowThreadIncludingDescendants(
381 bool inside_flow_thread) {
382 NOT_DESTROYED();
383 LayoutObject* next;
384 for (LayoutObject* object = this; object; object = next) {
385 // If object is a fragmentation context it already updated the descendants
386 // flag accordingly.
387 if (object->IsLayoutFlowThread()) {
388 next = object->NextInPreOrderAfterChildren(this);
389 continue;
390 }
391 next = object->NextInPreOrder(this);
392 DCHECK_NE(inside_flow_thread, object->IsInsideFlowThread());
393 object->SetIsInsideFlowThread(inside_flow_thread);
394 }
395 }
396
RequiresAnonymousTableWrappers(const LayoutObject * new_child) const397 bool LayoutObject::RequiresAnonymousTableWrappers(
398 const LayoutObject* new_child) const {
399 NOT_DESTROYED();
400 // Check should agree with:
401 // CSS 2.1 Tables: 17.2.1 Anonymous table objects
402 // http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes
403 if (new_child->IsLayoutTableCol()) {
404 bool is_column_in_column_group =
405 new_child->StyleRef().Display() == EDisplay::kTableColumn &&
406 IsLayoutTableCol();
407 return !IsTable() && !is_column_in_column_group;
408 }
409 if (new_child->IsTableCaption())
410 return !IsTable();
411 if (new_child->IsTableSection())
412 return !IsTable();
413 if (new_child->IsTableRow())
414 return !IsTableSection();
415 if (new_child->IsTableCell())
416 return !IsTableRow();
417 return false;
418 }
419
420 #if DCHECK_IS_ON()
421
AssertClearedPaintInvalidationFlags() const422 void LayoutObject::AssertClearedPaintInvalidationFlags() const {
423 NOT_DESTROYED();
424 if (!PaintInvalidationStateIsDirty() || ChildPrePaintBlockedByDisplayLock())
425 return;
426 // NG text objects are exempt, as pre-paint walking doesn't visit those with
427 // no paint effects (only white-space, for instance).
428 if ((IsText() && IsLayoutNGObject()) ||
429 // and culled inline boxes too.
430 (IsInLayoutNGInlineFormattingContext() && IsLayoutInline()))
431 return;
432 ShowLayoutTreeForThis();
433 NOTREACHED();
434 }
435
436 #endif // DCHECK_IS_ON()
437
438 DISABLE_CFI_PERF
AddChild(LayoutObject * new_child,LayoutObject * before_child)439 void LayoutObject::AddChild(LayoutObject* new_child,
440 LayoutObject* before_child) {
441 NOT_DESTROYED();
442 DCHECK(IsAllowedToModifyLayoutTreeStructure(GetDocument()));
443
444 LayoutObjectChildList* children = VirtualChildren();
445 DCHECK(children);
446 if (!children)
447 return;
448
449 if (RequiresAnonymousTableWrappers(new_child)) {
450 // Generate an anonymous table or reuse existing one from previous child
451 // Per: 17.2.1 Anonymous table objects 3. Generate missing parents
452 // http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes
453 LayoutObject* table;
454 LayoutObject* after_child =
455 before_child ? before_child->PreviousSibling() : children->LastChild();
456 if (after_child && after_child->IsAnonymous() && after_child->IsTable() &&
457 !after_child->IsBeforeContent()) {
458 table = after_child;
459 } else {
460 table = LayoutObjectFactory::CreateAnonymousTableWithParent(*this);
461 children->InsertChildNode(this, table, before_child);
462 }
463 table->AddChild(new_child);
464 } else {
465 children->InsertChildNode(this, new_child, before_child);
466 }
467
468 if (new_child->IsText() &&
469 new_child->StyleRef().TextTransform() == ETextTransform::kCapitalize)
470 To<LayoutText>(new_child)->TransformText();
471 }
472
RemoveChild(LayoutObject * old_child)473 void LayoutObject::RemoveChild(LayoutObject* old_child) {
474 NOT_DESTROYED();
475 DCHECK(IsAllowedToModifyLayoutTreeStructure(GetDocument()));
476
477 LayoutObjectChildList* children = VirtualChildren();
478 DCHECK(children);
479 if (!children)
480 return;
481
482 children->RemoveChildNode(this, old_child);
483 }
484
NotifyPriorityScrollAnchorStatusChanged()485 void LayoutObject::NotifyPriorityScrollAnchorStatusChanged() {
486 NOT_DESTROYED();
487 if (!Parent())
488 return;
489 for (auto* layer = Parent()->EnclosingLayer(); layer;
490 layer = layer->Parent()) {
491 if (PaintLayerScrollableArea* scrollable_area =
492 layer->GetScrollableArea()) {
493 DCHECK(scrollable_area->GetScrollAnchor());
494 scrollable_area->GetScrollAnchor()->ClearSelf();
495 }
496 }
497 }
498
RegisterSubtreeChangeListenerOnDescendants(bool value)499 void LayoutObject::RegisterSubtreeChangeListenerOnDescendants(bool value) {
500 NOT_DESTROYED();
501 // If we're set to the same value then we're done as that means it's
502 // set down the tree that way already.
503 if (bitfields_.SubtreeChangeListenerRegistered() == value)
504 return;
505
506 bitfields_.SetSubtreeChangeListenerRegistered(value);
507
508 for (LayoutObject* curr = SlowFirstChild(); curr; curr = curr->NextSibling())
509 curr->RegisterSubtreeChangeListenerOnDescendants(value);
510 }
511
NotifyAncestorsOfSubtreeChange()512 void LayoutObject::NotifyAncestorsOfSubtreeChange() {
513 NOT_DESTROYED();
514 if (bitfields_.NotifiedOfSubtreeChange())
515 return;
516
517 bitfields_.SetNotifiedOfSubtreeChange(true);
518 if (Parent())
519 Parent()->NotifyAncestorsOfSubtreeChange();
520 }
521
NotifyOfSubtreeChange()522 void LayoutObject::NotifyOfSubtreeChange() {
523 NOT_DESTROYED();
524 if (!bitfields_.SubtreeChangeListenerRegistered())
525 return;
526 if (bitfields_.NotifiedOfSubtreeChange())
527 return;
528
529 NotifyAncestorsOfSubtreeChange();
530
531 // We can modify the layout tree during layout which means that we may
532 // try to schedule this during performLayout. This should no longer
533 // happen when crbug.com/370457 is fixed.
534 DeprecatedScheduleStyleRecalcDuringLayout marker(GetDocument().Lifecycle());
535 GetDocument().ScheduleLayoutTreeUpdateIfNeeded();
536 }
537
HandleSubtreeModifications()538 void LayoutObject::HandleSubtreeModifications() {
539 NOT_DESTROYED();
540 DCHECK(WasNotifiedOfSubtreeChange());
541 DCHECK(GetDocument().Lifecycle().StateAllowsLayoutTreeNotifications());
542
543 if (ConsumesSubtreeChangeNotification())
544 SubtreeDidChange();
545
546 bitfields_.SetNotifiedOfSubtreeChange(false);
547
548 for (LayoutObject* object = SlowFirstChild(); object;
549 object = object->NextSibling()) {
550 if (!object->WasNotifiedOfSubtreeChange())
551 continue;
552 object->HandleSubtreeModifications();
553 }
554 }
555
NextInPreOrder() const556 LayoutObject* LayoutObject::NextInPreOrder() const {
557 NOT_DESTROYED();
558 if (LayoutObject* o = SlowFirstChild())
559 return o;
560
561 return NextInPreOrderAfterChildren();
562 }
563
HasClipRelatedProperty() const564 bool LayoutObject::HasClipRelatedProperty() const {
565 NOT_DESTROYED();
566 // This function detects a bunch of properties that can potentially affect
567 // clip inheritance chain. However such generalization is practically useless
568 // because these properties change clip inheritance in different way that
569 // needs to be handled explicitly.
570 // CSS clip applies clip to the current element and all descendants.
571 // CSS overflow clip applies only to containing-block descendants.
572 // CSS contain:paint applies to all descendants by making itself a containing
573 // block for all descendants.
574 // CSS clip-path/mask/filter induces a stacking context and applies inherited
575 // clip to that stacking context, while resetting clip for descendants. This
576 // special behavior is already handled elsewhere.
577 if (HasClip() || HasNonVisibleOverflow())
578 return true;
579 // Paint containment establishes isolation which creates clip isolation nodes.
580 // Style & Layout containment also establish isolation (see
581 // |NeedsIsolationNodes| in PaintPropertyTreeBuilder).
582 if (ShouldApplyPaintContainment() ||
583 (ShouldApplyStyleContainment() && ShouldApplyLayoutContainment())) {
584 return true;
585 }
586 if (IsBox() && To<LayoutBox>(this)->HasControlClip())
587 return true;
588 return false;
589 }
590
IsRenderedLegendInternal() const591 bool LayoutObject::IsRenderedLegendInternal() const {
592 NOT_DESTROYED();
593 DCHECK(IsBox());
594 DCHECK(IsRenderedLegendCandidate());
595
596 const auto* parent = Parent();
597 // We may not be inserted into the tree yet.
598 if (!parent)
599 return false;
600 if (RuntimeEnabledFeatures::LayoutNGFieldsetEnabled()) {
601 // If there is a rendered legend, it will be found inside the anonymous
602 // fieldset wrapper. If the anonymous fieldset wrapper is a multi-column,
603 // the rendered legend will be found inside the multi-column flow thread.
604 if (parent->IsLayoutFlowThread())
605 parent = parent->Parent();
606 if (parent->IsAnonymous() && parent->Parent()->IsLayoutNGFieldset())
607 parent = parent->Parent();
608 }
609 const auto* parent_layout_block = DynamicTo<LayoutBlock>(parent);
610 return parent_layout_block && IsA<HTMLFieldSetElement>(parent->GetNode()) &&
611 LayoutFieldset::FindInFlowLegend(*parent_layout_block) == this;
612 }
613
NextInPreOrderAfterChildren() const614 LayoutObject* LayoutObject::NextInPreOrderAfterChildren() const {
615 NOT_DESTROYED();
616 LayoutObject* o = NextSibling();
617 if (!o) {
618 o = Parent();
619 while (o && !o->NextSibling())
620 o = o->Parent();
621 if (o)
622 o = o->NextSibling();
623 }
624
625 return o;
626 }
627
NextInPreOrder(const LayoutObject * stay_within) const628 LayoutObject* LayoutObject::NextInPreOrder(
629 const LayoutObject* stay_within) const {
630 NOT_DESTROYED();
631 if (LayoutObject* o = SlowFirstChild())
632 return o;
633
634 return NextInPreOrderAfterChildren(stay_within);
635 }
636
PreviousInPostOrder(const LayoutObject * stay_within) const637 LayoutObject* LayoutObject::PreviousInPostOrder(
638 const LayoutObject* stay_within) const {
639 NOT_DESTROYED();
640 if (LayoutObject* o = SlowLastChild())
641 return o;
642
643 return PreviousInPostOrderBeforeChildren(stay_within);
644 }
645
NextInPreOrderAfterChildren(const LayoutObject * stay_within) const646 LayoutObject* LayoutObject::NextInPreOrderAfterChildren(
647 const LayoutObject* stay_within) const {
648 NOT_DESTROYED();
649 if (this == stay_within)
650 return nullptr;
651
652 const LayoutObject* current = this;
653 LayoutObject* next = current->NextSibling();
654 for (; !next; next = current->NextSibling()) {
655 current = current->Parent();
656 if (!current || current == stay_within)
657 return nullptr;
658 }
659 return next;
660 }
661
PreviousInPostOrderBeforeChildren(const LayoutObject * stay_within) const662 LayoutObject* LayoutObject::PreviousInPostOrderBeforeChildren(
663 const LayoutObject* stay_within) const {
664 NOT_DESTROYED();
665 if (this == stay_within)
666 return nullptr;
667
668 const LayoutObject* current = this;
669 LayoutObject* previous = current->PreviousSibling();
670 for (; !previous; previous = current->PreviousSibling()) {
671 current = current->Parent();
672 if (!current || current == stay_within)
673 return nullptr;
674 }
675 return previous;
676 }
677
PreviousInPreOrder() const678 LayoutObject* LayoutObject::PreviousInPreOrder() const {
679 NOT_DESTROYED();
680 if (LayoutObject* o = PreviousSibling()) {
681 while (LayoutObject* last_child = o->SlowLastChild())
682 o = last_child;
683 return o;
684 }
685
686 return Parent();
687 }
688
PreviousInPreOrder(const LayoutObject * stay_within) const689 LayoutObject* LayoutObject::PreviousInPreOrder(
690 const LayoutObject* stay_within) const {
691 NOT_DESTROYED();
692 if (this == stay_within)
693 return nullptr;
694
695 return PreviousInPreOrder();
696 }
697
LastLeafChild() const698 LayoutObject* LayoutObject::LastLeafChild() const {
699 NOT_DESTROYED();
700 LayoutObject* r = SlowLastChild();
701 while (r) {
702 LayoutObject* n = nullptr;
703 n = r->SlowLastChild();
704 if (!n)
705 break;
706 r = n;
707 }
708 return r;
709 }
710
AddLayers(LayoutObject * obj,PaintLayer * parent_layer,LayoutObject * & new_object,PaintLayer * & before_child)711 static void AddLayers(LayoutObject* obj,
712 PaintLayer* parent_layer,
713 LayoutObject*& new_object,
714 PaintLayer*& before_child) {
715 if (obj->HasLayer()) {
716 if (!before_child && new_object) {
717 // We need to figure out the layer that follows newObject. We only do
718 // this the first time we find a child layer, and then we update the
719 // pointer values for newObject and beforeChild used by everyone else.
720 before_child =
721 new_object->Parent()->FindNextLayer(parent_layer, new_object);
722 new_object = nullptr;
723 }
724 parent_layer->AddChild(To<LayoutBoxModelObject>(obj)->Layer(),
725 before_child);
726 return;
727 }
728
729 for (LayoutObject* curr = obj->SlowFirstChild(); curr;
730 curr = curr->NextSibling())
731 AddLayers(curr, parent_layer, new_object, before_child);
732 }
733
AddLayers(PaintLayer * parent_layer)734 void LayoutObject::AddLayers(PaintLayer* parent_layer) {
735 NOT_DESTROYED();
736 if (!parent_layer)
737 return;
738
739 LayoutObject* object = this;
740 PaintLayer* before_child = nullptr;
741 blink::AddLayers(this, parent_layer, object, before_child);
742 }
743
RemoveLayers(PaintLayer * parent_layer)744 void LayoutObject::RemoveLayers(PaintLayer* parent_layer) {
745 NOT_DESTROYED();
746 if (!parent_layer)
747 return;
748
749 if (HasLayer()) {
750 parent_layer->RemoveChild(To<LayoutBoxModelObject>(this)->Layer());
751 return;
752 }
753
754 for (LayoutObject* curr = SlowFirstChild(); curr; curr = curr->NextSibling())
755 curr->RemoveLayers(parent_layer);
756 }
757
MoveLayers(PaintLayer * old_parent,PaintLayer * new_parent)758 void LayoutObject::MoveLayers(PaintLayer* old_parent, PaintLayer* new_parent) {
759 NOT_DESTROYED();
760 if (!new_parent)
761 return;
762
763 if (HasLayer()) {
764 PaintLayer* layer = To<LayoutBoxModelObject>(this)->Layer();
765 DCHECK_EQ(old_parent, layer->Parent());
766 if (old_parent)
767 old_parent->RemoveChild(layer);
768 new_parent->AddChild(layer);
769 return;
770 }
771
772 for (LayoutObject* curr = SlowFirstChild(); curr; curr = curr->NextSibling())
773 curr->MoveLayers(old_parent, new_parent);
774 }
775
FindNextLayer(PaintLayer * parent_layer,LayoutObject * start_point,bool check_parent)776 PaintLayer* LayoutObject::FindNextLayer(PaintLayer* parent_layer,
777 LayoutObject* start_point,
778 bool check_parent) {
779 NOT_DESTROYED();
780 // Error check the parent layer passed in. If it's null, we can't find
781 // anything.
782 if (!parent_layer)
783 return nullptr;
784
785 // Step 1: If our layer is a child of the desired parent, then return our
786 // layer.
787 PaintLayer* our_layer =
788 HasLayer() ? To<LayoutBoxModelObject>(this)->Layer() : nullptr;
789 if (our_layer && our_layer->Parent() == parent_layer)
790 return our_layer;
791
792 // Step 2: If we don't have a layer, or our layer is the desired parent, then
793 // descend into our siblings trying to find the next layer whose parent is the
794 // desired parent.
795 if (!our_layer || our_layer == parent_layer) {
796 for (LayoutObject* curr = start_point ? start_point->NextSibling()
797 : SlowFirstChild();
798 curr; curr = curr->NextSibling()) {
799 PaintLayer* next_layer =
800 curr->FindNextLayer(parent_layer, nullptr, false);
801 if (next_layer)
802 return next_layer;
803 }
804 }
805
806 // Step 3: If our layer is the desired parent layer, then we're finished. We
807 // didn't find anything.
808 if (parent_layer == our_layer)
809 return nullptr;
810
811 // Step 4: If |checkParent| is set, climb up to our parent and check its
812 // siblings that follow us to see if we can locate a layer.
813 if (check_parent && Parent())
814 return Parent()->FindNextLayer(parent_layer, this, true);
815
816 return nullptr;
817 }
818
EnclosingLayer() const819 PaintLayer* LayoutObject::EnclosingLayer() const {
820 NOT_DESTROYED();
821 for (const LayoutObject* current = this; current;
822 current = current->Parent()) {
823 if (current->HasLayer())
824 return To<LayoutBoxModelObject>(current)->Layer();
825 }
826 // TODO(crbug.com/365897): we should get rid of detached layout subtrees, at
827 // which point this code should not be reached.
828 return nullptr;
829 }
830
PaintingLayer() const831 PaintLayer* LayoutObject::PaintingLayer() const {
832 NOT_DESTROYED();
833 auto FindContainer = [](const LayoutObject& object) -> const LayoutObject* {
834 if (object.IsRenderedLegend())
835 return LayoutFieldset::FindLegendContainingBlock(To<LayoutBox>(object));
836 // Use ContainingBlock() instead of ParentCrossingFrames() for floating
837 // objects to omit any self-painting layers of inline objects that don't
838 // paint the floating object. This is only needed for inline-level floats
839 // not managed by LayoutNG. LayoutNG floats are painted by the correct
840 // painting layer.
841 if (object.IsFloating() && !object.IsInLayoutNGInlineFormattingContext())
842 return object.ContainingBlock();
843 return object.ParentCrossingFrames();
844 };
845
846 for (const LayoutObject* current = this; current;
847 current = FindContainer(*current)) {
848 if (current->HasLayer() &&
849 To<LayoutBoxModelObject>(current)->Layer()->IsSelfPaintingLayer()) {
850 return To<LayoutBoxModelObject>(current)->Layer();
851 } else if (current->IsColumnSpanAll()) {
852 // Column spanners paint through their multicolumn containers which can
853 // be accessed through the associated out-of-flow placeholder's parent.
854 current = current->SpannerPlaceholder();
855 }
856 }
857 // TODO(crbug.com/365897): we should get rid of detached layout subtrees, at
858 // which point this code should not be reached.
859 return nullptr;
860 }
861
IsFixedPositionObjectInPagedMedia() const862 bool LayoutObject::IsFixedPositionObjectInPagedMedia() const {
863 NOT_DESTROYED();
864 if (StyleRef().GetPosition() != EPosition::kFixed)
865 return false;
866 LayoutView* view = View();
867 return Container() == view && view->PageLogicalHeight() &&
868 // TODO(crbug.com/619094): Figure out the correct behaviour for fixed
869 // position objects in paged media with vertical writing modes.
870 view->IsHorizontalWritingMode();
871 }
872
ScrollRectToVisible(const PhysicalRect & rect,mojom::blink::ScrollIntoViewParamsPtr params)873 PhysicalRect LayoutObject::ScrollRectToVisible(
874 const PhysicalRect& rect,
875 mojom::blink::ScrollIntoViewParamsPtr params) {
876 NOT_DESTROYED();
877 LayoutBox* enclosing_box = EnclosingBox();
878 if (!enclosing_box)
879 return rect;
880
881 GetDocument().GetFrame()->GetSmoothScrollSequencer().AbortAnimations();
882 GetDocument().GetFrame()->GetSmoothScrollSequencer().SetScrollType(
883 params->type);
884 params->is_for_scroll_sequence |=
885 params->type == mojom::blink::ScrollType::kProgrammatic;
886 PhysicalRect new_location =
887 enclosing_box->ScrollRectToVisibleRecursive(rect, std::move(params));
888 GetDocument().GetFrame()->GetSmoothScrollSequencer().RunQueuedAnimations();
889
890 return new_location;
891 }
892
EnclosingBox() const893 LayoutBox* LayoutObject::EnclosingBox() const {
894 NOT_DESTROYED();
895 LayoutObject* curr = const_cast<LayoutObject*>(this);
896 while (curr) {
897 if (curr->IsBox())
898 return To<LayoutBox>(curr);
899 curr = curr->Parent();
900 }
901
902 NOTREACHED();
903 return nullptr;
904 }
905
FragmentItemsContainer() const906 LayoutBlockFlow* LayoutObject::FragmentItemsContainer() const {
907 NOT_DESTROYED();
908 for (LayoutObject* parent = Parent(); parent; parent = parent->Parent()) {
909 if (auto* block_flow = DynamicTo<LayoutBlockFlow>(parent))
910 return block_flow;
911 }
912 return nullptr;
913 }
914
ContainingNGBlockFlow() const915 LayoutBlockFlow* LayoutObject::ContainingNGBlockFlow() const {
916 NOT_DESTROYED();
917 DCHECK(IsInline());
918 if (!RuntimeEnabledFeatures::LayoutNGEnabled())
919 return nullptr;
920 for (LayoutObject* parent = Parent(); parent; parent = parent->Parent()) {
921 if (auto* block_flow = DynamicTo<LayoutBlockFlow>(parent)) {
922 // Skip |LayoutFlowThread| because it is skipped when finding the first
923 // child in |GetLayoutObjectForFirstChildNode|.
924 if (UNLIKELY(block_flow->IsLayoutFlowThread()))
925 block_flow = DynamicTo<LayoutBlockFlow>(block_flow->Parent());
926 if (!NGBlockNode::CanUseNewLayout(*block_flow))
927 return nullptr;
928 return block_flow;
929 }
930 }
931 return nullptr;
932 }
933
ContainingBlockFlowFragment() const934 const NGPhysicalBoxFragment* LayoutObject::ContainingBlockFlowFragment() const {
935 NOT_DESTROYED();
936 DCHECK(IsInline() || IsText());
937 LayoutBlockFlow* const block_flow = ContainingNGBlockFlow();
938 if (!block_flow || !block_flow->ChildrenInline())
939 return nullptr;
940 // TODO(kojii): CurrentFragment isn't always available after layout clean.
941 // Investigate why.
942 return block_flow->CurrentFragment();
943 }
944
IsFirstInlineFragmentSafe() const945 bool LayoutObject::IsFirstInlineFragmentSafe() const {
946 NOT_DESTROYED();
947 DCHECK(IsInline());
948 LayoutBlockFlow* block_flow = ContainingNGBlockFlow();
949 return block_flow && !block_flow->NeedsLayout();
950 }
951
EnclosingScrollableBox() const952 LayoutBox* LayoutObject::EnclosingScrollableBox() const {
953 NOT_DESTROYED();
954 for (LayoutObject* ancestor = Parent(); ancestor;
955 ancestor = ancestor->Parent()) {
956 if (!ancestor->IsBox())
957 continue;
958
959 auto* ancestor_box = To<LayoutBox>(ancestor);
960 if (ancestor_box->CanBeScrolledAndHasScrollableArea())
961 return ancestor_box;
962 }
963
964 return nullptr;
965 }
966
LocateFlowThreadContainingBlock() const967 LayoutFlowThread* LayoutObject::LocateFlowThreadContainingBlock() const {
968 NOT_DESTROYED();
969 DCHECK(IsInsideFlowThread());
970
971 // See if we have the thread cached because we're in the middle of layout.
972 if (LayoutView* view = View()) {
973 if (LayoutState* layout_state = view->GetLayoutState()) {
974 // TODO(mstensho): We should really just return whatever
975 // layoutState->flowThread() returns here, also if the value is nullptr.
976 if (LayoutFlowThread* flow_thread = layout_state->FlowThread())
977 return flow_thread;
978 }
979 }
980
981 // Not in the middle of layout so have to find the thread the slow way.
982 return LayoutFlowThread::LocateFlowThreadContainingBlockOf(
983 *this, LayoutFlowThread::kAnyAncestor);
984 }
985
ObjectIsRelayoutBoundary(const LayoutObject * object)986 static inline bool ObjectIsRelayoutBoundary(const LayoutObject* object) {
987 // FIXME: In future it may be possible to broaden these conditions in order to
988 // improve performance.
989
990 // Positioned objects always have self-painting layers and are safe to use as
991 // relayout boundaries.
992 bool is_svg_root = object->IsSVGRoot();
993 bool has_self_painting_layer =
994 object->HasLayer() &&
995 To<LayoutBoxModelObject>(object)->HasSelfPaintingLayer();
996 if (!has_self_painting_layer && !is_svg_root)
997 return false;
998
999 // LayoutInline can't be relayout roots since LayoutBlockFlow is responsible
1000 // for layouting them.
1001 if (object->IsLayoutInline())
1002 return false;
1003
1004 // Table parts can't be relayout roots since the table is responsible for
1005 // layouting all the parts.
1006 if (object->IsTablePart())
1007 return false;
1008
1009 // OOF-positioned objects which rely on their static-position for placement
1010 // cannot be relayout boundaries (their final position would be incorrect).
1011 const ComputedStyle* style = object->Style();
1012 if (object->IsOutOfFlowPositioned() &&
1013 (style->HasAutoLeftAndRight() || style->HasAutoTopAndBottom()))
1014 return false;
1015
1016 if (UNLIKELY(RuntimeEnabledFeatures::LayoutNGFragmentTraversalEnabled() &&
1017 object->IsLayoutNGObject())) {
1018 // We need to rebuild the entire NG fragment spine all the way from the root
1019 // (or at least the nearest self-painting paint layer), since we traverse
1020 // the fragments, and not objects. Fragment painting is initiated at
1021 // self-painting layers, but we cannot check if it's a self-painting layer
1022 // now, because it may cease to be one during layout (an object with clipped
1023 // overflow that no longer has content that requires it to clip).
1024 return false;
1025 }
1026
1027 if (const auto* layout_box = DynamicTo<LayoutBox>(object)) {
1028 // In general we can't relayout a flex item independently of its container;
1029 // not only is the result incorrect due to the override size that's set, it
1030 // also messes with the cached main size on the flexbox.
1031 if (layout_box->IsFlexItemIncludingNG())
1032 return false;
1033
1034 // In LayoutNG, if box has any OOF descendants, they are propagated to
1035 // parent. Therefore, we must mark parent chain for layout.
1036 if (const NGLayoutResult* layouot_result =
1037 layout_box->GetCachedLayoutResult()) {
1038 if (layouot_result->PhysicalFragment()
1039 .HasOutOfFlowPositionedDescendants())
1040 return false;
1041 }
1042 }
1043
1044 if (object->ShouldApplyLayoutContainment() &&
1045 object->ShouldApplySizeContainment()) {
1046 return true;
1047 }
1048
1049 // SVG roots are sufficiently self-contained to be a relayout boundary, even
1050 // if their size is non-fixed.
1051 if (is_svg_root)
1052 return true;
1053
1054 // If either dimension is percent-based, intrinsic, or anything but fixed,
1055 // this object cannot form a re-layout boundary. A non-fixed computed logical
1056 // height will allow the object to grow and shrink based on the content
1057 // inside. The same goes for for logical width, if this objects is inside a
1058 // shrink-to-fit container, for instance.
1059 if (!style->Width().IsFixed() || !style->Height().IsFixed())
1060 return false;
1061
1062 if (object->IsTextControlIncludingNG())
1063 return true;
1064
1065 if (!object->HasNonVisibleOverflow())
1066 return false;
1067
1068 // Scrollbar parts can be removed during layout. Avoid the complexity of
1069 // having to deal with that.
1070 if (object->IsLayoutCustomScrollbarPart())
1071 return false;
1072
1073 // Inside multicol it's generally problematic to allow relayout roots. The
1074 // multicol container itself may be scheduled for relayout as well (due to
1075 // other changes that may have happened since the previous layout pass),
1076 // which might affect the column heights, which may affect how this object
1077 // breaks across columns). Spanners may also have been added or removed since
1078 // the previous layout pass, which is just another way of affecting the column
1079 // heights (and the number of rows). Instead of identifying cases where it's
1080 // safe to allow relayout roots, just disallow them inside multicol.
1081 if (object->IsInsideFlowThread())
1082 return false;
1083
1084 return true;
1085 }
1086
1087 // Mark this object needing to re-run |CollectInlines()|.
1088 //
1089 // The flag is propagated to its container so that NGInlineNode that contains
1090 // |this| is marked too. When |this| is a container, the propagation stops at
1091 // |this|. When invalidating on inline blocks, floats, or OOF, caller need to
1092 // pay attention whether it should mark its inner context or outer.
SetNeedsCollectInlines()1093 void LayoutObject::SetNeedsCollectInlines() {
1094 NOT_DESTROYED();
1095 if (!RuntimeEnabledFeatures::LayoutNGEnabled())
1096 return;
1097
1098 if (NeedsCollectInlines())
1099 return;
1100
1101 if (UNLIKELY(IsSVGChild()))
1102 return;
1103
1104 // Don't mark |LayoutFlowThread| because |CollectInlines()| skips them.
1105 if (!IsLayoutFlowThread())
1106 SetNeedsCollectInlines(true);
1107
1108 if (LayoutObject* parent = Parent())
1109 parent->SetChildNeedsCollectInlines();
1110 }
1111
SetChildNeedsCollectInlines()1112 void LayoutObject::SetChildNeedsCollectInlines() {
1113 NOT_DESTROYED();
1114 if (!RuntimeEnabledFeatures::LayoutNGEnabled())
1115 return;
1116
1117 LayoutObject* object = this;
1118 do {
1119 // Should not stop at |LayoutFlowThread| as |CollectInlines()| skips them.
1120 if (UNLIKELY(object->IsLayoutFlowThread())) {
1121 object = object->Parent();
1122 continue;
1123 }
1124 if (object->NeedsCollectInlines())
1125 break;
1126 object->SetNeedsCollectInlines(true);
1127
1128 // Stop marking at the inline formatting context root. This is usually a
1129 // |LayoutBlockFlow|, but some other classes can have children; e.g.,
1130 // |LayoutButton| or |LayoutSVGRoot|. |LayoutInline| is the only class we
1131 // collect recursively (see |CollectInlines|). Use the same condition here.
1132 if (!object->IsLayoutInline())
1133 break;
1134
1135 object = object->Parent();
1136 } while (object);
1137 }
1138
MarkContainerChainForLayout(bool schedule_relayout,SubtreeLayoutScope * layouter)1139 void LayoutObject::MarkContainerChainForLayout(bool schedule_relayout,
1140 SubtreeLayoutScope* layouter) {
1141 NOT_DESTROYED();
1142 #if DCHECK_IS_ON()
1143 DCHECK(!IsSetNeedsLayoutForbidden());
1144 #endif
1145 DCHECK(!layouter || this != layouter->Root());
1146 // When we're in layout, we're marking a descendant as needing layout with
1147 // the intention of visiting it during this layout. We shouldn't be
1148 // scheduling it to be laid out later. Also, scheduleRelayout() must not be
1149 // called while iterating LocalFrameView::layout_subtree_root_list_.
1150 schedule_relayout &= !GetFrameView()->IsInPerformLayout();
1151
1152 LayoutObject* object = Container();
1153 LayoutObject* last = this;
1154
1155 bool simplified_normal_flow_layout = NeedsSimplifiedNormalFlowLayout() &&
1156 !SelfNeedsLayout() &&
1157 !NormalChildNeedsLayout();
1158
1159 while (object) {
1160 if (object->SelfNeedsLayout())
1161 return;
1162
1163 // Note that if the last element we processed was blocked by a display lock,
1164 // and the reason we're propagating a change is that a subtree needed layout
1165 // (ie self doesn't need layout), then we can return and stop the dirty bit
1166 // propagation. Note that it's not enough to check |object|, since the
1167 // element that is actually locked needs its child bits set properly, we
1168 // need to go one more iteration after that.
1169 if (!last->SelfNeedsLayout() && last->ChildLayoutBlockedByDisplayLock()) {
1170 return;
1171 }
1172
1173 // Don't mark the outermost object of an unrooted subtree. That object will
1174 // be marked when the subtree is added to the document.
1175 LayoutObject* container = object->Container();
1176 if (!container && !IsA<LayoutView>(object))
1177 return;
1178 if (!last->IsTextOrSVGChild() && last->StyleRef().HasOutOfFlowPosition()) {
1179 object = last->ContainingBlock();
1180 if (object->PosChildNeedsLayout())
1181 return;
1182 container = object->Container();
1183 object->SetPosChildNeedsLayout(true);
1184 simplified_normal_flow_layout = true;
1185 } else if (simplified_normal_flow_layout) {
1186 if (object->NeedsSimplifiedNormalFlowLayout())
1187 return;
1188 object->SetNeedsSimplifiedNormalFlowLayout(true);
1189 } else {
1190 if (object->NormalChildNeedsLayout())
1191 return;
1192 object->SetNormalChildNeedsLayout(true);
1193 }
1194 #if DCHECK_IS_ON()
1195 DCHECK(!object->IsSetNeedsLayoutForbidden());
1196 #endif
1197
1198 object->MarkSelfPaintingLayerForVisualOverflowRecalc();
1199
1200 if (layouter) {
1201 layouter->RecordObjectMarkedForLayout(object);
1202
1203 if (object == layouter->Root()) {
1204 if (auto* painting_layer = PaintingLayer())
1205 painting_layer->SetNeedsVisualOverflowRecalc();
1206 return;
1207 }
1208 }
1209
1210 last = object;
1211 if (schedule_relayout && ObjectIsRelayoutBoundary(last))
1212 break;
1213 object = container;
1214 }
1215
1216 if (schedule_relayout)
1217 last->ScheduleRelayout();
1218 }
1219
1220 // LayoutNG has different OOF-positioned handling compared to the existing
1221 // layout system. To correctly determine the static-position of the object,
1222 // LayoutNG "bubbles" up the static-position inside the NGLayoutResult.
1223 // See: |NGLayoutResult::OutOfFlowPositionedDescendants()|.
1224 //
1225 // Whenever an OOF-positioned object is added/removed we need to invalidate
1226 // layout for all the layout objects which may have stored a NGLayoutResult
1227 // with this object contained in that list.
1228 //
1229 // In the future it may be possible to optimize this, e.g.
1230 // - For the removal case, add a pass which modifies the layout result to
1231 // remove the OOF-positioned descendant.
1232 // - For the adding case, if the OOF-positioned doesn't require a
1233 // static-position, simply insert the object up the NGLayoutResult chain with
1234 // an invalid static-position.
MarkParentForOutOfFlowPositionedChange()1235 void LayoutObject::MarkParentForOutOfFlowPositionedChange() {
1236 NOT_DESTROYED();
1237 #if DCHECK_IS_ON()
1238 DCHECK(!IsSetNeedsLayoutForbidden());
1239 #endif
1240
1241 LayoutObject* object = Parent();
1242 if (!object)
1243 return;
1244
1245 // As OOF-positioned objects are represented as an object replacement
1246 // character in the inline items list. We need to ensure we collect the
1247 // inline items again to either collect or drop the OOF-positioned object.
1248 object->SetNeedsCollectInlines();
1249
1250 const LayoutBlock* containing_block = ContainingBlock();
1251 while (object != containing_block) {
1252 object->SetChildNeedsLayout(kMarkOnlyThis);
1253 object = object->Parent();
1254 }
1255 // Finally mark the parent block for layout. This will mark everything which
1256 // has an OOF-positioned object in a NGLayoutResult as needing layout.
1257 if (object)
1258 object->SetChildNeedsLayout();
1259 }
1260
1261 #if DCHECK_IS_ON()
CheckBlockPositionedObjectsNeedLayout()1262 void LayoutObject::CheckBlockPositionedObjectsNeedLayout() {
1263 NOT_DESTROYED();
1264 if (ChildLayoutBlockedByDisplayLock())
1265 return;
1266 DCHECK(!NeedsLayout());
1267
1268 auto* layout_block = DynamicTo<LayoutBlock>(this);
1269 if (layout_block)
1270 layout_block->CheckPositionedObjectsNeedLayout();
1271 }
1272 #endif
1273
SetIntrinsicLogicalWidthsDirty(MarkingBehavior mark_parents)1274 void LayoutObject::SetIntrinsicLogicalWidthsDirty(
1275 MarkingBehavior mark_parents) {
1276 NOT_DESTROYED();
1277 bitfields_.SetIntrinsicLogicalWidthsDirty(true);
1278 bitfields_.SetIntrinsicLogicalWidthsDependsOnPercentageBlockSize(true);
1279 bitfields_.SetIntrinsicLogicalWidthsChildDependsOnPercentageBlockSize(true);
1280 if (mark_parents == kMarkContainerChain &&
1281 (IsText() || !StyleRef().HasOutOfFlowPosition()))
1282 InvalidateContainerIntrinsicLogicalWidths();
1283 }
1284
ClearIntrinsicLogicalWidthsDirty()1285 void LayoutObject::ClearIntrinsicLogicalWidthsDirty() {
1286 NOT_DESTROYED();
1287 bitfields_.SetIntrinsicLogicalWidthsDirty(false);
1288 }
1289
IsFontFallbackValid() const1290 bool LayoutObject::IsFontFallbackValid() const {
1291 NOT_DESTROYED();
1292 return StyleRef().GetFont().IsFallbackValid() &&
1293 FirstLineStyle()->GetFont().IsFallbackValid();
1294 }
1295
InvalidateSubtreeLayoutForFontUpdates()1296 void LayoutObject::InvalidateSubtreeLayoutForFontUpdates() {
1297 NOT_DESTROYED();
1298 if (!RuntimeEnabledFeatures::
1299 CSSReducedFontLoadingLayoutInvalidationsEnabled() ||
1300 !IsFontFallbackValid()) {
1301 SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
1302 layout_invalidation_reason::kFontsChanged);
1303 }
1304 for (LayoutObject* child = SlowFirstChild(); child;
1305 child = child->NextSibling()) {
1306 child->InvalidateSubtreeLayoutForFontUpdates();
1307 }
1308 }
1309
InvalidateIntersectionObserverCachedRects()1310 void LayoutObject::InvalidateIntersectionObserverCachedRects() {
1311 NOT_DESTROYED();
1312 if (GetNode() && GetNode()->IsElementNode()) {
1313 if (auto* data = To<Element>(GetNode())->IntersectionObserverData()) {
1314 data->InvalidateCachedRects();
1315 }
1316 }
1317 }
1318
NGKeepInvalidatingBeyond(LayoutObject * o)1319 static inline bool NGKeepInvalidatingBeyond(LayoutObject* o) {
1320 // Because LayoutNG does not work on individual inline objects, we can't
1321 // use a dirty width on an inline as a signal that it is safe to stop --
1322 // inlines never get marked as clean. Instead, we need to keep going to the
1323 // next block container.
1324 // Atomic inlines do not have this problem as they are treated like blocks
1325 // in this context.
1326 // There's a similar issue for flow thread objects, as they are invisible to
1327 // LayoutNG.
1328 if (!RuntimeEnabledFeatures::LayoutNGEnabled())
1329 return false;
1330 if (o->IsLayoutInline() || o->IsText() || o->IsLayoutFlowThread())
1331 return true;
1332 return false;
1333 }
1334
InvalidateContainerIntrinsicLogicalWidths()1335 inline void LayoutObject::InvalidateContainerIntrinsicLogicalWidths() {
1336 NOT_DESTROYED();
1337 // In order to avoid pathological behavior when inlines are deeply nested, we
1338 // do include them in the chain that we mark dirty (even though they're kind
1339 // of irrelevant).
1340 LayoutObject* o = IsTableCell() ? ContainingBlock() : Container();
1341 while (o &&
1342 (!o->IntrinsicLogicalWidthsDirty() || NGKeepInvalidatingBeyond(o))) {
1343 // Don't invalidate the outermost object of an unrooted subtree. That object
1344 // will be invalidated when the subtree is added to the document.
1345 LayoutObject* container =
1346 o->IsTableCell() ? o->ContainingBlock() : o->Container();
1347 if (!container && !IsA<LayoutView>(o))
1348 break;
1349
1350 o->bitfields_.SetIntrinsicLogicalWidthsDirty(true);
1351 // A positioned object has no effect on the min/max width of its containing
1352 // block ever. We can optimize this case and not go up any further.
1353 if (o->StyleRef().HasOutOfFlowPosition())
1354 break;
1355 o = container;
1356 }
1357 }
1358
ContainerForAbsolutePosition(AncestorSkipInfo * skip_info) const1359 LayoutObject* LayoutObject::ContainerForAbsolutePosition(
1360 AncestorSkipInfo* skip_info) const {
1361 NOT_DESTROYED();
1362 return FindAncestorByPredicate(this, skip_info, [](LayoutObject* candidate) {
1363 return candidate->CanContainAbsolutePositionObjects();
1364 });
1365 }
1366
ContainerForFixedPosition(AncestorSkipInfo * skip_info) const1367 LayoutObject* LayoutObject::ContainerForFixedPosition(
1368 AncestorSkipInfo* skip_info) const {
1369 NOT_DESTROYED();
1370 DCHECK(!IsText());
1371 return FindAncestorByPredicate(this, skip_info, [](LayoutObject* candidate) {
1372 return candidate->CanContainFixedPositionObjects();
1373 });
1374 }
1375
ContainingBlockForAbsolutePosition(AncestorSkipInfo * skip_info) const1376 LayoutBlock* LayoutObject::ContainingBlockForAbsolutePosition(
1377 AncestorSkipInfo* skip_info) const {
1378 NOT_DESTROYED();
1379 auto* container = ContainerForAbsolutePosition(skip_info);
1380 return FindNonAnonymousContainingBlock(container, skip_info);
1381 }
1382
ContainingBlockForFixedPosition(AncestorSkipInfo * skip_info) const1383 LayoutBlock* LayoutObject::ContainingBlockForFixedPosition(
1384 AncestorSkipInfo* skip_info) const {
1385 NOT_DESTROYED();
1386 auto* container = ContainerForFixedPosition(skip_info);
1387 return FindNonAnonymousContainingBlock(container, skip_info);
1388 }
1389
InclusiveContainingBlock() const1390 const LayoutBlock* LayoutObject::InclusiveContainingBlock() const {
1391 NOT_DESTROYED();
1392 auto* layout_block = DynamicTo<LayoutBlock>(this);
1393 return layout_block ? layout_block : ContainingBlock();
1394 }
1395
ContainingBlock(AncestorSkipInfo * skip_info) const1396 LayoutBlock* LayoutObject::ContainingBlock(AncestorSkipInfo* skip_info) const {
1397 NOT_DESTROYED();
1398 if (!IsTextOrSVGChild()) {
1399 if (style_->GetPosition() == EPosition::kFixed)
1400 return ContainingBlockForFixedPosition(skip_info);
1401 if (style_->GetPosition() == EPosition::kAbsolute)
1402 return ContainingBlockForAbsolutePosition(skip_info);
1403 }
1404 LayoutObject* object;
1405 if (IsColumnSpanAll()) {
1406 object = SpannerPlaceholder()->ContainingBlock();
1407 } else if (IsRenderedLegend()) {
1408 return LayoutFieldset::FindLegendContainingBlock(To<LayoutBox>(*this),
1409 skip_info);
1410 } else {
1411 object = Parent();
1412 if (!object && IsLayoutCustomScrollbarPart()) {
1413 object = To<LayoutCustomScrollbarPart>(this)
1414 ->GetScrollableArea()
1415 ->GetLayoutBox();
1416 }
1417 while (object && ((object->IsInline() && !object->IsAtomicInlineLevel()) ||
1418 !object->IsLayoutBlock())) {
1419 if (skip_info)
1420 skip_info->Update(*object);
1421 object = object->Parent();
1422 }
1423 }
1424
1425 return DynamicTo<LayoutBlock>(object);
1426 }
1427
NonAnonymousAncestor() const1428 LayoutObject* LayoutObject::NonAnonymousAncestor() const {
1429 NOT_DESTROYED();
1430 LayoutObject* ancestor = Parent();
1431 while (ancestor && ancestor->IsAnonymous())
1432 ancestor = ancestor->Parent();
1433 return ancestor;
1434 }
1435
FindNonAnonymousContainingBlock(LayoutObject * container,AncestorSkipInfo * skip_info)1436 LayoutBlock* LayoutObject::FindNonAnonymousContainingBlock(
1437 LayoutObject* container,
1438 AncestorSkipInfo* skip_info) {
1439 // For inlines, we return the nearest non-anonymous enclosing
1440 // block. We don't try to return the inline itself. This allows us to avoid
1441 // having a positioned objects list in all LayoutInlines and lets us return a
1442 // strongly-typed LayoutBlock* result from this method. The
1443 // LayoutObject::Container() method can actually be used to obtain the inline
1444 // directly.
1445 if (container && !container->IsLayoutBlock())
1446 container = container->ContainingBlock(skip_info);
1447
1448 while (container && container->IsAnonymousBlock())
1449 container = container->ContainingBlock(skip_info);
1450
1451 return DynamicTo<LayoutBlock>(container);
1452 }
1453
ComputeIsFixedContainer(const ComputedStyle * style) const1454 bool LayoutObject::ComputeIsFixedContainer(const ComputedStyle* style) const {
1455 NOT_DESTROYED();
1456 if (!style)
1457 return false;
1458 bool is_document_element = IsDocumentElement();
1459 // https://www.w3.org/TR/filter-effects-1/#FilterProperty
1460 if (!is_document_element && style->HasNonInitialFilter())
1461 return true;
1462 // Backdrop-filter creates a containing block for fixed and absolute
1463 // positioned elements:
1464 // https://drafts.fxtf.org/filter-effects-2/#backdrop-filter-operation
1465 if (!is_document_element && style->HasNonInitialBackdropFilter())
1466 return true;
1467 // The LayoutView is always a container of fixed positioned descendants. In
1468 // addition, SVG foreignObjects become such containers, so that descendants
1469 // of a foreignObject cannot escape it. Similarly, text controls let authors
1470 // select elements inside that are created by user agent shadow DOM, and we
1471 // have (C++) code that assumes that the elements are indeed contained by the
1472 // text control. So just make sure this is the case.
1473 if (IsA<LayoutView>(this) || IsSVGForeignObject() ||
1474 IsTextControlIncludingNG())
1475 return true;
1476 // https://www.w3.org/TR/css-transforms-1/#containing-block-for-all-descendants
1477
1478 if (RuntimeEnabledFeatures::TransformInteropEnabled() &&
1479 style->TransformStyle3D() == ETransformStyle3D::kPreserve3d)
1480 return true;
1481
1482 if (style->HasTransformRelatedProperty()) {
1483 if (!IsInline() || IsAtomicInlineLevel())
1484 return true;
1485 }
1486 // https://www.w3.org/TR/css-contain-1/#containment-layout
1487 if (ShouldApplyPaintContainment(*style) ||
1488 ShouldApplyLayoutContainment(*style))
1489 return true;
1490
1491 // We intend to change behavior to set containing block based on computed
1492 // rather than used style of transform-style. HasTransformRelatedProperty
1493 // above will return true if the *used* value of transform-style is
1494 // preserve-3d, so to estimate compat we need to count if the line below is
1495 // reached.
1496 if (style->TransformStyle3D() == ETransformStyle3D::kPreserve3d) {
1497 UseCounter::Count(
1498 GetDocument(),
1499 WebFeature::kTransformStyleContainingBlockComputedUsedMismatch);
1500 }
1501
1502 return false;
1503 }
1504
ComputeIsAbsoluteContainer(const ComputedStyle * style) const1505 bool LayoutObject::ComputeIsAbsoluteContainer(
1506 const ComputedStyle* style) const {
1507 NOT_DESTROYED();
1508 if (!style)
1509 return false;
1510 return style->CanContainAbsolutePositionObjects() ||
1511 ComputeIsFixedContainer(style);
1512 }
1513
AbsoluteBoundingBoxFloatRect(MapCoordinatesFlags flags) const1514 FloatRect LayoutObject::AbsoluteBoundingBoxFloatRect(
1515 MapCoordinatesFlags flags) const {
1516 NOT_DESTROYED();
1517 DCHECK(!(flags & kIgnoreTransforms));
1518 Vector<FloatQuad> quads;
1519 AbsoluteQuads(quads, flags);
1520
1521 wtf_size_t n = quads.size();
1522 if (n == 0)
1523 return FloatRect();
1524
1525 FloatRect result = quads[0].BoundingBox();
1526 for (wtf_size_t i = 1; i < n; ++i)
1527 result.Unite(quads[i].BoundingBox());
1528 return result;
1529 }
1530
AbsoluteBoundingBoxRect(MapCoordinatesFlags flags) const1531 IntRect LayoutObject::AbsoluteBoundingBoxRect(MapCoordinatesFlags flags) const {
1532 NOT_DESTROYED();
1533 DCHECK(!(flags & kIgnoreTransforms));
1534 Vector<FloatQuad> quads;
1535 AbsoluteQuads(quads, flags);
1536
1537 wtf_size_t n = quads.size();
1538 if (!n)
1539 return IntRect();
1540
1541 IntRect result = quads[0].EnclosingBoundingBox();
1542 for (wtf_size_t i = 1; i < n; ++i)
1543 result.Unite(quads[i].EnclosingBoundingBox());
1544 return result;
1545 }
1546
AbsoluteBoundingBoxRectHandlingEmptyInline() const1547 PhysicalRect LayoutObject::AbsoluteBoundingBoxRectHandlingEmptyInline() const {
1548 NOT_DESTROYED();
1549 return PhysicalRect::EnclosingRect(AbsoluteBoundingBoxFloatRect());
1550 }
1551
AbsoluteBoundingBoxRectForScrollIntoView() const1552 PhysicalRect LayoutObject::AbsoluteBoundingBoxRectForScrollIntoView() const {
1553 NOT_DESTROYED();
1554 PhysicalRect rect = AbsoluteBoundingBoxRectHandlingEmptyInline();
1555 const auto& style = StyleRef();
1556 rect.ExpandEdges(LayoutUnit(style.ScrollMarginTop()),
1557 LayoutUnit(style.ScrollMarginRight()),
1558 LayoutUnit(style.ScrollMarginBottom()),
1559 LayoutUnit(style.ScrollMarginLeft()));
1560 return rect;
1561 }
1562
AddAbsoluteRectForLayer(IntRect & result)1563 void LayoutObject::AddAbsoluteRectForLayer(IntRect& result) {
1564 NOT_DESTROYED();
1565 if (HasLayer())
1566 result.Unite(AbsoluteBoundingBoxRect());
1567 for (LayoutObject* current = SlowFirstChild(); current;
1568 current = current->NextSibling())
1569 current->AddAbsoluteRectForLayer(result);
1570 }
1571
AbsoluteBoundingBoxRectIncludingDescendants() const1572 IntRect LayoutObject::AbsoluteBoundingBoxRectIncludingDescendants() const {
1573 NOT_DESTROYED();
1574 IntRect result = AbsoluteBoundingBoxRect();
1575 for (LayoutObject* current = SlowFirstChild(); current;
1576 current = current->NextSibling())
1577 current->AddAbsoluteRectForLayer(result);
1578 return result;
1579 }
1580
Paint(const PaintInfo &) const1581 void LayoutObject::Paint(const PaintInfo&) const {
1582 NOT_DESTROYED();
1583 }
1584
DirectlyCompositableContainer() const1585 const LayoutBoxModelObject& LayoutObject::DirectlyCompositableContainer()
1586 const {
1587 NOT_DESTROYED();
1588 CHECK(IsRooted());
1589
1590 if (const LayoutBoxModelObject* container =
1591 EnclosingDirectlyCompositableContainer())
1592 return *container;
1593
1594 // If the current frame is not composited, we send just return the main
1595 // frame's LayoutView so that we generate invalidations on the window.
1596 const LayoutView* layout_view = View();
1597 while (const LayoutObject* owner_object =
1598 layout_view->GetFrame()->OwnerLayoutObject())
1599 layout_view = owner_object->View();
1600
1601 DCHECK(layout_view);
1602 return *layout_view;
1603 }
1604
1605 const LayoutBoxModelObject*
EnclosingDirectlyCompositableContainer() const1606 LayoutObject::EnclosingDirectlyCompositableContainer() const {
1607 NOT_DESTROYED();
1608 DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
1609 LayoutBoxModelObject* container = nullptr;
1610 // FIXME: CompositingState is not necessarily up to date for many callers of
1611 // this function.
1612 DisableCompositingQueryAsserts disabler;
1613
1614 if (PaintLayer* painting_layer = PaintingLayer()) {
1615 if (PaintLayer* compositing_layer =
1616 painting_layer
1617 ->EnclosingDirectlyCompositableLayerCrossingFrameBoundaries())
1618 container = &compositing_layer->GetLayoutObject();
1619 }
1620 return container;
1621 }
1622
RecalcLayoutOverflow()1623 RecalcLayoutOverflowResult LayoutObject::RecalcLayoutOverflow() {
1624 NOT_DESTROYED();
1625 if (!ChildNeedsLayoutOverflowRecalc())
1626 return RecalcLayoutOverflowResult();
1627
1628 ClearChildNeedsLayoutOverflowRecalc();
1629 bool children_layout_overflow_changed = false;
1630 for (LayoutObject* current = SlowFirstChild(); current;
1631 current = current->NextSibling()) {
1632 children_layout_overflow_changed |=
1633 current->RecalcLayoutOverflow().layout_overflow_changed;
1634 }
1635 return {children_layout_overflow_changed, /* rebuild_fragment_tree */ false};
1636 }
1637
RecalcVisualOverflow()1638 void LayoutObject::RecalcVisualOverflow() {
1639 NOT_DESTROYED();
1640 for (LayoutObject* current = SlowFirstChild(); current;
1641 current = current->NextSibling()) {
1642 if (current->HasLayer() &&
1643 To<LayoutBoxModelObject>(current)->HasSelfPaintingLayer())
1644 continue;
1645 current->RecalcVisualOverflow();
1646 }
1647 }
1648
RecalcNormalFlowChildVisualOverflowIfNeeded()1649 void LayoutObject::RecalcNormalFlowChildVisualOverflowIfNeeded() {
1650 NOT_DESTROYED();
1651 if (IsOutOfFlowPositioned() ||
1652 (HasLayer() && To<LayoutBoxModelObject>(this)->HasSelfPaintingLayer()))
1653 return;
1654 RecalcVisualOverflow();
1655 }
1656
HasDistortingVisualEffects() const1657 bool LayoutObject::HasDistortingVisualEffects() const {
1658 NOT_DESTROYED();
1659 // TODO(szager): Check occlusion information propagated from out-of-process
1660 // parent frame.
1661
1662 auto& first_fragment = EnclosingLayer()->GetLayoutObject().FirstFragment();
1663 // This can happen for an iframe element which is outside the viewport and has
1664 // therefore never been painted. In that case, we do the safe thing -- report
1665 // it as having distorting visual effects.
1666 if (!first_fragment.HasLocalBorderBoxProperties())
1667 return true;
1668 auto paint_properties = first_fragment.LocalBorderBoxProperties();
1669
1670 // No filters, no blends, no opacity < 100%.
1671 for (const auto* effect = &paint_properties.Effect().Unalias(); effect;
1672 effect = effect->UnaliasedParent()) {
1673 if (!effect->Filter().IsEmpty() || !effect->BackdropFilter().IsEmpty() ||
1674 effect->GetColorFilter() != kColorFilterNone ||
1675 effect->BlendMode() != SkBlendMode::kSrcOver ||
1676 effect->Opacity() != 1.0) {
1677 return true;
1678 }
1679 }
1680
1681 auto& local_frame_root = GetDocument().GetFrame()->LocalFrameRoot();
1682 auto& root_fragment = local_frame_root.ContentLayoutObject()->FirstFragment();
1683 CHECK(root_fragment.HasLocalBorderBoxProperties());
1684 const auto& root_properties = root_fragment.LocalBorderBoxProperties();
1685
1686 // The only allowed transforms are 2D translation and proportional up-scaling.
1687 const auto& translation_2d_or_matrix =
1688 GeometryMapper::SourceToDestinationProjection(
1689 paint_properties.Transform(), root_properties.Transform());
1690 if (!translation_2d_or_matrix.IsIdentityOr2DTranslation() &&
1691 !translation_2d_or_matrix.Matrix()
1692 .Is2DProportionalUpscaleAndOr2DTranslation())
1693 return true;
1694
1695 return false;
1696 }
1697
HasNonZeroEffectiveOpacity() const1698 bool LayoutObject::HasNonZeroEffectiveOpacity() const {
1699 NOT_DESTROYED();
1700 const FragmentData& fragment =
1701 EnclosingLayer()->GetLayoutObject().FirstFragment();
1702
1703 // This can happen for an iframe element which is outside the viewport and has
1704 // therefore never been painted. In that case, we do the safe thing -- report
1705 // it as having non-zero opacity -- since this method is used by
1706 // IntersectionObserver to detect occlusion.
1707 if (!fragment.HasLocalBorderBoxProperties())
1708 return true;
1709
1710 const auto& paint_properties = fragment.LocalBorderBoxProperties();
1711
1712 for (const auto* effect = &paint_properties.Effect().Unalias(); effect;
1713 effect = effect->UnaliasedParent()) {
1714 if (effect->Opacity() == 0.0)
1715 return false;
1716 }
1717 return true;
1718 }
1719
DecoratedName() const1720 String LayoutObject::DecoratedName() const {
1721 NOT_DESTROYED();
1722 StringBuilder name;
1723 name.Append(GetName());
1724
1725 if (IsAnonymous())
1726 name.Append(" (anonymous)");
1727 // FIXME: Remove the special case for LayoutView here (requires rebaseline of
1728 // all tests).
1729 if (IsOutOfFlowPositioned() && !IsA<LayoutView>(this))
1730 name.Append(" (positioned)");
1731 if (IsRelPositioned())
1732 name.Append(" (relative positioned)");
1733 if (IsStickyPositioned())
1734 name.Append(" (sticky positioned)");
1735 if (IsFloating())
1736 name.Append(" (floating)");
1737 if (SpannerPlaceholder())
1738 name.Append(" (column spanner)");
1739
1740 return name.ToString();
1741 }
1742
DebugName() const1743 String LayoutObject::DebugName() const {
1744 NOT_DESTROYED();
1745 StringBuilder name;
1746 name.Append(DecoratedName());
1747
1748 if (const Node* node = GetNode()) {
1749 name.Append(' ');
1750 name.Append(node->DebugName());
1751 }
1752 return name.ToString();
1753 }
1754
OwnerNodeId() const1755 DOMNodeId LayoutObject::OwnerNodeId() const {
1756 NOT_DESTROYED();
1757 return GetNode() ? DOMNodeIds::IdForNode(GetNode()) : kInvalidDOMNodeId;
1758 }
1759
IsPaintInvalidationContainer() const1760 bool LayoutObject::IsPaintInvalidationContainer() const {
1761 NOT_DESTROYED();
1762 return HasLayer() && To<LayoutBoxModelObject>(this)
1763 ->Layer()
1764 ->IsPaintInvalidationContainer();
1765 }
1766
CanBeCompositedForDirectReasons() const1767 bool LayoutObject::CanBeCompositedForDirectReasons() const {
1768 NOT_DESTROYED();
1769 return HasLayer() && To<LayoutBoxModelObject>(this)
1770 ->Layer()
1771 ->CanBeCompositedForDirectReasons();
1772 }
1773
InvalidateDisplayItemClients(PaintInvalidationReason reason) const1774 void LayoutObject::InvalidateDisplayItemClients(
1775 PaintInvalidationReason reason) const {
1776 NOT_DESTROYED();
1777 // This default implementation invalidates only the object itself as a
1778 // DisplayItemClient.
1779 DCHECK(!GetSelectionDisplayItemClient());
1780 ObjectPaintInvalidator(*this).InvalidateDisplayItemClient(*this, reason);
1781 }
1782
CompositedScrollsWithRespectTo(const LayoutBoxModelObject & paint_invalidation_container) const1783 bool LayoutObject::CompositedScrollsWithRespectTo(
1784 const LayoutBoxModelObject& paint_invalidation_container) const {
1785 NOT_DESTROYED();
1786 return paint_invalidation_container.UsesCompositedScrolling() &&
1787 this != &paint_invalidation_container;
1788 }
1789
AbsoluteSelectionRect() const1790 PhysicalRect LayoutObject::AbsoluteSelectionRect() const {
1791 NOT_DESTROYED();
1792 PhysicalRect selection_rect = LocalSelectionVisualRect();
1793 if (!selection_rect.IsEmpty())
1794 MapToVisualRectInAncestorSpace(View(), selection_rect);
1795
1796 if (LocalFrameView* frame_view = GetFrameView())
1797 return frame_view->DocumentToFrame(selection_rect);
1798
1799 return selection_rect;
1800 }
1801
1802 DISABLE_CFI_PERF
InvalidatePaint(const PaintInvalidatorContext & context) const1803 void LayoutObject::InvalidatePaint(
1804 const PaintInvalidatorContext& context) const {
1805 NOT_DESTROYED();
1806 ObjectPaintInvalidatorWithContext(*this, context).InvalidatePaint();
1807 }
1808
VisualRectInDocument(VisualRectFlags flags) const1809 PhysicalRect LayoutObject::VisualRectInDocument(VisualRectFlags flags) const {
1810 NOT_DESTROYED();
1811 PhysicalRect rect = LocalVisualRect();
1812 MapToVisualRectInAncestorSpace(View(), rect, flags);
1813 return rect;
1814 }
1815
LocalVisualRectIgnoringVisibility() const1816 PhysicalRect LayoutObject::LocalVisualRectIgnoringVisibility() const {
1817 NOT_DESTROYED();
1818 NOTREACHED();
1819 return PhysicalRect();
1820 }
1821
MapToVisualRectInAncestorSpaceInternalFastPath(const LayoutBoxModelObject * ancestor,PhysicalRect & rect,VisualRectFlags visual_rect_flags,bool & intersects) const1822 bool LayoutObject::MapToVisualRectInAncestorSpaceInternalFastPath(
1823 const LayoutBoxModelObject* ancestor,
1824 PhysicalRect& rect,
1825 VisualRectFlags visual_rect_flags,
1826 bool& intersects) const {
1827 NOT_DESTROYED();
1828 intersects = true;
1829 if (!(visual_rect_flags & kUseGeometryMapper) || !ancestor ||
1830 !ancestor->FirstFragment().HasLocalBorderBoxProperties())
1831 return false;
1832
1833 if (ancestor == this)
1834 return true;
1835
1836 AncestorSkipInfo skip_info(ancestor);
1837 PropertyTreeState container_properties = PropertyTreeState::Uninitialized();
1838 const LayoutObject* property_container =
1839 GetPropertyContainer(&skip_info, &container_properties);
1840 if (!property_container)
1841 return false;
1842
1843 // This works because it's not possible to have any intervening clips,
1844 // effects, transforms between |this| and |property_container|, and therefore
1845 // FirstFragment().PaintOffset() is relative to the transform space defined by
1846 // FirstFragment().LocalBorderBoxProperties() (if this == property_container)
1847 // or property_container->FirstFragment().ContentsProperties().
1848 rect.Move(FirstFragment().PaintOffset());
1849 if (property_container != ancestor) {
1850 FloatClipRect clip_rect((FloatRect(rect)));
1851 intersects = GeometryMapper::LocalToAncestorVisualRect(
1852 container_properties, ancestor->FirstFragment().ContentsProperties(),
1853 clip_rect, kIgnoreOverlayScrollbarSize,
1854 (visual_rect_flags & kEdgeInclusive) ? kInclusiveIntersect
1855 : kNonInclusiveIntersect);
1856 rect = PhysicalRect::EnclosingRect(clip_rect.Rect());
1857 }
1858 rect.offset -= ancestor->FirstFragment().PaintOffset();
1859
1860 return true;
1861 }
1862
MapToVisualRectInAncestorSpace(const LayoutBoxModelObject * ancestor,PhysicalRect & rect,VisualRectFlags visual_rect_flags) const1863 bool LayoutObject::MapToVisualRectInAncestorSpace(
1864 const LayoutBoxModelObject* ancestor,
1865 PhysicalRect& rect,
1866 VisualRectFlags visual_rect_flags) const {
1867 NOT_DESTROYED();
1868 bool intersects = true;
1869 if (MapToVisualRectInAncestorSpaceInternalFastPath(
1870 ancestor, rect, visual_rect_flags, intersects))
1871 return intersects;
1872
1873 TransformState transform_state(TransformState::kApplyTransformDirection,
1874 FloatQuad(FloatRect(rect)));
1875 intersects = MapToVisualRectInAncestorSpaceInternal(ancestor, transform_state,
1876 visual_rect_flags);
1877 transform_state.Flatten();
1878 rect = PhysicalRect::EnclosingRect(
1879 transform_state.LastPlanarQuad().BoundingBox());
1880 return intersects;
1881 }
1882
MapToVisualRectInAncestorSpaceInternal(const LayoutBoxModelObject * ancestor,TransformState & transform_state,VisualRectFlags visual_rect_flags) const1883 bool LayoutObject::MapToVisualRectInAncestorSpaceInternal(
1884 const LayoutBoxModelObject* ancestor,
1885 TransformState& transform_state,
1886 VisualRectFlags visual_rect_flags) const {
1887 NOT_DESTROYED();
1888 // For any layout object that doesn't override this method (the main example
1889 // is LayoutText), the rect is assumed to be in the parent's coordinate space,
1890 // except for container flip.
1891
1892 if (ancestor == this)
1893 return true;
1894
1895 if (LayoutObject* parent = Parent()) {
1896 if (parent->IsBox()) {
1897 bool preserve3d = parent->StyleRef().Preserves3D() && !parent->IsText();
1898 TransformState::TransformAccumulation accumulation =
1899 preserve3d ? TransformState::kAccumulateTransform
1900 : TransformState::kFlattenTransform;
1901
1902 if (parent != ancestor &&
1903 !To<LayoutBox>(parent)->MapContentsRectToBoxSpace(
1904 transform_state, accumulation, *this, visual_rect_flags))
1905 return false;
1906 }
1907 return parent->MapToVisualRectInAncestorSpaceInternal(
1908 ancestor, transform_state, visual_rect_flags);
1909 }
1910 return true;
1911 }
1912
GetPropertyContainer(AncestorSkipInfo * skip_info,PropertyTreeStateOrAlias * container_properties) const1913 const LayoutObject* LayoutObject::GetPropertyContainer(
1914 AncestorSkipInfo* skip_info,
1915 PropertyTreeStateOrAlias* container_properties) const {
1916 NOT_DESTROYED();
1917 const LayoutObject* property_container = this;
1918 while (!property_container->FirstFragment().HasLocalBorderBoxProperties()) {
1919 property_container = property_container->Container(skip_info);
1920 if (!property_container || (skip_info && skip_info->AncestorSkipped()) ||
1921 property_container->FirstFragment().NextFragment())
1922 return nullptr;
1923 }
1924 if (container_properties) {
1925 if (property_container == this) {
1926 *container_properties = FirstFragment().LocalBorderBoxProperties();
1927 } else {
1928 *container_properties =
1929 property_container->FirstFragment().ContentsProperties();
1930 }
1931 }
1932 return property_container;
1933 }
1934
HitTestForOcclusion(const PhysicalRect & hit_rect) const1935 HitTestResult LayoutObject::HitTestForOcclusion(
1936 const PhysicalRect& hit_rect) const {
1937 NOT_DESTROYED();
1938 LocalFrame* frame = GetDocument().GetFrame();
1939 DCHECK(!frame->View()->NeedsLayout());
1940 HitTestRequest::HitTestRequestType hit_type =
1941 HitTestRequest::kIgnorePointerEventsNone | HitTestRequest::kReadOnly |
1942 HitTestRequest::kIgnoreClipping |
1943 HitTestRequest::kIgnoreZeroOpacityObjects |
1944 HitTestRequest::kHitTestVisualOverflow;
1945 HitTestLocation location(hit_rect);
1946 return frame->GetEventHandler().HitTestResultAtLocation(location, hit_type,
1947 this, true);
1948 }
1949
DirtyLinesFromChangedChild(LayoutObject *,MarkingBehavior)1950 void LayoutObject::DirtyLinesFromChangedChild(LayoutObject*, MarkingBehavior) {
1951 NOT_DESTROYED();
1952 }
1953
operator <<(std::ostream & out,const LayoutObject & object)1954 std::ostream& operator<<(std::ostream& out, const LayoutObject& object) {
1955 String info;
1956 #if DCHECK_IS_ON()
1957 StringBuilder string_builder;
1958 object.DumpLayoutObject(string_builder, false, 0);
1959 info = string_builder.ToString();
1960 #else
1961 info = object.DebugName();
1962 #endif
1963 return out << static_cast<const void*>(&object) << ":" << info.Utf8();
1964 }
1965
operator <<(std::ostream & out,const LayoutObject * object)1966 std::ostream& operator<<(std::ostream& out, const LayoutObject* object) {
1967 if (!object)
1968 return out << "<null>";
1969 return out << *object;
1970 }
1971
1972 #if DCHECK_IS_ON()
1973
ShowTreeForThis() const1974 void LayoutObject::ShowTreeForThis() const {
1975 NOT_DESTROYED();
1976 if (GetNode())
1977 ::showTree(GetNode());
1978 }
1979
ShowLayoutTreeForThis() const1980 void LayoutObject::ShowLayoutTreeForThis() const {
1981 NOT_DESTROYED();
1982 showLayoutTree(this, nullptr);
1983 }
1984
ShowLineTreeForThis() const1985 void LayoutObject::ShowLineTreeForThis() const {
1986 NOT_DESTROYED();
1987 if (const LayoutBlock* cb = InclusiveContainingBlock()) {
1988 auto* child_block_flow = DynamicTo<LayoutBlockFlow>(cb);
1989 if (child_block_flow) {
1990 child_block_flow->ShowLineTreeAndMark(nullptr, nullptr, nullptr, nullptr,
1991 this);
1992 }
1993 }
1994 }
1995
ShowLayoutObject() const1996 void LayoutObject::ShowLayoutObject() const {
1997 NOT_DESTROYED();
1998 StringBuilder string_builder;
1999 DumpLayoutObject(string_builder, true, kShowTreeCharacterOffset);
2000 DLOG(INFO) << "\n" << string_builder.ToString().Utf8();
2001 }
2002
DumpLayoutObject(StringBuilder & string_builder,bool dump_address,unsigned show_tree_character_offset) const2003 void LayoutObject::DumpLayoutObject(StringBuilder& string_builder,
2004 bool dump_address,
2005 unsigned show_tree_character_offset) const {
2006 NOT_DESTROYED();
2007 string_builder.Append(DecoratedName());
2008
2009 if (dump_address)
2010 string_builder.AppendFormat(" %p", this);
2011
2012 if (IsText() && To<LayoutText>(this)->IsTextFragment()) {
2013 string_builder.AppendFormat(
2014 " \"%s\" ", To<LayoutText>(this)->GetText().Ascii().c_str());
2015 }
2016
2017 if (VirtualContinuation())
2018 string_builder.AppendFormat(" continuation=%p", VirtualContinuation());
2019
2020 if (GetNode()) {
2021 while (string_builder.length() < show_tree_character_offset)
2022 string_builder.Append(' ');
2023 string_builder.Append('\t');
2024 string_builder.Append(GetNode()->ToString());
2025 }
2026 if (ChildLayoutBlockedByDisplayLock())
2027 string_builder.Append(" (display-locked)");
2028 }
2029
DumpLayoutTreeAndMark(StringBuilder & string_builder,const LayoutObject * marked_object1,const char * marked_label1,const LayoutObject * marked_object2,const char * marked_label2,unsigned depth) const2030 void LayoutObject::DumpLayoutTreeAndMark(StringBuilder& string_builder,
2031 const LayoutObject* marked_object1,
2032 const char* marked_label1,
2033 const LayoutObject* marked_object2,
2034 const char* marked_label2,
2035 unsigned depth) const {
2036 NOT_DESTROYED();
2037 StringBuilder object_info;
2038 if (marked_object1 == this && marked_label1)
2039 object_info.Append(marked_label1);
2040 if (marked_object2 == this && marked_label2)
2041 object_info.Append(marked_label2);
2042 while (object_info.length() < depth * 2)
2043 object_info.Append(' ');
2044
2045 DumpLayoutObject(object_info, true, kShowTreeCharacterOffset);
2046 string_builder.Append(object_info);
2047
2048 if (!ChildLayoutBlockedByDisplayLock()) {
2049 for (const LayoutObject* child = SlowFirstChild(); child;
2050 child = child->NextSibling()) {
2051 string_builder.Append('\n');
2052 child->DumpLayoutTreeAndMark(string_builder, marked_object1,
2053 marked_label1, marked_object2, marked_label2,
2054 depth + 1);
2055 }
2056 }
2057 }
2058
2059 #endif // DCHECK_IS_ON()
2060
IsSelected() const2061 bool LayoutObject::IsSelected() const {
2062 NOT_DESTROYED();
2063 // Keep this fast and small, used in very hot functions to skip computing
2064 // selection when this is not selected. This function may be inlined in
2065 // link-optimized builds, but keeping fast and small helps running perf
2066 // tests.
2067 return GetSelectionState() != SelectionState::kNone ||
2068 // TODO(kojii): Can't we set SelectionState() properly to
2069 // LayoutTextFragment too?
2070 (IsA<LayoutTextFragment>(*this) && LayoutSelection::IsSelected(*this));
2071 }
2072
IsSelectable() const2073 bool LayoutObject::IsSelectable() const {
2074 NOT_DESTROYED();
2075 return !IsInert() && !(StyleRef().UserSelect() == EUserSelect::kNone &&
2076 StyleRef().UserModify() == EUserModify::kReadOnly);
2077 }
2078
SlowEffectiveStyle(NGStyleVariant style_variant) const2079 const ComputedStyle& LayoutObject::SlowEffectiveStyle(
2080 NGStyleVariant style_variant) const {
2081 NOT_DESTROYED();
2082 switch (style_variant) {
2083 case NGStyleVariant::kStandard:
2084 return StyleRef();
2085 case NGStyleVariant::kFirstLine:
2086 return FirstLineStyleRef();
2087 case NGStyleVariant::kEllipsis:
2088 // The ellipsis is styled according to the line style.
2089 // https://www.w3.org/TR/css-overflow-3/#ellipsing-details
2090 // Use first-line style if exists since most cases it is the first line.
2091 DCHECK(IsInline());
2092 if (LayoutObject* block = ContainingBlock())
2093 return block->FirstLineStyleRef();
2094 return FirstLineStyleRef();
2095 }
2096 NOTREACHED();
2097 return StyleRef();
2098 }
2099
2100 // Called when an object that was floating or positioned becomes a normal flow
2101 // object again. We have to make sure the layout tree updates as needed to
2102 // accommodate the new normal flow object.
HandleDynamicFloatPositionChange(LayoutObject * object)2103 static inline void HandleDynamicFloatPositionChange(LayoutObject* object) {
2104 // We have gone from not affecting the inline status of the parent flow to
2105 // suddenly having an impact. See if there is a mismatch between the parent
2106 // flow's childrenInline() state and our state.
2107 object->SetInline(object->StyleRef().IsDisplayInlineType());
2108 if (object->IsInline() != object->Parent()->ChildrenInline()) {
2109 if (!object->IsInline()) {
2110 To<LayoutBoxModelObject>(object->Parent())->ChildBecameNonInline(object);
2111 } else {
2112 // An anonymous block must be made to wrap this inline.
2113 LayoutBlock* block =
2114 To<LayoutBlock>(object->Parent())->CreateAnonymousBlock();
2115 LayoutObjectChildList* childlist = object->Parent()->VirtualChildren();
2116 childlist->InsertChildNode(object->Parent(), block, object);
2117 block->Children()->AppendChildNode(
2118 block, childlist->RemoveChildNode(object->Parent(), object));
2119 }
2120 }
2121 }
2122
AdjustStyleDifference(StyleDifference diff) const2123 StyleDifference LayoutObject::AdjustStyleDifference(
2124 StyleDifference diff) const {
2125 NOT_DESTROYED();
2126 if (diff.TransformChanged() && IsSVG()) {
2127 // Skip a full layout for transforms at the html/svg boundary which do not
2128 // affect sizes inside SVG.
2129 if (!IsSVGRoot())
2130 diff.SetNeedsFullLayout();
2131 }
2132
2133 // Optimization: for decoration/color property changes, invalidation is only
2134 // needed if we have style or text affected by these properties.
2135 if (diff.TextDecorationOrColorChanged() && !diff.NeedsPaintInvalidation()) {
2136 if (StyleRef().HasBorderColorReferencingCurrentColor() ||
2137 StyleRef().HasOutlineWithCurrentColor() ||
2138 StyleRef().HasBackgroundRelatedColorReferencingCurrentColor() ||
2139 // Skip any text nodes that do not contain text boxes. Whitespace cannot
2140 // be skipped or we will miss invalidating decorations (e.g.,
2141 // underlines). MathML elements are not skipped either as some of them
2142 // do special painting (e.g. fraction bar).
2143 (IsText() && !IsBR() && To<LayoutText>(this)->HasInlineFragments()) ||
2144 (IsSVG() && StyleRef().SvgStyle().IsFillColorCurrentColor()) ||
2145 (IsSVG() && StyleRef().SvgStyle().IsStrokeColorCurrentColor()) ||
2146 IsListMarkerForNormalContent() || IsDetailsMarker() || IsMathML())
2147 diff.SetNeedsPaintInvalidation();
2148 }
2149
2150 // TODO(1088373): Pixel_WebGLHighToLowPower fails without this. This isn't the
2151 // right way to ensure GPU switching. Investigate and do it in the right way.
2152 if (!diff.NeedsPaintInvalidation() && IsLayoutView() && Style() &&
2153 !Style()->GetFont().IsFallbackValid()) {
2154 diff.SetNeedsPaintInvalidation();
2155 }
2156
2157 // The answer to layerTypeRequired() for plugins, iframes, and canvas can
2158 // change without the actual style changing, since it depends on whether we
2159 // decide to composite these elements. When the/ layer status of one of these
2160 // elements changes, we need to force a layout.
2161 if (!diff.NeedsFullLayout() && Style() && IsBoxModelObject()) {
2162 bool requires_layer =
2163 To<LayoutBoxModelObject>(this)->LayerTypeRequired() != kNoPaintLayer;
2164 if (HasLayer() != requires_layer)
2165 diff.SetNeedsFullLayout();
2166 }
2167
2168 return diff;
2169 }
2170
SetPseudoElementStyle(scoped_refptr<const ComputedStyle> pseudo_style)2171 void LayoutObject::SetPseudoElementStyle(
2172 scoped_refptr<const ComputedStyle> pseudo_style) {
2173 NOT_DESTROYED();
2174 DCHECK(pseudo_style->StyleType() == kPseudoIdBefore ||
2175 pseudo_style->StyleType() == kPseudoIdAfter ||
2176 pseudo_style->StyleType() == kPseudoIdMarker ||
2177 pseudo_style->StyleType() == kPseudoIdFirstLetter);
2178
2179 // FIXME: We should consider just making all pseudo items use an inherited
2180 // style.
2181
2182 // Images are special and must inherit the pseudoStyle so the width and height
2183 // of the pseudo element doesn't change the size of the image. In all other
2184 // cases we can just share the style.
2185 //
2186 // Quotes are also LayoutInline, so we need to create an inherited style to
2187 // avoid getting an inline with positioning or an invalid display.
2188 //
2189 if (IsImage() || IsQuote()) {
2190 scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
2191 style->InheritFrom(*pseudo_style);
2192 SetStyle(std::move(style));
2193 return;
2194 }
2195
2196 SetStyle(std::move(pseudo_style));
2197 }
2198
MarkContainerChainForOverflowRecalcIfNeeded(bool mark_container_chain_layout_overflow_recalc)2199 void LayoutObject::MarkContainerChainForOverflowRecalcIfNeeded(
2200 bool mark_container_chain_layout_overflow_recalc) {
2201 NOT_DESTROYED();
2202 LayoutObject* object = this;
2203 do {
2204 // Cell and row need to propagate the flag to their containing section and
2205 // row as their containing block is the table wrapper.
2206 // This enables us to only recompute overflow the modified sections / rows.
2207 object = object->IsTableCell() || object->IsTableRow()
2208 ? object->Parent()
2209 : object->Container();
2210 if (object) {
2211 bool already_needs_layout_overflow_recalc = false;
2212 if (mark_container_chain_layout_overflow_recalc) {
2213 already_needs_layout_overflow_recalc =
2214 object->ChildNeedsLayoutOverflowRecalc();
2215 if (!already_needs_layout_overflow_recalc)
2216 object->SetChildNeedsLayoutOverflowRecalc();
2217 }
2218
2219 if (object->HasLayer()) {
2220 auto* box_model_object = To<LayoutBoxModelObject>(object);
2221 if (box_model_object->HasSelfPaintingLayer()) {
2222 auto* layer = box_model_object->Layer();
2223 if (layer->NeedsVisualOverflowRecalc()) {
2224 if (already_needs_layout_overflow_recalc)
2225 return;
2226 } else {
2227 layer->SetNeedsVisualOverflowRecalc();
2228 }
2229 }
2230 }
2231 }
2232
2233 } while (object);
2234 }
2235
SetNeedsOverflowRecalc(OverflowRecalcType overflow_recalc_type)2236 void LayoutObject::SetNeedsOverflowRecalc(
2237 OverflowRecalcType overflow_recalc_type) {
2238 NOT_DESTROYED();
2239 bool mark_container_chain_layout_overflow_recalc =
2240 !SelfNeedsLayoutOverflowRecalc();
2241
2242 if (overflow_recalc_type ==
2243 OverflowRecalcType::kLayoutAndVisualOverflowRecalc) {
2244 SetSelfNeedsLayoutOverflowRecalc();
2245 }
2246
2247 DCHECK(overflow_recalc_type ==
2248 OverflowRecalcType::kOnlyVisualOverflowRecalc ||
2249 overflow_recalc_type ==
2250 OverflowRecalcType::kLayoutAndVisualOverflowRecalc);
2251 SetShouldCheckForPaintInvalidation();
2252 MarkSelfPaintingLayerForVisualOverflowRecalc();
2253
2254 if (mark_container_chain_layout_overflow_recalc) {
2255 MarkContainerChainForOverflowRecalcIfNeeded(
2256 overflow_recalc_type ==
2257 OverflowRecalcType::kLayoutAndVisualOverflowRecalc);
2258 }
2259 }
2260
2261 DISABLE_CFI_PERF
SetStyle(scoped_refptr<const ComputedStyle> style,ApplyStyleChanges apply_changes)2262 void LayoutObject::SetStyle(scoped_refptr<const ComputedStyle> style,
2263 ApplyStyleChanges apply_changes) {
2264 NOT_DESTROYED();
2265 if (style_ == style)
2266 return;
2267
2268 if (apply_changes == ApplyStyleChanges::kNo) {
2269 SetStyleInternal(std::move(style));
2270 return;
2271 }
2272
2273 DCHECK(style);
2274
2275 StyleDifference diff;
2276 if (style_) {
2277 diff = style_->VisualInvalidationDiff(GetDocument(), *style);
2278 if (const auto* cached_inherited_first_line_style =
2279 style_->GetCachedPseudoElementStyle(kPseudoIdFirstLineInherited)) {
2280 // Merge the difference to the first line style because even if the new
2281 // style is the same as the old style, the new style may have some higher
2282 // priority properties overriding first line style.
2283 // See external/wpt/css/css-pseudo/first-line-change-inline-color*.html.
2284 diff.Merge(cached_inherited_first_line_style->VisualInvalidationDiff(
2285 GetDocument(), *style));
2286 }
2287 }
2288
2289 diff = AdjustStyleDifference(diff);
2290
2291 StyleWillChange(diff, *style);
2292
2293 scoped_refptr<const ComputedStyle> old_style = std::move(style_);
2294 SetStyleInternal(std::move(style));
2295
2296 if (!IsText())
2297 UpdateImageObservers(old_style.get(), style_.get());
2298
2299 CheckCounterChanges(old_style.get(), style_.get());
2300
2301 bool does_not_need_layout_or_paint_invalidation = !parent_;
2302
2303 StyleDidChange(diff, old_style.get());
2304
2305 // FIXME: |this| might be destroyed here. This can currently happen for a
2306 // LayoutTextFragment when its first-letter block gets an update in
2307 // LayoutTextFragment::styleDidChange. For LayoutTextFragment(s),
2308 // we will safely bail out with the doesNotNeedLayoutOrPaintInvalidation flag.
2309 // We might want to broaden this condition in the future as we move
2310 // layoutObject changes out of layout and into style changes.
2311 if (does_not_need_layout_or_paint_invalidation)
2312 return;
2313
2314 // Now that the layer (if any) has been updated, we need to adjust the diff
2315 // again, check whether we should layout now, and decide if we need to
2316 // invalidate paints.
2317 StyleDifference updated_diff = AdjustStyleDifference(diff);
2318
2319 if (!diff.NeedsFullLayout()) {
2320 if (updated_diff.NeedsFullLayout()) {
2321 SetNeedsLayoutAndIntrinsicWidthsRecalc(
2322 layout_invalidation_reason::kStyleChange);
2323 } else if (updated_diff.NeedsPositionedMovementLayout()) {
2324 SetNeedsPositionedMovementLayout();
2325 }
2326 }
2327
2328 // TODO(cbiesinger): Shouldn't this check container->NeedsLayout, since that's
2329 // the one we'll mark for NeedsOverflowRecalc()?
2330 if (diff.TransformChanged() && !NeedsLayout()) {
2331 if (LayoutBlock* container = ContainingBlock())
2332 container->SetNeedsOverflowRecalc();
2333 }
2334
2335 if (diff.NeedsRecomputeVisualOverflow()) {
2336 if (!(IsInLayoutNGInlineFormattingContext() &&
2337 RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) &&
2338 !IsLayoutNGObject() && !IsLayoutBlock() && !NeedsLayout()) {
2339 // TODO(crbug.com/1128199): This is still needed because
2340 // RecalcVisualOverflow() does not actually compute the visual overflow
2341 // for inline elements (legacy layout). However in LayoutNG
2342 // RecalcInlineChildrenInkOverflow() is called and visual overflow is
2343 // recomputed properly so we don't need this (see crbug.com/1043927).
2344 SetNeedsLayoutAndIntrinsicWidthsRecalc(
2345 layout_invalidation_reason::kStyleChange);
2346 } else {
2347 if (IsInLayoutNGInlineFormattingContext() && !NeedsLayout() &&
2348 RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
2349 if (auto* text = DynamicTo<LayoutText>(this))
2350 text->InvalidateVisualOverflow();
2351 }
2352 PaintingLayer()->SetNeedsVisualOverflowRecalc();
2353 SetShouldCheckForPaintInvalidation();
2354 }
2355 }
2356
2357 if (diff.NeedsPaintInvalidation() || updated_diff.NeedsPaintInvalidation()) {
2358 if (IsSVGRoot()) {
2359 // LayoutSVGRoot::LocalVisualRect() depends on some styles.
2360 SetShouldDoFullPaintInvalidation();
2361 } else {
2362 // We'll set needing geometry change later if the style change does cause
2363 // possible layout change or visual overflow change.
2364 SetShouldDoFullPaintInvalidationWithoutGeometryChange();
2365 }
2366 }
2367
2368 if (diff.NeedsPaintInvalidation() && old_style &&
2369 !old_style->ClipPathDataEquivalent(*style_)) {
2370 InvalidateClipPathCache();
2371 PaintingLayer()->SetNeedsCompositingInputsUpdate();
2372 }
2373
2374 if (diff.NeedsVisualRectUpdate())
2375 SetShouldCheckForPaintInvalidation();
2376
2377 // Text nodes share style with their parents but the paint properties don't
2378 // apply to them, hence the !isText() check. If property nodes are added or
2379 // removed as a result of these style changes, PaintPropertyTreeBuilder will
2380 // call SetNeedsRepaint to cause re-generation of PaintChunks.
2381 // This is skipped if no layer is present because |PaintLayer::StyleDidChange|
2382 // will handle this invalidation.
2383 if (!IsText() && !HasLayer() &&
2384 (diff.TransformChanged() || diff.OpacityChanged() ||
2385 diff.ZIndexChanged() || diff.FilterChanged() || diff.CssClipChanged() ||
2386 diff.BlendModeChanged() || diff.MaskChanged() ||
2387 diff.CompositingReasonsChanged())) {
2388 SetNeedsPaintPropertyUpdate();
2389 }
2390 }
2391
UpdateImageObservers(const ComputedStyle * old_style,const ComputedStyle * new_style)2392 void LayoutObject::UpdateImageObservers(const ComputedStyle* old_style,
2393 const ComputedStyle* new_style) {
2394 NOT_DESTROYED();
2395 DCHECK(old_style || new_style);
2396 DCHECK(!IsText());
2397
2398 UpdateFillImages(old_style ? &old_style->BackgroundLayers() : nullptr,
2399 new_style ? &new_style->BackgroundLayers() : nullptr);
2400 UpdateFillImages(old_style ? &old_style->MaskLayers() : nullptr,
2401 new_style ? &new_style->MaskLayers() : nullptr);
2402
2403 UpdateImage(old_style ? old_style->BorderImage().GetImage() : nullptr,
2404 new_style ? new_style->BorderImage().GetImage() : nullptr);
2405 UpdateImage(old_style ? old_style->MaskBoxImage().GetImage() : nullptr,
2406 new_style ? new_style->MaskBoxImage().GetImage() : nullptr);
2407
2408 StyleImage* old_content_image =
2409 old_style && old_style->GetContentData() &&
2410 old_style->GetContentData()->IsImage()
2411 ? To<ImageContentData>(old_style->GetContentData())->GetImage()
2412 : nullptr;
2413 StyleImage* new_content_image =
2414 new_style && new_style->GetContentData() &&
2415 new_style->GetContentData()->IsImage()
2416 ? To<ImageContentData>(new_style->GetContentData())->GetImage()
2417 : nullptr;
2418 UpdateImage(old_content_image, new_content_image);
2419
2420 StyleImage* old_box_reflect_mask_image =
2421 old_style && old_style->BoxReflect()
2422 ? old_style->BoxReflect()->Mask().GetImage()
2423 : nullptr;
2424 StyleImage* new_box_reflect_mask_image =
2425 new_style && new_style->BoxReflect()
2426 ? new_style->BoxReflect()->Mask().GetImage()
2427 : nullptr;
2428 UpdateImage(old_box_reflect_mask_image, new_box_reflect_mask_image);
2429
2430 UpdateShapeImage(old_style ? old_style->ShapeOutside() : nullptr,
2431 new_style ? new_style->ShapeOutside() : nullptr);
2432 UpdateCursorImages(old_style ? old_style->Cursors() : nullptr,
2433 new_style ? new_style->Cursors() : nullptr);
2434
2435 UpdateFirstLineImageObservers(new_style);
2436 }
2437
UpdateFirstLineImageObservers(const ComputedStyle * new_style)2438 void LayoutObject::UpdateFirstLineImageObservers(
2439 const ComputedStyle* new_style) {
2440 NOT_DESTROYED();
2441 bool has_new_first_line_style =
2442 new_style && new_style->HasPseudoElementStyle(kPseudoIdFirstLine) &&
2443 BehavesLikeBlockContainer();
2444 DCHECK(!has_new_first_line_style || new_style == Style());
2445
2446 if (!bitfields_.RegisteredAsFirstLineImageObserver() &&
2447 !has_new_first_line_style)
2448 return;
2449
2450 using FirstLineStyleMap =
2451 HashMap<const LayoutObject*, scoped_refptr<const ComputedStyle>>;
2452 DEFINE_STATIC_LOCAL(FirstLineStyleMap, first_line_style_map, ());
2453 DCHECK_EQ(bitfields_.RegisteredAsFirstLineImageObserver(),
2454 first_line_style_map.Contains(this));
2455 const auto* old_first_line_style =
2456 bitfields_.RegisteredAsFirstLineImageObserver()
2457 ? first_line_style_map.at(this)
2458 : nullptr;
2459
2460 // UpdateFillImages() may indirectly call LayoutBlock::ImageChanged() which
2461 // will invalidate the first line style cache and remove a reference to
2462 // new_first_line_style, so hold a reference here.
2463 scoped_refptr<const ComputedStyle> new_first_line_style =
2464 has_new_first_line_style ? FirstLineStyleWithoutFallback() : nullptr;
2465
2466 if (new_first_line_style && !new_first_line_style->HasBackgroundImage())
2467 new_first_line_style = nullptr;
2468
2469 if (old_first_line_style || new_first_line_style) {
2470 UpdateFillImages(
2471 old_first_line_style ? &old_first_line_style->BackgroundLayers()
2472 : nullptr,
2473 new_first_line_style ? &new_first_line_style->BackgroundLayers()
2474 : nullptr);
2475 if (new_first_line_style) {
2476 // The cached first line style may have been invalidated during
2477 // UpdateFillImages, so get it again. However, the new cached first line
2478 // style should be the same as the previous new_first_line_style.
2479 DCHECK(FillLayer::ImagesIdentical(
2480 &new_first_line_style->BackgroundLayers(),
2481 &FirstLineStyleWithoutFallback()->BackgroundLayers()));
2482 new_first_line_style = FirstLineStyleWithoutFallback();
2483 bitfields_.SetRegisteredAsFirstLineImageObserver(true);
2484 first_line_style_map.Set(this, std::move(new_first_line_style));
2485 } else {
2486 bitfields_.SetRegisteredAsFirstLineImageObserver(false);
2487 first_line_style_map.erase(this);
2488 }
2489 DCHECK_EQ(bitfields_.RegisteredAsFirstLineImageObserver(),
2490 first_line_style_map.Contains(this));
2491 }
2492 }
2493
StyleWillChange(StyleDifference diff,const ComputedStyle & new_style)2494 void LayoutObject::StyleWillChange(StyleDifference diff,
2495 const ComputedStyle& new_style) {
2496 NOT_DESTROYED();
2497 if (style_) {
2498 bool visibility_changed = style_->Visibility() != new_style.Visibility();
2499 // If our z-index changes value or our visibility changes,
2500 // we need to dirty our stacking context's z-order list.
2501 if (visibility_changed ||
2502 style_->EffectiveZIndex() != new_style.EffectiveZIndex() ||
2503 IsStackingContext(*style_) != IsStackingContext(new_style)) {
2504 GetDocument().SetAnnotatedRegionsDirty(true);
2505 if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache()) {
2506 if (GetNode())
2507 cache->ChildrenChanged(GetNode()->parentNode());
2508 else
2509 cache->ChildrenChanged(Parent());
2510 }
2511 }
2512
2513 bool background_color_changed =
2514 ResolveColor(GetCSSPropertyBackgroundColor()) !=
2515 ResolveColor(new_style, GetCSSPropertyBackgroundColor());
2516
2517 if (diff.TextDecorationOrColorChanged() || background_color_changed ||
2518 style_->GetFontDescription() != new_style.GetFontDescription() ||
2519 style_->GetWritingDirection() != new_style.GetWritingDirection() ||
2520 style_->InsideLink() != new_style.InsideLink() ||
2521 style_->VerticalAlign() != new_style.VerticalAlign() ||
2522 style_->GetTextAlign() != new_style.GetTextAlign() ||
2523 style_->TextIndent() != new_style.TextIndent()) {
2524 if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
2525 cache->StyleChanged(this);
2526 }
2527
2528 if (diff.TransformChanged()) {
2529 if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
2530 cache->LocationChanged(this);
2531 }
2532
2533 // Keep layer hierarchy visibility bits up to date if visibility changes.
2534 if (visibility_changed) {
2535 // We might not have an enclosing layer yet because we might not be in the
2536 // tree.
2537 if (PaintLayer* layer = EnclosingLayer())
2538 layer->DirtyVisibleContentStatus();
2539 }
2540
2541 if (IsFloating() &&
2542 (style_->UnresolvedFloating() != new_style.UnresolvedFloating())) {
2543 // For changes in float styles, we need to conceivably remove ourselves
2544 // from the floating objects list.
2545 To<LayoutBox>(this)->RemoveFloatingOrPositionedChildFromBlockLists();
2546 } else if (IsOutOfFlowPositioned() &&
2547 (style_->GetPosition() != new_style.GetPosition())) {
2548 // For changes in positioning styles, we need to conceivably remove
2549 // ourselves from the positioned objects list.
2550 To<LayoutBox>(this)->RemoveFloatingOrPositionedChildFromBlockLists();
2551 }
2552
2553 affects_parent_block_ =
2554 IsFloatingOrOutOfFlowPositioned() &&
2555 ((!new_style.IsFloating() || new_style.IsFlexOrGridItem()) &&
2556 !new_style.HasOutOfFlowPosition()) &&
2557 Parent() &&
2558 (Parent()->IsLayoutBlockFlow() || Parent()->IsLayoutInline());
2559
2560 // Clearing these bits is required to avoid leaving stale layoutObjects.
2561 // FIXME: We shouldn't need that hack if our logic was totally correct.
2562 if (diff.NeedsLayout()) {
2563 SetFloating(false);
2564 ClearPositionedState();
2565 }
2566 } else {
2567 affects_parent_block_ = false;
2568 }
2569
2570 // Elements with non-auto touch-action will send a SetTouchAction message
2571 // on touchstart in EventHandler::handleTouchEvent, and so effectively have
2572 // a touchstart handler that must be reported.
2573 //
2574 // Since a CSS property cannot be applied directly to a text node, a
2575 // handler will have already been added for its parent so ignore it.
2576 //
2577 // Elements may inherit touch action from parent frame, so we need to report
2578 // touchstart handler if the root layout object has non-auto effective touch
2579 // action.
2580 TouchAction old_touch_action = TouchAction::kAuto;
2581 bool is_document_element = GetNode() && IsDocumentElement();
2582 if (style_) {
2583 old_touch_action = style_->GetEffectiveTouchAction();
2584 }
2585 TouchAction new_touch_action = new_style.GetEffectiveTouchAction();
2586 if (GetNode() && !GetNode()->IsTextNode() &&
2587 (old_touch_action == TouchAction::kAuto) !=
2588 (new_touch_action == TouchAction::kAuto)) {
2589 EventHandlerRegistry& registry =
2590 GetDocument().GetFrame()->GetEventHandlerRegistry();
2591 if (new_touch_action != TouchAction::kAuto) {
2592 registry.DidAddEventHandler(*GetNode(),
2593 EventHandlerRegistry::kTouchAction);
2594 } else {
2595 registry.DidRemoveEventHandler(*GetNode(),
2596 EventHandlerRegistry::kTouchAction);
2597 }
2598 MarkEffectiveAllowedTouchActionChanged();
2599 }
2600 if (is_document_element && style_ && style_->Opacity() == 0.0f &&
2601 new_style.Opacity() != 0.0f) {
2602 if (LocalFrameView* frame_view = GetFrameView())
2603 frame_view->GetPaintTimingDetector().ReportIgnoredContent();
2604 }
2605 }
2606
ClearBaseComputedStyle()2607 void LayoutObject::ClearBaseComputedStyle() {
2608 NOT_DESTROYED();
2609 auto* element = DynamicTo<Element>(GetNode());
2610 if (!element)
2611 return;
2612
2613 if (ElementAnimations* animations = element->GetElementAnimations())
2614 animations->ClearBaseComputedStyle();
2615 }
2616
AreNonIdenticalCursorListsEqual(const ComputedStyle * a,const ComputedStyle * b)2617 static bool AreNonIdenticalCursorListsEqual(const ComputedStyle* a,
2618 const ComputedStyle* b) {
2619 DCHECK_NE(a->Cursors(), b->Cursors());
2620 return a->Cursors() && b->Cursors() && *a->Cursors() == *b->Cursors();
2621 }
2622
AreCursorsEqual(const ComputedStyle * a,const ComputedStyle * b)2623 static inline bool AreCursorsEqual(const ComputedStyle* a,
2624 const ComputedStyle* b) {
2625 return a->Cursor() == b->Cursor() && (a->Cursors() == b->Cursors() ||
2626 AreNonIdenticalCursorListsEqual(a, b));
2627 }
2628
SetScrollAnchorDisablingStyleChangedOnAncestor()2629 void LayoutObject::SetScrollAnchorDisablingStyleChangedOnAncestor() {
2630 NOT_DESTROYED();
2631 // Walk up the parent chain and find the first scrolling block to disable
2632 // scroll anchoring on.
2633 LayoutObject* object = Parent();
2634 Element* viewport_defining_element = GetDocument().ViewportDefiningElement();
2635 while (object) {
2636 auto* block = DynamicTo<LayoutBlock>(object);
2637 if (block && (block->HasNonVisibleOverflow() ||
2638 block->GetNode() == viewport_defining_element)) {
2639 block->SetScrollAnchorDisablingStyleChanged(true);
2640 return;
2641 }
2642 object = object->Parent();
2643 }
2644 }
2645
ClearAncestorScrollAnchors(LayoutObject * layout_object)2646 static void ClearAncestorScrollAnchors(LayoutObject* layout_object) {
2647 PaintLayer* layer = nullptr;
2648 if (LayoutObject* parent = layout_object->Parent())
2649 layer = parent->EnclosingLayer();
2650
2651 while (layer) {
2652 if (PaintLayerScrollableArea* scrollable_area =
2653 layer->GetScrollableArea()) {
2654 ScrollAnchor* anchor = scrollable_area->GetScrollAnchor();
2655 DCHECK(anchor);
2656 anchor->Clear();
2657 }
2658 layer = layer->Parent();
2659 }
2660 }
2661
StyleDidChange(StyleDifference diff,const ComputedStyle * old_style)2662 void LayoutObject::StyleDidChange(StyleDifference diff,
2663 const ComputedStyle* old_style) {
2664 NOT_DESTROYED();
2665 if (HasHiddenBackface()) {
2666 bool preserve_3d =
2667 (Parent() && Parent()->StyleRef().UsedTransformStyle3D() ==
2668 ETransformStyle3D::kPreserve3d);
2669 if (style_->HasTransform() || preserve_3d) {
2670 UseCounter::Count(GetDocument(),
2671 WebFeature::kHiddenBackfaceWithPossible3D);
2672 }
2673 if (preserve_3d) {
2674 UseCounter::Count(GetDocument(),
2675 WebFeature::kHiddenBackfaceWithPreserve3D);
2676 }
2677 }
2678
2679 if (ShouldApplyStrictContainment() &&
2680 (style_->ContentVisibility() == EContentVisibility::kVisible)) {
2681 if (ShouldApplyStyleContainment()) {
2682 UseCounter::Count(GetDocument(),
2683 WebFeature::kCSSContainAllWithoutContentVisibility);
2684 }
2685 UseCounter::Count(GetDocument(),
2686 WebFeature::kCSSContainStrictWithoutContentVisibility);
2687 }
2688
2689 // First assume the outline will be affected. It may be updated when we know
2690 // it's not affected.
2691 SetOutlineMayBeAffectedByDescendants(style_->HasOutline());
2692
2693 if (affects_parent_block_)
2694 HandleDynamicFloatPositionChange(this);
2695
2696 if (diff.NeedsFullLayout()) {
2697 // If the in-flow state of an element is changed, disable scroll
2698 // anchoring on the containing scroller.
2699 if (old_style->HasOutOfFlowPosition() != style_->HasOutOfFlowPosition()) {
2700 SetScrollAnchorDisablingStyleChangedOnAncestor();
2701 if (RuntimeEnabledFeatures::LayoutNGEnabled())
2702 MarkParentForOutOfFlowPositionedChange();
2703 }
2704
2705 // If the object already needs layout, then setNeedsLayout won't do
2706 // any work. But if the containing block has changed, then we may need
2707 // to mark the new containing blocks for layout. The change that can
2708 // directly affect the containing block of this object is a change to
2709 // the position style.
2710 if (NeedsLayout() && old_style->GetPosition() != style_->GetPosition()) {
2711 MarkContainerChainForLayout();
2712 }
2713
2714 SetNeedsLayoutAndIntrinsicWidthsRecalc(
2715 layout_invalidation_reason::kStyleChange);
2716 } else if (diff.NeedsPositionedMovementLayout()) {
2717 SetNeedsPositionedMovementLayout();
2718 }
2719
2720 if (diff.ScrollAnchorDisablingPropertyChanged())
2721 SetScrollAnchorDisablingStyleChanged(true);
2722
2723 // Don't check for paint invalidation here; we need to wait until the layer
2724 // has been updated by subclasses before we know if we have to invalidate
2725 // paints (in setStyle()).
2726
2727 if (old_style && !AreCursorsEqual(old_style, Style())) {
2728 if (LocalFrame* frame = GetFrame()) {
2729 // Cursor update scheduling is done by the local root, which is the main
2730 // frame if there are no RemoteFrame ancestors in the frame tree. Use of
2731 // localFrameRoot() is discouraged but will change when cursor update
2732 // scheduling is moved from EventHandler to PageEventHandler.
2733 frame->LocalFrameRoot().GetEventHandler().ScheduleCursorUpdate();
2734 }
2735 }
2736
2737 if (diff.NeedsPaintInvalidation() && old_style) {
2738 if (ResolveColor(*old_style, GetCSSPropertyBackgroundColor()) !=
2739 ResolveColor(GetCSSPropertyBackgroundColor()) ||
2740 old_style->BackgroundLayers() != StyleRef().BackgroundLayers())
2741 SetBackgroundNeedsFullPaintInvalidation();
2742 }
2743
2744 ApplyPseudoElementStyleChanges(old_style);
2745
2746 if (old_style &&
2747 old_style->UsedTransformStyle3D() != StyleRef().UsedTransformStyle3D()) {
2748 // Change of transform-style may affect descendant transform property nodes.
2749 AddSubtreePaintPropertyUpdateReason(
2750 SubtreePaintPropertyUpdateReason::kTransformStyleChanged);
2751 }
2752
2753 if (old_style && old_style->OverflowAnchor() != StyleRef().OverflowAnchor()) {
2754 ClearAncestorScrollAnchors(this);
2755 }
2756 }
2757
ApplyPseudoElementStyleChanges(const ComputedStyle * old_style)2758 void LayoutObject::ApplyPseudoElementStyleChanges(
2759 const ComputedStyle* old_style) {
2760 NOT_DESTROYED();
2761 ApplyFirstLineChanges(old_style);
2762
2763 if ((old_style && old_style->HasPseudoElementStyle(kPseudoIdSelection)) ||
2764 StyleRef().HasPseudoElementStyle(kPseudoIdSelection))
2765 InvalidateSelectedChildrenOnStyleChange();
2766 }
2767
ApplyFirstLineChanges(const ComputedStyle * old_style)2768 void LayoutObject::ApplyFirstLineChanges(const ComputedStyle* old_style) {
2769 NOT_DESTROYED();
2770 bool has_old_first_line_style =
2771 old_style && old_style->HasPseudoElementStyle(kPseudoIdFirstLine);
2772 bool has_new_first_line_style =
2773 StyleRef().HasPseudoElementStyle(kPseudoIdFirstLine);
2774 if (!has_old_first_line_style && !has_new_first_line_style)
2775 return;
2776
2777 StyleDifference diff;
2778 bool has_diff = false;
2779 if (Parent() && has_old_first_line_style && has_new_first_line_style) {
2780 if (const auto* old_first_line_style =
2781 old_style->GetCachedPseudoElementStyle(kPseudoIdFirstLine)) {
2782 if (const auto* new_first_line_style = FirstLineStyleWithoutFallback()) {
2783 diff = old_first_line_style->VisualInvalidationDiff(
2784 GetDocument(), *new_first_line_style);
2785 has_diff = true;
2786 }
2787 }
2788 }
2789 if (!has_diff) {
2790 diff.SetNeedsPaintInvalidation();
2791 diff.SetNeedsFullLayout();
2792 }
2793
2794 if (BehavesLikeBlockContainer() &&
2795 (diff.NeedsPaintInvalidation() || diff.TextDecorationOrColorChanged())) {
2796 if (auto* first_line_container =
2797 To<LayoutBlock>(this)->NearestInnerBlockWithFirstLine())
2798 first_line_container->SetShouldDoFullPaintInvalidationForFirstLine();
2799 }
2800
2801 if (diff.NeedsLayout()) {
2802 if (diff.NeedsFullLayout())
2803 SetNeedsCollectInlines();
2804 SetNeedsLayoutAndIntrinsicWidthsRecalc(
2805 layout_invalidation_reason::kStyleChange);
2806 }
2807 }
2808
PropagateStyleToAnonymousChildren()2809 void LayoutObject::PropagateStyleToAnonymousChildren() {
2810 NOT_DESTROYED();
2811 // FIXME: We could save this call when the change only affected non-inherited
2812 // properties.
2813 for (LayoutObject* child = SlowFirstChild(); child;
2814 child = child->NextSibling()) {
2815 if (!child->IsAnonymous() || child->StyleRef().StyleType() != kPseudoIdNone)
2816 continue;
2817 if (child->AnonymousHasStylePropagationOverride())
2818 continue;
2819
2820 scoped_refptr<ComputedStyle> new_style =
2821 ComputedStyle::CreateAnonymousStyleWithDisplay(
2822 StyleRef(), child->StyleRef().Display());
2823
2824 // Preserve the position style of anonymous block continuations as they can
2825 // have relative position when they contain block descendants of relative
2826 // positioned inlines.
2827 auto* child_block_flow = DynamicTo<LayoutBlockFlow>(child);
2828 if (child->IsInFlowPositioned() && child_block_flow &&
2829 child_block_flow->IsAnonymousBlockContinuation())
2830 new_style->SetPosition(child->StyleRef().GetPosition());
2831
2832 UpdateAnonymousChildStyle(child, *new_style);
2833
2834 child->SetStyle(std::move(new_style));
2835 }
2836
2837 PseudoId pseudo_id = StyleRef().StyleType();
2838 if (pseudo_id == kPseudoIdNone)
2839 return;
2840
2841 // Don't propagate style from markers with 'content: normal' because it's not
2842 // needed and it would be slow.
2843 if (pseudo_id == kPseudoIdMarker && StyleRef().ContentBehavesAsNormal())
2844 return;
2845
2846 // Propagate style from pseudo elements to generated content. We skip children
2847 // with pseudo element StyleType() in the for-loop above and skip over
2848 // descendants which are not generated content in this subtree traversal.
2849 //
2850 // TODO(futhark): It's possible we could propagate anonymous style from pseudo
2851 // elements through anonymous table layout objects in the recursive
2852 // implementation above, but it would require propagating the StyleType()
2853 // somehow because there is code relying on generated content having a certain
2854 // StyleType().
2855 LayoutObject* child = NextInPreOrder(this);
2856 while (child) {
2857 if (!child->IsAnonymous()) {
2858 // Don't propagate into non-anonymous descendants of pseudo elements. This
2859 // can typically happen for ::first-letter inside ::before. The
2860 // ::first-letter will propagate to its anonymous children separately.
2861 child = child->NextInPreOrderAfterChildren(this);
2862 continue;
2863 }
2864 if (child->IsText() || child->IsQuote() || child->IsImage())
2865 child->SetPseudoElementStyle(Style());
2866 child = child->NextInPreOrder(this);
2867 }
2868 }
2869
AddAsImageObserver(StyleImage * image)2870 void LayoutObject::AddAsImageObserver(StyleImage* image) {
2871 NOT_DESTROYED();
2872 if (!image)
2873 return;
2874 #if DCHECK_IS_ON()
2875 ++as_image_observer_count_;
2876 #endif
2877 image->AddClient(this);
2878 }
2879
RemoveAsImageObserver(StyleImage * image)2880 void LayoutObject::RemoveAsImageObserver(StyleImage* image) {
2881 NOT_DESTROYED();
2882 if (!image)
2883 return;
2884 #if DCHECK_IS_ON()
2885 SECURITY_DCHECK(as_image_observer_count_ > 0u);
2886 --as_image_observer_count_;
2887 #endif
2888 image->RemoveClient(this);
2889 }
2890
UpdateFillImages(const FillLayer * old_layers,const FillLayer * new_layers)2891 void LayoutObject::UpdateFillImages(const FillLayer* old_layers,
2892 const FillLayer* new_layers) {
2893 NOT_DESTROYED();
2894 // Optimize the common case
2895 if (FillLayer::ImagesIdentical(old_layers, new_layers))
2896 return;
2897
2898 // Go through the new layers and AddAsImageObserver() first, to avoid removing
2899 // all clients of an image.
2900 for (const FillLayer* curr_new = new_layers; curr_new;
2901 curr_new = curr_new->Next())
2902 AddAsImageObserver(curr_new->GetImage());
2903
2904 for (const FillLayer* curr_old = old_layers; curr_old;
2905 curr_old = curr_old->Next())
2906 RemoveAsImageObserver(curr_old->GetImage());
2907 }
2908
UpdateCursorImages(const CursorList * old_cursors,const CursorList * new_cursors)2909 void LayoutObject::UpdateCursorImages(const CursorList* old_cursors,
2910 const CursorList* new_cursors) {
2911 NOT_DESTROYED();
2912 if (old_cursors && new_cursors && *old_cursors == *new_cursors)
2913 return;
2914
2915 if (new_cursors) {
2916 for (const auto& cursor : *new_cursors)
2917 AddAsImageObserver(cursor.GetImage());
2918 }
2919 if (old_cursors) {
2920 for (const auto& cursor : *old_cursors)
2921 RemoveAsImageObserver(cursor.GetImage());
2922 }
2923 }
2924
UpdateImage(StyleImage * old_image,StyleImage * new_image)2925 void LayoutObject::UpdateImage(StyleImage* old_image, StyleImage* new_image) {
2926 NOT_DESTROYED();
2927 if (old_image != new_image) {
2928 // AddAsImageObserver first, to avoid removing all clients of an image.
2929 AddAsImageObserver(new_image);
2930 RemoveAsImageObserver(old_image);
2931 }
2932 }
2933
UpdateShapeImage(const ShapeValue * old_shape_value,const ShapeValue * new_shape_value)2934 void LayoutObject::UpdateShapeImage(const ShapeValue* old_shape_value,
2935 const ShapeValue* new_shape_value) {
2936 NOT_DESTROYED();
2937 if (old_shape_value || new_shape_value) {
2938 UpdateImage(old_shape_value ? old_shape_value->GetImage() : nullptr,
2939 new_shape_value ? new_shape_value->GetImage() : nullptr);
2940 }
2941 }
2942
CheckCounterChanges(const ComputedStyle * old_style,const ComputedStyle * new_style)2943 void LayoutObject::CheckCounterChanges(const ComputedStyle* old_style,
2944 const ComputedStyle* new_style) {
2945 NOT_DESTROYED();
2946 DCHECK(new_style);
2947 if (old_style) {
2948 if (old_style->CounterDirectivesEqual(*new_style))
2949 return;
2950 } else {
2951 if (!new_style->GetCounterDirectives())
2952 return;
2953 }
2954 LayoutCounter::LayoutObjectStyleChanged(*this, old_style, *new_style);
2955 View()->SetNeedsCounterUpdate();
2956 }
2957
ViewRect() const2958 PhysicalRect LayoutObject::ViewRect() const {
2959 NOT_DESTROYED();
2960 return View()->ViewRect();
2961 }
2962
AncestorToLocalFloatPoint(const LayoutBoxModelObject * ancestor,const FloatPoint & container_point,MapCoordinatesFlags mode) const2963 FloatPoint LayoutObject::AncestorToLocalFloatPoint(
2964 const LayoutBoxModelObject* ancestor,
2965 const FloatPoint& container_point,
2966 MapCoordinatesFlags mode) const {
2967 NOT_DESTROYED();
2968 TransformState transform_state(
2969 TransformState::kUnapplyInverseTransformDirection, container_point);
2970 MapAncestorToLocal(ancestor, transform_state, mode);
2971 transform_state.Flatten();
2972
2973 return transform_state.LastPlanarPoint();
2974 }
2975
AncestorToLocalQuad(const LayoutBoxModelObject * ancestor,const FloatQuad & quad,MapCoordinatesFlags mode) const2976 FloatQuad LayoutObject::AncestorToLocalQuad(
2977 const LayoutBoxModelObject* ancestor,
2978 const FloatQuad& quad,
2979 MapCoordinatesFlags mode) const {
2980 NOT_DESTROYED();
2981 TransformState transform_state(
2982 TransformState::kUnapplyInverseTransformDirection,
2983 quad.BoundingBox().Center(), quad);
2984 MapAncestorToLocal(ancestor, transform_state, mode);
2985 transform_state.Flatten();
2986 return transform_state.LastPlanarQuad();
2987 }
2988
MapLocalToAncestor(const LayoutBoxModelObject * ancestor,TransformState & transform_state,MapCoordinatesFlags mode) const2989 void LayoutObject::MapLocalToAncestor(const LayoutBoxModelObject* ancestor,
2990 TransformState& transform_state,
2991 MapCoordinatesFlags mode) const {
2992 NOT_DESTROYED();
2993 if (ancestor == this)
2994 return;
2995
2996 AncestorSkipInfo skip_info(ancestor);
2997 const LayoutObject* container = Container(&skip_info);
2998 if (!container)
2999 return;
3000
3001 PhysicalOffset container_offset =
3002 OffsetFromContainer(container, mode & kIgnoreScrollOffset);
3003 // TODO(smcgruer): This is inefficient. Instead we should avoid including
3004 // offsetForInFlowPosition in offsetFromContainer when ignoring sticky.
3005 if (mode & kIgnoreStickyOffset && IsStickyPositioned()) {
3006 container_offset -=
3007 To<LayoutBoxModelObject>(this)->OffsetForInFlowPosition();
3008 }
3009
3010 if (IsLayoutFlowThread()) {
3011 // So far the point has been in flow thread coordinates (i.e. as if
3012 // everything in the fragmentation context lived in one tall single column).
3013 // Convert it to a visual point now, since we're about to escape the flow
3014 // thread.
3015 container_offset += PhysicalOffsetToBeNoop(
3016 ColumnOffset(transform_state.MappedPoint().ToLayoutPoint()));
3017 }
3018
3019 // Text objects just copy their parent's computed style, so we need to ignore
3020 // them.
3021 bool use_transforms = !(mode & kIgnoreTransforms);
3022 bool preserve3d =
3023 use_transforms &&
3024 ((container->StyleRef().Preserves3D() && !container->IsText()) ||
3025 (StyleRef().Preserves3D() && !IsText()));
3026 if (use_transforms && ShouldUseTransformFromContainer(container)) {
3027 TransformationMatrix t;
3028 GetTransformFromContainer(container, container_offset, t);
3029 transform_state.ApplyTransform(t, preserve3d
3030 ? TransformState::kAccumulateTransform
3031 : TransformState::kFlattenTransform);
3032 } else {
3033 transform_state.Move(container_offset,
3034 preserve3d ? TransformState::kAccumulateTransform
3035 : TransformState::kFlattenTransform);
3036 }
3037
3038 if (skip_info.AncestorSkipped()) {
3039 // There can't be a transform between |ancestor| and |o|, because transforms
3040 // create containers, so it should be safe to just subtract the delta
3041 // between the ancestor and |o|.
3042 transform_state.Move(-ancestor->OffsetFromAncestor(container),
3043 preserve3d ? TransformState::kAccumulateTransform
3044 : TransformState::kFlattenTransform);
3045 // If the ancestor is fixed, then the rect is already in its coordinates so
3046 // doesn't need viewport-adjusting.
3047 auto* layout_view = DynamicTo<LayoutView>(container);
3048 if (ancestor->StyleRef().GetPosition() != EPosition::kFixed &&
3049 layout_view && StyleRef().GetPosition() == EPosition::kFixed) {
3050 transform_state.Move(layout_view->OffsetForFixedPosition());
3051 }
3052 return;
3053 }
3054
3055 container->MapLocalToAncestor(ancestor, transform_state, mode);
3056 }
3057
PushMappingToContainer(const LayoutBoxModelObject * ancestor_to_stop_at,LayoutGeometryMap & geometry_map) const3058 const LayoutObject* LayoutObject::PushMappingToContainer(
3059 const LayoutBoxModelObject* ancestor_to_stop_at,
3060 LayoutGeometryMap& geometry_map) const {
3061 NOT_DESTROYED();
3062 NOTREACHED();
3063 return nullptr;
3064 }
3065
MapAncestorToLocal(const LayoutBoxModelObject * ancestor,TransformState & transform_state,MapCoordinatesFlags mode) const3066 void LayoutObject::MapAncestorToLocal(const LayoutBoxModelObject* ancestor,
3067 TransformState& transform_state,
3068 MapCoordinatesFlags mode) const {
3069 NOT_DESTROYED();
3070 if (this == ancestor)
3071 return;
3072
3073 AncestorSkipInfo skip_info(ancestor);
3074 LayoutObject* container = Container(&skip_info);
3075 if (!container)
3076 return;
3077
3078 if (!skip_info.AncestorSkipped())
3079 container->MapAncestorToLocal(ancestor, transform_state, mode);
3080
3081 PhysicalOffset container_offset = OffsetFromContainer(container);
3082 bool use_transforms = !(mode & kIgnoreTransforms);
3083 bool preserve3d = use_transforms && (container->StyleRef().Preserves3D() ||
3084 StyleRef().Preserves3D());
3085 if (use_transforms && ShouldUseTransformFromContainer(container)) {
3086 TransformationMatrix t;
3087 GetTransformFromContainer(container, container_offset, t);
3088 transform_state.ApplyTransform(t, preserve3d
3089 ? TransformState::kAccumulateTransform
3090 : TransformState::kFlattenTransform);
3091 } else {
3092 transform_state.Move(container_offset,
3093 preserve3d ? TransformState::kAccumulateTransform
3094 : TransformState::kFlattenTransform);
3095 }
3096
3097 if (IsLayoutFlowThread()) {
3098 // Descending into a flow thread. Convert to the local coordinate space,
3099 // i.e. flow thread coordinates.
3100 PhysicalOffset visual_point = transform_state.MappedPoint();
3101 transform_state.Move(
3102 visual_point -
3103 PhysicalOffsetToBeNoop(
3104 To<LayoutFlowThread>(this)->VisualPointToFlowThreadPoint(
3105 visual_point.ToLayoutPoint())));
3106 }
3107
3108 if (skip_info.AncestorSkipped()) {
3109 container_offset = ancestor->OffsetFromAncestor(container);
3110 transform_state.Move(-container_offset);
3111 // If the ancestor is fixed, then the rect is already in its coordinates so
3112 // doesn't need viewport-adjusting.
3113 auto* layout_view = DynamicTo<LayoutView>(container);
3114 if (ancestor->StyleRef().GetPosition() != EPosition::kFixed &&
3115 layout_view && StyleRef().GetPosition() == EPosition::kFixed) {
3116 transform_state.Move(layout_view->OffsetForFixedPosition());
3117 }
3118 }
3119 }
3120
ShouldUseTransformFromContainer(const LayoutObject * container_object) const3121 bool LayoutObject::ShouldUseTransformFromContainer(
3122 const LayoutObject* container_object) const {
3123 NOT_DESTROYED();
3124 // hasTransform() indicates whether the object has transform, transform-style
3125 // or perspective. We just care about transform, so check the layer's
3126 // transform directly.
3127 return (HasLayer() && To<LayoutBoxModelObject>(this)->Layer()->Transform()) ||
3128 (container_object && container_object->StyleRef().HasPerspective());
3129 }
3130
GetTransformFromContainer(const LayoutObject * container_object,const PhysicalOffset & offset_in_container,TransformationMatrix & transform,const PhysicalSize * size) const3131 void LayoutObject::GetTransformFromContainer(
3132 const LayoutObject* container_object,
3133 const PhysicalOffset& offset_in_container,
3134 TransformationMatrix& transform,
3135 const PhysicalSize* size) const {
3136 NOT_DESTROYED();
3137 transform.MakeIdentity();
3138 PaintLayer* layer =
3139 HasLayer() ? To<LayoutBoxModelObject>(this)->Layer() : nullptr;
3140 if (layer && layer->Transform())
3141 transform.Multiply(layer->CurrentTransform());
3142
3143 transform.PostTranslate(offset_in_container.left.ToFloat(),
3144 offset_in_container.top.ToFloat());
3145
3146 bool has_perspective = container_object && container_object->HasLayer() &&
3147 container_object->StyleRef().HasPerspective();
3148 if (has_perspective && RuntimeEnabledFeatures::TransformInteropEnabled() &&
3149 container_object != NonAnonymousAncestor())
3150 has_perspective = false;
3151
3152 if (has_perspective) {
3153 // Perspective on the container affects us, so we have to factor it in here.
3154 DCHECK(container_object->HasLayer());
3155 FloatPoint perspective_origin;
3156 if (const auto* container_box = DynamicTo<LayoutBox>(container_object))
3157 perspective_origin = container_box->PerspectiveOrigin(size);
3158
3159 TransformationMatrix perspective_matrix;
3160 perspective_matrix.ApplyPerspective(
3161 container_object->StyleRef().Perspective());
3162 perspective_matrix.ApplyTransformOrigin(perspective_origin.X(),
3163 perspective_origin.Y(), 0);
3164
3165 transform = perspective_matrix * transform;
3166 }
3167 }
3168
LocalToAncestorFloatPoint(const FloatPoint & local_point,const LayoutBoxModelObject * ancestor,MapCoordinatesFlags mode) const3169 FloatPoint LayoutObject::LocalToAncestorFloatPoint(
3170 const FloatPoint& local_point,
3171 const LayoutBoxModelObject* ancestor,
3172 MapCoordinatesFlags mode) const {
3173 NOT_DESTROYED();
3174 TransformState transform_state(TransformState::kApplyTransformDirection,
3175 local_point);
3176 MapLocalToAncestor(ancestor, transform_state, mode);
3177 transform_state.Flatten();
3178
3179 return transform_state.LastPlanarPoint();
3180 }
3181
LocalToAncestorRectFastPath(const PhysicalRect & rect,const LayoutBoxModelObject * ancestor,MapCoordinatesFlags mode,PhysicalRect & result) const3182 bool LayoutObject::LocalToAncestorRectFastPath(
3183 const PhysicalRect& rect,
3184 const LayoutBoxModelObject* ancestor,
3185 MapCoordinatesFlags mode,
3186 PhysicalRect& result) const {
3187 NOT_DESTROYED();
3188 if (!(mode & kUseGeometryMapperMode))
3189 return false;
3190 // No other modes are supported.
3191 if (mode & (~kUseGeometryMapperMode))
3192 return false;
3193
3194 if (!ancestor)
3195 ancestor = View();
3196
3197 if (ancestor == this)
3198 return true;
3199
3200 AncestorSkipInfo skip_info(ancestor);
3201 PropertyTreeStateOrAlias container_properties =
3202 PropertyTreeState::Uninitialized();
3203 const LayoutObject* property_container =
3204 GetPropertyContainer(&skip_info, &container_properties);
3205 if (!property_container)
3206 return false;
3207
3208 FloatRect mapping_rect(rect);
3209
3210 // This works because it's not possible to have any intervening clips,
3211 // effects, transforms between |this| and |property_container|, and therefore
3212 // FirstFragment().PaintOffset() is relative to the transform space defined by
3213 // FirstFragment().LocalBorderBoxProperties() (if this == property_container)
3214 // or property_container->FirstFragment().ContentsProperties().
3215 mapping_rect.Move(FloatSize(FirstFragment().PaintOffset()));
3216
3217 if (property_container != ancestor) {
3218 GeometryMapper::SourceToDestinationRect(
3219 container_properties.Transform(),
3220 ancestor->FirstFragment().LocalBorderBoxProperties().Transform(),
3221 mapping_rect);
3222 }
3223 mapping_rect.Move(-FloatSize(ancestor->FirstFragment().PaintOffset()));
3224
3225 result = PhysicalRect::EnclosingRect(mapping_rect);
3226 return true;
3227 }
3228
LocalToAncestorRect(const PhysicalRect & rect,const LayoutBoxModelObject * ancestor,MapCoordinatesFlags mode) const3229 PhysicalRect LayoutObject::LocalToAncestorRect(
3230 const PhysicalRect& rect,
3231 const LayoutBoxModelObject* ancestor,
3232 MapCoordinatesFlags mode) const {
3233 NOT_DESTROYED();
3234 PhysicalRect result;
3235 if (LocalToAncestorRectFastPath(rect, ancestor, mode, result))
3236 return result;
3237
3238 return PhysicalRect::EnclosingRect(
3239 LocalToAncestorQuad(FloatRect(rect), ancestor, mode).BoundingBox());
3240 }
3241
LocalToAncestorQuad(const FloatQuad & local_quad,const LayoutBoxModelObject * ancestor,MapCoordinatesFlags mode) const3242 FloatQuad LayoutObject::LocalToAncestorQuad(
3243 const FloatQuad& local_quad,
3244 const LayoutBoxModelObject* ancestor,
3245 MapCoordinatesFlags mode) const {
3246 NOT_DESTROYED();
3247 // Track the point at the center of the quad's bounding box. As
3248 // MapLocalToAncestor() calls OffsetFromContainer(), it will use that point
3249 // as the reference point to decide which column's transform to apply in
3250 // multiple-column blocks.
3251 TransformState transform_state(TransformState::kApplyTransformDirection,
3252 local_quad.BoundingBox().Center(), local_quad);
3253 MapLocalToAncestor(ancestor, transform_state, mode);
3254 transform_state.Flatten();
3255
3256 return transform_state.LastPlanarQuad();
3257 }
3258
LocalToAncestorRects(Vector<PhysicalRect> & rects,const LayoutBoxModelObject * ancestor,const PhysicalOffset & pre_offset,const PhysicalOffset & post_offset) const3259 void LayoutObject::LocalToAncestorRects(
3260 Vector<PhysicalRect>& rects,
3261 const LayoutBoxModelObject* ancestor,
3262 const PhysicalOffset& pre_offset,
3263 const PhysicalOffset& post_offset) const {
3264 NOT_DESTROYED();
3265 for (wtf_size_t i = 0; i < rects.size(); ++i) {
3266 PhysicalRect& rect = rects[i];
3267 rect.Move(pre_offset);
3268 FloatQuad container_quad =
3269 LocalToAncestorQuad(FloatQuad(FloatRect(rect)), ancestor);
3270 PhysicalRect container_rect =
3271 PhysicalRect::EnclosingRect(container_quad.BoundingBox());
3272 if (container_rect.IsEmpty()) {
3273 rects.EraseAt(i--);
3274 continue;
3275 }
3276 container_rect.Move(post_offset);
3277 rects[i] = container_rect;
3278 }
3279 }
3280
LocalToAncestorTransform(const LayoutBoxModelObject * ancestor,MapCoordinatesFlags mode) const3281 TransformationMatrix LayoutObject::LocalToAncestorTransform(
3282 const LayoutBoxModelObject* ancestor,
3283 MapCoordinatesFlags mode) const {
3284 NOT_DESTROYED();
3285 DCHECK(!(mode & kIgnoreTransforms));
3286 TransformState transform_state(TransformState::kApplyTransformDirection);
3287 MapLocalToAncestor(ancestor, transform_state, mode);
3288 return transform_state.AccumulatedTransform();
3289 }
3290
OffsetFromContainer(const LayoutObject * o,bool ignore_scroll_offset) const3291 PhysicalOffset LayoutObject::OffsetFromContainer(
3292 const LayoutObject* o,
3293 bool ignore_scroll_offset) const {
3294 NOT_DESTROYED();
3295 return OffsetFromContainerInternal(o, ignore_scroll_offset);
3296 }
3297
OffsetFromContainerInternal(const LayoutObject * o,bool ignore_scroll_offset) const3298 PhysicalOffset LayoutObject::OffsetFromContainerInternal(
3299 const LayoutObject* o,
3300 bool ignore_scroll_offset) const {
3301 NOT_DESTROYED();
3302 DCHECK_EQ(o, Container());
3303 return o->IsScrollContainer()
3304 ? OffsetFromScrollableContainer(o, ignore_scroll_offset)
3305 : PhysicalOffset();
3306 }
3307
OffsetFromScrollableContainer(const LayoutObject * container,bool ignore_scroll_offset) const3308 PhysicalOffset LayoutObject::OffsetFromScrollableContainer(
3309 const LayoutObject* container,
3310 bool ignore_scroll_offset) const {
3311 NOT_DESTROYED();
3312 DCHECK(container->IsScrollContainer());
3313 const auto* box = To<LayoutBox>(container);
3314 if (!ignore_scroll_offset)
3315 return -PhysicalOffset(box->ScrolledContentOffset());
3316
3317 // ScrollOrigin accounts for other writing modes whose content's origin is not
3318 // at the top-left.
3319 return PhysicalOffset(box->GetScrollableArea()->ScrollOrigin());
3320 }
3321
OffsetFromAncestor(const LayoutObject * ancestor_container) const3322 PhysicalOffset LayoutObject::OffsetFromAncestor(
3323 const LayoutObject* ancestor_container) const {
3324 NOT_DESTROYED();
3325 if (ancestor_container == this)
3326 return PhysicalOffset();
3327
3328 PhysicalOffset offset;
3329 PhysicalOffset reference_point;
3330 const LayoutObject* curr_container = this;
3331 AncestorSkipInfo skip_info(ancestor_container);
3332 do {
3333 const LayoutObject* next_container = curr_container->Container(&skip_info);
3334
3335 // This means we reached the top without finding container.
3336 CHECK(next_container);
3337 if (!next_container)
3338 break;
3339 DCHECK(!curr_container->HasTransformRelatedProperty());
3340 PhysicalOffset current_offset =
3341 curr_container->OffsetFromContainer(next_container);
3342 offset += current_offset;
3343 reference_point += current_offset;
3344 curr_container = next_container;
3345 } while (curr_container != ancestor_container &&
3346 !skip_info.AncestorSkipped());
3347 if (skip_info.AncestorSkipped()) {
3348 DCHECK(curr_container);
3349 offset -= ancestor_container->OffsetFromAncestor(curr_container);
3350 }
3351
3352 return offset;
3353 }
3354
LocalCaretRect(const InlineBox *,int,LayoutUnit * extra_width_to_end_of_line) const3355 LayoutRect LayoutObject::LocalCaretRect(
3356 const InlineBox*,
3357 int,
3358 LayoutUnit* extra_width_to_end_of_line) const {
3359 NOT_DESTROYED();
3360 if (extra_width_to_end_of_line)
3361 *extra_width_to_end_of_line = LayoutUnit();
3362
3363 return LayoutRect();
3364 }
3365
IsRooted() const3366 bool LayoutObject::IsRooted() const {
3367 NOT_DESTROYED();
3368 const LayoutObject* object = this;
3369 while (object->Parent() && !object->HasLayer())
3370 object = object->Parent();
3371 if (object->HasLayer())
3372 return To<LayoutBoxModelObject>(object)->Layer()->Root()->IsRootLayer();
3373 return false;
3374 }
3375
ShouldRespectImageOrientation(const LayoutObject * layout_object)3376 RespectImageOrientationEnum LayoutObject::ShouldRespectImageOrientation(
3377 const LayoutObject* layout_object) {
3378 if (layout_object && layout_object->Style() &&
3379 layout_object->StyleRef().RespectImageOrientation() !=
3380 kRespectImageOrientation)
3381 return kDoNotRespectImageOrientation;
3382
3383 return kRespectImageOrientation;
3384 }
3385
Container(AncestorSkipInfo * skip_info) const3386 LayoutObject* LayoutObject::Container(AncestorSkipInfo* skip_info) const {
3387 NOT_DESTROYED();
3388 // TODO(mstensho): Get rid of this. Nobody should call this method with those
3389 // flags already set.
3390 if (skip_info)
3391 skip_info->ResetOutput();
3392
3393 if (IsTextOrSVGChild())
3394 return Parent();
3395
3396 EPosition pos = style_->GetPosition();
3397 if (pos == EPosition::kFixed)
3398 return ContainerForFixedPosition(skip_info);
3399
3400 if (pos == EPosition::kAbsolute) {
3401 return ContainerForAbsolutePosition(skip_info);
3402 }
3403
3404 if (IsColumnSpanAll()) {
3405 LayoutObject* multicol_container = SpannerPlaceholder()->Container();
3406 if (skip_info) {
3407 // We jumped directly from the spanner to the multicol container. Need to
3408 // check if we skipped |ancestor| or filter/reflection on the way.
3409 for (LayoutObject* walker = Parent();
3410 walker && walker != multicol_container; walker = walker->Parent())
3411 skip_info->Update(*walker);
3412 }
3413 return multicol_container;
3414 }
3415
3416 if ((IsFloating() && !IsInLayoutNGInlineFormattingContext()) ||
3417 IsRenderedLegend())
3418 return ContainingBlock(skip_info);
3419
3420 return Parent();
3421 }
3422
ParentCrossingFrames() const3423 inline LayoutObject* LayoutObject::ParentCrossingFrames() const {
3424 NOT_DESTROYED();
3425 if (IsA<LayoutView>(this))
3426 return GetFrame()->OwnerLayoutObject();
3427 return Parent();
3428 }
3429
ClearLayoutRootIfNeeded() const3430 inline void LayoutObject::ClearLayoutRootIfNeeded() const {
3431 NOT_DESTROYED();
3432 if (LocalFrameView* view = GetFrameView()) {
3433 if (!DocumentBeingDestroyed())
3434 view->ClearLayoutSubtreeRoot(*this);
3435 }
3436 }
3437
WillBeDestroyed()3438 void LayoutObject::WillBeDestroyed() {
3439 NOT_DESTROYED();
3440 // Destroy any leftover anonymous children.
3441 LayoutObjectChildList* children = VirtualChildren();
3442 if (children)
3443 children->DestroyLeftoverChildren();
3444
3445 if (LocalFrame* frame = GetFrame()) {
3446 // If this layoutObject is being autoscrolled, stop the autoscrolling.
3447 if (frame->GetPage())
3448 frame->GetPage()->GetAutoscrollController().StopAutoscrollIfNeeded(this);
3449 }
3450
3451 // For accessibility management, notify the parent of the imminent change to
3452 // its child set.
3453 // We do it now, before remove(), while the parent pointer is still available.
3454 if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
3455 cache->ChildrenChanged(Parent());
3456
3457 Remove();
3458
3459 // The remove() call above may invoke axObjectCache()->childrenChanged() on
3460 // the parent, which may require the AX layout object for this layoutObject.
3461 // So we remove the AX layout object now, after the layoutObject is removed.
3462 if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
3463 cache->Remove(this);
3464
3465 // If this layoutObject had a parent, remove should have destroyed any
3466 // counters attached to this layoutObject and marked the affected other
3467 // counters for reevaluation. This apparently redundant check is here for the
3468 // case when this layoutObject had no parent at the time remove() was called.
3469
3470 if (HasCounterNodeMap())
3471 LayoutCounter::DestroyCounterNodes(*this);
3472
3473 // Remove the handler if node had touch-action set. Handlers are not added
3474 // for text nodes so don't try removing for one too. Need to check if
3475 // m_style is null in cases of partial construction. Any handler we added
3476 // previously may have already been removed by the Document independently.
3477 if (GetNode() && !GetNode()->IsTextNode() && style_ &&
3478 style_->GetTouchAction() != TouchAction::kAuto) {
3479 EventHandlerRegistry& registry =
3480 GetDocument().GetFrame()->GetEventHandlerRegistry();
3481 if (registry.EventHandlerTargets(EventHandlerRegistry::kTouchAction)
3482 ->Contains(GetNode())) {
3483 registry.DidRemoveEventHandler(*GetNode(),
3484 EventHandlerRegistry::kTouchAction);
3485 }
3486 }
3487
3488 SetAncestorLineBoxDirty(false);
3489
3490 ClearLayoutRootIfNeeded();
3491
3492 // Remove this object as ImageResourceObserver.
3493 if (style_ && !IsText())
3494 UpdateImageObservers(style_.get(), nullptr);
3495
3496 // We must have removed all image observers.
3497 SECURITY_CHECK(!bitfields_.RegisteredAsFirstLineImageObserver());
3498 #if DCHECK_IS_ON()
3499 SECURITY_DCHECK(as_image_observer_count_ == 0u);
3500 #endif
3501
3502 if (GetFrameView())
3503 SetIsBackgroundAttachmentFixedObject(false);
3504 }
3505
3506 DISABLE_CFI_PERF
InsertedIntoTree()3507 void LayoutObject::InsertedIntoTree() {
3508 NOT_DESTROYED();
3509 // FIXME: We should DCHECK(isRooted()) here but generated content makes some
3510 // out-of-order insertion.
3511
3512 // Keep our layer hierarchy updated. Optimize for the common case where we
3513 // don't have any children and don't have a layer attached to ourselves.
3514 PaintLayer* layer = nullptr;
3515 if (SlowFirstChild() || HasLayer()) {
3516 layer = Parent()->EnclosingLayer();
3517 AddLayers(layer);
3518 }
3519
3520 // If |this| is visible but this object was not, tell the layer it has some
3521 // visible content that needs to be drawn and layer visibility optimization
3522 // can't be used
3523 if (Parent()->StyleRef().Visibility() != EVisibility::kVisible &&
3524 StyleRef().Visibility() == EVisibility::kVisible && !HasLayer()) {
3525 if (!layer)
3526 layer = Parent()->EnclosingLayer();
3527 if (layer)
3528 layer->DirtyVisibleContentStatus();
3529 }
3530
3531 // |FirstInlineFragment()| should be cleared. |LayoutObjectChildList| does
3532 // this, just check here for all new objects in the tree.
3533 DCHECK_EQ(FirstInlineFragment(), nullptr);
3534
3535 if (Parent()->ChildrenInline())
3536 Parent()->DirtyLinesFromChangedChild(this);
3537
3538 if (LayoutFlowThread* flow_thread = FlowThreadContainingBlock())
3539 flow_thread->FlowThreadDescendantWasInserted(this);
3540 }
3541
3542 enum FindReferencingScrollAnchorsBehavior { kDontClear, kClear };
3543
FindReferencingScrollAnchors(LayoutObject * layout_object,FindReferencingScrollAnchorsBehavior behavior)3544 static bool FindReferencingScrollAnchors(
3545 LayoutObject* layout_object,
3546 FindReferencingScrollAnchorsBehavior behavior) {
3547 PaintLayer* layer = nullptr;
3548 if (LayoutObject* parent = layout_object->Parent())
3549 layer = parent->EnclosingLayer();
3550 bool found = false;
3551
3552 // Walk up the layer tree to clear any scroll anchors that reference us.
3553 while (layer) {
3554 if (PaintLayerScrollableArea* scrollable_area =
3555 layer->GetScrollableArea()) {
3556 ScrollAnchor* anchor = scrollable_area->GetScrollAnchor();
3557 DCHECK(anchor);
3558 if (anchor->RefersTo(layout_object)) {
3559 found = true;
3560 if (behavior == kClear)
3561 anchor->NotifyRemoved(layout_object);
3562 else
3563 return true;
3564 }
3565 }
3566 layer = layer->Parent();
3567 }
3568 return found;
3569 }
3570
WillBeRemovedFromTree()3571 void LayoutObject::WillBeRemovedFromTree() {
3572 NOT_DESTROYED();
3573 // FIXME: We should DCHECK(isRooted()) but we have some out-of-order removals
3574 // which would need to be fixed first.
3575
3576 // If we remove a visible child from an invisible parent, we don't know the
3577 // layer visibility any more.
3578 PaintLayer* layer = nullptr;
3579 if (Parent()->StyleRef().Visibility() != EVisibility::kVisible &&
3580 StyleRef().Visibility() == EVisibility::kVisible && !HasLayer()) {
3581 layer = Parent()->EnclosingLayer();
3582 if (layer)
3583 layer->DirtyVisibleContentStatus();
3584 }
3585
3586 // Keep our layer hierarchy updated.
3587 if (SlowFirstChild() || HasLayer()) {
3588 if (!layer)
3589 layer = Parent()->EnclosingLayer();
3590 RemoveLayers(layer);
3591 }
3592
3593 if (IsOutOfFlowPositioned() && Parent()->ChildrenInline())
3594 Parent()->DirtyLinesFromChangedChild(this);
3595
3596 RemoveFromLayoutFlowThread();
3597
3598 // Update cached boundaries in SVG layoutObjects if a child is removed.
3599 if (Parent()->IsSVG())
3600 Parent()->SetNeedsBoundariesUpdate();
3601
3602 if (bitfields_.IsScrollAnchorObject()) {
3603 // Clear the bit first so that anchor.clear() doesn't recurse into
3604 // findReferencingScrollAnchors.
3605 bitfields_.SetIsScrollAnchorObject(false);
3606 FindReferencingScrollAnchors(this, kClear);
3607 }
3608
3609 if (LocalFrameView* frame_view = GetFrameView())
3610 frame_view->GetPaintTimingDetector().LayoutObjectWillBeDestroyed(*this);
3611 }
3612
SetNeedsPaintPropertyUpdate()3613 void LayoutObject::SetNeedsPaintPropertyUpdate() {
3614 NOT_DESTROYED();
3615 SetNeedsPaintPropertyUpdatePreservingCachedRects();
3616 InvalidateIntersectionObserverCachedRects();
3617 }
3618
SetNeedsPaintPropertyUpdatePreservingCachedRects()3619 void LayoutObject::SetNeedsPaintPropertyUpdatePreservingCachedRects() {
3620 NOT_DESTROYED();
3621 if (bitfields_.NeedsPaintPropertyUpdate())
3622 return;
3623
3624 // Anytime a layout object needs a paint property update, we should also do
3625 // intersection observation.
3626 // TODO(vmpstr): Figure out if there's a cleaner way to do this outside of
3627 // this function, since this is potentially called many times for a single
3628 // frame view subtree.
3629 GetFrameView()->SetIntersectionObservationState(LocalFrameView::kDesired);
3630
3631 bitfields_.SetNeedsPaintPropertyUpdate(true);
3632 for (auto* ancestor = ParentCrossingFrames();
3633 ancestor && !ancestor->DescendantNeedsPaintPropertyUpdate();
3634 ancestor = ancestor->ParentCrossingFrames()) {
3635 ancestor->bitfields_.SetDescendantNeedsPaintPropertyUpdate(true);
3636 }
3637 }
3638
SetAncestorsNeedPaintPropertyUpdateForMainThreadScrolling()3639 void LayoutObject::SetAncestorsNeedPaintPropertyUpdateForMainThreadScrolling() {
3640 NOT_DESTROYED();
3641 LayoutObject* ancestor = ParentCrossingFrames();
3642 while (ancestor) {
3643 ancestor->SetNeedsPaintPropertyUpdate();
3644 ancestor = ancestor->ParentCrossingFrames();
3645 }
3646 }
3647
MaybeClearIsScrollAnchorObject()3648 void LayoutObject::MaybeClearIsScrollAnchorObject() {
3649 NOT_DESTROYED();
3650 if (!bitfields_.IsScrollAnchorObject())
3651 return;
3652 bitfields_.SetIsScrollAnchorObject(
3653 FindReferencingScrollAnchors(this, kDontClear));
3654 }
3655
RemoveFromLayoutFlowThread()3656 void LayoutObject::RemoveFromLayoutFlowThread() {
3657 NOT_DESTROYED();
3658 if (!IsInsideFlowThread())
3659 return;
3660
3661 // Sometimes we remove the element from the flow, but it's not destroyed at
3662 // that time.
3663 // It's only until later when we actually destroy it and remove all the
3664 // children from it.
3665 // Currently, that happens for firstLetter elements and list markers.
3666 // Pass in the flow thread so that we don't have to look it up for all the
3667 // children.
3668 // If we're a column spanner, we need to use our parent to find the flow
3669 // thread, since a spanner doesn't have the flow thread in its containing
3670 // block chain. We still need to notify the flow thread when the layoutObject
3671 // removed happens to be a spanner, so that we get rid of the spanner
3672 // placeholder, and column sets around the placeholder get merged.
3673 LayoutFlowThread* flow_thread = IsColumnSpanAll()
3674 ? Parent()->FlowThreadContainingBlock()
3675 : FlowThreadContainingBlock();
3676 RemoveFromLayoutFlowThreadRecursive(flow_thread);
3677 }
3678
RemoveFromLayoutFlowThreadRecursive(LayoutFlowThread * layout_flow_thread)3679 void LayoutObject::RemoveFromLayoutFlowThreadRecursive(
3680 LayoutFlowThread* layout_flow_thread) {
3681 NOT_DESTROYED();
3682 if (const LayoutObjectChildList* children = VirtualChildren()) {
3683 for (LayoutObject* child = children->FirstChild(); child;
3684 child = child->NextSibling()) {
3685 if (child->IsLayoutFlowThread())
3686 continue; // Don't descend into inner fragmentation contexts.
3687 child->RemoveFromLayoutFlowThreadRecursive(
3688 child->IsLayoutFlowThread() ? To<LayoutFlowThread>(child)
3689 : layout_flow_thread);
3690 }
3691 }
3692
3693 if (layout_flow_thread && layout_flow_thread != this)
3694 layout_flow_thread->FlowThreadDescendantWillBeRemoved(this);
3695 SetIsInsideFlowThread(false);
3696 CHECK(!SpannerPlaceholder());
3697 }
3698
DestroyAndCleanupAnonymousWrappers()3699 void LayoutObject::DestroyAndCleanupAnonymousWrappers() {
3700 NOT_DESTROYED();
3701 // If the tree is destroyed, there is no need for a clean-up phase.
3702 if (DocumentBeingDestroyed()) {
3703 Destroy();
3704 return;
3705 }
3706
3707 LayoutObject* destroy_root = this;
3708 for (LayoutObject *destroy_root_parent = destroy_root->Parent();
3709 destroy_root_parent && destroy_root_parent->IsAnonymous();
3710 destroy_root = destroy_root_parent,
3711 destroy_root_parent = destroy_root_parent->Parent()) {
3712 // Anonymous block continuations are tracked and destroyed elsewhere (see
3713 // the bottom of LayoutBlockFlow::RemoveChild)
3714 auto* destroy_root_parent_block =
3715 DynamicTo<LayoutBlockFlow>(destroy_root_parent);
3716 if (destroy_root_parent_block &&
3717 destroy_root_parent_block->IsAnonymousBlockContinuation())
3718 break;
3719 // A flow thread is tracked by its containing block. Whether its children
3720 // are removed or not is irrelevant.
3721 if (destroy_root_parent->IsLayoutFlowThread())
3722 break;
3723
3724 // We need to keep the anonymous parent, if it won't become empty by the
3725 // removal of this LayoutObject.
3726 if (destroy_root->PreviousSibling())
3727 break;
3728 if (const LayoutObject* sibling = destroy_root->NextSibling()) {
3729 if (destroy_root->GetNode()) {
3730 // When there are inline continuations, there may be multiple layout
3731 // objects generated from the same node, and those are special. They
3732 // will be removed as part of destroying |this|, in
3733 // LayoutInline::WillBeDestroyed(). So if that's all we have left, we
3734 // need to realize now that the anonymous containing block will become
3735 // empty. So we have to destroy it.
3736 while (sibling && sibling->GetNode() == destroy_root->GetNode())
3737 sibling = sibling->NextSibling();
3738 }
3739 if (sibling)
3740 break;
3741 DCHECK(destroy_root->IsLayoutInline());
3742 DCHECK(To<LayoutInline>(destroy_root)->Continuation());
3743 }
3744 }
3745
3746 destroy_root->Destroy();
3747
3748 // WARNING: |this| is deleted here.
3749 }
3750
Destroy()3751 void LayoutObject::Destroy() {
3752 NOT_DESTROYED();
3753 CHECK(g_allow_destroying_layout_object_in_finalizer ||
3754 !ThreadState::Current()->InAtomicSweepingPause());
3755
3756 // Mark as being destroyed to avoid trouble with merges in |RemoveChild()| and
3757 // other house keepings.
3758 bitfields_.SetBeingDestroyed(true);
3759 WillBeDestroyed();
3760 DeleteThis();
3761 }
3762
DeleteThis()3763 void LayoutObject::DeleteThis() {
3764 NOT_DESTROYED();
3765 delete this;
3766 }
3767
PositionForPoint(const PhysicalOffset &) const3768 PositionWithAffinity LayoutObject::PositionForPoint(
3769 const PhysicalOffset&) const {
3770 NOT_DESTROYED();
3771 return CreatePositionWithAffinity(CaretMinOffset());
3772 }
3773
GetCompositingState() const3774 CompositingState LayoutObject::GetCompositingState() const {
3775 NOT_DESTROYED();
3776 return HasLayer()
3777 ? To<LayoutBoxModelObject>(this)->Layer()->GetCompositingState()
3778 : kNotComposited;
3779 }
3780
CanHaveAdditionalCompositingReasons() const3781 bool LayoutObject::CanHaveAdditionalCompositingReasons() const {
3782 NOT_DESTROYED();
3783 return false;
3784 }
3785
AdditionalCompositingReasons() const3786 CompositingReasons LayoutObject::AdditionalCompositingReasons() const {
3787 NOT_DESTROYED();
3788 return CompositingReason::kNone;
3789 }
3790
HitTestAllPhases(HitTestResult & result,const HitTestLocation & hit_test_location,const PhysicalOffset & accumulated_offset,HitTestFilter hit_test_filter)3791 bool LayoutObject::HitTestAllPhases(HitTestResult& result,
3792 const HitTestLocation& hit_test_location,
3793 const PhysicalOffset& accumulated_offset,
3794 HitTestFilter hit_test_filter) {
3795 NOT_DESTROYED();
3796 bool inside = false;
3797 if (hit_test_filter != kHitTestSelf) {
3798 // First test the foreground layer (lines and inlines).
3799 inside = NodeAtPoint(result, hit_test_location, accumulated_offset,
3800 kHitTestForeground);
3801
3802 // Test floats next.
3803 if (!inside)
3804 inside = NodeAtPoint(result, hit_test_location, accumulated_offset,
3805 kHitTestFloat);
3806
3807 // Finally test to see if the mouse is in the background (within a child
3808 // block's background).
3809 if (!inside)
3810 inside = NodeAtPoint(result, hit_test_location, accumulated_offset,
3811 kHitTestChildBlockBackgrounds);
3812 }
3813
3814 // See if the mouse is inside us but not any of our descendants
3815 if (hit_test_filter != kHitTestDescendants && !inside)
3816 inside = NodeAtPoint(result, hit_test_location, accumulated_offset,
3817 kHitTestBlockBackground);
3818
3819 return inside;
3820 }
3821
NodeForHitTest() const3822 Node* LayoutObject::NodeForHitTest() const {
3823 NOT_DESTROYED();
3824 if (Node* node = GetNode())
3825 return node;
3826
3827 // If we hit the anonymous layoutObjects inside generated content we should
3828 // actually hit the generated content so walk up to the PseudoElement.
3829 if (const LayoutObject* parent = Parent()) {
3830 if (parent->IsBeforeOrAfterContent() || parent->IsMarkerContent() ||
3831 parent->StyleRef().StyleType() == kPseudoIdFirstLetter) {
3832 for (; parent; parent = parent->Parent()) {
3833 if (Node* node = parent->GetNode())
3834 return node;
3835 }
3836 }
3837 }
3838
3839 return nullptr;
3840 }
3841
UpdateHitTestResult(HitTestResult & result,const PhysicalOffset & point) const3842 void LayoutObject::UpdateHitTestResult(HitTestResult& result,
3843 const PhysicalOffset& point) const {
3844 NOT_DESTROYED();
3845 if (result.InnerNode())
3846 return;
3847
3848 if (Node* n = NodeForHitTest())
3849 result.SetNodeAndPosition(n, point);
3850 }
3851
NodeAtPoint(HitTestResult &,const HitTestLocation &,const PhysicalOffset &,HitTestAction)3852 bool LayoutObject::NodeAtPoint(HitTestResult&,
3853 const HitTestLocation&,
3854 const PhysicalOffset&,
3855 HitTestAction) {
3856 NOT_DESTROYED();
3857 return false;
3858 }
3859
ScheduleRelayout()3860 void LayoutObject::ScheduleRelayout() {
3861 NOT_DESTROYED();
3862 if (auto* layout_view = DynamicTo<LayoutView>(this)) {
3863 if (LocalFrameView* view = layout_view->GetFrameView())
3864 view->ScheduleRelayout();
3865 } else {
3866 if (IsRooted()) {
3867 layout_view = View();
3868 if (layout_view) {
3869 if (LocalFrameView* frame_view = layout_view->GetFrameView())
3870 frame_view->ScheduleRelayoutOfSubtree(this);
3871 }
3872 }
3873 }
3874 }
3875
ForceLayout()3876 void LayoutObject::ForceLayout() {
3877 NOT_DESTROYED();
3878 SetSelfNeedsLayoutForAvailableSpace(true);
3879 UpdateLayout();
3880 }
3881
FirstLineStyleWithoutFallback() const3882 const ComputedStyle* LayoutObject::FirstLineStyleWithoutFallback() const {
3883 NOT_DESTROYED();
3884 DCHECK(GetDocument().GetStyleEngine().UsesFirstLineRules());
3885
3886 // Normal markers don't use ::first-line styles in Chromium, so be consistent
3887 // and return null for content markers. This may need to change depending on
3888 // https://github.com/w3c/csswg-drafts/issues/4506
3889 if (IsMarkerContent())
3890 return nullptr;
3891 if (IsBeforeOrAfterContent() || IsText()) {
3892 if (!Parent())
3893 return nullptr;
3894 return Parent()->FirstLineStyleWithoutFallback();
3895 }
3896
3897 if (BehavesLikeBlockContainer()) {
3898 if (const ComputedStyle* cached =
3899 StyleRef().GetCachedPseudoElementStyle(kPseudoIdFirstLine))
3900 return cached;
3901
3902 if (const LayoutBlock* first_line_block =
3903 To<LayoutBlock>(this)->EnclosingFirstLineStyleBlock()) {
3904 if (first_line_block->Style() == Style()) {
3905 return first_line_block->GetCachedPseudoElementStyle(
3906 kPseudoIdFirstLine);
3907 }
3908
3909 // We can't use first_line_block->GetCachedPseudoElementStyle() because
3910 // it's based on first_line_block's style. We need to get the uncached
3911 // first line style based on this object's style and cache the result in
3912 // it.
3913 if (scoped_refptr<ComputedStyle> first_line_style =
3914 first_line_block->GetUncachedPseudoElementStyle(
3915 PseudoElementStyleRequest(kPseudoIdFirstLine), Style())) {
3916 return StyleRef().AddCachedPseudoElementStyle(
3917 std::move(first_line_style));
3918 }
3919 }
3920 } else if (!IsAnonymous() && IsLayoutInline() &&
3921 !GetNode()->IsFirstLetterPseudoElement()) {
3922 if (const ComputedStyle* cached =
3923 StyleRef().GetCachedPseudoElementStyle(kPseudoIdFirstLineInherited))
3924 return cached;
3925
3926 if (const ComputedStyle* parent_first_line_style =
3927 Parent()->FirstLineStyleWithoutFallback()) {
3928 // A first-line style is in effect. Get uncached first line style based on
3929 // parent_first_line_style and cache the result in this object's style.
3930 if (scoped_refptr<ComputedStyle> first_line_style =
3931 GetUncachedPseudoElementStyle(kPseudoIdFirstLineInherited,
3932 parent_first_line_style)) {
3933 return StyleRef().AddCachedPseudoElementStyle(
3934 std::move(first_line_style));
3935 }
3936 }
3937 }
3938 return nullptr;
3939 }
3940
GetCachedPseudoElementStyle(PseudoId pseudo) const3941 const ComputedStyle* LayoutObject::GetCachedPseudoElementStyle(
3942 PseudoId pseudo) const {
3943 NOT_DESTROYED();
3944 DCHECK_NE(pseudo, kPseudoIdBefore);
3945 DCHECK_NE(pseudo, kPseudoIdAfter);
3946 if (!GetNode())
3947 return nullptr;
3948
3949 Element* element = Traversal<Element>::FirstAncestorOrSelf(*GetNode());
3950 if (!element)
3951 return nullptr;
3952
3953 return element->CachedStyleForPseudoElement(
3954 PseudoElementStyleRequest(pseudo));
3955 }
3956
GetUncachedPseudoElementStyle(const PseudoElementStyleRequest & request,const ComputedStyle * parent_style) const3957 scoped_refptr<ComputedStyle> LayoutObject::GetUncachedPseudoElementStyle(
3958 const PseudoElementStyleRequest& request,
3959 const ComputedStyle* parent_style) const {
3960 NOT_DESTROYED();
3961 DCHECK_NE(request.pseudo_id, kPseudoIdBefore);
3962 DCHECK_NE(request.pseudo_id, kPseudoIdAfter);
3963 if (!GetNode())
3964 return nullptr;
3965
3966 Element* element = Traversal<Element>::FirstAncestorOrSelf(*GetNode());
3967 if (!element)
3968 return nullptr;
3969 if (element->IsPseudoElement())
3970 return nullptr;
3971
3972 return element->StyleForPseudoElement(request, parent_style);
3973 }
3974
AddAnnotatedRegions(Vector<AnnotatedRegionValue> & regions)3975 void LayoutObject::AddAnnotatedRegions(Vector<AnnotatedRegionValue>& regions) {
3976 NOT_DESTROYED();
3977 // Convert the style regions to absolute coordinates.
3978 if (StyleRef().Visibility() != EVisibility::kVisible || !IsBox())
3979 return;
3980
3981 if (StyleRef().DraggableRegionMode() == EDraggableRegionMode::kNone)
3982 return;
3983
3984 auto* box = To<LayoutBox>(this);
3985 PhysicalRect local_bounds = box->PhysicalBorderBoxRect();
3986 PhysicalRect abs_bounds = LocalToAbsoluteRect(local_bounds);
3987
3988 AnnotatedRegionValue region;
3989 region.draggable =
3990 StyleRef().DraggableRegionMode() == EDraggableRegionMode::kDrag;
3991 region.bounds = abs_bounds;
3992 regions.push_back(region);
3993 }
3994
WillRenderImage()3995 bool LayoutObject::WillRenderImage() {
3996 NOT_DESTROYED();
3997 // Without visibility we won't render (and therefore don't care about
3998 // animation).
3999 if (StyleRef().Visibility() != EVisibility::kVisible)
4000 return false;
4001
4002 // We will not render a new image when ExecutionContext is paused
4003 if (GetDocument().GetExecutionContext()->IsContextPaused())
4004 return false;
4005
4006 // Suspend animations when the page is not visible.
4007 if (GetDocument().hidden())
4008 return false;
4009
4010 // If we're not in a window (i.e., we're dormant from being in a background
4011 // tab) then we don't want to render either.
4012 return GetDocument().View()->IsVisible();
4013 }
4014
GetImageAnimationPolicy(mojom::blink::ImageAnimationPolicy & policy)4015 bool LayoutObject::GetImageAnimationPolicy(
4016 mojom::blink::ImageAnimationPolicy& policy) {
4017 NOT_DESTROYED();
4018 if (!GetDocument().GetSettings())
4019 return false;
4020 policy = GetDocument().GetSettings()->GetImageAnimationPolicy();
4021 return true;
4022 }
4023
IsInsideListMarker() const4024 bool LayoutObject::IsInsideListMarker() const {
4025 NOT_DESTROYED();
4026 return (IsListMarkerForNormalContent() &&
4027 To<LayoutListMarker>(this)->IsInside()) ||
4028 IsInsideListMarkerForCustomContent();
4029 }
4030
IsOutsideListMarker() const4031 bool LayoutObject::IsOutsideListMarker() const {
4032 NOT_DESTROYED();
4033 return (IsListMarkerForNormalContent() &&
4034 !To<LayoutListMarker>(this)->IsInside()) ||
4035 IsOutsideListMarkerForCustomContent();
4036 }
4037
CaretMinOffset() const4038 int LayoutObject::CaretMinOffset() const {
4039 NOT_DESTROYED();
4040 return 0;
4041 }
4042
CaretMaxOffset() const4043 int LayoutObject::CaretMaxOffset() const {
4044 NOT_DESTROYED();
4045 if (IsAtomicInlineLevel())
4046 return GetNode() ? std::max(1U, GetNode()->CountChildren()) : 1;
4047 if (IsHR())
4048 return 1;
4049 return 0;
4050 }
4051
IsInert() const4052 bool LayoutObject::IsInert() const {
4053 NOT_DESTROYED();
4054 const LayoutObject* layout_object = this;
4055 while (!layout_object->GetNode())
4056 layout_object = layout_object->Parent();
4057 return layout_object->GetNode()->IsInert();
4058 }
4059
ImageChanged(ImageResourceContent * image,CanDeferInvalidation defer)4060 void LayoutObject::ImageChanged(ImageResourceContent* image,
4061 CanDeferInvalidation defer) {
4062 NOT_DESTROYED();
4063 DCHECK(node_);
4064
4065 // Image change notifications should not be received during paint because
4066 // the resulting invalidations will be cleared following paint. This can also
4067 // lead to modifying the tree out from under paint(), see: crbug.com/616700.
4068 DCHECK_NE(GetDocument().Lifecycle().GetState(),
4069 DocumentLifecycle::LifecycleState::kInPaint);
4070
4071 ImageChanged(static_cast<WrappedImagePtr>(image), defer);
4072 }
4073
ImageNotifyFinished(ImageResourceContent * image)4074 void LayoutObject::ImageNotifyFinished(ImageResourceContent* image) {
4075 NOT_DESTROYED();
4076 if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
4077 cache->ImageLoaded(this);
4078
4079 if (LocalDOMWindow* window = GetDocument().domWindow())
4080 ImageElementTiming::From(*window).NotifyImageFinished(*this, image);
4081 if (LocalFrameView* frame_view = GetFrameView())
4082 frame_view->GetPaintTimingDetector().NotifyImageFinished(*this, image);
4083 }
4084
OffsetParent(const Element * base) const4085 Element* LayoutObject::OffsetParent(const Element* base) const {
4086 NOT_DESTROYED();
4087 if (IsDocumentElement() || IsBody())
4088 return nullptr;
4089
4090 if (IsFixedPositioned())
4091 return nullptr;
4092
4093 float effective_zoom = StyleRef().EffectiveZoom();
4094 Node* node = nullptr;
4095 for (LayoutObject* ancestor = Parent(); ancestor;
4096 ancestor = ancestor->Parent()) {
4097 // Spec: http://www.w3.org/TR/cssom-view/#offset-attributes
4098
4099 node = ancestor->GetNode();
4100
4101 if (!node)
4102 continue;
4103
4104 // TODO(kochi): If |base| or |node| is nested deep in shadow roots, this
4105 // loop may get expensive, as isUnclosedNodeOf() can take up to O(N+M) time
4106 // (N and M are depths).
4107 if (base && (node->IsClosedShadowHiddenFrom(*base) ||
4108 (node->IsInShadowTree() &&
4109 node->ContainingShadowRoot()->IsUserAgent()))) {
4110 // If 'position: fixed' node is found while traversing up, terminate the
4111 // loop and return null.
4112 if (ancestor->IsFixedPositioned())
4113 return nullptr;
4114 continue;
4115 }
4116
4117 if (ancestor->CanContainAbsolutePositionObjects())
4118 break;
4119
4120 if (IsA<HTMLBodyElement>(*node))
4121 break;
4122
4123 if (!IsPositioned() &&
4124 (IsA<HTMLTableElement>(*node) || IsA<HTMLTableCellElement>(*node)))
4125 break;
4126
4127 // Webkit specific extension where offsetParent stops at zoom level changes.
4128 if (effective_zoom != ancestor->StyleRef().EffectiveZoom())
4129 break;
4130 }
4131
4132 return DynamicTo<Element>(node);
4133 }
4134
NotifyImageFullyRemoved(ImageResourceContent * image)4135 void LayoutObject::NotifyImageFullyRemoved(ImageResourceContent* image) {
4136 NOT_DESTROYED();
4137 if (LocalDOMWindow* window = GetDocument().domWindow())
4138 ImageElementTiming::From(*window).NotifyImageRemoved(this, image);
4139 if (LocalFrameView* frame_view = GetFrameView())
4140 frame_view->GetPaintTimingDetector().NotifyImageRemoved(*this, image);
4141 }
4142
CreatePositionWithAffinity(int offset,TextAffinity affinity) const4143 PositionWithAffinity LayoutObject::CreatePositionWithAffinity(
4144 int offset,
4145 TextAffinity affinity) const {
4146 NOT_DESTROYED();
4147 // If this is a non-anonymous layoutObject in an editable area, then it's
4148 // simple.
4149 if (Node* node = NonPseudoNode()) {
4150 if (!HasEditableStyle(*node)) {
4151 // If it can be found, we prefer a visually equivalent position that is
4152 // editable.
4153 // TODO(layout-dev): Once we fix callers of |CreatePositionWithAffinity()|
4154 // we should use |Position| constructor. See http://crbug.com/827923
4155 const Position position =
4156 Position::CreateWithoutValidationDeprecated(*node, offset);
4157 Position candidate =
4158 MostForwardCaretPosition(position, kCanCrossEditingBoundary);
4159 if (HasEditableStyle(*candidate.AnchorNode()))
4160 return PositionWithAffinity(candidate, affinity);
4161 candidate = MostBackwardCaretPosition(position, kCanCrossEditingBoundary);
4162 if (HasEditableStyle(*candidate.AnchorNode()))
4163 return PositionWithAffinity(candidate, affinity);
4164 }
4165 // FIXME: Eliminate legacy editing positions
4166 return PositionWithAffinity(Position::EditingPositionOf(node, offset),
4167 affinity);
4168 }
4169
4170 // We don't want to cross the boundary between editable and non-editable
4171 // regions of the document, but that is either impossible or at least
4172 // extremely unlikely in any normal case because we stop as soon as we
4173 // find a single non-anonymous layoutObject.
4174
4175 // Find a nearby non-anonymous layoutObject.
4176 const LayoutObject* child = this;
4177 while (const LayoutObject* parent = child->Parent()) {
4178 // Find non-anonymous content after.
4179 for (const LayoutObject* layout_object = child->NextInPreOrder(parent);
4180 layout_object; layout_object = layout_object->NextInPreOrder(parent)) {
4181 if (const Node* node = layout_object->NonPseudoNode()) {
4182 return PositionWithAffinity(FirstPositionInOrBeforeNode(*node));
4183 }
4184 }
4185
4186 // Find non-anonymous content before.
4187 for (const LayoutObject* layout_object = child->PreviousInPreOrder();
4188 layout_object; layout_object = layout_object->PreviousInPreOrder()) {
4189 if (layout_object == parent)
4190 break;
4191 if (const Node* node = layout_object->NonPseudoNode())
4192 return PositionWithAffinity(LastPositionInOrAfterNode(*node));
4193 }
4194
4195 // Use the parent itself unless it too is anonymous.
4196 if (const Node* node = parent->NonPseudoNode())
4197 return PositionWithAffinity(FirstPositionInOrBeforeNode(*node));
4198
4199 // Repeat at the next level up.
4200 child = parent;
4201 }
4202
4203 // Everything was anonymous. Give up.
4204 return PositionWithAffinity();
4205 }
4206
CreatePositionWithAffinity(int offset) const4207 PositionWithAffinity LayoutObject::CreatePositionWithAffinity(
4208 int offset) const {
4209 NOT_DESTROYED();
4210 return CreatePositionWithAffinity(offset, TextAffinity::kDownstream);
4211 }
4212
CreatePositionWithAffinity(const Position & position) const4213 PositionWithAffinity LayoutObject::CreatePositionWithAffinity(
4214 const Position& position) const {
4215 NOT_DESTROYED();
4216 if (position.IsNotNull())
4217 return PositionWithAffinity(position);
4218
4219 DCHECK(!NonPseudoNode());
4220 return CreatePositionWithAffinity(0);
4221 }
4222
GetCursor(const PhysicalOffset &,ui::Cursor &) const4223 CursorDirective LayoutObject::GetCursor(const PhysicalOffset&,
4224 ui::Cursor&) const {
4225 NOT_DESTROYED();
4226 return kSetCursorBasedOnStyle;
4227 }
4228
CanUpdateSelectionOnRootLineBoxes() const4229 bool LayoutObject::CanUpdateSelectionOnRootLineBoxes() const {
4230 NOT_DESTROYED();
4231 if (NeedsLayout())
4232 return false;
4233
4234 const LayoutBlock* containing_block = ContainingBlock();
4235 return containing_block ? !containing_block->NeedsLayout() : false;
4236 }
4237
SetNeedsBoundariesUpdate()4238 void LayoutObject::SetNeedsBoundariesUpdate() {
4239 NOT_DESTROYED();
4240 if (IsSVGChild()) {
4241 // The boundaries affect mask clip.
4242 auto* resources = SVGResourcesCache::CachedResourcesForLayoutObject(*this);
4243 if (resources && resources->Masker())
4244 SetNeedsPaintPropertyUpdate();
4245 if (resources && resources->Clipper())
4246 InvalidateClipPathCache();
4247 }
4248 if (LayoutObject* layout_object = Parent())
4249 layout_object->SetNeedsBoundariesUpdate();
4250 }
4251
ObjectBoundingBox() const4252 FloatRect LayoutObject::ObjectBoundingBox() const {
4253 NOT_DESTROYED();
4254 NOTREACHED();
4255 return FloatRect();
4256 }
4257
StrokeBoundingBox() const4258 FloatRect LayoutObject::StrokeBoundingBox() const {
4259 NOT_DESTROYED();
4260 NOTREACHED();
4261 return FloatRect();
4262 }
4263
VisualRectInLocalSVGCoordinates() const4264 FloatRect LayoutObject::VisualRectInLocalSVGCoordinates() const {
4265 NOT_DESTROYED();
4266 NOTREACHED();
4267 return FloatRect();
4268 }
4269
LocalSVGTransform() const4270 AffineTransform LayoutObject::LocalSVGTransform() const {
4271 NOT_DESTROYED();
4272 return AffineTransform();
4273 }
4274
IsRelayoutBoundary() const4275 bool LayoutObject::IsRelayoutBoundary() const {
4276 NOT_DESTROYED();
4277 return ObjectIsRelayoutBoundary(this);
4278 }
4279
SetShouldCheckGeometryForPaintInvalidation()4280 inline void LayoutObject::SetShouldCheckGeometryForPaintInvalidation() {
4281 NOT_DESTROYED();
4282 DCHECK(ShouldCheckForPaintInvalidation());
4283 bitfields_.SetShouldCheckGeometryForPaintInvalidation(true);
4284 for (auto* ancestor = ParentCrossingFrames();
4285 ancestor &&
4286 !ancestor->DescendantShouldCheckGeometryForPaintInvalidation();
4287 ancestor = ancestor->ParentCrossingFrames()) {
4288 ancestor->bitfields_.SetDescendantShouldCheckGeometryForPaintInvalidation(
4289 true);
4290 }
4291 }
4292
SetShouldInvalidateSelection()4293 void LayoutObject::SetShouldInvalidateSelection() {
4294 NOT_DESTROYED();
4295 bitfields_.SetShouldInvalidateSelection(true);
4296 SetShouldCheckForPaintInvalidation();
4297 }
4298
SetShouldDoFullPaintInvalidation(PaintInvalidationReason reason)4299 void LayoutObject::SetShouldDoFullPaintInvalidation(
4300 PaintInvalidationReason reason) {
4301 NOT_DESTROYED();
4302 SetShouldDoFullPaintInvalidationWithoutGeometryChange(reason);
4303 SetShouldCheckGeometryForPaintInvalidation();
4304 }
4305
DocumentLifecycleBasedPaintInvalidationReason(const DocumentLifecycle & document_lifecycle)4306 static PaintInvalidationReason DocumentLifecycleBasedPaintInvalidationReason(
4307 const DocumentLifecycle& document_lifecycle) {
4308 switch (document_lifecycle.GetState()) {
4309 case DocumentLifecycle::kInStyleRecalc:
4310 return PaintInvalidationReason::kStyle;
4311 case DocumentLifecycle::kInPreLayout:
4312 case DocumentLifecycle::kInPerformLayout:
4313 case DocumentLifecycle::kAfterPerformLayout:
4314 return PaintInvalidationReason::kGeometry;
4315 case DocumentLifecycle::kInCompositingAssignmentsUpdate:
4316 DCHECK(false);
4317 return PaintInvalidationReason::kFull;
4318 default:
4319 return PaintInvalidationReason::kFull;
4320 }
4321 }
4322
4323 void LayoutObject::
SetShouldDoFullPaintInvalidationWithoutGeometryChangeInternal(PaintInvalidationReason reason)4324 SetShouldDoFullPaintInvalidationWithoutGeometryChangeInternal(
4325 PaintInvalidationReason reason) {
4326 NOT_DESTROYED();
4327 // Only full invalidation reasons are allowed.
4328 DCHECK(IsFullPaintInvalidationReason(reason));
4329 if (ShouldDoFullPaintInvalidation())
4330 return;
4331
4332 SetShouldCheckForPaintInvalidationWithoutGeometryChange();
4333 if (reason == PaintInvalidationReason::kFull) {
4334 reason = DocumentLifecycleBasedPaintInvalidationReason(
4335 GetDocument().Lifecycle());
4336 }
4337 full_paint_invalidation_reason_ = reason;
4338 bitfields_.SetShouldDelayFullPaintInvalidation(false);
4339 }
4340
SetShouldCheckForPaintInvalidation()4341 void LayoutObject::SetShouldCheckForPaintInvalidation() {
4342 NOT_DESTROYED();
4343 SetShouldCheckForPaintInvalidationWithoutGeometryChange();
4344 SetShouldCheckGeometryForPaintInvalidation();
4345 }
4346
SetShouldCheckForPaintInvalidationWithoutGeometryChange()4347 void LayoutObject::SetShouldCheckForPaintInvalidationWithoutGeometryChange() {
4348 NOT_DESTROYED();
4349 if (ShouldCheckForPaintInvalidation())
4350 return;
4351 GetFrameView()->ScheduleVisualUpdateForPaintInvalidationIfNeeded();
4352
4353 bitfields_.SetShouldCheckForPaintInvalidation(true);
4354 for (LayoutObject* parent = ParentCrossingFrames();
4355 parent && !parent->ShouldCheckForPaintInvalidation();
4356 parent = parent->ParentCrossingFrames()) {
4357 parent->bitfields_.SetShouldCheckForPaintInvalidation(true);
4358 }
4359 }
4360
SetSubtreeShouldCheckForPaintInvalidation()4361 void LayoutObject::SetSubtreeShouldCheckForPaintInvalidation() {
4362 NOT_DESTROYED();
4363 if (SubtreeShouldCheckForPaintInvalidation()) {
4364 DCHECK(ShouldCheckForPaintInvalidation());
4365 return;
4366 }
4367 SetShouldCheckForPaintInvalidation();
4368 bitfields_.SetSubtreeShouldCheckForPaintInvalidation(true);
4369 }
4370
SetMayNeedPaintInvalidationAnimatedBackgroundImage()4371 void LayoutObject::SetMayNeedPaintInvalidationAnimatedBackgroundImage() {
4372 NOT_DESTROYED();
4373 if (MayNeedPaintInvalidationAnimatedBackgroundImage())
4374 return;
4375 bitfields_.SetMayNeedPaintInvalidationAnimatedBackgroundImage(true);
4376 SetShouldCheckForPaintInvalidationWithoutGeometryChange();
4377 }
4378
SetShouldDelayFullPaintInvalidation()4379 void LayoutObject::SetShouldDelayFullPaintInvalidation() {
4380 NOT_DESTROYED();
4381 // Should have already set a full paint invalidation reason.
4382 DCHECK(IsFullPaintInvalidationReason(full_paint_invalidation_reason_));
4383
4384 bitfields_.SetShouldDelayFullPaintInvalidation(true);
4385 if (!ShouldCheckForPaintInvalidation()) {
4386 // This will also schedule a visual update.
4387 SetShouldCheckForPaintInvalidationWithoutGeometryChange();
4388 } else {
4389 // Schedule visual update for the next document cycle in which we will
4390 // check if the delayed invalidation should be promoted to a real
4391 // invalidation.
4392 GetFrameView()->ScheduleVisualUpdateForPaintInvalidationIfNeeded();
4393 }
4394 }
4395
ClearShouldDelayFullPaintInvalidation()4396 void LayoutObject::ClearShouldDelayFullPaintInvalidation() {
4397 // This will clear ShouldDelayFullPaintInvalidation() flag and enable previous
4398 // BackgroundNeedsFullPaintInvalidaiton() if it's set.
4399 SetShouldDoFullPaintInvalidationWithoutGeometryChangeInternal(
4400 FullPaintInvalidationReason());
4401 }
4402
ClearPaintInvalidationFlags()4403 void LayoutObject::ClearPaintInvalidationFlags() {
4404 NOT_DESTROYED();
4405 // PaintInvalidationStateIsDirty should be kept in sync with the
4406 // booleans that are cleared below.
4407 #if DCHECK_IS_ON()
4408 DCHECK(!ShouldCheckForPaintInvalidation() || PaintInvalidationStateIsDirty());
4409 #endif
4410 fragment_.SetPartialInvalidationLocalRect(PhysicalRect());
4411 if (!ShouldDelayFullPaintInvalidation()) {
4412 full_paint_invalidation_reason_ = PaintInvalidationReason::kNone;
4413 bitfields_.SetBackgroundNeedsFullPaintInvalidation(false);
4414 }
4415 bitfields_.SetShouldCheckForPaintInvalidation(false);
4416 bitfields_.SetSubtreeShouldCheckForPaintInvalidation(false);
4417 bitfields_.SetSubtreeShouldDoFullPaintInvalidation(false);
4418 bitfields_.SetMayNeedPaintInvalidationAnimatedBackgroundImage(false);
4419 bitfields_.SetShouldCheckGeometryForPaintInvalidation(false);
4420 bitfields_.SetDescendantShouldCheckGeometryForPaintInvalidation(false);
4421 bitfields_.SetShouldInvalidateSelection(false);
4422 }
4423
4424 #if DCHECK_IS_ON()
PaintInvalidationStateIsDirty() const4425 bool LayoutObject::PaintInvalidationStateIsDirty() const {
4426 NOT_DESTROYED();
4427 return BackgroundNeedsFullPaintInvalidation() ||
4428 ShouldCheckForPaintInvalidation() || ShouldInvalidateSelection() ||
4429 ShouldCheckGeometryForPaintInvalidation() ||
4430 DescendantShouldCheckGeometryForPaintInvalidation() ||
4431 ShouldDoFullPaintInvalidation() ||
4432 SubtreeShouldDoFullPaintInvalidation() ||
4433 MayNeedPaintInvalidationAnimatedBackgroundImage() ||
4434 !fragment_.PartialInvalidationLocalRect().IsEmpty();
4435 }
4436 #endif
4437
EnsureIsReadyForPaintInvalidation()4438 void LayoutObject::EnsureIsReadyForPaintInvalidation() {
4439 NOT_DESTROYED();
4440 DCHECK(!NeedsLayout() || ChildLayoutBlockedByDisplayLock());
4441
4442 // Force full paint invalidation if the outline may be affected by descendants
4443 // and this object is marked for checking paint invalidation for any reason.
4444 if (bitfields_.OutlineMayBeAffectedByDescendants() ||
4445 bitfields_.PreviousOutlineMayBeAffectedByDescendants()) {
4446 SetShouldDoFullPaintInvalidationWithoutGeometryChange(
4447 PaintInvalidationReason::kOutline);
4448 }
4449 bitfields_.SetPreviousOutlineMayBeAffectedByDescendants(
4450 bitfields_.OutlineMayBeAffectedByDescendants());
4451 }
4452
ClearPaintFlags()4453 void LayoutObject::ClearPaintFlags() {
4454 NOT_DESTROYED();
4455 DCHECK_EQ(GetDocument().Lifecycle().GetState(),
4456 DocumentLifecycle::kInPrePaint);
4457 ClearPaintInvalidationFlags();
4458 bitfields_.SetNeedsPaintPropertyUpdate(false);
4459 bitfields_.SetEffectiveAllowedTouchActionChanged(false);
4460 bitfields_.SetBlockingWheelEventHandlerChanged(false);
4461
4462 if (!ChildPrePaintBlockedByDisplayLock()) {
4463 bitfields_.SetDescendantNeedsPaintPropertyUpdate(false);
4464 bitfields_.SetDescendantEffectiveAllowedTouchActionChanged(false);
4465 bitfields_.SetDescendantBlockingWheelEventHandlerChanged(false);
4466 bitfields_.ResetSubtreePaintPropertyUpdateReasons();
4467 }
4468 }
4469
IsAllowedToModifyLayoutTreeStructure(Document & document)4470 bool LayoutObject::IsAllowedToModifyLayoutTreeStructure(Document& document) {
4471 return document.Lifecycle().StateAllowsLayoutTreeMutations();
4472 }
4473
SetSubtreeShouldDoFullPaintInvalidation(PaintInvalidationReason reason)4474 void LayoutObject::SetSubtreeShouldDoFullPaintInvalidation(
4475 PaintInvalidationReason reason) {
4476 NOT_DESTROYED();
4477 SetShouldDoFullPaintInvalidation(reason);
4478 bitfields_.SetSubtreeShouldDoFullPaintInvalidation(true);
4479 }
4480
SetIsBackgroundAttachmentFixedObject(bool is_background_attachment_fixed_object)4481 void LayoutObject::SetIsBackgroundAttachmentFixedObject(
4482 bool is_background_attachment_fixed_object) {
4483 NOT_DESTROYED();
4484 DCHECK(GetFrameView());
4485 if (bitfields_.IsBackgroundAttachmentFixedObject() ==
4486 is_background_attachment_fixed_object)
4487 return;
4488 bitfields_.SetIsBackgroundAttachmentFixedObject(
4489 is_background_attachment_fixed_object);
4490 if (is_background_attachment_fixed_object)
4491 GetFrameView()->AddBackgroundAttachmentFixedObject(this);
4492 else
4493 GetFrameView()->RemoveBackgroundAttachmentFixedObject(this);
4494 }
4495
DebugRect() const4496 PhysicalRect LayoutObject::DebugRect() const {
4497 NOT_DESTROYED();
4498 return PhysicalRect();
4499 }
4500
InvalidateSelectedChildrenOnStyleChange()4501 void LayoutObject::InvalidateSelectedChildrenOnStyleChange() {
4502 NOT_DESTROYED();
4503 // LayoutSelection::Commit() propagates the state up the containing node
4504 // chain to
4505 // tell if a block contains selected nodes or not. If this layout object is
4506 // not a block, we need to get the selection state from the containing block
4507 // to tell if we have any selected node children.
4508 LayoutBlock* block =
4509 IsLayoutBlock() ? To<LayoutBlock>(this) : ContainingBlock();
4510 if (!block)
4511 return;
4512 if (!block->IsSelected())
4513 return;
4514
4515 // ::selection style only applies to direct selection leaf children of the
4516 // element on which the ::selection style is set. Thus, we only walk the
4517 // direct children here.
4518 for (LayoutObject* child = SlowFirstChild(); child;
4519 child = child->NextSibling()) {
4520 if (!child->CanBeSelectionLeaf())
4521 continue;
4522 if (!child->IsSelected())
4523 continue;
4524 child->SetShouldInvalidateSelection();
4525 }
4526 }
4527
MarkEffectiveAllowedTouchActionChanged()4528 void LayoutObject::MarkEffectiveAllowedTouchActionChanged() {
4529 NOT_DESTROYED();
4530 bitfields_.SetEffectiveAllowedTouchActionChanged(true);
4531 // If we're locked, mark our descendants as needing this change. This is used
4532 // a signal to ensure we mark the element as needing effective allowed
4533 // touch action recalculation when the element becomes unlocked.
4534 if (ChildPrePaintBlockedByDisplayLock()) {
4535 bitfields_.SetDescendantEffectiveAllowedTouchActionChanged(true);
4536 return;
4537 }
4538
4539 LayoutObject* obj = ParentCrossingFrames();
4540 while (obj && !obj->DescendantEffectiveAllowedTouchActionChanged()) {
4541 obj->bitfields_.SetDescendantEffectiveAllowedTouchActionChanged(true);
4542 if (obj->ChildPrePaintBlockedByDisplayLock())
4543 break;
4544
4545 obj = obj->ParentCrossingFrames();
4546 }
4547 }
4548
MarkBlockingWheelEventHandlerChanged()4549 void LayoutObject::MarkBlockingWheelEventHandlerChanged() {
4550 DCHECK(base::FeatureList::IsEnabled(::features::kWheelEventRegions));
4551 bitfields_.SetBlockingWheelEventHandlerChanged(true);
4552 // If we're locked, mark our descendants as needing this change. This is used
4553 // as a signal to ensure we mark the element as needing wheel event handler
4554 // recalculation when the element becomes unlocked.
4555 if (ChildPrePaintBlockedByDisplayLock()) {
4556 bitfields_.SetDescendantBlockingWheelEventHandlerChanged(true);
4557 return;
4558 }
4559
4560 LayoutObject* obj = ParentCrossingFrames();
4561 while (obj && !obj->DescendantBlockingWheelEventHandlerChanged()) {
4562 obj->bitfields_.SetDescendantBlockingWheelEventHandlerChanged(true);
4563 if (obj->ChildPrePaintBlockedByDisplayLock())
4564 break;
4565
4566 obj = obj->ParentCrossingFrames();
4567 }
4568 }
4569
4570 // Note about ::first-letter pseudo-element:
4571 // When an element has ::first-letter pseudo-element, first letter characters
4572 // are taken from |Text| node and first letter characters are considered
4573 // as content of <pseudo:first-letter>.
4574 // For following HTML,
4575 // <style>div::first-letter {color: red}</style>
4576 // <div>abc</div>
4577 // we have following layout tree:
4578 // LayoutBlockFlow {DIV} at (0,0) size 784x55
4579 // LayoutInline {<pseudo:first-letter>} at (0,0) size 22x53
4580 // LayoutTextFragment (anonymous) at (0,1) size 22x53
4581 // text run at (0,1) width 22: "a"
4582 // LayoutTextFragment {#text} at (21,30) size 16x17
4583 // text run at (21,30) width 16: "bc"
4584 // In this case, |Text::layoutObject()| for "abc" returns |LayoutTextFragment|
4585 // containing "bc", and it is called remaining part.
4586 //
4587 // Even if |Text| node contains only first-letter characters, e.g. just "a",
4588 // remaining part of |LayoutTextFragment|, with |fragmentLength()| == 0, is
4589 // appeared in layout tree.
4590 //
4591 // When |Text| node contains only first-letter characters and whitespaces, e.g.
4592 // "B\n", associated |LayoutTextFragment| is first-letter part instead of
4593 // remaining part.
4594 //
4595 // Punctuation characters are considered as first-letter. For "(1)ab",
4596 // "(1)" are first-letter part and "ab" are remaining part.
AssociatedLayoutObjectOf(const Node & node,int offset_in_node,LayoutObjectSide object_side)4597 const LayoutObject* AssociatedLayoutObjectOf(const Node& node,
4598 int offset_in_node,
4599 LayoutObjectSide object_side) {
4600 DCHECK_GE(offset_in_node, 0);
4601 LayoutObject* layout_object = node.GetLayoutObject();
4602 if (!node.IsTextNode() || !layout_object ||
4603 !To<LayoutText>(layout_object)->IsTextFragment())
4604 return layout_object;
4605 auto* layout_text_fragment = To<LayoutTextFragment>(layout_object);
4606 if (!layout_text_fragment->IsRemainingTextLayoutObject()) {
4607 DCHECK_LE(
4608 static_cast<unsigned>(offset_in_node),
4609 layout_text_fragment->Start() + layout_text_fragment->FragmentLength());
4610 return layout_text_fragment;
4611 }
4612 if (layout_text_fragment->FragmentLength()) {
4613 const unsigned threshold =
4614 object_side == LayoutObjectSide::kRemainingTextIfOnBoundary
4615 ? layout_text_fragment->Start()
4616 : layout_text_fragment->Start() + 1;
4617 if (static_cast<unsigned>(offset_in_node) >= threshold)
4618 return layout_object;
4619 }
4620 return layout_text_fragment->GetFirstLetterPart();
4621 }
4622
CanBeSelectionLeaf() const4623 bool LayoutObject::CanBeSelectionLeaf() const {
4624 NOT_DESTROYED();
4625 if (SlowFirstChild() || StyleRef().Visibility() != EVisibility::kVisible ||
4626 DisplayLockUtilities::NearestLockedExclusiveAncestor(*this)) {
4627 return false;
4628 }
4629 return CanBeSelectionLeafInternal();
4630 }
4631
InvalidateClipPathCache()4632 void LayoutObject::InvalidateClipPathCache() {
4633 NOT_DESTROYED();
4634 SetNeedsPaintPropertyUpdate();
4635 for (auto* fragment = &fragment_; fragment;
4636 fragment = fragment->NextFragment())
4637 fragment->InvalidateClipPathCache();
4638 }
4639
OutlineRects(const PhysicalOffset & additional_offset,NGOutlineType outline_type) const4640 Vector<PhysicalRect> LayoutObject::OutlineRects(
4641 const PhysicalOffset& additional_offset,
4642 NGOutlineType outline_type) const {
4643 NOT_DESTROYED();
4644 Vector<PhysicalRect> outline_rects;
4645 AddOutlineRects(outline_rects, additional_offset, outline_type);
4646 return outline_rects;
4647 }
4648
SetModifiedStyleOutsideStyleRecalc(scoped_refptr<const ComputedStyle> style,ApplyStyleChanges apply_changes)4649 void LayoutObject::SetModifiedStyleOutsideStyleRecalc(
4650 scoped_refptr<const ComputedStyle> style,
4651 ApplyStyleChanges apply_changes) {
4652 NOT_DESTROYED();
4653 SetStyle(style, apply_changes);
4654 if (IsAnonymous() || !GetNode() || !GetNode()->IsElementNode())
4655 return;
4656 GetNode()->SetComputedStyle(std::move(style));
4657 }
4658
FlipForWritingModeInternal(LayoutUnit position,LayoutUnit width,const LayoutBox * box_for_flipping) const4659 LayoutUnit LayoutObject::FlipForWritingModeInternal(
4660 LayoutUnit position,
4661 LayoutUnit width,
4662 const LayoutBox* box_for_flipping) const {
4663 NOT_DESTROYED();
4664 DCHECK(!IsBox());
4665 DCHECK(HasFlippedBlocksWritingMode());
4666 DCHECK(!box_for_flipping || box_for_flipping == ContainingBlock());
4667 // For now, block flipping doesn't apply for non-box SVG objects.
4668 if (IsSVG())
4669 return position;
4670 return (box_for_flipping ? box_for_flipping : ContainingBlock())
4671 ->FlipForWritingMode(position, width);
4672 }
4673
SelfPaintingLayerNeedsVisualOverflowRecalc() const4674 bool LayoutObject::SelfPaintingLayerNeedsVisualOverflowRecalc() const {
4675 NOT_DESTROYED();
4676 if (HasLayer()) {
4677 auto* box_model_object = To<LayoutBoxModelObject>(this);
4678 if (box_model_object->HasSelfPaintingLayer())
4679 return box_model_object->Layer()->NeedsVisualOverflowRecalc();
4680 }
4681 return false;
4682 }
4683
MarkSelfPaintingLayerForVisualOverflowRecalc()4684 void LayoutObject::MarkSelfPaintingLayerForVisualOverflowRecalc() {
4685 NOT_DESTROYED();
4686 if (HasLayer()) {
4687 auto* box_model_object = To<LayoutBoxModelObject>(this);
4688 if (box_model_object->HasSelfPaintingLayer())
4689 box_model_object->Layer()->SetNeedsVisualOverflowRecalc();
4690 }
4691 }
4692
IsMenuList(const LayoutObject * object)4693 bool IsMenuList(const LayoutObject* object) {
4694 if (!object)
4695 return false;
4696 auto* select = DynamicTo<HTMLSelectElement>(object->GetNode());
4697 return select && select->UsesMenuList();
4698 }
4699
IsListBox(const LayoutObject * object)4700 bool IsListBox(const LayoutObject* object) {
4701 if (!object)
4702 return false;
4703 auto* select = DynamicTo<HTMLSelectElement>(object->GetNode());
4704 return select && !select->UsesMenuList();
4705 }
4706
4707 } // namespace blink
4708
4709 #if DCHECK_IS_ON()
4710
showTree(const blink::LayoutObject * object)4711 void showTree(const blink::LayoutObject* object) {
4712 if (object)
4713 object->ShowTreeForThis();
4714 else
4715 DLOG(INFO) << "Cannot showTree. Root is (nil)";
4716 }
4717
showLineTree(const blink::LayoutObject * object)4718 void showLineTree(const blink::LayoutObject* object) {
4719 if (object)
4720 object->ShowLineTreeForThis();
4721 else
4722 DLOG(INFO) << "Cannot showLineTree. Root is (nil)";
4723 }
4724
showLayoutTree(const blink::LayoutObject * object1)4725 void showLayoutTree(const blink::LayoutObject* object1) {
4726 showLayoutTree(object1, nullptr);
4727 }
4728
showLayoutTree(const blink::LayoutObject * object1,const blink::LayoutObject * object2)4729 void showLayoutTree(const blink::LayoutObject* object1,
4730 const blink::LayoutObject* object2) {
4731 if (object1) {
4732 const blink::LayoutObject* root = object1;
4733 while (root->Parent())
4734 root = root->Parent();
4735 if (object1) {
4736 StringBuilder string_builder;
4737 root->DumpLayoutTreeAndMark(string_builder, object1, "*", object2, "-",
4738 0);
4739 DLOG(INFO) << "\n" << string_builder.ToString().Utf8();
4740 }
4741 } else {
4742 DLOG(INFO) << "Cannot showLayoutTree. Root is (nil)";
4743 }
4744 }
4745
4746 #endif // DCHECK_IS_ON()
4747