1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
5  *           (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
6  * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
7  * Copyright (C) 2010 Google Inc. All rights reserved.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  *
24  */
25 
26 #include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
27 
28 #include "cc/input/main_thread_scrolling_reason.h"
29 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
30 #include "third_party/blink/renderer/core/frame/local_frame.h"
31 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
32 #include "third_party/blink/renderer/core/frame/settings.h"
33 #include "third_party/blink/renderer/core/html/html_body_element.h"
34 #include "third_party/blink/renderer/core/layout/geometry/transform_state.h"
35 #include "third_party/blink/renderer/core/layout/layout_block.h"
36 #include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
37 #include "third_party/blink/renderer/core/layout/layout_geometry_map.h"
38 #include "third_party/blink/renderer/core/layout/layout_inline.h"
39 #include "third_party/blink/renderer/core/layout/layout_view.h"
40 #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
41 #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
42 #include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
43 #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
44 #include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
45 #include "third_party/blink/renderer/core/paint/paint_layer.h"
46 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
47 #include "third_party/blink/renderer/core/style/shadow_list.h"
48 #include "third_party/blink/renderer/platform/geometry/length_functions.h"
49 
50 namespace blink {
51 
52 namespace {
IsOutOfFlowPositionedWithImplicitHeight(const LayoutBoxModelObject * child)53 inline bool IsOutOfFlowPositionedWithImplicitHeight(
54     const LayoutBoxModelObject* child) {
55   return child->IsOutOfFlowPositioned() &&
56          !child->StyleRef().LogicalTop().IsAuto() &&
57          !child->StyleRef().LogicalBottom().IsAuto();
58 }
59 
60 // Inclusive of |from|, exclusive of |to|.
FindFirstStickyBetween(LayoutObject * from,LayoutObject * to)61 PaintLayer* FindFirstStickyBetween(LayoutObject* from, LayoutObject* to) {
62   LayoutObject* maybe_sticky_ancestor = from;
63   while (maybe_sticky_ancestor && maybe_sticky_ancestor != to) {
64     if (maybe_sticky_ancestor->StyleRef().HasStickyConstrainedPosition()) {
65       return ToLayoutBoxModelObject(maybe_sticky_ancestor)->Layer();
66     }
67 
68     maybe_sticky_ancestor =
69         maybe_sticky_ancestor->IsLayoutInline()
70             ? maybe_sticky_ancestor->Container()
71             : ToLayoutBox(maybe_sticky_ancestor)->LocationContainer();
72   }
73   return nullptr;
74 }
75 }  // namespace
76 
77 // The HashMap for storing continuation pointers.
78 // The continuation chain is a singly linked list. As such, the HashMap's value
79 // is the next pointer associated with the key.
80 typedef HashMap<const LayoutBoxModelObject*, LayoutBoxModelObject*>
81     ContinuationMap;
82 static ContinuationMap* g_continuation_map = nullptr;
83 
ContentChanged(ContentChangeType change_type)84 void LayoutBoxModelObject::ContentChanged(ContentChangeType change_type) {
85   if (!HasLayer())
86     return;
87 
88   Layer()->ContentChanged(change_type);
89 }
90 
LayoutBoxModelObject(ContainerNode * node)91 LayoutBoxModelObject::LayoutBoxModelObject(ContainerNode* node)
92     : LayoutObject(node) {}
93 
UsesCompositedScrolling() const94 bool LayoutBoxModelObject::UsesCompositedScrolling() const {
95   return HasOverflowClip() && HasLayer() &&
96          Layer()->GetScrollableArea()->UsesCompositedScrolling();
97 }
98 
99 BackgroundPaintLocation
ComputeBackgroundPaintLocationIfComposited(uint32_t * main_thread_scrolling_reasons) const100 LayoutBoxModelObject::ComputeBackgroundPaintLocationIfComposited(
101     uint32_t* main_thread_scrolling_reasons) const {
102   bool may_have_scrolling_layers_without_scrolling = IsA<LayoutView>(this);
103   const auto* scrollable_area = GetScrollableArea();
104   bool scrolls_overflow = scrollable_area && scrollable_area->ScrollsOverflow();
105   if (!scrolls_overflow && !may_have_scrolling_layers_without_scrolling)
106     return kBackgroundPaintInGraphicsLayer;
107 
108   // If we care about LCD text, paint root backgrounds into scrolling contents
109   // layer even if style suggests otherwise. (For non-root scrollers, we just
110   // avoid compositing - see PLSA::ComputeNeedsCompositedScrolling.)
111   if (IsA<LayoutView>(this)) {
112     if (!GetDocument().GetSettings()->GetPreferCompositingToLCDTextEnabled())
113       return kBackgroundPaintInScrollingContents;
114   }
115 
116   // TODO(flackr): Detect opaque custom scrollbars which would cover up a
117   // border-box background.
118   bool has_custom_scrollbars =
119       scrollable_area &&
120       ((scrollable_area->HorizontalScrollbar() &&
121         scrollable_area->HorizontalScrollbar()->IsCustomScrollbar()) ||
122        (scrollable_area->VerticalScrollbar() &&
123         scrollable_area->VerticalScrollbar()->IsCustomScrollbar()));
124 
125   // TODO(flackr): When we correctly clip the scrolling contents layer we can
126   // paint locally equivalent backgrounds into it. https://crbug.com/645957
127   if (HasClip())
128     return kBackgroundPaintInGraphicsLayer;
129 
130   // TODO(flackr): Remove this when box shadows are still painted correctly when
131   // painting into the composited scrolling contents layer.
132   // https://crbug.com/646464
133   if (StyleRef().BoxShadow()) {
134     if (main_thread_scrolling_reasons) {
135       *main_thread_scrolling_reasons |=
136           cc::MainThreadScrollingReason::kHasBoxShadowFromNonRootLayer;
137     }
138     return kBackgroundPaintInGraphicsLayer;
139   }
140 
141   // Assume optimistically that the background can be painted in the scrolling
142   // contents until we find otherwise.
143   BackgroundPaintLocation paint_location = kBackgroundPaintInScrollingContents;
144   const FillLayer* layer = &(StyleRef().BackgroundLayers());
145   for (; layer; layer = layer->Next()) {
146     if (layer->Attachment() == EFillAttachment::kLocal)
147       continue;
148 
149     // Solid color layers with an effective background clip of the padding box
150     // can be treated as local.
151     if (!layer->GetImage() && !layer->Next() &&
152         ResolveColor(GetCSSPropertyBackgroundColor()).Alpha() > 0) {
153       EFillBox clip = layer->Clip();
154       if (clip == EFillBox::kPadding)
155         continue;
156       // A border box can be treated as a padding box if the border is opaque or
157       // there is no border and we don't have custom scrollbars.
158       if (clip == EFillBox::kBorder) {
159         if (!has_custom_scrollbars &&
160             (StyleRef().BorderTopWidth() == 0 ||
161              (!ResolveColor(GetCSSPropertyBorderTopColor()).HasAlpha() &&
162               StyleRef().BorderTopStyle() == EBorderStyle::kSolid)) &&
163             (StyleRef().BorderLeftWidth() == 0 ||
164              (!ResolveColor(GetCSSPropertyBorderLeftColor()).HasAlpha() &&
165               StyleRef().BorderLeftStyle() == EBorderStyle::kSolid)) &&
166             (StyleRef().BorderRightWidth() == 0 ||
167              (!ResolveColor(GetCSSPropertyBorderRightColor()).HasAlpha() &&
168               StyleRef().BorderRightStyle() == EBorderStyle::kSolid)) &&
169             (StyleRef().BorderBottomWidth() == 0 ||
170              (!ResolveColor(GetCSSPropertyBorderBottomColor()).HasAlpha() &&
171               StyleRef().BorderBottomStyle() == EBorderStyle::kSolid))) {
172           continue;
173         }
174         // If we have an opaque background color only, we can safely paint it
175         // into both the scrolling contents layer and the graphics layer to
176         // preserve LCD text.
177         if (layer == (&StyleRef().BackgroundLayers()) &&
178             ResolveColor(GetCSSPropertyBackgroundColor()).Alpha() < 255)
179           return kBackgroundPaintInGraphicsLayer;
180         paint_location |= kBackgroundPaintInGraphicsLayer;
181         continue;
182       }
183       // A content fill box can be treated as a padding fill box if there is no
184       // padding.
185       if (clip == EFillBox::kContent && StyleRef().PaddingTop().IsZero() &&
186           StyleRef().PaddingLeft().IsZero() &&
187           StyleRef().PaddingRight().IsZero() &&
188           StyleRef().PaddingBottom().IsZero()) {
189         continue;
190       }
191     }
192     return kBackgroundPaintInGraphicsLayer;
193   }
194   return paint_location;
195 }
196 
~LayoutBoxModelObject()197 LayoutBoxModelObject::~LayoutBoxModelObject() {
198   // Our layer should have been destroyed and cleared by now
199   DCHECK(!HasLayer());
200   DCHECK(!Layer());
201 }
202 
WillBeDestroyed()203 void LayoutBoxModelObject::WillBeDestroyed() {
204   // A continuation of this LayoutObject should be destroyed at subclasses.
205   DCHECK(!Continuation());
206 
207   if (IsPositioned()) {
208     // Don't use view() because the document's layoutView has been set to
209     // 0 during destruction.
210     if (LocalFrame* frame = GetFrame()) {
211       if (LocalFrameView* frame_view = frame->View()) {
212         if (StyleRef().HasViewportConstrainedPosition() ||
213             StyleRef().HasStickyConstrainedPosition())
214           frame_view->RemoveViewportConstrainedObject(*this);
215       }
216     }
217   }
218 
219   LayoutObject::WillBeDestroyed();
220 
221   if (HasLayer())
222     DestroyLayer();
223 }
224 
StyleWillChange(StyleDifference diff,const ComputedStyle & new_style)225 void LayoutBoxModelObject::StyleWillChange(StyleDifference diff,
226                                            const ComputedStyle& new_style) {
227   // SPv1:
228   // This object's layer may begin or cease to be stacked or stacking context,
229   // in which case the paint invalidation container of this object and
230   // descendants may change. Thus we need to invalidate paint eagerly for all
231   // such children. PaintLayerCompositor::paintInvalidationOnCompositingChange()
232   // doesn't work for the case because we can only see the new
233   // paintInvalidationContainer during compositing update.
234   // SPv1 and v2:
235   // Change of stacked/stacking context status may cause change of this or
236   // descendant PaintLayer's CompositingContainer, so we need to eagerly
237   // invalidate the current compositing container chain which may have painted
238   // cached subsequences containing this object or descendant objects.
239   if (Style() &&
240       (StyleRef().IsStacked() != new_style.IsStacked() ||
241        StyleRef().IsStackingContext() != new_style.IsStackingContext()) &&
242       // ObjectPaintInvalidator requires this.
243       IsRooted()) {
244     if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
245       ObjectPaintInvalidator(*this).SlowSetPaintingLayerNeedsRepaint();
246     } else {
247       // We need to invalidate based on the current compositing status.
248       DisableCompositingQueryAsserts compositing_disabler;
249       ObjectPaintInvalidator(*this)
250           .InvalidatePaintIncludingNonCompositingDescendants();
251     }
252   }
253 
254   if (HasLayer() && diff.CssClipChanged())
255     Layer()->ClearClipRects();
256 
257   LayoutObject::StyleWillChange(diff, new_style);
258 }
259 
260 DISABLE_CFI_PERF
StyleDidChange(StyleDifference diff,const ComputedStyle * old_style)261 void LayoutBoxModelObject::StyleDidChange(StyleDifference diff,
262                                           const ComputedStyle* old_style) {
263   bool had_transform_related_property = HasTransformRelatedProperty();
264   bool had_layer = HasLayer();
265   bool layer_was_self_painting = had_layer && Layer()->IsSelfPaintingLayer();
266   bool was_horizontal_writing_mode = IsHorizontalWritingMode();
267   bool could_contain_fixed = ComputeIsFixedContainer(old_style);
268   bool could_contain_absolute =
269       could_contain_fixed || ComputeIsAbsoluteContainer(old_style);
270 
271   LayoutObject::StyleDidChange(diff, old_style);
272   UpdateFromStyle();
273 
274   // When an out-of-flow-positioned element changes its display between block
275   // and inline-block, then an incremental layout on the element's containing
276   // block lays out the element through LayoutPositionedObjects, which skips
277   // laying out the element's parent.
278   // The element's parent needs to relayout so that it calls LayoutBlockFlow::
279   // setStaticInlinePositionForChild with the out-of-flow-positioned child, so
280   // that when it's laid out, its LayoutBox::computePositionedLogicalWidth/
281   // Height takes into account its new inline/block position rather than its old
282   // block/inline position.
283   // Position changes and other types of display changes are handled elsewhere.
284   if (old_style && IsOutOfFlowPositioned() && Parent() &&
285       (StyleRef().GetPosition() == old_style->GetPosition()) &&
286       (StyleRef().IsOriginalDisplayInlineType() !=
287        old_style->IsOriginalDisplayInlineType()))
288     Parent()->SetNeedsLayout(layout_invalidation_reason::kChildChanged,
289                              kMarkContainerChain);
290 
291   PaintLayerType type = LayerTypeRequired();
292   if (type != kNoPaintLayer) {
293     if (!Layer()) {
294       // In order to update this object properly, we need to lay it out again.
295       // However, if we have never laid it out, don't mark it for layout. If
296       // this is a new object, it may not yet have been inserted into the tree,
297       // and if we mark it for layout then, we risk upsetting the tree
298       // insertion machinery.
299       if (EverHadLayout())
300         SetChildNeedsLayout();
301 
302       CreateLayerAfterStyleChange();
303     }
304   } else if (Layer() && Layer()->Parent()) {
305     PaintLayer* parent_layer = Layer()->Parent();
306     // Either a transform wasn't specified or the object doesn't support
307     // transforms, so just null out the bit.
308     SetHasTransformRelatedProperty(false);
309     SetHasReflection(false);
310     Layer()->UpdateFilters(old_style, StyleRef());
311     Layer()->UpdateBackdropFilters(old_style, StyleRef());
312     Layer()->UpdateClipPath(old_style, StyleRef());
313     // Calls DestroyLayer() which clears the layer.
314     Layer()->RemoveOnlyThisLayerAfterStyleChange(old_style);
315     if (EverHadLayout())
316       SetChildNeedsLayout();
317     if (had_transform_related_property) {
318       SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
319           layout_invalidation_reason::kStyleChange);
320     }
321     if (!NeedsLayout()) {
322       // FIXME: We should call a specialized version of this function.
323       parent_layer->UpdateLayerPositionsAfterLayout();
324     }
325   }
326 
327   bool can_contain_fixed = CanContainFixedPositionObjects();
328   bool can_contain_absolute = CanContainAbsolutePositionObjects();
329 
330   if (old_style && (could_contain_fixed != can_contain_fixed ||
331                     could_contain_absolute != can_contain_absolute)) {
332     // If out of flow element containment changed, then we need to force a
333     // subtree paint property update, since the children elements may now be
334     // referencing a different container.
335     AddSubtreePaintPropertyUpdateReason(
336         SubtreePaintPropertyUpdateReason::kContainerChainMayChange);
337   } else if (had_layer == HasLayer() &&
338              had_transform_related_property != HasTransformRelatedProperty()) {
339     // This affects whether to create transform node. Note that if the
340     // HasLayer() value changed, then all of this was already set in
341     // CreateLayerAfterStyleChange() or DestroyLayer().
342     SetNeedsPaintPropertyUpdate();
343     if (Layer())
344       Layer()->SetNeedsCompositingInputsUpdate();
345   }
346 
347   if (old_style && Parent()) {
348     LayoutBlock* block = FindNonAnonymousContainingBlock(this);
349 
350     if ((could_contain_fixed && !can_contain_fixed) ||
351         (could_contain_absolute && !can_contain_absolute)) {
352       // Clear our positioned objects list. Our absolute and fixed positioned
353       // descendants will be inserted into our containing block's positioned
354       // objects list during layout.
355       block->RemovePositionedObjects(nullptr, kNewContainingBlock);
356     }
357     if (!could_contain_absolute && can_contain_absolute) {
358       // Remove our absolute positioned descendants from their current
359       // containing block.
360       // They will be inserted into our positioned objects list during layout.
361       if (LayoutBlock* cb = block->ContainingBlockForAbsolutePosition())
362         cb->RemovePositionedObjects(this, kNewContainingBlock);
363     }
364     if (!could_contain_fixed && can_contain_fixed) {
365       // Remove our fixed positioned descendants from their current containing
366       // block.
367       // They will be inserted into our positioned objects list during layout.
368       if (LayoutBlock* cb = block->ContainingBlockForFixedPosition())
369         cb->RemovePositionedObjects(this, kNewContainingBlock);
370     }
371   }
372 
373   if (Layer()) {
374     Layer()->StyleDidChange(diff, old_style);
375     if (had_layer && Layer()->IsSelfPaintingLayer() != layer_was_self_painting)
376       SetChildNeedsLayout();
377   }
378 
379   if (old_style && was_horizontal_writing_mode != IsHorizontalWritingMode()) {
380     // Changing the getWritingMode() may change isOrthogonalWritingModeRoot()
381     // of children. Make sure all children are marked/unmarked as orthogonal
382     // writing-mode roots.
383     bool new_horizontal_writing_mode = IsHorizontalWritingMode();
384     for (LayoutObject* child = SlowFirstChild(); child;
385          child = child->NextSibling()) {
386       if (!child->IsBox())
387         continue;
388       if (new_horizontal_writing_mode != child->IsHorizontalWritingMode())
389         ToLayoutBox(child)->MarkOrthogonalWritingModeRoot();
390       else
391         ToLayoutBox(child)->UnmarkOrthogonalWritingModeRoot();
392     }
393   }
394 
395   // The used style for body background may change due to computed style change
396   // on the document element because of change of BackgroundTransfersToView()
397   // which depends on the document element style.
398   if (IsDocumentElement()) {
399     if (HTMLBodyElement* body = GetDocument().FirstBodyElement()) {
400       if (auto* body_object = body->GetLayoutObject()) {
401         if (body_object->IsBoxModelObject()) {
402           auto* body_box_model = ToLayoutBoxModelObject(body_object);
403           bool new_body_background_transfers =
404               body_box_model->BackgroundTransfersToView(Style());
405           bool old_body_background_transfers =
406               old_style && body_box_model->BackgroundTransfersToView(old_style);
407           if (new_body_background_transfers != old_body_background_transfers &&
408               body_object->Style() && body_object->StyleRef().HasBackground())
409             body_object->SetBackgroundNeedsFullPaintInvalidation();
410         }
411       }
412     }
413   }
414 
415   if (LocalFrameView* frame_view = View()->GetFrameView()) {
416     bool new_style_is_viewport_constained =
417         StyleRef().GetPosition() == EPosition::kFixed;
418     bool old_style_is_viewport_constrained =
419         old_style && old_style->GetPosition() == EPosition::kFixed;
420     bool new_style_is_sticky = StyleRef().HasStickyConstrainedPosition();
421     bool old_style_is_sticky =
422         old_style && old_style->HasStickyConstrainedPosition();
423 
424     if (new_style_is_sticky != old_style_is_sticky) {
425       if (new_style_is_sticky) {
426         // During compositing inputs update we'll have the scroll ancestor
427         // without having to walk up the tree and can compute the sticky
428         // position constraints then.
429         if (Layer())
430           Layer()->SetNeedsCompositingInputsUpdate();
431 
432         // TODO(pdr): When CompositeAfterPaint is enabled, we will need to
433         // invalidate the scroll paint property subtree for this so main thread
434         // scroll reasons are recomputed.
435       } else {
436         // This may get re-added to viewport constrained objects if the object
437         // went from sticky to fixed.
438         frame_view->RemoveViewportConstrainedObject(*this);
439 
440         // Remove sticky constraints for this layer.
441         if (Layer()) {
442           if (const PaintLayer* ancestor_overflow_layer =
443                   Layer()->AncestorOverflowLayer()) {
444             if (PaintLayerScrollableArea* scrollable_area =
445                     ancestor_overflow_layer->GetScrollableArea())
446               scrollable_area->InvalidateStickyConstraintsFor(Layer());
447           }
448         }
449 
450         // TODO(pdr): When CompositeAfterPaint is enabled, we will need to
451         // invalidate the scroll paint property subtree for this so main thread
452         // scroll reasons are recomputed.
453       }
454     }
455 
456     if (new_style_is_viewport_constained != old_style_is_viewport_constrained) {
457       if (new_style_is_viewport_constained && Layer())
458         frame_view->AddViewportConstrainedObject(*this);
459       else
460         frame_view->RemoveViewportConstrainedObject(*this);
461     }
462   }
463 
464   if (old_style &&
465       old_style->BackfaceVisibility() != StyleRef().BackfaceVisibility()) {
466     SetNeedsPaintPropertyUpdate();
467   }
468 
469   if (old_style && HasLayer() && !Layer()->SelfNeedsRepaint() &&
470       diff.TransformChanged() &&
471       (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
472        !Layer()->HasStyleDeterminedDirectCompositingReasons())) {
473     // PaintLayerPainter::PaintLayerWithAdjustedRoot skips painting of a layer
474     // whose transform is not invertible, so we need to repaint the layer when
475     // invertible status changes.
476     TransformationMatrix old_transform;
477     TransformationMatrix new_transform;
478     old_style->ApplyTransform(
479         old_transform, LayoutSize(), ComputedStyle::kExcludeTransformOrigin,
480         ComputedStyle::kExcludeMotionPath,
481         ComputedStyle::kIncludeIndependentTransformProperties);
482     StyleRef().ApplyTransform(
483         new_transform, LayoutSize(), ComputedStyle::kExcludeTransformOrigin,
484         ComputedStyle::kExcludeMotionPath,
485         ComputedStyle::kIncludeIndependentTransformProperties);
486     if (old_transform.IsInvertible() != new_transform.IsInvertible())
487       Layer()->SetNeedsRepaint();
488   }
489 
490   // We can't squash across a layout containment boundary. So, if the
491   // containment changes, we need to update the compositing inputs.
492   if (old_style &&
493       ShouldApplyLayoutContainment(*old_style) !=
494           ShouldApplyLayoutContainment() &&
495       Layer()) {
496     Layer()->SetNeedsCompositingInputsUpdate();
497   }
498 }
499 
InvalidateStickyConstraints()500 void LayoutBoxModelObject::InvalidateStickyConstraints() {
501   PaintLayer* enclosing = EnclosingLayer();
502 
503   if (PaintLayerScrollableArea* scrollable_area =
504           enclosing->GetScrollableArea()) {
505     scrollable_area->InvalidateAllStickyConstraints();
506     // If this object doesn't have a layer and its enclosing layer is a scroller
507     // then we don't need to invalidate the sticky constraints on the ancestor
508     // scroller because the enclosing scroller won't have changed size.
509     if (!Layer())
510       return;
511   }
512 
513   // This intentionally uses the stale ancestor overflow layer compositing input
514   // as if we have saved constraints for this layer they were saved in the
515   // previous frame.
516   if (const PaintLayer* ancestor_overflow_layer =
517           enclosing->AncestorOverflowLayer()) {
518     if (PaintLayerScrollableArea* ancestor_scrollable_area =
519             ancestor_overflow_layer->GetScrollableArea())
520       ancestor_scrollable_area->InvalidateAllStickyConstraints();
521   }
522 }
523 
CreateLayerAfterStyleChange()524 void LayoutBoxModelObject::CreateLayerAfterStyleChange() {
525   DCHECK(!HasLayer() && !Layer());
526   GetMutableForPainting().FirstFragment().SetLayer(
527       std::make_unique<PaintLayer>(*this));
528   SetHasLayer(true);
529   Layer()->InsertOnlyThisLayerAfterStyleChange();
530   // Creating a layer may affect existence of the LocalBorderBoxProperties, so
531   // we need to ensure that we update paint properties.
532   SetNeedsPaintPropertyUpdate();
533   if (GetScrollableArea())
534     GetScrollableArea()->InvalidateScrollTimeline();
535 }
536 
DestroyLayer()537 void LayoutBoxModelObject::DestroyLayer() {
538   DCHECK(HasLayer() && Layer());
539   SetHasLayer(false);
540   GetMutableForPainting().FirstFragment().SetLayer(nullptr);
541   // Removing a layer may affect existence of the LocalBorderBoxProperties, so
542   // we need to ensure that we update paint properties.
543   SetNeedsPaintPropertyUpdate();
544   SetBackgroundPaintLocation(kBackgroundPaintInGraphicsLayer);
545 }
546 
HasSelfPaintingLayer() const547 bool LayoutBoxModelObject::HasSelfPaintingLayer() const {
548   return Layer() && Layer()->IsSelfPaintingLayer();
549 }
550 
GetScrollableArea() const551 PaintLayerScrollableArea* LayoutBoxModelObject::GetScrollableArea() const {
552   return Layer() ? Layer()->GetScrollableArea() : nullptr;
553 }
554 
AddOutlineRectsForNormalChildren(Vector<PhysicalRect> & rects,const PhysicalOffset & additional_offset,NGOutlineType include_block_overflows) const555 void LayoutBoxModelObject::AddOutlineRectsForNormalChildren(
556     Vector<PhysicalRect>& rects,
557     const PhysicalOffset& additional_offset,
558     NGOutlineType include_block_overflows) const {
559   for (LayoutObject* child = SlowFirstChild(); child;
560        child = child->NextSibling()) {
561     // Outlines of out-of-flow positioned descendants are handled in
562     // LayoutBlock::AddOutlineRects().
563     if (child->IsOutOfFlowPositioned())
564       continue;
565 
566     // Outline of an element continuation or anonymous block continuation is
567     // added when we iterate the continuation chain.
568     // See LayoutBlock::AddOutlineRects() and LayoutInline::AddOutlineRects().
569     auto* child_block_flow = DynamicTo<LayoutBlockFlow>(child);
570     if (child->IsElementContinuation() ||
571         (child_block_flow && child_block_flow->IsAnonymousBlockContinuation()))
572       continue;
573 
574     AddOutlineRectsForDescendant(*child, rects, additional_offset,
575                                  include_block_overflows);
576   }
577 }
578 
AddOutlineRectsForDescendant(const LayoutObject & descendant,Vector<PhysicalRect> & rects,const PhysicalOffset & additional_offset,NGOutlineType include_block_overflows) const579 void LayoutBoxModelObject::AddOutlineRectsForDescendant(
580     const LayoutObject& descendant,
581     Vector<PhysicalRect>& rects,
582     const PhysicalOffset& additional_offset,
583     NGOutlineType include_block_overflows) const {
584   if (descendant.IsText() || descendant.IsListMarker())
585     return;
586 
587   if (descendant.HasLayer()) {
588     Vector<PhysicalRect> layer_outline_rects;
589     descendant.AddOutlineRects(layer_outline_rects, PhysicalOffset(),
590                                include_block_overflows);
591     descendant.LocalToAncestorRects(layer_outline_rects, this, PhysicalOffset(),
592                                     additional_offset);
593     rects.AppendVector(layer_outline_rects);
594     return;
595   }
596 
597   if (descendant.IsBox()) {
598     descendant.AddOutlineRects(
599         rects, additional_offset + ToLayoutBox(descendant).PhysicalLocation(),
600         include_block_overflows);
601     return;
602   }
603 
604   if (descendant.IsLayoutInline()) {
605     // As an optimization, an ancestor has added rects for its line boxes
606     // covering descendants' line boxes, so descendants don't need to add line
607     // boxes again. For example, if the parent is a LayoutBlock, it adds rects
608     // for its RootOutlineBoxes which cover the line boxes of this LayoutInline.
609     // So the LayoutInline needs to add rects for children and continuations
610     // only.
611     ToLayoutInline(descendant)
612         .AddOutlineRectsForChildrenAndContinuations(rects, additional_offset,
613                                                     include_block_overflows);
614     return;
615   }
616 
617   descendant.AddOutlineRects(rects, additional_offset, include_block_overflows);
618 }
619 
AbsoluteQuadsForSelf(Vector<FloatQuad> & quads,MapCoordinatesFlags mode) const620 void LayoutBoxModelObject::AbsoluteQuadsForSelf(
621     Vector<FloatQuad>& quads,
622     MapCoordinatesFlags mode) const {
623   NOTREACHED();
624 }
625 
AbsoluteQuads(Vector<FloatQuad> & quads,MapCoordinatesFlags mode) const626 void LayoutBoxModelObject::AbsoluteQuads(Vector<FloatQuad>& quads,
627                                          MapCoordinatesFlags mode) const {
628   AbsoluteQuadsForSelf(quads, mode);
629 
630   // Iterate over continuations, avoiding recursion in case there are
631   // many of them. See crbug.com/653767.
632   for (const LayoutBoxModelObject* continuation_object = Continuation();
633        continuation_object;
634        continuation_object = continuation_object->Continuation()) {
635     auto* continuation_block_flow =
636         DynamicTo<LayoutBlockFlow>(continuation_object);
637     DCHECK(continuation_object->IsLayoutInline() ||
638            (continuation_block_flow &&
639             continuation_block_flow->IsAnonymousBlockContinuation()));
640     continuation_object->AbsoluteQuadsForSelf(quads, mode);
641   }
642 }
643 
UpdateFromStyle()644 void LayoutBoxModelObject::UpdateFromStyle() {
645   const ComputedStyle& style_to_use = StyleRef();
646   SetHasBoxDecorationBackground(style_to_use.HasBoxDecorationBackground());
647   SetInline(style_to_use.IsDisplayInlineType());
648   SetPositionState(style_to_use.GetPosition());
649   SetHorizontalWritingMode(style_to_use.IsHorizontalWritingMode());
650   SetCanContainFixedPositionObjects(ComputeIsFixedContainer(&style_to_use));
651 }
652 
ContainingBlockForAutoHeightDetection(const Length & logical_height) const653 LayoutBlock* LayoutBoxModelObject::ContainingBlockForAutoHeightDetection(
654     const Length& logical_height) const {
655   // For percentage heights: The percentage is calculated with respect to the
656   // height of the generated box's containing block. If the height of the
657   // containing block is not specified explicitly (i.e., it depends on content
658   // height), and this element is not absolutely positioned, the used height is
659   // calculated as if 'auto' was specified.
660   if (!logical_height.IsPercentOrCalc() || IsOutOfFlowPositioned())
661     return nullptr;
662 
663   // Anonymous block boxes are ignored when resolving percentage values that
664   // would refer to it: the closest non-anonymous ancestor box is used instead.
665   LayoutBlock* cb = ContainingBlock();
666   while (cb->IsAnonymous())
667     cb = cb->ContainingBlock();
668 
669   // Matching LayoutBox::percentageLogicalHeightIsResolvableFromBlock() by
670   // ignoring table cell's attribute value, where it says that table cells
671   // violate what the CSS spec says to do with heights. Basically we don't care
672   // if the cell specified a height or not.
673   if (cb->IsTableCell())
674     return nullptr;
675 
676   // Match LayoutBox::availableLogicalHeightUsing by special casing the layout
677   // view. The available height is taken from the frame.
678   if (IsA<LayoutView>(cb))
679     return nullptr;
680 
681   if (IsOutOfFlowPositionedWithImplicitHeight(cb))
682     return nullptr;
683 
684   return cb;
685 }
686 
HasAutoHeightOrContainingBlockWithAutoHeight(RegisterPercentageDescendant register_percentage_descendant) const687 bool LayoutBoxModelObject::HasAutoHeightOrContainingBlockWithAutoHeight(
688     RegisterPercentageDescendant register_percentage_descendant) const {
689   // TODO(rego): Check if we can somehow reuse LayoutBlock::
690   // availableLogicalHeightForPercentageComputation() (see crbug.com/635655).
691   const LayoutBox* this_box = IsBox() ? ToLayoutBox(this) : nullptr;
692   const Length& logical_height_length = StyleRef().LogicalHeight();
693   LayoutBlock* cb =
694       ContainingBlockForAutoHeightDetection(logical_height_length);
695   if (register_percentage_descendant == kRegisterPercentageDescendant &&
696       logical_height_length.IsPercentOrCalc() && cb && IsBox()) {
697     cb->AddPercentHeightDescendant(const_cast<LayoutBox*>(ToLayoutBox(this)));
698   }
699   if (this_box && this_box->IsFlexItemIncludingNG()) {
700     if (this_box->IsFlexItem()) {
701       const LayoutFlexibleBox& flex_box = ToLayoutFlexibleBox(*Parent());
702       if (flex_box.UseOverrideLogicalHeightForPerentageResolution(*this_box))
703         return false;
704     } else if (this_box->GetCachedLayoutResult()) {
705       const NGConstraintSpace& space =
706           this_box->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
707       if (space.IsFixedBlockSize() && !space.IsFixedBlockSizeIndefinite())
708         return false;
709     }
710   }
711   if (this_box && this_box->IsGridItem() &&
712       this_box->HasOverrideContainingBlockContentLogicalHeight())
713     return false;
714   if (this_box && this_box->IsCustomItem() &&
715       (this_box->HasOverrideContainingBlockContentLogicalHeight() ||
716        this_box->HasOverridePercentageResolutionBlockSize()))
717     return false;
718 
719   if (logical_height_length.IsIntrinsicOrAuto() &&
720       !IsOutOfFlowPositionedWithImplicitHeight(this))
721     return true;
722 
723   if (cb) {
724     // We need the containing block to have a definite block-size in order to
725     // resolve the block-size of the descendant, except when in quirks mode.
726     // Flexboxes follow strict behavior even in quirks mode, though.
727     if (!GetDocument().InQuirksMode() ||
728         cb->IsFlexibleBoxIncludingDeprecatedAndNG()) {
729       if (this_box &&
730           this_box->HasOverrideContainingBlockContentLogicalHeight()) {
731         return this_box->OverrideContainingBlockContentLogicalHeight() ==
732                LayoutUnit(-1);
733       }
734       return !cb->HasDefiniteLogicalHeight();
735     }
736   }
737 
738   return false;
739 }
740 
RelativePositionOffset() const741 PhysicalOffset LayoutBoxModelObject::RelativePositionOffset() const {
742   DCHECK(IsRelPositioned());
743   PhysicalOffset offset = AccumulateInFlowPositionOffsets();
744 
745   LayoutBlock* containing_block = ContainingBlock();
746 
747   // Objects that shrink to avoid floats normally use available line width when
748   // computing containing block width. However in the case of relative
749   // positioning using percentages, we can't do this. The offset should always
750   // be resolved using the available width of the containing block. Therefore we
751   // don't use containingBlockLogicalWidthForContent() here, but instead
752   // explicitly call availableWidth on our containing block.
753   // https://drafts.csswg.org/css-position-3/#rel-pos
754   // However for grid items the containing block is the grid area, so offsets
755   // should be resolved against that:
756   // https://drafts.csswg.org/css-grid/#grid-item-sizing
757   base::Optional<LayoutUnit> left;
758   base::Optional<LayoutUnit> right;
759   if (!StyleRef().Left().IsAuto() || !StyleRef().Right().IsAuto()) {
760     LayoutUnit available_width = HasOverrideContainingBlockContentWidth()
761                                      ? OverrideContainingBlockContentWidth()
762                                      : containing_block->AvailableWidth();
763     if (!StyleRef().Left().IsAuto())
764       left = ValueForLength(StyleRef().Left(), available_width);
765     if (!StyleRef().Right().IsAuto())
766       right = ValueForLength(StyleRef().Right(), available_width);
767   }
768   if (!left && !right) {
769     left = LayoutUnit();
770     right = LayoutUnit();
771   }
772   if (!left)
773     left = -right.value();
774   if (!right)
775     right = -left.value();
776   bool is_ltr = containing_block->StyleRef().IsLeftToRightDirection();
777   WritingMode writing_mode = containing_block->StyleRef().GetWritingMode();
778   switch (writing_mode) {
779     case WritingMode::kHorizontalTb:
780       if (is_ltr)
781         offset.left += left.value();
782       else
783         offset.left = -right.value();
784       break;
785     case WritingMode::kVerticalRl:
786       offset.left = -right.value();
787       break;
788     case WritingMode::kVerticalLr:
789       offset.left += left.value();
790       break;
791     // TODO(layout-dev): Sideways-lr and sideways-rl are not yet supported.
792     default:
793       break;
794   }
795 
796   // If the containing block of a relatively positioned element does not specify
797   // a height, a percentage top or bottom offset should be resolved as auto.
798   // An exception to this is if the containing block has the WinIE quirk where
799   // <html> and <body> assume the size of the viewport. In this case, calculate
800   // the percent offset based on this height.
801   // See <https://bugs.webkit.org/show_bug.cgi?id=26396>.
802   // Another exception is a grid item, as the containing block is the grid area:
803   // https://drafts.csswg.org/css-grid/#grid-item-sizing
804 
805   base::Optional<LayoutUnit> top;
806   base::Optional<LayoutUnit> bottom;
807   bool has_override_containing_block_content_height =
808       HasOverrideContainingBlockContentHeight();
809   if (!StyleRef().Top().IsAuto() &&
810       (!containing_block->HasAutoHeightOrContainingBlockWithAutoHeight() ||
811        !StyleRef().Top().IsPercentOrCalc() ||
812        containing_block->StretchesToViewport() ||
813        has_override_containing_block_content_height)) {
814     // TODO(rego): The computation of the available height is repeated later for
815     // "bottom". We could refactor this and move it to some common code for both
816     // ifs, however moving it outside of the ifs is not possible as it'd cause
817     // performance regressions (see crbug.com/893884).
818     top = ValueForLength(StyleRef().Top(),
819                          has_override_containing_block_content_height
820                              ? OverrideContainingBlockContentHeight()
821                              : containing_block->AvailableHeight());
822   }
823   if (!StyleRef().Bottom().IsAuto() &&
824       (!containing_block->HasAutoHeightOrContainingBlockWithAutoHeight() ||
825        !StyleRef().Bottom().IsPercentOrCalc() ||
826        containing_block->StretchesToViewport() ||
827        has_override_containing_block_content_height)) {
828     // TODO(rego): Check comment above for "top", it applies here too.
829     bottom = ValueForLength(StyleRef().Bottom(),
830                             has_override_containing_block_content_height
831                                 ? OverrideContainingBlockContentHeight()
832                                 : containing_block->AvailableHeight());
833   }
834   if (!top && !bottom) {
835     top = LayoutUnit();
836     bottom = LayoutUnit();
837   }
838   if (!top)
839     top = -bottom.value();
840   if (!bottom)
841     bottom = -top.value();
842   switch (writing_mode) {
843     case WritingMode::kHorizontalTb:
844       offset.top += top.value();
845       break;
846     case WritingMode::kVerticalRl:
847       if (is_ltr)
848         offset.top += top.value();
849       else
850         offset.top = -bottom.value();
851       break;
852     case WritingMode::kVerticalLr:
853       if (is_ltr)
854         offset.top += top.value();
855       else
856         offset.top = -bottom.value();
857       break;
858     // TODO(layout-dev): Sideways-lr and sideways-rl are not yet supported.
859     default:
860       break;
861   }
862   return offset;
863 }
864 
UpdateStickyPositionConstraints() const865 void LayoutBoxModelObject::UpdateStickyPositionConstraints() const {
866   DCHECK(StyleRef().HasStickyConstrainedPosition());
867 
868   const PhysicalSize constraining_size = ComputeStickyConstrainingRect().size;
869 
870   StickyPositionScrollingConstraints constraints;
871   PhysicalOffset skipped_containers_offset;
872   LayoutBlock* containing_block = ContainingBlock();
873   // The location container for boxes is not always the containing block.
874   LayoutObject* location_container =
875       IsLayoutInline() ? Container() : ToLayoutBox(this)->LocationContainer();
876   // Skip anonymous containing blocks.
877   while (containing_block->IsAnonymous()) {
878     containing_block = containing_block->ContainingBlock();
879   }
880 
881   // The sticky position constraint rects should be independent of the current
882   // scroll position therefore we should ignore the scroll offset when
883   // calculating the quad.
884   // TODO(crbug.com/966131): Is kIgnoreTransforms correct here?
885   MapCoordinatesFlags flags =
886       kIgnoreTransforms | kIgnoreScrollOffset | kIgnoreStickyOffset;
887   skipped_containers_offset = location_container->LocalToAncestorPoint(
888       PhysicalOffset(), containing_block, flags);
889   LayoutBox& scroll_ancestor =
890       ToLayoutBox(Layer()->AncestorOverflowLayer()->GetLayoutObject());
891 
892   LayoutUnit max_container_width =
893       IsA<LayoutView>(containing_block)
894           ? containing_block->LogicalWidth()
895           : containing_block->ContainingBlockLogicalWidthForContent();
896   // Sticky positioned element ignore any override logical width on the
897   // containing block, as they don't call containingBlockLogicalWidthForContent.
898   // It's unclear whether this is totally fine.
899   // Compute the container-relative area within which the sticky element is
900   // allowed to move.
901   LayoutUnit max_width = containing_block->AvailableLogicalWidth();
902 
903   // Map the containing block to the inner corner of the scroll ancestor without
904   // transforms.
905   PhysicalRect scroll_container_relative_padding_box_rect(
906       containing_block->LayoutOverflowRect());
907   if (containing_block != &scroll_ancestor) {
908     PhysicalRect local_rect = containing_block->PhysicalPaddingBoxRect();
909     scroll_container_relative_padding_box_rect =
910         containing_block->LocalToAncestorRect(local_rect, &scroll_ancestor,
911                                               flags);
912   }
913 
914   // Remove top-left border offset from overflow scroller.
915   PhysicalOffset scroll_container_border_offset(scroll_ancestor.BorderLeft(),
916                                                 scroll_ancestor.BorderTop());
917   scroll_container_relative_padding_box_rect.Move(
918       -scroll_container_border_offset);
919 
920   PhysicalRect scroll_container_relative_containing_block_rect(
921       scroll_container_relative_padding_box_rect);
922 
923   // This is removing the padding of the containing block's overflow rect to get
924   // the flow box rectangle and removing the margin of the sticky element to
925   // ensure that space between the sticky element and its containing flow box.
926   // It is an open issue whether the margin should collapse.
927   // See https://www.w3.org/TR/css-position-3/#sticky-pos
928   scroll_container_relative_containing_block_rect.ContractEdges(
929       MinimumValueForLength(containing_block->StyleRef().PaddingTop(),
930                             max_container_width) +
931           MinimumValueForLength(StyleRef().MarginTop(), max_width),
932       MinimumValueForLength(containing_block->StyleRef().PaddingRight(),
933                             max_container_width) +
934           MinimumValueForLength(StyleRef().MarginRight(), max_width),
935       MinimumValueForLength(containing_block->StyleRef().PaddingBottom(),
936                             max_container_width) +
937           MinimumValueForLength(StyleRef().MarginBottom(), max_width),
938       MinimumValueForLength(containing_block->StyleRef().PaddingLeft(),
939                             max_container_width) +
940           MinimumValueForLength(StyleRef().MarginLeft(), max_width));
941 
942   constraints.scroll_container_relative_containing_block_rect =
943       scroll_container_relative_containing_block_rect;
944 
945   PhysicalRect sticky_box_rect;
946   if (IsLayoutInline()) {
947     sticky_box_rect = ToLayoutInline(this)->PhysicalLinesBoundingBox();
948   } else {
949     sticky_box_rect =
950         containing_block->FlipForWritingMode(ToLayoutBox(this)->FrameRect());
951   }
952   PhysicalOffset sticky_location =
953       sticky_box_rect.offset + skipped_containers_offset;
954 
955   // The scrollContainerRelativePaddingBoxRect's position is the padding box so
956   // we need to remove the border when finding the position of the sticky box
957   // within the scroll ancestor if the container is not our scroll ancestor. If
958   // the container is our scroll ancestor, we also need to remove the border
959   // box because we want the position from within the scroller border.
960   PhysicalOffset container_border_offset(containing_block->BorderLeft(),
961                                          containing_block->BorderTop());
962   sticky_location -= container_border_offset;
963   constraints.scroll_container_relative_sticky_box_rect = PhysicalRect(
964       scroll_container_relative_padding_box_rect.offset + sticky_location,
965       sticky_box_rect.size);
966 
967   // To correctly compute the offsets, the constraints need to know about any
968   // nested position:sticky elements between themselves and their
969   // containingBlock, and between the containingBlock and their scrollAncestor.
970   //
971   // The respective search ranges are [container, containingBlock) and
972   // [containingBlock, scrollAncestor).
973   constraints.nearest_sticky_layer_shifting_sticky_box =
974       FindFirstStickyBetween(location_container, containing_block);
975   // We cannot use |scrollAncestor| here as it disregards the root
976   // ancestorOverflowLayer(), which we should include.
977   constraints.nearest_sticky_layer_shifting_containing_block =
978       FindFirstStickyBetween(
979           containing_block,
980           &Layer()->AncestorOverflowLayer()->GetLayoutObject());
981 
982   // We skip the right or top sticky offset if there is not enough space to
983   // honor both the left/right or top/bottom offsets.
984   LayoutUnit horizontal_offsets =
985       MinimumValueForLength(StyleRef().Right(), constraining_size.width) +
986       MinimumValueForLength(StyleRef().Left(), constraining_size.width);
987   bool skip_right = false;
988   bool skip_left = false;
989   if (!StyleRef().Left().IsAuto() && !StyleRef().Right().IsAuto()) {
990     if (horizontal_offsets >
991             scroll_container_relative_containing_block_rect.Width() ||
992         horizontal_offsets + sticky_box_rect.Width() >
993             constraining_size.width) {
994       skip_right = StyleRef().IsLeftToRightDirection();
995       skip_left = !skip_right;
996     }
997   }
998 
999   if (!StyleRef().Left().IsAuto() && !skip_left) {
1000     constraints.left_offset =
1001         MinimumValueForLength(StyleRef().Left(), constraining_size.width);
1002     constraints.is_anchored_left = true;
1003   }
1004 
1005   if (!StyleRef().Right().IsAuto() && !skip_right) {
1006     constraints.right_offset =
1007         MinimumValueForLength(StyleRef().Right(), constraining_size.width);
1008     constraints.is_anchored_right = true;
1009   }
1010 
1011   bool skip_bottom = false;
1012   // TODO(flackr): Exclude top or bottom edge offset depending on the writing
1013   // mode when related sections are fixed in spec.
1014   // See http://lists.w3.org/Archives/Public/www-style/2014May/0286.html
1015   LayoutUnit vertical_offsets =
1016       MinimumValueForLength(StyleRef().Top(), constraining_size.height) +
1017       MinimumValueForLength(StyleRef().Bottom(), constraining_size.height);
1018   if (!StyleRef().Top().IsAuto() && !StyleRef().Bottom().IsAuto()) {
1019     if (vertical_offsets >
1020             scroll_container_relative_containing_block_rect.Height() ||
1021         vertical_offsets + sticky_box_rect.Height() >
1022             constraining_size.height) {
1023       skip_bottom = true;
1024     }
1025   }
1026 
1027   if (!StyleRef().Top().IsAuto()) {
1028     constraints.top_offset =
1029         MinimumValueForLength(StyleRef().Top(), constraining_size.height);
1030     constraints.is_anchored_top = true;
1031   }
1032 
1033   if (!StyleRef().Bottom().IsAuto() && !skip_bottom) {
1034     constraints.bottom_offset =
1035         MinimumValueForLength(StyleRef().Bottom(), constraining_size.height);
1036     constraints.is_anchored_bottom = true;
1037   }
1038   PaintLayerScrollableArea* scrollable_area =
1039       Layer()->AncestorOverflowLayer()->GetScrollableArea();
1040   scrollable_area->GetStickyConstraintsMap().Set(Layer(), constraints);
1041 }
1042 
IsSlowRepaintConstrainedObject() const1043 bool LayoutBoxModelObject::IsSlowRepaintConstrainedObject() const {
1044   if (!HasLayer() || (StyleRef().GetPosition() != EPosition::kFixed &&
1045                       StyleRef().GetPosition() != EPosition::kSticky)) {
1046     return false;
1047   }
1048 
1049   PaintLayer* layer = Layer();
1050 
1051   // Whether the Layer sticks to the viewport is a tree-depenent
1052   // property and our viewportConstrainedObjects collection is maintained
1053   // with only LayoutObject-level information.
1054   if (!layer->FixedToViewport() && !layer->SticksToScroller())
1055     return false;
1056 
1057   // If the whole subtree is invisible, there's no reason to scroll on
1058   // the main thread because we don't need to generate invalidations
1059   // for invisible content.
1060   if (layer->SubtreeIsInvisible())
1061     return false;
1062 
1063   // We're only smart enough to scroll viewport-constrainted objects
1064   // in the compositor if they have their own backing or they paint
1065   // into a grouped back (which necessarily all have the same viewport
1066   // constraints).
1067   return (layer->GetCompositingState() == kNotComposited);
1068 }
1069 
ComputeStickyConstrainingRect() const1070 PhysicalRect LayoutBoxModelObject::ComputeStickyConstrainingRect() const {
1071   LayoutBox* enclosing_clipping_box =
1072       Layer()->AncestorOverflowLayer()->GetLayoutBox();
1073   DCHECK(enclosing_clipping_box);
1074   PhysicalRect constraining_rect;
1075   constraining_rect =
1076       PhysicalRect(enclosing_clipping_box->OverflowClipRect(LayoutPoint()));
1077   constraining_rect.Move(
1078       PhysicalOffset(-enclosing_clipping_box->BorderLeft() +
1079                          enclosing_clipping_box->PaddingLeft(),
1080                      -enclosing_clipping_box->BorderTop() +
1081                          enclosing_clipping_box->PaddingTop()));
1082   constraining_rect.ContractEdges(LayoutUnit(),
1083                                   enclosing_clipping_box->PaddingLeft() +
1084                                       enclosing_clipping_box->PaddingRight(),
1085                                   enclosing_clipping_box->PaddingTop() +
1086                                       enclosing_clipping_box->PaddingBottom(),
1087                                   LayoutUnit());
1088   return constraining_rect;
1089 }
1090 
StickyPositionOffset() const1091 PhysicalOffset LayoutBoxModelObject::StickyPositionOffset() const {
1092   // TODO(chrishtr): StickyPositionOffset depends on compositing at present,
1093   // but there are callsites within Layout for it.
1094 
1095   const PaintLayer* ancestor_overflow_layer = Layer()->AncestorOverflowLayer();
1096   // TODO: Force compositing input update if we ask for offset before
1097   // compositing inputs have been computed?
1098   if (!ancestor_overflow_layer || !ancestor_overflow_layer->GetScrollableArea())
1099     return PhysicalOffset();
1100 
1101   StickyConstraintsMap& constraints_map =
1102       ancestor_overflow_layer->GetScrollableArea()->GetStickyConstraintsMap();
1103   auto it = constraints_map.find(Layer());
1104   if (it == constraints_map.end())
1105     return PhysicalOffset();
1106   StickyPositionScrollingConstraints* constraints = &it->value;
1107 
1108   // The sticky offset is physical, so we can just return the delta computed in
1109   // absolute coords (though it may be wrong with transforms).
1110   PhysicalRect constraining_rect = ComputeStickyConstrainingRect();
1111   constraining_rect.Move(PhysicalOffset::FromFloatPointRound(
1112       ancestor_overflow_layer->GetScrollableArea()->ScrollPosition()));
1113   return constraints->ComputeStickyOffset(constraining_rect, constraints_map);
1114 }
1115 
AdjustedPositionRelativeTo(const PhysicalOffset & start_point,const Element * offset_parent) const1116 PhysicalOffset LayoutBoxModelObject::AdjustedPositionRelativeTo(
1117     const PhysicalOffset& start_point,
1118     const Element* offset_parent) const {
1119   // If the element is the HTML body element or doesn't have a parent
1120   // return 0 and stop this algorithm.
1121   if (IsBody() || !Parent())
1122     return PhysicalOffset();
1123 
1124   PhysicalOffset reference_point = start_point;
1125 
1126   // If the offsetParent is null, return the distance between the canvas origin
1127   // and the left/top border edge of the element and stop this algorithm.
1128   if (!offset_parent)
1129     return reference_point;
1130 
1131   if (const LayoutBoxModelObject* offset_parent_object =
1132           offset_parent->GetLayoutBoxModelObject()) {
1133     if (!IsOutOfFlowPositioned()) {
1134       if (IsInFlowPositioned())
1135         reference_point += OffsetForInFlowPosition();
1136 
1137       // Note that we may fail to find |offsetParent| while walking the
1138       // container chain, if |offsetParent| is an inline split into
1139       // continuations: <body style="display:inline;" id="offsetParent">
1140       // <div id="this">
1141       // This is why we have to do a nullptr check here.
1142       for (const LayoutObject* current = Container();
1143            current && current->GetNode() != offset_parent;
1144            current = current->Container()) {
1145         // FIXME: What are we supposed to do inside SVG content?
1146         reference_point += PhysicalOffsetToBeNoop(
1147             current->ColumnOffset(reference_point.ToLayoutPoint()));
1148         if (current->IsBox() && !current->IsTableRow())
1149           reference_point += ToLayoutBox(current)->PhysicalLocation();
1150       }
1151 
1152       if (offset_parent_object->IsBox() && offset_parent_object->IsBody() &&
1153           !offset_parent_object->IsPositioned()) {
1154         reference_point +=
1155             ToLayoutBox(offset_parent_object)->PhysicalLocation();
1156       }
1157     }
1158 
1159     if (offset_parent_object->IsLayoutInline()) {
1160       const LayoutInline* inline_parent = ToLayoutInline(offset_parent_object);
1161 
1162       if (IsBox() && IsOutOfFlowPositioned() &&
1163           inline_parent->CanContainOutOfFlowPositionedElement(
1164               StyleRef().GetPosition())) {
1165         // Offset for out of flow positioned elements with inline containers is
1166         // a special case in the CSS spec
1167         reference_point +=
1168             inline_parent->OffsetForInFlowPositionedInline(*ToLayoutBox(this));
1169       }
1170 
1171       reference_point -= inline_parent->FirstLineBoxTopLeft();
1172     }
1173 
1174     if (offset_parent_object->IsBox() && !offset_parent_object->IsBody()) {
1175       reference_point -=
1176           PhysicalOffset(ToLayoutBox(offset_parent_object)->BorderLeft(),
1177                          ToLayoutBox(offset_parent_object)->BorderTop());
1178     }
1179   }
1180 
1181   return reference_point;
1182 }
1183 
OffsetForInFlowPosition() const1184 PhysicalOffset LayoutBoxModelObject::OffsetForInFlowPosition() const {
1185   if (IsRelPositioned())
1186     return RelativePositionOffset();
1187 
1188   if (IsStickyPositioned())
1189     return StickyPositionOffset();
1190 
1191   return PhysicalOffset();
1192 }
1193 
OffsetLeft(const Element * parent) const1194 LayoutUnit LayoutBoxModelObject::OffsetLeft(const Element* parent) const {
1195   // Note that LayoutInline and LayoutBox override this to pass a different
1196   // startPoint to adjustedPositionRelativeTo.
1197   return AdjustedPositionRelativeTo(PhysicalOffset(), parent).left;
1198 }
1199 
OffsetTop(const Element * parent) const1200 LayoutUnit LayoutBoxModelObject::OffsetTop(const Element* parent) const {
1201   // Note that LayoutInline and LayoutBox override this to pass a different
1202   // startPoint to adjustedPositionRelativeTo.
1203   return AdjustedPositionRelativeTo(PhysicalOffset(), parent).top;
1204 }
1205 
PixelSnappedOffsetWidth(const Element * parent) const1206 int LayoutBoxModelObject::PixelSnappedOffsetWidth(const Element* parent) const {
1207   return SnapSizeToPixel(OffsetWidth(), OffsetLeft(parent));
1208 }
1209 
PixelSnappedOffsetHeight(const Element * parent) const1210 int LayoutBoxModelObject::PixelSnappedOffsetHeight(
1211     const Element* parent) const {
1212   return SnapSizeToPixel(OffsetHeight(), OffsetTop(parent));
1213 }
1214 
ComputedCSSPadding(const Length & padding) const1215 LayoutUnit LayoutBoxModelObject::ComputedCSSPadding(
1216     const Length& padding) const {
1217   LayoutUnit w;
1218   if (padding.IsPercentOrCalc())
1219     w = ContainingBlockLogicalWidthForContent();
1220   return MinimumValueForLength(padding, w);
1221 }
1222 
ContainingBlockLogicalWidthForContent() const1223 LayoutUnit LayoutBoxModelObject::ContainingBlockLogicalWidthForContent() const {
1224   return ContainingBlock()->AvailableLogicalWidth();
1225 }
1226 
Continuation() const1227 LayoutBoxModelObject* LayoutBoxModelObject::Continuation() const {
1228   return (!g_continuation_map) ? nullptr : g_continuation_map->at(this);
1229 }
1230 
SetContinuation(LayoutBoxModelObject * continuation)1231 void LayoutBoxModelObject::SetContinuation(LayoutBoxModelObject* continuation) {
1232   if (continuation) {
1233     DCHECK(continuation->IsLayoutInline() || continuation->IsLayoutBlockFlow());
1234     if (!g_continuation_map)
1235       g_continuation_map = new ContinuationMap;
1236     g_continuation_map->Set(this, continuation);
1237   } else {
1238     if (g_continuation_map)
1239       g_continuation_map->erase(this);
1240   }
1241 }
1242 
LocalCaretRectForEmptyElement(LayoutUnit width,LayoutUnit text_indent_offset) const1243 LayoutRect LayoutBoxModelObject::LocalCaretRectForEmptyElement(
1244     LayoutUnit width,
1245     LayoutUnit text_indent_offset) const {
1246   DCHECK(!SlowFirstChild() || SlowFirstChild()->IsPseudoElement());
1247 
1248   // FIXME: This does not take into account either :first-line or :first-letter
1249   // However, as soon as some content is entered, the line boxes will be
1250   // constructed and this kludge is not called any more. So only the caret size
1251   // of an empty :first-line'd block is wrong. I think we can live with that.
1252   const ComputedStyle& current_style = FirstLineStyleRef();
1253 
1254   enum CaretAlignment { kAlignLeft, kAlignRight, kAlignCenter };
1255 
1256   CaretAlignment alignment = kAlignLeft;
1257 
1258   switch (current_style.GetTextAlign()) {
1259     case ETextAlign::kLeft:
1260     case ETextAlign::kWebkitLeft:
1261       break;
1262     case ETextAlign::kCenter:
1263     case ETextAlign::kWebkitCenter:
1264       alignment = kAlignCenter;
1265       break;
1266     case ETextAlign::kRight:
1267     case ETextAlign::kWebkitRight:
1268       alignment = kAlignRight;
1269       break;
1270     case ETextAlign::kJustify:
1271     case ETextAlign::kStart:
1272       if (!current_style.IsLeftToRightDirection())
1273         alignment = kAlignRight;
1274       break;
1275     case ETextAlign::kEnd:
1276       if (current_style.IsLeftToRightDirection())
1277         alignment = kAlignRight;
1278       break;
1279   }
1280 
1281   LayoutUnit x = BorderLeft() + PaddingLeft();
1282   LayoutUnit max_x = width - BorderRight() - PaddingRight();
1283   LayoutUnit caret_width = GetFrameView()->CaretWidth();
1284 
1285   switch (alignment) {
1286     case kAlignLeft:
1287       if (current_style.IsLeftToRightDirection())
1288         x += text_indent_offset;
1289       break;
1290     case kAlignCenter:
1291       x = (x + max_x) / 2;
1292       if (current_style.IsLeftToRightDirection())
1293         x += text_indent_offset / 2;
1294       else
1295         x -= text_indent_offset / 2;
1296       break;
1297     case kAlignRight:
1298       x = max_x - caret_width;
1299       if (!current_style.IsLeftToRightDirection())
1300         x -= text_indent_offset;
1301       break;
1302   }
1303   x = std::min(x, (max_x - caret_width).ClampNegativeToZero());
1304 
1305   const Font& font = StyleRef().GetFont();
1306   const SimpleFontData* font_data = font.PrimaryFont();
1307   LayoutUnit height;
1308   // crbug.com/595692 This check should not be needed but sometimes
1309   // primaryFont is null.
1310   if (font_data)
1311     height = LayoutUnit(font_data->GetFontMetrics().Height());
1312   LayoutUnit vertical_space =
1313       LineHeight(true,
1314                  current_style.IsHorizontalWritingMode() ? kHorizontalLine
1315                                                          : kVerticalLine,
1316                  kPositionOfInteriorLineBoxes) -
1317       height;
1318   LayoutUnit y = PaddingTop() + BorderTop() + (vertical_space / 2);
1319   return current_style.IsHorizontalWritingMode()
1320              ? LayoutRect(x, y, caret_width, height)
1321              : LayoutRect(y, x, height, caret_width);
1322 }
1323 
PushMappingToContainer(const LayoutBoxModelObject * ancestor_to_stop_at,LayoutGeometryMap & geometry_map) const1324 const LayoutObject* LayoutBoxModelObject::PushMappingToContainer(
1325     const LayoutBoxModelObject* ancestor_to_stop_at,
1326     LayoutGeometryMap& geometry_map) const {
1327   DCHECK_NE(ancestor_to_stop_at, this);
1328 
1329   AncestorSkipInfo skip_info(ancestor_to_stop_at);
1330   LayoutObject* container = Container(&skip_info);
1331   if (!container)
1332     return nullptr;
1333 
1334   bool is_inline = IsLayoutInline();
1335   bool is_fixed_pos =
1336       !is_inline && StyleRef().GetPosition() == EPosition::kFixed;
1337   bool contains_fixed_position = CanContainFixedPositionObjects();
1338 
1339   TransformationMatrix adjustment_for_skipped_ancestor;
1340   bool adjustment_for_skipped_ancestor_is_translate_2d = true;
1341   if (skip_info.AncestorSkipped()) {
1342     // There can't be a transform between container and ancestor_to_stop_at,
1343     // because transforms create containers, so it should be safe to just
1344     // subtract the delta between the container and ancestor_to_stop_at.
1345     PhysicalOffset ancestor_offset =
1346         ancestor_to_stop_at->OffsetFromAncestor(container);
1347     adjustment_for_skipped_ancestor.Translate(-ancestor_offset.left.ToFloat(),
1348                                               -ancestor_offset.top.ToFloat());
1349   }
1350 
1351   PhysicalOffset container_offset = OffsetFromContainer(container);
1352   bool offset_depends_on_point;
1353   if (IsLayoutFlowThread()) {
1354     container_offset += PhysicalOffsetToBeNoop(ColumnOffset(LayoutPoint()));
1355     offset_depends_on_point = true;
1356   } else {
1357     offset_depends_on_point =
1358         container->StyleRef().IsFlippedBlocksWritingMode() &&
1359         container->IsBox();
1360   }
1361 
1362   bool preserve3d =
1363       container->StyleRef().Preserves3D() || StyleRef().Preserves3D();
1364   GeometryInfoFlags flags = 0;
1365   if (preserve3d)
1366     flags |= kAccumulatingTransform;
1367   if (offset_depends_on_point)
1368     flags |= kIsNonUniform;
1369   if (is_fixed_pos)
1370     flags |= kIsFixedPosition;
1371   if (contains_fixed_position)
1372     flags |= kContainsFixedPosition;
1373   if (ShouldUseTransformFromContainer(container)) {
1374     TransformationMatrix t;
1375     GetTransformFromContainer(container, container_offset, t);
1376     adjustment_for_skipped_ancestor.Multiply(t);
1377     geometry_map.Push(this, adjustment_for_skipped_ancestor, flags,
1378                       PhysicalOffset());
1379   } else if (adjustment_for_skipped_ancestor_is_translate_2d) {
1380     container_offset += PhysicalOffset::FromFloatSizeRound(
1381         adjustment_for_skipped_ancestor.To2DTranslation());
1382     geometry_map.Push(this, container_offset, flags, PhysicalOffset());
1383   } else {
1384     adjustment_for_skipped_ancestor.Translate(container_offset.left,
1385                                               container_offset.top);
1386     geometry_map.Push(this, adjustment_for_skipped_ancestor, flags,
1387                       PhysicalOffset());
1388   }
1389 
1390   return skip_info.AncestorSkipped() ? ancestor_to_stop_at : container;
1391 }
1392 
MoveChildTo(LayoutBoxModelObject * to_box_model_object,LayoutObject * child,LayoutObject * before_child,bool full_remove_insert)1393 void LayoutBoxModelObject::MoveChildTo(
1394     LayoutBoxModelObject* to_box_model_object,
1395     LayoutObject* child,
1396     LayoutObject* before_child,
1397     bool full_remove_insert) {
1398   // We assume that callers have cleared their positioned objects list for child
1399   // moves (!fullRemoveInsert) so the positioned layoutObject maps don't become
1400   // stale. It would be too slow to do the map lookup on each call.
1401   DCHECK(!full_remove_insert || !IsLayoutBlock() ||
1402          !To<LayoutBlock>(this)->HasPositionedObjects());
1403 
1404   DCHECK_EQ(this, child->Parent());
1405   DCHECK(!before_child || to_box_model_object == before_child->Parent());
1406 
1407   // If a child is moving from a block-flow to an inline-flow parent then any
1408   // floats currently intruding into the child can no longer do so. This can
1409   // happen if a block becomes floating or out-of-flow and is moved to an
1410   // anonymous block. Remove all floats from their float-lists immediately as
1411   // markAllDescendantsWithFloatsForLayout won't attempt to remove floats from
1412   // parents that have inline-flow if we try later.
1413   auto* child_block_flow = DynamicTo<LayoutBlockFlow>(child);
1414   if (child_block_flow && to_box_model_object->ChildrenInline() &&
1415       !ChildrenInline()) {
1416     child_block_flow->RemoveFloatingObjectsFromDescendants();
1417     DCHECK(!child_block_flow->ContainsFloats());
1418   }
1419 
1420   if (full_remove_insert && IsLayoutBlock() && child->IsBox())
1421     ToLayoutBox(child)->RemoveFromPercentHeightContainer();
1422 
1423   if (full_remove_insert && (to_box_model_object->IsLayoutBlock() ||
1424                              to_box_model_object->IsLayoutInline())) {
1425     // Takes care of adding the new child correctly if toBlock and fromBlock
1426     // have different kind of children (block vs inline).
1427     to_box_model_object->AddChild(
1428         VirtualChildren()->RemoveChildNode(this, child), before_child);
1429   } else {
1430     to_box_model_object->VirtualChildren()->InsertChildNode(
1431         to_box_model_object,
1432         VirtualChildren()->RemoveChildNode(this, child, full_remove_insert),
1433         before_child, full_remove_insert);
1434   }
1435 }
1436 
MoveChildrenTo(LayoutBoxModelObject * to_box_model_object,LayoutObject * start_child,LayoutObject * end_child,LayoutObject * before_child,bool full_remove_insert)1437 void LayoutBoxModelObject::MoveChildrenTo(
1438     LayoutBoxModelObject* to_box_model_object,
1439     LayoutObject* start_child,
1440     LayoutObject* end_child,
1441     LayoutObject* before_child,
1442     bool full_remove_insert) {
1443   // This condition is rarely hit since this function is usually called on
1444   // anonymous blocks which can no longer carry positioned objects (see r120761)
1445   // or when fullRemoveInsert is false.
1446   auto* block = DynamicTo<LayoutBlock>(this);
1447   if (full_remove_insert && block) {
1448     block->RemovePositionedObjects(nullptr);
1449     block->RemoveFromPercentHeightContainer();
1450     auto* block_flow = DynamicTo<LayoutBlockFlow>(block);
1451     if (block_flow)
1452       block_flow->RemoveFloatingObjects();
1453   }
1454 
1455   DCHECK(!before_child || to_box_model_object == before_child->Parent());
1456   for (LayoutObject* child = start_child; child && child != end_child;) {
1457     // Save our next sibling as moveChildTo will clear it.
1458     LayoutObject* next_sibling = child->NextSibling();
1459     MoveChildTo(to_box_model_object, child, before_child, full_remove_insert);
1460     child = next_sibling;
1461   }
1462 }
1463 
BackgroundTransfersToView(const ComputedStyle * document_element_style) const1464 bool LayoutBoxModelObject::BackgroundTransfersToView(
1465     const ComputedStyle* document_element_style) const {
1466   // In our painter implementation, ViewPainter instead of the painter of the
1467   // layout object of the document element paints the view background.
1468   if (IsDocumentElement())
1469     return true;
1470 
1471   // http://www.w3.org/TR/css3-background/#body-background
1472   // If the document element is <html> with no background, and a <body> child
1473   // element exists, the <body> element's background transfers to the document
1474   // element which in turn transfers to the view in our painter implementation.
1475   if (!IsBody())
1476     return false;
1477 
1478   Element* document_element = GetDocument().documentElement();
1479   if (!IsA<HTMLHtmlElement>(document_element))
1480     return false;
1481 
1482   if (!document_element_style)
1483     document_element_style = document_element->GetComputedStyle();
1484   DCHECK(document_element_style);
1485   if (document_element_style->HasBackground())
1486     return false;
1487 
1488   if (GetNode() != GetDocument().FirstBodyElement())
1489     return false;
1490 
1491   return true;
1492 }
1493 
1494 }  // namespace blink
1495