1 /*
2  * Copyright (C) 2011 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "third_party/blink/renderer/core/layout/layout_grid.h"
27 
28 #include <algorithm>
29 #include <memory>
30 #include <utility>
31 
32 #include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
33 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
34 #include "third_party/blink/renderer/core/layout/grid_layout_utils.h"
35 #include "third_party/blink/renderer/core/layout/layout_state.h"
36 #include "third_party/blink/renderer/core/layout/text_autosizer.h"
37 #include "third_party/blink/renderer/core/paint/block_painter.h"
38 #include "third_party/blink/renderer/core/paint/paint_layer.h"
39 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
40 #include "third_party/blink/renderer/core/style/computed_style.h"
41 #include "third_party/blink/renderer/core/style/grid_area.h"
42 #include "third_party/blink/renderer/platform/geometry/length_functions.h"
43 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
44 #include "third_party/blink/renderer/platform/text/writing_mode.h"
45 
46 namespace blink {
47 
LayoutGrid(Element * element)48 LayoutGrid::LayoutGrid(Element* element)
49     : LayoutBlock(element),
50       grid_(Grid::Create(this)),
51       track_sizing_algorithm_(this, *grid_) {
52   DCHECK(!ChildrenInline());
53 }
54 
55 LayoutGrid::~LayoutGrid() = default;
56 
CreateAnonymous(Document * document)57 LayoutGrid* LayoutGrid::CreateAnonymous(Document* document) {
58   LayoutGrid* layout_grid = new LayoutGrid(nullptr);
59   layout_grid->SetDocumentForAnonymous(document);
60   return layout_grid;
61 }
62 
AddChild(LayoutObject * new_child,LayoutObject * before_child)63 void LayoutGrid::AddChild(LayoutObject* new_child, LayoutObject* before_child) {
64   NOT_DESTROYED();
65   LayoutBlock::AddChild(new_child, before_child);
66 
67   // Positioned grid items do not take up space or otherwise participate in the
68   // layout of the grid, for that reason we don't need to mark the grid as dirty
69   // when they are added.
70   if (new_child->IsOutOfFlowPositioned())
71     return;
72 
73   // The grid needs to be recomputed as it might contain auto-placed items that
74   // will change their position.
75   DirtyGrid();
76 }
77 
RemoveChild(LayoutObject * child)78 void LayoutGrid::RemoveChild(LayoutObject* child) {
79   NOT_DESTROYED();
80   LayoutBlock::RemoveChild(child);
81 
82   // Positioned grid items do not take up space or otherwise participate in the
83   // layout of the grid, for that reason we don't need to mark the grid as dirty
84   // when they are removed.
85   if (child->IsOutOfFlowPositioned())
86     return;
87 
88   // The grid needs to be recomputed as it might contain auto-placed items that
89   // will change their position.
90   DirtyGrid();
91 }
92 
SelfAlignmentForChild(GridAxis axis,const LayoutBox & child,const ComputedStyle * style) const93 StyleSelfAlignmentData LayoutGrid::SelfAlignmentForChild(
94     GridAxis axis,
95     const LayoutBox& child,
96     const ComputedStyle* style) const {
97   NOT_DESTROYED();
98   return axis == kGridRowAxis ? JustifySelfForChild(child, style)
99                               : AlignSelfForChild(child, style);
100 }
101 
DefaultAlignment(GridAxis axis,const ComputedStyle & style) const102 StyleSelfAlignmentData LayoutGrid::DefaultAlignment(
103     GridAxis axis,
104     const ComputedStyle& style) const {
105   NOT_DESTROYED();
106   return axis == kGridRowAxis
107              ? style.ResolvedJustifyItems(ItemPosition::kNormal)
108              : style.ResolvedAlignItems(ItemPosition::kNormal);
109 }
110 
DefaultAlignmentIsStretchOrNormal(GridAxis axis,const ComputedStyle & style) const111 bool LayoutGrid::DefaultAlignmentIsStretchOrNormal(
112     GridAxis axis,
113     const ComputedStyle& style) const {
114   NOT_DESTROYED();
115   ItemPosition alignment = DefaultAlignment(axis, style).GetPosition();
116   return alignment == ItemPosition::kStretch ||
117          alignment == ItemPosition::kNormal;
118 }
119 
SelfAlignmentChangedSize(GridAxis axis,const ComputedStyle & old_style,const ComputedStyle & new_style,const LayoutBox & child) const120 bool LayoutGrid::SelfAlignmentChangedSize(GridAxis axis,
121                                           const ComputedStyle& old_style,
122                                           const ComputedStyle& new_style,
123                                           const LayoutBox& child) const {
124   NOT_DESTROYED();
125   return SelfAlignmentForChild(axis, child, &old_style).GetPosition() ==
126                  ItemPosition::kStretch
127              ? SelfAlignmentForChild(axis, child, &new_style).GetPosition() !=
128                    ItemPosition::kStretch
129              : SelfAlignmentForChild(axis, child, &new_style).GetPosition() ==
130                    ItemPosition::kStretch;
131 }
132 
DefaultAlignmentChangedSize(GridAxis axis,const ComputedStyle & old_style,const ComputedStyle & new_style) const133 bool LayoutGrid::DefaultAlignmentChangedSize(
134     GridAxis axis,
135     const ComputedStyle& old_style,
136     const ComputedStyle& new_style) const {
137   NOT_DESTROYED();
138   return DefaultAlignmentIsStretchOrNormal(axis, old_style)
139              ? DefaultAlignment(axis, old_style).GetPosition() !=
140                    DefaultAlignment(axis, new_style).GetPosition()
141              : DefaultAlignmentIsStretchOrNormal(axis, new_style);
142 }
143 
StyleDidChange(StyleDifference diff,const ComputedStyle * old_style)144 void LayoutGrid::StyleDidChange(StyleDifference diff,
145                                 const ComputedStyle* old_style) {
146   NOT_DESTROYED();
147   LayoutBlock::StyleDidChange(diff, old_style);
148   if (!old_style)
149     return;
150 
151   const ComputedStyle& new_style = StyleRef();
152   if (diff.NeedsFullLayout() &&
153       (DefaultAlignmentChangedSize(kGridRowAxis, *old_style, new_style) ||
154        DefaultAlignmentChangedSize(kGridColumnAxis, *old_style, new_style))) {
155     // Style changes on the grid container implying stretching (to-stretch) or
156     // shrinking (from-stretch) require the affected items to be laid out again.
157     // These logic only applies to 'stretch' since the rest of the alignment
158     // values don't change the size of the box.
159     // In any case, the items' overrideSize will be cleared and recomputed (if
160     // necessary)  as part of the Grid layout logic, triggered by this style
161     // change.
162     for (LayoutBox* child = FirstInFlowChildBox(); child;
163          child = child->NextInFlowSiblingBox()) {
164       if (SelfAlignmentChangedSize(kGridRowAxis, *old_style, new_style,
165                                    *child) ||
166           SelfAlignmentChangedSize(kGridColumnAxis, *old_style, new_style,
167                                    *child)) {
168         child->SetNeedsLayout(layout_invalidation_reason::kGridChanged);
169       }
170     }
171   }
172 
173   // FIXME: The following checks could be narrowed down if we kept track of
174   // which type of grid items we have:
175   // - explicit grid size changes impact negative explicitely positioned and
176   //   auto-placed grid items.
177   // - named grid lines only impact grid items with named grid lines.
178   // - auto-flow changes only impacts auto-placed children.
179 
180   if (ExplicitGridDidResize(*old_style) ||
181       NamedGridLinesDefinitionDidChange(*old_style) ||
182       old_style->GetGridAutoFlow() != StyleRef().GetGridAutoFlow() ||
183       (diff.NeedsLayout() && (StyleRef().GridAutoRepeatColumns().size() ||
184                               StyleRef().GridAutoRepeatRows().size())))
185     DirtyGrid();
186 }
187 
ExplicitGridDidResize(const ComputedStyle & old_style) const188 bool LayoutGrid::ExplicitGridDidResize(const ComputedStyle& old_style) const {
189   NOT_DESTROYED();
190   return old_style.GridTemplateColumns().LegacyTrackList().size() !=
191              StyleRef().GridTemplateColumns().LegacyTrackList().size() ||
192          old_style.GridTemplateRows().LegacyTrackList().size() !=
193              StyleRef().GridTemplateRows().LegacyTrackList().size() ||
194          old_style.NamedGridAreaColumnCount() !=
195              StyleRef().NamedGridAreaColumnCount() ||
196          old_style.NamedGridAreaRowCount() !=
197              StyleRef().NamedGridAreaRowCount() ||
198          old_style.GridAutoRepeatColumns().size() !=
199              StyleRef().GridAutoRepeatColumns().size() ||
200          old_style.GridAutoRepeatRows().size() !=
201              StyleRef().GridAutoRepeatRows().size();
202 }
203 
NamedGridLinesDefinitionDidChange(const ComputedStyle & old_style) const204 bool LayoutGrid::NamedGridLinesDefinitionDidChange(
205     const ComputedStyle& old_style) const {
206   NOT_DESTROYED();
207   return old_style.NamedGridRowLines() != StyleRef().NamedGridRowLines() ||
208          old_style.NamedGridColumnLines() !=
209              StyleRef().NamedGridColumnLines() ||
210          old_style.ImplicitNamedGridRowLines() !=
211              StyleRef().ImplicitNamedGridRowLines() ||
212          old_style.ImplicitNamedGridColumnLines() !=
213              StyleRef().ImplicitNamedGridColumnLines();
214 }
215 
ComputeTrackSizesForDefiniteSize(GridTrackSizingDirection direction,LayoutUnit available_space)216 void LayoutGrid::ComputeTrackSizesForDefiniteSize(
217     GridTrackSizingDirection direction,
218     LayoutUnit available_space) {
219   NOT_DESTROYED();
220   track_sizing_algorithm_.Setup(direction, NumTracks(direction, *grid_),
221                                 available_space);
222   track_sizing_algorithm_.Run();
223 
224 #if DCHECK_IS_ON()
225   DCHECK(track_sizing_algorithm_.TracksAreWiderThanMinTrackBreadth());
226 #endif
227 }
228 
RepeatTracksSizingIfNeeded(LayoutUnit available_space_for_columns,LayoutUnit available_space_for_rows)229 void LayoutGrid::RepeatTracksSizingIfNeeded(
230     LayoutUnit available_space_for_columns,
231     LayoutUnit available_space_for_rows) {
232   NOT_DESTROYED();
233   // In orthogonal flow cases column track's size is determined by using the
234   // computed row track's size, which it was estimated during the first cycle of
235   // the sizing algorithm.
236   // TODO (lajava): these are just some of the cases which may require
237   // a new cycle of the sizing algorithm; there may be more. In addition, not
238   // all the cases with orthogonal flows require this extra cycle; we need a
239   // more specific condition to detect whether child's min-content contribution
240   // has changed or not.
241   if (!has_any_orthogonal_item_ &&
242       !track_sizing_algorithm_.HasAnyPercentSizedRowsIndefiniteHeight())
243     return;
244 
245   // TODO (lajava): Whenever the min-content contribution of a grid item changes
246   // we may need to update the grid container's intrinsic width. The new
247   // intrinsic width may also affect the extra Track Sizing algorithm cycles we
248   // are about to execute.
249   // https://crbug.com/704713
250   // https://github.com/w3c/csswg-drafts/issues/1039
251 
252   // Hence we need to repeat computeUsedBreadthOfGridTracks for both, columns
253   // and rows, to determine the final values.
254   ComputeTrackSizesForDefiniteSize(kForColumns, available_space_for_columns);
255   ComputeContentPositionAndDistributionOffset(
256       kForColumns, track_sizing_algorithm_.FreeSpace(kForColumns).value(),
257       NonCollapsedTracks(kForColumns));
258   ComputeTrackSizesForDefiniteSize(kForRows, available_space_for_rows);
259   ComputeContentPositionAndDistributionOffset(
260       kForRows, track_sizing_algorithm_.FreeSpace(kForRows).value(),
261       NonCollapsedTracks(kForRows));
262 }
263 
UpdateBlockLayout(bool relayout_children)264 void LayoutGrid::UpdateBlockLayout(bool relayout_children) {
265   NOT_DESTROYED();
266   DCHECK(NeedsLayout());
267 
268   // We cannot perform a |SimplifiedLayout()| with a dirty grid.
269   if (!relayout_children && !grid_->NeedsItemsPlacement() && SimplifiedLayout())
270     return;
271 
272   SubtreeLayoutScope layout_scope(*this);
273 
274   PaintLayerScrollableArea::DelayScrollOffsetClampScope delay_clamp_scope;
275 
276   {
277     // LayoutState needs this deliberate scope to pop before updating scroll
278     // information (which may trigger relayout).
279     LayoutState state(*this);
280 
281     LayoutSize previous_size = Size();
282     has_definite_logical_height_ = HasDefiniteLogicalHeight();
283 
284     has_any_orthogonal_item_ = false;
285     for (auto* child = FirstInFlowChildBox(); child;
286          child = child->NextInFlowSiblingBox()) {
287       // Grid's layout logic controls the grid item's override height, hence
288       // we need to clear any override height set previously, so it doesn't
289       // interfere in current layout execution.
290       // Grid never uses the override width, that's why we don't need to clear
291       // it.
292       child->ClearOverrideLogicalHeight();
293 
294       // We may need to repeat the track sizing in case of any grid item was
295       // orthogonal.
296       if (GridLayoutUtils::IsOrthogonalChild(*this, *child))
297         has_any_orthogonal_item_ = true;
298 
299       // We keep a cache of items with baseline as alignment values so
300       // that we only compute the baseline shims for such items. This
301       // cache is needed for performance related reasons due to the
302       // cost of evaluating the item's participation in a baseline
303       // context during the track sizing algorithm.
304       if (IsBaselineAlignmentForChild(*child, kGridColumnAxis)) {
305         track_sizing_algorithm_.CacheBaselineAlignedItem(*child,
306                                                          kGridColumnAxis);
307       }
308       if (IsBaselineAlignmentForChild(*child, kGridRowAxis)) {
309         track_sizing_algorithm_.CacheBaselineAlignedItem(*child, kGridRowAxis);
310       }
311     }
312     baseline_items_cached_ = true;
313     UpdateLogicalWidth();
314 
315     TextAutosizer::LayoutScope text_autosizer_layout_scope(this, &layout_scope);
316 
317     LayoutUnit available_space_for_columns = AvailableLogicalWidth();
318     PlaceItemsOnGrid(track_sizing_algorithm_, available_space_for_columns);
319 
320     track_sizing_algorithm_.SetAvailableSpace(kForColumns,
321                                               available_space_for_columns);
322     PerformGridItemsPreLayout(track_sizing_algorithm_);
323 
324     // 1- First, the track sizing algorithm is used to resolve the sizes of the
325     // grid columns.
326     // At this point the logical width is always definite as the above call to
327     // updateLogicalWidth() properly resolves intrinsic sizes. We cannot do the
328     // same for heights though because many code paths inside
329     // updateLogicalHeight() require a previous call to setLogicalHeight() to
330     // resolve heights properly (like for positioned items for example).
331     ComputeTrackSizesForDefiniteSize(kForColumns, available_space_for_columns);
332 
333     // 1.5- Compute Content Distribution offsets for column tracks
334     ComputeContentPositionAndDistributionOffset(
335         kForColumns, track_sizing_algorithm_.FreeSpace(kForColumns).value(),
336         NonCollapsedTracks(kForColumns));
337 
338     // 2- Next, the track sizing algorithm resolves the sizes of the grid rows,
339     // using the grid column sizes calculated in the previous step.
340     bool recompute_with_track_based_height = false;
341     if (CachedHasDefiniteLogicalHeight()) {
342       ComputeTrackSizesForDefiniteSize(
343           kForRows, AvailableLogicalHeight(kExcludeMarginBorderPadding));
344     } else if (HasOverrideIntrinsicContentLogicalHeight()) {
345       ComputeTrackSizesForDefiniteSize(kForRows,
346                                        OverrideIntrinsicContentLogicalHeight());
347     } else {
348       ComputeTrackSizesForIndefiniteSize(track_sizing_algorithm_, kForRows);
349       if (ShouldApplySizeContainment())
350         recompute_with_track_based_height = true;
351     }
352     LayoutUnit track_based_logical_height =
353         track_sizing_algorithm_.ComputeTrackBasedSize() +
354         BorderAndPaddingLogicalHeight();
355     if (recompute_with_track_based_height)
356       ComputeTrackSizesForDefiniteSize(kForRows, track_based_logical_height);
357 
358     // TODO(rego): We shouldn't need this once crbug.com/906530 is fixed.
359     // Right now we need this because
360     // LayoutBox::ComputeContentAndScrollbarLogicalHeightUsing() is adding the
361     // ScrollbarLogicalHeight() for the intrinsic height cases. But that's
362     // causing more problems as described in the bug linked before.
363     if (!StyleRef().LogicalHeight().IsContentOrIntrinsic())
364       track_based_logical_height += ComputeLogicalScrollbars().BlockSum();
365 
366     SetLogicalHeight(track_based_logical_height);
367     UpdateLogicalHeight();
368 
369     // Once grid's indefinite height is resolved, we can compute the
370     // available free space for Content Alignment.
371     if (!CachedHasDefiniteLogicalHeight()) {
372       track_sizing_algorithm_.SetFreeSpace(
373           kForRows, LogicalHeight() - track_based_logical_height);
374     }
375 
376     // 2.5- Compute Content Distribution offsets for rows tracks
377     ComputeContentPositionAndDistributionOffset(
378         kForRows, track_sizing_algorithm_.FreeSpace(kForRows).value(),
379         NonCollapsedTracks(kForRows));
380 
381     // 3- If the min-content contribution of any grid items have changed based
382     // on the row sizes calculated in step 2, steps 1 and 2 are repeated with
383     // the new min-content contribution (once only).
384     RepeatTracksSizingIfNeeded(available_space_for_columns,
385                                ContentLogicalHeight());
386 
387     // Grid container should have the minimum height of a line if it's editable.
388     // That doesn't affect track sizing though.
389     if (HasLineIfEmpty())
390       SetLogicalHeight(
391           std::max(LogicalHeight(), MinimumLogicalHeightForEmptyLine()));
392 
393     LayoutGridItems();
394     track_sizing_algorithm_.Reset();
395 
396     if (NumTracks(kForRows, *grid_) > 1u && StyleRef().RowGap() &&
397         StyleRef().RowGap()->IsPercentOrCalc()) {
398       UseCounter::Count(GetDocument(), WebFeature::kGridRowGapPercent);
399       if (!CachedHasDefiniteLogicalHeight()) {
400         UseCounter::Count(GetDocument(),
401                           WebFeature::kGridRowGapPercentIndefinite);
402       }
403     }
404 
405     if (Size() != previous_size)
406       relayout_children = true;
407 
408     LayoutPositionedObjects(relayout_children || IsDocumentElement());
409 
410     ComputeLayoutOverflow(ClientLogicalBottom());
411   }
412 
413   UpdateAfterLayout();
414 
415   ClearNeedsLayout();
416 
417   track_sizing_algorithm_.ClearBaselineItemsCache();
418   baseline_items_cached_ = false;
419 }
420 
GridGap(GridTrackSizingDirection direction,base::Optional<LayoutUnit> available_size) const421 LayoutUnit LayoutGrid::GridGap(
422     GridTrackSizingDirection direction,
423     base::Optional<LayoutUnit> available_size) const {
424   NOT_DESTROYED();
425   const base::Optional<Length>& gap =
426       direction == kForColumns ? StyleRef().ColumnGap() : StyleRef().RowGap();
427   if (!gap)
428     return LayoutUnit();
429 
430   return ValueForLength(*gap, available_size.value_or(LayoutUnit()));
431 }
432 
GridGap(GridTrackSizingDirection direction) const433 LayoutUnit LayoutGrid::GridGap(GridTrackSizingDirection direction) const {
434   NOT_DESTROYED();
435   LayoutUnit available_size;
436   bool is_row_axis = direction == kForColumns;
437 
438   const base::Optional<Length>& gap =
439       is_row_axis ? StyleRef().ColumnGap() : StyleRef().RowGap();
440   if (!gap)
441     return LayoutUnit();
442 
443   if (gap->IsPercentOrCalc()) {
444     available_size =
445         is_row_axis ? AvailableLogicalWidth() : ContentLogicalHeight();
446   }
447 
448   // TODO(rego): Maybe we could cache the computed percentage as a performance
449   // improvement.
450   return ValueForLength(*gap, available_size);
451 }
452 
GuttersSize(const Grid & grid,GridTrackSizingDirection direction,size_t start_line,size_t span,base::Optional<LayoutUnit> available_size) const453 LayoutUnit LayoutGrid::GuttersSize(
454     const Grid& grid,
455     GridTrackSizingDirection direction,
456     size_t start_line,
457     size_t span,
458     base::Optional<LayoutUnit> available_size) const {
459   NOT_DESTROYED();
460   if (span <= 1)
461     return LayoutUnit();
462 
463   LayoutUnit gap = GridGap(direction, available_size);
464 
465   // Fast path, no collapsing tracks.
466   if (!grid.HasAutoRepeatEmptyTracks(direction))
467     return gap * (span - 1);
468 
469   // If there are collapsing tracks we need to be sure that gutters are properly
470   // collapsed. Apart from that, if we have a collapsed track in the edges of
471   // the span we're considering, we need to move forward (or backwards) in order
472   // to know whether the collapsed tracks reach the end of the grid (so the gap
473   // becomes 0) or there is a non empty track before that.
474 
475   LayoutUnit gap_accumulator;
476   size_t end_line = start_line + span;
477 
478   for (size_t line = start_line; line < end_line - 1; ++line) {
479     if (!grid.IsEmptyAutoRepeatTrack(direction, line))
480       gap_accumulator += gap;
481   }
482 
483   // The above loop adds one extra gap for trailing collapsed tracks.
484   if (gap_accumulator && grid.IsEmptyAutoRepeatTrack(direction, end_line - 1)) {
485     DCHECK_GE(gap_accumulator, gap);
486     gap_accumulator -= gap;
487   }
488 
489   // If the startLine is the start line of a collapsed track we need to go
490   // backwards till we reach a non collapsed track. If we find a non collapsed
491   // track we need to add that gap.
492   size_t non_empty_tracks_before_start_line = 0;
493   if (start_line && grid.IsEmptyAutoRepeatTrack(direction, start_line)) {
494     non_empty_tracks_before_start_line = start_line;
495     auto begin = grid.AutoRepeatEmptyTracks(direction)->begin();
496     for (auto it = begin; *it != start_line; ++it) {
497       DCHECK(non_empty_tracks_before_start_line);
498       --non_empty_tracks_before_start_line;
499     }
500     if (non_empty_tracks_before_start_line)
501       gap_accumulator += gap;
502   }
503 
504   // If the endLine is the end line of a collapsed track we need to go forward
505   // till we reach a non collapsed track. If we find a non collapsed track we
506   // need to add that gap.
507   if (grid.IsEmptyAutoRepeatTrack(direction, end_line - 1)) {
508     size_t non_empty_tracks_after_end_line =
509         grid.NumTracks(direction) - end_line;
510     auto current_empty_track =
511         grid.AutoRepeatEmptyTracks(direction)->find(end_line - 1);
512     auto end_empty_track = grid.AutoRepeatEmptyTracks(direction)->end();
513     // HashSet iterators do not implement operator- so we have to manually
514     // iterate to know the number of remaining empty tracks.
515     for (auto it = ++current_empty_track; it != end_empty_track; ++it) {
516       DCHECK(non_empty_tracks_after_end_line);
517       --non_empty_tracks_after_end_line;
518     }
519     if (non_empty_tracks_after_end_line) {
520       // We shouldn't count the gap twice if the span starts and ends
521       // in a collapsed track bewtween two non-empty tracks.
522       if (!non_empty_tracks_before_start_line)
523         gap_accumulator += gap;
524     } else if (non_empty_tracks_before_start_line) {
525       // We shouldn't count the gap if the the span starts and ends in
526       // a collapsed but there isn't non-empty tracks afterwards (it's
527       // at the end of the grid).
528       gap_accumulator -= gap;
529     }
530   }
531 
532   return gap_accumulator;
533 }
534 
ComputeIntrinsicLogicalWidths() const535 MinMaxSizes LayoutGrid::ComputeIntrinsicLogicalWidths() const {
536   NOT_DESTROYED();
537   MinMaxSizes sizes;
538   sizes +=
539       BorderAndPaddingLogicalWidth() + ComputeLogicalScrollbars().InlineSum();
540 
541   if (HasOverrideIntrinsicContentLogicalWidth()) {
542     sizes += OverrideIntrinsicContentLogicalWidth();
543     return sizes;
544   }
545 
546   std::unique_ptr<Grid> grid = Grid::Create(this);
547   GridTrackSizingAlgorithm algorithm(this, *grid);
548   PlaceItemsOnGrid(algorithm, base::nullopt);
549 
550   PerformGridItemsPreLayout(algorithm);
551 
552   if (baseline_items_cached_) {
553     algorithm.CopyBaselineItemsCache(track_sizing_algorithm_, kGridRowAxis);
554   } else {
555     for (auto* child = FirstInFlowChildBox(); child;
556          child = child->NextInFlowSiblingBox()) {
557       if (IsBaselineAlignmentForChild(*child, kGridRowAxis)) {
558         algorithm.CacheBaselineAlignedItem(*child, kGridRowAxis);
559       }
560     }
561   }
562 
563   ComputeTrackSizesForIndefiniteSize(algorithm, kForColumns);
564 
565   size_t number_of_tracks = algorithm.Tracks(kForColumns).size();
566   LayoutUnit total_gutters_size = GuttersSize(
567       algorithm.GetGrid(), kForColumns, 0, number_of_tracks, base::nullopt);
568 
569   sizes.min_size += algorithm.MinContentSize() + total_gutters_size;
570   sizes.max_size += algorithm.MaxContentSize() + total_gutters_size;
571   return sizes;
572 }
573 
ComputeTrackSizesForIndefiniteSize(GridTrackSizingAlgorithm & algo,GridTrackSizingDirection direction) const574 void LayoutGrid::ComputeTrackSizesForIndefiniteSize(
575     GridTrackSizingAlgorithm& algo,
576     GridTrackSizingDirection direction) const {
577   NOT_DESTROYED();
578   const Grid& grid = algo.GetGrid();
579   algo.Setup(direction, NumTracks(direction, grid), base::nullopt);
580   algo.Run();
581 
582 #if DCHECK_IS_ON()
583   DCHECK(algo.TracksAreWiderThanMinTrackBreadth());
584 #endif
585 }
586 
OverrideIntrinsicContentLogicalSize(GridTrackSizingDirection direction) const587 base::Optional<LayoutUnit> LayoutGrid::OverrideIntrinsicContentLogicalSize(
588     GridTrackSizingDirection direction) const {
589   NOT_DESTROYED();
590   if (direction == kForColumns && HasOverrideIntrinsicContentLogicalWidth())
591     return OverrideIntrinsicContentLogicalWidth();
592   if (direction == kForRows && HasOverrideIntrinsicContentLogicalHeight())
593     return OverrideIntrinsicContentLogicalHeight();
594   return base::nullopt;
595 }
596 
OverrideContainingBlockContentSizeForChild(const LayoutBox & child,GridTrackSizingDirection direction)597 LayoutUnit LayoutGrid::OverrideContainingBlockContentSizeForChild(
598     const LayoutBox& child,
599     GridTrackSizingDirection direction) {
600   return direction == kForColumns
601              ? child.OverrideContainingBlockContentLogicalWidth()
602              : child.OverrideContainingBlockContentLogicalHeight();
603 }
604 
605 // Unfortunately there are still many layout methods that return -1 for
606 // non-resolvable sizes. We prefer to represent them with base::nullopt.
ConvertLayoutUnitToOptional(LayoutUnit size)607 static base::Optional<LayoutUnit> ConvertLayoutUnitToOptional(LayoutUnit size) {
608   if (size == -1)
609     return base::nullopt;
610   return size;
611 }
612 
ComputeAutoRepeatTracksCount(GridTrackSizingDirection direction,base::Optional<LayoutUnit> available_size) const613 size_t LayoutGrid::ComputeAutoRepeatTracksCount(
614     GridTrackSizingDirection direction,
615     base::Optional<LayoutUnit> available_size) const {
616   NOT_DESTROYED();
617   DCHECK(!available_size || available_size.value() != -1);
618   bool is_row_axis = direction == kForColumns;
619   // Since auto-fit collapses empty tracks, and contain: size dictates that
620   // children should be ignored for the purposes of layout, we can conclude that
621   // if these conditions hold we have 0 repetitions.
622   if (ShouldApplySizeContainment() &&
623       ((is_row_axis &&
624         StyleRef().GridAutoRepeatColumnsType() == AutoRepeatType::kAutoFit) ||
625        (!is_row_axis &&
626         StyleRef().GridAutoRepeatRowsType() == AutoRepeatType::kAutoFit)))
627     return 0;
628   const auto& auto_repeat_tracks = is_row_axis
629                                        ? StyleRef().GridAutoRepeatColumns()
630                                        : StyleRef().GridAutoRepeatRows();
631   size_t auto_repeat_track_list_length = auto_repeat_tracks.size();
632 
633   if (!auto_repeat_track_list_length)
634     return 0;
635 
636   bool needs_to_fulfill_minimum_size = false;
637   if (!available_size) {
638     const Length& max_size = is_row_axis ? StyleRef().LogicalMaxWidth()
639                                          : StyleRef().LogicalMaxHeight();
640     base::Optional<LayoutUnit> containing_block_available_size;
641     LayoutUnit available_max_size = LayoutUnit();
642     if (max_size.IsSpecified()) {
643       if (max_size.IsPercentOrCalc()) {
644         containing_block_available_size =
645             is_row_axis ? ContainingBlockLogicalWidthForContent()
646                         : ContainingBlockLogicalHeightForContent(
647                               kExcludeMarginBorderPadding);
648       }
649       LayoutUnit max_size_value = ValueForLength(
650           max_size, containing_block_available_size.value_or(LayoutUnit()));
651       available_max_size =
652           is_row_axis
653               ? AdjustContentBoxLogicalWidthForBoxSizing(max_size_value)
654               : AdjustContentBoxLogicalHeightForBoxSizing(max_size_value);
655     }
656 
657     base::Optional<LayoutUnit> intrinsic_size_override =
658         OverrideIntrinsicContentLogicalSize(direction);
659 
660     const Length& min_size = is_row_axis ? StyleRef().LogicalMinWidth()
661                                          : StyleRef().LogicalMinHeight();
662     if (!available_max_size && !min_size.IsSpecified() &&
663         !intrinsic_size_override) {
664       return auto_repeat_track_list_length;
665     }
666 
667     LayoutUnit available_min_size = LayoutUnit();
668     if (min_size.IsSpecified()) {
669       if (!containing_block_available_size && min_size.IsPercentOrCalc()) {
670         containing_block_available_size =
671             is_row_axis ? ContainingBlockLogicalWidthForContent()
672                         : ContainingBlockLogicalHeightForContent(
673                               kExcludeMarginBorderPadding);
674       }
675       LayoutUnit min_size_value = ValueForLength(
676           min_size, containing_block_available_size.value_or(LayoutUnit()));
677       available_min_size =
678           is_row_axis
679               ? AdjustContentBoxLogicalWidthForBoxSizing(min_size_value)
680               : AdjustContentBoxLogicalHeightForBoxSizing(min_size_value);
681     }
682 
683     // See https://drafts.csswg.org/css-grid/#auto-repeat for explanation of why
684     // we use needs_to_fulfill_minimum_size. Note that we can treat the
685     // intrinsic-size similar to min-size when filling the remainder of space.
686     // That is, we should fill the intrinsic size fully.
687     if (!max_size.IsSpecified() &&
688         (min_size.IsSpecified() || intrinsic_size_override)) {
689       needs_to_fulfill_minimum_size = true;
690     }
691 
692     // Now we need to determine the available size.
693     // We start with the maximum of all of the values. Then, we need to see if
694     // max-size is breached. If it is, then we can shrink the size back up to
695     // the max of min-size and max-size. This is because we can ignore
696     // intrinsic-size in this situation since the min- and max- sizes take
697     // priority.
698     auto available_intrinsic_size =
699         intrinsic_size_override.value_or(LayoutUnit());
700     available_size =
701         std::max(std::max(available_min_size, available_intrinsic_size),
702                  available_max_size);
703     if (max_size.IsSpecified() && available_max_size < available_size) {
704       available_size = std::max(available_min_size, available_max_size);
705     }
706   }
707 
708   LayoutUnit auto_repeat_tracks_size;
709   for (auto auto_track_size : auto_repeat_tracks) {
710     DCHECK(auto_track_size.MinTrackBreadth().IsLength());
711     DCHECK(!auto_track_size.MinTrackBreadth().IsFlex());
712     bool has_definite_max_track_sizing_function =
713         auto_track_size.MaxTrackBreadth().IsLength() &&
714         !auto_track_size.MaxTrackBreadth().IsContentSized();
715     const Length& track_length =
716         has_definite_max_track_sizing_function
717             ? auto_track_size.MaxTrackBreadth().length()
718             : auto_track_size.MinTrackBreadth().length();
719     auto_repeat_tracks_size +=
720         ValueForLength(track_length, available_size.value());
721   }
722   // For the purpose of finding the number of auto-repeated tracks, the UA must
723   // floor the track size to a UA-specified value to avoid division by zero. It
724   // is suggested that this floor be 1px.
725   auto_repeat_tracks_size =
726       std::max<LayoutUnit>(LayoutUnit(1), auto_repeat_tracks_size);
727 
728   // There will be always at least 1 auto-repeat track, so take it already into
729   // account when computing the total track size.
730   LayoutUnit tracks_size = auto_repeat_tracks_size;
731   const Vector<GridTrackSize>& track_sizes =
732       is_row_axis ? StyleRef().GridTemplateColumns().LegacyTrackList()
733                   : StyleRef().GridTemplateRows().LegacyTrackList();
734 
735   for (const auto& track : track_sizes) {
736     bool has_definite_max_track_breadth =
737         track.MaxTrackBreadth().IsLength() &&
738         !track.MaxTrackBreadth().IsContentSized();
739     DCHECK(has_definite_max_track_breadth ||
740            (track.MinTrackBreadth().IsLength() &&
741             !track.MinTrackBreadth().IsContentSized()));
742     tracks_size += ValueForLength(has_definite_max_track_breadth
743                                       ? track.MaxTrackBreadth().length()
744                                       : track.MinTrackBreadth().length(),
745                                   available_size.value());
746   }
747 
748   // Add gutters as if there where only 1 auto repeat track. Gaps between auto
749   // repeat tracks will be added later when computing the repetitions.
750   LayoutUnit gap_size = GridGap(direction, available_size);
751   tracks_size +=
752       gap_size * (track_sizes.size() + auto_repeat_track_list_length - 1);
753 
754   LayoutUnit free_space = available_size.value() - tracks_size;
755   if (free_space <= 0)
756     return auto_repeat_track_list_length;
757 
758   LayoutUnit auto_repeat_size_with_gap =
759       auto_repeat_tracks_size + gap_size * auto_repeat_track_list_length;
760 
761   size_t repetitions = 1 + (free_space / auto_repeat_size_with_gap).ToInt();
762   free_space -= auto_repeat_size_with_gap * (repetitions - 1);
763 
764   // Provided the grid container does not have a definite size or max-size in
765   // the relevant axis, if the min size is definite then the number of
766   // repetitions is the smallest positive integer that fulfills that
767   // minimum requirement. If after determining the repetitions, we still have
768   // free space, then we need one more repetition to ensure we fill at least all
769   // of the space.
770   if (needs_to_fulfill_minimum_size && free_space)
771     ++repetitions;
772 
773   return repetitions * auto_repeat_track_list_length;
774 }
775 
776 std::unique_ptr<OrderedTrackIndexSet>
ComputeEmptyTracksForAutoRepeat(Grid & grid,GridTrackSizingDirection direction) const777 LayoutGrid::ComputeEmptyTracksForAutoRepeat(
778     Grid& grid,
779     GridTrackSizingDirection direction) const {
780   NOT_DESTROYED();
781   bool is_row_axis = direction == kForColumns;
782   if ((is_row_axis &&
783        StyleRef().GridAutoRepeatColumnsType() != AutoRepeatType::kAutoFit) ||
784       (!is_row_axis &&
785        StyleRef().GridAutoRepeatRowsType() != AutoRepeatType::kAutoFit))
786     return nullptr;
787 
788   std::unique_ptr<OrderedTrackIndexSet> empty_track_indexes;
789   size_t insertion_point =
790       is_row_axis ? StyleRef().GridAutoRepeatColumnsInsertionPoint()
791                   : StyleRef().GridAutoRepeatRowsInsertionPoint();
792   size_t first_auto_repeat_track =
793       insertion_point + grid.ExplicitGridStart(direction);
794   size_t last_auto_repeat_track =
795       first_auto_repeat_track + grid.AutoRepeatTracks(direction);
796 
797   if (!grid.HasGridItems()) {
798     empty_track_indexes = std::make_unique<OrderedTrackIndexSet>();
799     for (size_t track_index = first_auto_repeat_track;
800          track_index < last_auto_repeat_track; ++track_index)
801       empty_track_indexes->insert(track_index);
802   } else {
803     for (size_t track_index = first_auto_repeat_track;
804          track_index < last_auto_repeat_track; ++track_index) {
805       auto iterator = grid.CreateIterator(direction, track_index);
806       if (!iterator->NextGridItem()) {
807         if (!empty_track_indexes)
808           empty_track_indexes = std::make_unique<OrderedTrackIndexSet>();
809         empty_track_indexes->insert(track_index);
810       }
811     }
812   }
813   return empty_track_indexes;
814 }
815 
ClampAutoRepeatTracks(GridTrackSizingDirection direction,size_t auto_repeat_tracks) const816 size_t LayoutGrid::ClampAutoRepeatTracks(GridTrackSizingDirection direction,
817                                          size_t auto_repeat_tracks) const {
818   NOT_DESTROYED();
819   if (!auto_repeat_tracks)
820     return 0;
821 
822   size_t insertion_point =
823       direction == kForColumns
824           ? StyleRef().GridAutoRepeatColumnsInsertionPoint()
825           : StyleRef().GridAutoRepeatRowsInsertionPoint();
826 
827   if (insertion_point == 0)
828     return std::min<size_t>(auto_repeat_tracks, kGridMaxTracks);
829 
830   if (insertion_point >= kGridMaxTracks)
831     return 0;
832 
833   return std::min(auto_repeat_tracks,
834                   static_cast<size_t>(kGridMaxTracks) - insertion_point);
835 }
836 
837 // TODO(svillar): we shouldn't have to pass the available logical width as
838 // argument. The problem is that availableLogicalWidth() does always return a
839 // value even if we cannot resolve it like when computing the intrinsic size
840 // (preferred widths). That's why we pass the responsibility to the caller who
841 // does know whether the available logical width is indefinite or not.
PlaceItemsOnGrid(GridTrackSizingAlgorithm & algorithm,base::Optional<LayoutUnit> available_logical_width) const842 void LayoutGrid::PlaceItemsOnGrid(
843     GridTrackSizingAlgorithm& algorithm,
844     base::Optional<LayoutUnit> available_logical_width) const {
845   NOT_DESTROYED();
846   Grid& grid = algorithm.GetMutableGrid();
847   size_t auto_repeat_rows = ComputeAutoRepeatTracksCount(
848       kForRows, ConvertLayoutUnitToOptional(
849                     AvailableLogicalHeightForPercentageComputation()));
850   size_t auto_repeat_columns =
851       ComputeAutoRepeatTracksCount(kForColumns, available_logical_width);
852 
853   auto_repeat_rows = ClampAutoRepeatTracks(kForRows, auto_repeat_rows);
854   auto_repeat_columns = ClampAutoRepeatTracks(kForColumns, auto_repeat_columns);
855 
856   if (auto_repeat_rows != grid.AutoRepeatTracks(kForRows) ||
857       auto_repeat_columns != grid.AutoRepeatTracks(kForColumns)) {
858     grid.SetNeedsItemsPlacement(true);
859     grid.SetAutoRepeatTracks(auto_repeat_rows, auto_repeat_columns);
860   }
861 
862   if (!grid.NeedsItemsPlacement())
863     return;
864 
865   DCHECK(!grid.HasGridItems());
866   PopulateExplicitGridAndOrderIterator(grid);
867 
868   Vector<LayoutBox*> auto_major_axis_auto_grid_items;
869   Vector<LayoutBox*> specified_major_axis_auto_grid_items;
870 #if DCHECK_IS_ON()
871   DCHECK(!grid.HasAnyGridItemPaintOrder());
872 #endif
873   size_t child_index = 0;
874   for (LayoutBox* child = grid.GetOrderIterator().First(); child;
875        child = grid.GetOrderIterator().Next()) {
876     if (child->IsOutOfFlowPositioned())
877       continue;
878 
879     // Grid items should use the grid area sizes instead of the containing block
880     // (grid container) sizes, we initialize the overrides here if needed to
881     // ensure it.
882     if (!child->HasOverrideContainingBlockContentLogicalWidth())
883       child->SetOverrideContainingBlockContentLogicalWidth(LayoutUnit());
884     if (!child->HasOverrideContainingBlockContentLogicalHeight())
885       child->SetOverrideContainingBlockContentLogicalHeight(LayoutUnit(-1));
886 
887     grid.SetGridItemPaintOrder(*child, child_index++);
888 
889     GridArea area = grid.GridItemArea(*child);
890     if (!area.rows.IsIndefinite())
891       area.rows.Translate(grid.ExplicitGridStart(kForRows));
892     if (!area.columns.IsIndefinite())
893       area.columns.Translate(grid.ExplicitGridStart(kForColumns));
894 
895     if (area.rows.IsIndefinite() || area.columns.IsIndefinite()) {
896       grid.SetGridItemArea(*child, area);
897       GridSpan major_axis_positions =
898           (AutoPlacementMajorAxisDirection() == kForColumns) ? area.columns
899                                                              : area.rows;
900       if (major_axis_positions.IsIndefinite())
901         auto_major_axis_auto_grid_items.push_back(child);
902       else
903         specified_major_axis_auto_grid_items.push_back(child);
904       continue;
905     }
906     grid.Insert(*child, area);
907   }
908 
909 #if DCHECK_IS_ON()
910   if (grid.HasGridItems()) {
911     DCHECK_GE(grid.NumTracks(kForRows),
912               GridPositionsResolver::ExplicitGridRowCount(
913                   StyleRef(), grid.AutoRepeatTracks(kForRows)));
914     DCHECK_GE(grid.NumTracks(kForColumns),
915               GridPositionsResolver::ExplicitGridColumnCount(
916                   StyleRef(), grid.AutoRepeatTracks(kForColumns)));
917   }
918 #endif
919 
920   PlaceSpecifiedMajorAxisItemsOnGrid(grid,
921                                      specified_major_axis_auto_grid_items);
922   PlaceAutoMajorAxisItemsOnGrid(grid, auto_major_axis_auto_grid_items);
923 
924   // Compute collapsable tracks for auto-fit.
925   grid.SetAutoRepeatEmptyColumns(
926       ComputeEmptyTracksForAutoRepeat(grid, kForColumns));
927   grid.SetAutoRepeatEmptyRows(ComputeEmptyTracksForAutoRepeat(grid, kForRows));
928 
929   grid.SetNeedsItemsPlacement(false);
930 
931 #if DCHECK_IS_ON()
932   for (LayoutBox* child = grid.GetOrderIterator().First(); child;
933        child = grid.GetOrderIterator().Next()) {
934     if (child->IsOutOfFlowPositioned())
935       continue;
936 
937     GridArea area = grid.GridItemArea(*child);
938     DCHECK(area.rows.IsTranslatedDefinite());
939     DCHECK(area.columns.IsTranslatedDefinite());
940   }
941 #endif
942 }
943 
944 // TODO(lajava): Consider rafactoring this code with
945 // LocalFrameView::PrepareOrthogonalWritingModeRootForLayout
PrepareOrthogonalWritingModeRootForLayout(LayoutObject & root)946 static bool PrepareOrthogonalWritingModeRootForLayout(LayoutObject& root) {
947   DCHECK(To<LayoutBox>(root).IsOrthogonalWritingModeRoot());
948   if (!root.NeedsLayout() || root.IsOutOfFlowPositioned() ||
949       root.IsColumnSpanAll() || root.IsTablePart())
950     return false;
951 
952   return true;
953 }
954 
PerformGridItemsPreLayout(const GridTrackSizingAlgorithm & algorithm) const955 void LayoutGrid::PerformGridItemsPreLayout(
956     const GridTrackSizingAlgorithm& algorithm) const {
957   NOT_DESTROYED();
958   DCHECK(!algorithm.GetGrid().NeedsItemsPlacement());
959   if (!GetDocument().View()->IsInPerformLayout())
960     return;
961   for (auto* child = FirstInFlowChildBox(); child;
962        child = child->NextInFlowSiblingBox()) {
963     // Blink does a pre-layout of all the orthogonal boxes in the layout
964     // tree (see how LocalFrameView::PerformLayout calls its
965     // LayoutOrthogonalWritingModeRoots function). However, grid items
966     // don't participate in this process (see the function
967     // PrepareOrthogonalWritingModeRootForLayout) because it's useless
968     // and even wrong if they don't have their corresponding Grid Area.
969     // TODO(jfernandez): Consider rafactoring this code with
970     // LocalFrameView::LayoutOrthogonalWritingModeRoots
971     if (GridLayoutUtils::IsOrthogonalChild(*this, *child)) {
972       if (PrepareOrthogonalWritingModeRootForLayout(*child)) {
973         UpdateGridAreaLogicalSize(
974             *child, algorithm.EstimatedGridAreaBreadthForChild(*child));
975         child->LayoutIfNeeded();
976         continue;
977       }
978     }
979     // We need to layout the item to know whether it must synthesize its
980     // baseline or not, which may imply a cyclic sizing dependency.
981     // TODO (jfernandez): Can we avoid it ?
982     if (IsBaselineAlignmentForChild(*child)) {
983       if (child->HasRelativeLogicalWidth() ||
984           child->HasRelativeLogicalHeight() ||
985           child->StyleRef().LogicalHeight().IsAuto()) {
986         UpdateGridAreaLogicalSize(
987             *child, algorithm.EstimatedGridAreaBreadthForChild(*child));
988       }
989       child->LayoutIfNeeded();
990     }
991   }
992 }
993 
PopulateExplicitGridAndOrderIterator(Grid & grid) const994 void LayoutGrid::PopulateExplicitGridAndOrderIterator(Grid& grid) const {
995   NOT_DESTROYED();
996   OrderIteratorPopulator populator(grid.GetOrderIterator());
997   size_t explicit_row_start = 0;
998   size_t explicit_column_start = 0;
999 
1000   size_t auto_repeat_rows = grid.AutoRepeatTracks(kForRows);
1001   size_t auto_repeat_columns = grid.AutoRepeatTracks(kForColumns);
1002   size_t maximum_row_index =
1003       GridPositionsResolver::ExplicitGridRowCount(StyleRef(), auto_repeat_rows);
1004   size_t maximum_column_index = GridPositionsResolver::ExplicitGridColumnCount(
1005       StyleRef(), auto_repeat_columns);
1006 
1007   for (LayoutBox* child = FirstInFlowChildBox(); child;
1008        child = child->NextInFlowSiblingBox()) {
1009     populator.CollectChild(child);
1010 
1011     // This function bypasses the cache (gridItemArea()) as it is used to
1012     // build it.
1013     GridSpan row_positions =
1014         GridPositionsResolver::ResolveGridPositionsFromStyle(
1015             StyleRef(), child->StyleRef(), kForRows, auto_repeat_rows);
1016     GridSpan column_positions =
1017         GridPositionsResolver::ResolveGridPositionsFromStyle(
1018             StyleRef(), child->StyleRef(), kForColumns, auto_repeat_columns);
1019     grid.SetGridItemArea(*child, GridArea(row_positions, column_positions));
1020 
1021     // |positions| is 0 if we need to run the auto-placement algorithm.
1022     if (!row_positions.IsIndefinite()) {
1023       explicit_row_start = std::max<int>(
1024           explicit_row_start, -row_positions.UntranslatedStartLine());
1025       maximum_row_index =
1026           std::max<int>(maximum_row_index, row_positions.UntranslatedEndLine());
1027     } else {
1028       // Grow the grid for items with a definite row span, getting the largest
1029       // such span.
1030       size_t span_size = GridPositionsResolver::SpanSizeForAutoPlacedItem(
1031           child->StyleRef(), kForRows);
1032       maximum_row_index = std::max(maximum_row_index, span_size);
1033     }
1034 
1035     if (!column_positions.IsIndefinite()) {
1036       explicit_column_start = std::max<int>(
1037           explicit_column_start, -column_positions.UntranslatedStartLine());
1038       maximum_column_index = std::max<int>(
1039           maximum_column_index, column_positions.UntranslatedEndLine());
1040     } else {
1041       // Grow the grid for items with a definite column span, getting the
1042       // largest such span.
1043       size_t span_size = GridPositionsResolver::SpanSizeForAutoPlacedItem(
1044           child->StyleRef(), kForColumns);
1045       maximum_column_index = std::max(maximum_column_index, span_size);
1046     }
1047   }
1048 
1049   grid.SetExplicitGridStart(explicit_row_start, explicit_column_start);
1050   grid.EnsureGridSize(maximum_row_index + explicit_row_start,
1051                       maximum_column_index + explicit_column_start);
1052 }
1053 
1054 std::unique_ptr<GridArea>
CreateEmptyGridAreaAtSpecifiedPositionsOutsideGrid(const Grid & grid,const LayoutBox & grid_item,GridTrackSizingDirection specified_direction,const GridSpan & specified_positions) const1055 LayoutGrid::CreateEmptyGridAreaAtSpecifiedPositionsOutsideGrid(
1056     const Grid& grid,
1057     const LayoutBox& grid_item,
1058     GridTrackSizingDirection specified_direction,
1059     const GridSpan& specified_positions) const {
1060   NOT_DESTROYED();
1061   GridTrackSizingDirection cross_direction =
1062       specified_direction == kForColumns ? kForRows : kForColumns;
1063   const size_t end_of_cross_direction = grid.NumTracks(cross_direction);
1064   size_t cross_direction_span_size =
1065       GridPositionsResolver::SpanSizeForAutoPlacedItem(grid_item.StyleRef(),
1066                                                        cross_direction);
1067   GridSpan cross_direction_positions = GridSpan::TranslatedDefiniteGridSpan(
1068       end_of_cross_direction,
1069       end_of_cross_direction + cross_direction_span_size);
1070   return std::make_unique<GridArea>(
1071       specified_direction == kForColumns ? cross_direction_positions
1072                                          : specified_positions,
1073       specified_direction == kForColumns ? specified_positions
1074                                          : cross_direction_positions);
1075 }
1076 
PlaceSpecifiedMajorAxisItemsOnGrid(Grid & grid,const Vector<LayoutBox * > & auto_grid_items) const1077 void LayoutGrid::PlaceSpecifiedMajorAxisItemsOnGrid(
1078     Grid& grid,
1079     const Vector<LayoutBox*>& auto_grid_items) const {
1080   NOT_DESTROYED();
1081   bool is_for_columns = AutoPlacementMajorAxisDirection() == kForColumns;
1082   bool is_grid_auto_flow_dense = StyleRef().IsGridAutoFlowAlgorithmDense();
1083 
1084   // Mapping between the major axis tracks (rows or columns) and the last
1085   // auto-placed item's position inserted on that track. This is needed to
1086   // implement "sparse" packing for items locked to a given track.
1087   // See https://drafts.csswg.org/css-grid/#auto-placement-algo
1088   HashMap<unsigned, unsigned, DefaultHash<unsigned>::Hash,
1089           WTF::UnsignedWithZeroKeyHashTraits<unsigned>>
1090       minor_axis_cursors;
1091 
1092   for (auto* const auto_grid_item : auto_grid_items) {
1093     GridSpan major_axis_positions =
1094         grid.GridItemSpan(*auto_grid_item, AutoPlacementMajorAxisDirection());
1095     DCHECK(major_axis_positions.IsTranslatedDefinite());
1096     DCHECK(
1097         !grid.GridItemSpan(*auto_grid_item, AutoPlacementMinorAxisDirection())
1098              .IsTranslatedDefinite());
1099     size_t minor_axis_span_size =
1100         GridPositionsResolver::SpanSizeForAutoPlacedItem(
1101             auto_grid_item->StyleRef(), AutoPlacementMinorAxisDirection());
1102     unsigned major_axis_initial_position = major_axis_positions.StartLine();
1103 
1104     auto iterator = grid.CreateIterator(
1105         AutoPlacementMajorAxisDirection(), major_axis_positions.StartLine(),
1106         is_grid_auto_flow_dense
1107             ? 0
1108             : minor_axis_cursors.at(major_axis_initial_position));
1109     std::unique_ptr<GridArea> empty_grid_area = iterator->NextEmptyGridArea(
1110         major_axis_positions.IntegerSpan(), minor_axis_span_size);
1111     DCHECK(empty_grid_area);
1112 
1113     grid.Insert(*auto_grid_item, *empty_grid_area);
1114 
1115     if (!is_grid_auto_flow_dense)
1116       minor_axis_cursors.Set(major_axis_initial_position,
1117                              is_for_columns
1118                                  ? empty_grid_area->rows.StartLine()
1119                                  : empty_grid_area->columns.StartLine());
1120   }
1121 }
1122 
PlaceAutoMajorAxisItemsOnGrid(Grid & grid,const Vector<LayoutBox * > & auto_grid_items) const1123 void LayoutGrid::PlaceAutoMajorAxisItemsOnGrid(
1124     Grid& grid,
1125     const Vector<LayoutBox*>& auto_grid_items) const {
1126   NOT_DESTROYED();
1127   std::pair<size_t, size_t> auto_placement_cursor = std::make_pair(0, 0);
1128   bool is_grid_auto_flow_dense = StyleRef().IsGridAutoFlowAlgorithmDense();
1129 
1130   for (auto* const auto_grid_item : auto_grid_items) {
1131     PlaceAutoMajorAxisItemOnGrid(grid, *auto_grid_item, auto_placement_cursor);
1132 
1133     // If grid-auto-flow is dense, reset auto-placement cursor.
1134     if (is_grid_auto_flow_dense) {
1135       auto_placement_cursor.first = 0;
1136       auto_placement_cursor.second = 0;
1137     }
1138   }
1139 }
1140 
PlaceAutoMajorAxisItemOnGrid(Grid & grid,LayoutBox & grid_item,std::pair<size_t,size_t> & auto_placement_cursor) const1141 void LayoutGrid::PlaceAutoMajorAxisItemOnGrid(
1142     Grid& grid,
1143     LayoutBox& grid_item,
1144     std::pair<size_t, size_t>& auto_placement_cursor) const {
1145   NOT_DESTROYED();
1146   GridSpan minor_axis_positions =
1147       grid.GridItemSpan(grid_item, AutoPlacementMinorAxisDirection());
1148   DCHECK(!grid.GridItemSpan(grid_item, AutoPlacementMajorAxisDirection())
1149               .IsTranslatedDefinite());
1150   size_t major_axis_span_size =
1151       GridPositionsResolver::SpanSizeForAutoPlacedItem(
1152           grid_item.StyleRef(), AutoPlacementMajorAxisDirection());
1153 
1154   const size_t end_of_major_axis =
1155       grid.NumTracks(AutoPlacementMajorAxisDirection());
1156   size_t major_axis_auto_placement_cursor =
1157       AutoPlacementMajorAxisDirection() == kForColumns
1158           ? auto_placement_cursor.second
1159           : auto_placement_cursor.first;
1160   size_t minor_axis_auto_placement_cursor =
1161       AutoPlacementMajorAxisDirection() == kForColumns
1162           ? auto_placement_cursor.first
1163           : auto_placement_cursor.second;
1164 
1165   std::unique_ptr<GridArea> empty_grid_area;
1166   if (minor_axis_positions.IsTranslatedDefinite()) {
1167     // Move to the next track in major axis if initial position in minor axis is
1168     // before auto-placement cursor.
1169     if (minor_axis_positions.StartLine() < minor_axis_auto_placement_cursor)
1170       major_axis_auto_placement_cursor++;
1171 
1172     if (major_axis_auto_placement_cursor < end_of_major_axis) {
1173       auto iterator = grid.CreateIterator(AutoPlacementMinorAxisDirection(),
1174                                           minor_axis_positions.StartLine(),
1175                                           major_axis_auto_placement_cursor);
1176       empty_grid_area = iterator->NextEmptyGridArea(
1177           minor_axis_positions.IntegerSpan(), major_axis_span_size);
1178     }
1179 
1180     if (!empty_grid_area) {
1181       empty_grid_area = CreateEmptyGridAreaAtSpecifiedPositionsOutsideGrid(
1182           grid, grid_item, AutoPlacementMinorAxisDirection(),
1183           minor_axis_positions);
1184     }
1185   } else {
1186     size_t minor_axis_span_size =
1187         GridPositionsResolver::SpanSizeForAutoPlacedItem(
1188             grid_item.StyleRef(), AutoPlacementMinorAxisDirection());
1189 
1190     for (size_t major_axis_index = major_axis_auto_placement_cursor;
1191          major_axis_index < end_of_major_axis; ++major_axis_index) {
1192       auto iterator = grid.CreateIterator(AutoPlacementMajorAxisDirection(),
1193                                           major_axis_index,
1194                                           minor_axis_auto_placement_cursor);
1195       empty_grid_area = iterator->NextEmptyGridArea(major_axis_span_size,
1196                                                     minor_axis_span_size);
1197       DCHECK(empty_grid_area);
1198 
1199       // Check that it fits in the minor axis direction, as we shouldn't grow
1200       // in that direction here (it was already managed in
1201       // populateExplicitGridAndOrderIterator()).
1202       size_t minor_axis_final_position_index =
1203           AutoPlacementMinorAxisDirection() == kForColumns
1204               ? empty_grid_area->columns.EndLine()
1205               : empty_grid_area->rows.EndLine();
1206       const size_t end_of_minor_axis =
1207           grid.NumTracks(AutoPlacementMinorAxisDirection());
1208       if (minor_axis_final_position_index <= end_of_minor_axis)
1209         break;
1210 
1211       // Discard empty grid area as it does not fit in the minor axis
1212       // direction. We don't need to create a new empty grid area yet as we
1213       // might find a valid one in the next iteration.
1214       empty_grid_area.reset();
1215 
1216       // As we're moving to the next track in the major axis we should reset the
1217       // auto-placement cursor in the minor axis.
1218       minor_axis_auto_placement_cursor = 0;
1219     }
1220 
1221     if (!empty_grid_area)
1222       empty_grid_area = CreateEmptyGridAreaAtSpecifiedPositionsOutsideGrid(
1223           grid, grid_item, AutoPlacementMinorAxisDirection(),
1224           GridSpan::TranslatedDefiniteGridSpan(0, minor_axis_span_size));
1225   }
1226 
1227   grid.Insert(grid_item, *empty_grid_area);
1228   // Move auto-placement cursor to the new position.
1229   auto_placement_cursor.first = empty_grid_area->rows.StartLine();
1230   auto_placement_cursor.second = empty_grid_area->columns.StartLine();
1231 }
1232 
AutoPlacementMajorAxisDirection() const1233 GridTrackSizingDirection LayoutGrid::AutoPlacementMajorAxisDirection() const {
1234   NOT_DESTROYED();
1235   return StyleRef().IsGridAutoFlowDirectionColumn() ? kForColumns : kForRows;
1236 }
1237 
AutoPlacementMinorAxisDirection() const1238 GridTrackSizingDirection LayoutGrid::AutoPlacementMinorAxisDirection() const {
1239   NOT_DESTROYED();
1240   return StyleRef().IsGridAutoFlowDirectionColumn() ? kForRows : kForColumns;
1241 }
1242 
DirtyGrid()1243 void LayoutGrid::DirtyGrid() {
1244   NOT_DESTROYED();
1245   if (grid_->NeedsItemsPlacement())
1246     return;
1247 
1248   grid_->SetNeedsItemsPlacement(true);
1249 }
1250 
TrackSizesForComputedStyle(GridTrackSizingDirection direction) const1251 Vector<LayoutUnit> LayoutGrid::TrackSizesForComputedStyle(
1252     GridTrackSizingDirection direction) const {
1253   NOT_DESTROYED();
1254   bool is_row_axis = direction == kForColumns;
1255   auto& positions = is_row_axis ? column_positions_ : row_positions_;
1256   size_t num_positions = positions.size();
1257   LayoutUnit offset_between_tracks =
1258       is_row_axis ? offset_between_columns_.distribution_offset
1259                   : offset_between_rows_.distribution_offset;
1260 
1261   Vector<LayoutUnit> tracks;
1262   if (num_positions < 2)
1263     return tracks;
1264 
1265   DCHECK(!grid_->NeedsItemsPlacement());
1266   bool has_collapsed_tracks = grid_->HasAutoRepeatEmptyTracks(direction);
1267   LayoutUnit gap = !has_collapsed_tracks ? GridGap(direction) : LayoutUnit();
1268   tracks.ReserveCapacity(num_positions - 1);
1269   for (size_t i = 0; i < num_positions - 2; ++i)
1270     tracks.push_back(positions[i + 1] - positions[i] - offset_between_tracks -
1271                      gap);
1272   tracks.push_back(positions[num_positions - 1] - positions[num_positions - 2]);
1273 
1274   if (!has_collapsed_tracks)
1275     return tracks;
1276 
1277   size_t remaining_empty_tracks =
1278       grid_->AutoRepeatEmptyTracks(direction)->size();
1279   size_t last_line = tracks.size();
1280   gap = GridGap(direction);
1281   for (size_t i = 1; i < last_line; ++i) {
1282     if (grid_->IsEmptyAutoRepeatTrack(direction, i - 1)) {
1283       --remaining_empty_tracks;
1284     } else {
1285       // Remove the gap between consecutive non empty tracks. Remove it also
1286       // just once for an arbitrary number of empty tracks between two non empty
1287       // ones.
1288       bool all_remaining_tracks_are_empty =
1289           remaining_empty_tracks == (last_line - i);
1290       if (!all_remaining_tracks_are_empty ||
1291           !grid_->IsEmptyAutoRepeatTrack(direction, i))
1292         tracks[i - 1] -= gap;
1293     }
1294   }
1295 
1296   return tracks;
1297 }
1298 
ContentAlignmentNormalBehavior()1299 const StyleContentAlignmentData& LayoutGrid::ContentAlignmentNormalBehavior() {
1300   static const StyleContentAlignmentData kNormalBehavior = {
1301       ContentPosition::kNormal, ContentDistributionType::kStretch};
1302   return kNormalBehavior;
1303 }
1304 
OverrideSizeChanged(const LayoutBox & child,GridTrackSizingDirection direction,LayoutSize size)1305 static bool OverrideSizeChanged(const LayoutBox& child,
1306                                 GridTrackSizingDirection direction,
1307                                 LayoutSize size) {
1308   if (direction == kForColumns) {
1309     return !child.HasOverrideContainingBlockContentLogicalWidth() ||
1310            child.OverrideContainingBlockContentLogicalWidth() != size.Width();
1311   }
1312   return !child.HasOverrideContainingBlockContentLogicalHeight() ||
1313          child.OverrideContainingBlockContentLogicalHeight() != size.Height();
1314 }
1315 
HasRelativeBlockAxisSize(const LayoutGrid & grid,const LayoutBox & child)1316 static bool HasRelativeBlockAxisSize(const LayoutGrid& grid,
1317                                      const LayoutBox& child) {
1318   return GridLayoutUtils::IsOrthogonalChild(grid, child)
1319              ? child.HasRelativeLogicalWidth() ||
1320                    child.StyleRef().LogicalWidth().IsAuto()
1321              : child.HasRelativeLogicalHeight();
1322 }
1323 
UpdateGridAreaLogicalSize(LayoutBox & child,LayoutSize grid_area_logical_size) const1324 void LayoutGrid::UpdateGridAreaLogicalSize(
1325     LayoutBox& child,
1326     LayoutSize grid_area_logical_size) const {
1327   NOT_DESTROYED();
1328   // Because the grid area cannot be styled, we don't need to adjust
1329   // the grid breadth to account for 'box-sizing'.
1330   bool grid_area_width_changed =
1331       OverrideSizeChanged(child, kForColumns, grid_area_logical_size);
1332   bool grid_area_height_changed =
1333       OverrideSizeChanged(child, kForRows, grid_area_logical_size);
1334   if (grid_area_width_changed ||
1335       (grid_area_height_changed && HasRelativeBlockAxisSize(*this, child))) {
1336     child.SetSelfNeedsLayoutForAvailableSpace(true);
1337   }
1338 
1339   child.SetOverrideContainingBlockContentLogicalWidth(
1340       grid_area_logical_size.Width());
1341   child.SetOverrideContainingBlockContentLogicalHeight(
1342       grid_area_logical_size.Height());
1343 }
1344 
LayoutGridItems()1345 void LayoutGrid::LayoutGridItems() {
1346   NOT_DESTROYED();
1347   if (ChildLayoutBlockedByDisplayLock())
1348     return;
1349 
1350   PopulateGridPositionsForDirection(kForColumns);
1351   PopulateGridPositionsForDirection(kForRows);
1352 
1353   for (LayoutBox* child = FirstChildBox(); child;
1354        child = child->NextSiblingBox()) {
1355     if (child->IsOutOfFlowPositioned()) {
1356       PrepareChildForPositionedLayout(*child);
1357       continue;
1358     }
1359 
1360     // Setting the definite grid area's sizes. It may imply that the
1361     // item must perform a layout if its area differs from the one
1362     // used during the track sizing algorithm.
1363     UpdateGridAreaLogicalSize(
1364         *child, LayoutSize(GridAreaBreadthForChildIncludingAlignmentOffsets(
1365                                *child, kForColumns),
1366                            GridAreaBreadthForChildIncludingAlignmentOffsets(
1367                                *child, kForRows)));
1368 
1369     // Stretching logic might force a child layout, so we need to run it before
1370     // the layoutIfNeeded call to avoid unnecessary relayouts. This might imply
1371     // that child margins, needed to correctly determine the available space
1372     // before stretching, are not set yet.
1373     ApplyStretchAlignmentToChildIfNeeded(*child);
1374 
1375     child->LayoutIfNeeded();
1376 
1377     // We need pending layouts to be done in order to compute auto-margins
1378     // properly.
1379     UpdateAutoMarginsInColumnAxisIfNeeded(*child);
1380     UpdateAutoMarginsInRowAxisIfNeeded(*child);
1381 
1382     const GridArea& area = grid_->GridItemArea(*child);
1383 #if DCHECK_IS_ON()
1384     DCHECK_LT(area.columns.StartLine(),
1385               track_sizing_algorithm_.Tracks(kForColumns).size());
1386     DCHECK_LT(area.rows.StartLine(),
1387               track_sizing_algorithm_.Tracks(kForRows).size());
1388 #endif
1389     SetLogicalPositionForChild(*child);
1390 
1391     // Keep track of children overflowing their grid area as we might need to
1392     // paint them even if the grid-area is not visible. Using physical
1393     // dimensions for simplicity, so we can forget about orthogonalty.
1394     LayoutUnit child_grid_area_height =
1395         child->OverrideContainingBlockContentHeight();
1396     LayoutUnit child_grid_area_width =
1397         child->OverrideContainingBlockContentWidth();
1398     LayoutRect grid_area_rect(
1399         GridAreaLogicalPosition(area),
1400         LayoutSize(child_grid_area_width, child_grid_area_height));
1401     LayoutRect child_overflow_rect = child->FrameRect();
1402     child_overflow_rect.SetSize(child->VisualOverflowRect().Size());
1403   }
1404 }
1405 
PrepareChildForPositionedLayout(LayoutBox & child)1406 void LayoutGrid::PrepareChildForPositionedLayout(LayoutBox& child) {
1407   NOT_DESTROYED();
1408   DCHECK(child.IsOutOfFlowPositioned());
1409   child.ContainingBlock()->InsertPositionedObject(&child);
1410 
1411   PaintLayer* child_layer = child.Layer();
1412   // Static position of a positioned child should use the content-box
1413   // (https://drafts.csswg.org/css-grid/#static-position).
1414   child_layer->SetStaticInlinePosition(BorderAndPaddingStart());
1415   child_layer->SetStaticBlockPosition(BorderAndPaddingBefore());
1416 }
1417 
HasStaticPositionForChild(const LayoutBox & child,GridTrackSizingDirection direction) const1418 bool LayoutGrid::HasStaticPositionForChild(
1419     const LayoutBox& child,
1420     GridTrackSizingDirection direction) const {
1421   NOT_DESTROYED();
1422   return direction == kForColumns ? child.StyleRef().HasStaticInlinePosition(
1423                                         IsHorizontalWritingMode())
1424                                   : child.StyleRef().HasStaticBlockPosition(
1425                                         IsHorizontalWritingMode());
1426 }
1427 
LayoutPositionedObjects(bool relayout_children,PositionedLayoutBehavior info)1428 void LayoutGrid::LayoutPositionedObjects(bool relayout_children,
1429                                          PositionedLayoutBehavior info) {
1430   NOT_DESTROYED();
1431   if (ChildLayoutBlockedByDisplayLock())
1432     return;
1433 
1434   column_of_positioned_item_.clear();
1435   row_of_positioned_item_.clear();
1436 
1437   TrackedLayoutBoxListHashSet* positioned_descendants = PositionedObjects();
1438   if (!positioned_descendants)
1439     return;
1440 
1441   for (auto* child : *positioned_descendants) {
1442     LayoutUnit column_breadth =
1443         GridAreaBreadthForOutOfFlowChild(*child, kForColumns);
1444     LayoutUnit row_breadth = GridAreaBreadthForOutOfFlowChild(*child, kForRows);
1445 
1446     child->SetOverrideContainingBlockContentLogicalWidth(column_breadth);
1447     child->SetOverrideContainingBlockContentLogicalHeight(row_breadth);
1448 
1449     // Mark for layout as we're resetting the position before and we relay in
1450     // generic layout logic for positioned items in order to get the offsets
1451     // properly resolved.
1452     child->SetNeedsLayout(layout_invalidation_reason::kGridChanged,
1453                           kMarkOnlyThis);
1454 
1455     LayoutPositionedObject(child, relayout_children, info);
1456 
1457     SetLogicalOffsetForChild(*child, kForColumns);
1458     SetLogicalOffsetForChild(*child, kForRows);
1459   }
1460 }
1461 
GridAreaBreadthForChildIncludingAlignmentOffsets(const LayoutBox & child,GridTrackSizingDirection direction) const1462 LayoutUnit LayoutGrid::GridAreaBreadthForChildIncludingAlignmentOffsets(
1463     const LayoutBox& child,
1464     GridTrackSizingDirection direction) const {
1465   NOT_DESTROYED();
1466   // We need the cached value when available because Content Distribution
1467   // alignment properties may have some influence in the final grid area
1468   // breadth.
1469   const Vector<GridTrack>& tracks = track_sizing_algorithm_.Tracks(direction);
1470   const GridSpan& span =
1471       track_sizing_algorithm_.GetGrid().GridItemSpan(child, direction);
1472   const Vector<LayoutUnit>& line_positions =
1473       (direction == kForColumns) ? column_positions_ : row_positions_;
1474   LayoutUnit initial_track_position = line_positions[span.StartLine()];
1475   LayoutUnit final_track_position = line_positions[span.EndLine() - 1];
1476   // Track Positions vector stores the 'start' grid line of each track, so we
1477   // have to add last track's baseSize.
1478   return final_track_position - initial_track_position +
1479          tracks[span.EndLine() - 1].BaseSize();
1480 }
1481 
PopulateGridPositionsForDirection(GridTrackSizingDirection direction)1482 void LayoutGrid::PopulateGridPositionsForDirection(
1483     GridTrackSizingDirection direction) {
1484   NOT_DESTROYED();
1485   // Since we add alignment offsets and track gutters, grid lines are not always
1486   // adjacent. Hence we will have to assume from now on that we just store
1487   // positions of the initial grid lines of each track, except the last one,
1488   // which is the only one considered as a final grid line of a track.
1489 
1490   // The grid container's frame elements (border, padding and <content-position>
1491   // offset) are sensible to the inline-axis flow direction. However, column
1492   // lines positions are 'direction' unaware. This simplification allows us to
1493   // use the same indexes to identify the columns independently on the
1494   // inline-axis direction.
1495   bool is_row_axis = direction == kForColumns;
1496   auto& tracks = track_sizing_algorithm_.Tracks(direction);
1497   size_t number_of_tracks = tracks.size();
1498   size_t number_of_lines = number_of_tracks + 1;
1499   size_t last_line = number_of_lines - 1;
1500   bool has_collapsed_tracks = grid_->HasAutoRepeatEmptyTracks(direction);
1501   size_t number_of_collapsed_tracks =
1502       has_collapsed_tracks ? grid_->AutoRepeatEmptyTracks(direction)->size()
1503                            : 0;
1504   const auto& offset =
1505       direction == kForColumns ? offset_between_columns_ : offset_between_rows_;
1506   auto& positions = is_row_axis ? column_positions_ : row_positions_;
1507   positions.resize(number_of_lines);
1508 
1509   auto border_and_padding =
1510       is_row_axis ? BorderAndPaddingLogicalLeft() : BorderAndPaddingBefore();
1511   if (is_row_axis) {
1512     if (StyleRef().IsHorizontalWritingMode() &&
1513         !StyleRef().IsLeftToRightDirection())
1514       border_and_padding += ComputeLogicalScrollbars().InlineSum();
1515   } else {
1516     if (StyleRef().GetWritingMode() == WritingMode::kVerticalRl)
1517       border_and_padding += ComputeLogicalScrollbars().BlockSum();
1518   }
1519 
1520   positions[0] = border_and_padding + offset.position_offset;
1521   if (number_of_lines > 1) {
1522     // If we have collapsed tracks we just ignore gaps here and add them later
1523     // as we might not compute the gap between two consecutive tracks without
1524     // examining the surrounding ones.
1525     LayoutUnit gap = !has_collapsed_tracks ? GridGap(direction) : LayoutUnit();
1526     size_t next_to_last_line = number_of_lines - 2;
1527     for (size_t i = 0; i < next_to_last_line; ++i)
1528       positions[i + 1] = positions[i] + offset.distribution_offset +
1529                          tracks[i].BaseSize() + gap;
1530     positions[last_line] =
1531         positions[next_to_last_line] + tracks[next_to_last_line].BaseSize();
1532 
1533     // Adjust collapsed gaps. Collapsed tracks cause the surrounding gutters to
1534     // collapse (they coincide exactly) except on the edges of the grid where
1535     // they become 0.
1536     if (has_collapsed_tracks) {
1537       gap = GridGap(direction);
1538       size_t remaining_empty_tracks = number_of_collapsed_tracks;
1539       LayoutUnit offset_accumulator;
1540       LayoutUnit gap_accumulator;
1541       for (size_t i = 1; i < last_line; ++i) {
1542         if (grid_->IsEmptyAutoRepeatTrack(direction, i - 1)) {
1543           --remaining_empty_tracks;
1544           offset_accumulator += offset.distribution_offset;
1545         } else {
1546           // Add gap between consecutive non empty tracks. Add it also just once
1547           // for an arbitrary number of empty tracks between two non empty ones.
1548           bool all_remaining_tracks_are_empty =
1549               remaining_empty_tracks == (last_line - i);
1550           if (!all_remaining_tracks_are_empty ||
1551               !grid_->IsEmptyAutoRepeatTrack(direction, i))
1552             gap_accumulator += gap;
1553         }
1554         positions[i] += gap_accumulator - offset_accumulator;
1555       }
1556       positions[last_line] += gap_accumulator - offset_accumulator;
1557     }
1558   }
1559 }
1560 
ComputeOverflowAlignmentOffset(OverflowAlignment overflow,LayoutUnit track_size,LayoutUnit child_size)1561 static LayoutUnit ComputeOverflowAlignmentOffset(OverflowAlignment overflow,
1562                                                  LayoutUnit track_size,
1563                                                  LayoutUnit child_size) {
1564   LayoutUnit offset = track_size - child_size;
1565   switch (overflow) {
1566     case OverflowAlignment::kSafe:
1567       // If overflow is 'safe', we have to make sure we don't overflow the
1568       // 'start' edge (potentially cause some data loss as the overflow is
1569       // unreachable).
1570       return offset.ClampNegativeToZero();
1571     case OverflowAlignment::kUnsafe:
1572     case OverflowAlignment::kDefault:
1573       // If we overflow our alignment container and overflow is 'true'
1574       // (default), we ignore the overflow and just return the value regardless
1575       // (which may cause data loss as we overflow the 'start' edge).
1576       return offset;
1577   }
1578 
1579   NOTREACHED();
1580   return LayoutUnit();
1581 }
1582 
AvailableAlignmentSpaceForChildBeforeStretching(LayoutUnit grid_area_breadth_for_child,const LayoutBox & child) const1583 LayoutUnit LayoutGrid::AvailableAlignmentSpaceForChildBeforeStretching(
1584     LayoutUnit grid_area_breadth_for_child,
1585     const LayoutBox& child) const {
1586   NOT_DESTROYED();
1587   // Because we want to avoid multiple layouts, stretching logic might be
1588   // performed before children are laid out, so we can't use the child cached
1589   // values. Hence, we may need to compute margins in order to determine the
1590   // available height before stretching.
1591   return grid_area_breadth_for_child -
1592          GridLayoutUtils::MarginLogicalHeightForChild(*this, child);
1593 }
1594 
AlignSelfForChild(const LayoutBox & child,const ComputedStyle * style) const1595 StyleSelfAlignmentData LayoutGrid::AlignSelfForChild(
1596     const LayoutBox& child,
1597     const ComputedStyle* style) const {
1598   NOT_DESTROYED();
1599   if (!style)
1600     style = Style();
1601   return child.StyleRef().ResolvedAlignSelf(SelfAlignmentNormalBehavior(&child),
1602                                             style);
1603 }
1604 
JustifySelfForChild(const LayoutBox & child,const ComputedStyle * style) const1605 StyleSelfAlignmentData LayoutGrid::JustifySelfForChild(
1606     const LayoutBox& child,
1607     const ComputedStyle* style) const {
1608   NOT_DESTROYED();
1609   if (!style)
1610     style = Style();
1611   return child.StyleRef().ResolvedJustifySelf(
1612       SelfAlignmentNormalBehavior(&child), style);
1613 }
1614 
1615 // FIXME: This logic is shared by LayoutFlexibleBox, so it should be moved to
1616 // LayoutBox.
ApplyStretchAlignmentToChildIfNeeded(LayoutBox & child)1617 void LayoutGrid::ApplyStretchAlignmentToChildIfNeeded(LayoutBox& child) {
1618   NOT_DESTROYED();
1619   GridTrackSizingDirection child_block_direction =
1620       GridLayoutUtils::FlowAwareDirectionForChild(*this, child, kForRows);
1621   bool block_flow_is_column_axis = child_block_direction == kForRows;
1622   bool allowed_to_stretch_child_block_size =
1623       block_flow_is_column_axis ? AllowedToStretchChildAlongColumnAxis(child)
1624                                 : AllowedToStretchChildAlongRowAxis(child);
1625   if (allowed_to_stretch_child_block_size) {
1626     LayoutUnit stretched_logical_height =
1627         AvailableAlignmentSpaceForChildBeforeStretching(
1628             OverrideContainingBlockContentSizeForChild(child,
1629                                                        child_block_direction),
1630             child);
1631     LayoutUnit desired_logical_height = child.ConstrainLogicalHeightByMinMax(
1632         stretched_logical_height, LayoutUnit(-1));
1633     child.SetOverrideLogicalHeight(desired_logical_height);
1634 
1635     // Checking the logical-height of a child isn't enough. Setting an override
1636     // logical-height changes the definiteness, resulting in percentages to
1637     // resolve differently.
1638     // NG nodes have enough information to check for this case, and only layout
1639     // if needed.
1640     //
1641     // TODO (lajava): Can avoid laying out here in some cases.
1642     // See https://webkit.org/b/87905.
1643     if (desired_logical_height != child.LogicalHeight() ||
1644         child.MaybeHasPercentHeightDescendant()) {
1645       // Never mess around with the logical-height of any NG children.
1646       if (!child.IsLayoutNGMixin())
1647         child.SetLogicalHeight(LayoutUnit());
1648       child.SetSelfNeedsLayoutForAvailableSpace(true);
1649     }
1650   }
1651 }
1652 
HasAutoSizeInColumnAxis(const LayoutBox & child) const1653 bool LayoutGrid::HasAutoSizeInColumnAxis(const LayoutBox& child) const {
1654   NOT_DESTROYED();
1655   if (!child.StyleRef().AspectRatio().IsAuto()) {
1656     if (IsHorizontalWritingMode() == child.IsHorizontalWritingMode()) {
1657       // If the used inline size is non-auto, we do have a non auto block size
1658       // (column axis size) because of the aspect ratio.
1659       if (!child.StyleRef().LogicalWidth().IsAuto())
1660         return false;
1661     } else {
1662       const Length& logical_height = child.StyleRef().LogicalHeight();
1663       if (logical_height.IsFixed() ||
1664           (logical_height.IsPercentOrCalc() &&
1665            child.ComputePercentageLogicalHeight(Length::Percent(0)) !=
1666                kIndefiniteSize)) {
1667         return false;
1668       }
1669     }
1670   }
1671   return IsHorizontalWritingMode() ? child.StyleRef().Height().IsAuto()
1672                                    : child.StyleRef().Width().IsAuto();
1673 }
1674 
HasAutoSizeInRowAxis(const LayoutBox & child) const1675 bool LayoutGrid::HasAutoSizeInRowAxis(const LayoutBox& child) const {
1676   NOT_DESTROYED();
1677   if (!child.StyleRef().AspectRatio().IsAuto()) {
1678     if (IsHorizontalWritingMode() == child.IsHorizontalWritingMode()) {
1679       // If the used block size is non-auto, we do have a non auto inline size
1680       // (row axis size) because of the aspect ratio.
1681       const Length& logical_height = child.StyleRef().LogicalHeight();
1682       if (logical_height.IsFixed() ||
1683           (logical_height.IsPercentOrCalc() &&
1684            child.ComputePercentageLogicalHeight(Length::Percent(0)) !=
1685                kIndefiniteSize)) {
1686         return false;
1687       }
1688     } else {
1689       if (!child.StyleRef().LogicalWidth().IsAuto())
1690         return false;
1691     }
1692   }
1693   return IsHorizontalWritingMode() ? child.StyleRef().Width().IsAuto()
1694                                    : child.StyleRef().Height().IsAuto();
1695 }
1696 
1697 // TODO(lajava): This logic is shared by LayoutFlexibleBox, so it should be
1698 // moved to LayoutBox.
HasAutoMarginsInColumnAxis(const LayoutBox & child) const1699 bool LayoutGrid::HasAutoMarginsInColumnAxis(const LayoutBox& child) const {
1700   NOT_DESTROYED();
1701   if (IsHorizontalWritingMode())
1702     return child.StyleRef().MarginTop().IsAuto() ||
1703            child.StyleRef().MarginBottom().IsAuto();
1704   return child.StyleRef().MarginLeft().IsAuto() ||
1705          child.StyleRef().MarginRight().IsAuto();
1706 }
1707 
1708 // TODO(lajava): This logic is shared by LayoutFlexibleBox, so it should be
1709 // moved to LayoutBox.
HasAutoMarginsInRowAxis(const LayoutBox & child) const1710 bool LayoutGrid::HasAutoMarginsInRowAxis(const LayoutBox& child) const {
1711   NOT_DESTROYED();
1712   if (IsHorizontalWritingMode())
1713     return child.StyleRef().MarginLeft().IsAuto() ||
1714            child.StyleRef().MarginRight().IsAuto();
1715   return child.StyleRef().MarginTop().IsAuto() ||
1716          child.StyleRef().MarginBottom().IsAuto();
1717 }
1718 
1719 // TODO(lajava): This logic is shared by LayoutFlexibleBox, so it should be
1720 // moved to LayoutBox.
1721 DISABLE_CFI_PERF
UpdateAutoMarginsInRowAxisIfNeeded(LayoutBox & child)1722 void LayoutGrid::UpdateAutoMarginsInRowAxisIfNeeded(LayoutBox& child) {
1723   NOT_DESTROYED();
1724   DCHECK(!child.IsOutOfFlowPositioned());
1725 
1726   const Length& margin_start = child.StyleRef().MarginStartUsing(StyleRef());
1727   const Length& margin_end = child.StyleRef().MarginEndUsing(StyleRef());
1728   LayoutUnit margin_logical_width;
1729   // We should only consider computed margins if their specified value isn't
1730   // 'auto', since such computed value may come from a previous layout and may
1731   // be incorrect now.
1732   if (!margin_start.IsAuto())
1733     margin_logical_width += child.MarginStart();
1734   if (!margin_end.IsAuto())
1735     margin_logical_width += child.MarginEnd();
1736   LayoutUnit available_alignment_space =
1737       child.OverrideContainingBlockContentLogicalWidth() -
1738       child.LogicalWidth() - margin_logical_width;
1739   if (available_alignment_space <= 0)
1740     return;
1741 
1742   if (margin_start.IsAuto() && margin_end.IsAuto()) {
1743     child.SetMarginStart(available_alignment_space / 2, Style());
1744     child.SetMarginEnd(available_alignment_space / 2, Style());
1745   } else if (margin_start.IsAuto()) {
1746     child.SetMarginStart(available_alignment_space, Style());
1747   } else if (margin_end.IsAuto()) {
1748     child.SetMarginEnd(available_alignment_space, Style());
1749   }
1750 }
1751 
1752 // TODO(lajava): This logic is shared by LayoutFlexibleBox, so it should be
1753 // moved to LayoutBox.
1754 DISABLE_CFI_PERF
UpdateAutoMarginsInColumnAxisIfNeeded(LayoutBox & child)1755 void LayoutGrid::UpdateAutoMarginsInColumnAxisIfNeeded(LayoutBox& child) {
1756   NOT_DESTROYED();
1757   DCHECK(!child.IsOutOfFlowPositioned());
1758 
1759   const Length& margin_before = child.StyleRef().MarginBeforeUsing(StyleRef());
1760   const Length& margin_after = child.StyleRef().MarginAfterUsing(StyleRef());
1761   LayoutUnit margin_logical_height;
1762   // We should only consider computed margins if their specified value isn't
1763   // 'auto', since such computed value may come from a previous layout and may
1764   // be incorrect now.
1765   if (!margin_before.IsAuto())
1766     margin_logical_height += child.MarginBefore();
1767   if (!margin_after.IsAuto())
1768     margin_logical_height += child.MarginAfter();
1769   LayoutUnit available_alignment_space =
1770       child.OverrideContainingBlockContentLogicalHeight() -
1771       child.LogicalHeight() - margin_logical_height;
1772   if (available_alignment_space <= 0)
1773     return;
1774 
1775   if (margin_before.IsAuto() && margin_after.IsAuto()) {
1776     child.SetMarginBefore(available_alignment_space / 2, Style());
1777     child.SetMarginAfter(available_alignment_space / 2, Style());
1778   } else if (margin_before.IsAuto()) {
1779     child.SetMarginBefore(available_alignment_space, Style());
1780   } else if (margin_after.IsAuto()) {
1781     child.SetMarginAfter(available_alignment_space, Style());
1782   }
1783 }
1784 
1785 // TODO(lajava): This logic is shared by LayoutFlexibleBox, so it might be
1786 // refactored somehow.
SynthesizedBaselineFromBorderBox(const LayoutBox & box,LineDirectionMode direction)1787 LayoutUnit LayoutGrid::SynthesizedBaselineFromBorderBox(
1788     const LayoutBox& box,
1789     LineDirectionMode direction) {
1790   return direction == kHorizontalLine ? box.Size().Height()
1791                                       : box.Size().Width();
1792 }
1793 
BaselinePosition(FontBaseline,bool,LineDirectionMode direction,LinePositionMode mode) const1794 LayoutUnit LayoutGrid::BaselinePosition(FontBaseline,
1795                                         bool,
1796                                         LineDirectionMode direction,
1797                                         LinePositionMode mode) const {
1798   NOT_DESTROYED();
1799   DCHECK_EQ(mode, kPositionOnContainingLine);
1800   LayoutUnit baseline = FirstLineBoxBaseline();
1801   // We take border-box's bottom if no valid baseline.
1802   if (baseline == -1) {
1803     return SynthesizedBaselineFromBorderBox(*this, direction) +
1804            MarginLogicalHeight();
1805   }
1806 
1807   return baseline + BeforeMarginInLineDirection(direction);
1808 }
1809 
FirstLineBoxBaseline() const1810 LayoutUnit LayoutGrid::FirstLineBoxBaseline() const {
1811   NOT_DESTROYED();
1812   if (IsWritingModeRoot() || !grid_->HasGridItems() ||
1813       ShouldApplyLayoutContainment())
1814     return LayoutUnit(-1);
1815   const LayoutBox* baseline_child = nullptr;
1816   const LayoutBox* first_child = nullptr;
1817   bool is_baseline_aligned = false;
1818   // Finding the first grid item in grid order.
1819   for (size_t column = 0;
1820        !is_baseline_aligned && column < grid_->NumTracks(kForColumns);
1821        column++) {
1822     const GridItemList& cell = grid_->Cell(0, column);
1823     for (size_t index = 0; index < cell.size(); index++) {
1824       const LayoutBox* child = cell[index];
1825       DCHECK(!child->IsOutOfFlowPositioned());
1826       // If an item participates in baseline alignment, we select such item.
1827       if (IsBaselineAlignmentForChild(*child, kGridColumnAxis)) {
1828         // TODO (lajava): self-baseline and content-baseline alignment
1829         // still not implemented.
1830         baseline_child = child;
1831         is_baseline_aligned = true;
1832         break;
1833       }
1834       if (!baseline_child) {
1835         // Use dom order for items in the same cell.
1836         if (!first_child || (grid_->GridItemPaintOrder(*child) <
1837                              grid_->GridItemPaintOrder(*first_child)))
1838           first_child = child;
1839       }
1840     }
1841     if (!baseline_child && first_child)
1842       baseline_child = first_child;
1843   }
1844 
1845   if (!baseline_child)
1846     return LayoutUnit(-1);
1847 
1848   LayoutUnit baseline =
1849       GridLayoutUtils::IsOrthogonalChild(*this, *baseline_child)
1850           ? LayoutUnit(-1)
1851           : baseline_child->FirstLineBoxBaseline();
1852   // We take border-box's bottom if no valid baseline.
1853   if (baseline == -1) {
1854     // TODO (lajava): We should pass |direction| into
1855     // firstLineBoxBaseline and stop bailing out if we're a writing
1856     // mode root.  This would also fix some cases where the grid is
1857     // orthogonal to its container.
1858     LineDirectionMode direction =
1859         IsHorizontalWritingMode() ? kHorizontalLine : kVerticalLine;
1860     return SynthesizedBaselineFromBorderBox(*baseline_child, direction) +
1861            LogicalTopForChild(*baseline_child);
1862   }
1863 
1864   return baseline + baseline_child->LogicalTop();
1865 }
1866 
InlineBlockBaseline(LineDirectionMode direction) const1867 LayoutUnit LayoutGrid::InlineBlockBaseline(LineDirectionMode direction) const {
1868   NOT_DESTROYED();
1869   return FirstLineBoxBaseline();
1870 }
1871 
IsBaselineAlignmentForChild(const LayoutBox & child) const1872 bool LayoutGrid::IsBaselineAlignmentForChild(const LayoutBox& child) const {
1873   NOT_DESTROYED();
1874   return IsBaselineAlignmentForChild(child, kGridRowAxis) ||
1875          IsBaselineAlignmentForChild(child, kGridColumnAxis);
1876 }
1877 
IsBaselineAlignmentForChild(const LayoutBox & child,GridAxis baseline_axis) const1878 bool LayoutGrid::IsBaselineAlignmentForChild(const LayoutBox& child,
1879                                              GridAxis baseline_axis) const {
1880   NOT_DESTROYED();
1881   if (child.IsOutOfFlowPositioned())
1882     return false;
1883   ItemPosition align =
1884       SelfAlignmentForChild(baseline_axis, child).GetPosition();
1885   bool has_auto_margins = baseline_axis == kGridColumnAxis
1886                               ? HasAutoMarginsInColumnAxis(child)
1887                               : HasAutoMarginsInRowAxis(child);
1888   return IsBaselinePosition(align) && !has_auto_margins;
1889 }
1890 
ColumnAxisBaselineOffsetForChild(const LayoutBox & child) const1891 LayoutUnit LayoutGrid::ColumnAxisBaselineOffsetForChild(
1892     const LayoutBox& child) const {
1893   NOT_DESTROYED();
1894   return track_sizing_algorithm_.BaselineOffsetForChild(child, kGridColumnAxis);
1895 }
1896 
RowAxisBaselineOffsetForChild(const LayoutBox & child) const1897 LayoutUnit LayoutGrid::RowAxisBaselineOffsetForChild(
1898     const LayoutBox& child) const {
1899   NOT_DESTROYED();
1900   return track_sizing_algorithm_.BaselineOffsetForChild(child, kGridRowAxis);
1901 }
1902 
ColumnAxisPositionForChild(const LayoutBox & child) const1903 GridAxisPosition LayoutGrid::ColumnAxisPositionForChild(
1904     const LayoutBox& child) const {
1905   NOT_DESTROYED();
1906   bool has_same_writing_mode =
1907       child.StyleRef().GetWritingMode() == StyleRef().GetWritingMode();
1908   bool child_is_ltr = child.StyleRef().IsLeftToRightDirection();
1909   if (child.IsOutOfFlowPositioned() &&
1910       !HasStaticPositionForChild(child, kForRows))
1911     return kGridAxisStart;
1912 
1913   switch (AlignSelfForChild(child).GetPosition()) {
1914     case ItemPosition::kSelfStart:
1915       // TODO (lajava): Should we implement this logic in a generic utility
1916       // function?
1917       // Aligns the alignment subject to be flush with the edge of the alignment
1918       // container corresponding to the alignment subject's 'start' side in the
1919       // column axis.
1920       if (GridLayoutUtils::IsOrthogonalChild(*this, child)) {
1921         // If orthogonal writing-modes, self-start will be based on the child's
1922         // inline-axis direction (inline-start), because it's the one parallel
1923         // to the column axis.
1924         if (StyleRef().IsFlippedBlocksWritingMode())
1925           return child_is_ltr ? kGridAxisEnd : kGridAxisStart;
1926         return child_is_ltr ? kGridAxisStart : kGridAxisEnd;
1927       }
1928       // self-start is based on the child's block-flow direction. That's why we
1929       // need to check against the grid container's block-flow direction.
1930       return has_same_writing_mode ? kGridAxisStart : kGridAxisEnd;
1931     case ItemPosition::kSelfEnd:
1932       // TODO (lajava): Should we implement this logic in a generic utility
1933       // function?
1934       // Aligns the alignment subject to be flush with the edge of the alignment
1935       // container corresponding to the alignment subject's 'end' side in the
1936       // column axis.
1937       if (GridLayoutUtils::IsOrthogonalChild(*this, child)) {
1938         // If orthogonal writing-modes, self-end will be based on the child's
1939         // inline-axis direction, (inline-end) because it's the one parallel to
1940         // the column axis.
1941         if (StyleRef().IsFlippedBlocksWritingMode())
1942           return child_is_ltr ? kGridAxisStart : kGridAxisEnd;
1943         return child_is_ltr ? kGridAxisEnd : kGridAxisStart;
1944       }
1945       // self-end is based on the child's block-flow direction. That's why we
1946       // need to check against the grid container's block-flow direction.
1947       return has_same_writing_mode ? kGridAxisEnd : kGridAxisStart;
1948     case ItemPosition::kCenter:
1949       return kGridAxisCenter;
1950     // Only used in flex layout, otherwise equivalent to 'start'.
1951     case ItemPosition::kFlexStart:
1952     // Aligns the alignment subject to be flush with the alignment container's
1953     // 'start' edge (block-start) in the column axis.
1954     case ItemPosition::kStart:
1955       return kGridAxisStart;
1956     // Only used in flex layout, otherwise equivalent to 'end'.
1957     case ItemPosition::kFlexEnd:
1958     // Aligns the alignment subject to be flush with the alignment container's
1959     // 'end' edge (block-end) in the column axis.
1960     case ItemPosition::kEnd:
1961       return kGridAxisEnd;
1962     case ItemPosition::kStretch:
1963       return kGridAxisStart;
1964     case ItemPosition::kBaseline:
1965     case ItemPosition::kLastBaseline:
1966       return kGridAxisStart;
1967     case ItemPosition::kLegacy:
1968     case ItemPosition::kAuto:
1969     case ItemPosition::kNormal:
1970     case ItemPosition::kLeft:
1971     case ItemPosition::kRight:
1972       break;
1973   }
1974 
1975   NOTREACHED();
1976   return kGridAxisStart;
1977 }
1978 
RowAxisPositionForChild(const LayoutBox & child) const1979 GridAxisPosition LayoutGrid::RowAxisPositionForChild(
1980     const LayoutBox& child) const {
1981   NOT_DESTROYED();
1982   bool has_same_direction =
1983       child.StyleRef().Direction() == StyleRef().Direction();
1984   bool grid_is_ltr = StyleRef().IsLeftToRightDirection();
1985   if (child.IsOutOfFlowPositioned() &&
1986       !HasStaticPositionForChild(child, kForColumns))
1987     return kGridAxisStart;
1988 
1989   switch (JustifySelfForChild(child).GetPosition()) {
1990     case ItemPosition::kSelfStart:
1991       // TODO (lajava): Should we implement this logic in a generic utility
1992       // function?
1993       // Aligns the alignment subject to be flush with the edge of the alignment
1994       // container corresponding to the alignment subject's 'start' side in the
1995       // row axis.
1996       if (GridLayoutUtils::IsOrthogonalChild(*this, child)) {
1997         // If orthogonal writing-modes, self-start will be based on the child's
1998         // block-axis direction, because it's the one parallel to the row axis.
1999         if (child.StyleRef().IsFlippedBlocksWritingMode())
2000           return grid_is_ltr ? kGridAxisEnd : kGridAxisStart;
2001         return grid_is_ltr ? kGridAxisStart : kGridAxisEnd;
2002       }
2003       // self-start is based on the child's inline-flow direction. That's why we
2004       // need to check against the grid container's direction.
2005       return has_same_direction ? kGridAxisStart : kGridAxisEnd;
2006     case ItemPosition::kSelfEnd:
2007       // TODO (lajava): Should we implement this logic in a generic utility
2008       // function?
2009       // Aligns the alignment subject to be flush with the edge of the alignment
2010       // container corresponding to the alignment subject's 'end' side in the
2011       // row axis.
2012       if (GridLayoutUtils::IsOrthogonalChild(*this, child)) {
2013         // If orthogonal writing-modes, self-end will be based on the child's
2014         // block-axis direction, because it's the one parallel to the row axis.
2015         if (child.StyleRef().IsFlippedBlocksWritingMode())
2016           return grid_is_ltr ? kGridAxisStart : kGridAxisEnd;
2017         return grid_is_ltr ? kGridAxisEnd : kGridAxisStart;
2018       }
2019       // self-end is based on the child's inline-flow direction. That's why we
2020       // need to check against the grid container's direction.
2021       return has_same_direction ? kGridAxisEnd : kGridAxisStart;
2022     case ItemPosition::kLeft:
2023       // Aligns the alignment subject to be flush with the alignment container's
2024       // 'line-left' edge. We want the physical 'left' side, so we have to take
2025       // account, container's inline-flow direction.
2026       return grid_is_ltr ? kGridAxisStart : kGridAxisEnd;
2027     case ItemPosition::kRight:
2028       // Aligns the alignment subject to be flush with the alignment container's
2029       // 'line-right' edge. We want the physical 'right' side, so we have to
2030       // take account, container's inline-flow direction.
2031       return grid_is_ltr ? kGridAxisEnd : kGridAxisStart;
2032     case ItemPosition::kCenter:
2033       return kGridAxisCenter;
2034     // Only used in flex layout, otherwise equivalent to 'start'.
2035     case ItemPosition::kFlexStart:
2036     // Aligns the alignment subject to be flush with the alignment container's
2037     // 'start' edge (inline-start) in the row axis.
2038     case ItemPosition::kStart:
2039       return kGridAxisStart;
2040     // Only used in flex layout, otherwise equivalent to 'end'.
2041     case ItemPosition::kFlexEnd:
2042     // Aligns the alignment subject to be flush with the alignment container's
2043     // 'end' edge (inline-end) in the row axis.
2044     case ItemPosition::kEnd:
2045       return kGridAxisEnd;
2046     case ItemPosition::kStretch:
2047       return kGridAxisStart;
2048     case ItemPosition::kBaseline:
2049     case ItemPosition::kLastBaseline:
2050       return kGridAxisStart;
2051     case ItemPosition::kLegacy:
2052     case ItemPosition::kAuto:
2053     case ItemPosition::kNormal:
2054       break;
2055   }
2056 
2057   NOTREACHED();
2058   return kGridAxisStart;
2059 }
2060 
ColumnAxisOffsetForChild(const LayoutBox & child) const2061 LayoutUnit LayoutGrid::ColumnAxisOffsetForChild(const LayoutBox& child) const {
2062   NOT_DESTROYED();
2063   LayoutUnit start_of_row;
2064   LayoutUnit end_of_row;
2065   GridAreaPositionForChild(child, kForRows, start_of_row, end_of_row);
2066   LayoutUnit start_position = start_of_row + MarginBeforeForChild(child);
2067   if (HasAutoMarginsInColumnAxis(child))
2068     return start_position;
2069   GridAxisPosition axis_position = ColumnAxisPositionForChild(child);
2070   switch (axis_position) {
2071     case kGridAxisStart:
2072       return start_position + ColumnAxisBaselineOffsetForChild(child);
2073     case kGridAxisEnd:
2074     case kGridAxisCenter: {
2075       LayoutUnit column_axis_child_size =
2076           GridLayoutUtils::IsOrthogonalChild(*this, child)
2077               ? child.LogicalWidth() + child.MarginLogicalWidth()
2078               : child.LogicalHeight() + child.MarginLogicalHeight();
2079       OverflowAlignment overflow = AlignSelfForChild(child).Overflow();
2080       LayoutUnit offset_from_start_position = ComputeOverflowAlignmentOffset(
2081           overflow, end_of_row - start_of_row, column_axis_child_size);
2082       return start_position + (axis_position == kGridAxisEnd
2083                                    ? offset_from_start_position
2084                                    : offset_from_start_position / 2);
2085     }
2086   }
2087 
2088   NOTREACHED();
2089   return LayoutUnit();
2090 }
2091 
RowAxisOffsetForChild(const LayoutBox & child) const2092 LayoutUnit LayoutGrid::RowAxisOffsetForChild(const LayoutBox& child) const {
2093   NOT_DESTROYED();
2094   LayoutUnit start_of_column;
2095   LayoutUnit end_of_column;
2096   GridAreaPositionForChild(child, kForColumns, start_of_column, end_of_column);
2097   LayoutUnit start_position = start_of_column + MarginStartForChild(child);
2098   if (HasAutoMarginsInRowAxis(child))
2099     return start_position;
2100   GridAxisPosition axis_position = RowAxisPositionForChild(child);
2101   switch (axis_position) {
2102     case kGridAxisStart:
2103       return start_position + RowAxisBaselineOffsetForChild(child);
2104     case kGridAxisEnd:
2105     case kGridAxisCenter: {
2106       LayoutUnit row_axis_child_size =
2107           GridLayoutUtils::IsOrthogonalChild(*this, child)
2108               ? child.LogicalHeight() + child.MarginLogicalHeight()
2109               : child.LogicalWidth() + child.MarginLogicalWidth();
2110       OverflowAlignment overflow = JustifySelfForChild(child).Overflow();
2111       LayoutUnit offset_from_start_position = ComputeOverflowAlignmentOffset(
2112           overflow, end_of_column - start_of_column, row_axis_child_size);
2113       return start_position + (axis_position == kGridAxisEnd
2114                                    ? offset_from_start_position
2115                                    : offset_from_start_position / 2);
2116     }
2117   }
2118 
2119   NOTREACHED();
2120   return LayoutUnit();
2121 }
2122 
ResolveAutoStartGridPosition(GridTrackSizingDirection direction) const2123 LayoutUnit LayoutGrid::ResolveAutoStartGridPosition(
2124     GridTrackSizingDirection direction) const {
2125   NOT_DESTROYED();
2126   if (direction == kForRows || StyleRef().IsLeftToRightDirection())
2127     return LayoutUnit();
2128 
2129   int last_line = NumTracks(kForColumns, *grid_);
2130   ContentPosition position = StyleRef().ResolvedJustifyContentPosition(
2131       ContentAlignmentNormalBehavior());
2132   if (position == ContentPosition::kEnd)
2133     return column_positions_[last_line] - ClientLogicalWidth();
2134   if (position == ContentPosition::kStart ||
2135       StyleRef().ResolvedJustifyContentDistribution(
2136           ContentAlignmentNormalBehavior()) ==
2137           ContentDistributionType::kStretch)
2138     return column_positions_[0] - BorderAndPaddingLogicalLeft();
2139   return LayoutUnit();
2140 }
2141 
ResolveAutoEndGridPosition(GridTrackSizingDirection direction) const2142 LayoutUnit LayoutGrid::ResolveAutoEndGridPosition(
2143     GridTrackSizingDirection direction) const {
2144   NOT_DESTROYED();
2145   if (direction == kForRows)
2146     return ClientLogicalHeight();
2147   if (StyleRef().IsLeftToRightDirection())
2148     return ClientLogicalWidth();
2149 
2150   int last_line = NumTracks(kForColumns, *grid_);
2151   ContentPosition position = StyleRef().ResolvedJustifyContentPosition(
2152       ContentAlignmentNormalBehavior());
2153   if (position == ContentPosition::kEnd)
2154     return column_positions_[last_line];
2155   if (position == ContentPosition::kStart ||
2156       StyleRef().ResolvedJustifyContentDistribution(
2157           ContentAlignmentNormalBehavior()) ==
2158           ContentDistributionType::kStretch) {
2159     return column_positions_[0] - BorderAndPaddingLogicalLeft() +
2160            ClientLogicalWidth();
2161   }
2162   return ClientLogicalWidth();
2163 }
2164 
GridAreaBreadthForOutOfFlowChild(const LayoutBox & child,GridTrackSizingDirection direction)2165 LayoutUnit LayoutGrid::GridAreaBreadthForOutOfFlowChild(
2166     const LayoutBox& child,
2167     GridTrackSizingDirection direction) {
2168   NOT_DESTROYED();
2169   DCHECK(child.IsOutOfFlowPositioned());
2170   bool is_row_axis = direction == kForColumns;
2171   GridSpan span = GridPositionsResolver::ResolveGridPositionsFromStyle(
2172       StyleRef(), child.StyleRef(), direction,
2173       AutoRepeatCountForDirection(direction));
2174   if (span.IsIndefinite())
2175     return is_row_axis ? ClientLogicalWidth() : ClientLogicalHeight();
2176 
2177   size_t explicit_start = grid_->ExplicitGridStart(direction);
2178   size_t start_line = span.UntranslatedStartLine() + explicit_start;
2179   size_t end_line = span.UntranslatedEndLine() + explicit_start;
2180   size_t last_line = NumTracks(direction, *grid_);
2181   GridPosition start_position = direction == kForColumns
2182                                     ? child.StyleRef().GridColumnStart()
2183                                     : child.StyleRef().GridRowStart();
2184   GridPosition end_position = direction == kForColumns
2185                                   ? child.StyleRef().GridColumnEnd()
2186                                   : child.StyleRef().GridRowEnd();
2187 
2188   bool start_is_auto =
2189       start_position.IsAuto() || start_line < 0 || start_line > last_line;
2190   bool end_is_auto =
2191       end_position.IsAuto() || end_line < 0 || end_line > last_line;
2192 
2193   if (start_is_auto && end_is_auto)
2194     return is_row_axis ? ClientLogicalWidth() : ClientLogicalHeight();
2195 
2196   LayoutUnit start;
2197   LayoutUnit end;
2198   auto& positions = is_row_axis ? column_positions_ : row_positions_;
2199   auto& line_of_positioned_item =
2200       is_row_axis ? column_of_positioned_item_ : row_of_positioned_item_;
2201   LayoutUnit border_edge = is_row_axis ? BorderLogicalLeft() : BorderBefore();
2202   if (start_is_auto) {
2203     start = ResolveAutoStartGridPosition(direction) + border_edge;
2204   } else {
2205     line_of_positioned_item.Set(&child, start_line);
2206     start = positions[start_line];
2207   }
2208   if (end_is_auto) {
2209     end = ResolveAutoEndGridPosition(direction) + border_edge;
2210   } else {
2211     end = positions[end_line];
2212     // These vectors store line positions including gaps, but we shouldn't
2213     // consider them for the edges of the grid.
2214     if (end_line > 0 && end_line < last_line) {
2215       DCHECK(!grid_->NeedsItemsPlacement());
2216       // TODO(rego): It would be more efficient to call GridGap(direction) and
2217       // pass that value to GuttersSize(), so we could avoid the call to
2218       // available size if the gutter doesn't use percentages.
2219       end -= GuttersSize(
2220           *grid_, direction, end_line - 1, 2,
2221           is_row_axis ? AvailableLogicalWidth() : ContentLogicalHeight());
2222       end -= is_row_axis ? offset_between_columns_.distribution_offset
2223                          : offset_between_rows_.distribution_offset;
2224     }
2225   }
2226   // TODO (lajava): Is expectable that in some cases 'end' is smaller than
2227   // 'start' ?
2228   return std::max(end - start, LayoutUnit());
2229 }
2230 
LogicalOffsetForOutOfFlowChild(const LayoutBox & child,GridTrackSizingDirection direction,LayoutUnit track_breadth) const2231 LayoutUnit LayoutGrid::LogicalOffsetForOutOfFlowChild(
2232     const LayoutBox& child,
2233     GridTrackSizingDirection direction,
2234     LayoutUnit track_breadth) const {
2235   NOT_DESTROYED();
2236   DCHECK(child.IsOutOfFlowPositioned());
2237   if (HasStaticPositionForChild(child, direction))
2238     return LayoutUnit();
2239 
2240   bool is_row_axis = direction == kForColumns;
2241   bool is_flowaware_row_axis = GridLayoutUtils::FlowAwareDirectionForChild(
2242                                    *this, child, direction) == kForColumns;
2243   LayoutUnit child_position =
2244       is_flowaware_row_axis ? child.LogicalLeft() : child.LogicalTop();
2245   LayoutUnit grid_border = is_row_axis ? BorderLogicalLeft() : BorderBefore();
2246   LayoutUnit child_margin =
2247       is_flowaware_row_axis ? child.MarginLineLeft() : child.MarginBefore();
2248   LayoutUnit offset = child_position - grid_border - child_margin;
2249   if (!is_row_axis || StyleRef().IsLeftToRightDirection())
2250     return offset;
2251 
2252   LayoutUnit child_breadth =
2253       is_flowaware_row_axis
2254           ? child.LogicalWidth() + child.MarginLogicalWidth()
2255           : child.LogicalHeight() + child.MarginLogicalHeight();
2256   return track_breadth - offset - child_breadth;
2257 }
2258 
GridAreaPositionForOutOfFlowChild(const LayoutBox & child,GridTrackSizingDirection direction,LayoutUnit & start,LayoutUnit & end) const2259 void LayoutGrid::GridAreaPositionForOutOfFlowChild(
2260     const LayoutBox& child,
2261     GridTrackSizingDirection direction,
2262     LayoutUnit& start,
2263     LayoutUnit& end) const {
2264   NOT_DESTROYED();
2265   DCHECK(child.IsOutOfFlowPositioned());
2266   DCHECK(GridLayoutUtils::HasOverrideContainingBlockContentSizeForChild(
2267       child, direction));
2268   LayoutUnit track_breadth =
2269       GridLayoutUtils::OverrideContainingBlockContentSizeForChild(child,
2270                                                                   direction);
2271   bool is_row_axis = direction == kForColumns;
2272   auto& line_of_positioned_item =
2273       is_row_axis ? column_of_positioned_item_ : row_of_positioned_item_;
2274   start = is_row_axis ? BorderLogicalLeft() : BorderBefore();
2275   if (base::Optional<size_t> line = line_of_positioned_item.at(&child)) {
2276     auto& positions = is_row_axis ? column_positions_ : row_positions_;
2277     start = positions[line.value()];
2278   }
2279   start += LogicalOffsetForOutOfFlowChild(child, direction, track_breadth);
2280   end = start + track_breadth;
2281 }
2282 
GridAreaPositionForInFlowChild(const LayoutBox & child,GridTrackSizingDirection direction,LayoutUnit & start,LayoutUnit & end) const2283 void LayoutGrid::GridAreaPositionForInFlowChild(
2284     const LayoutBox& child,
2285     GridTrackSizingDirection direction,
2286     LayoutUnit& start,
2287     LayoutUnit& end) const {
2288   NOT_DESTROYED();
2289   DCHECK(!child.IsOutOfFlowPositioned());
2290   const Grid& grid = track_sizing_algorithm_.GetGrid();
2291   const GridSpan& span = grid.GridItemSpan(child, direction);
2292   // TODO (lajava): This is a common pattern, why not defining a function like
2293   // positions(direction) ?
2294   auto& positions =
2295       direction == kForColumns ? column_positions_ : row_positions_;
2296   start = positions[span.StartLine()];
2297   end = positions[span.EndLine()];
2298   // The 'positions' vector includes distribution offset (because of content
2299   // alignment) and gutters so we need to subtract them to get the actual
2300   // end position for a given track (this does not have to be done for the
2301   // last track as there are no more positions's elements after it, nor for
2302   // collapsed tracks).
2303   if (span.EndLine() < positions.size() - 1 &&
2304       !(grid.HasAutoRepeatEmptyTracks(direction) &&
2305         grid.IsEmptyAutoRepeatTrack(direction, span.EndLine())))
2306     end -= GridGap(direction) + GridItemOffset(direction);
2307 }
2308 
GridAreaPositionForChild(const LayoutBox & child,GridTrackSizingDirection direction,LayoutUnit & start,LayoutUnit & end) const2309 void LayoutGrid::GridAreaPositionForChild(const LayoutBox& child,
2310                                           GridTrackSizingDirection direction,
2311                                           LayoutUnit& start,
2312                                           LayoutUnit& end) const {
2313   NOT_DESTROYED();
2314   if (child.IsOutOfFlowPositioned())
2315     GridAreaPositionForOutOfFlowChild(child, direction, start, end);
2316   else
2317     GridAreaPositionForInFlowChild(child, direction, start, end);
2318 }
2319 
ResolveContentDistributionFallback(ContentDistributionType distribution)2320 ContentPosition static ResolveContentDistributionFallback(
2321     ContentDistributionType distribution) {
2322   switch (distribution) {
2323     case ContentDistributionType::kSpaceBetween:
2324       return ContentPosition::kStart;
2325     case ContentDistributionType::kSpaceAround:
2326       return ContentPosition::kCenter;
2327     case ContentDistributionType::kSpaceEvenly:
2328       return ContentPosition::kCenter;
2329     case ContentDistributionType::kStretch:
2330       return ContentPosition::kStart;
2331     case ContentDistributionType::kDefault:
2332       return ContentPosition::kNormal;
2333   }
2334 
2335   NOTREACHED();
2336   return ContentPosition::kNormal;
2337 }
2338 
ComputeContentDistributionOffset(ContentAlignmentData & offset,const LayoutUnit & available_free_space,ContentPosition & fallback_position,ContentDistributionType distribution,unsigned number_of_grid_tracks)2339 static void ComputeContentDistributionOffset(
2340     ContentAlignmentData& offset,
2341     const LayoutUnit& available_free_space,
2342     ContentPosition& fallback_position,
2343     ContentDistributionType distribution,
2344     unsigned number_of_grid_tracks) {
2345   if (distribution != ContentDistributionType::kDefault &&
2346       fallback_position == ContentPosition::kNormal)
2347     fallback_position = ResolveContentDistributionFallback(distribution);
2348 
2349   // Initialize to an invalid offset.
2350   offset.position_offset = LayoutUnit(-1);
2351   offset.distribution_offset = LayoutUnit(-1);
2352   if (available_free_space <= 0)
2353     return;
2354 
2355   LayoutUnit position_offset;
2356   LayoutUnit distribution_offset;
2357   switch (distribution) {
2358     case ContentDistributionType::kSpaceBetween:
2359       if (number_of_grid_tracks < 2)
2360         return;
2361       distribution_offset = available_free_space / (number_of_grid_tracks - 1);
2362       position_offset = LayoutUnit();
2363       break;
2364     case ContentDistributionType::kSpaceAround:
2365       if (number_of_grid_tracks < 1)
2366         return;
2367       distribution_offset = available_free_space / number_of_grid_tracks;
2368       position_offset = distribution_offset / 2;
2369       break;
2370     case ContentDistributionType::kSpaceEvenly:
2371       distribution_offset = available_free_space / (number_of_grid_tracks + 1);
2372       position_offset = distribution_offset;
2373       break;
2374     case ContentDistributionType::kStretch:
2375     case ContentDistributionType::kDefault:
2376       return;
2377     default:
2378       NOTREACHED();
2379       return;
2380   }
2381 
2382   offset.position_offset = position_offset;
2383   offset.distribution_offset = distribution_offset;
2384 }
2385 
ContentAlignment(GridTrackSizingDirection direction) const2386 StyleContentAlignmentData LayoutGrid::ContentAlignment(
2387     GridTrackSizingDirection direction) const {
2388   NOT_DESTROYED();
2389   return direction == kForColumns ? StyleRef().ResolvedJustifyContent(
2390                                         ContentAlignmentNormalBehavior())
2391                                   : StyleRef().ResolvedAlignContent(
2392                                         ContentAlignmentNormalBehavior());
2393 }
2394 
ComputeContentPositionAndDistributionOffset(GridTrackSizingDirection direction,const LayoutUnit & available_free_space,unsigned number_of_grid_tracks)2395 void LayoutGrid::ComputeContentPositionAndDistributionOffset(
2396     GridTrackSizingDirection direction,
2397     const LayoutUnit& available_free_space,
2398     unsigned number_of_grid_tracks) {
2399   NOT_DESTROYED();
2400   auto& offset =
2401       direction == kForColumns ? offset_between_columns_ : offset_between_rows_;
2402   StyleContentAlignmentData content_alignment_data =
2403       ContentAlignment(direction);
2404   ContentPosition position = content_alignment_data.GetPosition();
2405   // If <content-distribution> value can't be applied, 'position' will become
2406   // the associated <content-position> fallback value.
2407   ComputeContentDistributionOffset(offset, available_free_space, position,
2408                                    content_alignment_data.Distribution(),
2409                                    number_of_grid_tracks);
2410   if (offset.IsValid())
2411     return;
2412 
2413   // TODO (lajava): Default value for overflow isn't exaclty as 'unsafe'.
2414   // https://drafts.csswg.org/css-align/#overflow-values
2415   if (available_free_space == 0 ||
2416       (available_free_space < 0 &&
2417        content_alignment_data.Overflow() == OverflowAlignment::kSafe)) {
2418     offset.position_offset = LayoutUnit();
2419     offset.distribution_offset = LayoutUnit();
2420     return;
2421   }
2422 
2423   LayoutUnit position_offset;
2424   bool is_row_axis = direction == kForColumns;
2425   switch (position) {
2426     case ContentPosition::kLeft:
2427       DCHECK(is_row_axis);
2428       position_offset = LayoutUnit();
2429       break;
2430     case ContentPosition::kRight:
2431       DCHECK(is_row_axis);
2432       position_offset = available_free_space;
2433       break;
2434     case ContentPosition::kCenter:
2435       position_offset = available_free_space / 2;
2436       break;
2437     // Only used in flex layout, for other layout, it's equivalent to 'End'.
2438     case ContentPosition::kFlexEnd:
2439       U_FALLTHROUGH;
2440     case ContentPosition::kEnd:
2441       if (is_row_axis) {
2442         position_offset = StyleRef().IsLeftToRightDirection()
2443                               ? available_free_space
2444                               : LayoutUnit();
2445       } else {
2446         position_offset = available_free_space;
2447       }
2448       break;
2449     // Only used in flex layout, for other layout, it's equivalent to 'Start'.
2450     case ContentPosition::kFlexStart:
2451       U_FALLTHROUGH;
2452     case ContentPosition::kStart:
2453       if (is_row_axis) {
2454         position_offset = StyleRef().IsLeftToRightDirection()
2455                               ? LayoutUnit()
2456                               : available_free_space;
2457       } else {
2458         position_offset = LayoutUnit();
2459       }
2460       break;
2461     case ContentPosition::kBaseline:
2462       U_FALLTHROUGH;
2463     case ContentPosition::kLastBaseline:
2464       // FIXME: These two require implementing Baseline Alignment. For now, we
2465       // always 'start' align the child. crbug.com/234191
2466       if (is_row_axis) {
2467         position_offset = StyleRef().IsLeftToRightDirection()
2468                               ? LayoutUnit()
2469                               : available_free_space;
2470       } else {
2471         position_offset = LayoutUnit();
2472       }
2473       break;
2474     case ContentPosition::kNormal:
2475       U_FALLTHROUGH;
2476     default:
2477       NOTREACHED();
2478       return;
2479   }
2480 
2481   offset.position_offset = position_offset;
2482   offset.distribution_offset = LayoutUnit();
2483 }
2484 
TranslateOutOfFlowRTLCoordinate(const LayoutBox & child,LayoutUnit coordinate) const2485 LayoutUnit LayoutGrid::TranslateOutOfFlowRTLCoordinate(
2486     const LayoutBox& child,
2487     LayoutUnit coordinate) const {
2488   NOT_DESTROYED();
2489   DCHECK(child.IsOutOfFlowPositioned());
2490   DCHECK(!StyleRef().IsLeftToRightDirection());
2491 
2492   if (column_of_positioned_item_.at(&child))
2493     return TranslateRTLCoordinate(coordinate);
2494 
2495   return BorderLogicalLeft() + BorderLogicalRight() + ClientLogicalWidth() -
2496          coordinate;
2497 }
2498 
TranslateRTLCoordinate(LayoutUnit coordinate) const2499 LayoutUnit LayoutGrid::TranslateRTLCoordinate(LayoutUnit coordinate) const {
2500   NOT_DESTROYED();
2501   DCHECK(!StyleRef().IsLeftToRightDirection());
2502 
2503   LayoutUnit alignment_offset = column_positions_[0];
2504   LayoutUnit right_grid_edge_position =
2505       column_positions_[column_positions_.size() - 1];
2506   return right_grid_edge_position + alignment_offset - coordinate;
2507 }
2508 
2509 // TODO: SetLogicalPositionForChild has only one caller, consider its
2510 // refactoring in the future.
SetLogicalPositionForChild(LayoutBox & child) const2511 void LayoutGrid::SetLogicalPositionForChild(LayoutBox& child) const {
2512   NOT_DESTROYED();
2513   // "In the positioning phase [...] calculations are performed according to the
2514   // writing mode of the containing block of the box establishing the orthogonal
2515   // flow." However, 'setLogicalPosition' will only take into account the
2516   // child's writing-mode, so the position may need to be transposed.
2517   LayoutPoint child_location(LogicalOffsetForChild(child, kForColumns),
2518                              LogicalOffsetForChild(child, kForRows));
2519   child.SetLogicalLocation(GridLayoutUtils::IsOrthogonalChild(*this, child)
2520                                ? child_location.TransposedPoint()
2521                                : child_location);
2522 }
2523 
SetLogicalOffsetForChild(LayoutBox & child,GridTrackSizingDirection direction) const2524 void LayoutGrid::SetLogicalOffsetForChild(
2525     LayoutBox& child,
2526     GridTrackSizingDirection direction) const {
2527   NOT_DESTROYED();
2528   if (!child.IsGridItem() && HasStaticPositionForChild(child, direction))
2529     return;
2530   // 'SetLogicalLeft' and 'SetLogicalTop' only take into account the child's
2531   // writing-mode, that's why 'FlowAwareDirectionForChild' is needed.
2532   if (GridLayoutUtils::FlowAwareDirectionForChild(*this, child, direction) ==
2533       kForColumns)
2534     child.SetLogicalLeft(LogicalOffsetForChild(child, direction));
2535   else
2536     child.SetLogicalTop(LogicalOffsetForChild(child, direction));
2537 }
2538 
LogicalOffsetForChild(const LayoutBox & child,GridTrackSizingDirection direction) const2539 LayoutUnit LayoutGrid::LogicalOffsetForChild(
2540     const LayoutBox& child,
2541     GridTrackSizingDirection direction) const {
2542   NOT_DESTROYED();
2543   if (direction == kForRows) {
2544     return ColumnAxisOffsetForChild(child);
2545   }
2546   LayoutUnit row_axis_offset = RowAxisOffsetForChild(child);
2547   // We stored column_position_'s data ignoring the direction, hence we might
2548   // need now to translate positions from RTL to LTR, as it's more convenient
2549   // for painting.
2550   if (!StyleRef().IsLeftToRightDirection()) {
2551     row_axis_offset =
2552         (child.IsOutOfFlowPositioned()
2553              ? TranslateOutOfFlowRTLCoordinate(child, row_axis_offset)
2554              : TranslateRTLCoordinate(row_axis_offset)) -
2555         (GridLayoutUtils::IsOrthogonalChild(*this, child)
2556              ? child.LogicalHeight()
2557              : child.LogicalWidth());
2558   }
2559   return row_axis_offset;
2560 }
2561 
GridAreaLogicalPosition(const GridArea & area) const2562 LayoutPoint LayoutGrid::GridAreaLogicalPosition(const GridArea& area) const {
2563   NOT_DESTROYED();
2564   LayoutUnit column_axis_offset = row_positions_[area.rows.StartLine()];
2565   LayoutUnit row_axis_offset = column_positions_[area.columns.StartLine()];
2566 
2567   // See comment in findChildLogicalPosition() about why we need sometimes to
2568   // translate from RTL to LTR the rowAxisOffset coordinate.
2569   return LayoutPoint(StyleRef().IsLeftToRightDirection()
2570                          ? row_axis_offset
2571                          : TranslateRTLCoordinate(row_axis_offset),
2572                      column_axis_offset);
2573 }
2574 
PaintChildren(const PaintInfo & paint_info,const PhysicalOffset & paint_offset) const2575 void LayoutGrid::PaintChildren(const PaintInfo& paint_info,
2576                                const PhysicalOffset& paint_offset) const {
2577   NOT_DESTROYED();
2578   DCHECK(!grid_->NeedsItemsPlacement());
2579   if (grid_->HasGridItems()) {
2580     BlockPainter(*this).PaintChildrenAtomically(grid_->GetOrderIterator(),
2581                                                 paint_info);
2582   }
2583 }
2584 
CachedHasDefiniteLogicalHeight() const2585 bool LayoutGrid::CachedHasDefiniteLogicalHeight() const {
2586   NOT_DESTROYED();
2587   SECURITY_DCHECK(has_definite_logical_height_);
2588   return has_definite_logical_height_.value();
2589 }
2590 
NonCollapsedTracks(GridTrackSizingDirection direction) const2591 size_t LayoutGrid::NonCollapsedTracks(
2592     GridTrackSizingDirection direction) const {
2593   NOT_DESTROYED();
2594   auto& tracks = track_sizing_algorithm_.Tracks(direction);
2595   size_t number_of_tracks = tracks.size();
2596   bool has_collapsed_tracks = grid_->HasAutoRepeatEmptyTracks(direction);
2597   size_t number_of_collapsed_tracks =
2598       has_collapsed_tracks ? grid_->AutoRepeatEmptyTracks(direction)->size()
2599                            : 0;
2600   return number_of_tracks - number_of_collapsed_tracks;
2601 }
2602 
NumTracks(GridTrackSizingDirection direction,const Grid & grid) const2603 size_t LayoutGrid::NumTracks(GridTrackSizingDirection direction,
2604                              const Grid& grid) const {
2605   NOT_DESTROYED();
2606   // Due to limitations in our internal representation, we cannot know the
2607   // number of columns from m_grid *if* there is no row (because m_grid would be
2608   // empty). That's why in that case we need to get it from the style. Note that
2609   // we know for sure that there are't any implicit tracks, because not having
2610   // rows implies that there are no "normal" children (out-of-flow children are
2611   // not stored in m_grid).
2612   DCHECK(!grid.NeedsItemsPlacement());
2613   if (direction == kForRows)
2614     return grid.NumTracks(kForRows);
2615 
2616   return grid.NumTracks(kForRows)
2617              ? grid.NumTracks(kForColumns)
2618              : GridPositionsResolver::ExplicitGridColumnCount(
2619                    StyleRef(), grid.AutoRepeatTracks(kForColumns));
2620 }
2621 
ExplicitGridEndForDirection(GridTrackSizingDirection direction) const2622 size_t LayoutGrid::ExplicitGridEndForDirection(
2623     GridTrackSizingDirection direction) const {
2624   NOT_DESTROYED();
2625   size_t leading = ExplicitGridStartForDirection(direction);
2626 
2627   if (direction == kForRows) {
2628     return leading + GridPositionsResolver::ExplicitGridRowCount(
2629                          StyleRef(), grid_->AutoRepeatTracks(direction));
2630   }
2631 
2632   return leading + GridPositionsResolver::ExplicitGridColumnCount(
2633                        StyleRef(), grid_->AutoRepeatTracks(direction));
2634 }
2635 
GridItemOffset(GridTrackSizingDirection direction) const2636 LayoutUnit LayoutGrid::GridItemOffset(
2637     GridTrackSizingDirection direction) const {
2638   NOT_DESTROYED();
2639   return direction == kForRows ? offset_between_rows_.distribution_offset
2640                                : offset_between_columns_.distribution_offset;
2641 }
2642 
2643 }  // namespace blink
2644