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, 2010 Apple Inc.
7  *               All rights reserved.
8  * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  *
25  */
26 
27 #include "third_party/blink/renderer/core/layout/layout_box.h"
28 
29 #include <math.h>
30 #include <algorithm>
31 #include <utility>
32 
33 #include "cc/input/scroll_snap_data.h"
34 #include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink.h"
35 #include "third_party/blink/public/platform/web_rect.h"
36 #include "third_party/blink/public/strings/grit/blink_strings.h"
37 #include "third_party/blink/renderer/core/dom/document.h"
38 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
39 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
40 #include "third_party/blink/renderer/core/editing/ime/input_method_controller.h"
41 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
42 #include "third_party/blink/renderer/core/frame/local_frame.h"
43 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
44 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
45 #include "third_party/blink/renderer/core/frame/settings.h"
46 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
47 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
48 #include "third_party/blink/renderer/core/html/forms/html_opt_group_element.h"
49 #include "third_party/blink/renderer/core/html/forms/html_select_element.h"
50 #include "third_party/blink/renderer/core/html/forms/html_text_area_element.h"
51 #include "third_party/blink/renderer/core/html/html_div_element.h"
52 #include "third_party/blink/renderer/core/html/html_element.h"
53 #include "third_party/blink/renderer/core/html/html_frame_element_base.h"
54 #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
55 #include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h"
56 #include "third_party/blink/renderer/core/html/shadow/shadow_element_utils.h"
57 #include "third_party/blink/renderer/core/input/event_handler.h"
58 #include "third_party/blink/renderer/core/input_type_names.h"
59 #include "third_party/blink/renderer/core/layout/api/line_layout_block_flow.h"
60 #include "third_party/blink/renderer/core/layout/api/line_layout_box.h"
61 #include "third_party/blink/renderer/core/layout/box_layout_extra_input.h"
62 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
63 #include "third_party/blink/renderer/core/layout/layout_analyzer.h"
64 #include "third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h"
65 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
66 #include "third_party/blink/renderer/core/layout/layout_fieldset.h"
67 #include "third_party/blink/renderer/core/layout/layout_file_upload_control.h"
68 #include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
69 #include "third_party/blink/renderer/core/layout/layout_grid.h"
70 #include "third_party/blink/renderer/core/layout/layout_inline.h"
71 #include "third_party/blink/renderer/core/layout/layout_list_marker.h"
72 #include "third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h"
73 #include "third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h"
74 #include "third_party/blink/renderer/core/layout/layout_table_cell.h"
75 #include "third_party/blink/renderer/core/layout/layout_text_control.h"
76 #include "third_party/blink/renderer/core/layout/layout_view.h"
77 #include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_child.h"
78 #include "third_party/blink/renderer/core/layout/ng/custom/layout_ng_custom.h"
79 #include "third_party/blink/renderer/core/layout/ng/custom/layout_worklet.h"
80 #include "third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.h"
81 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h"
82 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
83 #include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
84 #include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
85 #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
86 #include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h"
87 #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
88 #include "third_party/blink/renderer/core/layout/ng/ng_layout_utils.h"
89 #include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
90 #include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.h"
91 #include "third_party/blink/renderer/core/layout/shapes/shape_outside_info.h"
92 #include "third_party/blink/renderer/core/page/autoscroll_controller.h"
93 #include "third_party/blink/renderer/core/page/page.h"
94 #include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h"
95 #include "third_party/blink/renderer/core/paint/background_image_geometry.h"
96 #include "third_party/blink/renderer/core/paint/box_paint_invalidator.h"
97 #include "third_party/blink/renderer/core/paint/box_painter.h"
98 #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
99 #include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
100 #include "third_party/blink/renderer/core/paint/paint_layer.h"
101 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
102 #include "third_party/blink/renderer/core/paint/rounded_border_geometry.h"
103 #include "third_party/blink/renderer/core/style/shadow_list.h"
104 #include "third_party/blink/renderer/platform/geometry/double_rect.h"
105 #include "third_party/blink/renderer/platform/geometry/float_quad.h"
106 #include "third_party/blink/renderer/platform/geometry/float_rounded_rect.h"
107 #include "third_party/blink/renderer/platform/geometry/length_functions.h"
108 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
109 #include "third_party/blink/renderer/platform/text/platform_locale.h"
110 #include "third_party/blink/renderer/platform/wtf/size_assertions.h"
111 
112 namespace blink {
113 
114 // Used by flexible boxes when flexing this element and by table cells.
115 typedef WTF::HashMap<const LayoutBox*, LayoutUnit> OverrideSizeMap;
116 
117 // Size of border belt for autoscroll. When mouse pointer in border belt,
118 // autoscroll is started.
119 static const int kAutoscrollBeltSize = 20;
120 static const unsigned kBackgroundObscurationTestMaxDepth = 4;
121 
122 struct SameSizeAsLayoutBox : public LayoutBoxModelObject {
123   LayoutRect frame_rect;
124   LayoutSize previous_size;
125   LayoutUnit intrinsic_content_logical_height;
126   LayoutRectOutsets margin_box_outsets;
127   MinMaxSizes intrinsic_logical_widths;
128   LayoutUnit intrinsic_logical_widths_percentage_resolution_block_size;
129   void* pointers[4];
130   Vector<scoped_refptr<const NGLayoutResult>, 1> layout_results;
131   Persistent<void*> rare_data;
132 };
133 
134 ASSERT_SIZE(LayoutBox, SameSizeAsLayoutBox);
135 
136 namespace {
137 
TextAreaIntrinsicInlineSize(const HTMLTextAreaElement & textarea,const LayoutBox & box)138 LayoutUnit TextAreaIntrinsicInlineSize(const HTMLTextAreaElement& textarea,
139                                        const LayoutBox& box) {
140   // <textarea>'s intrinsic inline-size always contains the scrollbar thickness
141   // regardless of actual existence of a scrollbar.
142   //
143   // See |NGBlockLayoutAlgorithm::ComputeMinMaxSizes()| and |LayoutBlock::
144   // ComputeIntrinsicLogicalWidths()|.
145   return LayoutUnit(ceilf(LayoutTextControl::GetAvgCharWidth(box.StyleRef()) *
146                           textarea.cols())) +
147          LayoutTextControl::ScrollbarThickness(box);
148 }
149 
TextFieldIntrinsicInlineSize(const HTMLInputElement & input,const LayoutBox & box)150 LayoutUnit TextFieldIntrinsicInlineSize(const HTMLInputElement& input,
151                                         const LayoutBox& box) {
152   int factor;
153   const bool includes_decoration = input.SizeShouldIncludeDecoration(factor);
154   if (factor <= 0)
155     factor = 20;
156 
157   const float char_width = LayoutTextControl::GetAvgCharWidth(box.StyleRef());
158   LayoutUnit result = LayoutUnit::FromFloatCeil(char_width * factor);
159 
160   float max_char_width = 0.f;
161   const Font& font = box.StyleRef().GetFont();
162   if (LayoutTextControl::HasValidAvgCharWidth(font))
163     max_char_width = roundf(font.PrimaryFont()->MaxCharWidth());
164 
165   // For text inputs, IE adds some extra width.
166   if (max_char_width > 0.f)
167     result += max_char_width - char_width;
168 
169   if (includes_decoration) {
170     const auto* spin_button =
171         To<HTMLElement>(input.UserAgentShadowRoot()->getElementById(
172             shadow_element_names::kIdSpinButton));
173     if (LayoutBox* spin_box =
174             spin_button ? spin_button->GetLayoutBox() : nullptr) {
175       result += spin_box->BorderAndPaddingLogicalWidth();
176       // Since the width of spin_box is not calculated yet,
177       // spin_box->LogicalWidth() returns 0. Use the computed logical
178       // width instead.
179       result += spin_box->StyleRef().LogicalWidth().Value();
180     }
181   }
182 
183   return result;
184 }
185 
TextAreaIntrinsicBlockSize(const HTMLTextAreaElement & textarea,const LayoutBox & box)186 LayoutUnit TextAreaIntrinsicBlockSize(const HTMLTextAreaElement& textarea,
187                                       const LayoutBox& box) {
188   const auto* inner_editor = textarea.InnerEditorElement();
189   if (!inner_editor || !inner_editor->GetLayoutBox()) {
190     const LayoutUnit line_height = box.LineHeight(
191         true,
192         box.StyleRef().IsHorizontalWritingMode() ? kHorizontalLine
193                                                  : kVerticalLine,
194         kPositionOfInteriorLineBoxes);
195 
196     return line_height * textarea.rows();
197   }
198   const LayoutBox& inner_box = *inner_editor->GetLayoutBox();
199   const ComputedStyle& inner_style = inner_box.StyleRef();
200   // We are able to have a horizontal scrollbar if the overflow style is
201   // scroll, or if its auto and there's no word wrap.
202   int scrollbar_thickness = 0;
203   if (box.StyleRef().OverflowInlineDirection() == EOverflow::kScroll ||
204       (box.StyleRef().OverflowInlineDirection() == EOverflow::kAuto &&
205        inner_style.OverflowWrap() == EOverflowWrap::kNormal))
206     scrollbar_thickness = LayoutTextControl::ScrollbarThickness(box);
207   return inner_box.LineHeight(true,
208                               inner_style.IsHorizontalWritingMode()
209                                   ? kHorizontalLine
210                                   : kVerticalLine,
211                               kPositionOfInteriorLineBoxes) *
212              textarea.rows() +
213          scrollbar_thickness;
214 }
215 
TextFieldIntrinsicBlockSize(const HTMLInputElement & input,const LayoutBox & box)216 LayoutUnit TextFieldIntrinsicBlockSize(const HTMLInputElement& input,
217                                        const LayoutBox& box) {
218   const auto* inner_editor = input.InnerEditorElement();
219   // inner_editor's LayoutBox can be nullptr because web authors can set
220   // display:none to ::-webkit-textfield-decoration-container element.
221   const LayoutBox& target_box = (inner_editor && inner_editor->GetLayoutBox())
222                                     ? *inner_editor->GetLayoutBox()
223                                     : box;
224   return target_box.LineHeight(true,
225                                target_box.StyleRef().IsHorizontalWritingMode()
226                                    ? kHorizontalLine
227                                    : kVerticalLine,
228                                kPositionOfInteriorLineBoxes);
229 }
230 
FileUploadControlIntrinsicInlineSize(const HTMLInputElement & input,const LayoutBox & box)231 LayoutUnit FileUploadControlIntrinsicInlineSize(const HTMLInputElement& input,
232                                                 const LayoutBox& box) {
233   // Figure out how big the filename space needs to be for a given number of
234   // characters (using "0" as the nominal character).
235   constexpr int kDefaultWidthNumChars = 34;
236   constexpr UChar kCharacter = '0';
237   const String character_as_string = String(&kCharacter, 1);
238   const Font& font = box.StyleRef().GetFont();
239   const float min_default_label_width =
240       kDefaultWidthNumChars *
241       font.Width(ConstructTextRun(font, character_as_string, box.StyleRef(),
242                                   TextRun::kAllowTrailingExpansion));
243 
244   const String label =
245       input.GetLocale().QueryString(IDS_FORM_FILE_NO_FILE_LABEL);
246   float default_label_width = font.Width(ConstructTextRun(
247       font, label, box.StyleRef(), TextRun::kAllowTrailingExpansion));
248   if (HTMLInputElement* button = input.UploadButton()) {
249     if (LayoutObject* button_layout_object = button->GetLayoutObject()) {
250       default_label_width +=
251           button_layout_object->PreferredLogicalWidths().max_size +
252           LayoutFileUploadControl::kAfterButtonSpacing;
253     }
254   }
255   return LayoutUnit(
256       ceilf(std::max(min_default_label_width, default_label_width)));
257 }
258 
SliderIntrinsicInlineSize(const LayoutBox & box)259 LayoutUnit SliderIntrinsicInlineSize(const LayoutBox& box) {
260   constexpr int kDefaultTrackLength = 129;
261   return LayoutUnit(kDefaultTrackLength * box.StyleRef().EffectiveZoom());
262 }
263 
ListBoxDefaultItemHeight(const LayoutBox & box)264 LayoutUnit ListBoxDefaultItemHeight(const LayoutBox& box) {
265   constexpr int kDefaultPaddingBottom = 1;
266 
267   const SimpleFontData* font_data = box.StyleRef().GetFont().PrimaryFont();
268   if (!font_data)
269     return LayoutUnit();
270   return LayoutUnit(font_data->GetFontMetrics().Height() +
271                     kDefaultPaddingBottom);
272 }
273 
274 // TODO(crbug.com/1040826): This function is written in LayoutObject API
275 // so that this works in both of the legacy layout and LayoutNG. We
276 // should have LayoutNG-specific code.
ListBoxItemHeight(const HTMLSelectElement & select,const LayoutBox & box)277 LayoutUnit ListBoxItemHeight(const HTMLSelectElement& select,
278                              const LayoutBox& box) {
279   const auto& items = select.GetListItems();
280   if (items.IsEmpty() || box.ShouldApplySizeContainment())
281     return ListBoxDefaultItemHeight(box);
282 
283   LayoutUnit max_height;
284   for (Element* element : items) {
285     if (auto* optgroup = DynamicTo<HTMLOptGroupElement>(element))
286       element = &optgroup->OptGroupLabelElement();
287     LayoutUnit item_height;
288     if (auto* layout_box = element->GetLayoutBox())
289       item_height = layout_box->Size().Height();
290     else
291       item_height = ListBoxDefaultItemHeight(box);
292     max_height = std::max(max_height, item_height);
293   }
294   return max_height;
295 }
296 
MenuListIntrinsicInlineSize(const HTMLSelectElement & select,const LayoutBox & box)297 LayoutUnit MenuListIntrinsicInlineSize(const HTMLSelectElement& select,
298                                        const LayoutBox& box) {
299   const ComputedStyle& style = box.StyleRef();
300   float max_option_width = 0;
301   if (!box.ShouldApplySizeContainment()) {
302     for (auto* const option : select.GetOptionList()) {
303       String text = option->TextIndentedToRespectGroupLabel();
304       const ComputedStyle* item_style =
305           option->GetComputedStyle() ? option->GetComputedStyle() : &style;
306       item_style->ApplyTextTransform(&text);
307       // We apply SELECT's style, not OPTION's style because max_option_width is
308       // used to determine intrinsic width of the menulist box.
309       TextRun text_run = ConstructTextRun(style.GetFont(), text, style);
310       max_option_width =
311           std::max(max_option_width, style.GetFont().Width(text_run));
312     }
313   }
314 
315   LayoutTheme& theme = LayoutTheme::GetTheme();
316   int paddings = theme.PopupInternalPaddingStart(style) +
317                  theme.PopupInternalPaddingEnd(box.GetFrame(), style);
318   return LayoutUnit(ceilf(max_option_width)) + LayoutUnit(paddings);
319 }
320 
MenuListIntrinsicBlockSize(const HTMLSelectElement & select,const LayoutBox & box)321 LayoutUnit MenuListIntrinsicBlockSize(const HTMLSelectElement& select,
322                                       const LayoutBox& box) {
323   if (!box.StyleRef().HasEffectiveAppearance())
324     return kIndefiniteSize;
325   const SimpleFontData* font_data = box.StyleRef().GetFont().PrimaryFont();
326   DCHECK(font_data);
327   const LayoutBox* inner_box = select.InnerElement().GetLayoutBox();
328   return (font_data ? font_data->GetFontMetrics().Height() : 0) +
329          (inner_box ? inner_box->BorderAndPaddingLogicalHeight()
330                     : LayoutUnit());
331 }
332 
333 #if DCHECK_IS_ON()
CheckDidAddFragment(const LayoutBox & box,const NGPhysicalBoxFragment & new_fragment)334 void CheckDidAddFragment(const LayoutBox& box,
335                          const NGPhysicalBoxFragment& new_fragment) {
336   // If |HasFragmentItems|, |ChildrenInline()| should be true.
337   // |HasFragmentItems| uses this condition to optimize .
338   if (new_fragment.HasItems())
339     DCHECK(box.ChildrenInline());
340 
341   for (const NGPhysicalBoxFragment& fragment : box.PhysicalFragments()) {
342     if (const NGFragmentItems* fragment_items = fragment.Items())
343       fragment_items->CheckAllItemsAreValid();
344   }
345 }
346 #else
CheckDidAddFragment(const LayoutBox & box,const NGPhysicalBoxFragment & fragment)347 inline void CheckDidAddFragment(const LayoutBox& box,
348                                 const NGPhysicalBoxFragment& fragment) {}
349 #endif
350 
351 // Applies the overflow clip to |result|. For any axis that is clipped, |result|
352 // is reset to |no_overflow_rect|. If neither axis is clipped, nothing is
353 // changed.
ApplyOverflowClip(OverflowClipAxes overflow_clip_axes,const LayoutRect & no_overflow_rect,LayoutRect & result)354 void ApplyOverflowClip(OverflowClipAxes overflow_clip_axes,
355                        const LayoutRect& no_overflow_rect,
356                        LayoutRect& result) {
357   if (overflow_clip_axes & kOverflowClipX) {
358     result.SetX(no_overflow_rect.X());
359     result.SetWidth(no_overflow_rect.Width());
360   }
361   if (overflow_clip_axes & kOverflowClipY) {
362     result.SetY(no_overflow_rect.Y());
363     result.SetHeight(no_overflow_rect.Height());
364   }
365 }
366 
367 }  // namespace
368 
BoxLayoutExtraInput(LayoutBox & box)369 BoxLayoutExtraInput::BoxLayoutExtraInput(LayoutBox& box) : box(box) {
370   box.SetBoxLayoutExtraInput(this);
371 }
372 
~BoxLayoutExtraInput()373 BoxLayoutExtraInput::~BoxLayoutExtraInput() {
374   box.SetBoxLayoutExtraInput(nullptr);
375 }
376 
LayoutBoxRareData()377 LayoutBoxRareData::LayoutBoxRareData()
378     : spanner_placeholder_(nullptr),
379       override_logical_width_(-1),
380       override_logical_height_(-1),
381       // TODO(rego): We should store these based on physical direction.
382       has_override_containing_block_content_logical_width_(false),
383       has_override_containing_block_content_logical_height_(false),
384       has_override_percentage_resolution_block_size_(false),
385       has_previous_content_box_rect_(false),
386       percent_height_container_(nullptr),
387       snap_container_(nullptr),
388       snap_areas_(nullptr) {}
389 
Trace(Visitor * visitor) const390 void LayoutBoxRareData::Trace(Visitor* visitor) const {
391   visitor->Trace(layout_child_);
392 }
393 
LayoutBox(ContainerNode * node)394 LayoutBox::LayoutBox(ContainerNode* node)
395     : LayoutBoxModelObject(node),
396       intrinsic_content_logical_height_(-1),
397       intrinsic_logical_widths_percentage_resolution_block_size_(
398           LayoutUnit::Min()),
399       inline_box_wrapper_(nullptr) {
400   SetIsBox();
401   if (blink::IsA<HTMLLegendElement>(node))
402     SetIsHTMLLegendElement();
403 }
404 
405 LayoutBox::~LayoutBox() = default;
406 
LayerTypeRequired() const407 PaintLayerType LayoutBox::LayerTypeRequired() const {
408   NOT_DESTROYED();
409   if (IsStacked() || HasHiddenBackface() ||
410       (StyleRef().SpecifiesColumns() && !CanTraversePhysicalFragments()) ||
411       IsEffectiveRootScroller())
412     return kNormalPaintLayer;
413 
414   if (HasNonVisibleOverflow())
415     return kOverflowClipPaintLayer;
416 
417   if (StyleRef().IsScrollbarGutterForce())
418     return kNormalPaintLayer;
419 
420   return kNoPaintLayer;
421 }
422 
WillBeDestroyed()423 void LayoutBox::WillBeDestroyed() {
424   NOT_DESTROYED();
425   ClearOverrideSize();
426   ClearOverrideContainingBlockContentSize();
427   ClearOverridePercentageResolutionBlockSize();
428 
429   if (IsOutOfFlowPositioned())
430     LayoutBlock::RemovePositionedObject(this);
431   RemoveFromPercentHeightContainer();
432   if (IsOrthogonalWritingModeRoot() && !DocumentBeingDestroyed())
433     UnmarkOrthogonalWritingModeRoot();
434 
435   ShapeOutsideInfo::RemoveInfo(*this);
436 
437   if (!DocumentBeingDestroyed()) {
438     if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
439       if (NGPaintFragment* first_inline_fragment = FirstInlineFragment())
440         first_inline_fragment->LayoutObjectWillBeDestroyed();
441     } else if (FirstInlineFragmentItemIndex()) {
442       NGFragmentItems::LayoutObjectWillBeDestroyed(*this);
443       ClearFirstInlineFragmentItemIndex();
444     }
445     if (measure_result_)
446       measure_result_->PhysicalFragment().LayoutObjectWillBeDestroyed();
447     for (auto result : layout_results_)
448       result->PhysicalFragment().LayoutObjectWillBeDestroyed();
449     GetDocument()
450         .GetFrame()
451         ->GetInputMethodController()
452         .LayoutObjectWillBeDestroyed(*this);
453   }
454 
455   SetSnapContainer(nullptr);
456   LayoutBoxModelObject::WillBeDestroyed();
457 }
458 
InsertedIntoTree()459 void LayoutBox::InsertedIntoTree() {
460   NOT_DESTROYED();
461   LayoutBoxModelObject::InsertedIntoTree();
462   AddScrollSnapMapping();
463   AddCustomLayoutChildIfNeeded();
464 
465   if (IsOrthogonalWritingModeRoot())
466     MarkOrthogonalWritingModeRoot();
467 }
468 
WillBeRemovedFromTree()469 void LayoutBox::WillBeRemovedFromTree() {
470   NOT_DESTROYED();
471   if (!DocumentBeingDestroyed() && IsOrthogonalWritingModeRoot())
472     UnmarkOrthogonalWritingModeRoot();
473 
474   ClearCustomLayoutChild();
475   ClearScrollSnapMapping();
476   LayoutBoxModelObject::WillBeRemovedFromTree();
477 }
478 
RemoveFloatingOrPositionedChildFromBlockLists()479 void LayoutBox::RemoveFloatingOrPositionedChildFromBlockLists() {
480   NOT_DESTROYED();
481   DCHECK(IsFloatingOrOutOfFlowPositioned());
482 
483   if (DocumentBeingDestroyed())
484     return;
485 
486   if (IsFloating()) {
487     LayoutBlockFlow* parent_block_flow = nullptr;
488     for (LayoutObject* curr = Parent(); curr; curr = curr->Parent()) {
489       auto* curr_block_flow = DynamicTo<LayoutBlockFlow>(curr);
490       if (curr_block_flow) {
491         if (!parent_block_flow || curr_block_flow->ContainsFloat(this))
492           parent_block_flow = curr_block_flow;
493       }
494     }
495 
496     if (parent_block_flow) {
497       parent_block_flow->MarkSiblingsWithFloatsForLayout(this);
498       parent_block_flow->MarkAllDescendantsWithFloatsForLayout(this, false);
499     }
500   }
501 
502   if (IsOutOfFlowPositioned())
503     LayoutBlock::RemovePositionedObject(this);
504 }
505 
StyleWillChange(StyleDifference diff,const ComputedStyle & new_style)506 void LayoutBox::StyleWillChange(StyleDifference diff,
507                                 const ComputedStyle& new_style) {
508   NOT_DESTROYED();
509   const ComputedStyle* old_style = Style();
510   if (old_style) {
511     LayoutFlowThread* flow_thread = FlowThreadContainingBlock();
512     if (flow_thread && flow_thread != this)
513       flow_thread->FlowThreadDescendantStyleWillChange(this, diff, new_style);
514 
515     // The background of the root element or the body element could propagate up
516     // to the canvas. Just dirty the entire canvas when our style changes
517     // substantially.
518     if ((diff.NeedsPaintInvalidation() || diff.NeedsLayout()) && GetNode() &&
519         (IsDocumentElement() || IsA<HTMLBodyElement>(*GetNode()))) {
520       View()->SetShouldDoFullPaintInvalidation();
521     }
522 
523     // When a layout hint happens and an object's position style changes, we
524     // have to do a layout to dirty the layout tree using the old position
525     // value now.
526     if (diff.NeedsFullLayout() && Parent() &&
527         old_style->GetPosition() != new_style.GetPosition()) {
528       if (!old_style->HasOutOfFlowPosition() &&
529           new_style.HasOutOfFlowPosition()) {
530         // We're about to go out of flow. Before that takes place, we need to
531         // mark the current containing block chain for preferred widths
532         // recalculation.
533         SetNeedsLayoutAndIntrinsicWidthsRecalc(
534             layout_invalidation_reason::kStyleChange);
535 
536         if (IsInLayoutNGInlineFormattingContext() &&
537             RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled() &&
538             FirstInlineFragmentItemIndex()) {
539           // Out of flow are not part of |NGFragmentItems|, and that further
540           // changes including destruction cannot be tracked. Mark it is moved
541           // out from this IFC.
542           NGFragmentItems::LayoutObjectWillBeMoved(*this);
543           ClearFirstInlineFragmentItemIndex();
544         }
545       } else {
546         MarkContainerChainForLayout();
547       }
548       if (old_style->GetPosition() == EPosition::kStatic)
549         SetShouldDoFullPaintInvalidation();
550       else if (new_style.HasOutOfFlowPosition())
551         Parent()->SetChildNeedsLayout();
552       if (IsFloating() && !IsOutOfFlowPositioned() &&
553           new_style.HasOutOfFlowPosition())
554         RemoveFloatingOrPositionedChildFromBlockLists();
555     }
556     // FIXME: This branch runs when !oldStyle, which means that layout was never
557     // called so what's the point in invalidating the whole view that we never
558     // painted?
559   } else if (IsBody()) {
560     View()->SetShouldDoFullPaintInvalidation();
561   }
562 
563   LayoutBoxModelObject::StyleWillChange(diff, new_style);
564 }
565 
StyleDidChange(StyleDifference diff,const ComputedStyle * old_style)566 void LayoutBox::StyleDidChange(StyleDifference diff,
567                                const ComputedStyle* old_style) {
568   NOT_DESTROYED();
569   // Horizontal writing mode definition is updated in LayoutBoxModelObject::
570   // updateFromStyle, (as part of the LayoutBoxModelObject::styleDidChange call
571   // below). So, we can safely cache the horizontal writing mode value before
572   // style change here.
573   bool old_horizontal_writing_mode = IsHorizontalWritingMode();
574 
575   LayoutBoxModelObject::StyleDidChange(diff, old_style);
576 
577   // Reflection works through PaintLayer. Some child classes e.g. LayoutSVGBlock
578   // don't create layers and ignore reflections.
579   if (HasReflection() && !HasLayer())
580     SetHasReflection(false);
581 
582   auto* parent_flow_block = DynamicTo<LayoutBlockFlow>(Parent());
583   if (IsFloatingOrOutOfFlowPositioned() && old_style &&
584       !old_style->IsFloating() && !old_style->HasOutOfFlowPosition() &&
585       parent_flow_block)
586     parent_flow_block->ChildBecameFloatingOrOutOfFlow(this);
587 
588   const ComputedStyle& new_style = StyleRef();
589   if (NeedsLayout() && old_style)
590     RemoveFromPercentHeightContainer();
591 
592   if (old_horizontal_writing_mode != IsHorizontalWritingMode()) {
593     if (old_style) {
594       if (IsOrthogonalWritingModeRoot())
595         MarkOrthogonalWritingModeRoot();
596       else
597         UnmarkOrthogonalWritingModeRoot();
598     }
599 
600     ClearPercentHeightDescendants();
601   }
602 
603   SetOverflowClipAxes(ComputeOverflowClipAxes());
604 
605   // If our zoom factor changes and we have a defined scrollLeft/Top, we need to
606   // adjust that value into the new zoomed coordinate space.  Note that the new
607   // scroll offset may be outside the normal min/max range of the scrollable
608   // area, which is weird but OK, because the scrollable area will update its
609   // min/max in updateAfterLayout().
610   if (IsScrollContainer() && old_style &&
611       old_style->EffectiveZoom() != new_style.EffectiveZoom()) {
612     PaintLayerScrollableArea* scrollable_area = GetScrollableArea();
613     DCHECK(scrollable_area);
614     // We use getScrollOffset() rather than scrollPosition(), because scroll
615     // offset is the distance from the beginning of flow for the box, which is
616     // the dimension we want to preserve.
617     ScrollOffset old_offset = scrollable_area->GetScrollOffset();
618     if (old_offset.Width() || old_offset.Height()) {
619       ScrollOffset new_offset = old_offset.ScaledBy(new_style.EffectiveZoom() /
620                                                     old_style->EffectiveZoom());
621       scrollable_area->SetScrollOffsetUnconditionally(new_offset);
622     }
623   }
624 
625   UpdateShapeOutsideInfoAfterStyleChange(*Style(), old_style);
626   UpdateGridPositionAfterStyleChange(old_style);
627 
628   // When we're no longer a flex item because we're now absolutely positioned,
629   // we need to clear the override size so we're not affected by it anymore.
630   // This technically covers too many cases (even when out-of-flow did not
631   // change) but that should be harmless.
632   if (IsOutOfFlowPositioned() && Parent() &&
633       Parent()->StyleRef().IsDisplayFlexibleOrGridBox())
634     ClearOverrideSize();
635 
636   if (LayoutMultiColumnSpannerPlaceholder* placeholder = SpannerPlaceholder())
637     placeholder->LayoutObjectInFlowThreadStyleDidChange(old_style);
638 
639   UpdateBackgroundAttachmentFixedStatusAfterStyleChange();
640 
641   if (old_style) {
642     LayoutFlowThread* flow_thread = FlowThreadContainingBlock();
643     if (flow_thread && flow_thread != this)
644       flow_thread->FlowThreadDescendantStyleDidChange(this, diff, *old_style);
645 
646     UpdateScrollSnapMappingAfterStyleChange(*old_style);
647 
648     if (ShouldClipOverflowAlongEitherAxis()) {
649       // The overflow clip paint property depends on border sizes through
650       // overflowClipRect(), and border radii, so we update properties on
651       // border size or radii change.
652       //
653       // For some controls, it depends on paddings.
654       if (!old_style->BorderSizeEquals(new_style) ||
655           !old_style->RadiiEqual(new_style) ||
656           (HasControlClip() && !old_style->PaddingEqual(new_style))) {
657         SetNeedsPaintPropertyUpdate();
658         if (Layer())
659           Layer()->SetNeedsCompositingInputsUpdate();
660       }
661     }
662 
663     if (old_style->OverscrollBehaviorX() != new_style.OverscrollBehaviorX() ||
664         old_style->OverscrollBehaviorY() != new_style.OverscrollBehaviorY()) {
665       SetNeedsPaintPropertyUpdate();
666     }
667 
668     if (old_style->OverflowClipMargin() != new_style.OverflowClipMargin())
669       SetNeedsPaintPropertyUpdate();
670 
671     if (IsInLayoutNGInlineFormattingContext() && IsAtomicInlineLevel() &&
672         old_style->Direction() != new_style.Direction()) {
673       SetNeedsCollectInlines();
674     }
675   }
676 
677   // Update the script style map, from the new computed style.
678   if (IsCustomItem())
679     GetCustomLayoutChild()->styleMap()->UpdateStyle(GetDocument(), StyleRef());
680 
681   // Non-atomic inlines should be LayoutInline or LayoutText, not LayoutBox.
682   DCHECK(!IsInline() || IsAtomicInlineLevel());
683 }
684 
UpdateBackgroundAttachmentFixedStatusAfterStyleChange()685 void LayoutBox::UpdateBackgroundAttachmentFixedStatusAfterStyleChange() {
686   NOT_DESTROYED();
687   if (!GetFrameView())
688     return;
689 
690   SetIsBackgroundAttachmentFixedObject(
691       !BackgroundTransfersToView() &&
692       StyleRef().HasFixedAttachmentBackgroundImage());
693 }
694 
UpdateShapeOutsideInfoAfterStyleChange(const ComputedStyle & style,const ComputedStyle * old_style)695 void LayoutBox::UpdateShapeOutsideInfoAfterStyleChange(
696     const ComputedStyle& style,
697     const ComputedStyle* old_style) {
698   NOT_DESTROYED();
699   const ShapeValue* shape_outside = style.ShapeOutside();
700   const ShapeValue* old_shape_outside =
701       old_style ? old_style->ShapeOutside()
702                 : ComputedStyleInitialValues::InitialShapeOutside();
703 
704   const Length& shape_margin = style.ShapeMargin();
705   Length old_shape_margin =
706       old_style ? old_style->ShapeMargin()
707                 : ComputedStyleInitialValues::InitialShapeMargin();
708 
709   float shape_image_threshold = style.ShapeImageThreshold();
710   float old_shape_image_threshold =
711       old_style ? old_style->ShapeImageThreshold()
712                 : ComputedStyleInitialValues::InitialShapeImageThreshold();
713 
714   // FIXME: A future optimization would do a deep comparison for equality. (bug
715   // 100811)
716   if (shape_outside == old_shape_outside && shape_margin == old_shape_margin &&
717       shape_image_threshold == old_shape_image_threshold)
718     return;
719 
720   if (!shape_outside)
721     ShapeOutsideInfo::RemoveInfo(*this);
722   else
723     ShapeOutsideInfo::EnsureInfo(*this).MarkShapeAsDirty();
724 
725   if (shape_outside || shape_outside != old_shape_outside)
726     MarkShapeOutsideDependentsForLayout();
727 }
728 
UpdateGridPositionAfterStyleChange(const ComputedStyle * old_style)729 void LayoutBox::UpdateGridPositionAfterStyleChange(
730     const ComputedStyle* old_style) {
731   NOT_DESTROYED();
732   if (!old_style || !Parent() || !Parent()->IsLayoutGrid())
733     return;
734 
735   if (old_style->GridColumnStart() == StyleRef().GridColumnStart() &&
736       old_style->GridColumnEnd() == StyleRef().GridColumnEnd() &&
737       old_style->GridRowStart() == StyleRef().GridRowStart() &&
738       old_style->GridRowEnd() == StyleRef().GridRowEnd() &&
739       old_style->Order() == StyleRef().Order() &&
740       old_style->HasOutOfFlowPosition() == StyleRef().HasOutOfFlowPosition())
741     return;
742 
743   // Positioned items don't participate on the layout of the grid,
744   // so we don't need to mark the grid as dirty if they change positions.
745   if (old_style->HasOutOfFlowPosition() && StyleRef().HasOutOfFlowPosition())
746     return;
747 
748   // It should be possible to not dirty the grid in some cases (like moving an
749   // explicitly placed grid item).
750   // For now, it's more simple to just always recompute the grid.
751   ToLayoutGrid(Parent())->DirtyGrid();
752 }
753 
UpdateScrollSnapMappingAfterStyleChange(const ComputedStyle & old_style)754 void LayoutBox::UpdateScrollSnapMappingAfterStyleChange(
755     const ComputedStyle& old_style) {
756   NOT_DESTROYED();
757   DCHECK(Style());
758   SnapCoordinator& snap_coordinator = GetDocument().GetSnapCoordinator();
759   // scroll-snap-type and scroll-padding invalidate the snap container.
760   if (old_style.GetScrollSnapType() != StyleRef().GetScrollSnapType() ||
761       old_style.ScrollPaddingBottom() != StyleRef().ScrollPaddingBottom() ||
762       old_style.ScrollPaddingLeft() != StyleRef().ScrollPaddingLeft() ||
763       old_style.ScrollPaddingTop() != StyleRef().ScrollPaddingTop() ||
764       old_style.ScrollPaddingRight() != StyleRef().ScrollPaddingRight()) {
765     snap_coordinator.SnapContainerDidChange(*this);
766   }
767 
768   // scroll-snap-align, scroll-snap-stop and scroll-margin invalidate the snap
769   // area.
770   if (old_style.GetScrollSnapAlign() != StyleRef().GetScrollSnapAlign() ||
771       old_style.ScrollSnapStop() != StyleRef().ScrollSnapStop() ||
772       old_style.ScrollMarginBottom() != StyleRef().ScrollMarginBottom() ||
773       old_style.ScrollMarginLeft() != StyleRef().ScrollMarginLeft() ||
774       old_style.ScrollMarginTop() != StyleRef().ScrollMarginTop() ||
775       old_style.ScrollMarginRight() != StyleRef().ScrollMarginRight())
776     snap_coordinator.SnapAreaDidChange(*this, StyleRef().GetScrollSnapAlign());
777 
778   // Transform invalidates the snap area.
779   if (old_style.Transform() != StyleRef().Transform())
780     snap_coordinator.SnapAreaDidChange(*this, StyleRef().GetScrollSnapAlign());
781 }
782 
AddScrollSnapMapping()783 void LayoutBox::AddScrollSnapMapping() {
784   NOT_DESTROYED();
785   SnapCoordinator& snap_coordinator = GetDocument().GetSnapCoordinator();
786   snap_coordinator.SnapAreaDidChange(*this, Style()->GetScrollSnapAlign());
787 }
788 
ClearScrollSnapMapping()789 void LayoutBox::ClearScrollSnapMapping() {
790   NOT_DESTROYED();
791   SnapCoordinator& snap_coordinator = GetDocument().GetSnapCoordinator();
792   snap_coordinator.SnapAreaDidChange(*this, cc::ScrollSnapAlign());
793 }
794 
UpdateFromStyle()795 void LayoutBox::UpdateFromStyle() {
796   NOT_DESTROYED();
797   LayoutBoxModelObject::UpdateFromStyle();
798 
799   const ComputedStyle& style_to_use = StyleRef();
800   SetFloating(style_to_use.IsFloating() && !IsOutOfFlowPositioned() &&
801               !style_to_use.IsFlexOrGridItem());
802   SetHasTransformRelatedProperty(style_to_use.HasTransformRelatedProperty());
803   SetHasReflection(style_to_use.BoxReflect());
804   // LayoutTable and LayoutTableCell will overwrite this flag if needed.
805   SetHasNonCollapsedBorderDecoration(style_to_use.HasBorderDecoration());
806 }
807 
LayoutSubtreeRoot()808 void LayoutBox::LayoutSubtreeRoot() {
809   NOT_DESTROYED();
810   if (RuntimeEnabledFeatures::LayoutNGEnabled() &&
811       !NGBlockNode::CanUseNewLayout(*this) && GetCachedLayoutResult()) {
812     // If this object is laid out by the legacy engine, while its containing
813     // block is laid out by NG, it means that we normally (when laying out
814     // starting at the real root, i.e. LayoutView) enter layout of this object
815     // from NG code. This takes care of setting up a BoxLayoutExtraInput
816     // structure, which makes legacy layout behave when managed by NG. Make a
817     // short detour via NG just to set things up to re-enter legacy layout
818     // correctly.
819     DCHECK_EQ(PhysicalFragmentCount(), 1u);
820     LayoutPoint old_location = Location();
821 
822     // Make a copy of the cached constraint space, since we'll overwrite the
823     // layout result object as part of performing layout.
824     auto constraint_space =
825         GetCachedLayoutResult()->GetConstraintSpaceForCaching();
826 
827     NGBlockNode(this).Layout(constraint_space);
828 
829     // Restore the old location. While it's usually the job of the containing
830     // block to position its children, out-of-flow positioned objects set
831     // their own position, which could be wrong in this case.
832     SetLocation(old_location);
833   } else {
834     UpdateLayout();
835   }
836 
837   // If this box has an associated layout-result, rebuild the spine of the
838   // fragment-tree to ensure consistency.
839   if (PhysicalFragmentCount() &&
840       RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
841     LayoutBlock* cb = ContainingBlock();
842     while (NGBlockNode::CanUseNewLayout(*cb) && !cb->NeedsLayout()) {
843       // Create and set a new identical results.
844       if (cb->measure_result_) {
845         cb->measure_result_ =
846             NGLayoutResult::CloneWithPostLayoutFragments(*cb->measure_result_);
847       }
848       for (scoped_refptr<const NGLayoutResult>& layout_result :
849            cb->layout_results_) {
850         layout_result =
851             NGLayoutResult::CloneWithPostLayoutFragments(*layout_result);
852       }
853       cb = cb->ContainingBlock();
854     }
855   }
856 
857   GetDocument().GetFrame()->GetInputMethodController().DidLayoutSubtree(*this);
858 }
859 
UpdateLayout()860 void LayoutBox::UpdateLayout() {
861   NOT_DESTROYED();
862   DCHECK(NeedsLayout());
863   LayoutAnalyzer::Scope analyzer(*this);
864 
865   if (ChildLayoutBlockedByDisplayLock())
866     return;
867 
868   LayoutObject* child = SlowFirstChild();
869   if (!child) {
870     ClearNeedsLayout();
871     return;
872   }
873 
874   LayoutState state(*this);
875   while (child) {
876     child->LayoutIfNeeded();
877     DCHECK(!child->NeedsLayout());
878     child = child->NextSibling();
879   }
880   UpdateAfterLayout();
881   ClearNeedsLayout();
882   NotifyDisplayLockDidLayoutChildren();
883 }
884 
885 // ClientWidth and ClientHeight represent the interior of an object excluding
886 // border and scrollbar.
887 DISABLE_CFI_PERF
ClientWidth() const888 LayoutUnit LayoutBox::ClientWidth() const {
889   NOT_DESTROYED();
890   // We need to clamp negative values. This function may be called during layout
891   // before frame_rect_ gets the final proper value. Another reason: While
892   // border side values are currently limited to 2^20px (a recent change in the
893   // code), if this limit is raised again in the future, we'd have ill effects
894   // of saturated arithmetic otherwise.
895   if (CanSkipComputeScrollbars()) {
896     return (frame_rect_.Width() - BorderLeft() - BorderRight())
897         .ClampNegativeToZero();
898   } else {
899     return (frame_rect_.Width() - BorderLeft() - BorderRight() -
900             ComputeScrollbarsInternal(kClampToContentBox).HorizontalSum())
901         .ClampNegativeToZero();
902   }
903 }
904 
905 DISABLE_CFI_PERF
ClientHeight() const906 LayoutUnit LayoutBox::ClientHeight() const {
907   NOT_DESTROYED();
908   // We need to clamp negative values. This function can be called during layout
909   // before frame_rect_ gets the final proper value. The scrollbar may be wider
910   // than the padding box. Another reason: While border side values are
911   // currently limited to 2^20px (a recent change in the code), if this limit is
912   // raised again in the future, we'd have ill effects of saturated arithmetic
913   // otherwise.
914   if (CanSkipComputeScrollbars()) {
915     return (frame_rect_.Height() - BorderTop() - BorderBottom())
916         .ClampNegativeToZero();
917   } else {
918     return (frame_rect_.Height() - BorderTop() - BorderBottom() -
919             ComputeScrollbarsInternal(kClampToContentBox).VerticalSum())
920         .ClampNegativeToZero();
921   }
922 }
923 
PixelSnappedClientWidth() const924 int LayoutBox::PixelSnappedClientWidth() const {
925   NOT_DESTROYED();
926   return SnapSizeToPixel(ClientWidth(), Location().X() + ClientLeft());
927 }
928 
929 DISABLE_CFI_PERF
PixelSnappedClientHeight() const930 int LayoutBox::PixelSnappedClientHeight() const {
931   NOT_DESTROYED();
932   return SnapSizeToPixel(ClientHeight(), Location().Y() + ClientTop());
933 }
934 
PixelSnappedClientWidthWithTableSpecialBehavior() const935 int LayoutBox::PixelSnappedClientWidthWithTableSpecialBehavior() const {
936   NOT_DESTROYED();
937   // clientWidth/Height is the visual portion of the box content, not including
938   // borders or scroll bars, but includes padding. And per
939   // https://www.w3.org/TR/CSS2/tables.html#model,
940   // table wrapper box is a principal block box that contains the table box
941   // itself and any caption boxes, and table grid box is a block-level box that
942   // contains the table's internal table boxes. When table's border is specified
943   // in CSS, the border is added to table grid box, not table wrapper box.
944   // Currently, Blink doesn't have table wrapper box, and we are supposed to
945   // retrieve clientWidth/Height from table wrapper box, not table grid box. So
946   // when we retrieve clientWidth/Height, it includes table's border size.
947   LayoutUnit client_width = ClientWidth();
948   if (IsTable())
949     client_width += BorderLeft() + BorderRight();
950   return SnapSizeToPixel(client_width, Location().X() + ClientLeft());
951 }
952 
953 DISABLE_CFI_PERF
PixelSnappedClientHeightWithTableSpecialBehavior() const954 int LayoutBox::PixelSnappedClientHeightWithTableSpecialBehavior() const {
955   NOT_DESTROYED();
956   // clientWidth/Height is the visual portion of the box content, not including
957   // borders or scroll bars, but includes padding. And per
958   // https://www.w3.org/TR/CSS2/tables.html#model,
959   // table wrapper box is a principal block box that contains the table box
960   // itself and any caption boxes, and table grid box is a block-level box that
961   // contains the table's internal table boxes. When table's border is specified
962   // in CSS, the border is added to table grid box, not table wrapper box.
963   // Currently, Blink doesn't have table wrapper box, and we are supposed to
964   // retrieve clientWidth/Height from table wrapper box, not table grid box. So
965   // when we retrieve clientWidth/Height, it includes table's border size.
966   LayoutUnit client_height = ClientHeight();
967   if (IsTable())
968     client_height += BorderTop() + BorderBottom();
969   return SnapSizeToPixel(client_height, Location().Y() + ClientTop());
970 }
971 
PixelSnappedOffsetWidth(const Element *) const972 int LayoutBox::PixelSnappedOffsetWidth(const Element*) const {
973   NOT_DESTROYED();
974   return SnapSizeToPixel(OffsetWidth(), Location().X() + ClientLeft());
975 }
976 
PixelSnappedOffsetHeight(const Element *) const977 int LayoutBox::PixelSnappedOffsetHeight(const Element*) const {
978   NOT_DESTROYED();
979   return SnapSizeToPixel(OffsetHeight(), Location().Y() + ClientTop());
980 }
981 
ScrollWidth() const982 LayoutUnit LayoutBox::ScrollWidth() const {
983   NOT_DESTROYED();
984   if (IsScrollContainer() || StyleRef().IsScrollbarGutterForce())
985     return GetScrollableArea()->ScrollWidth();
986   // For objects with visible overflow, this matches IE.
987   // FIXME: Need to work right with writing modes.
988   if (StyleRef().IsLeftToRightDirection())
989     return std::max(ClientWidth(), LayoutOverflowRect().MaxX() - BorderLeft());
990   return ClientWidth() -
991          std::min(LayoutUnit(), LayoutOverflowRect().X() - BorderLeft());
992 }
993 
ScrollHeight() const994 LayoutUnit LayoutBox::ScrollHeight() const {
995   NOT_DESTROYED();
996   if (IsScrollContainer() || StyleRef().IsScrollbarGutterForce())
997     return GetScrollableArea()->ScrollHeight();
998   // For objects with visible overflow, this matches IE.
999   // FIXME: Need to work right with writing modes.
1000   return std::max(ClientHeight(), LayoutOverflowRect().MaxY() - BorderTop());
1001 }
1002 
PixelSnappedScrollWidth() const1003 int LayoutBox::PixelSnappedScrollWidth() const {
1004   NOT_DESTROYED();
1005   return SnapSizeToPixel(ScrollWidth(), Location().X() + ClientLeft());
1006 }
1007 
PixelSnappedScrollHeight() const1008 int LayoutBox::PixelSnappedScrollHeight() const {
1009   NOT_DESTROYED();
1010   if (IsScrollContainer())
1011     return SnapSizeToPixel(GetScrollableArea()->ScrollHeight(),
1012                            Location().Y() + ClientTop());
1013   // For objects with visible overflow, this matches IE.
1014   // FIXME: Need to work right with writing modes.
1015   return SnapSizeToPixel(ScrollHeight(), Location().Y() + ClientTop());
1016 }
1017 
ScrollRectToVisibleRecursive(const PhysicalRect & absolute_rect,mojom::blink::ScrollIntoViewParamsPtr params)1018 PhysicalRect LayoutBox::ScrollRectToVisibleRecursive(
1019     const PhysicalRect& absolute_rect,
1020     mojom::blink::ScrollIntoViewParamsPtr params) {
1021   NOT_DESTROYED();
1022   DCHECK(params->type == mojom::blink::ScrollType::kProgrammatic ||
1023          params->type == mojom::blink::ScrollType::kUser);
1024 
1025   if (!GetFrameView())
1026     return absolute_rect;
1027 
1028   // If we've reached the main frame's layout viewport (which is always set to
1029   // the global root scroller, see ViewportScrollCallback::SetScroller), abort
1030   // if the stop_at_main_frame_layout_viewport option is set. We do this so
1031   // that we can allow a smooth "scroll and zoom" animation to do the final
1032   // scroll in cases like scrolling a focused editable box into view.
1033   if (params->stop_at_main_frame_layout_viewport && IsGlobalRootScroller())
1034     return absolute_rect;
1035 
1036   PhysicalRect absolute_rect_to_scroll = absolute_rect;
1037   if (absolute_rect_to_scroll.Width() <= 0)
1038     absolute_rect_to_scroll.SetWidth(LayoutUnit(1));
1039   if (absolute_rect_to_scroll.Height() <= 0)
1040     absolute_rect_to_scroll.SetHeight(LayoutUnit(1));
1041 
1042   LayoutBox* parent_box = nullptr;
1043 
1044   if (ContainingBlock())
1045     parent_box = ContainingBlock();
1046 
1047   PhysicalRect absolute_rect_for_parent;
1048   if (!IsA<LayoutView>(this) && IsScrollContainer()) {
1049     absolute_rect_for_parent =
1050         GetScrollableArea()->ScrollIntoView(absolute_rect_to_scroll, params);
1051   } else if (!parent_box && CanBeProgramaticallyScrolled()) {
1052     ScrollableArea* area_to_scroll = params->make_visible_in_visual_viewport
1053                                          ? GetFrameView()->GetScrollableArea()
1054                                          : GetFrameView()->LayoutViewport();
1055     absolute_rect_for_parent =
1056         area_to_scroll->ScrollIntoView(absolute_rect_to_scroll, params);
1057 
1058     // If the parent is a local iframe, convert to the absolute coordinate
1059     // space of its document. For remote frames, this will happen on the other
1060     // end of the IPC call.
1061     HTMLFrameOwnerElement* owner_element = GetDocument().LocalOwner();
1062     if (owner_element && owner_element->GetLayoutObject() &&
1063         AllowedToPropagateRecursiveScrollToParentFrame(params)) {
1064       parent_box = owner_element->GetLayoutObject()->EnclosingBox();
1065       LayoutView* parent_view = owner_element->GetLayoutObject()->View();
1066       absolute_rect_for_parent = View()->LocalToAncestorRect(
1067           absolute_rect_for_parent, parent_view, kTraverseDocumentBoundaries);
1068     }
1069   } else {
1070     absolute_rect_for_parent = absolute_rect_to_scroll;
1071   }
1072 
1073   // If we're in a position:fixed element, scrolling the layout viewport won't
1074   // have any effect, so we avoid using the RootFrameViewport and explicitly
1075   // scroll the visual viewport if we can.  If not, we're done.
1076   if (StyleRef().GetPosition() == EPosition::kFixed && Container() == View() &&
1077       params->make_visible_in_visual_viewport) {
1078     if (GetFrame()->IsMainFrame()) {
1079       // TODO(donnd): We should continue the recursion if we're in a subframe.
1080       return GetFrame()->GetPage()->GetVisualViewport().ScrollIntoView(
1081           absolute_rect_for_parent, params);
1082     } else {
1083       return absolute_rect_for_parent;
1084     }
1085   }
1086 
1087   if (parent_box) {
1088     return parent_box->ScrollRectToVisibleRecursive(absolute_rect_for_parent,
1089                                                     std::move(params));
1090   } else if (GetFrame()->IsLocalRoot() && !GetFrame()->IsMainFrame()) {
1091     if (AllowedToPropagateRecursiveScrollToParentFrame(params)) {
1092       GetFrameView()->ScrollRectToVisibleInRemoteParent(
1093           absolute_rect_for_parent, std::move(params));
1094     }
1095   }
1096 
1097   return absolute_rect_for_parent;
1098 }
1099 
SetMargin(const NGPhysicalBoxStrut & box)1100 void LayoutBox::SetMargin(const NGPhysicalBoxStrut& box) {
1101   NOT_DESTROYED();
1102   margin_box_outsets_.SetTop(box.top);
1103   margin_box_outsets_.SetRight(box.right);
1104   margin_box_outsets_.SetBottom(box.bottom);
1105   margin_box_outsets_.SetLeft(box.left);
1106 }
1107 
AbsoluteQuads(Vector<FloatQuad> & quads,MapCoordinatesFlags mode) const1108 void LayoutBox::AbsoluteQuads(Vector<FloatQuad>& quads,
1109                               MapCoordinatesFlags mode) const {
1110   NOT_DESTROYED();
1111   if (LayoutFlowThread* flow_thread = FlowThreadContainingBlock()) {
1112     flow_thread->AbsoluteQuadsForDescendant(*this, quads, mode);
1113     return;
1114   }
1115   quads.push_back(LocalRectToAbsoluteQuad(PhysicalBorderBoxRect(), mode));
1116 }
1117 
LocalBoundingBoxRectForAccessibility() const1118 FloatRect LayoutBox::LocalBoundingBoxRectForAccessibility() const {
1119   NOT_DESTROYED();
1120   return FloatRect(0, 0, frame_rect_.Width().ToFloat(),
1121                    frame_rect_.Height().ToFloat());
1122 }
1123 
UpdateAfterLayout()1124 void LayoutBox::UpdateAfterLayout() {
1125   NOT_DESTROYED();
1126   // Transform-origin depends on box size, so we need to update the layer
1127   // transform after layout.
1128   if (HasLayer()) {
1129     Layer()->UpdateTransformationMatrix();
1130     Layer()->UpdateSizeAndScrollingAfterLayout();
1131   }
1132 
1133   // When we've finished layout, if we aren't a LayoutNG object, we need to
1134   // reset our cached layout result. LayoutNG inside of
1135   // |NGBlockNode::RunOldLayout| will call |LayoutBox::SetCachedLayoutResult|
1136   // with a new synthesized layout result.
1137   //
1138   // We also want to make sure that if our entrance point into layout changes,
1139   // e.g. an OOF-positioned object is laid out by an NG containing block, then
1140   // Legacy, then NG again, NG won't use a stale layout result.
1141   if (IsOutOfFlowPositioned() && !IsLayoutNGObject())
1142     ClearLayoutResults();
1143 
1144   Document& document = GetDocument();
1145   document.IncLayoutCallsCounter();
1146   document.GetFrame()->GetInputMethodController().DidUpdateLayout(*this);
1147   if (IsLayoutNGObject())
1148     document.IncLayoutCallsCounterNG();
1149 }
1150 
HasOverrideIntrinsicContentWidth() const1151 bool LayoutBox::HasOverrideIntrinsicContentWidth() const {
1152   NOT_DESTROYED();
1153   if (!ShouldApplySizeContainment())
1154     return false;
1155 
1156   const Length& intrinsic_length = StyleRef().ContainIntrinsicSize().Width();
1157   return !intrinsic_length.IsAuto();
1158 }
1159 
HasOverrideIntrinsicContentHeight() const1160 bool LayoutBox::HasOverrideIntrinsicContentHeight() const {
1161   NOT_DESTROYED();
1162   if (!ShouldApplySizeContainment())
1163     return false;
1164 
1165   const Length& intrinsic_length = StyleRef().ContainIntrinsicSize().Height();
1166   return !intrinsic_length.IsAuto();
1167 }
1168 
OverrideIntrinsicContentWidth() const1169 LayoutUnit LayoutBox::OverrideIntrinsicContentWidth() const {
1170   NOT_DESTROYED();
1171   DCHECK(HasOverrideIntrinsicContentWidth());
1172   const auto& style = StyleRef();
1173   const Length& intrinsic_length = style.ContainIntrinsicSize().Width();
1174   DCHECK(!intrinsic_length.IsAuto());
1175   DCHECK(intrinsic_length.IsFixed());
1176   DCHECK_GE(intrinsic_length.Value(), 0.f);
1177   return LayoutUnit(intrinsic_length.Value());
1178 }
1179 
OverrideIntrinsicContentHeight() const1180 LayoutUnit LayoutBox::OverrideIntrinsicContentHeight() const {
1181   NOT_DESTROYED();
1182   DCHECK(HasOverrideIntrinsicContentHeight());
1183   const auto& style = StyleRef();
1184   const Length& intrinsic_length = style.ContainIntrinsicSize().Height();
1185   DCHECK(!intrinsic_length.IsAuto());
1186   DCHECK(intrinsic_length.IsFixed());
1187   DCHECK_GE(intrinsic_length.Value(), 0.f);
1188   return LayoutUnit(intrinsic_length.Value());
1189 }
1190 
DefaultIntrinsicContentInlineSize() const1191 LayoutUnit LayoutBox::DefaultIntrinsicContentInlineSize() const {
1192   NOT_DESTROYED();
1193   // If the intrinsic-inline-size is specified, then we shouldn't ever need to
1194   // get here.
1195   DCHECK(!HasOverrideIntrinsicContentLogicalWidth());
1196 
1197   if (!IsA<Element>(GetNode()))
1198     return kIndefiniteSize;
1199   const Element& element = *To<Element>(GetNode());
1200 
1201   auto* select = DynamicTo<HTMLSelectElement>(element);
1202   if (UNLIKELY(select && select->UsesMenuList())) {
1203     return MenuListIntrinsicInlineSize(*select, *this);
1204   }
1205   auto* input = DynamicTo<HTMLInputElement>(element);
1206   if (UNLIKELY(input)) {
1207     if (input->IsTextField())
1208       return TextFieldIntrinsicInlineSize(*input, *this);
1209     const AtomicString& type = input->type();
1210     if (type == input_type_names::kFile)
1211       return FileUploadControlIntrinsicInlineSize(*input, *this);
1212     else if (type == input_type_names::kRange)
1213       return SliderIntrinsicInlineSize(*this);
1214     return kIndefiniteSize;
1215   }
1216   auto* textarea = DynamicTo<HTMLTextAreaElement>(element);
1217   if (UNLIKELY(textarea))
1218     return TextAreaIntrinsicInlineSize(*textarea, *this);
1219 
1220   if (IsSliderContainer(element))
1221     return SliderIntrinsicInlineSize(*this);
1222   return kIndefiniteSize;
1223 }
1224 
DefaultIntrinsicContentBlockSize() const1225 LayoutUnit LayoutBox::DefaultIntrinsicContentBlockSize() const {
1226   NOT_DESTROYED();
1227   // If the intrinsic-block-size is specified, then we shouldn't ever need to
1228   // get here.
1229   DCHECK(!HasOverrideIntrinsicContentLogicalHeight());
1230 
1231   if (const auto* select = DynamicTo<HTMLSelectElement>(GetNode())) {
1232     if (select->UsesMenuList()) {
1233       return MenuListIntrinsicBlockSize(*select, *this);
1234     } else {
1235       return ListBoxItemHeight(*select, *this) * select->ListBoxSize() -
1236              ComputeLogicalScrollbars().BlockSum();
1237     }
1238   } else if (IsTextFieldIncludingNG()) {
1239     return TextFieldIntrinsicBlockSize(*To<HTMLInputElement>(GetNode()), *this);
1240   } else if (IsTextAreaIncludingNG()) {
1241     return TextAreaIntrinsicBlockSize(*To<HTMLTextAreaElement>(GetNode()),
1242                                       *this);
1243   }
1244   return kIndefiniteSize;
1245 }
1246 
LogicalHeightWithVisibleOverflow() const1247 LayoutUnit LayoutBox::LogicalHeightWithVisibleOverflow() const {
1248   NOT_DESTROYED();
1249   if (!LayoutOverflowIsSet() || IsScrollContainer() ||
1250       StyleRef().OverflowY() == EOverflow::kClip)
1251     return LogicalHeight();
1252   LayoutRect overflow = LayoutOverflowRect();
1253   if (StyleRef().IsHorizontalWritingMode())
1254     return overflow.MaxY();
1255   return overflow.MaxX();
1256 }
1257 
ConstrainLogicalWidthByMinMax(LayoutUnit logical_width,LayoutUnit available_width,const LayoutBlock * cb,bool allow_intrinsic) const1258 LayoutUnit LayoutBox::ConstrainLogicalWidthByMinMax(
1259     LayoutUnit logical_width,
1260     LayoutUnit available_width,
1261     const LayoutBlock* cb,
1262     bool allow_intrinsic) const {
1263   NOT_DESTROYED();
1264   const ComputedStyle& style_to_use = StyleRef();
1265 
1266   // This implements the transferred min/max sizes per
1267   // https://drafts.csswg.org/css-sizing-4/#aspect-ratio
1268   if (ShouldComputeLogicalHeightFromAspectRatio()) {
1269     MinMaxSizes transferred_min_max =
1270         ComputeMinMaxLogicalWidthFromAspectRatio();
1271     logical_width = transferred_min_max.ClampSizeToMinAndMax(logical_width);
1272   }
1273 
1274   if (!style_to_use.LogicalMaxWidth().IsNone() &&
1275       (allow_intrinsic ||
1276        !style_to_use.LogicalMaxWidth().IsContentOrIntrinsic())) {
1277     logical_width = std::min(
1278         logical_width,
1279         ComputeLogicalWidthUsing(kMaxSize, style_to_use.LogicalMaxWidth(),
1280                                  available_width, cb));
1281   }
1282 
1283   // If we have an aspect-ratio, check if we need to apply min-width: auto.
1284   Length min_length = style_to_use.LogicalMinWidth();
1285   if (!style_to_use.AspectRatio().IsAuto() &&
1286       style_to_use.LogicalWidth().IsAuto() && min_length.IsAuto() &&
1287       style_to_use.OverflowInlineDirection() == EOverflow::kVisible) {
1288     // Make sure we actually used the aspect ratio.
1289     if (ShouldComputeLogicalWidthFromAspectRatio())
1290       min_length = Length::MinIntrinsic();
1291   }
1292   if (!allow_intrinsic && style_to_use.LogicalMinWidth().IsContentOrIntrinsic())
1293     return logical_width;
1294   return std::max(logical_width, ComputeLogicalWidthUsing(kMinSize, min_length,
1295                                                           available_width, cb));
1296 }
1297 
ConstrainLogicalHeightByMinMax(LayoutUnit logical_height,LayoutUnit intrinsic_content_height) const1298 LayoutUnit LayoutBox::ConstrainLogicalHeightByMinMax(
1299     LayoutUnit logical_height,
1300     LayoutUnit intrinsic_content_height) const {
1301   NOT_DESTROYED();
1302   // Note that the values 'min-content', 'max-content' and 'fit-content' should
1303   // behave as the initial value if specified in the block direction.
1304   const Length& logical_max_height = StyleRef().LogicalMaxHeight();
1305   if (!logical_max_height.IsNone() && !logical_max_height.IsMinContent() &&
1306       !logical_max_height.IsMaxContent() &&
1307       !logical_max_height.IsMinIntrinsic() &&
1308       !logical_max_height.IsFitContent()) {
1309     LayoutUnit max_h = ComputeLogicalHeightUsing(kMaxSize, logical_max_height,
1310                                                  intrinsic_content_height);
1311     if (max_h != -1)
1312       logical_height = std::min(logical_height, max_h);
1313   }
1314   Length logical_min_height = StyleRef().LogicalMinHeight();
1315   if (logical_min_height.IsAuto() &&
1316       ShouldComputeLogicalHeightFromAspectRatio() &&
1317       intrinsic_content_height != kIndefiniteSize &&
1318       intrinsic_content_height != LayoutUnit::Max() &&
1319       StyleRef().OverflowBlockDirection() == EOverflow::kVisible) {
1320     logical_min_height = Length::Fixed(intrinsic_content_height);
1321   }
1322   if (logical_min_height.IsMinContent() || logical_min_height.IsMaxContent() ||
1323       logical_min_height.IsMinIntrinsic() || logical_min_height.IsFitContent())
1324     logical_min_height = Length::Auto();
1325   return std::max(logical_height,
1326                   ComputeLogicalHeightUsing(kMinSize, logical_min_height,
1327                                             intrinsic_content_height));
1328 }
1329 
ConstrainContentBoxLogicalHeightByMinMax(LayoutUnit logical_height,LayoutUnit intrinsic_content_height) const1330 LayoutUnit LayoutBox::ConstrainContentBoxLogicalHeightByMinMax(
1331     LayoutUnit logical_height,
1332     LayoutUnit intrinsic_content_height) const {
1333   NOT_DESTROYED();
1334   // If the min/max height and logical height are both percentages we take
1335   // advantage of already knowing the current resolved percentage height
1336   // to avoid recursing up through our containing blocks again to determine it.
1337   const ComputedStyle& style_to_use = StyleRef();
1338   if (!style_to_use.LogicalMaxHeight().IsNone()) {
1339     if (style_to_use.LogicalMaxHeight().IsPercent() &&
1340         style_to_use.LogicalHeight().IsPercent()) {
1341       LayoutUnit available_logical_height(
1342           logical_height / style_to_use.LogicalHeight().Value() * 100);
1343       logical_height = std::min(logical_height,
1344                                 ValueForLength(style_to_use.LogicalMaxHeight(),
1345                                                available_logical_height));
1346     } else {
1347       LayoutUnit max_height(ComputeContentLogicalHeight(
1348           kMaxSize, style_to_use.LogicalMaxHeight(), intrinsic_content_height));
1349       if (max_height != -1)
1350         logical_height = std::min(logical_height, max_height);
1351     }
1352   }
1353 
1354   if (style_to_use.LogicalMinHeight().IsPercent() &&
1355       style_to_use.LogicalHeight().IsPercent()) {
1356     LayoutUnit available_logical_height(
1357         logical_height / style_to_use.LogicalHeight().Value() * 100);
1358     logical_height =
1359         std::max(logical_height, ValueForLength(style_to_use.LogicalMinHeight(),
1360                                                 available_logical_height));
1361   } else {
1362     logical_height = std::max(
1363         logical_height,
1364         ComputeContentLogicalHeight(kMinSize, style_to_use.LogicalMinHeight(),
1365                                     intrinsic_content_height));
1366   }
1367 
1368   return logical_height;
1369 }
1370 
SetLocationAndUpdateOverflowControlsIfNeeded(const LayoutPoint & location)1371 void LayoutBox::SetLocationAndUpdateOverflowControlsIfNeeded(
1372     const LayoutPoint& location) {
1373   NOT_DESTROYED();
1374   if (!HasLayer()) {
1375     SetLocation(location);
1376     return;
1377   }
1378   // The Layer does not yet have the up to date subpixel accumulation
1379   // so we base the size strictly on the frame rect's location.
1380   IntSize old_pixel_snapped_border_rect_size =
1381       PixelSnappedBorderBoxRect().Size();
1382   SetLocation(location);
1383   // TODO(crbug.com/1020913): This is problematic because this function may be
1384   // called after layout of this LayoutBox. Changing scroll container size here
1385   // will cause inconsistent layout. Also we should be careful not to set
1386   // this LayoutBox NeedsLayout. This will be unnecessary when we support
1387   // subpixel layout of scrollable area and overflow controls.
1388   if (PixelSnappedBorderBoxRect().Size() !=
1389       old_pixel_snapped_border_rect_size) {
1390     bool needed_layout = NeedsLayout();
1391     PaintLayerScrollableArea::FreezeScrollbarsScope freeze_scrollbar;
1392     Layer()->UpdateSizeAndScrollingAfterLayout();
1393     // The above call should not schedule new NeedsLayout.
1394     DCHECK(needed_layout || !NeedsLayout());
1395   }
1396 }
1397 
AbsoluteContentQuad(MapCoordinatesFlags flags) const1398 FloatQuad LayoutBox::AbsoluteContentQuad(MapCoordinatesFlags flags) const {
1399   NOT_DESTROYED();
1400   PhysicalRect rect = PhysicalContentBoxRect();
1401   return LocalRectToAbsoluteQuad(rect, flags);
1402 }
1403 
PhysicalBackgroundRect(BackgroundRectType rect_type) const1404 PhysicalRect LayoutBox::PhysicalBackgroundRect(
1405     BackgroundRectType rect_type) const {
1406   NOT_DESTROYED();
1407   // If the background transfers to view, the used background of this object
1408   // is transparent.
1409   if (rect_type == kBackgroundKnownOpaqueRect && BackgroundTransfersToView())
1410     return PhysicalRect();
1411 
1412   EFillBox background_box = EFillBox::kText;
1413   // Find the largest background rect of the given opaqueness.
1414   if (const FillLayer* current = &(StyleRef().BackgroundLayers())) {
1415     do {
1416       const FillLayer* cur = current;
1417       current = current->Next();
1418       if (rect_type == kBackgroundKnownOpaqueRect) {
1419         if (cur->GetBlendMode() != BlendMode::kNormal ||
1420             cur->Composite() != kCompositeSourceOver)
1421           continue;
1422 
1423         bool layer_known_opaque = false;
1424         // Check if the image is opaque and fills the clip.
1425         if (const StyleImage* image = cur->GetImage()) {
1426           if ((cur->RepeatX() == EFillRepeat::kRepeatFill ||
1427                cur->RepeatX() == EFillRepeat::kRoundFill) &&
1428               (cur->RepeatY() == EFillRepeat::kRepeatFill ||
1429                cur->RepeatY() == EFillRepeat::kRoundFill) &&
1430               image->KnownToBeOpaque(GetDocument(), StyleRef())) {
1431             layer_known_opaque = true;
1432           }
1433         }
1434 
1435         // The background color is painted into the last layer.
1436         if (!cur->Next()) {
1437           Color background_color =
1438               ResolveColor(GetCSSPropertyBackgroundColor());
1439           if (!background_color.HasAlpha())
1440             layer_known_opaque = true;
1441         }
1442 
1443         // If neither the image nor the color are opaque then skip this layer.
1444         if (!layer_known_opaque)
1445           continue;
1446       }
1447       EFillBox current_clip = cur->Clip();
1448       // Restrict clip if attachment is local.
1449       if (current_clip == EFillBox::kBorder &&
1450           cur->Attachment() == EFillAttachment::kLocal)
1451         current_clip = EFillBox::kPadding;
1452 
1453       // If we're asking for the clip rect, a content-box clipped fill layer can
1454       // be scrolled into the padding box of the overflow container.
1455       if (rect_type == kBackgroundClipRect &&
1456           current_clip == EFillBox::kContent &&
1457           cur->Attachment() == EFillAttachment::kLocal) {
1458         current_clip = EFillBox::kPadding;
1459       }
1460 
1461       background_box = EnclosingFillBox(background_box, current_clip);
1462     } while (current);
1463   }
1464   switch (background_box) {
1465     case EFillBox::kBorder:
1466       return PhysicalBorderBoxRect();
1467     case EFillBox::kPadding:
1468       return PhysicalPaddingBoxRect();
1469     case EFillBox::kContent:
1470       return PhysicalContentBoxRect();
1471     default:
1472       break;
1473   }
1474   return PhysicalRect();
1475 }
1476 
AddOutlineRects(Vector<PhysicalRect> & rects,const PhysicalOffset & additional_offset,NGOutlineType) const1477 void LayoutBox::AddOutlineRects(Vector<PhysicalRect>& rects,
1478                                 const PhysicalOffset& additional_offset,
1479                                 NGOutlineType) const {
1480   NOT_DESTROYED();
1481   rects.emplace_back(additional_offset, Size());
1482 }
1483 
CanResize() const1484 bool LayoutBox::CanResize() const {
1485   NOT_DESTROYED();
1486   // We need a special case for <iframe> because they never have
1487   // hasOverflowClip(). However, they do "implicitly" clip their contents, so
1488   // we want to allow resizing them also.
1489   return (IsScrollContainer() || IsLayoutIFrame()) && StyleRef().HasResize();
1490 }
1491 
ComputeMinMaxLogicalWidthFromAspectRatio() const1492 MinMaxSizes LayoutBox::ComputeMinMaxLogicalWidthFromAspectRatio() const {
1493   NOT_DESTROYED();
1494   DCHECK_NE(StyleRef().AspectRatio().GetType(), EAspectRatioType::kAuto);
1495 
1496   // The spec requires us to clamp these by the specified size (it calls it the
1497   // preferred size). However, we actually don't need to worry about that,
1498   // because we only use this if the width is indefinite.
1499 
1500   // We do not need to compute the min/max inline sizes; as long as we always
1501   // apply the transferred min/max size before the explicit min/max size, the
1502   // result will be identical.
1503 
1504   LogicalSize ratio = StyleRef().LogicalAspectRatio();
1505   MinMaxSizes block_min_max{
1506       ConstrainLogicalHeightByMinMax(LayoutUnit(), kIndefiniteSize),
1507       ConstrainLogicalHeightByMinMax(LayoutUnit::Max(), kIndefiniteSize)};
1508   if (block_min_max.max_size == kIndefiniteSize)
1509     block_min_max.max_size = LayoutUnit::Max();
1510 
1511   NGBoxStrut border_padding(BorderStart() + ComputedCSSPaddingStart(),
1512                             BorderEnd() + ComputedCSSPaddingEnd(),
1513                             BorderBefore() + ComputedCSSPaddingBefore(),
1514                             BorderAfter() + ComputedCSSPaddingAfter());
1515 
1516   MinMaxSizes transferred_min_max = {LayoutUnit(), LayoutUnit::Max()};
1517   if (block_min_max.min_size > LayoutUnit()) {
1518     transferred_min_max.min_size = InlineSizeFromAspectRatio(
1519         border_padding, ratio, StyleRef().BoxSizing(), block_min_max.min_size);
1520   }
1521   if (block_min_max.max_size != LayoutUnit::Max()) {
1522     transferred_min_max.max_size = InlineSizeFromAspectRatio(
1523         border_padding, ratio, StyleRef().BoxSizing(), block_min_max.max_size);
1524   }
1525   // Minimum size wins over maximum size.
1526   transferred_min_max.max_size =
1527       std::max(transferred_min_max.max_size, transferred_min_max.min_size);
1528   return transferred_min_max;
1529 }
1530 
HasScrollbarGutters(ScrollbarOrientation orientation) const1531 bool LayoutBox::HasScrollbarGutters(ScrollbarOrientation orientation) const {
1532   NOT_DESTROYED();
1533   if (StyleRef().IsScrollbarGutterAuto())
1534     return false;
1535 
1536   bool is_stable = StyleRef().IsScrollbarGutterStable();
1537   bool is_always = StyleRef().IsScrollbarGutterAlways();
1538 
1539   if (!is_stable && !is_always)
1540     return false;
1541 
1542   if (orientation == kVerticalScrollbar) {
1543     EOverflow overflow = StyleRef().OverflowY();
1544     return (StyleRef().IsScrollbarGutterForce() ||
1545             overflow == EOverflow::kAuto || overflow == EOverflow::kScroll) &&
1546            StyleRef().IsHorizontalWritingMode() &&
1547            !(is_stable && UsesOverlayScrollbars());
1548   } else {
1549     EOverflow overflow = StyleRef().OverflowX();
1550     return (StyleRef().IsScrollbarGutterForce() ||
1551             overflow == EOverflow::kAuto || overflow == EOverflow::kScroll) &&
1552            !StyleRef().IsHorizontalWritingMode() &&
1553            !(is_stable && UsesOverlayScrollbars());
1554   }
1555 }
1556 
ComputeScrollbarsInternal(ShouldClampToContentBox clamp_to_content_box,OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const1557 NGPhysicalBoxStrut LayoutBox::ComputeScrollbarsInternal(
1558     ShouldClampToContentBox clamp_to_content_box,
1559     OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const {
1560   NOT_DESTROYED();
1561   NGPhysicalBoxStrut scrollbars;
1562   PaintLayerScrollableArea* scrollable_area = GetScrollableArea();
1563   if (!scrollable_area)
1564     return scrollbars;
1565 
1566   if (HasScrollbarGutters(kVerticalScrollbar)) {
1567     LayoutUnit gutter_size =
1568         LayoutUnit(scrollable_area->HypotheticalScrollbarThickness(
1569             kVerticalScrollbar, /* should_include_overlay_thickness */ true));
1570     if (ShouldPlaceVerticalScrollbarOnLeft()) {
1571       scrollbars.left = gutter_size;
1572       if (StyleRef().IsScrollbarGutterBoth())
1573         scrollbars.right = gutter_size;
1574     } else {
1575       scrollbars.right = gutter_size;
1576       if (StyleRef().IsScrollbarGutterBoth())
1577         scrollbars.left = gutter_size;
1578     }
1579   } else if (ShouldPlaceVerticalScrollbarOnLeft()) {
1580     scrollbars.left = LayoutUnit(scrollable_area->VerticalScrollbarWidth(
1581         overlay_scrollbar_clip_behavior));
1582   } else {
1583     scrollbars.right = LayoutUnit(scrollable_area->VerticalScrollbarWidth(
1584         overlay_scrollbar_clip_behavior));
1585   }
1586 
1587   if (HasScrollbarGutters(kHorizontalScrollbar)) {
1588     LayoutUnit gutter_size =
1589         LayoutUnit(scrollable_area->HypotheticalScrollbarThickness(
1590             kHorizontalScrollbar, /* should_include_overlay_thickness */ true));
1591     scrollbars.bottom = gutter_size;
1592     if (StyleRef().IsScrollbarGutterBoth())
1593       scrollbars.top = gutter_size;
1594   } else {
1595     scrollbars.bottom = LayoutUnit(scrollable_area->HorizontalScrollbarHeight(
1596         overlay_scrollbar_clip_behavior));
1597   }
1598 
1599   // Use the width of the vertical scrollbar, unless it's larger than the
1600   // logical width of the content box, in which case we'll use that instead.
1601   // Scrollbar handling is quite bad in such situations, and this code here
1602   // is just to make sure that left-hand scrollbars don't mess up
1603   // scrollWidth. For the full story, visit http://crbug.com/724255.
1604   if (scrollbars.left > 0 && clamp_to_content_box == kClampToContentBox) {
1605     LayoutUnit max_width = frame_rect_.Width() - BorderAndPaddingWidth();
1606     scrollbars.left =
1607         std::min(scrollbars.left, max_width.ClampNegativeToZero());
1608   }
1609 
1610   return scrollbars;
1611 }
1612 
CanBeScrolledAndHasScrollableArea() const1613 bool LayoutBox::CanBeScrolledAndHasScrollableArea() const {
1614   NOT_DESTROYED();
1615   return CanBeProgramaticallyScrolled() &&
1616          (PixelSnappedScrollHeight() != PixelSnappedClientHeight() ||
1617           PixelSnappedScrollWidth() != PixelSnappedClientWidth());
1618 }
1619 
CanBeProgramaticallyScrolled() const1620 bool LayoutBox::CanBeProgramaticallyScrolled() const {
1621   NOT_DESTROYED();
1622   Node* node = GetNode();
1623   if (node && node->IsDocumentNode())
1624     return true;
1625 
1626   if (!IsScrollContainer())
1627     return false;
1628 
1629   bool has_scrollable_overflow =
1630       HasScrollableOverflowX() || HasScrollableOverflowY();
1631   if (ScrollsOverflow() && has_scrollable_overflow)
1632     return true;
1633 
1634   return node && HasEditableStyle(*node);
1635 }
1636 
Autoscroll(const PhysicalOffset & position_in_root_frame)1637 void LayoutBox::Autoscroll(const PhysicalOffset& position_in_root_frame) {
1638   NOT_DESTROYED();
1639   LocalFrame* frame = GetFrame();
1640   if (!frame)
1641     return;
1642 
1643   LocalFrameView* frame_view = frame->View();
1644   if (!frame_view)
1645     return;
1646 
1647   PhysicalOffset absolute_position =
1648       frame_view->ConvertFromRootFrame(position_in_root_frame);
1649   ScrollRectToVisibleRecursive(
1650       PhysicalRect(absolute_position,
1651                    PhysicalSize(LayoutUnit(1), LayoutUnit(1))),
1652       ScrollAlignment::CreateScrollIntoViewParams(
1653           ScrollAlignment::ToEdgeIfNeeded(), ScrollAlignment::ToEdgeIfNeeded(),
1654           mojom::blink::ScrollType::kUser));
1655 }
1656 
CanAutoscroll() const1657 bool LayoutBox::CanAutoscroll() const {
1658   NOT_DESTROYED();
1659   // TODO(skobes): Remove one of these methods.
1660   return CanBeScrolledAndHasScrollableArea();
1661 }
1662 
1663 // If specified point is outside the border-belt-excluded box (the border box
1664 // inset by the autoscroll activation threshold), returned offset denotes
1665 // direction of scrolling.
CalculateAutoscrollDirection(const FloatPoint & point_in_root_frame) const1666 PhysicalOffset LayoutBox::CalculateAutoscrollDirection(
1667     const FloatPoint& point_in_root_frame) const {
1668   NOT_DESTROYED();
1669   if (!GetFrame())
1670     return PhysicalOffset();
1671 
1672   LocalFrameView* frame_view = GetFrame()->View();
1673   if (!frame_view)
1674     return PhysicalOffset();
1675 
1676   PhysicalRect absolute_scrolling_box(AbsoluteBoundingBoxRect());
1677 
1678   // Exclude scrollbars so the border belt (activation area) starts from the
1679   // scrollbar-content edge rather than the window edge.
1680   ExcludeScrollbars(absolute_scrolling_box,
1681                     kExcludeOverlayScrollbarSizeForHitTesting);
1682 
1683   PhysicalRect belt_box =
1684       View()->GetFrameView()->ConvertToRootFrame(absolute_scrolling_box);
1685   belt_box.Inflate(LayoutUnit(-kAutoscrollBeltSize));
1686   FloatPoint point = point_in_root_frame;
1687 
1688   if (point.X() < belt_box.X())
1689     point.Move(-kAutoscrollBeltSize, 0);
1690   else if (point.X() > belt_box.Right())
1691     point.Move(kAutoscrollBeltSize, 0);
1692 
1693   if (point.Y() < belt_box.Y())
1694     point.Move(0, -kAutoscrollBeltSize);
1695   else if (point.Y() > belt_box.Bottom())
1696     point.Move(0, kAutoscrollBeltSize);
1697 
1698   return PhysicalOffset::FromFloatSizeRound(point - point_in_root_frame);
1699 }
1700 
FindAutoscrollable(LayoutObject * layout_object,bool is_middle_click_autoscroll)1701 LayoutBox* LayoutBox::FindAutoscrollable(LayoutObject* layout_object,
1702                                          bool is_middle_click_autoscroll) {
1703   while (layout_object && !(layout_object->IsBox() &&
1704                             To<LayoutBox>(layout_object)->CanAutoscroll())) {
1705     // Do not start selection-based autoscroll when the node is inside a
1706     // fixed-position element.
1707     if (!is_middle_click_autoscroll && layout_object->IsBox() &&
1708         To<LayoutBox>(layout_object)->HasLayer() &&
1709         To<LayoutBox>(layout_object)->Layer()->FixedToViewport()) {
1710       return nullptr;
1711     }
1712 
1713     if (!layout_object->Parent() &&
1714         layout_object->GetNode() == layout_object->GetDocument() &&
1715         layout_object->GetDocument().LocalOwner()) {
1716       layout_object =
1717           layout_object->GetDocument().LocalOwner()->GetLayoutObject();
1718     } else {
1719       layout_object = layout_object->Parent();
1720     }
1721   }
1722 
1723   return DynamicTo<LayoutBox>(layout_object);
1724 }
1725 
HasHorizontallyScrollableAncestor(LayoutObject * layout_object)1726 bool LayoutBox::HasHorizontallyScrollableAncestor(LayoutObject* layout_object) {
1727   while (layout_object) {
1728     if (layout_object->IsBox() &&
1729         To<LayoutBox>(layout_object)->HasScrollableOverflowX())
1730       return true;
1731 
1732     // Scroll is not propagating.
1733     if (layout_object->StyleRef().OverscrollBehaviorX() !=
1734         EOverscrollBehavior::kAuto)
1735       break;
1736 
1737     if (!layout_object->Parent() &&
1738         layout_object->GetNode() == layout_object->GetDocument() &&
1739         layout_object->GetDocument().LocalOwner()) {
1740       layout_object =
1741           layout_object->GetDocument().LocalOwner()->GetLayoutObject();
1742     } else {
1743       layout_object = layout_object->Parent();
1744     }
1745   }
1746 
1747   return false;
1748 }
1749 
ScrollByRecursively(const ScrollOffset & delta)1750 void LayoutBox::ScrollByRecursively(const ScrollOffset& delta) {
1751   NOT_DESTROYED();
1752   if (delta.IsZero() || !IsScrollContainer())
1753     return;
1754 
1755   PaintLayerScrollableArea* scrollable_area = GetScrollableArea();
1756   DCHECK(scrollable_area);
1757   ScrollOffset new_scroll_offset = scrollable_area->GetScrollOffset() + delta;
1758   scrollable_area->SetScrollOffset(new_scroll_offset,
1759                                    mojom::blink::ScrollType::kProgrammatic);
1760 
1761   // If this layer can't do the scroll we ask the next layer up that can
1762   // scroll to try.
1763   ScrollOffset remaining_scroll_offset =
1764       new_scroll_offset - scrollable_area->GetScrollOffset();
1765   if (!remaining_scroll_offset.IsZero() && Parent()) {
1766     if (LayoutBox* scrollable_box = EnclosingScrollableBox())
1767       scrollable_box->ScrollByRecursively(remaining_scroll_offset);
1768 
1769     LocalFrame* frame = GetFrame();
1770     if (frame && frame->GetPage()) {
1771       frame->GetPage()
1772           ->GetAutoscrollController()
1773           .UpdateAutoscrollLayoutObject();
1774     }
1775   }
1776   // FIXME: If we didn't scroll the whole way, do we want to try looking at
1777   // the frames ownerElement?
1778   // https://bugs.webkit.org/show_bug.cgi?id=28237
1779 }
1780 
NeedsPreferredWidthsRecalculation() const1781 bool LayoutBox::NeedsPreferredWidthsRecalculation() const {
1782   NOT_DESTROYED();
1783   return StyleRef().PaddingStart().IsPercentOrCalc() ||
1784          StyleRef().PaddingEnd().IsPercentOrCalc();
1785 }
1786 
OriginAdjustmentForScrollbars() const1787 IntSize LayoutBox::OriginAdjustmentForScrollbars() const {
1788   NOT_DESTROYED();
1789   if (CanSkipComputeScrollbars()) {
1790     return IntSize();
1791   } else {
1792     NGPhysicalBoxStrut scrollbars =
1793         ComputeScrollbarsInternal(kClampToContentBox);
1794     return IntSize(scrollbars.left.ToInt(), scrollbars.top.ToInt());
1795   }
1796 }
1797 
ScrollOrigin() const1798 IntPoint LayoutBox::ScrollOrigin() const {
1799   NOT_DESTROYED();
1800   return GetScrollableArea() ? GetScrollableArea()->ScrollOrigin() : IntPoint();
1801 }
1802 
ScrolledContentOffset() const1803 LayoutSize LayoutBox::ScrolledContentOffset() const {
1804   NOT_DESTROYED();
1805   DCHECK(IsScrollContainer());
1806   DCHECK(GetScrollableArea());
1807   return LayoutSize(GetScrollableArea()->GetScrollOffset());
1808 }
1809 
PixelSnappedScrolledContentOffset() const1810 LayoutSize LayoutBox::PixelSnappedScrolledContentOffset() const {
1811   NOT_DESTROYED();
1812   DCHECK(IsScrollContainer());
1813   DCHECK(GetScrollableArea());
1814   return LayoutSize(GetScrollableArea()->ScrollOffsetInt());
1815 }
1816 
ClippingRect(const PhysicalOffset & location) const1817 PhysicalRect LayoutBox::ClippingRect(const PhysicalOffset& location) const {
1818   NOT_DESTROYED();
1819   PhysicalRect result(PhysicalRect::InfiniteIntRect());
1820   if (ShouldClipOverflowAlongEitherAxis())
1821     result = OverflowClipRect(location);
1822 
1823   if (HasClip())
1824     result.Intersect(ClipRect(location));
1825 
1826   return result;
1827 }
1828 
PerspectiveOrigin(const PhysicalSize * size) const1829 FloatPoint LayoutBox::PerspectiveOrigin(const PhysicalSize* size) const {
1830   if (!HasTransformRelatedProperty())
1831     return FloatPoint();
1832 
1833   // Use the |size| parameter instead of |Size()| if present.
1834   FloatSize float_size = size ? FloatSize(*size) : FloatSize(Size());
1835 
1836   return FloatPointForLengthPoint(StyleRef().PerspectiveOrigin(), float_size);
1837 }
1838 
MapVisualRectToContainer(const LayoutObject * container_object,const PhysicalOffset & container_offset,const LayoutObject * ancestor,VisualRectFlags visual_rect_flags,TransformState & transform_state) const1839 bool LayoutBox::MapVisualRectToContainer(
1840     const LayoutObject* container_object,
1841     const PhysicalOffset& container_offset,
1842     const LayoutObject* ancestor,
1843     VisualRectFlags visual_rect_flags,
1844     TransformState& transform_state) const {
1845   NOT_DESTROYED();
1846   bool container_preserve_3d = container_object->StyleRef().Preserves3D();
1847 
1848   TransformState::TransformAccumulation accumulation =
1849       container_preserve_3d ? TransformState::kAccumulateTransform
1850                             : TransformState::kFlattenTransform;
1851 
1852   // If there is no transform on this box, adjust for container offset and
1853   // container scrolling, then apply container clip.
1854   if (!ShouldUseTransformFromContainer(container_object)) {
1855     transform_state.Move(container_offset, accumulation);
1856     if (container_object->IsBox() && container_object != ancestor &&
1857         !To<LayoutBox>(container_object)
1858              ->MapContentsRectToBoxSpace(transform_state, accumulation, *this,
1859                                          visual_rect_flags)) {
1860       return false;
1861     }
1862     return true;
1863   }
1864 
1865   // Otherwise, do the following:
1866   // 1. Expand for pixel snapping.
1867   // 2. Generate transformation matrix combining, in this order
1868   //    a) transform,
1869   //    b) container offset,
1870   //    c) container scroll offset,
1871   //    d) perspective applied by container.
1872   // 3. Apply transform Transform+flattening.
1873   // 4. Apply container clip.
1874 
1875   // 1. Expand for pixel snapping.
1876   // Use EnclosingBoundingBox because we cannot properly compute pixel
1877   // snapping for painted elements within the transform since we don't know
1878   // the desired subpixel accumulation at this point, and the transform may
1879   // include a scale. This only makes sense for non-preserve3D.
1880   if (!StyleRef().Preserves3D()) {
1881     transform_state.Flatten();
1882     transform_state.SetQuad(
1883         FloatQuad(transform_state.LastPlanarQuad().EnclosingBoundingBox()));
1884   }
1885 
1886   // 2. Generate transformation matrix.
1887   // a) Transform.
1888   TransformationMatrix transform;
1889   if (Layer() && Layer()->Transform())
1890     transform.Multiply(Layer()->CurrentTransform());
1891 
1892   // b) Container offset.
1893   transform.PostTranslate(container_offset.left.ToFloat(),
1894                           container_offset.top.ToFloat());
1895 
1896   // c) Container scroll offset.
1897   if (container_object->IsBox() && container_object != ancestor &&
1898       To<LayoutBox>(container_object)->ContainedContentsScroll(*this)) {
1899     LayoutSize offset(
1900         -To<LayoutBox>(container_object)->ScrolledContentOffset());
1901     transform.PostTranslate(offset.Width(), offset.Height());
1902   }
1903 
1904   bool has_perspective = container_object && container_object->HasLayer() &&
1905                          container_object->StyleRef().HasPerspective();
1906   if (has_perspective && RuntimeEnabledFeatures::TransformInteropEnabled() &&
1907       container_object != NonAnonymousAncestor())
1908     has_perspective = false;
1909 
1910   // d) Perspective applied by container.
1911   if (has_perspective) {
1912     // Perspective on the container affects us, so we have to factor it in here.
1913     DCHECK(container_object->HasLayer());
1914     FloatPoint perspective_origin;
1915     if (const auto* container_box = DynamicTo<LayoutBox>(container_object))
1916       perspective_origin = container_box->PerspectiveOrigin();
1917 
1918     TransformationMatrix perspective_matrix;
1919     perspective_matrix.ApplyPerspective(
1920         container_object->StyleRef().Perspective());
1921     perspective_matrix.ApplyTransformOrigin(perspective_origin.X(),
1922                                             perspective_origin.Y(), 0);
1923 
1924     transform = perspective_matrix * transform;
1925   }
1926 
1927   // 3. Apply transform and flatten.
1928   transform_state.ApplyTransform(transform, accumulation);
1929   if (!container_preserve_3d)
1930     transform_state.Flatten();
1931 
1932   // 4. Apply container clip.
1933   if (container_object->IsBox() && container_object != ancestor &&
1934       container_object->HasClipRelatedProperty()) {
1935     return To<LayoutBox>(container_object)
1936         ->ApplyBoxClips(transform_state, accumulation, visual_rect_flags);
1937   }
1938 
1939   return true;
1940 }
1941 
MapContentsRectToBoxSpace(TransformState & transform_state,TransformState::TransformAccumulation accumulation,const LayoutObject & contents,VisualRectFlags visual_rect_flags) const1942 bool LayoutBox::MapContentsRectToBoxSpace(
1943     TransformState& transform_state,
1944     TransformState::TransformAccumulation accumulation,
1945     const LayoutObject& contents,
1946     VisualRectFlags visual_rect_flags) const {
1947   NOT_DESTROYED();
1948   if (!HasClipRelatedProperty())
1949     return true;
1950 
1951   if (ContainedContentsScroll(contents))
1952     transform_state.Move(PhysicalOffset(-ScrolledContentOffset()));
1953 
1954   return ApplyBoxClips(transform_state, accumulation, visual_rect_flags);
1955 }
1956 
ContainedContentsScroll(const LayoutObject & contents) const1957 bool LayoutBox::ContainedContentsScroll(const LayoutObject& contents) const {
1958   NOT_DESTROYED();
1959   if (IsA<LayoutView>(this) &&
1960       contents.StyleRef().GetPosition() == EPosition::kFixed) {
1961     return false;
1962   }
1963   return IsScrollContainer();
1964 }
1965 
ApplyBoxClips(TransformState & transform_state,TransformState::TransformAccumulation accumulation,VisualRectFlags visual_rect_flags) const1966 bool LayoutBox::ApplyBoxClips(
1967     TransformState& transform_state,
1968     TransformState::TransformAccumulation accumulation,
1969     VisualRectFlags visual_rect_flags) const {
1970   NOT_DESTROYED();
1971   // This won't work fully correctly for fixed-position elements, who should
1972   // receive CSS clip but for whom the current object is not in the containing
1973   // block chain.
1974   PhysicalRect clip_rect = ClippingRect(PhysicalOffset());
1975 
1976   transform_state.Flatten();
1977   PhysicalRect rect(transform_state.LastPlanarQuad().EnclosingBoundingBox());
1978   bool does_intersect;
1979   if (visual_rect_flags & kEdgeInclusive) {
1980     does_intersect = rect.InclusiveIntersect(clip_rect);
1981   } else {
1982     rect.Intersect(clip_rect);
1983     does_intersect = !rect.IsEmpty();
1984   }
1985   transform_state.SetQuad(FloatQuad(FloatRect(rect)));
1986 
1987   return does_intersect;
1988 }
1989 
PreferredLogicalWidths() const1990 MinMaxSizes LayoutBox::PreferredLogicalWidths() const {
1991   NOT_DESTROYED();
1992   NOTREACHED();
1993   return MinMaxSizes();
1994 }
1995 
IntrinsicLogicalWidths(MinMaxSizesType type) const1996 MinMaxSizes LayoutBox::IntrinsicLogicalWidths(MinMaxSizesType type) const {
1997   NOT_DESTROYED();
1998   if (!ShouldComputeSizeAsReplaced() && type == MinMaxSizesType::kContent &&
1999       !StyleRef().AspectRatio().IsAuto()) {
2000     MinMaxSizes sizes;
2001     if (ComputeLogicalWidthFromAspectRatio(&sizes.min_size)) {
2002       sizes.max_size = sizes.min_size;
2003       return sizes;
2004     }
2005   }
2006   const_cast<LayoutBox*>(this)->UpdateCachedIntrinsicLogicalWidthsIfNeeded();
2007   return intrinsic_logical_widths_;
2008 }
2009 
UpdateCachedIntrinsicLogicalWidthsIfNeeded()2010 void LayoutBox::UpdateCachedIntrinsicLogicalWidthsIfNeeded() {
2011   NOT_DESTROYED();
2012   if (!IntrinsicLogicalWidthsDirty())
2013     return;
2014 
2015 #if DCHECK_IS_ON()
2016   SetLayoutNeededForbiddenScope layout_forbidden_scope(*this);
2017 #endif
2018 
2019   intrinsic_logical_widths_ = ComputeIntrinsicLogicalWidths();
2020   intrinsic_logical_widths_percentage_resolution_block_size_ =
2021       LayoutUnit::Min();
2022   ClearIntrinsicLogicalWidthsDirty();
2023 }
2024 
OverrideLogicalWidth() const2025 LayoutUnit LayoutBox::OverrideLogicalWidth() const {
2026   NOT_DESTROYED();
2027   DCHECK(HasOverrideLogicalWidth());
2028   if (extra_input_ && extra_input_->override_inline_size)
2029     return *extra_input_->override_inline_size;
2030   return rare_data_->override_logical_width_;
2031 }
2032 
OverrideLogicalHeight() const2033 LayoutUnit LayoutBox::OverrideLogicalHeight() const {
2034   NOT_DESTROYED();
2035   DCHECK(HasOverrideLogicalHeight());
2036   if (extra_input_ && extra_input_->override_block_size)
2037     return *extra_input_->override_block_size;
2038   return rare_data_->override_logical_height_;
2039 }
2040 
IsOverrideLogicalHeightDefinite() const2041 bool LayoutBox::IsOverrideLogicalHeightDefinite() const {
2042   NOT_DESTROYED();
2043   return extra_input_ && extra_input_->is_override_block_size_definite;
2044 }
2045 
HasOverrideLogicalHeight() const2046 bool LayoutBox::HasOverrideLogicalHeight() const {
2047   NOT_DESTROYED();
2048   if (extra_input_ && extra_input_->override_block_size)
2049     return true;
2050   return rare_data_ && rare_data_->override_logical_height_ != -1;
2051 }
2052 
HasOverrideLogicalWidth() const2053 bool LayoutBox::HasOverrideLogicalWidth() const {
2054   NOT_DESTROYED();
2055   if (extra_input_ && extra_input_->override_inline_size)
2056     return true;
2057   return rare_data_ && rare_data_->override_logical_width_ != -1;
2058 }
2059 
SetOverrideLogicalHeight(LayoutUnit height)2060 void LayoutBox::SetOverrideLogicalHeight(LayoutUnit height) {
2061   NOT_DESTROYED();
2062   DCHECK(!extra_input_);
2063   DCHECK_GE(height, 0);
2064   EnsureRareData().override_logical_height_ = height;
2065 }
2066 
SetOverrideLogicalWidth(LayoutUnit width)2067 void LayoutBox::SetOverrideLogicalWidth(LayoutUnit width) {
2068   NOT_DESTROYED();
2069   DCHECK(!extra_input_);
2070   DCHECK_GE(width, 0);
2071   EnsureRareData().override_logical_width_ = width;
2072 }
2073 
ClearOverrideLogicalHeight()2074 void LayoutBox::ClearOverrideLogicalHeight() {
2075   NOT_DESTROYED();
2076   DCHECK(!extra_input_);
2077   if (rare_data_)
2078     rare_data_->override_logical_height_ = LayoutUnit(-1);
2079 }
2080 
ClearOverrideLogicalWidth()2081 void LayoutBox::ClearOverrideLogicalWidth() {
2082   NOT_DESTROYED();
2083   DCHECK(!extra_input_);
2084   if (rare_data_)
2085     rare_data_->override_logical_width_ = LayoutUnit(-1);
2086 }
2087 
ClearOverrideSize()2088 void LayoutBox::ClearOverrideSize() {
2089   NOT_DESTROYED();
2090   ClearOverrideLogicalHeight();
2091   ClearOverrideLogicalWidth();
2092 }
2093 
OverrideContentLogicalWidth() const2094 LayoutUnit LayoutBox::OverrideContentLogicalWidth() const {
2095   NOT_DESTROYED();
2096   return (OverrideLogicalWidth() - BorderAndPaddingLogicalWidth() -
2097           ComputeLogicalScrollbars().InlineSum())
2098       .ClampNegativeToZero();
2099 }
2100 
OverrideContentLogicalHeight() const2101 LayoutUnit LayoutBox::OverrideContentLogicalHeight() const {
2102   NOT_DESTROYED();
2103   return (OverrideLogicalHeight() - BorderAndPaddingLogicalHeight() -
2104           ComputeLogicalScrollbars().BlockSum())
2105       .ClampNegativeToZero();
2106 }
2107 
OverrideContainingBlockContentWidth() const2108 LayoutUnit LayoutBox::OverrideContainingBlockContentWidth() const {
2109   NOT_DESTROYED();
2110   DCHECK(HasOverrideContainingBlockContentWidth());
2111   return ContainingBlock()->StyleRef().IsHorizontalWritingMode()
2112              ? OverrideContainingBlockContentLogicalWidth()
2113              : OverrideContainingBlockContentLogicalHeight();
2114 }
2115 
OverrideContainingBlockContentHeight() const2116 LayoutUnit LayoutBox::OverrideContainingBlockContentHeight() const {
2117   NOT_DESTROYED();
2118   DCHECK(HasOverrideContainingBlockContentHeight());
2119   return ContainingBlock()->StyleRef().IsHorizontalWritingMode()
2120              ? OverrideContainingBlockContentLogicalHeight()
2121              : OverrideContainingBlockContentLogicalWidth();
2122 }
2123 
HasOverrideContainingBlockContentWidth() const2124 bool LayoutBox::HasOverrideContainingBlockContentWidth() const {
2125   NOT_DESTROYED();
2126   if (!ContainingBlock())
2127     return false;
2128 
2129   return ContainingBlock()->StyleRef().IsHorizontalWritingMode()
2130              ? HasOverrideContainingBlockContentLogicalWidth()
2131              : HasOverrideContainingBlockContentLogicalHeight();
2132 }
2133 
HasOverrideContainingBlockContentHeight() const2134 bool LayoutBox::HasOverrideContainingBlockContentHeight() const {
2135   NOT_DESTROYED();
2136   if (!ContainingBlock())
2137     return false;
2138 
2139   return ContainingBlock()->StyleRef().IsHorizontalWritingMode()
2140              ? HasOverrideContainingBlockContentLogicalHeight()
2141              : HasOverrideContainingBlockContentLogicalWidth();
2142 }
2143 
2144 // TODO (lajava) Shouldn't we implement these functions based on physical
2145 // direction ?.
OverrideContainingBlockContentLogicalWidth() const2146 LayoutUnit LayoutBox::OverrideContainingBlockContentLogicalWidth() const {
2147   NOT_DESTROYED();
2148   DCHECK(HasOverrideContainingBlockContentLogicalWidth());
2149   if (extra_input_)
2150     return extra_input_->containing_block_content_inline_size;
2151   return rare_data_->override_containing_block_content_logical_width_;
2152 }
2153 
2154 // TODO (lajava) Shouldn't we implement these functions based on physical
2155 // direction ?.
OverrideContainingBlockContentLogicalHeight() const2156 LayoutUnit LayoutBox::OverrideContainingBlockContentLogicalHeight() const {
2157   NOT_DESTROYED();
2158   DCHECK(HasOverrideContainingBlockContentLogicalHeight());
2159   if (extra_input_)
2160     return extra_input_->containing_block_content_block_size;
2161   return rare_data_->override_containing_block_content_logical_height_;
2162 }
2163 
2164 // TODO (lajava) Shouldn't we implement these functions based on physical
2165 // direction ?.
HasOverrideContainingBlockContentLogicalWidth() const2166 bool LayoutBox::HasOverrideContainingBlockContentLogicalWidth() const {
2167   NOT_DESTROYED();
2168   if (extra_input_)
2169     return true;
2170   return rare_data_ &&
2171          rare_data_->has_override_containing_block_content_logical_width_;
2172 }
2173 
2174 // TODO (lajava) Shouldn't we implement these functions based on physical
2175 // direction ?.
HasOverrideContainingBlockContentLogicalHeight() const2176 bool LayoutBox::HasOverrideContainingBlockContentLogicalHeight() const {
2177   NOT_DESTROYED();
2178   if (extra_input_)
2179     return true;
2180   return rare_data_ &&
2181          rare_data_->has_override_containing_block_content_logical_height_;
2182 }
2183 
2184 // TODO (lajava) Shouldn't we implement these functions based on physical
2185 // direction ?.
SetOverrideContainingBlockContentLogicalWidth(LayoutUnit logical_width)2186 void LayoutBox::SetOverrideContainingBlockContentLogicalWidth(
2187     LayoutUnit logical_width) {
2188   NOT_DESTROYED();
2189   DCHECK(!extra_input_);
2190   DCHECK_GE(logical_width, LayoutUnit(-1));
2191   EnsureRareData().override_containing_block_content_logical_width_ =
2192       logical_width;
2193   EnsureRareData().has_override_containing_block_content_logical_width_ = true;
2194 }
2195 
2196 // TODO (lajava) Shouldn't we implement these functions based on physical
2197 // direction ?.
SetOverrideContainingBlockContentLogicalHeight(LayoutUnit logical_height)2198 void LayoutBox::SetOverrideContainingBlockContentLogicalHeight(
2199     LayoutUnit logical_height) {
2200   NOT_DESTROYED();
2201   DCHECK(!extra_input_);
2202   DCHECK_GE(logical_height, LayoutUnit(-1));
2203   EnsureRareData().override_containing_block_content_logical_height_ =
2204       logical_height;
2205   EnsureRareData().has_override_containing_block_content_logical_height_ = true;
2206 }
2207 
2208 // TODO (lajava) Shouldn't we implement these functions based on physical
2209 // direction ?.
ClearOverrideContainingBlockContentSize()2210 void LayoutBox::ClearOverrideContainingBlockContentSize() {
2211   NOT_DESTROYED();
2212   DCHECK(!extra_input_);
2213   if (!rare_data_)
2214     return;
2215   EnsureRareData().has_override_containing_block_content_logical_width_ = false;
2216   EnsureRareData().has_override_containing_block_content_logical_height_ =
2217       false;
2218 }
2219 
OverridePercentageResolutionBlockSize() const2220 LayoutUnit LayoutBox::OverridePercentageResolutionBlockSize() const {
2221   NOT_DESTROYED();
2222   DCHECK(HasOverridePercentageResolutionBlockSize());
2223   return rare_data_->override_percentage_resolution_block_size_;
2224 }
2225 
HasOverridePercentageResolutionBlockSize() const2226 bool LayoutBox::HasOverridePercentageResolutionBlockSize() const {
2227   NOT_DESTROYED();
2228   return rare_data_ &&
2229          rare_data_->has_override_percentage_resolution_block_size_;
2230 }
2231 
SetOverridePercentageResolutionBlockSize(LayoutUnit logical_height)2232 void LayoutBox::SetOverridePercentageResolutionBlockSize(
2233     LayoutUnit logical_height) {
2234   NOT_DESTROYED();
2235   DCHECK_GE(logical_height, LayoutUnit(-1));
2236   auto& rare_data = EnsureRareData();
2237   rare_data.override_percentage_resolution_block_size_ = logical_height;
2238   rare_data.has_override_percentage_resolution_block_size_ = true;
2239 }
2240 
ClearOverridePercentageResolutionBlockSize()2241 void LayoutBox::ClearOverridePercentageResolutionBlockSize() {
2242   NOT_DESTROYED();
2243   if (!rare_data_)
2244     return;
2245   EnsureRareData().has_override_percentage_resolution_block_size_ = false;
2246 }
2247 
OverrideAvailableInlineSize() const2248 LayoutUnit LayoutBox::OverrideAvailableInlineSize() const {
2249   NOT_DESTROYED();
2250   DCHECK(HasOverrideAvailableInlineSize());
2251   if (extra_input_)
2252     return extra_input_->available_inline_size;
2253   return LayoutUnit();
2254 }
2255 
AdjustBorderBoxLogicalWidthForBoxSizing(float width) const2256 LayoutUnit LayoutBox::AdjustBorderBoxLogicalWidthForBoxSizing(
2257     float width) const {
2258   NOT_DESTROYED();
2259   LayoutUnit borders_plus_padding = CollapsedBorderAndCSSPaddingLogicalWidth();
2260   LayoutUnit result(width);
2261   if (StyleRef().BoxSizing() == EBoxSizing::kContentBox)
2262     return result + borders_plus_padding;
2263   return std::max(result, borders_plus_padding);
2264 }
2265 
AdjustBorderBoxLogicalHeightForBoxSizing(float height) const2266 LayoutUnit LayoutBox::AdjustBorderBoxLogicalHeightForBoxSizing(
2267     float height) const {
2268   NOT_DESTROYED();
2269   LayoutUnit borders_plus_padding = CollapsedBorderAndCSSPaddingLogicalHeight();
2270   LayoutUnit result(height);
2271   if (StyleRef().BoxSizing() == EBoxSizing::kContentBox)
2272     return result + borders_plus_padding;
2273   return std::max(result, borders_plus_padding);
2274 }
2275 
AdjustContentBoxLogicalWidthForBoxSizing(float width) const2276 LayoutUnit LayoutBox::AdjustContentBoxLogicalWidthForBoxSizing(
2277     float width) const {
2278   NOT_DESTROYED();
2279   LayoutUnit result(width);
2280   if (StyleRef().BoxSizing() == EBoxSizing::kBorderBox)
2281     result -= CollapsedBorderAndCSSPaddingLogicalWidth();
2282   return std::max(LayoutUnit(), result);
2283 }
2284 
AdjustContentBoxLogicalHeightForBoxSizing(float height) const2285 LayoutUnit LayoutBox::AdjustContentBoxLogicalHeightForBoxSizing(
2286     float height) const {
2287   NOT_DESTROYED();
2288   LayoutUnit result(height);
2289   if (StyleRef().BoxSizing() == EBoxSizing::kBorderBox)
2290     result -= CollapsedBorderAndCSSPaddingLogicalHeight();
2291   return std::max(LayoutUnit(), result);
2292 }
2293 
2294 // Hit Testing
MayIntersect(const HitTestResult & result,const HitTestLocation & hit_test_location,const PhysicalOffset & accumulated_offset) const2295 bool LayoutBox::MayIntersect(const HitTestResult& result,
2296                              const HitTestLocation& hit_test_location,
2297                              const PhysicalOffset& accumulated_offset) const {
2298   NOT_DESTROYED();
2299   // Check if we need to do anything at all.
2300   // If we have clipping, then we can't have any spillout.
2301   // TODO(pdr): Why is this optimization not valid for the effective root?
2302   if (UNLIKELY(IsEffectiveRootScroller()))
2303     return true;
2304 
2305   PhysicalRect overflow_box;
2306   if (result.GetHitTestRequest().GetType() &
2307       HitTestRequest::kHitTestVisualOverflow) {
2308     overflow_box = PhysicalVisualOverflowRectIncludingFilters();
2309   } else {
2310     // Unite because overflow may not include borders.
2311     overflow_box = PhysicalBorderBoxRect();
2312     if (!ShouldClipOverflowAlongBothAxis() && HasVisualOverflow())
2313       overflow_box.Unite(PhysicalVisualOverflowRect());
2314   }
2315 
2316   overflow_box.Move(accumulated_offset);
2317   return hit_test_location.Intersects(overflow_box);
2318 }
2319 
HitTestAllPhases(HitTestResult & result,const HitTestLocation & hit_test_location,const PhysicalOffset & accumulated_offset,HitTestFilter hit_test_filter)2320 bool LayoutBox::HitTestAllPhases(HitTestResult& result,
2321                                  const HitTestLocation& hit_test_location,
2322                                  const PhysicalOffset& accumulated_offset,
2323                                  HitTestFilter hit_test_filter) {
2324   NOT_DESTROYED();
2325   if (!MayIntersect(result, hit_test_location, accumulated_offset))
2326     return false;
2327   return LayoutObject::HitTestAllPhases(result, hit_test_location,
2328                                         accumulated_offset, hit_test_filter);
2329 }
2330 
NodeAtPoint(HitTestResult & result,const HitTestLocation & hit_test_location,const PhysicalOffset & accumulated_offset,HitTestAction action)2331 bool LayoutBox::NodeAtPoint(HitTestResult& result,
2332                             const HitTestLocation& hit_test_location,
2333                             const PhysicalOffset& accumulated_offset,
2334                             HitTestAction action) {
2335   NOT_DESTROYED();
2336   if (!MayIntersect(result, hit_test_location, accumulated_offset))
2337     return false;
2338 
2339   bool should_hit_test_self = IsInSelfHitTestingPhase(action);
2340 
2341   if (should_hit_test_self && IsScrollContainer() &&
2342       HitTestOverflowControl(result, hit_test_location, accumulated_offset))
2343     return true;
2344 
2345   bool skip_children = (result.GetHitTestRequest().GetStopNode() == this) ||
2346                        ChildPaintBlockedByDisplayLock();
2347   if (!skip_children && ShouldClipOverflowAlongEitherAxis()) {
2348     // PaintLayer::HitTestContentsForFragments checked the fragments'
2349     // foreground rect for intersection if a layer is self painting,
2350     // so only do the overflow clip check here for non-self-painting layers.
2351     if (!HasSelfPaintingLayer() &&
2352         !hit_test_location.Intersects(OverflowClipRect(
2353             accumulated_offset, kExcludeOverlayScrollbarSizeForHitTesting))) {
2354       skip_children = true;
2355     }
2356     if (!skip_children && StyleRef().HasBorderRadius()) {
2357       PhysicalRect bounds_rect(accumulated_offset, Size());
2358       skip_children = !hit_test_location.Intersects(
2359           RoundedBorderGeometry::PixelSnappedRoundedInnerBorder(StyleRef(),
2360                                                                 bounds_rect));
2361     }
2362   }
2363 
2364   if (!skip_children &&
2365       HitTestChildren(result, hit_test_location, accumulated_offset, action)) {
2366     return true;
2367   }
2368 
2369   if (StyleRef().HasBorderRadius() &&
2370       HitTestClippedOutByBorder(hit_test_location, accumulated_offset))
2371     return false;
2372 
2373   // Now hit test ourselves.
2374   if (should_hit_test_self &&
2375       VisibleToHitTestRequest(result.GetHitTestRequest())) {
2376     PhysicalRect bounds_rect;
2377     if (result.GetHitTestRequest().GetType() &
2378         HitTestRequest::kHitTestVisualOverflow) {
2379       bounds_rect = PhysicalVisualOverflowRectIncludingFilters();
2380     } else {
2381       bounds_rect = PhysicalBorderBoxRect();
2382     }
2383     bounds_rect.Move(accumulated_offset);
2384     if (hit_test_location.Intersects(bounds_rect)) {
2385       UpdateHitTestResult(result,
2386                           hit_test_location.Point() - accumulated_offset);
2387       if (result.AddNodeToListBasedTestResult(NodeForHitTest(),
2388                                               hit_test_location,
2389                                               bounds_rect) == kStopHitTesting)
2390         return true;
2391     }
2392   }
2393 
2394   return false;
2395 }
2396 
HitTestChildren(HitTestResult & result,const HitTestLocation & hit_test_location,const PhysicalOffset & accumulated_offset,HitTestAction action)2397 bool LayoutBox::HitTestChildren(HitTestResult& result,
2398                                 const HitTestLocation& hit_test_location,
2399                                 const PhysicalOffset& accumulated_offset,
2400                                 HitTestAction action) {
2401   NOT_DESTROYED();
2402   for (LayoutObject* child = SlowLastChild(); child;
2403        child = child->PreviousSibling()) {
2404     if (child->HasLayer() &&
2405         To<LayoutBoxModelObject>(child)->Layer()->IsSelfPaintingLayer())
2406       continue;
2407 
2408     PhysicalOffset child_accumulated_offset = accumulated_offset;
2409     if (auto* box = DynamicTo<LayoutBox>(child))
2410       child_accumulated_offset += box->PhysicalLocation(this);
2411 
2412     if (child->NodeAtPoint(result, hit_test_location, child_accumulated_offset,
2413                            action))
2414       return true;
2415   }
2416 
2417   return false;
2418 }
2419 
HitTestClippedOutByBorder(const HitTestLocation & hit_test_location,const PhysicalOffset & border_box_location) const2420 bool LayoutBox::HitTestClippedOutByBorder(
2421     const HitTestLocation& hit_test_location,
2422     const PhysicalOffset& border_box_location) const {
2423   NOT_DESTROYED();
2424   PhysicalRect border_rect = PhysicalBorderBoxRect();
2425   border_rect.Move(border_box_location);
2426   return !hit_test_location.Intersects(
2427       RoundedBorderGeometry::PixelSnappedRoundedBorder(StyleRef(),
2428                                                        border_rect));
2429 }
2430 
Paint(const PaintInfo & paint_info) const2431 void LayoutBox::Paint(const PaintInfo& paint_info) const {
2432   NOT_DESTROYED();
2433   BoxPainter(*this).Paint(paint_info);
2434 }
2435 
PaintBoxDecorationBackground(const PaintInfo & paint_info,const PhysicalOffset & paint_offset) const2436 void LayoutBox::PaintBoxDecorationBackground(
2437     const PaintInfo& paint_info,
2438     const PhysicalOffset& paint_offset) const {
2439   NOT_DESTROYED();
2440   BoxPainter(*this).PaintBoxDecorationBackground(paint_info, paint_offset);
2441 }
2442 
GetBackgroundPaintedExtent(PhysicalRect & painted_extent) const2443 bool LayoutBox::GetBackgroundPaintedExtent(PhysicalRect& painted_extent) const {
2444   NOT_DESTROYED();
2445   DCHECK(StyleRef().HasBackground());
2446 
2447   // LayoutView is special in the sense that it expands to the whole canvas,
2448   // thus can't be handled by this function.
2449   DCHECK(!IsA<LayoutView>(this));
2450 
2451   PhysicalRect background_rect(PhysicalBorderBoxRect());
2452 
2453   Color background_color = ResolveColor(GetCSSPropertyBackgroundColor());
2454   if (background_color.Alpha()) {
2455     painted_extent = background_rect;
2456     return true;
2457   }
2458 
2459   if (!StyleRef().BackgroundLayers().GetImage() ||
2460       StyleRef().BackgroundLayers().Next()) {
2461     painted_extent = background_rect;
2462     return true;
2463   }
2464 
2465   BackgroundImageGeometry geometry(*this);
2466   // TODO(schenney): This function should be rethought as it's called during
2467   // and outside of the paint phase. Potentially returning different results at
2468   // different phases. crbug.com/732934
2469   geometry.Calculate(nullptr, PaintPhase::kBlockBackground,
2470                      kGlobalPaintNormalPhase, StyleRef().BackgroundLayers(),
2471                      background_rect);
2472   if (geometry.HasNonLocalGeometry())
2473     return false;
2474   painted_extent = PhysicalRect(geometry.SnappedDestRect());
2475   return true;
2476 }
2477 
BackgroundIsKnownToBeOpaqueInRect(const PhysicalRect & local_rect) const2478 bool LayoutBox::BackgroundIsKnownToBeOpaqueInRect(
2479     const PhysicalRect& local_rect) const {
2480   NOT_DESTROYED();
2481   // If the element has appearance, it might be painted by theme.
2482   // We cannot be sure if theme paints the background opaque.
2483   // In this case it is safe to not assume opaqueness.
2484   // FIXME: May be ask theme if it paints opaque.
2485   if (StyleRef().HasEffectiveAppearance())
2486     return false;
2487   // FIXME: Check the opaqueness of background images.
2488 
2489   // FIXME: Use rounded rect if border radius is present.
2490   if (StyleRef().HasBorderRadius())
2491     return false;
2492   if (HasClipPath())
2493     return false;
2494   if (StyleRef().HasBlendMode())
2495     return false;
2496   return PhysicalBackgroundRect(kBackgroundKnownOpaqueRect)
2497       .Contains(local_rect);
2498 }
2499 
2500 // TODO(wangxianzhu): The current rules are very basic. May use more complex
2501 // rules if they can improve LCD text.
TextIsKnownToBeOnOpaqueBackground() const2502 bool LayoutBox::TextIsKnownToBeOnOpaqueBackground() const {
2503   NOT_DESTROYED();
2504   // Text may overflow the background area.
2505   if (!ShouldClipOverflowAlongEitherAxis())
2506     return false;
2507   // Same as BackgroundIsKnownToBeOpaqueInRect() about appearance.
2508   if (StyleRef().HasEffectiveAppearance())
2509     return false;
2510 
2511   PhysicalRect rect = OverflowClipRect(PhysicalOffset());
2512   return PhysicalBackgroundRect(kBackgroundKnownOpaqueRect).Contains(rect);
2513 }
2514 
IsCandidateForOpaquenessTest(const LayoutBox & child_box)2515 static bool IsCandidateForOpaquenessTest(const LayoutBox& child_box) {
2516   // Skip all layers to simplify ForegroundIsKnownToBeOpaqueInRect(). This
2517   // covers cases of clipped, transformed, translucent, composited, etc.
2518   if (child_box.HasLayer())
2519     return false;
2520   const ComputedStyle& child_style = child_box.StyleRef();
2521   if (child_style.Visibility() != EVisibility::kVisible ||
2522       child_style.ShapeOutside())
2523     return false;
2524   if (child_box.Size().IsZero())
2525     return false;
2526   return true;
2527 }
2528 
ForegroundIsKnownToBeOpaqueInRect(const PhysicalRect & local_rect,unsigned max_depth_to_test) const2529 bool LayoutBox::ForegroundIsKnownToBeOpaqueInRect(
2530     const PhysicalRect& local_rect,
2531     unsigned max_depth_to_test) const {
2532   NOT_DESTROYED();
2533   if (!max_depth_to_test)
2534     return false;
2535   for (LayoutObject* child = SlowFirstChild(); child;
2536        child = child->NextSibling()) {
2537     if (!child->IsBox())
2538       continue;
2539     auto* child_box = To<LayoutBox>(child);
2540     if (!IsCandidateForOpaquenessTest(*child_box))
2541       continue;
2542     DCHECK(!child_box->IsPositioned());
2543     PhysicalRect child_local_rect = local_rect;
2544     child_local_rect.Move(-child_box->PhysicalLocation());
2545     if (child_local_rect.Y() < 0 || child_local_rect.X() < 0) {
2546       // If there is unobscured area above/left of a static positioned box then
2547       // the rect is probably not covered. This can cause false-negative in
2548       // non-horizontal-tb writing mode but is allowed.
2549       return false;
2550     }
2551     if (child_local_rect.Bottom() > child_box->Size().Height() ||
2552         child_local_rect.Right() > child_box->Size().Width())
2553       continue;
2554     if (child_box->BackgroundIsKnownToBeOpaqueInRect(child_local_rect))
2555       return true;
2556     if (child_box->ForegroundIsKnownToBeOpaqueInRect(child_local_rect,
2557                                                      max_depth_to_test - 1))
2558       return true;
2559   }
2560   return false;
2561 }
2562 
2563 DISABLE_CFI_PERF
ComputeBackgroundIsKnownToBeObscured() const2564 bool LayoutBox::ComputeBackgroundIsKnownToBeObscured() const {
2565   NOT_DESTROYED();
2566   if (ScrollsOverflow())
2567     return false;
2568   // Test to see if the children trivially obscure the background.
2569   if (!StyleRef().HasBackground())
2570     return false;
2571   // Root background painting is special.
2572   if (IsA<LayoutView>(this))
2573     return false;
2574   if (StyleRef().BoxShadow())
2575     return false;
2576   PhysicalRect background_rect;
2577   if (!GetBackgroundPaintedExtent(background_rect))
2578     return false;
2579   return ForegroundIsKnownToBeOpaqueInRect(background_rect,
2580                                            kBackgroundObscurationTestMaxDepth);
2581 }
2582 
PaintMask(const PaintInfo & paint_info,const PhysicalOffset & paint_offset) const2583 void LayoutBox::PaintMask(const PaintInfo& paint_info,
2584                           const PhysicalOffset& paint_offset) const {
2585   NOT_DESTROYED();
2586   BoxPainter(*this).PaintMask(paint_info, paint_offset);
2587 }
2588 
ImageChanged(WrappedImagePtr image,CanDeferInvalidation defer)2589 void LayoutBox::ImageChanged(WrappedImagePtr image,
2590                              CanDeferInvalidation defer) {
2591   NOT_DESTROYED();
2592   bool is_box_reflect_image =
2593       (StyleRef().BoxReflect() && StyleRef().BoxReflect()->Mask().GetImage() &&
2594        StyleRef().BoxReflect()->Mask().GetImage()->Data() == image);
2595 
2596   if (is_box_reflect_image && HasLayer()) {
2597     Layer()->SetFilterOnEffectNodeDirty();
2598     SetNeedsPaintPropertyUpdate();
2599   }
2600 
2601   // TODO(chrishtr): support delayed paint invalidation for animated border
2602   // images.
2603   if ((StyleRef().BorderImage().GetImage() &&
2604        StyleRef().BorderImage().GetImage()->Data() == image) ||
2605       (StyleRef().MaskBoxImage().GetImage() &&
2606        StyleRef().MaskBoxImage().GetImage()->Data() == image) ||
2607       is_box_reflect_image) {
2608     SetShouldDoFullPaintInvalidationWithoutGeometryChange(
2609         PaintInvalidationReason::kImage);
2610   } else {
2611     for (const FillLayer* layer = &StyleRef().MaskLayers(); layer;
2612          layer = layer->Next()) {
2613       if (layer->GetImage() && image == layer->GetImage()->Data()) {
2614         SetShouldDoFullPaintInvalidationWithoutGeometryChange(
2615             PaintInvalidationReason::kImage);
2616         break;
2617       }
2618     }
2619   }
2620 
2621   if (!BackgroundTransfersToView()) {
2622     for (const FillLayer* layer = &StyleRef().BackgroundLayers(); layer;
2623          layer = layer->Next()) {
2624       if (layer->GetImage() && image == layer->GetImage()->Data()) {
2625         bool maybe_animated =
2626             layer->GetImage()->CachedImage() &&
2627             layer->GetImage()->CachedImage()->GetImage() &&
2628             layer->GetImage()->CachedImage()->GetImage()->MaybeAnimated();
2629         if (defer == CanDeferInvalidation::kYes && maybe_animated)
2630           SetMayNeedPaintInvalidationAnimatedBackgroundImage();
2631         else
2632           SetBackgroundNeedsFullPaintInvalidation();
2633         break;
2634       }
2635     }
2636   }
2637 
2638   ShapeValue* shape_outside_value = StyleRef().ShapeOutside();
2639   if (!GetFrameView()->IsInPerformLayout() && IsFloating() &&
2640       shape_outside_value && shape_outside_value->GetImage() &&
2641       shape_outside_value->GetImage()->Data() == image) {
2642     ShapeOutsideInfo& info = ShapeOutsideInfo::EnsureInfo(*this);
2643     if (!info.IsComputingShape()) {
2644       info.MarkShapeAsDirty();
2645       MarkShapeOutsideDependentsForLayout();
2646     }
2647   }
2648 }
2649 
ComputeResourcePriority() const2650 ResourcePriority LayoutBox::ComputeResourcePriority() const {
2651   NOT_DESTROYED();
2652   PhysicalRect view_bounds = ViewRect();
2653   PhysicalRect object_bounds = PhysicalContentBoxRect();
2654   // TODO(japhet): Is this IgnoreTransforms correct? Would it be better to use
2655   // the visual rect (which has ancestor clips and transforms applied)? Should
2656   // we map to the top-level viewport instead of the current (sub) frame?
2657   object_bounds.Move(LocalToAbsolutePoint(PhysicalOffset(), kIgnoreTransforms));
2658 
2659   // The object bounds might be empty right now, so intersects will fail since
2660   // it doesn't deal with empty rects. Use LayoutRect::contains in that case.
2661   bool is_visible;
2662   if (!object_bounds.IsEmpty())
2663     is_visible = view_bounds.Intersects(object_bounds);
2664   else
2665     is_visible = view_bounds.Contains(object_bounds);
2666 
2667   PhysicalRect screen_rect;
2668   if (!object_bounds.IsEmpty()) {
2669     screen_rect = view_bounds;
2670     screen_rect.Intersect(object_bounds);
2671   }
2672 
2673   int screen_area = 0;
2674   if (!screen_rect.IsEmpty() && is_visible)
2675     screen_area = (screen_rect.Width() * screen_rect.Height()).ToInt();
2676   return ResourcePriority(
2677       is_visible ? ResourcePriority::kVisible : ResourcePriority::kNotVisible,
2678       screen_area);
2679 }
2680 
LocationChanged()2681 void LayoutBox::LocationChanged() {
2682   NOT_DESTROYED();
2683   // The location may change because of layout of other objects. Should check
2684   // this object for paint invalidation.
2685   if (!NeedsLayout())
2686     SetShouldCheckForPaintInvalidation();
2687 }
2688 
SizeChanged()2689 void LayoutBox::SizeChanged() {
2690   NOT_DESTROYED();
2691   // The size may change because of layout of other objects. Should check this
2692   // object for paint invalidation.
2693   if (!NeedsLayout())
2694     SetShouldCheckForPaintInvalidation();
2695 }
2696 
IntersectsVisibleViewport() const2697 bool LayoutBox::IntersectsVisibleViewport() const {
2698   NOT_DESTROYED();
2699   PhysicalRect rect = PhysicalVisualOverflowRect();
2700   LayoutView* layout_view = View();
2701   while (layout_view->GetFrame()->OwnerLayoutObject())
2702     layout_view = layout_view->GetFrame()->OwnerLayoutObject()->View();
2703   MapToVisualRectInAncestorSpace(layout_view, rect);
2704   return rect.Intersects(PhysicalRect(
2705       layout_view->GetFrameView()->GetScrollableArea()->VisibleContentRect()));
2706 }
2707 
EnsureIsReadyForPaintInvalidation()2708 void LayoutBox::EnsureIsReadyForPaintInvalidation() {
2709   NOT_DESTROYED();
2710   LayoutBoxModelObject::EnsureIsReadyForPaintInvalidation();
2711 
2712   bool new_obscured = ComputeBackgroundIsKnownToBeObscured();
2713   if (BackgroundIsKnownToBeObscured() != new_obscured) {
2714     SetBackgroundIsKnownToBeObscured(new_obscured);
2715     SetBackgroundNeedsFullPaintInvalidation();
2716   }
2717 
2718   if (MayNeedPaintInvalidationAnimatedBackgroundImage() &&
2719       !BackgroundIsKnownToBeObscured()) {
2720     SetBackgroundNeedsFullPaintInvalidation();
2721     SetShouldDelayFullPaintInvalidation();
2722   }
2723 
2724   if (ShouldDelayFullPaintInvalidation() && IntersectsVisibleViewport()) {
2725     // Do regular full paint invalidation if the object with delayed paint
2726     // invalidation is on screen.
2727     ClearShouldDelayFullPaintInvalidation();
2728     DCHECK(ShouldDoFullPaintInvalidation());
2729   }
2730 }
2731 
InvalidatePaintRectangle(const PhysicalRect & dirty_rect)2732 void LayoutBox::InvalidatePaintRectangle(const PhysicalRect& dirty_rect) {
2733   NOT_DESTROYED();
2734   DCHECK_NE(GetDocument().Lifecycle().GetState(), DocumentLifecycle::kInPaint);
2735 
2736   if (dirty_rect.IsEmpty())
2737     return;
2738 
2739   EnsureRareData().partial_invalidation_rect_.Unite(dirty_rect);
2740   SetShouldCheckForPaintInvalidationWithoutGeometryChange();
2741 }
2742 
ClearPartialInvalidationVisualRect() const2743 void LayoutBox::ClearPartialInvalidationVisualRect() const {
2744   NOT_DESTROYED();
2745   if (rare_data_)
2746     rare_data_->partial_invalidation_rect_ = PhysicalRect();
2747 }
2748 
PartialInvalidationVisualRect() const2749 IntRect LayoutBox::PartialInvalidationVisualRect() const {
2750   NOT_DESTROYED();
2751   if (!rare_data_)
2752     return IntRect();
2753   PhysicalRect rect = rare_data_->partial_invalidation_rect_;
2754   if (rect.IsEmpty())
2755     return IntRect();
2756   rect.Move(FirstFragment().PaintOffset());
2757   return EnclosingIntRect(rect);
2758 }
2759 
InvalidatePaint(const PaintInvalidatorContext & context) const2760 void LayoutBox::InvalidatePaint(const PaintInvalidatorContext& context) const {
2761   NOT_DESTROYED();
2762   BoxPaintInvalidator(*this, context).InvalidatePaint();
2763 }
2764 
ClearPaintFlags()2765 void LayoutBox::ClearPaintFlags() {
2766   NOT_DESTROYED();
2767   LayoutObject::ClearPaintFlags();
2768 
2769   if (auto* scrollable_area = GetScrollableArea()) {
2770     if (auto* scrollbar =
2771             DynamicTo<CustomScrollbar>(scrollable_area->HorizontalScrollbar()))
2772       scrollbar->ClearPaintFlags();
2773     if (auto* scrollbar =
2774             DynamicTo<CustomScrollbar>(scrollable_area->VerticalScrollbar()))
2775       scrollbar->ClearPaintFlags();
2776   }
2777 }
2778 
OverflowClipRect(const PhysicalOffset & location,OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const2779 PhysicalRect LayoutBox::OverflowClipRect(
2780     const PhysicalOffset& location,
2781     OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const {
2782   NOT_DESTROYED();
2783   PhysicalRect clip_rect;
2784 
2785   if (IsEffectiveRootScroller()) {
2786     // If this box is the effective root scroller, use the viewport clipping
2787     // rect since it will account for the URL bar correctly which the border
2788     // box does not. We can do this because the effective root scroller is
2789     // restricted such that it exactly fills the viewport. See
2790     // RootScrollerController::IsValidRootScroller()
2791     clip_rect = PhysicalRect(location, View()->ViewRect().size);
2792   } else {
2793     clip_rect = PhysicalBorderBoxRect();
2794     clip_rect.Contract(BorderBoxOutsets());
2795     clip_rect.Move(location);
2796     if (HasNonVisibleOverflow()) {
2797       const auto overflow_clip = GetOverflowClipAxes();
2798       if (overflow_clip == kOverflowClipBothAxis) {
2799         clip_rect.Inflate(StyleRef().OverflowClipMargin());
2800       } else {
2801         auto infinite_rect = LayoutRect::InfiniteIntRect();
2802         if ((overflow_clip & kOverflowClipX) == kNoOverflowClip) {
2803           clip_rect.offset.left = LayoutUnit(infinite_rect.X());
2804           clip_rect.size.width = LayoutUnit(infinite_rect.Width());
2805         }
2806         if ((overflow_clip & kOverflowClipY) == kNoOverflowClip) {
2807           clip_rect.offset.top = LayoutUnit(infinite_rect.Y());
2808           clip_rect.size.height = LayoutUnit(infinite_rect.Height());
2809         }
2810       }
2811     }
2812   }
2813 
2814   if (IsScrollContainer())
2815     ExcludeScrollbars(clip_rect, overlay_scrollbar_clip_behavior);
2816 
2817   auto* input = DynamicTo<HTMLInputElement>(GetNode());
2818   if (UNLIKELY(input)) {
2819     // As for LayoutButton, ControlClip is to for not BUTTONs but INPUT
2820     // buttons for IE/Firefox compatibility.
2821     if (IsTextFieldIncludingNG() || IsButtonIncludingNG()) {
2822       DCHECK(HasControlClip());
2823       PhysicalRect control_clip = PhysicalPaddingBoxRect();
2824       control_clip.Move(location);
2825       clip_rect.Intersect(control_clip);
2826     }
2827   } else if (UNLIKELY(IsMenuList(this))) {
2828     DCHECK(HasControlClip());
2829     PhysicalRect control_clip = PhysicalContentBoxRect();
2830     control_clip.Move(location);
2831     clip_rect.Intersect(control_clip);
2832   } else {
2833     DCHECK(!HasControlClip());
2834   }
2835 
2836   return clip_rect;
2837 }
2838 
HasControlClip() const2839 bool LayoutBox::HasControlClip() const {
2840   NOT_DESTROYED();
2841   return UNLIKELY(IsTextFieldIncludingNG() || IsFileUploadControl() ||
2842                   IsMenuList(this) ||
2843                   (IsButtonIncludingNG() && IsA<HTMLInputElement>(GetNode())));
2844 }
2845 
ExcludeScrollbars(PhysicalRect & rect,OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const2846 void LayoutBox::ExcludeScrollbars(
2847     PhysicalRect& rect,
2848     OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const {
2849   NOT_DESTROYED();
2850   if (CanSkipComputeScrollbars())
2851     return;
2852 
2853   NGPhysicalBoxStrut scrollbars = ComputeScrollbarsInternal(
2854       kDoNotClampToContentBox, overlay_scrollbar_clip_behavior);
2855   rect.offset.top += scrollbars.top;
2856   rect.offset.left += scrollbars.left;
2857   rect.size.width -= scrollbars.HorizontalSum();
2858   rect.size.height -= scrollbars.VerticalSum();
2859   rect.size.ClampNegativeToZero();
2860 }
2861 
ClipRect(const PhysicalOffset & location) const2862 PhysicalRect LayoutBox::ClipRect(const PhysicalOffset& location) const {
2863   NOT_DESTROYED();
2864   PhysicalRect clip_rect(location, Size());
2865   LayoutUnit width = Size().Width();
2866   LayoutUnit height = Size().Height();
2867 
2868   if (!StyleRef().ClipLeft().IsAuto()) {
2869     LayoutUnit c = ValueForLength(StyleRef().ClipLeft(), width);
2870     clip_rect.offset.left += c;
2871     clip_rect.size.width -= c;
2872   }
2873 
2874   if (!StyleRef().ClipRight().IsAuto()) {
2875     clip_rect.size.width -=
2876         width - ValueForLength(StyleRef().ClipRight(), width);
2877   }
2878 
2879   if (!StyleRef().ClipTop().IsAuto()) {
2880     LayoutUnit c = ValueForLength(StyleRef().ClipTop(), height);
2881     clip_rect.offset.top += c;
2882     clip_rect.size.height -= c;
2883   }
2884 
2885   if (!StyleRef().ClipBottom().IsAuto()) {
2886     clip_rect.size.height -=
2887         height - ValueForLength(StyleRef().ClipBottom(), height);
2888   }
2889 
2890   return clip_rect;
2891 }
2892 
PortionOfMarginNotConsumedByFloat(LayoutUnit child_margin,LayoutUnit content_side,LayoutUnit offset)2893 static LayoutUnit PortionOfMarginNotConsumedByFloat(LayoutUnit child_margin,
2894                                                     LayoutUnit content_side,
2895                                                     LayoutUnit offset) {
2896   if (child_margin <= 0)
2897     return LayoutUnit();
2898   LayoutUnit content_side_with_margin = content_side + child_margin;
2899   if (offset > content_side_with_margin)
2900     return child_margin;
2901   return offset - content_side;
2902 }
2903 
ShrinkLogicalWidthToAvoidFloats(LayoutUnit child_margin_start,LayoutUnit child_margin_end,const LayoutBlockFlow * cb) const2904 LayoutUnit LayoutBox::ShrinkLogicalWidthToAvoidFloats(
2905     LayoutUnit child_margin_start,
2906     LayoutUnit child_margin_end,
2907     const LayoutBlockFlow* cb) const {
2908   NOT_DESTROYED();
2909   LayoutUnit logical_top_position = LogicalTop();
2910   LayoutUnit start_offset_for_content = cb->StartOffsetForContent();
2911   LayoutUnit end_offset_for_content = cb->EndOffsetForContent();
2912 
2913   // NOTE: This call to LogicalHeightForChild is bad, as it may contain data
2914   // from a previous layout.
2915   LayoutUnit logical_height = cb->LogicalHeightForChild(*this);
2916   LayoutUnit start_offset_for_avoiding_floats =
2917       cb->StartOffsetForAvoidingFloats(logical_top_position, logical_height);
2918   LayoutUnit end_offset_for_avoiding_floats =
2919       cb->EndOffsetForAvoidingFloats(logical_top_position, logical_height);
2920 
2921   // If there aren't any floats constraining us then allow the margins to
2922   // shrink/expand the width as much as they want.
2923   if (start_offset_for_content == start_offset_for_avoiding_floats &&
2924       end_offset_for_content == end_offset_for_avoiding_floats)
2925     return cb->AvailableLogicalWidthForAvoidingFloats(logical_top_position,
2926                                                       logical_height) -
2927            child_margin_start - child_margin_end;
2928 
2929   LayoutUnit width = cb->AvailableLogicalWidthForAvoidingFloats(
2930       logical_top_position, logical_height);
2931   width -= std::max(LayoutUnit(), child_margin_start);
2932   width -= std::max(LayoutUnit(), child_margin_end);
2933 
2934   // We need to see if margins on either the start side or the end side can
2935   // contain the floats in question. If they can, then just using the line width
2936   // is inaccurate. In the case where a float completely fits, we don't need to
2937   // use the line offset at all, but can instead push all the way to the content
2938   // edge of the containing block. In the case where the float doesn't fit, we
2939   // can use the line offset, but we need to grow it by the margin to reflect
2940   // the fact that the margin was "consumed" by the float. Negative margins
2941   // aren't consumed by the float, and so we ignore them.
2942   width += PortionOfMarginNotConsumedByFloat(child_margin_start,
2943                                              start_offset_for_content,
2944                                              start_offset_for_avoiding_floats);
2945   width += PortionOfMarginNotConsumedByFloat(
2946       child_margin_end, end_offset_for_content, end_offset_for_avoiding_floats);
2947   return width;
2948 }
2949 
ContainingBlockLogicalHeightForGetComputedStyle() const2950 LayoutUnit LayoutBox::ContainingBlockLogicalHeightForGetComputedStyle() const {
2951   NOT_DESTROYED();
2952   if (HasOverrideContainingBlockContentLogicalHeight())
2953     return OverrideContainingBlockContentLogicalHeight();
2954 
2955   if (!IsPositioned())
2956     return ContainingBlockLogicalHeightForContent(kExcludeMarginBorderPadding);
2957 
2958   auto* cb = To<LayoutBoxModelObject>(Container());
2959   LayoutUnit height = ContainingBlockLogicalHeightForPositioned(
2960       cb, /* check_for_perpendicular_writing_mode */ false);
2961   if (IsInFlowPositioned())
2962     height -= cb->PaddingLogicalHeight();
2963   return height;
2964 }
2965 
ContainingBlockLogicalWidthForContent() const2966 LayoutUnit LayoutBox::ContainingBlockLogicalWidthForContent() const {
2967   NOT_DESTROYED();
2968   if (HasOverrideContainingBlockContentLogicalWidth())
2969     return OverrideContainingBlockContentLogicalWidth();
2970 
2971   LayoutBlock* cb = ContainingBlock();
2972   if (IsOutOfFlowPositioned())
2973     return cb->ClientLogicalWidth();
2974   return cb->AvailableLogicalWidth();
2975 }
2976 
ContainingBlockLogicalHeightForContent(AvailableLogicalHeightType height_type) const2977 LayoutUnit LayoutBox::ContainingBlockLogicalHeightForContent(
2978     AvailableLogicalHeightType height_type) const {
2979   NOT_DESTROYED();
2980   if (HasOverrideContainingBlockContentLogicalHeight())
2981     return OverrideContainingBlockContentLogicalHeight();
2982 
2983   LayoutBlock* cb = ContainingBlock();
2984   return cb->AvailableLogicalHeight(height_type);
2985 }
2986 
ContainingBlockAvailableLineWidth() const2987 LayoutUnit LayoutBox::ContainingBlockAvailableLineWidth() const {
2988   NOT_DESTROYED();
2989   LayoutBlock* cb = ContainingBlock();
2990   auto* child_block_flow = DynamicTo<LayoutBlockFlow>(cb);
2991   if (child_block_flow) {
2992     return child_block_flow->AvailableLogicalWidthForAvoidingFloats(
2993         LogicalTop(), AvailableLogicalHeight(kIncludeMarginBorderPadding));
2994   }
2995   return LayoutUnit();
2996 }
2997 
PerpendicularContainingBlockLogicalHeight() const2998 LayoutUnit LayoutBox::PerpendicularContainingBlockLogicalHeight() const {
2999   NOT_DESTROYED();
3000   if (HasOverrideContainingBlockContentLogicalHeight())
3001     return OverrideContainingBlockContentLogicalHeight();
3002 
3003   LayoutBlock* cb = ContainingBlock();
3004   if (cb->HasOverrideLogicalHeight())
3005     return cb->OverrideContentLogicalHeight();
3006 
3007   const ComputedStyle& containing_block_style = cb->StyleRef();
3008   const Length& logical_height_length = containing_block_style.LogicalHeight();
3009 
3010   // FIXME: For now just support fixed heights.  Eventually should support
3011   // percentage heights as well.
3012   if (!logical_height_length.IsFixed()) {
3013     LayoutUnit fill_fallback_extent =
3014         LayoutUnit(containing_block_style.IsHorizontalWritingMode()
3015                        ? View()->GetFrameView()->Size().Height()
3016                        : View()->GetFrameView()->Size().Width());
3017     LayoutUnit fill_available_extent =
3018         ContainingBlock()->AvailableLogicalHeight(kExcludeMarginBorderPadding);
3019     if (fill_available_extent == -1)
3020       return fill_fallback_extent;
3021     return std::min(fill_available_extent, fill_fallback_extent);
3022   }
3023 
3024   // Use the content box logical height as specified by the style.
3025   return cb->AdjustContentBoxLogicalHeightForBoxSizing(
3026       LayoutUnit(logical_height_length.Value()));
3027 }
3028 
MapLocalToAncestor(const LayoutBoxModelObject * ancestor,TransformState & transform_state,MapCoordinatesFlags mode) const3029 void LayoutBox::MapLocalToAncestor(const LayoutBoxModelObject* ancestor,
3030                                    TransformState& transform_state,
3031                                    MapCoordinatesFlags mode) const {
3032   NOT_DESTROYED();
3033   bool is_fixed_pos = StyleRef().GetPosition() == EPosition::kFixed;
3034 
3035   // If this box has a transform or contains paint, it acts as a fixed position
3036   // container for fixed descendants, and may itself also be fixed position. So
3037   // propagate 'fixed' up only if this box is fixed position.
3038   if (CanContainFixedPositionObjects() && !is_fixed_pos)
3039     mode &= ~kIsFixed;
3040   else if (is_fixed_pos)
3041     mode |= kIsFixed;
3042 
3043   LayoutBoxModelObject::MapLocalToAncestor(ancestor, transform_state, mode);
3044 }
3045 
MapAncestorToLocal(const LayoutBoxModelObject * ancestor,TransformState & transform_state,MapCoordinatesFlags mode) const3046 void LayoutBox::MapAncestorToLocal(const LayoutBoxModelObject* ancestor,
3047                                    TransformState& transform_state,
3048                                    MapCoordinatesFlags mode) const {
3049   NOT_DESTROYED();
3050   if (this == ancestor)
3051     return;
3052 
3053   bool is_fixed_pos = StyleRef().GetPosition() == EPosition::kFixed;
3054 
3055   // If this box has a transform or contains paint, it acts as a fixed position
3056   // container for fixed descendants, and may itself also be fixed position. So
3057   // propagate 'fixed' up only if this box is fixed position.
3058   if (CanContainFixedPositionObjects() && !is_fixed_pos)
3059     mode &= ~kIsFixed;
3060   else if (is_fixed_pos)
3061     mode |= kIsFixed;
3062 
3063   LayoutBoxModelObject::MapAncestorToLocal(ancestor, transform_state, mode);
3064 }
3065 
OffsetFromContainerInternal(const LayoutObject * o,bool ignore_scroll_offset) const3066 PhysicalOffset LayoutBox::OffsetFromContainerInternal(
3067     const LayoutObject* o,
3068     bool ignore_scroll_offset) const {
3069   NOT_DESTROYED();
3070   DCHECK_EQ(o, Container());
3071 
3072   PhysicalOffset offset;
3073   if (IsInFlowPositioned())
3074     offset += OffsetForInFlowPosition();
3075 
3076   offset += PhysicalLocation();
3077 
3078   if (o->IsScrollContainer())
3079     offset += OffsetFromScrollableContainer(o, ignore_scroll_offset);
3080 
3081   if (IsOutOfFlowPositioned() && o->IsLayoutInline() &&
3082       o->CanContainOutOfFlowPositionedElement(StyleRef().GetPosition())) {
3083     offset += To<LayoutInline>(o)->OffsetForInFlowPositionedInline(*this);
3084   }
3085 
3086   return offset;
3087 }
3088 
CreateInlineBox()3089 InlineBox* LayoutBox::CreateInlineBox() {
3090   NOT_DESTROYED();
3091   return new InlineBox(LineLayoutItem(this));
3092 }
3093 
DirtyLineBoxes(bool full_layout)3094 void LayoutBox::DirtyLineBoxes(bool full_layout) {
3095   NOT_DESTROYED();
3096   if (!IsInLayoutNGInlineFormattingContext() && inline_box_wrapper_) {
3097     if (full_layout) {
3098       inline_box_wrapper_->Destroy();
3099       inline_box_wrapper_ = nullptr;
3100     } else {
3101       inline_box_wrapper_->DirtyLineBoxes();
3102     }
3103   }
3104 }
3105 
HasInlineFragments() const3106 bool LayoutBox::HasInlineFragments() const {
3107   NOT_DESTROYED();
3108   if (!IsInLayoutNGInlineFormattingContext())
3109     return inline_box_wrapper_;
3110   if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
3111     return first_paint_fragment_;
3112   return first_fragment_item_index_;
3113 }
3114 
SetFirstInlineFragment(NGPaintFragment * fragment)3115 void LayoutBox::SetFirstInlineFragment(NGPaintFragment* fragment) {
3116   NOT_DESTROYED();
3117   CHECK(IsInLayoutNGInlineFormattingContext()) << *this;
3118   DCHECK(!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
3119   first_paint_fragment_ = fragment;
3120 }
3121 
ClearFirstInlineFragmentItemIndex()3122 void LayoutBox::ClearFirstInlineFragmentItemIndex() {
3123   NOT_DESTROYED();
3124   CHECK(IsInLayoutNGInlineFormattingContext()) << *this;
3125   DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
3126   first_fragment_item_index_ = 0u;
3127 }
3128 
SetFirstInlineFragmentItemIndex(wtf_size_t index)3129 void LayoutBox::SetFirstInlineFragmentItemIndex(wtf_size_t index) {
3130   NOT_DESTROYED();
3131   CHECK(IsInLayoutNGInlineFormattingContext()) << *this;
3132   DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
3133   DCHECK_NE(index, 0u);
3134   first_fragment_item_index_ = index;
3135 }
3136 
InLayoutNGInlineFormattingContextWillChange(bool new_value)3137 void LayoutBox::InLayoutNGInlineFormattingContextWillChange(bool new_value) {
3138   NOT_DESTROYED();
3139   if (IsInLayoutNGInlineFormattingContext()) {
3140     if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
3141       SetFirstInlineFragment(nullptr);
3142     } else {
3143       ClearFirstInlineFragmentItemIndex();
3144     }
3145   } else {
3146     DeleteLineBoxWrapper();
3147   }
3148 
3149   // Because |first_paint_fragment_| and |inline_box_wrapper_| are union, when
3150   // one is deleted, the other should be initialized to nullptr.
3151   DCHECK(new_value ? (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()
3152                           ? !first_fragment_item_index_
3153                           : !first_paint_fragment_)
3154                    : !inline_box_wrapper_);
3155 }
3156 
HasFragmentItems() const3157 bool LayoutBox::NGPhysicalFragmentList::HasFragmentItems() const {
3158   for (const NGPhysicalBoxFragment& fragment : *this) {
3159     if (fragment.HasItems())
3160       return true;
3161   }
3162   return false;
3163 }
3164 
SetCachedLayoutResult(scoped_refptr<const NGLayoutResult> result)3165 void LayoutBox::SetCachedLayoutResult(
3166     scoped_refptr<const NGLayoutResult> result) {
3167   NOT_DESTROYED();
3168   DCHECK(!result->PhysicalFragment().BreakToken());
3169   DCHECK(!result->IsSingleUse());
3170 
3171   if (result->GetConstraintSpaceForCaching().CacheSlot() ==
3172       NGCacheSlot::kMeasure) {
3173     // We don't early return here, when setting the "measure" result we also
3174     // set the "layout" result.
3175     if (measure_result_)
3176       InvalidateItems(*measure_result_);
3177     if (IsTableCell() && !IsTableCellLegacy())
3178       To<LayoutNGTableCell>(this)->InvalidateLayoutResultCacheAfterMeasure();
3179     measure_result_ = result;
3180   } else {
3181     // We have a "layout" result, and we may need to clear the old "measure"
3182     // result if we needed non-simplified layout.
3183     if (measure_result_ && NeedsLayout() && !NeedsSimplifiedLayoutOnly()) {
3184       InvalidateItems(*measure_result_);
3185       measure_result_ = nullptr;
3186     }
3187   }
3188 
3189   AddLayoutResult(std::move(result), 0);
3190 }
3191 
AddLayoutResult(scoped_refptr<const NGLayoutResult> result,wtf_size_t index)3192 void LayoutBox::AddLayoutResult(scoped_refptr<const NGLayoutResult> result,
3193                                 wtf_size_t index) {
3194   NOT_DESTROYED();
3195   DCHECK_EQ(result->Status(), NGLayoutResult::kSuccess);
3196   if (index != WTF::kNotFound && layout_results_.size() > index) {
3197     if (layout_results_.size() > index + 1)
3198       ShrinkLayoutResults(index + 1);
3199     ReplaceLayoutResult(std::move(result), index);
3200     return;
3201   }
3202 
3203   DCHECK_EQ(index, layout_results_.size());
3204   const auto& fragment = To<NGPhysicalBoxFragment>(result->PhysicalFragment());
3205   layout_results_.push_back(std::move(result));
3206   CheckDidAddFragment(*this, fragment);
3207 
3208   // If this is the last fragment for the node, and its node establishes an
3209   // inline formatting context, we have some finalization to do.
3210   if (!fragment.BreakToken() && HasFragmentItems())
3211     NGFragmentItems::FinalizeAfterLayout(layout_results_);
3212 }
3213 
ReplaceLayoutResult(scoped_refptr<const NGLayoutResult> result,wtf_size_t index)3214 void LayoutBox::ReplaceLayoutResult(scoped_refptr<const NGLayoutResult> result,
3215                                     wtf_size_t index) {
3216   NOT_DESTROYED();
3217   DCHECK_LE(index, layout_results_.size());
3218   const NGLayoutResult* old_result = layout_results_[index].get();
3219   if (old_result == result.get())
3220     return;
3221   const auto& fragment = To<NGPhysicalBoxFragment>(result->PhysicalFragment());
3222   bool got_new_fragment = &old_result->PhysicalFragment() != &fragment;
3223   if (got_new_fragment) {
3224     // Clear associations with the LayoutObjects and the items in the *first*
3225     // box fragment. We only ever associate LayoutObjects with the items in the
3226     // first box fragment, but this doesn't take place until we have added all
3227     // the fragments for the node. Therefore we need to clean up this now,
3228     // regardless of which index we're at. This means that we're potentially
3229     // doing duplicate work here (for each fragment we replace), but only if
3230     // we're split into multiple box fragments.
3231     // TODO(layout-dev): Make this work for multiple box fragments (block
3232     // fragmentation).
3233     if (To<NGPhysicalBoxFragment>(layout_results_[0]->PhysicalFragment())
3234             .HasItems()) {
3235       if (!index)
3236         InvalidateItems(*old_result);
3237       NGFragmentItems::ClearAssociatedFragments(this);
3238     }
3239   }
3240   layout_results_[index] = std::move(result);
3241   CheckDidAddFragment(*this, fragment);
3242 
3243   // If this is the last fragment for the node, and its node establishes an
3244   // inline formatting context, we have some finalization to do.
3245   if (got_new_fragment && !fragment.BreakToken() && HasFragmentItems())
3246     NGFragmentItems::FinalizeAfterLayout(layout_results_);
3247 }
3248 
ClearLayoutResults()3249 void LayoutBox::ClearLayoutResults() {
3250   NOT_DESTROYED();
3251   if (measure_result_)
3252     InvalidateItems(*measure_result_);
3253   measure_result_ = nullptr;
3254 
3255   ShrinkLayoutResults(0);
3256 }
3257 
ShrinkLayoutResults(wtf_size_t results_to_keep)3258 void LayoutBox::ShrinkLayoutResults(wtf_size_t results_to_keep) {
3259   NOT_DESTROYED();
3260   DCHECK_GE(layout_results_.size(), results_to_keep);
3261   // Invalidate if inline |DisplayItemClient|s will be destroyed.
3262   for (wtf_size_t i = results_to_keep; i < layout_results_.size(); i++)
3263     InvalidateItems(*layout_results_[i]);
3264   if (results_to_keep == 0 && !layout_results_.IsEmpty()) {
3265     if (To<NGPhysicalBoxFragment>(layout_results_[0]->PhysicalFragment())
3266             .HasItems()) {
3267       NGFragmentItems::ClearAssociatedFragments(this);
3268     }
3269   }
3270   layout_results_.Shrink(results_to_keep);
3271 }
3272 
InvalidateItems(const NGLayoutResult & result)3273 void LayoutBox::InvalidateItems(const NGLayoutResult& result) {
3274   NOT_DESTROYED();
3275   // Invalidate if inline |DisplayItemClient|s will be destroyed.
3276   const auto& box_fragment =
3277       To<NGPhysicalBoxFragment>(result.PhysicalFragment());
3278   if (!box_fragment.HasItems())
3279     return;
3280 #if DCHECK_IS_ON()
3281   // Column fragments are not really associated with a layout object.
3282   if (IsLayoutFlowThread())
3283     DCHECK(box_fragment.IsColumnBox());
3284   else
3285     DCHECK_EQ(this, box_fragment.GetLayoutObject());
3286 #endif
3287   ObjectPaintInvalidator(*this).SlowSetPaintingLayerNeedsRepaint();
3288 }
3289 
GetCachedLayoutResult() const3290 const NGLayoutResult* LayoutBox::GetCachedLayoutResult() const {
3291   NOT_DESTROYED();
3292   if (layout_results_.IsEmpty())
3293     return nullptr;
3294   // Only return re-usable results.
3295   const NGLayoutResult* result = layout_results_[0].get();
3296   if (result->IsSingleUse())
3297     return nullptr;
3298   DCHECK(!result->PhysicalFragment().IsLayoutObjectDestroyedOrMoved() ||
3299          BeingDestroyed());
3300   DCHECK_EQ(layout_results_.size(), 1u);
3301   return result;
3302 }
3303 
GetCachedMeasureResult() const3304 const NGLayoutResult* LayoutBox::GetCachedMeasureResult() const {
3305   NOT_DESTROYED();
3306   if (!measure_result_)
3307     return nullptr;
3308 
3309   if (measure_result_->IsSingleUse())
3310     return nullptr;
3311 
3312   return measure_result_.get();
3313 }
3314 
CachedLayoutResult(const NGConstraintSpace & new_space,const NGBreakToken * break_token,const NGEarlyBreak * early_break,base::Optional<NGFragmentGeometry> * initial_fragment_geometry,NGLayoutCacheStatus * out_cache_status)3315 scoped_refptr<const NGLayoutResult> LayoutBox::CachedLayoutResult(
3316     const NGConstraintSpace& new_space,
3317     const NGBreakToken* break_token,
3318     const NGEarlyBreak* early_break,
3319     base::Optional<NGFragmentGeometry>* initial_fragment_geometry,
3320     NGLayoutCacheStatus* out_cache_status) {
3321   NOT_DESTROYED();
3322   *out_cache_status = NGLayoutCacheStatus::kNeedsLayout;
3323 
3324   const bool use_layout_cache_slot =
3325       new_space.CacheSlot() == NGCacheSlot::kLayout &&
3326       !layout_results_.IsEmpty();
3327   const NGLayoutResult* cached_layout_result = use_layout_cache_slot
3328                                                    ? GetCachedLayoutResult()
3329                                                    : GetCachedMeasureResult();
3330 
3331   if (!cached_layout_result)
3332     return nullptr;
3333 
3334   // TODO(cbiesinger): Support caching fragmented boxes.
3335   if (break_token)
3336     return nullptr;
3337 
3338   if (early_break)
3339     return nullptr;
3340 
3341   // We'll never re-use the layout result of a fieldset contents wrapper. If the
3342   // current rendered legend ceased to be one, and any next legend child became
3343   // the rendered legend instead, we need to lay out the fieldset contents
3344   // wrapper, to get rid of the fragment for the former regular block child
3345   // legend (now rendered legend). When this happens, the contents wrapper won't
3346   // necessarily be marked for layout, since we don't detect that anything in
3347   // there has changed (and detecting that would be more expensive). So just
3348   // refuse to hit the cache, so that we force re-layout.
3349   if (UNLIKELY(IsAnonymous() && Parent()->IsLayoutNGFieldset()))
3350     return nullptr;
3351 
3352   DCHECK_EQ(cached_layout_result->Status(), NGLayoutResult::kSuccess);
3353 
3354   // Set our initial temporary cache status to "hit".
3355   NGLayoutCacheStatus cache_status = NGLayoutCacheStatus::kHit;
3356 
3357   // If the display-lock blocked child layout, then we don't clear child needs
3358   // layout bits. However, we can still use the cached result, since we will
3359   // re-layout when unlocking.
3360   bool child_needs_layout_unless_locked =
3361       !ChildLayoutBlockedByDisplayLock() &&
3362       (PosChildNeedsLayout() || NormalChildNeedsLayout());
3363 
3364   const NGPhysicalBoxFragment& physical_fragment =
3365       To<NGPhysicalBoxFragment>(cached_layout_result->PhysicalFragment());
3366   if (SelfNeedsLayoutForStyle() || child_needs_layout_unless_locked ||
3367       NeedsSimplifiedNormalFlowLayout() ||
3368       (NeedsPositionedMovementLayout() &&
3369        !NeedsPositionedMovementLayoutOnly())) {
3370     if (!ChildrenInline()) {
3371       // Check if we only need "simplified" layout. We don't abort yet, as we
3372       // need to check if other things (like floats) will require us to perform
3373       // a full layout.
3374       if (!NeedsSimplifiedLayoutOnly())
3375         return nullptr;
3376 
3377       cache_status = NGLayoutCacheStatus::kNeedsSimplifiedLayout;
3378     } else if (!NeedsSimplifiedLayoutOnly() ||
3379                NeedsSimplifiedNormalFlowLayout()) {
3380       // We don't regenerate any lineboxes during our "simplified" layout pass.
3381       // If something needs "simplified" layout within a linebox, (e.g. an
3382       // atomic-inline) we miss the cache.
3383 
3384       if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
3385         return nullptr;
3386 
3387       // Check if some of line boxes are reusable.
3388 
3389       // Only for the layout cache slot. Measure has several special
3390       // optimizations that makes reusing lines complicated.
3391       if (!use_layout_cache_slot)
3392         return nullptr;
3393 
3394       if (SelfNeedsLayout())
3395         return nullptr;
3396 
3397       if (!physical_fragment.HasItems())
3398         return nullptr;
3399 
3400       // Propagating OOF needs re-layout.
3401       if (physical_fragment.HasOutOfFlowPositionedDescendants())
3402         return nullptr;
3403 
3404       // Any floats might need to move, causing lines to wrap differently,
3405       // needing re-layout, either in cached result or in new constraint space.
3406       if (!cached_layout_result->ExclusionSpace().IsEmpty() ||
3407           new_space.HasFloats())
3408         return nullptr;
3409 
3410       cache_status = NGLayoutCacheStatus::kCanReuseLines;
3411     } else {
3412       cache_status = NGLayoutCacheStatus::kNeedsSimplifiedLayout;
3413     }
3414   }
3415 
3416   DCHECK(!physical_fragment.BreakToken());
3417 
3418   NGBlockNode node(this);
3419   NGLayoutCacheStatus size_cache_status = CalculateSizeBasedLayoutCacheStatus(
3420       node, *cached_layout_result, new_space, initial_fragment_geometry);
3421 
3422   // If our size may change (or we know a descendants size may change), we miss
3423   // the cache.
3424   if (size_cache_status == NGLayoutCacheStatus::kNeedsLayout)
3425     return nullptr;
3426 
3427   // Update our temporary cache status, if the size cache check indicated we
3428   // might need simplified layout.
3429   if (size_cache_status == NGLayoutCacheStatus::kNeedsSimplifiedLayout &&
3430       cache_status == NGLayoutCacheStatus::kHit)
3431     cache_status = NGLayoutCacheStatus::kNeedsSimplifiedLayout;
3432 
3433   LayoutUnit bfc_line_offset = new_space.BfcOffset().line_offset;
3434   base::Optional<LayoutUnit> bfc_block_offset =
3435       cached_layout_result->BfcBlockOffset();
3436   LayoutUnit block_offset_delta;
3437   NGMarginStrut end_margin_strut = cached_layout_result->EndMarginStrut();
3438 
3439   const NGConstraintSpace& old_space =
3440       cached_layout_result->GetConstraintSpaceForCaching();
3441 
3442   // Check the BFC offset. Even if they don't match, there're some cases we can
3443   // still reuse the fragment.
3444   bool are_bfc_offsets_equal =
3445       new_space.BfcOffset() == old_space.BfcOffset() &&
3446       new_space.ExpectedBfcBlockOffset() ==
3447           old_space.ExpectedBfcBlockOffset() &&
3448       new_space.ForcedBfcBlockOffset() == old_space.ForcedBfcBlockOffset();
3449 
3450   // Even for the first fragment, when block fragmentation is enabled, block
3451   // offset changes should cause re-layout, since we will fragment at other
3452   // locations than before.
3453   if (UNLIKELY(!are_bfc_offsets_equal && new_space.HasBlockFragmentation())) {
3454     DCHECK(old_space.HasBlockFragmentation());
3455     return nullptr;
3456   }
3457 
3458   bool is_margin_strut_equal =
3459       new_space.MarginStrut() == old_space.MarginStrut();
3460   bool is_exclusion_space_equal =
3461       new_space.ExclusionSpace() == old_space.ExclusionSpace();
3462 
3463   bool is_new_formatting_context = physical_fragment.IsFormattingContextRoot();
3464 
3465   // If a node *doesn't* establish a new formatting context it may be affected
3466   // by floats, or clearance.
3467   // If anything has changed prior to us (different exclusion space, etc), we
3468   // need to perform a series of additional checks if we can still reuse this
3469   // layout result.
3470   if (!is_new_formatting_context &&
3471       (!are_bfc_offsets_equal || !is_exclusion_space_equal ||
3472        !is_margin_strut_equal ||
3473        new_space.ClearanceOffset() != old_space.ClearanceOffset())) {
3474     DCHECK(!CreatesNewFormattingContext());
3475 
3476     // If we have a different BFC offset, or exclusion space we can't perform
3477     // "simplified" layout.
3478     // This may occur if our %-block-size has changed (allowing "simplified"
3479     // layout), and we've been pushed down in the BFC coordinate space by a
3480     // sibling.
3481     // The "simplified" layout algorithm doesn't have the required logic to
3482     // shift any added exclusions within the output exclusion space.
3483     if (cache_status == NGLayoutCacheStatus::kNeedsSimplifiedLayout ||
3484         cache_status == NGLayoutCacheStatus::kCanReuseLines)
3485       return nullptr;
3486 
3487     DCHECK_EQ(cache_status, NGLayoutCacheStatus::kHit);
3488 
3489     if (!MaySkipLayoutWithinBlockFormattingContext(
3490             *cached_layout_result, new_space, &bfc_block_offset,
3491             &block_offset_delta, &end_margin_strut))
3492       return nullptr;
3493   }
3494 
3495   // We've performed all of the cache checks at this point. If we need
3496   // "simplified" layout then abort now.
3497   *out_cache_status = cache_status;
3498   if (cache_status == NGLayoutCacheStatus::kNeedsSimplifiedLayout ||
3499       cache_status == NGLayoutCacheStatus::kCanReuseLines)
3500     return cached_layout_result;
3501 
3502   physical_fragment.CheckType();
3503 
3504   DCHECK_EQ(*out_cache_status, NGLayoutCacheStatus::kHit);
3505 
3506   // We can safely re-use this fragment if we are positioned, and only our
3507   // position constraints changed (left/top/etc). However we need to clear the
3508   // dirty layout bit(s). Note that we may be here because we are display locked
3509   // and have cached a locked layout result. In that case, this function will
3510   // not clear the child dirty bits.
3511   ClearNeedsLayout();
3512 
3513   // Optimization: TableConstraintSpaceData can be large, and it is shared
3514   // between all the rows in a table. Make constraint space table data for
3515   // reused row fragment be identical to the one used by other row fragments.
3516   if (IsTableRow() && IsLayoutNGMixin()) {
3517     const_cast<NGConstraintSpace&>(old_space).ReplaceTableConstraintSpaceData(
3518         *new_space.TableData());
3519   }
3520 
3521   // OOF-positioned nodes have to two-tier cache. The additional cache check
3522   // runs before the OOF-positioned sizing, and positioning calculations.
3523   //
3524   // This additional check compares the percentage resolution size.
3525   //
3526   // As a result, the cached layout result always needs to contain the previous
3527   // percentage resolution size in order for the first-tier cache to work.
3528   // See |NGBlockNode::CachedLayoutResultForOutOfFlowPositioned|.
3529   bool needs_cached_result_update =
3530       node.IsOutOfFlowPositioned() && new_space.PercentageResolutionSize() !=
3531                                           old_space.PercentageResolutionSize();
3532 
3533   // We can safely reuse this result if our BFC and "input" exclusion spaces
3534   // were equal.
3535   if (are_bfc_offsets_equal && is_exclusion_space_equal &&
3536       is_margin_strut_equal && !needs_cached_result_update) {
3537     // In order not to rebuild the internal derived-geometry "cache" of float
3538     // data, we need to move this to the new "output" exclusion space.
3539     cached_layout_result->ExclusionSpace().MoveAndUpdateDerivedGeometry(
3540         new_space.ExclusionSpace());
3541     return cached_layout_result;
3542   }
3543 
3544   scoped_refptr<const NGLayoutResult> new_result =
3545       base::AdoptRef(new NGLayoutResult(*cached_layout_result, new_space,
3546                                         end_margin_strut, bfc_line_offset,
3547                                         bfc_block_offset, block_offset_delta));
3548 
3549   if (needs_cached_result_update)
3550     SetCachedLayoutResult(new_result);
3551 
3552   return new_result;
3553 }
3554 
GetPhysicalFragment(wtf_size_t index) const3555 const NGPhysicalBoxFragment* LayoutBox::GetPhysicalFragment(
3556     wtf_size_t index) const {
3557   NOT_DESTROYED();
3558   return &To<NGPhysicalBoxFragment>(layout_results_[index]->PhysicalFragment());
3559 }
3560 
3561 const NGPhysicalBoxFragment&
operator *() const3562 LayoutBox::NGPhysicalFragmentList::Iterator::operator*() const {
3563   return To<NGPhysicalBoxFragment>((*iterator_)->PhysicalFragment());
3564 }
3565 
FragmentDataFromPhysicalFragment(const NGPhysicalBoxFragment & physical_fragment) const3566 const FragmentData* LayoutBox::FragmentDataFromPhysicalFragment(
3567     const NGPhysicalBoxFragment& physical_fragment) const {
3568   NOT_DESTROYED();
3569   const FragmentData* fragment_data = &FirstFragment();
3570   for (const auto& result : layout_results_) {
3571     if (&result->PhysicalFragment() == &physical_fragment)
3572       return fragment_data;
3573     DCHECK(fragment_data->NextFragment());
3574     fragment_data = fragment_data->NextFragment();
3575   }
3576   NOTREACHED();
3577   return fragment_data;
3578 }
3579 
PositionLineBox(InlineBox * box)3580 void LayoutBox::PositionLineBox(InlineBox* box) {
3581   NOT_DESTROYED();
3582   if (IsOutOfFlowPositioned()) {
3583     // Cache the x position only if we were an INLINE type originally.
3584     bool originally_inline = StyleRef().IsOriginalDisplayInlineType();
3585     if (originally_inline) {
3586       // The value is cached in the xPos of the box.  We only need this value if
3587       // our object was inline originally, since otherwise it would have ended
3588       // up underneath the inlines.
3589       RootInlineBox& root = box->Root();
3590       root.Block().SetStaticInlinePositionForChild(LineLayoutBox(this),
3591                                                    box->LogicalLeft());
3592     } else {
3593       // Our object was a block originally, so we make our normal flow position
3594       // be just below the line box (as though all the inlines that came before
3595       // us got wrapped in an anonymous block, which is what would have happened
3596       // had we been in flow). This value was cached in the y() of the box.
3597       Layer()->SetStaticBlockPosition(box->LogicalTop());
3598     }
3599 
3600     if (Container()->IsLayoutInline())
3601       MoveWithEdgeOfInlineContainerIfNecessary(box->IsHorizontal());
3602 
3603     // Nuke the box.
3604     box->Remove(kDontMarkLineBoxes);
3605     box->Destroy();
3606   } else if (IsAtomicInlineLevel()) {
3607     SetLocationAndUpdateOverflowControlsIfNeeded(box->Location());
3608     SetInlineBoxWrapper(box);
3609   }
3610 }
3611 
MoveWithEdgeOfInlineContainerIfNecessary(bool is_horizontal)3612 void LayoutBox::MoveWithEdgeOfInlineContainerIfNecessary(bool is_horizontal) {
3613   NOT_DESTROYED();
3614   DCHECK(IsOutOfFlowPositioned());
3615   DCHECK(Container()->IsLayoutInline());
3616   DCHECK(Container()->CanContainOutOfFlowPositionedElement(
3617       StyleRef().GetPosition()));
3618   // If this object is inside a relative positioned inline and its inline
3619   // position is an explicit offset from the edge of its container then it will
3620   // need to move if its inline container has changed width. We do not track if
3621   // the width has changed but if we are here then we are laying out lines
3622   // inside it, so it probably has - mark our object for layout so that it can
3623   // move to the new offset created by the new width.
3624   if (!NormalChildNeedsLayout() &&
3625       !StyleRef().HasStaticInlinePosition(is_horizontal))
3626     SetChildNeedsLayout(kMarkOnlyThis);
3627 }
3628 
DeleteLineBoxWrapper()3629 void LayoutBox::DeleteLineBoxWrapper() {
3630   NOT_DESTROYED();
3631   if (!IsInLayoutNGInlineFormattingContext() && inline_box_wrapper_) {
3632     if (!DocumentBeingDestroyed())
3633       inline_box_wrapper_->Remove();
3634     inline_box_wrapper_->Destroy();
3635     inline_box_wrapper_ = nullptr;
3636   }
3637 }
3638 
SetSpannerPlaceholder(LayoutMultiColumnSpannerPlaceholder & placeholder)3639 void LayoutBox::SetSpannerPlaceholder(
3640     LayoutMultiColumnSpannerPlaceholder& placeholder) {
3641   NOT_DESTROYED();
3642   // Not expected to change directly from one spanner to another.
3643   CHECK(!rare_data_ || !rare_data_->spanner_placeholder_);
3644   EnsureRareData().spanner_placeholder_ = &placeholder;
3645 }
3646 
ClearSpannerPlaceholder()3647 void LayoutBox::ClearSpannerPlaceholder() {
3648   NOT_DESTROYED();
3649   if (!rare_data_)
3650     return;
3651   rare_data_->spanner_placeholder_ = nullptr;
3652 }
3653 
SetPaginationStrut(LayoutUnit strut)3654 void LayoutBox::SetPaginationStrut(LayoutUnit strut) {
3655   NOT_DESTROYED();
3656   if (!strut && !rare_data_)
3657     return;
3658   EnsureRareData().pagination_strut_ = strut;
3659 }
3660 
IsBreakBetweenControllable(EBreakBetween break_value) const3661 bool LayoutBox::IsBreakBetweenControllable(EBreakBetween break_value) const {
3662   NOT_DESTROYED();
3663   if (break_value == EBreakBetween::kAuto)
3664     return true;
3665   // We currently only support non-auto break-before and break-after values on
3666   // in-flow block level elements, which is the minimum requirement according to
3667   // the spec.
3668   if (IsInline() || IsFloatingOrOutOfFlowPositioned())
3669     return false;
3670   const LayoutBlock* curr = ContainingBlock();
3671   if (!curr || !curr->IsLayoutBlockFlow())
3672     return false;
3673   const LayoutView* layout_view = View();
3674   bool view_is_paginated = layout_view->FragmentationContext();
3675   if (!view_is_paginated && !FlowThreadContainingBlock())
3676     return false;
3677   while (curr) {
3678     if (curr == layout_view) {
3679       return view_is_paginated && break_value != EBreakBetween::kColumn &&
3680              break_value != EBreakBetween::kAvoidColumn;
3681     }
3682     if (curr->IsLayoutFlowThread()) {
3683       if (break_value ==
3684           EBreakBetween::kAvoid)  // Valid in any kind of fragmentation context.
3685         return true;
3686       bool is_multicol_value = break_value == EBreakBetween::kColumn ||
3687                                break_value == EBreakBetween::kAvoidColumn;
3688       if (is_multicol_value)
3689         return true;
3690       // If this is a flow thread for a multicol container, and we have a break
3691       // value for paged, we need to keep looking.
3692     }
3693     if (curr->IsOutOfFlowPositioned())
3694       return false;
3695     curr = curr->ContainingBlock();
3696   }
3697   NOTREACHED();
3698   return false;
3699 }
3700 
IsBreakInsideControllable(EBreakInside break_value) const3701 bool LayoutBox::IsBreakInsideControllable(EBreakInside break_value) const {
3702   NOT_DESTROYED();
3703   if (break_value == EBreakInside::kAuto)
3704     return true;
3705   // First check multicol.
3706   const LayoutFlowThread* flow_thread = FlowThreadContainingBlock();
3707   // 'avoid-column' is only valid in a multicol context.
3708   if (break_value == EBreakInside::kAvoidColumn)
3709     return flow_thread;
3710   // 'avoid' is valid in any kind of fragmentation context.
3711   if (break_value == EBreakInside::kAvoid && flow_thread)
3712     return true;
3713   DCHECK(break_value == EBreakInside::kAvoidPage ||
3714          break_value == EBreakInside::kAvoid);
3715   if (View()->FragmentationContext())
3716     return true;  // The view is paginated, probably because we're printing.
3717   if (!flow_thread)
3718     return false;  // We're not inside any pagination context
3719   return false;
3720 }
3721 
BreakAfter() const3722 EBreakBetween LayoutBox::BreakAfter() const {
3723   NOT_DESTROYED();
3724   EBreakBetween break_value = StyleRef().BreakAfter();
3725   if (break_value == EBreakBetween::kAuto ||
3726       IsBreakBetweenControllable(break_value))
3727     return break_value;
3728   return EBreakBetween::kAuto;
3729 }
3730 
BreakBefore() const3731 EBreakBetween LayoutBox::BreakBefore() const {
3732   NOT_DESTROYED();
3733   EBreakBetween break_value = StyleRef().BreakBefore();
3734   if (break_value == EBreakBetween::kAuto ||
3735       IsBreakBetweenControllable(break_value))
3736     return break_value;
3737   return EBreakBetween::kAuto;
3738 }
3739 
BreakInside() const3740 EBreakInside LayoutBox::BreakInside() const {
3741   NOT_DESTROYED();
3742   EBreakInside break_value = StyleRef().BreakInside();
3743   if (break_value == EBreakInside::kAuto ||
3744       IsBreakInsideControllable(break_value))
3745     return break_value;
3746   return EBreakInside::kAuto;
3747 }
3748 
ClassABreakPointValue(EBreakBetween previous_break_after_value) const3749 EBreakBetween LayoutBox::ClassABreakPointValue(
3750     EBreakBetween previous_break_after_value) const {
3751   NOT_DESTROYED();
3752   // First assert that we're at a class A break point.
3753   DCHECK(IsBreakBetweenControllable(previous_break_after_value));
3754 
3755   return JoinFragmentainerBreakValues(previous_break_after_value,
3756                                       BreakBefore());
3757 }
3758 
NeedsForcedBreakBefore(EBreakBetween previous_break_after_value) const3759 bool LayoutBox::NeedsForcedBreakBefore(
3760     EBreakBetween previous_break_after_value) const {
3761   NOT_DESTROYED();
3762   // Forced break values are only honored when specified on in-flow objects, but
3763   // floats and out-of-flow positioned objects may be affected by a break-after
3764   // value of the previous in-flow object, even though we're not at a class A
3765   // break point.
3766   EBreakBetween break_value =
3767       IsFloatingOrOutOfFlowPositioned()
3768           ? previous_break_after_value
3769           : ClassABreakPointValue(previous_break_after_value);
3770   return IsForcedFragmentainerBreakValue(break_value);
3771 }
3772 
StartPageName() const3773 const AtomicString LayoutBox::StartPageName() const {
3774   NOT_DESTROYED();
3775   return StyleRef().Page();
3776 }
3777 
EndPageName() const3778 const AtomicString LayoutBox::EndPageName() const {
3779   NOT_DESTROYED();
3780   return StyleRef().Page();
3781 }
3782 
LocalVisualRectIgnoringVisibility() const3783 PhysicalRect LayoutBox::LocalVisualRectIgnoringVisibility() const {
3784   NOT_DESTROYED();
3785   return PhysicalSelfVisualOverflowRect();
3786 }
3787 
InflateVisualRectForFilterUnderContainer(TransformState & transform_state,const LayoutObject & container,const LayoutBoxModelObject * ancestor_to_stop_at) const3788 void LayoutBox::InflateVisualRectForFilterUnderContainer(
3789     TransformState& transform_state,
3790     const LayoutObject& container,
3791     const LayoutBoxModelObject* ancestor_to_stop_at) const {
3792   NOT_DESTROYED();
3793   transform_state.Flatten();
3794   // Apply visual overflow caused by reflections and filters defined on objects
3795   // between this object and container (not included) or ancestorToStopAt
3796   // (included).
3797   PhysicalOffset offset_from_container = OffsetFromContainer(&container);
3798   transform_state.Move(offset_from_container);
3799   for (LayoutObject* parent = Parent(); parent && parent != container;
3800        parent = parent->Parent()) {
3801     if (parent->IsBox()) {
3802       // Convert rect into coordinate space of parent to apply parent's
3803       // reflection and filter.
3804       PhysicalOffset parent_offset = parent->OffsetFromAncestor(&container);
3805       transform_state.Move(-parent_offset);
3806       To<LayoutBox>(parent)->InflateVisualRectForFilter(transform_state);
3807       transform_state.Move(parent_offset);
3808     }
3809     if (parent == ancestor_to_stop_at)
3810       break;
3811   }
3812   transform_state.Move(-offset_from_container);
3813 }
3814 
MapToVisualRectInAncestorSpaceInternal(const LayoutBoxModelObject * ancestor,TransformState & transform_state,VisualRectFlags visual_rect_flags) const3815 bool LayoutBox::MapToVisualRectInAncestorSpaceInternal(
3816     const LayoutBoxModelObject* ancestor,
3817     TransformState& transform_state,
3818     VisualRectFlags visual_rect_flags) const {
3819   NOT_DESTROYED();
3820   InflateVisualRectForFilter(transform_state);
3821 
3822   if (ancestor == this)
3823     return true;
3824 
3825   AncestorSkipInfo skip_info(ancestor, true);
3826   LayoutObject* container = Container(&skip_info);
3827   LayoutBox* table_row_container = nullptr;
3828   // Skip table row because cells and rows are in the same coordinate space (see
3829   // below, however for more comments about when |ancestor| is the table row).
3830   if ((IsTableCell() && !IsLayoutNGObject()) || IsTableCellLegacy()) {
3831     DCHECK(container->IsTableRow());
3832     DCHECK_EQ(ParentBox(), container);
3833     if (container != ancestor)
3834       container = container->Parent();
3835     else
3836       table_row_container = To<LayoutBox>(container);
3837   }
3838   if (!container)
3839     return true;
3840 
3841   PhysicalOffset container_offset;
3842   if (auto* box = DynamicTo<LayoutBox>(container)) {
3843     container_offset += PhysicalLocation(box);
3844 
3845     // If the row is the ancestor, however, add its offset back in. In effect,
3846     // this passes from the joint <td> / <tr> coordinate space to the parent
3847     // space, then back to <tr> / <td>.
3848     if (table_row_container)
3849       container_offset -= table_row_container->PhysicalLocation(box);
3850   } else {
3851     container_offset += PhysicalLocation();
3852   }
3853 
3854   const ComputedStyle& style_to_use = StyleRef();
3855   EPosition position = style_to_use.GetPosition();
3856   if (IsOutOfFlowPositioned() && container->IsLayoutInline() &&
3857       container->CanContainOutOfFlowPositionedElement(position)) {
3858     container_offset +=
3859         To<LayoutInline>(container)->OffsetForInFlowPositionedInline(*this);
3860   } else if (style_to_use.HasInFlowPosition() && Layer()) {
3861     // Apply the relative position offset when invalidating a rectangle. The
3862     // layer is translated, but the layout box isn't, so we need to do this to
3863     // get the right dirty rect.  Since this is called from
3864     // LayoutObject::setStyle, the relative position flag on the LayoutObject
3865     // has been cleared, so use the one on the style().
3866     container_offset += OffsetForInFlowPosition();
3867   }
3868 
3869   if (skip_info.FilterSkipped()) {
3870     InflateVisualRectForFilterUnderContainer(transform_state, *container,
3871                                              ancestor);
3872   }
3873 
3874   if (!MapVisualRectToContainer(container, container_offset, ancestor,
3875                                 visual_rect_flags, transform_state))
3876     return false;
3877 
3878   if (skip_info.AncestorSkipped()) {
3879     bool preserve3D = container->StyleRef().Preserves3D();
3880     TransformState::TransformAccumulation accumulation =
3881         preserve3D ? TransformState::kAccumulateTransform
3882                    : TransformState::kFlattenTransform;
3883 
3884     // If the ancestor is below the container, then we need to map the rect into
3885     // ancestor's coordinates.
3886     PhysicalOffset ancestor_container_offset =
3887         ancestor->OffsetFromAncestor(container);
3888     transform_state.Move(-ancestor_container_offset, accumulation);
3889     return true;
3890   }
3891 
3892   if (auto* layout_view = DynamicTo<LayoutView>(container)) {
3893     bool use_fixed_position_adjustment =
3894         position == EPosition::kFixed && container == ancestor;
3895     return layout_view->MapToVisualRectInAncestorSpaceInternal(
3896         ancestor, transform_state, use_fixed_position_adjustment ? kIsFixed : 0,
3897         visual_rect_flags);
3898   } else {
3899     return container->MapToVisualRectInAncestorSpaceInternal(
3900         ancestor, transform_state, visual_rect_flags);
3901   }
3902 }
3903 
InflateVisualRectForFilter(TransformState & transform_state) const3904 void LayoutBox::InflateVisualRectForFilter(
3905     TransformState& transform_state) const {
3906   NOT_DESTROYED();
3907   if (!Layer() || !Layer()->PaintsWithFilters())
3908     return;
3909 
3910   transform_state.Flatten();
3911   PhysicalRect rect = PhysicalRect::EnclosingRect(
3912       transform_state.LastPlanarQuad().BoundingBox());
3913   transform_state.SetQuad(
3914       FloatQuad(FloatRect(Layer()->MapRectForFilter(rect))));
3915 }
3916 
ShouldRecalculateMinMaxWidthsAffectedByAncestor(const LayoutBox * box)3917 static bool ShouldRecalculateMinMaxWidthsAffectedByAncestor(
3918     const LayoutBox* box) {
3919   if (box->IntrinsicLogicalWidthsDirty()) {
3920     // If the preferred widths are already dirty at this point (during layout),
3921     // it actually means that we never need to calculate them, since that should
3922     // have been carried out by an ancestor that's sized based on preferred
3923     // widths (a shrink-to-fit container, for instance). In such cases the
3924     // object will be left as dirty indefinitely, and it would just be a waste
3925     // of time to calculate the preferred withs when nobody needs them.
3926     return false;
3927   }
3928   if (const LayoutBox* containing_block = box->ContainingBlock()) {
3929     if (containing_block->NeedsPreferredWidthsRecalculation() &&
3930         !containing_block->IntrinsicLogicalWidthsDirty()) {
3931       // If our containing block also has min/max widths that are affected by
3932       // the ancestry, we have already dealt with this object as well. Avoid
3933       // unnecessary work and O(n^2) time complexity.
3934       return false;
3935     }
3936   }
3937   return true;
3938 }
3939 
UpdateLogicalWidth()3940 void LayoutBox::UpdateLogicalWidth() {
3941   NOT_DESTROYED();
3942   if (NeedsPreferredWidthsRecalculation()) {
3943     if (ShouldRecalculateMinMaxWidthsAffectedByAncestor(this)) {
3944       // Laying out this object means that its containing block is also being
3945       // laid out. This object is special, in that its min/max widths depend on
3946       // the ancestry (min/max width calculation should ideally be strictly
3947       // bottom-up, but that's not always the case), so since the containing
3948       // block size may have changed, we need to recalculate the min/max widths
3949       // of this object, and every child that has the same issue, recursively.
3950       SetIntrinsicLogicalWidthsDirty(kMarkOnlyThis);
3951 
3952       // Since all this takes place during actual layout, instead of being part
3953       // of min/max the width calculation machinery, we need to enter said
3954       // machinery here, to make sure that what was dirtied is actually
3955       // recalculated. Leaving things dirty would mean that any subsequent
3956       // dirtying of descendants would fail.
3957       UpdateCachedIntrinsicLogicalWidthsIfNeeded();
3958     }
3959   }
3960 
3961   LogicalExtentComputedValues computed_values;
3962   ComputeLogicalWidth(computed_values);
3963 
3964   SetLogicalWidth(computed_values.extent_);
3965   SetLogicalLeft(computed_values.position_);
3966   SetMarginStart(computed_values.margins_.start_);
3967   SetMarginEnd(computed_values.margins_.end_);
3968 }
3969 
GetMaxWidthListMarker(const LayoutBox * layout_object)3970 static float GetMaxWidthListMarker(const LayoutBox* layout_object) {
3971 #if DCHECK_IS_ON()
3972   DCHECK(layout_object);
3973   Node* parent_node = layout_object->GeneratingNode();
3974   DCHECK(parent_node);
3975   DCHECK(IsA<HTMLOListElement>(parent_node) ||
3976          IsA<HTMLUListElement>(parent_node));
3977   DCHECK_NE(layout_object->StyleRef().TextAutosizingMultiplier(), 1);
3978 #endif
3979   float max_width = 0;
3980   for (LayoutObject* child = layout_object->SlowFirstChild(); child;
3981        child = child->NextSibling()) {
3982     if (!child->IsListItem())
3983       continue;
3984 
3985     auto* list_item = To<LayoutBox>(child);
3986     for (LayoutObject* item_child = list_item->SlowFirstChild(); item_child;
3987          item_child = item_child->NextSibling()) {
3988       if (!item_child->IsListMarkerForNormalContent())
3989         continue;
3990       auto* item_marker = To<LayoutBox>(item_child);
3991       // Make sure to compute the autosized width.
3992       if (item_marker->NeedsLayout())
3993         item_marker->UpdateLayout();
3994       max_width = std::max<float>(
3995           max_width,
3996           To<LayoutListMarker>(item_marker)->LogicalWidth().ToFloat());
3997       break;
3998     }
3999   }
4000   return max_width;
4001 }
4002 
ContainerWidthInInlineDirection() const4003 LayoutUnit LayoutBox::ContainerWidthInInlineDirection() const {
4004   NOT_DESTROYED();
4005   LayoutBlock* cb = ContainingBlock();
4006 
4007   if (IsParallelWritingMode(cb->StyleRef().GetWritingMode(),
4008                             StyleRef().GetWritingMode())) {
4009     return std::max(LayoutUnit(), ContainingBlockLogicalWidthForContent());
4010   }
4011 
4012   // PerpendicularContainingBlockLogicalHeight() can return -1 in some
4013   // situations but we cannot have a negative width, that's why we clamp it to
4014   // zero.
4015   return PerpendicularContainingBlockLogicalHeight().ClampNegativeToZero();
4016 }
4017 
ShouldComputeLogicalWidthFromAspectRatio(LayoutUnit * out_logical_height) const4018 bool LayoutBox::ShouldComputeLogicalWidthFromAspectRatio(
4019     LayoutUnit* out_logical_height) const {
4020   NOT_DESTROYED();
4021   if (StyleRef().AspectRatio().IsAuto())
4022     return false;
4023 
4024   if (!HasOverrideLogicalHeight() &&
4025       !ShouldComputeLogicalWidthFromAspectRatioAndInsets() &&
4026       !StyleRef().LogicalHeight().IsFixed() &&
4027       !StyleRef().LogicalHeight().IsPercentOrCalc()) {
4028     return false;
4029   }
4030 
4031   LogicalExtentComputedValues values;
4032   values.extent_ = kIndefiniteSize;
4033   ComputeLogicalHeight(values);
4034   if (values.extent_ == kIndefiniteSize)
4035     return false;
4036 
4037   if (out_logical_height)
4038     *out_logical_height = values.extent_;
4039   return true;
4040 }
4041 
ComputeLogicalWidthFromAspectRatio(LayoutUnit * out_logical_width) const4042 bool LayoutBox::ComputeLogicalWidthFromAspectRatio(
4043     LayoutUnit* out_logical_width) const {
4044   NOT_DESTROYED();
4045   LayoutUnit logical_height_for_ar;
4046   if (!ShouldComputeLogicalWidthFromAspectRatio(&logical_height_for_ar))
4047     return false;
4048 
4049   LayoutUnit container_width_in_inline_direction =
4050       ContainerWidthInInlineDirection();
4051 
4052   NGBoxStrut border_padding(BorderStart() + ComputedCSSPaddingStart(),
4053                             BorderEnd() + ComputedCSSPaddingEnd(),
4054                             BorderBefore() + ComputedCSSPaddingBefore(),
4055                             BorderAfter() + ComputedCSSPaddingAfter());
4056   LayoutUnit logical_width =
4057       InlineSizeFromAspectRatio(border_padding, StyleRef().LogicalAspectRatio(),
4058                                 StyleRef().BoxSizing(), logical_height_for_ar);
4059   *out_logical_width = ConstrainLogicalWidthByMinMax(
4060       logical_width, container_width_in_inline_direction, ContainingBlock(),
4061       /* allow_intrinsic */ false);
4062   return true;
4063 }
4064 
4065 DISABLE_CFI_PERF
ComputeLogicalWidth(LogicalExtentComputedValues & computed_values) const4066 void LayoutBox::ComputeLogicalWidth(
4067     LogicalExtentComputedValues& computed_values) const {
4068   NOT_DESTROYED();
4069   computed_values.position_ = LogicalLeft();
4070   computed_values.margins_.start_ = MarginStart();
4071   computed_values.margins_.end_ = MarginEnd();
4072 
4073   // The parent box is flexing us, so it has increased or decreased our
4074   // width.  Use the width from the style context.
4075   if (HasOverrideLogicalWidth()) {
4076     computed_values.extent_ = OverrideLogicalWidth();
4077     return;
4078   }
4079 
4080   if (IsOutOfFlowPositioned()) {
4081     ComputePositionedLogicalWidth(computed_values);
4082     return;
4083   }
4084 
4085   // FIXME: Account for writing-mode in flexible boxes.
4086   // https://bugs.webkit.org/show_bug.cgi?id=46418
4087   bool in_vertical_box =
4088       Parent()->IsDeprecatedFlexibleBox() &&
4089       (Parent()->StyleRef().BoxOrient() == EBoxOrient::kVertical);
4090   bool stretching =
4091       (Parent()->StyleRef().BoxAlign() == EBoxAlignment::kStretch);
4092   // TODO (lajava): Stretching is the only reason why we don't want the box to
4093   // be treated as a replaced element, so we could perhaps refactor all this
4094   // logic, not only for flex and grid since alignment is intended to be applied
4095   // to any block.
4096   bool treat_as_replaced = ShouldComputeSizeAsReplaced() &&
4097                            (!in_vertical_box || !stretching) &&
4098                            (!IsGridItem() || !HasStretchedLogicalWidth());
4099   const ComputedStyle& style_to_use = StyleRef();
4100   LayoutUnit container_logical_width =
4101       std::max(LayoutUnit(), ContainingBlockLogicalWidthForContent());
4102 
4103   if (IsInline() && !IsInlineBlockOrInlineTable()) {
4104     // just calculate margins
4105     computed_values.margins_.start_ = MinimumValueForLength(
4106         style_to_use.MarginStart(), container_logical_width);
4107     computed_values.margins_.end_ = MinimumValueForLength(
4108         style_to_use.MarginEnd(), container_logical_width);
4109     if (treat_as_replaced) {
4110       computed_values.extent_ = std::max(
4111           ComputeReplacedLogicalWidth() + BorderAndPaddingLogicalWidth(),
4112           PreferredLogicalWidths().min_size);
4113     }
4114     return;
4115   }
4116 
4117   LayoutUnit container_width_in_inline_direction =
4118       ContainerWidthInInlineDirection();
4119   LayoutBlock* cb = ContainingBlock();
4120 
4121   if (StyleRef().LogicalWidth().IsAuto() && !treat_as_replaced &&
4122       ComputeLogicalWidthFromAspectRatio(&computed_values.extent_)) {
4123     /* we're good */
4124   } else if (treat_as_replaced) {
4125     computed_values.extent_ =
4126         ComputeReplacedLogicalWidth() + BorderAndPaddingLogicalWidth();
4127   } else {
4128     LayoutUnit preferred_width = ComputeLogicalWidthUsing(
4129         kMainOrPreferredSize, style_to_use.LogicalWidth(),
4130         container_width_in_inline_direction, cb);
4131     computed_values.extent_ = ConstrainLogicalWidthByMinMax(
4132         preferred_width, container_width_in_inline_direction, cb);
4133   }
4134 
4135   // Margin calculations.
4136   ComputeMarginsForDirection(
4137       kInlineDirection, cb, container_logical_width, computed_values.extent_,
4138       computed_values.margins_.start_, computed_values.margins_.end_,
4139       StyleRef().MarginStart(), StyleRef().MarginEnd());
4140 
4141   bool has_perpendicular_containing_block =
4142       cb->IsHorizontalWritingMode() != IsHorizontalWritingMode();
4143   if (!has_perpendicular_containing_block && container_logical_width &&
4144       container_logical_width !=
4145           (computed_values.extent_ + computed_values.margins_.start_ +
4146            computed_values.margins_.end_) &&
4147       !IsFloating() && !IsInline() &&
4148       !cb->IsFlexibleBoxIncludingDeprecatedAndNG() && !cb->IsLayoutGrid()) {
4149     LayoutUnit new_margin_total =
4150         container_logical_width - computed_values.extent_;
4151     bool has_inverted_direction = cb->StyleRef().IsLeftToRightDirection() !=
4152                                   StyleRef().IsLeftToRightDirection();
4153     if (has_inverted_direction) {
4154       computed_values.margins_.start_ =
4155           new_margin_total - computed_values.margins_.end_;
4156     } else {
4157       computed_values.margins_.end_ =
4158           new_margin_total - computed_values.margins_.start_;
4159     }
4160   }
4161 
4162   if (style_to_use.TextAutosizingMultiplier() != 1 &&
4163       style_to_use.MarginStart().IsFixed()) {
4164     Node* parent_node = GeneratingNode();
4165     if (parent_node && (IsA<HTMLOListElement>(*parent_node) ||
4166                         IsA<HTMLUListElement>(*parent_node))) {
4167       // Make sure the markers in a list are properly positioned (i.e. not
4168       // chopped off) when autosized.
4169       const float adjusted_margin =
4170           (1 - 1.0 / style_to_use.TextAutosizingMultiplier()) *
4171           GetMaxWidthListMarker(this);
4172       bool has_inverted_direction = cb->StyleRef().IsLeftToRightDirection() !=
4173                                     StyleRef().IsLeftToRightDirection();
4174       if (has_inverted_direction)
4175         computed_values.margins_.end_ += adjusted_margin;
4176       else
4177         computed_values.margins_.start_ += adjusted_margin;
4178     }
4179   }
4180 }
4181 
FillAvailableMeasure(LayoutUnit available_logical_width) const4182 LayoutUnit LayoutBox::FillAvailableMeasure(
4183     LayoutUnit available_logical_width) const {
4184   NOT_DESTROYED();
4185   LayoutUnit margin_start;
4186   LayoutUnit margin_end;
4187   return FillAvailableMeasure(available_logical_width, margin_start,
4188                               margin_end);
4189 }
4190 
FillAvailableMeasure(LayoutUnit available_logical_width,LayoutUnit & margin_start,LayoutUnit & margin_end) const4191 LayoutUnit LayoutBox::FillAvailableMeasure(LayoutUnit available_logical_width,
4192                                            LayoutUnit& margin_start,
4193                                            LayoutUnit& margin_end) const {
4194   NOT_DESTROYED();
4195   DCHECK_GE(available_logical_width, 0);
4196 
4197   bool isOrthogonalElement =
4198       IsHorizontalWritingMode() != ContainingBlock()->IsHorizontalWritingMode();
4199   LayoutUnit available_size_for_resolving_margin =
4200       isOrthogonalElement ? ContainingBlockLogicalWidthForContent()
4201                           : available_logical_width;
4202   margin_start = MinimumValueForLength(StyleRef().MarginStart(),
4203                                        available_size_for_resolving_margin);
4204   margin_end = MinimumValueForLength(StyleRef().MarginEnd(),
4205                                      available_size_for_resolving_margin);
4206 
4207   if (HasOverrideAvailableInlineSize())
4208     available_logical_width = OverrideAvailableInlineSize();
4209 
4210   LayoutUnit available = available_logical_width - margin_start - margin_end;
4211   available = std::max(available, LayoutUnit());
4212   return available;
4213 }
4214 
4215 DISABLE_CFI_PERF
ComputeIntrinsicLogicalWidthUsing(const Length & logical_width_length,LayoutUnit available_logical_width) const4216 LayoutUnit LayoutBox::ComputeIntrinsicLogicalWidthUsing(
4217     const Length& logical_width_length,
4218     LayoutUnit available_logical_width) const {
4219   NOT_DESTROYED();
4220   if (logical_width_length.IsFillAvailable()) {
4221     if (!IsA<HTMLMarqueeElement>(GetNode())) {
4222       UseCounter::Count(GetDocument(),
4223                         WebFeature::kCSSFillAvailableLogicalWidth);
4224     }
4225     return std::max(BorderAndPaddingLogicalWidth(),
4226                     FillAvailableMeasure(available_logical_width));
4227   }
4228 
4229   MinMaxSizesType type = MinMaxSizesType::kContent;
4230   if (logical_width_length.IsMinIntrinsic())
4231     type = MinMaxSizesType::kIntrinsic;
4232   MinMaxSizes sizes = IntrinsicLogicalWidths(type);
4233 
4234   if (logical_width_length.IsMinContent() ||
4235       logical_width_length.IsMinIntrinsic())
4236     return sizes.min_size;
4237 
4238   if (logical_width_length.IsMaxContent())
4239     return sizes.max_size;
4240 
4241   if (logical_width_length.IsFitContent()) {
4242     return sizes.ClampSizeToMinAndMax(
4243         FillAvailableMeasure(available_logical_width));
4244   }
4245 
4246   NOTREACHED();
4247   return LayoutUnit();
4248 }
4249 
4250 DISABLE_CFI_PERF
ComputeLogicalWidthUsing(SizeType width_type,const Length & logical_width,LayoutUnit available_logical_width,const LayoutBlock * cb) const4251 LayoutUnit LayoutBox::ComputeLogicalWidthUsing(
4252     SizeType width_type,
4253     const Length& logical_width,
4254     LayoutUnit available_logical_width,
4255     const LayoutBlock* cb) const {
4256   NOT_DESTROYED();
4257   DCHECK(width_type == kMinSize || width_type == kMainOrPreferredSize ||
4258          !logical_width.IsAuto());
4259   if (width_type == kMinSize && logical_width.IsAuto())
4260     return AdjustBorderBoxLogicalWidthForBoxSizing(0);
4261 
4262   if (logical_width.IsSpecified()) {
4263     // FIXME: If the containing block flow is perpendicular to our direction we
4264     // need to use the available logical height instead.
4265     return AdjustBorderBoxLogicalWidthForBoxSizing(
4266         ValueForLength(logical_width, available_logical_width));
4267   }
4268 
4269   if (logical_width.IsContentOrIntrinsicOrFillAvailable()) {
4270     return ComputeIntrinsicLogicalWidthUsing(logical_width,
4271                                              available_logical_width);
4272   }
4273 
4274   LayoutUnit margin_start;
4275   LayoutUnit margin_end;
4276   LayoutUnit logical_width_result =
4277       FillAvailableMeasure(available_logical_width, margin_start, margin_end);
4278 
4279   auto* child_block_flow = DynamicTo<LayoutBlockFlow>(cb);
4280   if (ShrinkToAvoidFloats() && child_block_flow &&
4281       child_block_flow->ContainsFloats()) {
4282     logical_width_result = std::min(
4283         logical_width_result, ShrinkLogicalWidthToAvoidFloats(
4284                                   margin_start, margin_end, child_block_flow));
4285   }
4286 
4287   if (width_type == kMainOrPreferredSize &&
4288       SizesLogicalWidthToFitContent(logical_width)) {
4289     // Reset width so that any percent margins on inline children do not
4290     // use it when calculating min/max preferred width.
4291     // TODO(crbug.com/710026): Remove const_cast
4292     LayoutUnit w = LogicalWidth();
4293     const_cast<LayoutBox*>(this)->SetLogicalWidth(LayoutUnit());
4294     MinMaxSizes preferred_logical_widths = PreferredLogicalWidths();
4295     LayoutUnit result =
4296         preferred_logical_widths.ClampSizeToMinAndMax(logical_width_result);
4297     const_cast<LayoutBox*>(this)->SetLogicalWidth(w);
4298     return result;
4299   }
4300   return logical_width_result;
4301 }
4302 
ColumnFlexItemHasStretchAlignment() const4303 bool LayoutBox::ColumnFlexItemHasStretchAlignment() const {
4304   NOT_DESTROYED();
4305   // auto margins mean we don't stretch. Note that this function will only be
4306   // used for widths, so we don't have to check marginBefore/marginAfter.
4307   const auto& parent_style = Parent()->StyleRef();
4308   DCHECK(parent_style.ResolvedIsColumnFlexDirection());
4309   if (StyleRef().MarginStart().IsAuto() || StyleRef().MarginEnd().IsAuto())
4310     return false;
4311   return StyleRef()
4312              .ResolvedAlignSelf(
4313                  ContainingBlock()->SelfAlignmentNormalBehavior(),
4314                  &parent_style)
4315              .GetPosition() == ItemPosition::kStretch;
4316 }
4317 
IsStretchingColumnFlexItem() const4318 bool LayoutBox::IsStretchingColumnFlexItem() const {
4319   NOT_DESTROYED();
4320   LayoutObject* parent = Parent();
4321   if (parent->StyleRef().IsDeprecatedWebkitBox() &&
4322       parent->StyleRef().BoxOrient() == EBoxOrient::kVertical &&
4323       parent->StyleRef().BoxAlign() == EBoxAlignment::kStretch)
4324     return true;
4325 
4326   // We don't stretch multiline flexboxes because they need to apply line
4327   // spacing (align-content) first.
4328   if (parent->IsFlexibleBoxIncludingNG() &&
4329       parent->StyleRef().FlexWrap() == EFlexWrap::kNowrap &&
4330       parent->StyleRef().ResolvedIsColumnFlexDirection() &&
4331       ColumnFlexItemHasStretchAlignment())
4332     return true;
4333   return false;
4334 }
4335 
4336 // TODO (lajava) Can/Should we move this inside specific layout classes (flex.
4337 // grid)? Can we refactor columnFlexItemHasStretchAlignment logic?
HasStretchedLogicalWidth() const4338 bool LayoutBox::HasStretchedLogicalWidth() const {
4339   NOT_DESTROYED();
4340   const ComputedStyle& style = StyleRef();
4341   if (!style.LogicalWidth().IsAuto() || style.MarginStart().IsAuto() ||
4342       style.MarginEnd().IsAuto())
4343     return false;
4344   LayoutBlock* cb = ContainingBlock();
4345   if (!cb) {
4346     // We are evaluating align-self/justify-self, which default to 'normal' for
4347     // the root element. The 'normal' value behaves like 'start' except for
4348     // Flexbox Items, which obviously should have a container.
4349     return false;
4350   }
4351   if (cb->IsHorizontalWritingMode() != IsHorizontalWritingMode()) {
4352     return style
4353                .ResolvedAlignSelf(cb->SelfAlignmentNormalBehavior(this),
4354                                   cb->Style())
4355                .GetPosition() == ItemPosition::kStretch;
4356   }
4357   return style
4358              .ResolvedJustifySelf(cb->SelfAlignmentNormalBehavior(this),
4359                                   cb->Style())
4360              .GetPosition() == ItemPosition::kStretch;
4361 }
4362 
SizesLogicalWidthToFitContent(const Length & logical_width) const4363 bool LayoutBox::SizesLogicalWidthToFitContent(
4364     const Length& logical_width) const {
4365   NOT_DESTROYED();
4366   if (IsFloating() || IsInlineBlockOrInlineTable() ||
4367       StyleRef().HasOutOfFlowPosition())
4368     return true;
4369 
4370   if (IsGridItem())
4371     return !HasStretchedLogicalWidth();
4372 
4373   // Flexible box items should shrink wrap, so we lay them out at their
4374   // intrinsic widths. In the case of columns that have a stretch alignment, we
4375   // go ahead and layout at the stretched size to avoid an extra layout when
4376   // applying alignment.
4377   if (Parent()->IsFlexibleBoxIncludingNG()) {
4378     // For multiline columns, we need to apply align-content first, so we can't
4379     // stretch now.
4380     if (!Parent()->StyleRef().ResolvedIsColumnFlexDirection() ||
4381         Parent()->StyleRef().FlexWrap() != EFlexWrap::kNowrap)
4382       return true;
4383     if (!ColumnFlexItemHasStretchAlignment())
4384       return true;
4385   }
4386 
4387   // Flexible horizontal boxes lay out children at their intrinsic widths. Also
4388   // vertical boxes that don't stretch their kids lay out their children at
4389   // their intrinsic widths.
4390   // FIXME: Think about writing-mode here.
4391   // https://bugs.webkit.org/show_bug.cgi?id=46473
4392   if ((Parent()->IsDeprecatedFlexibleBox() ||
4393        (Parent()->StyleRef().IsDeprecatedWebkitBox() &&
4394         Parent()->IsFlexibleBox())) &&
4395       (Parent()->StyleRef().BoxOrient() == EBoxOrient::kHorizontal ||
4396        Parent()->StyleRef().BoxAlign() != EBoxAlignment::kStretch))
4397     return true;
4398 
4399   // Button, input, select, textarea, and legend treat width value of 'auto' as
4400   // 'intrinsic' unless it's in a stretching column flexbox.
4401   // FIXME: Think about writing-mode here.
4402   // https://bugs.webkit.org/show_bug.cgi?id=46473
4403   if (logical_width.IsAuto() && !IsStretchingColumnFlexItem() &&
4404       AutoWidthShouldFitContent())
4405     return true;
4406 
4407   if (IsHorizontalWritingMode() != ContainingBlock()->IsHorizontalWritingMode())
4408     return true;
4409 
4410   if (IsCustomItem())
4411     return IsCustomItemShrinkToFit();
4412 
4413   return false;
4414 }
4415 
AutoWidthShouldFitContent() const4416 bool LayoutBox::AutoWidthShouldFitContent() const {
4417   NOT_DESTROYED();
4418   return GetNode() &&
4419          (IsA<HTMLInputElement>(*GetNode()) ||
4420           IsA<HTMLSelectElement>(*GetNode()) ||
4421           IsA<HTMLButtonElement>(*GetNode()) ||
4422           IsA<HTMLTextAreaElement>(*GetNode()) || IsRenderedLegend());
4423 }
4424 
ComputeMarginsForDirection(MarginDirection flow_direction,const LayoutBlock * containing_block,LayoutUnit container_width,LayoutUnit child_width,LayoutUnit & margin_start,LayoutUnit & margin_end,Length margin_start_length,Length margin_end_length) const4425 void LayoutBox::ComputeMarginsForDirection(MarginDirection flow_direction,
4426                                            const LayoutBlock* containing_block,
4427                                            LayoutUnit container_width,
4428                                            LayoutUnit child_width,
4429                                            LayoutUnit& margin_start,
4430                                            LayoutUnit& margin_end,
4431                                            Length margin_start_length,
4432                                            Length margin_end_length) const {
4433   NOT_DESTROYED();
4434   // First assert that we're not calling this method on box types that don't
4435   // support margins.
4436   DCHECK(!IsTableCell());
4437   DCHECK(!IsTableRow());
4438   DCHECK(!IsTableSection());
4439   DCHECK(!IsLayoutTableCol());
4440   if (flow_direction == kBlockDirection || IsFloating() || IsInline()) {
4441     // Margins are calculated with respect to the logical width of
4442     // the containing block (8.3)
4443     // Inline blocks/tables and floats don't have their margins increased.
4444     margin_start = MinimumValueForLength(margin_start_length, container_width);
4445     margin_end = MinimumValueForLength(margin_end_length, container_width);
4446     return;
4447   }
4448 
4449   if (containing_block->IsFlexibleBoxIncludingNG()) {
4450     // We need to let flexbox handle the margin adjustment - otherwise, flexbox
4451     // will think we're wider than we actually are and calculate line sizes
4452     // wrong. See also https://drafts.csswg.org/css-flexbox/#auto-margins
4453     if (margin_start_length.IsAuto())
4454       margin_start_length = Length::Fixed(0);
4455     if (margin_end_length.IsAuto())
4456       margin_end_length = Length::Fixed(0);
4457   }
4458 
4459   LayoutUnit margin_start_width =
4460       MinimumValueForLength(margin_start_length, container_width);
4461   LayoutUnit margin_end_width =
4462       MinimumValueForLength(margin_end_length, container_width);
4463 
4464   LayoutUnit available_width = container_width;
4465   auto* containing_block_flow = DynamicTo<LayoutBlockFlow>(containing_block);
4466   if (CreatesNewFormattingContext() && containing_block_flow &&
4467       containing_block_flow->ContainsFloats()) {
4468     available_width = ContainingBlockAvailableLineWidth();
4469     if (ShrinkToAvoidFloats() && available_width < container_width) {
4470       margin_start = std::max(LayoutUnit(), margin_start_width);
4471       margin_end = std::max(LayoutUnit(), margin_end_width);
4472     }
4473   }
4474 
4475   // CSS 2.1 (10.3.3): "If 'width' is not 'auto' and 'border-left-width' +
4476   // 'padding-left' + 'width' + 'padding-right' + 'border-right-width' (plus any
4477   // of 'margin-left' or 'margin-right' that are not 'auto') is larger than the
4478   // width of the containing block, then any 'auto' values for 'margin-left' or
4479   // 'margin-right' are, for the following rules, treated as zero.
4480   LayoutUnit margin_box_width =
4481       child_width + (!StyleRef().Width().IsAuto()
4482                          ? margin_start_width + margin_end_width
4483                          : LayoutUnit());
4484 
4485   if (margin_box_width < available_width) {
4486     // CSS 2.1: "If both 'margin-left' and 'margin-right' are 'auto', their used
4487     // values are equal. This horizontally centers the element with respect to
4488     // the edges of the containing block."
4489     const ComputedStyle& containing_block_style = containing_block->StyleRef();
4490     if ((margin_start_length.IsAuto() && margin_end_length.IsAuto()) ||
4491         (!margin_start_length.IsAuto() && !margin_end_length.IsAuto() &&
4492          containing_block_style.GetTextAlign() == ETextAlign::kWebkitCenter)) {
4493       // Other browsers center the margin box for align=center elements so we
4494       // match them here.
4495       LayoutUnit centered_margin_box_start =
4496           std::max(LayoutUnit(), (available_width - child_width -
4497                                   margin_start_width - margin_end_width) /
4498                                      2);
4499       margin_start = centered_margin_box_start + margin_start_width;
4500       margin_end =
4501           available_width - child_width - margin_start + margin_end_width;
4502       return;
4503     }
4504 
4505     // Adjust margins for the align attribute
4506     if ((!containing_block_style.IsLeftToRightDirection() &&
4507          containing_block_style.GetTextAlign() == ETextAlign::kWebkitLeft) ||
4508         (containing_block_style.IsLeftToRightDirection() &&
4509          containing_block_style.GetTextAlign() == ETextAlign::kWebkitRight)) {
4510       if (containing_block_style.IsLeftToRightDirection() !=
4511           StyleRef().IsLeftToRightDirection()) {
4512         if (!margin_start_length.IsAuto())
4513           margin_end_length = Length::Auto();
4514       } else {
4515         if (!margin_end_length.IsAuto())
4516           margin_start_length = Length::Auto();
4517       }
4518     }
4519 
4520     // CSS 2.1: "If there is exactly one value specified as 'auto', its used
4521     // value follows from the equality."
4522     if (margin_end_length.IsAuto()) {
4523       margin_start = margin_start_width;
4524       margin_end = available_width - child_width - margin_start;
4525       return;
4526     }
4527 
4528     if (margin_start_length.IsAuto()) {
4529       margin_end = margin_end_width;
4530       margin_start = available_width - child_width - margin_end;
4531       return;
4532     }
4533   }
4534 
4535   // Either no auto margins, or our margin box width is >= the container width,
4536   // auto margins will just turn into 0.
4537   margin_start = margin_start_width;
4538   margin_end = margin_end_width;
4539 }
4540 
4541 DISABLE_CFI_PERF
UpdateLogicalHeight()4542 void LayoutBox::UpdateLogicalHeight() {
4543   NOT_DESTROYED();
4544   if (!HasOverrideLogicalHeight()) {
4545     // If we have an override height, our children will have sized themselves
4546     // relative to our override height, which would make our intrinsic size
4547     // incorrect (too big).
4548     intrinsic_content_logical_height_ = ContentLogicalHeight();
4549   }
4550 
4551   LogicalExtentComputedValues computed_values;
4552   ComputeLogicalHeight(computed_values);
4553 
4554   SetLogicalHeight(computed_values.extent_);
4555   SetLogicalTop(computed_values.position_);
4556   SetMarginBefore(computed_values.margins_.before_);
4557   SetMarginAfter(computed_values.margins_.after_);
4558 }
4559 
HeightForDocumentElement(const Document & document)4560 static inline const Length& HeightForDocumentElement(const Document& document) {
4561   return document.documentElement()
4562       ->GetLayoutObject()
4563       ->StyleRef()
4564       .LogicalHeight();
4565 }
4566 
ComputeLogicalHeight(LogicalExtentComputedValues & computed_values) const4567 void LayoutBox::ComputeLogicalHeight(
4568     LogicalExtentComputedValues& computed_values) const {
4569   NOT_DESTROYED();
4570   LayoutUnit height;
4571   if (HasOverrideIntrinsicContentLogicalHeight()) {
4572     height = OverrideIntrinsicContentLogicalHeight() +
4573              BorderAndPaddingLogicalHeight() +
4574              ComputeLogicalScrollbars().BlockSum();
4575   } else {
4576     LayoutUnit default_height = DefaultIntrinsicContentBlockSize();
4577     if (default_height != kIndefiniteSize) {
4578       height = default_height + BorderAndPaddingLogicalHeight();
4579       // <textarea>'s intrinsic size should ignore scrollbar existence.
4580       if (!IsTextAreaIncludingNG())
4581         height += ComputeLogicalScrollbars().BlockSum();
4582       // FIXME: The logical height of the inner editor box should have been
4583       // added before calling ComputeLogicalHeight to avoid this hack.
4584       if (IsTextControlIncludingNG())
4585         SetIntrinsicContentLogicalHeight(default_height);
4586     } else if (ShouldApplySizeContainment() && !IsLayoutGrid()) {
4587       height = BorderAndPaddingLogicalHeight() +
4588                ComputeLogicalScrollbars().BlockSum();
4589     } else {
4590       height = LogicalHeight();
4591     }
4592   }
4593   ComputeLogicalHeight(height, LogicalTop(), computed_values);
4594 }
4595 
ComputeLogicalHeight(LayoutUnit logical_height,LayoutUnit logical_top,LogicalExtentComputedValues & computed_values) const4596 void LayoutBox::ComputeLogicalHeight(
4597     LayoutUnit logical_height,
4598     LayoutUnit logical_top,
4599     LogicalExtentComputedValues& computed_values) const {
4600   NOT_DESTROYED();
4601   computed_values.extent_ = logical_height;
4602   computed_values.position_ = logical_top;
4603 
4604   // Cell height is managed by the table.
4605   if (IsTableCell())
4606     return;
4607 
4608   Length h;
4609   if (IsOutOfFlowPositioned()) {
4610     ComputePositionedLogicalHeight(computed_values);
4611     if (HasOverrideLogicalHeight())
4612       computed_values.extent_ = OverrideLogicalHeight();
4613   } else {
4614     LayoutBlock* cb = ContainingBlock();
4615 
4616     // If we are perpendicular to our containing block then we need to resolve
4617     // our block-start and block-end margins so that if they are 'auto' we are
4618     // centred or aligned within the inline flow containing block: this is done
4619     // by computing the margins as though they are inline.
4620     // Note that as this is the 'sizing phase' we are using our own writing mode
4621     // rather than the containing block's. We use the containing block's writing
4622     // mode when figuring out the block-direction margins for positioning in
4623     // |computeAndSetBlockDirectionMargins| (i.e. margin collapsing etc.).
4624     // http://www.w3.org/TR/2014/CR-css-writing-modes-3-20140320/#orthogonal-flows
4625     MarginDirection flow_direction =
4626         IsHorizontalWritingMode() != cb->IsHorizontalWritingMode()
4627             ? kInlineDirection
4628             : kBlockDirection;
4629 
4630     // For tables, calculate margins only.
4631     if (IsTable()) {
4632       ComputeMarginsForDirection(
4633           flow_direction, cb, ContainingBlockLogicalWidthForContent(),
4634           computed_values.extent_, computed_values.margins_.before_,
4635           computed_values.margins_.after_, StyleRef().MarginBefore(),
4636           StyleRef().MarginAfter());
4637       return;
4638     }
4639 
4640     bool check_min_max_height = false;
4641     bool compute_size_as_replaced = ShouldComputeSizeAsReplaced();
4642 
4643     // The parent box is flexing us, so it has increased or decreased our
4644     // height. We have to grab our cached flexible height.
4645     if (HasOverrideLogicalHeight()) {
4646       h = Length::Fixed(OverrideLogicalHeight());
4647     } else if (compute_size_as_replaced) {
4648       h = Length::Fixed(ComputeReplacedLogicalHeight() +
4649                         BorderAndPaddingLogicalHeight());
4650     } else {
4651       h = StyleRef().LogicalHeight();
4652       check_min_max_height = true;
4653     }
4654 
4655     LayoutUnit height_result;
4656     if (check_min_max_height) {
4657       if (!compute_size_as_replaced &&
4658           ShouldComputeLogicalHeightFromAspectRatio()) {
4659         NGBoxStrut border_padding(BorderStart() + ComputedCSSPaddingStart(),
4660                                   BorderEnd() + ComputedCSSPaddingEnd(),
4661                                   BorderBefore() + ComputedCSSPaddingBefore(),
4662                                   BorderAfter() + ComputedCSSPaddingAfter());
4663         height_result = BlockSizeFromAspectRatio(
4664             border_padding, StyleRef().LogicalAspectRatio(),
4665             StyleRef().BoxSizing(), LogicalWidth());
4666       } else {
4667         height_result = ComputeLogicalHeightUsing(
4668             kMainOrPreferredSize, h,
4669             computed_values.extent_ - BorderAndPaddingLogicalHeight());
4670       }
4671       if (height_result == -1)
4672         height_result = computed_values.extent_;
4673       height_result = ConstrainLogicalHeightByMinMax(
4674           height_result,
4675           computed_values.extent_ - BorderAndPaddingLogicalHeight());
4676     } else {
4677       DCHECK(h.IsFixed());
4678       height_result = LayoutUnit(h.Value());
4679     }
4680 
4681     computed_values.extent_ = height_result;
4682     ComputeMarginsForDirection(
4683         flow_direction, cb, ContainingBlockLogicalWidthForContent(),
4684         computed_values.extent_, computed_values.margins_.before_,
4685         computed_values.margins_.after_, StyleRef().MarginBefore(),
4686         StyleRef().MarginAfter());
4687   }
4688 
4689   // WinIE quirk: The <html> block always fills the entire canvas in quirks
4690   // mode. The <body> always fills the <html> block in quirks mode. Only apply
4691   // this quirk if the block is normal flow and no height is specified. When
4692   // we're printing, we also need this quirk if the body or root has a
4693   // percentage height since we don't set a height in LayoutView when we're
4694   // printing. So without this quirk, the height has nothing to be a percentage
4695   // of, and it ends up being 0. That is bad.
4696   bool paginated_content_needs_base_height =
4697       GetDocument().Printing() && h.IsPercentOrCalc() &&
4698       (IsDocumentElement() ||
4699        (IsBody() &&
4700         HeightForDocumentElement(GetDocument()).IsPercentOrCalc())) &&
4701       !IsInline();
4702   if (StretchesToViewport() || paginated_content_needs_base_height) {
4703     LayoutUnit margins = CollapsedMarginBefore() + CollapsedMarginAfter();
4704     LayoutUnit visible_height = View()->ViewLogicalHeightForPercentages();
4705     if (IsDocumentElement()) {
4706       computed_values.extent_ =
4707           std::max(computed_values.extent_, visible_height - margins);
4708     } else {
4709       LayoutUnit margins_borders_padding =
4710           margins + ParentBox()->MarginBefore() + ParentBox()->MarginAfter() +
4711           ParentBox()->BorderAndPaddingLogicalHeight();
4712       computed_values.extent_ = std::max(
4713           computed_values.extent_, visible_height - margins_borders_padding);
4714     }
4715   }
4716 }
4717 
ComputeLogicalHeightWithoutLayout() const4718 LayoutUnit LayoutBox::ComputeLogicalHeightWithoutLayout() const {
4719   NOT_DESTROYED();
4720   LogicalExtentComputedValues computed_values;
4721 
4722   if (!SelfNeedsLayout() && HasOverrideIntrinsicContentLogicalHeight()) {
4723     ComputeLogicalHeight(OverrideIntrinsicContentLogicalHeight() +
4724                              BorderAndPaddingLogicalHeight(),
4725                          LayoutUnit(), computed_values);
4726   } else {
4727     // TODO(cbiesinger): We should probably return something other than just
4728     // border + padding, but for now we have no good way to do anything else
4729     // without layout, so we just use that.
4730     ComputeLogicalHeight(BorderAndPaddingLogicalHeight(), LayoutUnit(),
4731                          computed_values);
4732   }
4733   return computed_values.extent_;
4734 }
4735 
ComputeLogicalHeightUsing(SizeType height_type,const Length & height,LayoutUnit intrinsic_content_height) const4736 LayoutUnit LayoutBox::ComputeLogicalHeightUsing(
4737     SizeType height_type,
4738     const Length& height,
4739     LayoutUnit intrinsic_content_height) const {
4740   NOT_DESTROYED();
4741   LayoutUnit logical_height = ComputeContentAndScrollbarLogicalHeightUsing(
4742       height_type, height, intrinsic_content_height);
4743   if (logical_height != -1) {
4744     if (height.IsSpecified())
4745       logical_height = AdjustBorderBoxLogicalHeightForBoxSizing(logical_height);
4746     else
4747       logical_height += BorderAndPaddingLogicalHeight();
4748   }
4749   return logical_height;
4750 }
4751 
ComputeContentLogicalHeight(SizeType height_type,const Length & height,LayoutUnit intrinsic_content_height) const4752 LayoutUnit LayoutBox::ComputeContentLogicalHeight(
4753     SizeType height_type,
4754     const Length& height,
4755     LayoutUnit intrinsic_content_height) const {
4756   NOT_DESTROYED();
4757   LayoutUnit height_including_scrollbar =
4758       ComputeContentAndScrollbarLogicalHeightUsing(height_type, height,
4759                                                    intrinsic_content_height);
4760   if (height_including_scrollbar == -1)
4761     return LayoutUnit(-1);
4762   LayoutUnit adjusted = height_including_scrollbar;
4763   if (height.IsSpecified()) {
4764     // Keywords don't get adjusted for box-sizing
4765     adjusted =
4766         AdjustContentBoxLogicalHeightForBoxSizing(height_including_scrollbar);
4767   }
4768   return std::max(LayoutUnit(),
4769                   adjusted - ComputeLogicalScrollbars().BlockSum());
4770 }
4771 
ComputeIntrinsicLogicalContentHeightUsing(SizeType height_type,const Length & logical_height_length,LayoutUnit intrinsic_content_height,LayoutUnit border_and_padding) const4772 LayoutUnit LayoutBox::ComputeIntrinsicLogicalContentHeightUsing(
4773     SizeType height_type,
4774     const Length& logical_height_length,
4775     LayoutUnit intrinsic_content_height,
4776     LayoutUnit border_and_padding) const {
4777   NOT_DESTROYED();
4778   // FIXME(cbiesinger): The css-sizing spec is considering changing what
4779   // min-content/max-content should resolve to.
4780   // If that happens, this code will have to change.
4781   if (logical_height_length.IsMinContent() ||
4782       logical_height_length.IsMaxContent() ||
4783       logical_height_length.IsMinIntrinsic() ||
4784       logical_height_length.IsFitContent()) {
4785     if (IsAtomicInlineLevel() && !IsFlexibleBoxIncludingNG() && !IsLayoutGrid())
4786       return IntrinsicSize().Height();
4787     return intrinsic_content_height;
4788   }
4789   if (logical_height_length.IsFillAvailable()) {
4790     if (!IsA<HTMLMarqueeElement>(GetNode())) {
4791       UseCounter::Count(GetDocument(),
4792                         WebFeature::kCSSFillAvailableLogicalHeight);
4793     }
4794     const LayoutUnit available_logical_height =
4795         LayoutBoxUtils::AvailableLogicalHeight(*this, ContainingBlock());
4796     // If the available logical-height is indefinite fallback to the "default"
4797     // depending on the |SizeType|.
4798     if (available_logical_height == -1) {
4799       if (height_type == kMinSize)
4800         return LayoutUnit();
4801       if (height_type == kMainOrPreferredSize)
4802         return intrinsic_content_height;
4803       return LayoutUnit::Max();
4804     }
4805     return available_logical_height - border_and_padding;
4806   }
4807   NOTREACHED();
4808   return LayoutUnit();
4809 }
4810 
ComputeContentAndScrollbarLogicalHeightUsing(SizeType height_type,const Length & height,LayoutUnit intrinsic_content_height) const4811 LayoutUnit LayoutBox::ComputeContentAndScrollbarLogicalHeightUsing(
4812     SizeType height_type,
4813     const Length& height,
4814     LayoutUnit intrinsic_content_height) const {
4815   NOT_DESTROYED();
4816   if (height.IsAuto())
4817     return height_type == kMinSize ? LayoutUnit() : LayoutUnit(-1);
4818   // FIXME(cbiesinger): The css-sizing spec is considering changing what
4819   // min-content/max-content should resolve to.
4820   // If that happens, this code will have to change.
4821   if (height.IsContentOrIntrinsicOrFillAvailable()) {
4822     if (intrinsic_content_height == -1)
4823       return LayoutUnit(-1);  // Intrinsic height isn't available.
4824     return ComputeIntrinsicLogicalContentHeightUsing(
4825                height_type, height, intrinsic_content_height,
4826                BorderAndPaddingLogicalHeight()) +
4827            ComputeLogicalScrollbars().BlockSum();
4828   }
4829   if (height.IsFixed())
4830     return LayoutUnit(height.Value());
4831   if (height.IsPercentOrCalc())
4832     return ComputePercentageLogicalHeight(height);
4833   return LayoutUnit(-1);
4834 }
4835 
StretchesToViewportInQuirksMode() const4836 bool LayoutBox::StretchesToViewportInQuirksMode() const {
4837   NOT_DESTROYED();
4838   if (!IsDocumentElement() && !IsBody())
4839     return false;
4840   return StyleRef().LogicalHeight().IsAuto() &&
4841          !IsFloatingOrOutOfFlowPositioned() && !IsInline() &&
4842          !ShouldComputeLogicalHeightFromAspectRatio() &&
4843          !FlowThreadContainingBlock();
4844 }
4845 
SkipContainingBlockForPercentHeightCalculation(const LayoutBox * containing_block)4846 bool LayoutBox::SkipContainingBlockForPercentHeightCalculation(
4847     const LayoutBox* containing_block) {
4848   const bool in_quirks_mode = containing_block->GetDocument().InQuirksMode();
4849   // Anonymous blocks should not impede percentage resolution on a child.
4850   // Examples of such anonymous blocks are blocks wrapped around inlines that
4851   // have block siblings (from the CSS spec) and multicol flow threads (an
4852   // implementation detail). Another implementation detail, ruby runs, create
4853   // anonymous inline-blocks, so skip those too. All other types of anonymous
4854   // objects, such as table-cells, will be treated just as if they were
4855   // non-anonymous.
4856   if (containing_block->IsAnonymous()) {
4857     if (!in_quirks_mode && containing_block->Parent() &&
4858         containing_block->Parent()->IsLayoutNGFieldset())
4859       return false;
4860     EDisplay display = containing_block->StyleRef().Display();
4861     return display == EDisplay::kBlock || display == EDisplay::kInlineBlock ||
4862            display == EDisplay::kFlowRoot;
4863   }
4864 
4865   // For quirks mode, we skip most auto-height containing blocks when computing
4866   // percentages.
4867   if (!in_quirks_mode || !containing_block->StyleRef().LogicalHeight().IsAuto())
4868     return false;
4869 
4870   const Node* node = containing_block->GetNode();
4871   if (UNLIKELY(node->IsInUserAgentShadowRoot())) {
4872     const Element* host = node->OwnerShadowHost();
4873     if (const auto* input = DynamicTo<HTMLInputElement>(host)) {
4874       // In web_tests/fast/forms/range/range-thumb-height-percentage.html, a
4875       // percent height for the slider thumb element should refer to the height
4876       // of the INPUT box.
4877       if (input->type() == input_type_names::kRange)
4878         return true;
4879     }
4880   }
4881 
4882   return !containing_block->IsTableCell() &&
4883          !containing_block->IsOutOfFlowPositioned() &&
4884          !containing_block->HasOverridePercentageResolutionBlockSize() &&
4885          !containing_block->IsLayoutGrid() &&
4886          !containing_block->IsFlexibleBoxIncludingDeprecatedAndNG() &&
4887          !containing_block->IsLayoutNGCustom();
4888 }
4889 
ContainingBlockLogicalHeightForPercentageResolution(LayoutBlock ** out_cb,bool * out_skipped_auto_height_containing_block) const4890 LayoutUnit LayoutBox::ContainingBlockLogicalHeightForPercentageResolution(
4891     LayoutBlock** out_cb,
4892     bool* out_skipped_auto_height_containing_block) const {
4893   NOT_DESTROYED();
4894   LayoutBlock* cb = ContainingBlock();
4895   const LayoutBlock* const real_cb = cb;
4896   const LayoutBox* containing_block_child = this;
4897   bool skipped_auto_height_containing_block = false;
4898   LayoutUnit root_margin_border_padding_height;
4899   while (!IsA<LayoutView>(cb) &&
4900          (IsHorizontalWritingMode() == cb->IsHorizontalWritingMode() &&
4901           SkipContainingBlockForPercentHeightCalculation(cb))) {
4902     if ((cb->IsBody() || cb->IsDocumentElement()) &&
4903         !HasOverrideContainingBlockContentLogicalHeight())
4904       root_margin_border_padding_height += cb->MarginBefore() +
4905                                            cb->MarginAfter() +
4906                                            cb->BorderAndPaddingLogicalHeight();
4907     skipped_auto_height_containing_block = true;
4908     containing_block_child = cb;
4909     cb = cb->ContainingBlock();
4910   }
4911 
4912   if (out_cb)
4913     *out_cb = cb;
4914 
4915   if (out_skipped_auto_height_containing_block) {
4916     *out_skipped_auto_height_containing_block =
4917         skipped_auto_height_containing_block;
4918   }
4919 
4920   LayoutUnit available_height(-1);
4921   if (containing_block_child->HasOverridePercentageResolutionBlockSize()) {
4922     available_height =
4923         containing_block_child->OverridePercentageResolutionBlockSize();
4924   } else if (cb->HasOverridePercentageResolutionBlockSize()) {
4925     available_height = cb->OverridePercentageResolutionBlockSize();
4926   } else if (HasOverrideContainingBlockContentLogicalWidth() &&
4927              IsHorizontalWritingMode() != real_cb->IsHorizontalWritingMode()) {
4928     available_height = OverrideContainingBlockContentLogicalWidth();
4929   } else if (HasOverrideContainingBlockContentLogicalHeight() &&
4930              IsHorizontalWritingMode() == real_cb->IsHorizontalWritingMode()) {
4931     available_height = OverrideContainingBlockContentLogicalHeight();
4932   } else if (IsHorizontalWritingMode() != cb->IsHorizontalWritingMode()) {
4933     available_height =
4934         containing_block_child->ContainingBlockLogicalWidthForContent();
4935   } else if (cb->IsTableCell()) {
4936     if (!skipped_auto_height_containing_block) {
4937       // Table cells violate what the CSS spec says to do with heights.
4938       // Basically we don't care if the cell specified a height or not. We just
4939       // always make ourselves be a percentage of the cell's current content
4940       // height.
4941       if (!cb->HasOverrideLogicalHeight()) {
4942         // https://drafts.csswg.org/css-tables-3/#row-layout:
4943         // For the purpose of calculating [the minimum height of a row],
4944         // descendants of table cells whose height depends on percentages
4945         // of their parent cell's height are considered to have an auto
4946         // height if they have overflow set to visible or hidden or if
4947         // they are replaced elements, and a 0px height if they have not.
4948         const LayoutNGTableCellInterface* cell =
4949             ToInterface<LayoutNGTableCellInterface>(cb);
4950         if (StyleRef().OverflowY() != EOverflow::kVisible &&
4951             StyleRef().OverflowY() != EOverflow::kHidden &&
4952             !ShouldBeConsideredAsReplaced() &&
4953             (!cb->StyleRef().LogicalHeight().IsAuto() || !cell->TableInterface()
4954                                                               ->ToLayoutObject()
4955                                                               ->StyleRef()
4956                                                               .LogicalHeight()
4957                                                               .IsAuto()))
4958           return LayoutUnit();
4959         return LayoutUnit(-1);
4960       }
4961       available_height = cb->OverrideLogicalHeight() -
4962                          cb->CollapsedBorderAndCSSPaddingLogicalHeight() -
4963                          cb->ComputeLogicalScrollbars().BlockSum();
4964     }
4965   } else {
4966     available_height = cb->AvailableLogicalHeightForPercentageComputation();
4967   }
4968 
4969   if (available_height == -1)
4970     return available_height;
4971 
4972   available_height -= root_margin_border_padding_height;
4973 
4974   // LayoutNG already includes padding in
4975   // OverrideContainingBlockContentLogicalHeight so we only need to add it here
4976   // for legacy containing blocks.
4977   if (IsTable() && IsOutOfFlowPositioned() && !cb->IsLayoutNGObject())
4978     available_height += cb->PaddingLogicalHeight();
4979 
4980   return available_height;
4981 }
4982 
ComputePercentageLogicalHeight(const Length & height) const4983 LayoutUnit LayoutBox::ComputePercentageLogicalHeight(
4984     const Length& height) const {
4985   NOT_DESTROYED();
4986   bool skipped_auto_height_containing_block = false;
4987   LayoutBlock* cb = nullptr;
4988   LayoutUnit available_height =
4989       ContainingBlockLogicalHeightForPercentageResolution(
4990           &cb, &skipped_auto_height_containing_block);
4991 
4992   DCHECK(cb);
4993   cb->AddPercentHeightDescendant(const_cast<LayoutBox*>(this));
4994 
4995   if (available_height == -1)
4996     return available_height;
4997 
4998   LayoutUnit result = ValueForLength(height, available_height);
4999 
5000   // |OverrideLogicalHeight| is the maximum height made available by the
5001   // cell to its percent height children when we decide they can determine the
5002   // height of the cell. If the percent height child is box-sizing:content-box
5003   // then we must subtract the border and padding from the cell's
5004   // |available_height| (given by |OverrideLogicalHeight|) to arrive
5005   // at the child's computed height.
5006   bool subtract_border_and_padding =
5007       IsTable() ||
5008       (!RuntimeEnabledFeatures::TableCellNewPercentsEnabled() &&
5009        cb->IsTableCell() && !skipped_auto_height_containing_block &&
5010        cb->HasOverrideLogicalHeight() &&
5011        StyleRef().BoxSizing() == EBoxSizing::kContentBox);
5012   if (subtract_border_and_padding) {
5013     result -= BorderAndPaddingLogicalHeight();
5014     return std::max(LayoutUnit(), result);
5015   }
5016   return result;
5017 }
5018 
ComputeReplacedLogicalWidth(ShouldComputePreferred should_compute_preferred) const5019 LayoutUnit LayoutBox::ComputeReplacedLogicalWidth(
5020     ShouldComputePreferred should_compute_preferred) const {
5021   NOT_DESTROYED();
5022   return ComputeReplacedLogicalWidthRespectingMinMaxWidth(
5023       ComputeReplacedLogicalWidthUsing(kMainOrPreferredSize,
5024                                        StyleRef().LogicalWidth()),
5025       should_compute_preferred);
5026 }
5027 
ComputeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logical_width,ShouldComputePreferred should_compute_preferred) const5028 LayoutUnit LayoutBox::ComputeReplacedLogicalWidthRespectingMinMaxWidth(
5029     LayoutUnit logical_width,
5030     ShouldComputePreferred should_compute_preferred) const {
5031   NOT_DESTROYED();
5032   LayoutUnit min_logical_width =
5033       (should_compute_preferred == kComputePreferred &&
5034        StyleRef().LogicalMinWidth().IsPercentOrCalc())
5035           ? logical_width
5036           : ComputeReplacedLogicalWidthUsing(kMinSize,
5037                                              StyleRef().LogicalMinWidth());
5038   LayoutUnit max_logical_width =
5039       (should_compute_preferred == kComputePreferred &&
5040        StyleRef().LogicalMaxWidth().IsPercentOrCalc()) ||
5041               StyleRef().LogicalMaxWidth().IsNone()
5042           ? logical_width
5043           : ComputeReplacedLogicalWidthUsing(kMaxSize,
5044                                              StyleRef().LogicalMaxWidth());
5045   return std::max(min_logical_width,
5046                   std::min(logical_width, max_logical_width));
5047 }
5048 
ComputeReplacedLogicalWidthUsing(SizeType size_type,const Length & logical_width) const5049 LayoutUnit LayoutBox::ComputeReplacedLogicalWidthUsing(
5050     SizeType size_type,
5051     const Length& logical_width) const {
5052   NOT_DESTROYED();
5053   DCHECK(size_type == kMinSize || size_type == kMainOrPreferredSize ||
5054          !logical_width.IsAuto());
5055   if (size_type == kMinSize && logical_width.IsAuto())
5056     return AdjustContentBoxLogicalWidthForBoxSizing(LayoutUnit());
5057 
5058   switch (logical_width.GetType()) {
5059     case Length::kFixed:
5060       return AdjustContentBoxLogicalWidthForBoxSizing(logical_width.Value());
5061     case Length::kMinContent:
5062     case Length::kMaxContent:
5063     case Length::kMinIntrinsic: {
5064       // MinContent/MaxContent don't need the availableLogicalWidth argument.
5065       LayoutUnit available_logical_width;
5066       return ComputeIntrinsicLogicalWidthUsing(logical_width,
5067                                                available_logical_width) -
5068              BorderAndPaddingLogicalWidth();
5069     }
5070     case Length::kFitContent:
5071     case Length::kFillAvailable:
5072     case Length::kPercent:
5073     case Length::kCalculated: {
5074       LayoutUnit cw;
5075       if (IsOutOfFlowPositioned()) {
5076         cw = ContainingBlockLogicalWidthForPositioned(
5077             To<LayoutBoxModelObject>(Container()));
5078       } else {
5079         cw = IsHorizontalWritingMode() ==
5080                      ContainingBlock()->IsHorizontalWritingMode()
5081                  ? ContainingBlockLogicalWidthForContent()
5082                  : PerpendicularContainingBlockLogicalHeight();
5083       }
5084       const Length& container_logical_width =
5085           ContainingBlock()->StyleRef().LogicalWidth();
5086       // FIXME: Handle cases when containing block width is calculated or
5087       // viewport percent. https://bugs.webkit.org/show_bug.cgi?id=91071
5088       if (logical_width.IsContentOrIntrinsicOrFillAvailable())
5089         return ComputeIntrinsicLogicalWidthUsing(logical_width, cw) -
5090                BorderAndPaddingLogicalWidth();
5091       if (cw > 0 || (!cw && (container_logical_width.IsFixed() ||
5092                              container_logical_width.IsPercentOrCalc())))
5093         return AdjustContentBoxLogicalWidthForBoxSizing(
5094             MinimumValueForLength(logical_width, cw));
5095       return LayoutUnit();
5096     }
5097     case Length::kAuto:
5098     case Length::kNone:
5099       return IntrinsicLogicalWidth();
5100     case Length::kExtendToZoom:
5101     case Length::kDeviceWidth:
5102     case Length::kDeviceHeight:
5103       break;
5104   }
5105 
5106   NOTREACHED();
5107   return LayoutUnit();
5108 }
5109 
ComputeReplacedLogicalHeight(LayoutUnit) const5110 LayoutUnit LayoutBox::ComputeReplacedLogicalHeight(LayoutUnit) const {
5111   NOT_DESTROYED();
5112   return ComputeReplacedLogicalHeightRespectingMinMaxHeight(
5113       ComputeReplacedLogicalHeightUsing(kMainOrPreferredSize,
5114                                         StyleRef().LogicalHeight()));
5115 }
5116 
LogicalHeightComputesAsNone(SizeType size_type) const5117 bool LayoutBox::LogicalHeightComputesAsNone(SizeType size_type) const {
5118   NOT_DESTROYED();
5119   DCHECK(size_type == kMinSize || size_type == kMaxSize);
5120   const Length& logical_height = size_type == kMinSize
5121                                      ? StyleRef().LogicalMinHeight()
5122                                      : StyleRef().LogicalMaxHeight();
5123 
5124   // Note that the values 'min-content', 'max-content' and 'fit-content' should
5125   // behave as the initial value if specified in the block direction.
5126   if (logical_height.IsMinContent() || logical_height.IsMaxContent() ||
5127       logical_height.IsMinIntrinsic() || logical_height.IsFitContent())
5128     return true;
5129 
5130   Length initial_logical_height =
5131       size_type == kMinSize ? ComputedStyleInitialValues::InitialMinHeight()
5132                             : ComputedStyleInitialValues::InitialMaxHeight();
5133 
5134   if (logical_height == initial_logical_height)
5135     return true;
5136 
5137   if (logical_height.IsPercentOrCalc() &&
5138       HasOverrideContainingBlockContentLogicalHeight()) {
5139     if (OverrideContainingBlockContentLogicalHeight() == kIndefiniteSize)
5140       return true;
5141     else if (!GetDocument().InQuirksMode())
5142       return false;
5143   }
5144 
5145   // CustomLayout items can resolve their percentages against an available or
5146   // percentage size override.
5147   if (IsCustomItem() && (HasOverrideContainingBlockContentLogicalHeight() ||
5148                          HasOverridePercentageResolutionBlockSize()))
5149     return false;
5150 
5151   if (LayoutBlock* cb = ContainingBlockForAutoHeightDetection(logical_height))
5152     return cb->HasAutoHeightOrContainingBlockWithAutoHeight();
5153   return false;
5154 }
5155 
ComputeReplacedLogicalHeightRespectingMinMaxHeight(LayoutUnit logical_height) const5156 LayoutUnit LayoutBox::ComputeReplacedLogicalHeightRespectingMinMaxHeight(
5157     LayoutUnit logical_height) const {
5158   NOT_DESTROYED();
5159   // If the height of the containing block is not specified explicitly (i.e., it
5160   // depends on content height), and this element is not absolutely positioned,
5161   // the percentage value is treated as '0' (for 'min-height') or 'none' (for
5162   // 'max-height').
5163   LayoutUnit min_logical_height;
5164   if (!LogicalHeightComputesAsNone(kMinSize)) {
5165     min_logical_height = ComputeReplacedLogicalHeightUsing(
5166         kMinSize, StyleRef().LogicalMinHeight());
5167   }
5168   LayoutUnit max_logical_height = logical_height;
5169   if (!LogicalHeightComputesAsNone(kMaxSize)) {
5170     max_logical_height = ComputeReplacedLogicalHeightUsing(
5171         kMaxSize, StyleRef().LogicalMaxHeight());
5172   }
5173   return std::max(min_logical_height,
5174                   std::min(logical_height, max_logical_height));
5175 }
5176 
ComputeReplacedLogicalHeightUsing(SizeType size_type,const Length & logical_height) const5177 LayoutUnit LayoutBox::ComputeReplacedLogicalHeightUsing(
5178     SizeType size_type,
5179     const Length& logical_height) const {
5180   NOT_DESTROYED();
5181   DCHECK(size_type == kMinSize || size_type == kMainOrPreferredSize ||
5182          !logical_height.IsAuto());
5183   if (size_type == kMinSize && logical_height.IsAuto())
5184     return AdjustContentBoxLogicalHeightForBoxSizing(LayoutUnit());
5185 
5186   switch (logical_height.GetType()) {
5187     case Length::kFixed:
5188       return AdjustContentBoxLogicalHeightForBoxSizing(logical_height.Value());
5189     case Length::kPercent:
5190     case Length::kCalculated: {
5191       // TODO(rego): Check if we can somehow reuse
5192       // LayoutBox::computePercentageLogicalHeight() and/or
5193       // LayoutBlock::availableLogicalHeightForPercentageComputation() (see
5194       // http://crbug.com/635655).
5195       LayoutObject* cb =
5196           IsOutOfFlowPositioned() ? Container() : ContainingBlock();
5197       while (cb->IsAnonymous())
5198         cb = cb->ContainingBlock();
5199       bool has_perpendicular_containing_block =
5200           cb->IsHorizontalWritingMode() != IsHorizontalWritingMode();
5201       LayoutUnit stretched_height(-1);
5202       auto* block = DynamicTo<LayoutBlock>(cb);
5203       if (block) {
5204         block->AddPercentHeightDescendant(const_cast<LayoutBox*>(this));
5205         if (block->IsFlexItem()) {
5206           const LayoutFlexibleBox* flex_box =
5207               ToLayoutFlexibleBox(block->Parent());
5208           if (flex_box->UseOverrideLogicalHeightForPerentageResolution(*block))
5209             stretched_height = block->OverrideContentLogicalHeight();
5210         } else if (block->IsGridItem() && block->HasOverrideLogicalHeight() &&
5211                    !has_perpendicular_containing_block) {
5212           stretched_height = block->OverrideContentLogicalHeight();
5213         }
5214       }
5215 
5216       LayoutUnit available_height;
5217       if (IsOutOfFlowPositioned()) {
5218         available_height = ContainingBlockLogicalHeightForPositioned(
5219             To<LayoutBoxModelObject>(cb));
5220       } else if (stretched_height != -1) {
5221         available_height = stretched_height;
5222       } else if (HasOverridePercentageResolutionBlockSize()) {
5223         available_height = OverridePercentageResolutionBlockSize();
5224       } else {
5225         available_height = has_perpendicular_containing_block
5226                                ? ContainingBlockLogicalWidthForContent()
5227                                : ContainingBlockLogicalHeightForContent(
5228                                      kIncludeMarginBorderPadding);
5229 
5230         // It is necessary to use the border-box to match WinIE's broken
5231         // box model.  This is essential for sizing inside
5232         // table cells using percentage heights.
5233         // FIXME: This needs to be made writing-mode-aware. If the cell and
5234         // image are perpendicular writing-modes, this isn't right.
5235         // https://bugs.webkit.org/show_bug.cgi?id=46997
5236         while (!IsA<LayoutView>(cb) &&
5237                (cb->StyleRef().LogicalHeight().IsAuto() ||
5238                 cb->StyleRef().LogicalHeight().IsPercentOrCalc())) {
5239           if (!RuntimeEnabledFeatures::TableCellNewPercentsEnabled() &&
5240               cb->IsTableCell()) {
5241             // Don't let table cells squeeze percent-height replaced elements
5242             // <http://bugs.webkit.org/show_bug.cgi?id=15359>
5243             available_height =
5244                 std::max(available_height, IntrinsicLogicalHeight());
5245             return ValueForLength(
5246                 logical_height,
5247                 available_height - BorderAndPaddingLogicalHeight());
5248           }
5249           To<LayoutBlock>(cb)->AddPercentHeightDescendant(
5250               const_cast<LayoutBox*>(this));
5251           cb = cb->ContainingBlock();
5252         }
5253       }
5254 
5255       return AdjustContentBoxLogicalHeightForBoxSizing(
5256           (RuntimeEnabledFeatures::TableCellNewPercentsEnabled() &&
5257            available_height == kIndefiniteSize)
5258               ? IntrinsicLogicalHeight()
5259               : ValueForLength(logical_height, available_height));
5260     }
5261     case Length::kMinContent:
5262     case Length::kMaxContent:
5263     case Length::kFitContent:
5264     case Length::kFillAvailable:
5265       return AdjustContentBoxLogicalHeightForBoxSizing(
5266           ComputeIntrinsicLogicalContentHeightUsing(size_type, logical_height,
5267                                                     IntrinsicLogicalHeight(),
5268                                                     BorderAndPaddingHeight()));
5269     default:
5270       return IntrinsicLogicalHeight();
5271   }
5272 }
5273 
AvailableLogicalHeight(AvailableLogicalHeightType height_type) const5274 LayoutUnit LayoutBox::AvailableLogicalHeight(
5275     AvailableLogicalHeightType height_type) const {
5276   NOT_DESTROYED();
5277   if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
5278     // LayoutNG code is correct, Legacy code incorrectly ConstrainsMinMax
5279     // when height is -1, and returns 0, not -1.
5280     // The reason this code is NG-only is that this code causes performance
5281     // regression for nested-percent-height-tables test case.
5282     // This code gets executed 740 times in the test case.
5283     // https://chromium-review.googlesource.com/c/chromium/src/+/1103289
5284     LayoutUnit height =
5285         AvailableLogicalHeightUsing(StyleRef().LogicalHeight(), height_type);
5286     if (UNLIKELY(height == -1))
5287       return height;
5288     return ConstrainContentBoxLogicalHeightByMinMax(height, LayoutUnit(-1));
5289   }
5290   // http://www.w3.org/TR/CSS2/visudet.html#propdef-height - We are interested
5291   // in the content height.
5292   // FIXME: Should we pass intrinsicContentLogicalHeight() instead of -1 here?
5293   return ConstrainContentBoxLogicalHeightByMinMax(
5294       AvailableLogicalHeightUsing(StyleRef().LogicalHeight(), height_type),
5295       LayoutUnit(-1));
5296 }
5297 
AvailableLogicalHeightUsing(const Length & h,AvailableLogicalHeightType height_type) const5298 LayoutUnit LayoutBox::AvailableLogicalHeightUsing(
5299     const Length& h,
5300     AvailableLogicalHeightType height_type) const {
5301   NOT_DESTROYED();
5302   if (auto* layout_view = DynamicTo<LayoutView>(this)) {
5303     return LayoutUnit(IsHorizontalWritingMode()
5304                           ? layout_view->GetFrameView()->Size().Height()
5305                           : layout_view->GetFrameView()->Size().Width());
5306   }
5307 
5308   // We need to stop here, since we don't want to increase the height of the
5309   // table artificially.  We're going to rely on this cell getting expanded to
5310   // some new height, and then when we lay out again we'll use the calculation
5311   // below.
5312   if (IsTableCell() && (h.IsAuto() || h.IsPercentOrCalc())) {
5313     if (HasOverrideLogicalHeight()) {
5314       return OverrideLogicalHeight() -
5315              CollapsedBorderAndCSSPaddingLogicalHeight() -
5316              ComputeLogicalScrollbars().BlockSum();
5317     }
5318     return LogicalHeight() - BorderAndPaddingLogicalHeight();
5319   }
5320 
5321   if (IsFlexItemIncludingNG()) {
5322     if (IsFlexItem()) {
5323       const LayoutFlexibleBox& flex_box = ToLayoutFlexibleBox(*Parent());
5324       if (flex_box.UseOverrideLogicalHeightForPerentageResolution(*this))
5325         return OverrideContentLogicalHeight();
5326     } else if (HasOverrideContainingBlockContentLogicalWidth() &&
5327                IsOrthogonalWritingModeRoot()) {
5328       return OverrideContainingBlockContentLogicalWidth();
5329     } else if (HasOverrideLogicalHeight() &&
5330                IsOverrideLogicalHeightDefinite()) {
5331       return OverrideContentLogicalHeight();
5332     } else if (!GetBoxLayoutExtraInput()) {
5333       // TODO(ikilpatrick): Remove this post M86.
5334       if (const auto* previous_result = GetCachedLayoutResult()) {
5335         const NGConstraintSpace& space =
5336             previous_result->GetConstraintSpaceForCaching();
5337         if (space.IsFixedBlockSize() && !space.IsFixedBlockSizeIndefinite())
5338           return space.AvailableSize().block_size;
5339       }
5340     }
5341   }
5342 
5343   if (ShouldComputeLogicalHeightFromAspectRatio()) {
5344     NGBoxStrut border_padding(BorderStart() + ComputedCSSPaddingStart(),
5345                               BorderEnd() + ComputedCSSPaddingEnd(),
5346                               BorderBefore() + ComputedCSSPaddingBefore(),
5347                               BorderAfter() + ComputedCSSPaddingAfter());
5348     return BlockSizeFromAspectRatio(border_padding,
5349                                     StyleRef().LogicalAspectRatio(),
5350                                     StyleRef().BoxSizing(), LogicalWidth());
5351   }
5352 
5353   if (h.IsPercentOrCalc() && IsOutOfFlowPositioned()) {
5354     // FIXME: This is wrong if the containingBlock has a perpendicular writing
5355     // mode.
5356     LayoutUnit available_height =
5357         ContainingBlockLogicalHeightForPositioned(ContainingBlock());
5358     return AdjustContentBoxLogicalHeightForBoxSizing(
5359         ValueForLength(h, available_height));
5360   }
5361 
5362   // FIXME: Should we pass intrinsicContentLogicalHeight() instead of -1 here?
5363   LayoutUnit height_including_scrollbar =
5364       ComputeContentAndScrollbarLogicalHeightUsing(kMainOrPreferredSize, h,
5365                                                    LayoutUnit(-1));
5366   if (height_including_scrollbar != -1) {
5367     return std::max(LayoutUnit(), AdjustContentBoxLogicalHeightForBoxSizing(
5368                                       height_including_scrollbar) -
5369                                       ComputeLogicalScrollbars().BlockSum());
5370   }
5371 
5372   // FIXME: Check logicalTop/logicalBottom here to correctly handle vertical
5373   // writing-mode.
5374   // https://bugs.webkit.org/show_bug.cgi?id=46500
5375   auto* curr_layout_block = DynamicTo<LayoutBlock>(this);
5376   if (curr_layout_block && IsOutOfFlowPositioned() &&
5377       StyleRef().Height().IsAuto() &&
5378       !(StyleRef().Top().IsAuto() || StyleRef().Bottom().IsAuto())) {
5379     LayoutBlock* block = const_cast<LayoutBlock*>(curr_layout_block);
5380     LogicalExtentComputedValues computed_values;
5381     block->ComputeLogicalHeight(block->LogicalHeight(), LayoutUnit(),
5382                                 computed_values);
5383     return computed_values.extent_ - block->BorderAndPaddingLogicalHeight() -
5384            block->ComputeLogicalScrollbars().BlockSum();
5385   }
5386 
5387   // FIXME: This is wrong if the containingBlock has a perpendicular writing
5388   // mode.
5389   LayoutUnit available_height =
5390       ContainingBlockLogicalHeightForContent(height_type);
5391   // FIXME: This is incorrect if available_height == -1 || 0
5392   if (height_type == kExcludeMarginBorderPadding) {
5393     // FIXME: Margin collapsing hasn't happened yet, so this incorrectly removes
5394     // collapsed margins.
5395     available_height -=
5396         MarginBefore() + MarginAfter() + BorderAndPaddingLogicalHeight();
5397   }
5398   return available_height;
5399 }
5400 
ComputeAndSetBlockDirectionMargins(const LayoutBlock * containing_block)5401 void LayoutBox::ComputeAndSetBlockDirectionMargins(
5402     const LayoutBlock* containing_block) {
5403   NOT_DESTROYED();
5404   LayoutUnit margin_before;
5405   LayoutUnit margin_after;
5406   DCHECK(containing_block);
5407   ComputeMarginsForDirection(
5408       kBlockDirection, containing_block,
5409       ContainingBlockLogicalWidthForContent(), LogicalHeight(), margin_before,
5410       margin_after, StyleRef().MarginBeforeUsing(containing_block->StyleRef()),
5411       StyleRef().MarginAfterUsing(containing_block->StyleRef()));
5412   // Note that in this 'positioning phase' of the layout we are using the
5413   // containing block's writing mode rather than our own when calculating
5414   // margins.
5415   // http://www.w3.org/TR/2014/CR-css-writing-modes-3-20140320/#orthogonal-flows
5416   containing_block->SetMarginBeforeForChild(*this, margin_before);
5417   containing_block->SetMarginAfterForChild(*this, margin_after);
5418 }
5419 
ContainingBlockLogicalWidthForPositioned(const LayoutBoxModelObject * containing_block,bool check_for_perpendicular_writing_mode) const5420 LayoutUnit LayoutBox::ContainingBlockLogicalWidthForPositioned(
5421     const LayoutBoxModelObject* containing_block,
5422     bool check_for_perpendicular_writing_mode) const {
5423   NOT_DESTROYED();
5424   if (check_for_perpendicular_writing_mode &&
5425       containing_block->IsHorizontalWritingMode() != IsHorizontalWritingMode())
5426     return ContainingBlockLogicalHeightForPositioned(containing_block, false);
5427 
5428   // Use viewport as container for top-level fixed-position elements.
5429   const auto* view = DynamicTo<LayoutView>(containing_block);
5430   if (StyleRef().GetPosition() == EPosition::kFixed && view &&
5431       !GetDocument().Printing()) {
5432     if (LocalFrameView* frame_view = view->GetFrameView()) {
5433       // Don't use visibleContentRect since the PaintLayer's size has not been
5434       // set yet.
5435       LayoutSize viewport_size(
5436           frame_view->LayoutViewport()->ExcludeScrollbars(frame_view->Size()));
5437       return LayoutUnit(containing_block->IsHorizontalWritingMode()
5438                             ? viewport_size.Width()
5439                             : viewport_size.Height());
5440     }
5441   }
5442 
5443   if (HasOverrideContainingBlockContentLogicalWidth())
5444     return OverrideContainingBlockContentLogicalWidth();
5445 
5446   if (containing_block->IsAnonymousBlock() &&
5447       containing_block->IsRelPositioned()) {
5448     // Ensure we compute our width based on the width of our rel-pos inline
5449     // container rather than any anonymous block created to manage a block-flow
5450     // ancestor of ours in the rel-pos inline's inline flow.
5451     containing_block = To<LayoutBox>(containing_block)->Continuation();
5452     // There may be nested parallel inline continuations. We have now found the
5453     // innermost inline (which may not be relatively positioned). Locate the
5454     // inline that serves as the containing block of this box.
5455     while (!containing_block->CanContainOutOfFlowPositionedElement(
5456         StyleRef().GetPosition())) {
5457       containing_block =
5458           To<LayoutBoxModelObject>(containing_block->Container());
5459       DCHECK(containing_block->IsLayoutInline());
5460     }
5461   } else if (containing_block->IsBox()) {
5462     return std::max(LayoutUnit(),
5463                     To<LayoutBox>(containing_block)->ClientLogicalWidth());
5464   }
5465 
5466   DCHECK(containing_block->IsLayoutInline());
5467   DCHECK(containing_block->CanContainOutOfFlowPositionedElement(
5468       StyleRef().GetPosition()));
5469 
5470   const auto* flow = To<LayoutInline>(containing_block);
5471   InlineFlowBox* first = flow->FirstLineBox();
5472   InlineFlowBox* last = flow->LastLineBox();
5473 
5474   // If the containing block is empty, return a width of 0.
5475   if (!first || !last)
5476     return LayoutUnit();
5477 
5478   LayoutUnit from_left;
5479   LayoutUnit from_right;
5480   if (containing_block->StyleRef().IsLeftToRightDirection()) {
5481     from_left = first->LogicalLeft() + first->BorderLogicalLeft();
5482     from_right =
5483         last->LogicalLeft() + last->LogicalWidth() - last->BorderLogicalRight();
5484   } else {
5485     from_right = first->LogicalLeft() + first->LogicalWidth() -
5486                  first->BorderLogicalRight();
5487     from_left = last->LogicalLeft() + last->BorderLogicalLeft();
5488   }
5489 
5490   return std::max(LayoutUnit(), from_right - from_left);
5491 }
5492 
ContainingBlockLogicalHeightForPositioned(const LayoutBoxModelObject * containing_block,bool check_for_perpendicular_writing_mode) const5493 LayoutUnit LayoutBox::ContainingBlockLogicalHeightForPositioned(
5494     const LayoutBoxModelObject* containing_block,
5495     bool check_for_perpendicular_writing_mode) const {
5496   NOT_DESTROYED();
5497   if (check_for_perpendicular_writing_mode &&
5498       containing_block->IsHorizontalWritingMode() != IsHorizontalWritingMode())
5499     return ContainingBlockLogicalWidthForPositioned(containing_block, false);
5500 
5501   // Use viewport as container for top-level fixed-position elements.
5502   const auto* view = DynamicTo<LayoutView>(containing_block);
5503   if (StyleRef().GetPosition() == EPosition::kFixed && view &&
5504       !GetDocument().Printing()) {
5505     if (LocalFrameView* frame_view = view->GetFrameView()) {
5506       // Don't use visibleContentRect since the PaintLayer's size has not been
5507       // set yet.
5508       LayoutSize viewport_size(
5509           frame_view->LayoutViewport()->ExcludeScrollbars(frame_view->Size()));
5510       return containing_block->IsHorizontalWritingMode()
5511                  ? viewport_size.Height()
5512                  : viewport_size.Width();
5513     }
5514   }
5515 
5516   if (HasOverrideContainingBlockContentLogicalHeight())
5517     return OverrideContainingBlockContentLogicalHeight();
5518 
5519   if (containing_block->IsBox())
5520     return To<LayoutBox>(containing_block)->ClientLogicalHeight();
5521 
5522   DCHECK(containing_block->IsLayoutInline());
5523   DCHECK(containing_block->CanContainOutOfFlowPositionedElement(
5524       StyleRef().GetPosition()));
5525 
5526   const auto* flow = To<LayoutInline>(containing_block);
5527   // If the containing block is empty, return a height of 0.
5528   if (!flow->HasInlineFragments())
5529     return LayoutUnit();
5530 
5531   LayoutUnit height_result;
5532   auto bounding_box_size = flow->PhysicalLinesBoundingBox().size;
5533   if (containing_block->IsHorizontalWritingMode())
5534     height_result = bounding_box_size.height;
5535   else
5536     height_result = bounding_box_size.width;
5537   height_result -=
5538       (containing_block->BorderBefore() + containing_block->BorderAfter());
5539   return height_result;
5540 }
5541 
AccumulateStaticOffsetForFlowThread(LayoutBox & layout_box,LayoutUnit inline_position,LayoutUnit & block_position)5542 static LayoutUnit AccumulateStaticOffsetForFlowThread(
5543     LayoutBox& layout_box,
5544     LayoutUnit inline_position,
5545     LayoutUnit& block_position) {
5546   if (layout_box.IsLegacyTableRow())
5547     return LayoutUnit();
5548   block_position += layout_box.LogicalTop();
5549   if (!layout_box.IsLayoutFlowThread())
5550     return LayoutUnit();
5551   LayoutUnit previous_inline_position = inline_position;
5552   // We're walking out of a flowthread here. This flow thread is not in the
5553   // containing block chain, so we need to convert the position from the
5554   // coordinate space of this flowthread to the containing coordinate space.
5555   To<LayoutFlowThread>(layout_box)
5556       .FlowThreadToContainingCoordinateSpace(block_position, inline_position);
5557   return inline_position - previous_inline_position;
5558 }
5559 
ComputeInlineStaticDistance(Length & logical_left,Length & logical_right,const LayoutBox * child,const LayoutBoxModelObject * container_block,LayoutUnit container_logical_width,const NGBoxFragmentBuilder * fragment_builder)5560 void LayoutBox::ComputeInlineStaticDistance(
5561     Length& logical_left,
5562     Length& logical_right,
5563     const LayoutBox* child,
5564     const LayoutBoxModelObject* container_block,
5565     LayoutUnit container_logical_width,
5566     const NGBoxFragmentBuilder* fragment_builder) {
5567   if (!logical_left.IsAuto() || !logical_right.IsAuto())
5568     return;
5569 
5570   LayoutObject* parent = child->Parent();
5571   TextDirection parent_direction = parent->StyleRef().Direction();
5572 
5573   // This method is using EnclosingBox() which is wrong for absolutely
5574   // positioned grid items, as they rely on the grid area. So for grid items if
5575   // both "left" and "right" properties are "auto", we can consider that one of
5576   // them (depending on the direction) is simply "0".
5577   if (parent->IsLayoutGrid() && parent == child->ContainingBlock()) {
5578     if (parent_direction == TextDirection::kLtr)
5579       logical_left = Length::Fixed(0);
5580     else
5581       logical_right = Length::Fixed(0);
5582     return;
5583   }
5584 
5585   // For multicol we also need to keep track of the block position, since that
5586   // determines which column we're in and thus affects the inline position.
5587   LayoutUnit static_block_position = child->Layer()->StaticBlockPosition();
5588 
5589   // FIXME: The static distance computation has not been patched for mixed
5590   // writing modes yet.
5591   if (parent_direction == TextDirection::kLtr) {
5592     LayoutUnit static_position = child->Layer()->StaticInlinePosition() -
5593                                  container_block->BorderLogicalLeft();
5594     for (LayoutObject* curr = child->Parent(); curr && curr != container_block;
5595          curr = curr->Container()) {
5596       if (auto* box = DynamicTo<LayoutBox>(curr)) {
5597         static_position +=
5598             (fragment_builder &&
5599              fragment_builder->GetLayoutObject() == curr->Parent())
5600                 ? fragment_builder->GetChildOffset(curr).inline_offset
5601                 : box->LogicalLeft();
5602         if (box->IsInFlowPositioned())
5603           static_position += box->OffsetForInFlowPosition().left;
5604         if (curr->IsInsideFlowThread()) {
5605           static_position += AccumulateStaticOffsetForFlowThread(
5606               *box, static_position, static_block_position);
5607         }
5608       } else if (curr->IsInline() && curr->IsInFlowPositioned()) {
5609         if (!curr->IsInLayoutNGInlineFormattingContext()) {
5610           if (!curr->StyleRef().LogicalLeft().IsAuto())
5611             static_position +=
5612                 ValueForLength(curr->StyleRef().LogicalLeft(),
5613                                curr->ContainingBlock()->AvailableWidth());
5614           else
5615             static_position -=
5616                 ValueForLength(curr->StyleRef().LogicalRight(),
5617                                curr->ContainingBlock()->AvailableWidth());
5618         }
5619       }
5620     }
5621     logical_left = Length::Fixed(static_position);
5622   } else {
5623     LayoutBox* enclosing_box = child->Parent()->EnclosingBox();
5624     LayoutUnit static_position = child->Layer()->StaticInlinePosition() +
5625                                  container_logical_width +
5626                                  container_block->BorderLogicalLeft();
5627     if (container_block->IsBox()) {
5628       static_position +=
5629           To<LayoutBox>(container_block)->LogicalLeftScrollbarWidth();
5630     }
5631     for (LayoutObject* curr = child->Parent(); curr; curr = curr->Container()) {
5632       if (auto* box = DynamicTo<LayoutBox>(curr)) {
5633         if (curr == enclosing_box)
5634           static_position -= enclosing_box->LogicalWidth();
5635         if (curr != container_block) {
5636           static_position -=
5637               (fragment_builder &&
5638                fragment_builder->GetLayoutObject() == curr->Parent())
5639                   ? fragment_builder->GetChildOffset(curr).inline_offset
5640                   : box->LogicalLeft();
5641           if (box->IsInFlowPositioned()) {
5642             static_position -= box->OffsetForInFlowPosition().left;
5643           }
5644           if (curr->IsInsideFlowThread()) {
5645             static_position -= AccumulateStaticOffsetForFlowThread(
5646                 *box, static_position, static_block_position);
5647           }
5648         }
5649       } else if (curr->IsInline() && curr->IsInFlowPositioned()) {
5650         if (!curr->IsInLayoutNGInlineFormattingContext()) {
5651           if (!curr->StyleRef().LogicalLeft().IsAuto())
5652             static_position -=
5653                 ValueForLength(curr->StyleRef().LogicalLeft(),
5654                                curr->ContainingBlock()->AvailableWidth());
5655           else
5656             static_position +=
5657                 ValueForLength(curr->StyleRef().LogicalRight(),
5658                                curr->ContainingBlock()->AvailableWidth());
5659         }
5660       }
5661       if (curr == container_block)
5662         break;
5663     }
5664     logical_right = Length::Fixed(static_position);
5665   }
5666 }
5667 
ComputePositionedLogicalWidth(LogicalExtentComputedValues & computed_values) const5668 void LayoutBox::ComputePositionedLogicalWidth(
5669     LogicalExtentComputedValues& computed_values) const {
5670   NOT_DESTROYED();
5671   // QUESTIONS
5672   // FIXME 1: Should we still deal with these the cases of 'left' or 'right'
5673   // having the type 'static' in determining whether to calculate the static
5674   // distance?
5675   // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
5676 
5677   // FIXME 2: Can perhaps optimize out cases when max-width/min-width are
5678   // greater than or less than the computed width(). Be careful of box-sizing
5679   // and percentage issues.
5680 
5681   // The following is based off of the W3C Working Draft from April 11, 2006 of
5682   // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
5683   // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
5684   // (block-style-comments in this function and in
5685   // computePositionedLogicalWidthUsing() correspond to text from the spec)
5686 
5687   // We don't use containingBlock(), since we may be positioned by an enclosing
5688   // relative positioned inline.
5689   const auto* container_block = To<LayoutBoxModelObject>(Container());
5690 
5691   const LayoutUnit container_logical_width =
5692       ContainingBlockLogicalWidthForPositioned(container_block);
5693 
5694   // Use the container block's direction except when calculating the static
5695   // distance. This conforms with the reference results for
5696   // abspos-replaced-width-margin-000.htm of the CSS 2.1 test suite.
5697   TextDirection container_direction = container_block->StyleRef().Direction();
5698 
5699   bool is_horizontal = IsHorizontalWritingMode();
5700   const LayoutUnit borders_plus_padding = BorderAndPaddingLogicalWidth();
5701   const Length& margin_logical_left =
5702       is_horizontal ? StyleRef().MarginLeft() : StyleRef().MarginTop();
5703   const Length& margin_logical_right =
5704       is_horizontal ? StyleRef().MarginRight() : StyleRef().MarginBottom();
5705 
5706   Length logical_left_length = StyleRef().LogicalLeft();
5707   Length logical_right_length = StyleRef().LogicalRight();
5708   // ---------------------------------------------------------------------------
5709   //  For the purposes of this section and the next, the term "static position"
5710   //  (of an element) refers, roughly, to the position an element would have had
5711   //  in the normal flow. More precisely:
5712   //
5713   //  * The static position for 'left' is the distance from the left edge of the
5714   //    containing block to the left margin edge of a hypothetical box that
5715   //    would have been the first box of the element if its 'position' property
5716   //    had been 'static' and 'float' had been 'none'. The value is negative if
5717   //    the hypothetical box is to the left of the containing block.
5718   //  * The static position for 'right' is the distance from the right edge of
5719   //    the containing block to the right margin edge of the same hypothetical
5720   //    box as above. The value is positive if the hypothetical box is to the
5721   //    left of the containing block's edge.
5722   //
5723   //  But rather than actually calculating the dimensions of that hypothetical
5724   //  box, user agents are free to make a guess at its probable position.
5725   //
5726   //  For the purposes of calculating the static position, the containing block
5727   //  of fixed positioned elements is the initial containing block instead of
5728   //  the viewport, and all scrollable boxes should be assumed to be scrolled to
5729   //  their origin.
5730   // ---------------------------------------------------------------------------
5731   // see FIXME 1
5732   // Calculate the static distance if needed.
5733   ComputeInlineStaticDistance(logical_left_length, logical_right_length, this,
5734                               container_block, container_logical_width);
5735 
5736   // Calculate constraint equation values for 'width' case.
5737   ComputePositionedLogicalWidthUsing(
5738       kMainOrPreferredSize, StyleRef().LogicalWidth(), container_block,
5739       container_direction, container_logical_width, borders_plus_padding,
5740       logical_left_length, logical_right_length, margin_logical_left,
5741       margin_logical_right, computed_values);
5742 
5743   MinMaxSizes transferred_min_max{LayoutUnit(), LayoutUnit::Max()};
5744   if (ShouldComputeLogicalHeightFromAspectRatio())
5745     transferred_min_max = ComputeMinMaxLogicalWidthFromAspectRatio();
5746 
5747   // Calculate constraint equation values for 'max-width' case.
5748   LogicalExtentComputedValues max_values;
5749   max_values.extent_ = LayoutUnit::Max();
5750   if (!StyleRef().LogicalMaxWidth().IsNone()) {
5751     ComputePositionedLogicalWidthUsing(
5752         kMaxSize, StyleRef().LogicalMaxWidth(), container_block,
5753         container_direction, container_logical_width, borders_plus_padding,
5754         logical_left_length, logical_right_length, margin_logical_left,
5755         margin_logical_right, max_values);
5756   }
5757   if (transferred_min_max.max_size < max_values.extent_) {
5758     ComputePositionedLogicalWidthUsing(
5759         kMaxSize, Length::Fixed(transferred_min_max.max_size), container_block,
5760         container_direction, container_logical_width, borders_plus_padding,
5761         logical_left_length, logical_right_length, margin_logical_left,
5762         margin_logical_right, max_values);
5763   }
5764 
5765   if (computed_values.extent_ > max_values.extent_)
5766     max_values.CopyExceptBlockMargins(&computed_values);
5767 
5768   LogicalExtentComputedValues min_values;
5769   // Calculate constraint equation values for 'min-width' case.
5770   if (!StyleRef().LogicalMinWidth().IsZero() ||
5771       StyleRef().LogicalMinWidth().IsContentOrIntrinsicOrFillAvailable()) {
5772     ComputePositionedLogicalWidthUsing(
5773         kMinSize, StyleRef().LogicalMinWidth(), container_block,
5774         container_direction, container_logical_width, borders_plus_padding,
5775         logical_left_length, logical_right_length, margin_logical_left,
5776         margin_logical_right, min_values);
5777   }
5778   if (transferred_min_max.min_size > min_values.extent_) {
5779     ComputePositionedLogicalWidthUsing(
5780         kMinSize, Length::Fixed(transferred_min_max.min_size), container_block,
5781         container_direction, container_logical_width, borders_plus_padding,
5782         logical_left_length, logical_right_length, margin_logical_left,
5783         margin_logical_right, min_values);
5784   }
5785   if (computed_values.extent_ < min_values.extent_)
5786     min_values.CopyExceptBlockMargins(&computed_values);
5787 
5788   computed_values.extent_ += borders_plus_padding;
5789 }
5790 
ComputeLogicalLeftPositionedOffset(LayoutUnit & logical_left_pos,const LayoutBox * child,LayoutUnit logical_width_value,const LayoutBoxModelObject * container_block,LayoutUnit container_logical_width)5791 void LayoutBox::ComputeLogicalLeftPositionedOffset(
5792     LayoutUnit& logical_left_pos,
5793     const LayoutBox* child,
5794     LayoutUnit logical_width_value,
5795     const LayoutBoxModelObject* container_block,
5796     LayoutUnit container_logical_width) {
5797   if (child->IsHorizontalWritingMode()) {
5798     if (container_block->HasFlippedBlocksWritingMode()) {
5799       // Deal with differing writing modes here. Our offset needs to be in the
5800       // containing block's coordinate space. If the containing block is flipped
5801       // along this axis, then we need to flip the coordinate. This can only
5802       // happen if the containing block has flipped mode and is perpendicular
5803       // to us.
5804       logical_left_pos =
5805           container_logical_width - logical_width_value - logical_left_pos;
5806       logical_left_pos += container_block->BorderRight();
5807       if (container_block->IsBox() &&
5808           !To<LayoutBox>(container_block)->CanSkipComputeScrollbars()) {
5809         logical_left_pos += To<LayoutBox>(container_block)
5810                                 ->ComputeScrollbarsInternal(kClampToContentBox)
5811                                 .right;
5812       }
5813     } else {
5814       logical_left_pos += container_block->BorderLeft();
5815       if (container_block->IsBox() &&
5816           !To<LayoutBox>(container_block)->CanSkipComputeScrollbars()) {
5817         logical_left_pos += To<LayoutBox>(container_block)
5818                                 ->ComputeScrollbarsInternal(kClampToContentBox)
5819                                 .left;
5820       }
5821     }
5822   } else {
5823     logical_left_pos += container_block->BorderTop();
5824     if (container_block->IsBox() &&
5825         !To<LayoutBox>(container_block)->CanSkipComputeScrollbars()) {
5826       logical_left_pos += To<LayoutBox>(container_block)
5827                               ->ComputeScrollbarsInternal(kClampToContentBox)
5828                               .top;
5829     }
5830   }
5831 }
5832 
ShrinkToFitLogicalWidth(LayoutUnit available_logical_width,LayoutUnit borders_plus_padding) const5833 LayoutUnit LayoutBox::ShrinkToFitLogicalWidth(
5834     LayoutUnit available_logical_width,
5835     LayoutUnit borders_plus_padding) const {
5836   NOT_DESTROYED();
5837   MinMaxSizes sizes = PreferredLogicalWidths();
5838   sizes -= borders_plus_padding;
5839   return sizes.ShrinkToFit(available_logical_width);
5840 }
5841 
ComputePositionedLogicalWidthUsing(SizeType width_size_type,const Length & logical_width,const LayoutBoxModelObject * container_block,TextDirection container_direction,LayoutUnit container_logical_width,LayoutUnit borders_plus_padding,const Length & logical_left,const Length & logical_right,const Length & margin_logical_left,const Length & margin_logical_right,LogicalExtentComputedValues & computed_values) const5842 void LayoutBox::ComputePositionedLogicalWidthUsing(
5843     SizeType width_size_type,
5844     const Length& logical_width,
5845     const LayoutBoxModelObject* container_block,
5846     TextDirection container_direction,
5847     LayoutUnit container_logical_width,
5848     LayoutUnit borders_plus_padding,
5849     const Length& logical_left,
5850     const Length& logical_right,
5851     const Length& margin_logical_left,
5852     const Length& margin_logical_right,
5853     LogicalExtentComputedValues& computed_values) const {
5854   NOT_DESTROYED();
5855   LayoutUnit logical_width_value;
5856 
5857   DCHECK(width_size_type == kMinSize ||
5858          width_size_type == kMainOrPreferredSize || !logical_width.IsAuto());
5859   if (width_size_type == kMinSize && logical_width.IsAuto()) {
5860     if (ShouldComputeLogicalWidthFromAspectRatio()) {
5861       logical_width_value =
5862           IntrinsicLogicalWidths(MinMaxSizesType::kIntrinsic).min_size;
5863     } else {
5864       logical_width_value = LayoutUnit();
5865     }
5866   } else if (width_size_type == kMainOrPreferredSize &&
5867              logical_width.IsAuto() &&
5868              ComputeLogicalWidthFromAspectRatio(&logical_width_value)) {
5869     // We're good.
5870   } else if (logical_width.IsContentOrIntrinsicOrFillAvailable()) {
5871     logical_width_value = ComputeIntrinsicLogicalWidthUsing(
5872                               logical_width, container_logical_width) -
5873                           borders_plus_padding;
5874   } else {
5875     logical_width_value = AdjustContentBoxLogicalWidthForBoxSizing(
5876         ValueForLength(logical_width, container_logical_width));
5877   }
5878 
5879   // 'left' and 'right' cannot both be 'auto' because one would of been
5880   // converted to the static position already
5881   DCHECK(!(logical_left.IsAuto() && logical_right.IsAuto()));
5882 
5883   // minimumValueForLength will convert 'auto' to 0 so that it doesn't impact
5884   // the available space computation below.
5885   LayoutUnit logical_left_value =
5886       MinimumValueForLength(logical_left, container_logical_width);
5887   LayoutUnit logical_right_value =
5888       MinimumValueForLength(logical_right, container_logical_width);
5889 
5890   const LayoutUnit container_relative_logical_width =
5891       ContainingBlockLogicalWidthForPositioned(container_block, false);
5892 
5893   // If we are using aspect-ratio, the width is effectively not auto.
5894   bool logical_width_is_auto =
5895       logical_width.IsAuto() && !ShouldComputeLogicalWidthFromAspectRatio();
5896   bool logical_left_is_auto = logical_left.IsAuto();
5897   bool logical_right_is_auto = logical_right.IsAuto();
5898   LayoutUnit& margin_logical_left_value = StyleRef().IsLeftToRightDirection()
5899                                               ? computed_values.margins_.start_
5900                                               : computed_values.margins_.end_;
5901   LayoutUnit& margin_logical_right_value =
5902       StyleRef().IsLeftToRightDirection() ? computed_values.margins_.end_
5903                                           : computed_values.margins_.start_;
5904   if (!logical_left_is_auto && !logical_width_is_auto &&
5905       !logical_right_is_auto) {
5906     // -------------------------------------------------------------------------
5907     // If none of the three is 'auto': If both 'margin-left' and 'margin-
5908     // right' are 'auto', solve the equation under the extra constraint that
5909     // the two margins get equal values, unless this would make them negative,
5910     // in which case when direction of the containing block is 'ltr' ('rtl'),
5911     // set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
5912     // ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
5913     // solve the equation for that value. If the values are over-constrained,
5914     // ignore the value for 'left' (in case the 'direction' property of the
5915     // containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
5916     // and solve for that value.
5917     // -------------------------------------------------------------------------
5918     // NOTE:  It is not necessary to solve for 'right' in the over constrained
5919     // case because the value is not used for any further calculations.
5920 
5921     computed_values.extent_ = logical_width_value;
5922 
5923     const LayoutUnit available_space =
5924         container_logical_width -
5925         (logical_left_value + computed_values.extent_ + logical_right_value +
5926          borders_plus_padding);
5927 
5928     // Margins are now the only unknown
5929     if (margin_logical_left.IsAuto() && margin_logical_right.IsAuto()) {
5930       // Both margins auto, solve for equality
5931       if (available_space >= 0) {
5932         margin_logical_left_value =
5933             available_space / 2;  // split the difference
5934         margin_logical_right_value =
5935             available_space -
5936             margin_logical_left_value;  // account for odd valued differences
5937       } else {
5938         // Use the containing block's direction rather than the parent block's
5939         // per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
5940         if (container_direction == TextDirection::kLtr) {
5941           margin_logical_left_value = LayoutUnit();
5942           margin_logical_right_value = available_space;  // will be negative
5943         } else {
5944           margin_logical_left_value = available_space;  // will be negative
5945           margin_logical_right_value = LayoutUnit();
5946         }
5947       }
5948     } else if (margin_logical_left.IsAuto()) {
5949       // Solve for left margin
5950       margin_logical_right_value = ValueForLength(
5951           margin_logical_right, container_relative_logical_width);
5952       margin_logical_left_value = available_space - margin_logical_right_value;
5953     } else if (margin_logical_right.IsAuto()) {
5954       // Solve for right margin
5955       margin_logical_left_value =
5956           ValueForLength(margin_logical_left, container_relative_logical_width);
5957       margin_logical_right_value = available_space - margin_logical_left_value;
5958     } else {
5959       // Over-constrained, solve for left if direction is RTL
5960       margin_logical_left_value =
5961           ValueForLength(margin_logical_left, container_relative_logical_width);
5962       margin_logical_right_value = ValueForLength(
5963           margin_logical_right, container_relative_logical_width);
5964 
5965       // Use the containing block's direction rather than the parent block's
5966       // per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
5967       if (container_direction == TextDirection::kRtl)
5968         logical_left_value = (available_space + logical_left_value) -
5969                              margin_logical_left_value -
5970                              margin_logical_right_value;
5971     }
5972   } else {
5973     // -------------------------------------------------------------------------
5974     // Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
5975     // to 0, and pick the one of the following six rules that applies.
5976     //
5977     // 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
5978     //    width is shrink-to-fit. Then solve for 'left'
5979     //
5980     //              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
5981     // ------------------------------------------------------------------
5982     // 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
5983     //    the 'direction' property of the containing block is 'ltr' set
5984     //    'left' to the static position, otherwise set 'right' to the
5985     //    static position. Then solve for 'left' (if 'direction is 'rtl')
5986     //    or 'right' (if 'direction' is 'ltr').
5987     // ------------------------------------------------------------------
5988     //
5989     // 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
5990     //    width is shrink-to-fit . Then solve for 'right'
5991     // 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
5992     //    for 'left'
5993     // 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
5994     //    for 'width'
5995     // 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
5996     //    for 'right'
5997     //
5998     // Calculation of the shrink-to-fit width is similar to calculating the
5999     // width of a table cell using the automatic table layout algorithm.
6000     // Roughly: calculate the preferred width by formatting the content without
6001     // breaking lines other than where explicit line breaks occur, and also
6002     // calculate the preferred minimum width, e.g., by trying all possible line
6003     // breaks. CSS 2.1 does not define the exact algorithm.
6004     // Thirdly, calculate the available width: this is found by solving for
6005     // 'width' after setting 'left' (in case 1) or 'right' (in case 3) to 0.
6006     //
6007     // Then the shrink-to-fit width is:
6008     // min(max(preferred minimum width, available width), preferred width).
6009     // -------------------------------------------------------------------------
6010     // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
6011     // because the value is not used for any further calculations.
6012 
6013     // Calculate margins, 'auto' margins are ignored.
6014     margin_logical_left_value = MinimumValueForLength(
6015         margin_logical_left, container_relative_logical_width);
6016     margin_logical_right_value = MinimumValueForLength(
6017         margin_logical_right, container_relative_logical_width);
6018 
6019     const LayoutUnit available_space =
6020         container_logical_width -
6021         (margin_logical_left_value + margin_logical_right_value +
6022          logical_left_value + logical_right_value + borders_plus_padding);
6023 
6024     // FIXME: Is there a faster way to find the correct case?
6025     // Use rule/case that applies.
6026     if (logical_left_is_auto && logical_width_is_auto &&
6027         !logical_right_is_auto) {
6028       // RULE 1: (use shrink-to-fit for width, and solve of left)
6029       computed_values.extent_ =
6030           ShrinkToFitLogicalWidth(available_space, borders_plus_padding);
6031       logical_left_value = available_space - computed_values.extent_;
6032     } else if (!logical_left_is_auto && logical_width_is_auto &&
6033                logical_right_is_auto) {
6034       // RULE 3: (use shrink-to-fit for width, and no need solve of right)
6035       computed_values.extent_ =
6036           ShrinkToFitLogicalWidth(available_space, borders_plus_padding);
6037     } else if (logical_left_is_auto && !logical_width_is_auto &&
6038                !logical_right_is_auto) {
6039       // RULE 4: (solve for left)
6040       computed_values.extent_ = logical_width_value;
6041       logical_left_value = available_space - computed_values.extent_;
6042     } else if (!logical_left_is_auto && logical_width_is_auto &&
6043                !logical_right_is_auto) {
6044       // RULE 5: (solve for width)
6045       if (AutoWidthShouldFitContent())
6046         computed_values.extent_ =
6047             ShrinkToFitLogicalWidth(available_space, borders_plus_padding);
6048       else
6049         computed_values.extent_ = std::max(LayoutUnit(), available_space);
6050     } else if (!logical_left_is_auto && !logical_width_is_auto &&
6051                logical_right_is_auto) {
6052       // RULE 6: (no need solve for right)
6053       computed_values.extent_ = logical_width_value;
6054     }
6055   }
6056 
6057   // Use computed values to calculate the horizontal position.
6058 
6059   // FIXME: This hack is needed to calculate the  logical left position for a
6060   // 'rtl' relatively positioned, inline because right now, it is using the
6061   // logical left position of the first line box when really it should use the
6062   // last line box. When this is fixed elsewhere, this block should be removed.
6063   if (container_block->IsLayoutInline() &&
6064       !container_block->StyleRef().IsLeftToRightDirection()) {
6065     const auto* flow = To<LayoutInline>(container_block);
6066     InlineFlowBox* first_line = flow->FirstLineBox();
6067     InlineFlowBox* last_line = flow->LastLineBox();
6068     if (first_line && last_line && first_line != last_line) {
6069       computed_values.position_ =
6070           logical_left_value + margin_logical_left_value +
6071           last_line->BorderLogicalLeft() +
6072           (last_line->LogicalLeft() - first_line->LogicalLeft());
6073       return;
6074     }
6075   }
6076 
6077   computed_values.position_ = logical_left_value + margin_logical_left_value;
6078   ComputeLogicalLeftPositionedOffset(computed_values.position_, this,
6079                                      computed_values.extent_, container_block,
6080                                      container_logical_width);
6081 }
6082 
ComputeBlockStaticDistance(Length & logical_top,Length & logical_bottom,const LayoutBox * child,const LayoutBoxModelObject * container_block,const NGBoxFragmentBuilder * fragment_builder)6083 void LayoutBox::ComputeBlockStaticDistance(
6084     Length& logical_top,
6085     Length& logical_bottom,
6086     const LayoutBox* child,
6087     const LayoutBoxModelObject* container_block,
6088     const NGBoxFragmentBuilder* fragment_builder) {
6089   if (!logical_top.IsAuto() || !logical_bottom.IsAuto())
6090     return;
6091 
6092   // FIXME: The static distance computation has not been patched for mixed
6093   // writing modes.
6094   LayoutUnit static_logical_top = child->Layer()->StaticBlockPosition();
6095   for (LayoutObject* curr = child->Parent(); curr && curr != container_block;
6096        curr = curr->Container()) {
6097     if (!curr->IsBox() || curr->IsLegacyTableRow())
6098       continue;
6099     const auto& box = *To<LayoutBox>(curr);
6100     static_logical_top +=
6101         (fragment_builder &&
6102          fragment_builder->GetLayoutObject() == box.Parent())
6103             ? fragment_builder->GetChildOffset(&box).block_offset
6104             : box.LogicalTop();
6105     if (box.IsInFlowPositioned())
6106       static_logical_top += box.OffsetForInFlowPosition().top;
6107     if (!box.IsLayoutFlowThread())
6108       continue;
6109     // We're walking out of a flowthread here. This flow thread is not in the
6110     // containing block chain, so we need to convert the position from the
6111     // coordinate space of this flowthread to the containing coordinate space.
6112     // The inline position cannot affect the block position, so we don't bother
6113     // calculating it.
6114     LayoutUnit dummy_inline_position;
6115     To<LayoutFlowThread>(box).FlowThreadToContainingCoordinateSpace(
6116         static_logical_top, dummy_inline_position);
6117   }
6118 
6119   // Now static_logical_top is relative to container_block's logical top.
6120   // Convert it to be relative to containing_block's logical client top.
6121   static_logical_top -= container_block->BorderBefore();
6122   if (auto* box = DynamicTo<LayoutBox>(container_block))
6123     static_logical_top -= box->LogicalTopScrollbarHeight();
6124   logical_top = Length::Fixed(static_logical_top);
6125 }
6126 
ComputePositionedLogicalHeight(LogicalExtentComputedValues & computed_values) const6127 void LayoutBox::ComputePositionedLogicalHeight(
6128     LogicalExtentComputedValues& computed_values) const {
6129   NOT_DESTROYED();
6130   // The following is based off of the W3C Working Draft from April 11, 2006 of
6131   // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
6132   // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height>
6133   // (block-style-comments in this function and in
6134   // computePositionedLogicalHeightUsing()
6135   // correspond to text from the spec)
6136 
6137   // We don't use containingBlock(), since we may be positioned by an enclosing
6138   // relpositioned inline.
6139   const auto* container_block = To<LayoutBoxModelObject>(Container());
6140 
6141   const LayoutUnit container_logical_height =
6142       ContainingBlockLogicalHeightForPositioned(container_block);
6143 
6144   const ComputedStyle& style_to_use = StyleRef();
6145   const LayoutUnit borders_plus_padding = BorderAndPaddingLogicalHeight();
6146   const Length& margin_before = style_to_use.MarginBefore();
6147   const Length& margin_after = style_to_use.MarginAfter();
6148   Length logical_top_length = style_to_use.LogicalTop();
6149   Length logical_bottom_length = style_to_use.LogicalBottom();
6150 
6151   // ---------------------------------------------------------------------------
6152   // For the purposes of this section and the next, the term "static position"
6153   // (of an element) refers, roughly, to the position an element would have had
6154   // in the normal flow. More precisely, the static position for 'top' is the
6155   // distance from the top edge of the containing block to the top margin edge
6156   // of a hypothetical box that would have been the first box of the element if
6157   // its 'position' property had been 'static' and 'float' had been 'none'. The
6158   // value is negative if the hypothetical box is above the containing block.
6159   //
6160   // But rather than actually calculating the dimensions of that hypothetical
6161   // box, user agents are free to make a guess at its probable position.
6162   //
6163   // For the purposes of calculating the static position, the containing block
6164   // of fixed positioned elements is the initial containing block instead of
6165   // the viewport.
6166   // ---------------------------------------------------------------------------
6167   // see FIXME 1
6168   // Calculate the static distance if needed.
6169   ComputeBlockStaticDistance(logical_top_length, logical_bottom_length, this,
6170                              container_block);
6171 
6172   // Calculate constraint equation values for 'height' case.
6173   LayoutUnit logical_height = computed_values.extent_;
6174   ComputePositionedLogicalHeightUsing(
6175       kMainOrPreferredSize, style_to_use.LogicalHeight(), container_block,
6176       container_logical_height, borders_plus_padding, logical_height,
6177       logical_top_length, logical_bottom_length, margin_before, margin_after,
6178       computed_values);
6179 
6180   // Avoid doing any work in the common case (where the values of min-height and
6181   // max-height are their defaults).
6182   // see FIXME 2
6183 
6184   // Calculate constraint equation values for 'max-height' case.
6185   const Length& logical_max_height = style_to_use.LogicalMaxHeight();
6186   if (!logical_max_height.IsNone() && !logical_max_height.IsMinContent() &&
6187       !logical_max_height.IsMaxContent() &&
6188       !logical_max_height.IsMinIntrinsic() &&
6189       !logical_max_height.IsFitContent()) {
6190     LogicalExtentComputedValues max_values;
6191 
6192     ComputePositionedLogicalHeightUsing(
6193         kMaxSize, logical_max_height, container_block, container_logical_height,
6194         borders_plus_padding, logical_height, logical_top_length,
6195         logical_bottom_length, margin_before, margin_after, max_values);
6196 
6197     if (computed_values.extent_ > max_values.extent_) {
6198       computed_values.extent_ = max_values.extent_;
6199       computed_values.position_ = max_values.position_;
6200       computed_values.margins_.before_ = max_values.margins_.before_;
6201       computed_values.margins_.after_ = max_values.margins_.after_;
6202     }
6203   }
6204 
6205   // Calculate constraint equation values for 'min-height' case.
6206   Length logical_min_height = style_to_use.LogicalMinHeight();
6207   if (logical_min_height.IsMinContent() || logical_min_height.IsMaxContent() ||
6208       logical_min_height.IsMinIntrinsic() || logical_min_height.IsFitContent())
6209     logical_min_height = Length::Auto();
6210   // auto is considered to be zero, so we need to check for it explicitly.
6211   if (logical_min_height.IsAuto() || !logical_min_height.IsZero() ||
6212       logical_min_height.IsFillAvailable()) {
6213     LogicalExtentComputedValues min_values;
6214 
6215     ComputePositionedLogicalHeightUsing(
6216         kMinSize, logical_min_height, container_block, container_logical_height,
6217         borders_plus_padding, logical_height, logical_top_length,
6218         logical_bottom_length, margin_before, margin_after, min_values);
6219 
6220     if (computed_values.extent_ < min_values.extent_) {
6221       computed_values.extent_ = min_values.extent_;
6222       computed_values.position_ = min_values.position_;
6223       computed_values.margins_.before_ = min_values.margins_.before_;
6224       computed_values.margins_.after_ = min_values.margins_.after_;
6225     }
6226   }
6227 
6228   // Set final height value.
6229   computed_values.extent_ += borders_plus_padding;
6230 }
6231 
ComputeLogicalTopPositionedOffset(LayoutUnit & logical_top_pos,const LayoutBox * child,LayoutUnit logical_height_value,const LayoutBoxModelObject * container_block,LayoutUnit container_logical_height)6232 void LayoutBox::ComputeLogicalTopPositionedOffset(
6233     LayoutUnit& logical_top_pos,
6234     const LayoutBox* child,
6235     LayoutUnit logical_height_value,
6236     const LayoutBoxModelObject* container_block,
6237     LayoutUnit container_logical_height) {
6238   // Deal with differing writing modes here. Our offset needs to be in the
6239   // containing block's coordinate space. If the containing block is flipped
6240   // along this axis, then we need to flip the coordinate.  This can only happen
6241   // if the containing block is both a flipped mode and perpendicular to us.
6242   if ((child->StyleRef().IsFlippedBlocksWritingMode() &&
6243        child->IsHorizontalWritingMode() !=
6244            container_block->IsHorizontalWritingMode()) ||
6245       (child->StyleRef().IsFlippedBlocksWritingMode() !=
6246            container_block->StyleRef().IsFlippedBlocksWritingMode() &&
6247        child->IsHorizontalWritingMode() ==
6248            container_block->IsHorizontalWritingMode())) {
6249     logical_top_pos =
6250         container_logical_height - logical_height_value - logical_top_pos;
6251   }
6252 
6253   // Convert logical_top_pos from container's client space to container's border
6254   // box space.
6255   if (child->IsHorizontalWritingMode()) {
6256     logical_top_pos += container_block->BorderTop();
6257     if (container_block->IsBox() &&
6258         !To<LayoutBox>(container_block)->CanSkipComputeScrollbars()) {
6259       logical_top_pos += To<LayoutBox>(container_block)
6260                              ->ComputeScrollbarsInternal(kClampToContentBox)
6261                              .top;
6262     }
6263   } else if (container_block->HasFlippedBlocksWritingMode()) {
6264     logical_top_pos += container_block->BorderRight();
6265     if (container_block->IsBox() &&
6266         !To<LayoutBox>(container_block)->CanSkipComputeScrollbars()) {
6267       logical_top_pos += To<LayoutBox>(container_block)
6268                              ->ComputeScrollbarsInternal(kClampToContentBox)
6269                              .right;
6270     }
6271   } else {
6272     logical_top_pos += container_block->BorderLeft();
6273     if (container_block->IsBox() &&
6274         !To<LayoutBox>(container_block)->CanSkipComputeScrollbars()) {
6275       logical_top_pos += To<LayoutBox>(container_block)
6276                              ->ComputeScrollbarsInternal(kClampToContentBox)
6277                              .left;
6278     }
6279   }
6280 }
6281 
ComputePositionedLogicalHeightUsing(SizeType height_size_type,Length logical_height_length,const LayoutBoxModelObject * container_block,LayoutUnit container_logical_height,LayoutUnit borders_plus_padding,LayoutUnit logical_height,const Length & logical_top,const Length & logical_bottom,const Length & margin_before,const Length & margin_after,LogicalExtentComputedValues & computed_values) const6282 void LayoutBox::ComputePositionedLogicalHeightUsing(
6283     SizeType height_size_type,
6284     Length logical_height_length,
6285     const LayoutBoxModelObject* container_block,
6286     LayoutUnit container_logical_height,
6287     LayoutUnit borders_plus_padding,
6288     LayoutUnit logical_height,
6289     const Length& logical_top,
6290     const Length& logical_bottom,
6291     const Length& margin_before,
6292     const Length& margin_after,
6293     LogicalExtentComputedValues& computed_values) const {
6294   NOT_DESTROYED();
6295   DCHECK(height_size_type == kMinSize ||
6296          height_size_type == kMainOrPreferredSize ||
6297          !logical_height_length.IsAuto());
6298   if (height_size_type == kMinSize && logical_height_length.IsAuto()) {
6299     if (ShouldComputeLogicalHeightFromAspectRatio())
6300       logical_height_length = Length::Fixed(logical_height);
6301     else
6302       logical_height_length = Length::Fixed(0);
6303   }
6304 
6305   // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
6306   // converted to the static position in computePositionedLogicalHeight()
6307   DCHECK(!(logical_top.IsAuto() && logical_bottom.IsAuto()));
6308 
6309   LayoutUnit logical_height_value;
6310   LayoutUnit content_logical_height = logical_height - borders_plus_padding;
6311 
6312   const LayoutUnit container_relative_logical_width =
6313       ContainingBlockLogicalWidthForPositioned(container_block, false);
6314 
6315   LayoutUnit logical_top_value;
6316 
6317   bool from_aspect_ratio = height_size_type == kMainOrPreferredSize &&
6318                            ShouldComputeLogicalHeightFromAspectRatio();
6319   bool logical_height_is_auto =
6320       logical_height_length.IsAuto() && !from_aspect_ratio;
6321   bool logical_top_is_auto = logical_top.IsAuto();
6322   bool logical_bottom_is_auto = logical_bottom.IsAuto();
6323 
6324   LayoutUnit resolved_logical_height;
6325   // Height is never unsolved for tables.
6326   if (IsTable()) {
6327     resolved_logical_height = content_logical_height;
6328     logical_height_is_auto = false;
6329   } else {
6330     if (logical_height_length.IsContentOrIntrinsicOrFillAvailable()) {
6331       resolved_logical_height = ComputeIntrinsicLogicalContentHeightUsing(
6332           height_size_type, logical_height_length, content_logical_height,
6333           borders_plus_padding);
6334     } else if (from_aspect_ratio) {
6335       NGBoxStrut border_padding(BorderStart() + ComputedCSSPaddingStart(),
6336                                 BorderEnd() + ComputedCSSPaddingEnd(),
6337                                 BorderBefore() + ComputedCSSPaddingBefore(),
6338                                 BorderAfter() + ComputedCSSPaddingAfter());
6339       resolved_logical_height = BlockSizeFromAspectRatio(
6340           border_padding, StyleRef().LogicalAspectRatio(),
6341           StyleRef().BoxSizing(), LogicalWidth());
6342       resolved_logical_height = std::max(
6343           LayoutUnit(), resolved_logical_height - borders_plus_padding);
6344     } else {
6345       resolved_logical_height = AdjustContentBoxLogicalHeightForBoxSizing(
6346           ValueForLength(logical_height_length, container_logical_height));
6347     }
6348   }
6349 
6350   if (!logical_top_is_auto && !logical_height_is_auto &&
6351       !logical_bottom_is_auto) {
6352     // -------------------------------------------------------------------------
6353     // If none of the three are 'auto': If both 'margin-top' and 'margin-bottom'
6354     // are 'auto', solve the equation under the extra constraint that the two
6355     // margins get equal values. If one of 'margin-top' or 'margin- bottom' is
6356     // 'auto', solve the equation for that value. If the values are over-
6357     // constrained, ignore the value for 'bottom' and solve for that value.
6358     // -------------------------------------------------------------------------
6359     // NOTE:  It is not necessary to solve for 'bottom' in the over constrained
6360     // case because the value is not used for any further calculations.
6361 
6362     logical_height_value = resolved_logical_height;
6363     logical_top_value = ValueForLength(logical_top, container_logical_height);
6364 
6365     const LayoutUnit available_space =
6366         container_logical_height -
6367         (logical_top_value + logical_height_value +
6368          ValueForLength(logical_bottom, container_logical_height) +
6369          borders_plus_padding);
6370 
6371     // Margins are now the only unknown
6372     if (margin_before.IsAuto() && margin_after.IsAuto()) {
6373       // Both margins auto, solve for equality
6374       // NOTE: This may result in negative values.
6375       computed_values.margins_.before_ =
6376           available_space / 2;  // split the difference
6377       computed_values.margins_.after_ =
6378           available_space - computed_values.margins_
6379                                 .before_;  // account for odd valued differences
6380     } else if (margin_before.IsAuto()) {
6381       // Solve for top margin
6382       computed_values.margins_.after_ =
6383           ValueForLength(margin_after, container_relative_logical_width);
6384       computed_values.margins_.before_ =
6385           available_space - computed_values.margins_.after_;
6386     } else if (margin_after.IsAuto()) {
6387       // Solve for bottom margin
6388       computed_values.margins_.before_ =
6389           ValueForLength(margin_before, container_relative_logical_width);
6390       computed_values.margins_.after_ =
6391           available_space - computed_values.margins_.before_;
6392     } else {
6393       // Over-constrained, (no need solve for bottom)
6394       computed_values.margins_.before_ =
6395           ValueForLength(margin_before, container_relative_logical_width);
6396       computed_values.margins_.after_ =
6397           ValueForLength(margin_after, container_relative_logical_width);
6398     }
6399   } else {
6400     // -------------------------------------------------------------------------
6401     // Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
6402     // to 0, and pick the one of the following six rules that applies.
6403     //
6404     // 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then
6405     //    the height is based on the content, and solve for 'top'.
6406     //
6407     //              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
6408     // ------------------------------------------------------------------
6409     // 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
6410     //    set 'top' to the static position, and solve for 'bottom'.
6411     // ------------------------------------------------------------------
6412     //
6413     // 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
6414     //    the height is based on the content, and solve for 'bottom'.
6415     // 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
6416     //    solve for 'top'.
6417     // 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
6418     //    solve for 'height'.
6419     // 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
6420     //    solve for 'bottom'.
6421     // -------------------------------------------------------------------------
6422     // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
6423     // because the value is not used for any further calculations.
6424 
6425     // Calculate margins, 'auto' margins are ignored.
6426     computed_values.margins_.before_ =
6427         MinimumValueForLength(margin_before, container_relative_logical_width);
6428     computed_values.margins_.after_ =
6429         MinimumValueForLength(margin_after, container_relative_logical_width);
6430 
6431     const LayoutUnit available_space =
6432         container_logical_height -
6433         (computed_values.margins_.before_ + computed_values.margins_.after_ +
6434          borders_plus_padding);
6435 
6436     // Use rule/case that applies.
6437     if (logical_top_is_auto && logical_height_is_auto &&
6438         !logical_bottom_is_auto) {
6439       // RULE 1: (height is content based, solve of top)
6440       logical_height_value = content_logical_height;
6441       logical_top_value =
6442           available_space -
6443           (logical_height_value +
6444            ValueForLength(logical_bottom, container_logical_height));
6445     } else if (!logical_top_is_auto && logical_height_is_auto &&
6446                logical_bottom_is_auto) {
6447       // RULE 3: (height is content based, no need solve of bottom)
6448       logical_top_value = ValueForLength(logical_top, container_logical_height);
6449       logical_height_value = content_logical_height;
6450     } else if (logical_top_is_auto && !logical_height_is_auto &&
6451                !logical_bottom_is_auto) {
6452       // RULE 4: (solve of top)
6453       logical_height_value = resolved_logical_height;
6454       logical_top_value =
6455           available_space -
6456           (logical_height_value +
6457            ValueForLength(logical_bottom, container_logical_height));
6458     } else if (!logical_top_is_auto && logical_height_is_auto &&
6459                !logical_bottom_is_auto) {
6460       // RULE 5: (solve of height)
6461       logical_top_value = ValueForLength(logical_top, container_logical_height);
6462       logical_height_value = std::max(
6463           LayoutUnit(),
6464           available_space -
6465               (logical_top_value +
6466                ValueForLength(logical_bottom, container_logical_height)));
6467     } else if (!logical_top_is_auto && !logical_height_is_auto &&
6468                logical_bottom_is_auto) {
6469       // RULE 6: (no need solve of bottom)
6470       logical_height_value = resolved_logical_height;
6471       logical_top_value = ValueForLength(logical_top, container_logical_height);
6472     }
6473   }
6474   computed_values.extent_ = logical_height_value;
6475 
6476   // Use computed values to calculate the vertical position.
6477   computed_values.position_ =
6478       logical_top_value + computed_values.margins_.before_;
6479   ComputeLogicalTopPositionedOffset(computed_values.position_, this,
6480                                     logical_height_value, container_block,
6481                                     container_logical_height);
6482 }
6483 
LocalCaretRect(const InlineBox * box,int caret_offset,LayoutUnit * extra_width_to_end_of_line) const6484 LayoutRect LayoutBox::LocalCaretRect(
6485     const InlineBox* box,
6486     int caret_offset,
6487     LayoutUnit* extra_width_to_end_of_line) const {
6488   NOT_DESTROYED();
6489   // VisiblePositions at offsets inside containers either a) refer to the
6490   // positions before/after those containers (tables and select elements) or
6491   // b) refer to the position inside an empty block.
6492   // They never refer to children.
6493   // FIXME: Paint the carets inside empty blocks differently than the carets
6494   // before/after elements.
6495   LayoutUnit caret_width = GetFrameView()->CaretWidth();
6496   LayoutRect rect(Location(), LayoutSize(caret_width, Size().Height()));
6497   bool ltr =
6498       box ? box->IsLeftToRightDirection() : StyleRef().IsLeftToRightDirection();
6499 
6500   if ((!caret_offset) ^ ltr)
6501     rect.Move(LayoutSize(Size().Width() - caret_width, LayoutUnit()));
6502 
6503   if (box) {
6504     const RootInlineBox& root_box = box->Root();
6505     LayoutUnit top = root_box.LineTop();
6506     rect.SetY(top);
6507     rect.SetHeight(root_box.LineBottom() - top);
6508   }
6509 
6510   // If height of box is smaller than font height, use the latter one,
6511   // otherwise the caret might become invisible.
6512   //
6513   // Also, if the box is not an atomic inline-level element, always use the font
6514   // height. This prevents the "big caret" bug described in:
6515   // <rdar://problem/3777804> Deleting all content in a document can result in
6516   // giant tall-as-window insertion point
6517   //
6518   // FIXME: ignoring :first-line, missing good reason to take care of
6519   const SimpleFontData* font_data = StyleRef().GetFont().PrimaryFont();
6520   LayoutUnit font_height =
6521       LayoutUnit(font_data ? font_data->GetFontMetrics().Height() : 0);
6522   if (font_height > rect.Height() || (!IsAtomicInlineLevel() && !IsTable()))
6523     rect.SetHeight(font_height);
6524 
6525   if (extra_width_to_end_of_line)
6526     *extra_width_to_end_of_line = Location().X() + Size().Width() - rect.MaxX();
6527 
6528   // Move to local coords
6529   rect.MoveBy(-Location());
6530 
6531   // FIXME: Border/padding should be added for all elements but this workaround
6532   // is needed because we use offsets inside an "atomic" element to represent
6533   // positions before and after the element in deprecated editing offsets.
6534   if (GetNode() &&
6535       !(EditingIgnoresContent(*GetNode()) || IsDisplayInsideTable(GetNode()))) {
6536     rect.SetX(rect.X() + BorderLeft() + PaddingLeft());
6537     rect.SetY(rect.Y() + PaddingTop() + BorderTop());
6538   }
6539 
6540   if (!IsHorizontalWritingMode())
6541     return rect.TransposedRect();
6542 
6543   return rect;
6544 }
6545 
PositionForPoint(const PhysicalOffset & point) const6546 PositionWithAffinity LayoutBox::PositionForPoint(
6547     const PhysicalOffset& point) const {
6548   NOT_DESTROYED();
6549   // no children...return this layout object's element, if there is one, and
6550   // offset 0
6551   LayoutObject* first_child = SlowFirstChild();
6552   if (!first_child)
6553     return CreatePositionWithAffinity(
6554         NonPseudoNode() ? FirstPositionInOrBeforeNode(*NonPseudoNode())
6555                         : Position());
6556 
6557   if (IsTable() && NonPseudoNode()) {
6558     const Node& node = *NonPseudoNode();
6559     LayoutUnit x_in_block_direction = FlipForWritingMode(point.left);
6560     if (x_in_block_direction < 0 || x_in_block_direction > Size().Width() ||
6561         point.top < 0 || point.top > Size().Height()) {
6562       if (x_in_block_direction <= Size().Width() / 2) {
6563         return CreatePositionWithAffinity(FirstPositionInOrBeforeNode(node));
6564       }
6565       return CreatePositionWithAffinity(LastPositionInOrAfterNode(node));
6566     }
6567   }
6568 
6569   // Pass off to the closest child.
6570   LayoutUnit min_dist = LayoutUnit::Max();
6571   LayoutBox* closest_layout_object = nullptr;
6572   PhysicalOffset adjusted_point = point;
6573   if (IsLegacyTableRow())
6574     adjusted_point += PhysicalLocation();
6575 
6576   for (LayoutObject* layout_object = first_child; layout_object;
6577        layout_object = layout_object->NextSibling()) {
6578     if ((!layout_object->SlowFirstChild() && !layout_object->IsInline() &&
6579          !layout_object->IsLayoutBlockFlow()) ||
6580         layout_object->StyleRef().Visibility() != EVisibility::kVisible)
6581       continue;
6582 
6583     if (!layout_object->IsBox())
6584       continue;
6585 
6586     auto* layout_box = To<LayoutBox>(layout_object);
6587 
6588     LayoutUnit top =
6589         layout_box->BorderTop() + layout_box->PaddingTop() +
6590         (IsLegacyTableRow() ? LayoutUnit() : layout_box->Location().Y());
6591     LayoutUnit bottom = top + layout_box->ContentHeight();
6592     LayoutUnit left =
6593         layout_box->BorderLeft() + layout_box->PaddingLeft() +
6594         (IsLegacyTableRow() ? LayoutUnit()
6595                             : layout_box->PhysicalLocation().left);
6596     LayoutUnit right = left + layout_box->ContentWidth();
6597 
6598     if (point.left <= right && point.left >= left && point.top <= top &&
6599         point.top >= bottom) {
6600       if (layout_box->IsLegacyTableRow()) {
6601         return layout_box->PositionForPoint(point + adjusted_point -
6602                                             layout_box->PhysicalLocation());
6603       }
6604       return layout_box->PositionForPoint(point -
6605                                           layout_box->PhysicalLocation());
6606     }
6607 
6608     // Find the distance from (x, y) to the box.  Split the space around the box
6609     // into 8 pieces and use a different compare depending on which piece (x, y)
6610     // is in.
6611     PhysicalOffset cmp;
6612     if (point.left > right) {
6613       if (point.top < top)
6614         cmp = PhysicalOffset(right, top);
6615       else if (point.top > bottom)
6616         cmp = PhysicalOffset(right, bottom);
6617       else
6618         cmp = PhysicalOffset(right, point.top);
6619     } else if (point.left < left) {
6620       if (point.top < top)
6621         cmp = PhysicalOffset(left, top);
6622       else if (point.top > bottom)
6623         cmp = PhysicalOffset(left, bottom);
6624       else
6625         cmp = PhysicalOffset(left, point.top);
6626     } else {
6627       if (point.top < top)
6628         cmp = PhysicalOffset(point.left, top);
6629       else
6630         cmp = PhysicalOffset(point.left, bottom);
6631     }
6632 
6633     PhysicalOffset difference = cmp - point;
6634 
6635     LayoutUnit dist =
6636         difference.left * difference.left + difference.top * difference.top;
6637     if (dist < min_dist) {
6638       closest_layout_object = layout_box;
6639       min_dist = dist;
6640     }
6641   }
6642 
6643   if (closest_layout_object) {
6644     return closest_layout_object->PositionForPoint(
6645         adjusted_point - closest_layout_object->PhysicalLocation());
6646   }
6647   return CreatePositionWithAffinity(
6648       NonPseudoNode() ? FirstPositionInOrBeforeNode(*NonPseudoNode())
6649                       : Position());
6650 }
6651 
6652 DISABLE_CFI_PERF
ShrinkToAvoidFloats() const6653 bool LayoutBox::ShrinkToAvoidFloats() const {
6654   NOT_DESTROYED();
6655   // Floating objects don't shrink.  Objects that don't avoid floats don't
6656   // shrink.
6657   if (IsInline() || !CreatesNewFormattingContext() || IsFloating())
6658     return false;
6659 
6660   // Only auto width objects can possibly shrink to avoid floats.
6661   if (!StyleRef().Width().IsAuto())
6662     return false;
6663 
6664   // If the containing block is LayoutNG, we will not let legacy layout deal
6665   // with positioning of floats or sizing of auto-width new formatting context
6666   // block level objects adjacent to them.
6667   if (const auto* containing_block = ContainingBlock()) {
6668     if (containing_block->IsLayoutNGMixin())
6669       return false;
6670   }
6671 
6672   // Legends are taken out of the normal flow, and are laid out at the very
6673   // start of the fieldset, and are therefore not affected by floats (that may
6674   // appear earlier in the DOM).
6675   if (IsRenderedLegend())
6676     return false;
6677 
6678   return true;
6679 }
6680 
6681 DISABLE_CFI_PERF
ShouldBeConsideredAsReplaced() const6682 bool LayoutBox::ShouldBeConsideredAsReplaced() const {
6683   NOT_DESTROYED();
6684   if (IsAtomicInlineLevel())
6685     return true;
6686   // We need to detect all types of objects that should be treated as replaced.
6687   // Callers of this method will use the result for various things, such as
6688   // determining how to size the object, or whether it needs to avoid adjacent
6689   // floats, just like objects that establish a new formatting context.
6690   // IsAtomicInlineLevel() will not catch all the cases. Objects may be
6691   // block-level and still replaced, and we cannot deduce this from the
6692   // LayoutObject type. Checkboxes and radio buttons are such examples. We need
6693   // to check the Element type. This also applies to images, since we may have
6694   // created a block-flow LayoutObject for the ALT text (which still counts as
6695   // replaced).
6696   auto* element = DynamicTo<Element>(GetNode());
6697   if (!element)
6698     return false;
6699   if (element->IsFormControlElement()) {
6700     // Form control elements are generally replaced objects. Fieldsets are not,
6701     // though. A fieldset is (almost) a regular block container, and should be
6702     // treated as such.
6703     return !IsA<HTMLFieldSetElement>(element);
6704   }
6705   return IsA<HTMLImageElement>(element);
6706 }
6707 
UpdateFragmentationInfoForChild(LayoutBox & child)6708 void LayoutBox::UpdateFragmentationInfoForChild(LayoutBox& child) {
6709   NOT_DESTROYED();
6710   LayoutState* layout_state = View()->GetLayoutState();
6711   DCHECK(layout_state->IsPaginated());
6712   child.SetOffsetToNextPage(LayoutUnit());
6713   if (!IsPageLogicalHeightKnown())
6714     return;
6715 
6716   LayoutUnit logical_top = child.LogicalTop();
6717   LayoutUnit logical_height = child.LogicalHeightWithVisibleOverflow();
6718   LayoutUnit space_left = PageRemainingLogicalHeightForOffset(
6719       logical_top, kAssociateWithLatterPage);
6720   if (space_left < logical_height)
6721     child.SetOffsetToNextPage(space_left);
6722 }
6723 
ChildNeedsRelayoutForPagination(const LayoutBox & child) const6724 bool LayoutBox::ChildNeedsRelayoutForPagination(const LayoutBox& child) const {
6725   NOT_DESTROYED();
6726   // TODO(mstensho): Should try to get this to work for floats too, instead of
6727   // just marking and bailing here.
6728   if (child.IsFloating())
6729     return true;
6730   const LayoutFlowThread* flow_thread = child.FlowThreadContainingBlock();
6731   // Figure out if we really need to force re-layout of the child. We only need
6732   // to do this if there's a chance that we need to recalculate pagination
6733   // struts inside.
6734   if (IsPageLogicalHeightKnown()) {
6735     LayoutUnit logical_top = child.LogicalTop();
6736     LayoutUnit logical_height = child.LogicalHeightWithVisibleOverflow();
6737     LayoutUnit remaining_space = PageRemainingLogicalHeightForOffset(
6738         logical_top, kAssociateWithLatterPage);
6739     if (child.OffsetToNextPage()) {
6740       // We need to relayout unless we're going to break at the exact same
6741       // location as before.
6742       if (child.OffsetToNextPage() != remaining_space)
6743         return true;
6744       // If column height isn't guaranteed to be uniform, we have no way of
6745       // telling what has happened after the first break.
6746       if (flow_thread && flow_thread->MayHaveNonUniformPageLogicalHeight())
6747         return true;
6748     } else if (logical_height > remaining_space) {
6749       // Last time we laid out this child, we didn't need to break, but now we
6750       // have to. So we need to relayout.
6751       return true;
6752     }
6753   } else if (child.OffsetToNextPage()) {
6754     // This child did previously break, but it won't anymore, because we no
6755     // longer have a known fragmentainer height.
6756     return true;
6757   }
6758 
6759   // It seems that we can skip layout of this child, but we need to ask the flow
6760   // thread for permission first. We currently cannot skip over objects
6761   // containing column spanners.
6762   return flow_thread && !flow_thread->CanSkipLayout(child);
6763 }
6764 
MarkChildForPaginationRelayoutIfNeeded(LayoutBox & child,SubtreeLayoutScope & layout_scope)6765 void LayoutBox::MarkChildForPaginationRelayoutIfNeeded(
6766     LayoutBox& child,
6767     SubtreeLayoutScope& layout_scope) {
6768   NOT_DESTROYED();
6769   DCHECK(!child.NeedsLayout() || child.ChildLayoutBlockedByDisplayLock());
6770   LayoutState* layout_state = View()->GetLayoutState();
6771 
6772   if (layout_state->PaginationStateChanged() ||
6773       (layout_state->IsPaginated() && ChildNeedsRelayoutForPagination(child)))
6774     layout_scope.SetChildNeedsLayout(&child);
6775 }
6776 
MarkOrthogonalWritingModeRoot()6777 void LayoutBox::MarkOrthogonalWritingModeRoot() {
6778   NOT_DESTROYED();
6779   DCHECK(GetFrameView());
6780   GetFrameView()->AddOrthogonalWritingModeRoot(*this);
6781 }
6782 
UnmarkOrthogonalWritingModeRoot()6783 void LayoutBox::UnmarkOrthogonalWritingModeRoot() {
6784   NOT_DESTROYED();
6785   DCHECK(GetFrameView());
6786   GetFrameView()->RemoveOrthogonalWritingModeRoot(*this);
6787 }
6788 
6789 // Children of LayoutCustom object's are only considered "items" when it has a
6790 // loaded algorithm.
IsCustomItem() const6791 bool LayoutBox::IsCustomItem() const {
6792   NOT_DESTROYED();
6793   auto* parent_layout_box = DynamicTo<LayoutNGCustom>(Parent());
6794   return parent_layout_box && parent_layout_box->IsLoaded();
6795 }
6796 
6797 // LayoutCustom items are only shrink-to-fit during the web-developer defined
6798 // layout phase (not during fallback).
IsCustomItemShrinkToFit() const6799 bool LayoutBox::IsCustomItemShrinkToFit() const {
6800   NOT_DESTROYED();
6801   DCHECK(IsCustomItem());
6802   return To<LayoutNGCustom>(Parent())->IsLoaded();
6803 }
6804 
AddVisualEffectOverflow()6805 void LayoutBox::AddVisualEffectOverflow() {
6806   NOT_DESTROYED();
6807   if (!StyleRef().HasVisualOverflowingEffect())
6808     return;
6809 
6810   // Add in the final overflow with shadows, outsets and outline combined.
6811   PhysicalRect visual_effect_overflow = PhysicalBorderBoxRect();
6812   LayoutRectOutsets outsets = ComputeVisualEffectOverflowOutsets();
6813   visual_effect_overflow.Expand(outsets);
6814   AddSelfVisualOverflow(visual_effect_overflow);
6815 
6816   if (VisualOverflowIsSet()) {
6817     overflow_->visual_overflow->SetHasSubpixelVisualEffectOutsets(
6818         !IsIntegerValue(outsets.Top()) || !IsIntegerValue(outsets.Right()) ||
6819         !IsIntegerValue(outsets.Bottom()) || !IsIntegerValue(outsets.Left()));
6820   }
6821 }
6822 
ComputeVisualEffectOverflowOutsets()6823 LayoutRectOutsets LayoutBox::ComputeVisualEffectOverflowOutsets() {
6824   NOT_DESTROYED();
6825   const ComputedStyle& style = StyleRef();
6826   DCHECK(style.HasVisualOverflowingEffect());
6827 
6828   LayoutRectOutsets outsets = style.BoxDecorationOutsets();
6829 
6830   if (style.HasOutline()) {
6831     Vector<PhysicalRect> outline_rects = OutlineRects(
6832         PhysicalOffset(), OutlineRectsShouldIncludeBlockVisualOverflow());
6833     PhysicalRect rect = UnionRect(outline_rects);
6834     bool outline_affected = rect.size != PhysicalSizeToBeNoop(Size());
6835     SetOutlineMayBeAffectedByDescendants(outline_affected);
6836     rect.Inflate(LayoutUnit(style.OutlineOutsetExtent()));
6837     outsets.Unite(LayoutRectOutsets(-rect.Y(), rect.Right() - Size().Width(),
6838                                     rect.Bottom() - Size().Height(),
6839                                     -rect.X()));
6840   }
6841 
6842   return outsets;
6843 }
6844 
AddVisualOverflowFromChild(const LayoutBox & child,const LayoutSize & delta)6845 void LayoutBox::AddVisualOverflowFromChild(const LayoutBox& child,
6846                                            const LayoutSize& delta) {
6847   NOT_DESTROYED();
6848   // Never allow flow threads to propagate overflow up to a parent.
6849   if (child.IsLayoutFlowThread())
6850     return;
6851 
6852   // Add in visual overflow from the child.  Even if the child clips its
6853   // overflow, it may still have visual overflow of its own set from box shadows
6854   // or reflections. It is unnecessary to propagate this overflow if we are
6855   // clipping our own overflow.
6856   if (child.HasSelfPaintingLayer())
6857     return;
6858   LayoutRect child_visual_overflow_rect =
6859       child.VisualOverflowRectForPropagation();
6860   child_visual_overflow_rect.Move(delta);
6861   AddContentsVisualOverflow(child_visual_overflow_rect);
6862 }
6863 
6864 DISABLE_CFI_PERF
AddLayoutOverflowFromChild(const LayoutBox & child,const LayoutSize & delta)6865 void LayoutBox::AddLayoutOverflowFromChild(const LayoutBox& child,
6866                                            const LayoutSize& delta) {
6867   NOT_DESTROYED();
6868   DCHECK(!ChildLayoutBlockedByDisplayLock());
6869 
6870   // Never allow flow threads to propagate overflow up to a parent.
6871   if (child.IsLayoutFlowThread())
6872     return;
6873 
6874   // Only propagate layout overflow from the child if the child isn't clipping
6875   // its overflow.  If it is, then its overflow is internal to it, and we don't
6876   // care about it. LayoutOverflowRectForPropagation takes care of this and just
6877   // propagates the border box rect instead.
6878   LayoutRect child_layout_overflow_rect =
6879       child.LayoutOverflowRectForPropagation(this);
6880   child_layout_overflow_rect.Move(delta);
6881   AddLayoutOverflow(child_layout_overflow_rect);
6882 }
6883 
SetLayoutClientAfterEdge(LayoutUnit client_after_edge)6884 void LayoutBox::SetLayoutClientAfterEdge(LayoutUnit client_after_edge) {
6885   NOT_DESTROYED();
6886   if (LayoutOverflowIsSet())
6887     overflow_->layout_overflow->SetLayoutClientAfterEdge(client_after_edge);
6888 }
6889 
LayoutClientAfterEdge() const6890 LayoutUnit LayoutBox::LayoutClientAfterEdge() const {
6891   NOT_DESTROYED();
6892   return LayoutOverflowIsSet()
6893              ? overflow_->layout_overflow->LayoutClientAfterEdge()
6894              : ClientLogicalBottom();
6895 }
6896 
PhysicalVisualOverflowRectIncludingFilters() const6897 PhysicalRect LayoutBox::PhysicalVisualOverflowRectIncludingFilters() const {
6898   NOT_DESTROYED();
6899   PhysicalRect bounds_rect = PhysicalVisualOverflowRect();
6900   if (!StyleRef().HasFilter())
6901     return bounds_rect;
6902   FloatRect float_rect = Layer()->MapRectForFilter(FloatRect(bounds_rect));
6903   float_rect.UniteIfNonZero(Layer()->FilterReferenceBox());
6904   bounds_rect = PhysicalRect::EnclosingRect(float_rect);
6905   return bounds_rect;
6906 }
6907 
HasTopOverflow() const6908 bool LayoutBox::HasTopOverflow() const {
6909   NOT_DESTROYED();
6910   return !StyleRef().IsLeftToRightDirection() && !IsHorizontalWritingMode();
6911 }
6912 
HasLeftOverflow() const6913 bool LayoutBox::HasLeftOverflow() const {
6914   NOT_DESTROYED();
6915   if (IsHorizontalWritingMode())
6916     return !StyleRef().IsLeftToRightDirection();
6917   return StyleRef().GetWritingMode() == WritingMode::kVerticalRl;
6918 }
6919 
SetLayoutOverflowFromLayoutResults()6920 void LayoutBox::SetLayoutOverflowFromLayoutResults() {
6921   NOT_DESTROYED();
6922   DCHECK(RuntimeEnabledFeatures::LayoutNGLayoutOverflowEnabled());
6923   ClearSelfNeedsLayoutOverflowRecalc();
6924   ClearChildNeedsLayoutOverflowRecalc();
6925   ClearLayoutOverflow();
6926 
6927   const WritingMode writing_mode = StyleRef().GetWritingMode();
6928   base::Optional<PhysicalRect> layout_overflow;
6929   LayoutUnit consumed_block_size;
6930 
6931   // Iterate over all the fragments and unite their individual layout-overflow
6932   // to determine the final layout-overflow.
6933   for (const auto& layout_result : layout_results_) {
6934     const auto& fragment =
6935         To<NGPhysicalBoxFragment>(layout_result->PhysicalFragment());
6936 
6937     // In order to correctly unite the overflow, we need to shift an individual
6938     // fragment's layout-overflow by previously consumed block-size so far.
6939     PhysicalOffset offset_adjust;
6940     switch (writing_mode) {
6941       case WritingMode::kHorizontalTb:
6942         offset_adjust = {LayoutUnit(), consumed_block_size};
6943         break;
6944       case WritingMode::kVerticalRl:
6945       case WritingMode::kSidewaysRl:
6946         offset_adjust = {-fragment.Size().width - consumed_block_size,
6947                          LayoutUnit()};
6948         break;
6949       case WritingMode::kVerticalLr:
6950       case WritingMode::kSidewaysLr:
6951         offset_adjust = {consumed_block_size, LayoutUnit()};
6952         break;
6953       default:
6954         NOTREACHED();
6955         break;
6956     }
6957 
6958     PhysicalRect fragment_layout_overflow = fragment.LayoutOverflow();
6959     fragment_layout_overflow.offset += offset_adjust;
6960 
6961     // If we are the first fragment just set the layout-overflow.
6962     if (!layout_overflow)
6963       layout_overflow = fragment_layout_overflow;
6964     else
6965       layout_overflow->UniteEvenIfEmpty(fragment_layout_overflow);
6966 
6967     if (const auto* break_token = fragment.BreakToken()) {
6968       consumed_block_size =
6969           To<NGBlockBreakToken>(break_token)->ConsumedBlockSize();
6970     }
6971   }
6972 
6973   if (!layout_overflow)
6974     return;
6975 
6976   // layout-overflow is stored respecting flipped-blocks.
6977   if (IsFlippedBlocksWritingMode(writing_mode)) {
6978     layout_overflow->offset.left =
6979         -layout_overflow->offset.left - layout_overflow->size.width;
6980   }
6981 
6982   if (layout_overflow->IsEmpty() ||
6983       PhysicalPaddingBoxRect().Contains(*layout_overflow))
6984     return;
6985 
6986   DCHECK(!LayoutOverflowIsSet());
6987   if (!overflow_)
6988     overflow_ = std::make_unique<BoxOverflowModel>();
6989   overflow_->layout_overflow.emplace(layout_overflow->ToLayoutRect());
6990 }
6991 
6992 DISABLE_CFI_PERF
AddLayoutOverflow(const LayoutRect & rect)6993 void LayoutBox::AddLayoutOverflow(const LayoutRect& rect) {
6994   NOT_DESTROYED();
6995   if (rect.IsEmpty())
6996     return;
6997 
6998   LayoutRect client_box = NoOverflowRect();
6999   if (client_box.Contains(rect))
7000     return;
7001 
7002   // For overflow clip objects, we don't want to propagate overflow into
7003   // unreachable areas.
7004   LayoutRect overflow_rect(rect);
7005   if (IsScrollContainer() || IsA<LayoutView>(this)) {
7006     // Overflow is in the block's coordinate space and thus is flipped for
7007     // vertical-rl writing
7008     // mode.  At this stage that is actually a simplification, since we can
7009     // treat vertical-lr/rl
7010     // as the same.
7011     if (HasTopOverflow()) {
7012       overflow_rect.ShiftMaxYEdgeTo(
7013           std::min(overflow_rect.MaxY(), client_box.MaxY()));
7014     } else {
7015       overflow_rect.ShiftYEdgeTo(std::max(overflow_rect.Y(), client_box.Y()));
7016     }
7017     if (HasLeftOverflow() !=
7018         IsFlippedBlocksWritingMode(StyleRef().GetWritingMode())) {
7019       overflow_rect.ShiftMaxXEdgeTo(
7020           std::min(overflow_rect.MaxX(), client_box.MaxX()));
7021     } else {
7022       overflow_rect.ShiftXEdgeTo(std::max(overflow_rect.X(), client_box.X()));
7023     }
7024 
7025     // Now re-test with the adjusted rectangle and see if it has become
7026     // unreachable or fully
7027     // contained.
7028     if (client_box.Contains(overflow_rect) || overflow_rect.IsEmpty())
7029       return;
7030   }
7031 
7032   if (!LayoutOverflowIsSet()) {
7033     if (!overflow_)
7034       overflow_ = std::make_unique<BoxOverflowModel>();
7035     overflow_->layout_overflow.emplace(client_box);
7036   }
7037 
7038   overflow_->layout_overflow->AddLayoutOverflow(overflow_rect);
7039 }
7040 
AddSelfVisualOverflow(const LayoutRect & rect)7041 void LayoutBox::AddSelfVisualOverflow(const LayoutRect& rect) {
7042   NOT_DESTROYED();
7043   if (rect.IsEmpty())
7044     return;
7045 
7046   LayoutRect border_box = BorderBoxRect();
7047   if (border_box.Contains(rect))
7048     return;
7049 
7050   if (!VisualOverflowIsSet()) {
7051     if (!overflow_)
7052       overflow_ = std::make_unique<BoxOverflowModel>();
7053 
7054     overflow_->visual_overflow.emplace(border_box);
7055   }
7056 
7057   overflow_->visual_overflow->AddSelfVisualOverflow(rect);
7058 }
7059 
AddContentsVisualOverflow(const LayoutRect & rect)7060 void LayoutBox::AddContentsVisualOverflow(const LayoutRect& rect) {
7061   NOT_DESTROYED();
7062   if (rect.IsEmpty())
7063     return;
7064 
7065   // If hasOverflowClip() we always save contents visual overflow because we
7066   // need it
7067   // e.g. to determine whether to apply rounded corner clip on contents.
7068   // Otherwise we save contents visual overflow only if it overflows the border
7069   // box.
7070   LayoutRect border_box = BorderBoxRect();
7071   if (!HasNonVisibleOverflow() && border_box.Contains(rect))
7072     return;
7073 
7074   if (!VisualOverflowIsSet()) {
7075     if (!overflow_)
7076       overflow_ = std::make_unique<BoxOverflowModel>();
7077 
7078     overflow_->visual_overflow.emplace(border_box);
7079   }
7080   overflow_->visual_overflow->AddContentsVisualOverflow(rect);
7081 }
7082 
ClearLayoutOverflow()7083 void LayoutBox::ClearLayoutOverflow() {
7084   NOT_DESTROYED();
7085   if (overflow_)
7086     overflow_->layout_overflow.reset();
7087   // overflow_ will be reset by MutableForPainting::ClearPreviousOverflowData()
7088   // if we don't need it to store previous overflow data.
7089 }
7090 
ClearVisualOverflow()7091 void LayoutBox::ClearVisualOverflow() {
7092   NOT_DESTROYED();
7093   if (overflow_)
7094     overflow_->visual_overflow.reset();
7095   // overflow_ will be reset by MutableForPainting::ClearPreviousOverflowData()
7096   // if we don't need it to store previous overflow data.
7097 }
7098 
PercentageLogicalHeightIsResolvable() const7099 bool LayoutBox::PercentageLogicalHeightIsResolvable() const {
7100   NOT_DESTROYED();
7101   Length fake_length = Length::Percent(100);
7102   return ComputePercentageLogicalHeight(fake_length) != -1;
7103 }
7104 
7105 DISABLE_CFI_PERF
HasUnsplittableScrollingOverflow() const7106 bool LayoutBox::HasUnsplittableScrollingOverflow() const {
7107   NOT_DESTROYED();
7108   // We will paginate as long as we don't scroll overflow in the pagination
7109   // direction.
7110   bool is_horizontal = IsHorizontalWritingMode();
7111   if ((is_horizontal && !ScrollsOverflowY()) ||
7112       (!is_horizontal && !ScrollsOverflowX()))
7113     return false;
7114 
7115   // Fragmenting scrollbars is only problematic in interactive media, e.g.
7116   // multicol on a screen. If we're printing, which is non-interactive media, we
7117   // should allow objects with non-visible overflow to be paginated as normally.
7118   if (GetDocument().Printing())
7119     return false;
7120 
7121   // We do have overflow. We'll still be willing to paginate as long as the
7122   // block has auto logical height, auto or undefined max-logical-height and a
7123   // zero or auto min-logical-height.
7124   // Note this is just a heuristic, and it's still possible to have overflow
7125   // under these conditions, but it should work out to be good enough for common
7126   // cases. Paginating overflow with scrollbars present is not the end of the
7127   // world and is what we used to do in the old model anyway.
7128   return StyleRef().LogicalHeight().IsSpecified() ||
7129          (StyleRef().LogicalMaxHeight().IsSpecified() &&
7130           (!StyleRef().LogicalMaxHeight().IsPercentOrCalc() ||
7131            PercentageLogicalHeightIsResolvable())) ||
7132          (StyleRef().LogicalMinHeight().IsSpecified() &&
7133           (!StyleRef().LogicalMinHeight().IsPercentOrCalc() ||
7134            PercentageLogicalHeightIsResolvable()));
7135 }
7136 
GetPaginationBreakability(FragmentationEngine engine) const7137 LayoutBox::PaginationBreakability LayoutBox::GetPaginationBreakability(
7138     FragmentationEngine engine) const {
7139   NOT_DESTROYED();
7140   if (ShouldBeConsideredAsReplaced() || HasUnsplittableScrollingOverflow() ||
7141       (Parent() && IsWritingModeRoot()) ||
7142       (IsOutOfFlowPositioned() &&
7143        StyleRef().GetPosition() == EPosition::kFixed) ||
7144       ShouldApplySizeContainment() || IsFrameSet())
7145     return kForbidBreaks;
7146 
7147   if (engine != kUnknownFragmentationEngine) {
7148     // If the object isn't using the same engine as the fragmentation context,
7149     // it must be treated as monolithic.
7150     if (IsLayoutNGObject() != (engine == kNGFragmentationEngine))
7151       return kForbidBreaks;
7152   }
7153 
7154   EBreakInside break_value = BreakInside();
7155   if (break_value == EBreakInside::kAvoid ||
7156       break_value == EBreakInside::kAvoidPage ||
7157       break_value == EBreakInside::kAvoidColumn)
7158     return kAvoidBreaks;
7159   return kAllowAnyBreaks;
7160 }
7161 
LineHeight(bool,LineDirectionMode direction,LinePositionMode) const7162 LayoutUnit LayoutBox::LineHeight(bool /*firstLine*/,
7163                                  LineDirectionMode direction,
7164                                  LinePositionMode /*linePositionMode*/) const {
7165   if (IsAtomicInlineLevel()) {
7166     return direction == kHorizontalLine ? MarginHeight() + Size().Height()
7167                                         : MarginWidth() + Size().Width();
7168   }
7169   return LayoutUnit();
7170 }
7171 
7172 DISABLE_CFI_PERF
BaselinePosition(FontBaseline baseline_type,bool,LineDirectionMode direction,LinePositionMode line_position_mode) const7173 LayoutUnit LayoutBox::BaselinePosition(
7174     FontBaseline baseline_type,
7175     bool /*firstLine*/,
7176     LineDirectionMode direction,
7177     LinePositionMode line_position_mode) const {
7178   DCHECK_EQ(line_position_mode, kPositionOnContainingLine);
7179   if (IsAtomicInlineLevel()) {
7180     LayoutUnit result = direction == kHorizontalLine
7181                             ? MarginHeight() + Size().Height()
7182                             : MarginWidth() + Size().Width();
7183     if (baseline_type == kAlphabeticBaseline)
7184       return result;
7185     return result - result / 2;
7186   }
7187   return LayoutUnit();
7188 }
7189 
EnclosingFloatPaintingLayer() const7190 PaintLayer* LayoutBox::EnclosingFloatPaintingLayer() const {
7191   NOT_DESTROYED();
7192   const LayoutObject* curr = this;
7193   while (curr) {
7194     PaintLayer* layer = curr->HasLayer() && curr->IsBox()
7195                             ? To<LayoutBox>(curr)->Layer()
7196                             : nullptr;
7197     if (layer && layer->IsSelfPaintingLayer())
7198       return layer;
7199     curr = curr->Parent();
7200   }
7201   return nullptr;
7202 }
7203 
EnclosingScrollportBox() const7204 const LayoutBlock& LayoutBox::EnclosingScrollportBox() const {
7205   NOT_DESTROYED();
7206   const LayoutBlock* ancestor = ContainingBlock();
7207   for (; ancestor; ancestor = ancestor->ContainingBlock()) {
7208     if (ancestor->IsScrollContainer())
7209       return *ancestor;
7210   }
7211   NOTREACHED();
7212   return *ancestor;
7213 }
7214 
LogicalVisualOverflowRectForPropagation() const7215 LayoutRect LayoutBox::LogicalVisualOverflowRectForPropagation() const {
7216   NOT_DESTROYED();
7217   LayoutRect rect = VisualOverflowRectForPropagation();
7218   if (!Parent()->StyleRef().IsHorizontalWritingMode())
7219     return rect.TransposedRect();
7220   return rect;
7221 }
7222 
7223 DISABLE_CFI_PERF
RectForOverflowPropagation(const LayoutRect & rect) const7224 LayoutRect LayoutBox::RectForOverflowPropagation(const LayoutRect& rect) const {
7225   NOT_DESTROYED();
7226   // If the child and parent are in the same blocks direction, then we don't
7227   // have to do anything fancy. Just return the rect.
7228   if (Parent()->StyleRef().IsFlippedBlocksWritingMode() ==
7229       StyleRef().IsFlippedBlocksWritingMode())
7230     return rect;
7231 
7232   // Convert the rect into parent's blocks direction by flipping along the y
7233   // axis.
7234   LayoutRect result = rect;
7235   result.SetX(Size().Width() - rect.MaxX());
7236   return result;
7237 }
7238 
7239 DISABLE_CFI_PERF
LogicalLayoutOverflowRectForPropagation(LayoutObject * container) const7240 LayoutRect LayoutBox::LogicalLayoutOverflowRectForPropagation(
7241     LayoutObject* container) const {
7242   NOT_DESTROYED();
7243   LayoutRect rect = LayoutOverflowRectForPropagation(container);
7244   if (!Parent()->StyleRef().IsHorizontalWritingMode())
7245     return rect.TransposedRect();
7246   return rect;
7247 }
7248 
7249 DISABLE_CFI_PERF
LayoutOverflowRectForPropagation(LayoutObject * container) const7250 LayoutRect LayoutBox::LayoutOverflowRectForPropagation(
7251     LayoutObject* container) const {
7252   NOT_DESTROYED();
7253   // Only propagate interior layout overflow if we don't clip it.
7254   LayoutRect rect = BorderBoxRect();
7255 
7256   if (!ShouldApplyLayoutContainment() &&
7257       (!ShouldClipOverflowAlongBothAxis() ||
7258        StyleRef().OverflowClipMargin() != LayoutUnit())) {
7259     rect.Unite(LayoutOverflowRect());
7260   }
7261 
7262   bool has_transform = HasLayer() && Layer()->Transform();
7263   if (IsInFlowPositioned() || has_transform) {
7264     // If we are relatively positioned or if we have a transform, then we have
7265     // to convert this rectangle into physical coordinates, apply relative
7266     // positioning and transforms to it, and then convert it back.
7267     DeprecatedFlipForWritingMode(rect);
7268 
7269     PhysicalOffset container_offset;
7270 
7271     if (IsRelPositioned())
7272       container_offset = RelativePositionOffset();
7273 
7274     if (ShouldUseTransformFromContainer(container)) {
7275       TransformationMatrix t;
7276       GetTransformFromContainer(container ? container : Container(),
7277                                 container_offset, t);
7278       rect = t.MapRect(rect);
7279     } else {
7280       rect.Move(container_offset.ToLayoutSize());
7281     }
7282 
7283     // Now we need to flip back.
7284     DeprecatedFlipForWritingMode(rect);
7285   }
7286 
7287   return RectForOverflowPropagation(rect);
7288 }
7289 
7290 DISABLE_CFI_PERF
NoOverflowRect() const7291 LayoutRect LayoutBox::NoOverflowRect() const {
7292   NOT_DESTROYED();
7293   return FlipForWritingMode(PhysicalPaddingBoxRect());
7294 }
7295 
VisualOverflowRect() const7296 LayoutRect LayoutBox::VisualOverflowRect() const {
7297   NOT_DESTROYED();
7298   if (!VisualOverflowIsSet())
7299     return BorderBoxRect();
7300 
7301   const LayoutRect& self_visual_overflow_rect =
7302       overflow_->visual_overflow->SelfVisualOverflowRect();
7303   if (HasMask())
7304     return self_visual_overflow_rect;
7305 
7306   const OverflowClipAxes overflow_clip_axes = GetOverflowClipAxes();
7307   const LayoutUnit overflow_clip_margin = StyleRef().OverflowClipMargin();
7308   if (overflow_clip_margin != LayoutUnit()) {
7309     // overflow_clip_margin should only be set if 'overflow' is 'clip' along
7310     // both axis.
7311     DCHECK_EQ(overflow_clip_axes, kOverflowClipBothAxis);
7312     const LayoutRect& contents_visual_overflow_rect =
7313         overflow_->visual_overflow->ContentsVisualOverflowRect();
7314     if (!contents_visual_overflow_rect.IsEmpty()) {
7315       LayoutRect result = BorderBoxRect();
7316       result.Inflate(overflow_clip_margin);
7317       result.Intersect(contents_visual_overflow_rect);
7318       result.Unite(self_visual_overflow_rect);
7319       return result;
7320     }
7321   }
7322 
7323   if (overflow_clip_axes == kOverflowClipBothAxis)
7324     return self_visual_overflow_rect;
7325 
7326   LayoutRect result = overflow_->visual_overflow->ContentsVisualOverflowRect();
7327   result.Unite(self_visual_overflow_rect);
7328   ApplyOverflowClip(overflow_clip_axes, self_visual_overflow_rect, result);
7329   return result;
7330 }
7331 
OffsetPoint(const Element * parent) const7332 PhysicalOffset LayoutBox::OffsetPoint(const Element* parent) const {
7333   NOT_DESTROYED();
7334   return AdjustedPositionRelativeTo(PhysicalLocation(), parent);
7335 }
7336 
OffsetLeft(const Element * parent) const7337 LayoutUnit LayoutBox::OffsetLeft(const Element* parent) const {
7338   NOT_DESTROYED();
7339   return OffsetPoint(parent).left;
7340 }
7341 
OffsetTop(const Element * parent) const7342 LayoutUnit LayoutBox::OffsetTop(const Element* parent) const {
7343   NOT_DESTROYED();
7344   return OffsetPoint(parent).top;
7345 }
7346 
LocationContainer() const7347 LayoutBox* LayoutBox::LocationContainer() const {
7348   NOT_DESTROYED();
7349   // Location of a non-root SVG object derived from LayoutBox should not be
7350   // affected by writing-mode of the containing box (SVGRoot).
7351   if (IsSVGChild())
7352     return nullptr;
7353 
7354   // Normally the box's location is relative to its containing box.
7355   LayoutObject* container = Container();
7356   while (container && !container->IsBox())
7357     container = container->Container();
7358   return To<LayoutBox>(container);
7359 }
7360 
HasRelativeLogicalWidth() const7361 bool LayoutBox::HasRelativeLogicalWidth() const {
7362   NOT_DESTROYED();
7363   return StyleRef().LogicalWidth().IsPercentOrCalc() ||
7364          StyleRef().LogicalMinWidth().IsPercentOrCalc() ||
7365          StyleRef().LogicalMaxWidth().IsPercentOrCalc();
7366 }
7367 
HasRelativeLogicalHeight() const7368 bool LayoutBox::HasRelativeLogicalHeight() const {
7369   NOT_DESTROYED();
7370   return StyleRef().LogicalHeight().IsPercentOrCalc() ||
7371          StyleRef().LogicalMinHeight().IsPercentOrCalc() ||
7372          StyleRef().LogicalMaxHeight().IsPercentOrCalc();
7373 }
7374 
MarkBoxForRelayoutAfterSplit(LayoutBox * box)7375 static void MarkBoxForRelayoutAfterSplit(LayoutBox* box) {
7376   // FIXME: The table code should handle that automatically. If not,
7377   // we should fix it and remove the table part checks.
7378   if (box->IsTable()) {
7379     // Because we may have added some sections with already computed column
7380     // structures, we need to sync the table structure with them now. This
7381     // avoids crashes when adding new cells to the table.
7382     ToInterface<LayoutNGTableInterface>(box)->ForceSectionsRecalc();
7383   } else if (box->IsTableSection()) {
7384     ToInterface<LayoutNGTableSectionInterface>(box)->SetNeedsCellRecalc();
7385   }
7386 
7387   box->SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
7388       layout_invalidation_reason::kAnonymousBlockChange);
7389 }
7390 
CollapseLoneAnonymousBlockChild(LayoutBox * parent,LayoutObject * child)7391 static void CollapseLoneAnonymousBlockChild(LayoutBox* parent,
7392                                             LayoutObject* child) {
7393   auto* child_block_flow = DynamicTo<LayoutBlockFlow>(child);
7394   auto* parent_block_flow = DynamicTo<LayoutBlockFlow>(parent);
7395   if (!child->IsAnonymousBlock() || !child_block_flow)
7396     return;
7397   if (!parent_block_flow)
7398     return;
7399   parent_block_flow->CollapseAnonymousBlockChild(child_block_flow);
7400 }
7401 
SplitAnonymousBoxesAroundChild(LayoutObject * before_child)7402 LayoutObject* LayoutBox::SplitAnonymousBoxesAroundChild(
7403     LayoutObject* before_child) {
7404   NOT_DESTROYED();
7405   LayoutBox* box_at_top_of_new_branch = nullptr;
7406 
7407   while (before_child->Parent() != this) {
7408     auto* box_to_split = To<LayoutBox>(before_child->Parent());
7409     if (box_to_split->SlowFirstChild() != before_child &&
7410         box_to_split->IsAnonymous()) {
7411       // We have to split the parent box into two boxes and move children
7412       // from |beforeChild| to end into the new post box.
7413       LayoutBox* post_box =
7414           box_to_split->CreateAnonymousBoxWithSameTypeAs(this);
7415       post_box->SetChildrenInline(box_to_split->ChildrenInline());
7416       auto* parent_box = To<LayoutBox>(box_to_split->Parent());
7417       // We need to invalidate the |parentBox| before inserting the new node
7418       // so that the table paint invalidation logic knows the structure is
7419       // dirty. See for example LayoutTableCell:localVisualRect().
7420       MarkBoxForRelayoutAfterSplit(parent_box);
7421       parent_box->VirtualChildren()->InsertChildNode(
7422           parent_box, post_box, box_to_split->NextSibling());
7423       box_to_split->MoveChildrenTo(post_box, before_child, nullptr, true);
7424 
7425       LayoutObject* child = post_box->SlowFirstChild();
7426       DCHECK(child);
7427       if (child && !child->NextSibling())
7428         CollapseLoneAnonymousBlockChild(post_box, child);
7429       child = box_to_split->SlowFirstChild();
7430       DCHECK(child);
7431       if (child && !child->NextSibling())
7432         CollapseLoneAnonymousBlockChild(box_to_split, child);
7433 
7434       MarkBoxForRelayoutAfterSplit(box_to_split);
7435       MarkBoxForRelayoutAfterSplit(post_box);
7436       box_at_top_of_new_branch = post_box;
7437 
7438       before_child = post_box;
7439     } else {
7440       before_child = box_to_split;
7441     }
7442   }
7443 
7444   // Splitting the box means the left side of the container chain will lose any
7445   // percent height descendants below |boxAtTopOfNewBranch| on the right hand
7446   // side.
7447   if (box_at_top_of_new_branch) {
7448     box_at_top_of_new_branch->ClearPercentHeightDescendants();
7449     MarkBoxForRelayoutAfterSplit(this);
7450   }
7451 
7452   DCHECK_EQ(before_child->Parent(), this);
7453   return before_child;
7454 }
7455 
OffsetFromLogicalTopOfFirstPage() const7456 LayoutUnit LayoutBox::OffsetFromLogicalTopOfFirstPage() const {
7457   NOT_DESTROYED();
7458   LayoutState* layout_state = View()->GetLayoutState();
7459   if (!layout_state || !layout_state->IsPaginated())
7460     return LayoutUnit();
7461 
7462   if (layout_state->GetLayoutObject() == this) {
7463     LayoutSize offset = layout_state->PaginationOffset();
7464     return IsHorizontalWritingMode() ? offset.Height() : offset.Width();
7465   }
7466 
7467   // A LayoutBlock always establishes a layout state, and this method is only
7468   // meant to be called on the object currently being laid out.
7469   DCHECK(!IsLayoutBlock());
7470 
7471   // In case this box doesn't establish a layout state, try the containing
7472   // block.
7473   LayoutBlock* container_block = ContainingBlock();
7474   DCHECK(layout_state->GetLayoutObject() == container_block);
7475   return container_block->OffsetFromLogicalTopOfFirstPage() + LogicalTop();
7476 }
7477 
SetOffsetToNextPage(LayoutUnit offset)7478 void LayoutBox::SetOffsetToNextPage(LayoutUnit offset) {
7479   NOT_DESTROYED();
7480   if (!rare_data_ && !offset)
7481     return;
7482   EnsureRareData().offset_to_next_page_ = offset;
7483 }
7484 
LogicalExtentAfterUpdatingLogicalWidth(const LayoutUnit & new_logical_top,LayoutBox::LogicalExtentComputedValues & computed_values)7485 void LayoutBox::LogicalExtentAfterUpdatingLogicalWidth(
7486     const LayoutUnit& new_logical_top,
7487     LayoutBox::LogicalExtentComputedValues& computed_values) {
7488   NOT_DESTROYED();
7489   // FIXME: None of this is right for perpendicular writing-mode children.
7490   LayoutUnit old_logical_width = LogicalWidth();
7491   LayoutUnit old_logical_left = LogicalLeft();
7492   LayoutUnit old_margin_left = MarginLeft();
7493   LayoutUnit old_margin_right = MarginRight();
7494   LayoutUnit old_logical_top = LogicalTop();
7495 
7496   SetLogicalTop(new_logical_top);
7497   UpdateLogicalWidth();
7498 
7499   computed_values.extent_ = LogicalWidth();
7500   computed_values.position_ = LogicalLeft();
7501   computed_values.margins_.start_ = MarginStart();
7502   computed_values.margins_.end_ = MarginEnd();
7503 
7504   SetLogicalTop(old_logical_top);
7505   SetLogicalWidth(old_logical_width);
7506   SetLogicalLeft(old_logical_left);
7507   SetMarginLeft(old_margin_left);
7508   SetMarginRight(old_margin_right);
7509 }
7510 
GetShapeOutsideInfo() const7511 ShapeOutsideInfo* LayoutBox::GetShapeOutsideInfo() const {
7512   NOT_DESTROYED();
7513   return ShapeOutsideInfo::Info(*this);
7514 }
7515 
SetPercentHeightContainer(LayoutBlock * container)7516 void LayoutBox::SetPercentHeightContainer(LayoutBlock* container) {
7517   NOT_DESTROYED();
7518   DCHECK(!container || !PercentHeightContainer());
7519   if (!container && !rare_data_)
7520     return;
7521   EnsureRareData().percent_height_container_ = container;
7522 }
7523 
RemoveFromPercentHeightContainer()7524 void LayoutBox::RemoveFromPercentHeightContainer() {
7525   NOT_DESTROYED();
7526   if (!PercentHeightContainer())
7527     return;
7528 
7529   DCHECK(PercentHeightContainer()->HasPercentHeightDescendant(this));
7530   PercentHeightContainer()->RemovePercentHeightDescendant(this);
7531   // The above call should call this object's
7532   // setPercentHeightContainer(nullptr).
7533   DCHECK(!PercentHeightContainer());
7534 }
7535 
ClearPercentHeightDescendants()7536 void LayoutBox::ClearPercentHeightDescendants() {
7537   NOT_DESTROYED();
7538   for (LayoutObject* curr = SlowFirstChild(); curr;
7539        curr = curr->NextInPreOrder(this)) {
7540     if (curr->IsBox())
7541       To<LayoutBox>(curr)->RemoveFromPercentHeightContainer();
7542   }
7543 }
7544 
PageLogicalHeightForOffset(LayoutUnit offset) const7545 LayoutUnit LayoutBox::PageLogicalHeightForOffset(LayoutUnit offset) const {
7546   NOT_DESTROYED();
7547   // We need to have calculated some fragmentainer logical height (even a
7548   // tentative one will do, though) in order to tell how tall one fragmentainer
7549   // is.
7550   DCHECK(IsPageLogicalHeightKnown());
7551 
7552   LayoutView* layout_view = View();
7553   LayoutFlowThread* flow_thread = FlowThreadContainingBlock();
7554   LayoutUnit page_logical_height;
7555   if (!flow_thread) {
7556     page_logical_height = layout_view->PageLogicalHeight();
7557   } else {
7558     page_logical_height = flow_thread->PageLogicalHeightForOffset(
7559         offset + OffsetFromLogicalTopOfFirstPage());
7560   }
7561   DCHECK_GT(page_logical_height, LayoutUnit());
7562   return page_logical_height;
7563 }
7564 
IsPageLogicalHeightKnown() const7565 bool LayoutBox::IsPageLogicalHeightKnown() const {
7566   NOT_DESTROYED();
7567   if (const LayoutFlowThread* flow_thread = FlowThreadContainingBlock())
7568     return flow_thread->IsPageLogicalHeightKnown();
7569   return View()->PageLogicalHeight();
7570 }
7571 
PageRemainingLogicalHeightForOffset(LayoutUnit offset,PageBoundaryRule page_boundary_rule) const7572 LayoutUnit LayoutBox::PageRemainingLogicalHeightForOffset(
7573     LayoutUnit offset,
7574     PageBoundaryRule page_boundary_rule) const {
7575   NOT_DESTROYED();
7576   DCHECK(IsPageLogicalHeightKnown());
7577   LayoutView* layout_view = View();
7578   offset += OffsetFromLogicalTopOfFirstPage();
7579 
7580   LayoutUnit footer_height =
7581       View()->GetLayoutState()->HeightOffsetForTableFooters();
7582   LayoutFlowThread* flow_thread = FlowThreadContainingBlock();
7583   LayoutUnit remaining_height;
7584   if (!flow_thread) {
7585     LayoutUnit page_logical_height = layout_view->PageLogicalHeight();
7586     remaining_height =
7587         page_logical_height - IntMod(offset, page_logical_height);
7588     if (page_boundary_rule == kAssociateWithFormerPage) {
7589       // An offset exactly at a page boundary will act as being part of the
7590       // former page in question (i.e. no remaining space), rather than being
7591       // part of the latter (i.e. one whole page length of remaining space).
7592       remaining_height = IntMod(remaining_height, page_logical_height);
7593     }
7594   } else {
7595     remaining_height = flow_thread->PageRemainingLogicalHeightForOffset(
7596         offset, page_boundary_rule);
7597   }
7598   return remaining_height - footer_height;
7599 }
7600 
CurrentPageNumber(LayoutUnit child_logical_top) const7601 int LayoutBox::CurrentPageNumber(LayoutUnit child_logical_top) const {
7602   NOT_DESTROYED();
7603   LayoutUnit offset = OffsetFromLogicalTopOfFirstPage() + child_logical_top;
7604   return (offset / View()->PageLogicalHeight()).Floor();
7605 }
7606 
CrossesPageBoundary(LayoutUnit offset,LayoutUnit logical_height) const7607 bool LayoutBox::CrossesPageBoundary(LayoutUnit offset,
7608                                     LayoutUnit logical_height) const {
7609   NOT_DESTROYED();
7610   if (!IsPageLogicalHeightKnown())
7611     return false;
7612   return PageRemainingLogicalHeightForOffset(offset, kAssociateWithLatterPage) <
7613          logical_height;
7614 }
7615 
CalculatePaginationStrutToFitContent(LayoutUnit offset,LayoutUnit content_logical_height) const7616 LayoutUnit LayoutBox::CalculatePaginationStrutToFitContent(
7617     LayoutUnit offset,
7618     LayoutUnit content_logical_height) const {
7619   NOT_DESTROYED();
7620   LayoutUnit strut_to_next_page =
7621       PageRemainingLogicalHeightForOffset(offset, kAssociateWithLatterPage);
7622 
7623   LayoutState* layout_state = View()->GetLayoutState();
7624   strut_to_next_page += layout_state->HeightOffsetForTableFooters();
7625   // If we're inside a cell in a row that straddles a page then avoid the
7626   // repeating header group if necessary. If we're a table section we're
7627   // already accounting for it.
7628   if (!IsTableSection()) {
7629     strut_to_next_page += layout_state->HeightOffsetForTableHeaders();
7630   }
7631 
7632   LayoutUnit next_page_logical_top = offset + strut_to_next_page;
7633   if (PageLogicalHeightForOffset(next_page_logical_top) >=
7634       content_logical_height)
7635     return strut_to_next_page;  // Content fits just fine in the next page or
7636                                 // column.
7637 
7638   // Moving to the top of the next page or column doesn't result in enough space
7639   // for the content that we're trying to fit. If we're in a nested
7640   // fragmentation context, we may find enough space if we move to a column
7641   // further ahead, by effectively breaking to the next outer fragmentainer.
7642   LayoutFlowThread* flow_thread = FlowThreadContainingBlock();
7643   if (!flow_thread) {
7644     // If there's no flow thread, we're not nested. All pages have the same
7645     // height. Give up.
7646     return strut_to_next_page;
7647   }
7648   // Start searching for a suitable offset at the top of the next page or
7649   // column.
7650   LayoutUnit flow_thread_offset =
7651       OffsetFromLogicalTopOfFirstPage() + next_page_logical_top;
7652   return strut_to_next_page +
7653          flow_thread->NextLogicalTopForUnbreakableContent(
7654              flow_thread_offset, content_logical_height) -
7655          flow_thread_offset;
7656 }
7657 
SnapContainer() const7658 LayoutBox* LayoutBox::SnapContainer() const {
7659   NOT_DESTROYED();
7660   return rare_data_ ? rare_data_->snap_container_ : nullptr;
7661 }
7662 
SetSnapContainer(LayoutBox * new_container)7663 void LayoutBox::SetSnapContainer(LayoutBox* new_container) {
7664   NOT_DESTROYED();
7665   LayoutBox* old_container = SnapContainer();
7666   if (old_container == new_container)
7667     return;
7668 
7669   if (old_container)
7670     old_container->RemoveSnapArea(*this);
7671 
7672   EnsureRareData().snap_container_ = new_container;
7673 
7674   if (new_container)
7675     new_container->AddSnapArea(*this);
7676 }
7677 
ClearSnapAreas()7678 void LayoutBox::ClearSnapAreas() {
7679   NOT_DESTROYED();
7680   if (SnapAreaSet* areas = SnapAreas()) {
7681     for (auto* const snap_area : *areas)
7682       snap_area->rare_data_->snap_container_ = nullptr;
7683     areas->clear();
7684   }
7685 }
7686 
AddSnapArea(LayoutBox & snap_area)7687 void LayoutBox::AddSnapArea(LayoutBox& snap_area) {
7688   NOT_DESTROYED();
7689   EnsureRareData().EnsureSnapAreas().insert(&snap_area);
7690 }
7691 
RemoveSnapArea(const LayoutBox & snap_area)7692 void LayoutBox::RemoveSnapArea(const LayoutBox& snap_area) {
7693   NOT_DESTROYED();
7694   // const_cast is safe here because we only need to modify the type to match
7695   // the key type, and not actually mutate the object.
7696   if (rare_data_ && rare_data_->snap_areas_)
7697     rare_data_->snap_areas_->erase(const_cast<LayoutBox*>(&snap_area));
7698 }
7699 
ReassignSnapAreas(LayoutBox & new_container)7700 void LayoutBox::ReassignSnapAreas(LayoutBox& new_container) {
7701   NOT_DESTROYED();
7702   SnapAreaSet* areas = SnapAreas();
7703   if (!areas)
7704     return;
7705   for (auto* const snap_area : *areas) {
7706     snap_area->rare_data_->snap_container_ = &new_container;
7707     new_container.AddSnapArea(*snap_area);
7708   }
7709   areas->clear();
7710 }
7711 
AllowedToPropagateRecursiveScrollToParentFrame(const mojom::blink::ScrollIntoViewParamsPtr & params)7712 bool LayoutBox::AllowedToPropagateRecursiveScrollToParentFrame(
7713     const mojom::blink::ScrollIntoViewParamsPtr& params) {
7714   NOT_DESTROYED();
7715   if (!GetFrameView()->SafeToPropagateScrollToParent())
7716     return false;
7717 
7718   if (params->type != mojom::blink::ScrollType::kProgrammatic)
7719     return true;
7720 
7721   return !GetDocument().IsVerticalScrollEnforced();
7722 }
7723 
SnapAreas() const7724 SnapAreaSet* LayoutBox::SnapAreas() const {
7725   NOT_DESTROYED();
7726   return rare_data_ ? rare_data_->snap_areas_.get() : nullptr;
7727 }
7728 
GetCustomLayoutChild() const7729 CustomLayoutChild* LayoutBox::GetCustomLayoutChild() const {
7730   NOT_DESTROYED();
7731   DCHECK(rare_data_);
7732   DCHECK(rare_data_->layout_child_);
7733   return rare_data_->layout_child_.Get();
7734 }
7735 
AddCustomLayoutChildIfNeeded()7736 void LayoutBox::AddCustomLayoutChildIfNeeded() {
7737   NOT_DESTROYED();
7738   if (!IsCustomItem())
7739     return;
7740 
7741   const AtomicString& name = Parent()->StyleRef().DisplayLayoutCustomName();
7742   LayoutWorklet* worklet = LayoutWorklet::From(*GetDocument().domWindow());
7743   const CSSLayoutDefinition* definition =
7744       worklet->Proxy()->FindDefinition(name);
7745 
7746   // If there isn't a definition yet, the web developer defined layout isn't
7747   // loaded yet (or is invalid). The layout tree will get re-attached when
7748   // loaded, so don't bother creating a script representation of this node yet.
7749   if (!definition)
7750     return;
7751 
7752   EnsureRareData().layout_child_ =
7753       MakeGarbageCollected<CustomLayoutChild>(*definition, NGBlockNode(this));
7754 }
7755 
ClearCustomLayoutChild()7756 void LayoutBox::ClearCustomLayoutChild() {
7757   NOT_DESTROYED();
7758   if (!rare_data_)
7759     return;
7760 
7761   if (rare_data_->layout_child_)
7762     rare_data_->layout_child_->ClearLayoutNode();
7763 
7764   rare_data_->layout_child_ = nullptr;
7765 }
7766 
DebugRect() const7767 PhysicalRect LayoutBox::DebugRect() const {
7768   NOT_DESTROYED();
7769   return PhysicalRect(PhysicalLocation(), Size());
7770 }
7771 
ApplyOverflowClipToLayoutOverflowRect()7772 void LayoutBox::ApplyOverflowClipToLayoutOverflowRect() {
7773   NOT_DESTROYED();
7774   if (!HasNonVisibleOverflow() || IsScrollContainer() ||
7775       !LayoutOverflowIsSet()) {
7776     return;
7777   }
7778 
7779   const OverflowClipAxes overflow_clip_axes = GetOverflowClipAxes();
7780   if (overflow_clip_axes == kNoOverflowClip)
7781     return;
7782 
7783   LayoutRect no_overflow_rect = NoOverflowRect();
7784   LayoutRect overflow_rect = overflow_->layout_overflow->LayoutOverflowRect();
7785   const LayoutUnit overflow_clip_margin = StyleRef().OverflowClipMargin();
7786   if (overflow_clip_margin != LayoutUnit()) {
7787     // overflow_clip_margin should only be set if 'overflow' is 'clip' along
7788     // both axis.
7789     DCHECK_EQ(overflow_clip_axes, kOverflowClipBothAxis);
7790     no_overflow_rect.Inflate(overflow_clip_margin);
7791     overflow_rect.Intersect(no_overflow_rect);
7792   } else {
7793     ApplyOverflowClip(overflow_clip_axes, no_overflow_rect, overflow_rect);
7794   }
7795   overflow_->layout_overflow->SetLayoutOverflow(overflow_rect);
7796 }
7797 
ComputeOverflowClipAxes() const7798 OverflowClipAxes LayoutBox::ComputeOverflowClipAxes() const {
7799   NOT_DESTROYED();
7800   if (ShouldApplyPaintContainment() || HasControlClip())
7801     return kOverflowClipBothAxis;
7802   if (!HasNonVisibleOverflow())
7803     return kNoOverflowClip;
7804   if (IsScrollContainer())
7805     return kOverflowClipBothAxis;
7806   return (StyleRef().OverflowX() == EOverflow::kVisible ? kNoOverflowClip
7807                                                         : kOverflowClipX) |
7808          (StyleRef().OverflowY() == EOverflow::kVisible ? kNoOverflowClip
7809                                                         : kOverflowClipY);
7810 }
7811 
SavePreviousOverflowData()7812 void LayoutBox::MutableForPainting::SavePreviousOverflowData() {
7813   if (!GetLayoutBox().overflow_)
7814     GetLayoutBox().overflow_ = std::make_unique<BoxOverflowModel>();
7815   auto& previous_overflow = GetLayoutBox().overflow_->previous_overflow_data;
7816   if (!previous_overflow)
7817     previous_overflow.emplace();
7818   previous_overflow->previous_physical_layout_overflow_rect =
7819       GetLayoutBox().PhysicalLayoutOverflowRect();
7820   previous_overflow->previous_physical_visual_overflow_rect =
7821       GetLayoutBox().PhysicalVisualOverflowRect();
7822   previous_overflow->previous_physical_self_visual_overflow_rect =
7823       GetLayoutBox().PhysicalSelfVisualOverflowRect();
7824 }
7825 
SetPreviousGeometryForLayoutShiftTracking(const PhysicalOffset & paint_offset,const LayoutSize & size,const PhysicalRect & visual_overflow_rect)7826 void LayoutBox::MutableForPainting::SetPreviousGeometryForLayoutShiftTracking(
7827     const PhysicalOffset& paint_offset,
7828     const LayoutSize& size,
7829     const PhysicalRect& visual_overflow_rect) {
7830   FirstFragment().SetPaintOffset(paint_offset);
7831   GetLayoutBox().previous_size_ = size;
7832   if (PhysicalRect(PhysicalOffset(), size).Contains(visual_overflow_rect))
7833     return;
7834 
7835   if (!GetLayoutBox().overflow_)
7836     GetLayoutBox().overflow_ = std::make_unique<BoxOverflowModel>();
7837   auto& previous_overflow = GetLayoutBox().overflow_->previous_overflow_data;
7838   if (!previous_overflow)
7839     previous_overflow.emplace();
7840   previous_overflow->previous_physical_visual_overflow_rect =
7841       visual_overflow_rect;
7842   // Other previous rects don't matter because they are used for paint
7843   // invalidation and we always do full paint invalidation on reattachment.
7844 }
7845 
VisualRectOutsetForRasterEffects() const7846 RasterEffectOutset LayoutBox::VisualRectOutsetForRasterEffects() const {
7847   NOT_DESTROYED();
7848   // If the box has subpixel visual effect outsets, as the visual effect may be
7849   // painted along the pixel-snapped border box, the pixels on the anti-aliased
7850   // edge of the effect may overflow the calculated visual rect. Expand visual
7851   // rect by one pixel in the case.
7852   return VisualOverflowIsSet() &&
7853                  overflow_->visual_overflow->HasSubpixelVisualEffectOutsets()
7854              ? RasterEffectOutset::kWholePixel
7855              : RasterEffectOutset::kNone;
7856 }
7857 
ResolvedDirection() const7858 TextDirection LayoutBox::ResolvedDirection() const {
7859   NOT_DESTROYED();
7860   if (IsInline() && IsAtomicInlineLevel()) {
7861     if (IsInLayoutNGInlineFormattingContext()) {
7862       NGInlineCursor cursor;
7863       cursor.MoveTo(*this);
7864       if (cursor)
7865         return cursor.Current().ResolvedDirection();
7866     }
7867     if (InlineBoxWrapper())
7868       return InlineBoxWrapper()->Direction();
7869   }
7870   return StyleRef().Direction();
7871 }
7872 
NeedsScrollNode(CompositingReasons direct_compositing_reasons) const7873 bool LayoutBox::NeedsScrollNode(
7874     CompositingReasons direct_compositing_reasons) const {
7875   NOT_DESTROYED();
7876   if (!IsScrollContainer())
7877     return false;
7878 
7879   if (direct_compositing_reasons & CompositingReason::kRootScroller)
7880     return true;
7881 
7882   return GetScrollableArea()->ScrollsOverflow();
7883 }
7884 
OverrideTickmarks(Vector<IntRect> tickmarks)7885 void LayoutBox::OverrideTickmarks(Vector<IntRect> tickmarks) {
7886   NOT_DESTROYED();
7887   GetScrollableArea()->SetTickmarksOverride(std::move(tickmarks));
7888   InvalidatePaintForTickmarks();
7889 }
7890 
InvalidatePaintForTickmarks()7891 void LayoutBox::InvalidatePaintForTickmarks() {
7892   NOT_DESTROYED();
7893   ScrollableArea* scrollable_area = GetScrollableArea();
7894   if (!scrollable_area)
7895     return;
7896   Scrollbar* scrollbar = scrollable_area->VerticalScrollbar();
7897   if (!scrollbar)
7898     return;
7899   scrollbar->SetNeedsPaintInvalidation(static_cast<ScrollbarPart>(~kThumbPart));
7900 }
7901 
7902 }  // namespace blink
7903