source: webkit/trunk/Source/WebCore/rendering/GridTrackSizingAlgorithm.h

Last change on this file was 292973, checked in by Matt Woodrow, 3 years ago

Implement support for aligning baselines through subgrids
https://bugs.webkit.org/show_bug.cgi?id=238643

Reviewed by Javier Fernandez.

LayoutTests/imported/w3c:

  • web-platform-tests/css/css-grid/subgrid/baseline-002-expected.html: Added.
  • web-platform-tests/css/css-grid/subgrid/baseline-002.html: Added.
  • web-platform-tests/css/css-grid/subgrid/baseline-003-expected.html: Added.
  • web-platform-tests/css/css-grid/subgrid/baseline-003.html: Added.
  • web-platform-tests/css/css-grid/subgrid/baseline-004-expected.html: Added.
  • web-platform-tests/css/css-grid/subgrid/baseline-004.html: Added.
  • web-platform-tests/css/css-grid/subgrid/baseline-005-expected.html: Added.
  • web-platform-tests/css/css-grid/subgrid/baseline-005.html: Added.

Added new WPT variants of the baseline tests, for the case where the introspected subgrid
has padding that affects the baseline position, and for the case where the subgrid uses an
orthogonal writing mode.

Source/WebCore:

Implement baseline sharing recursion into subgrids

Tests: imported/w3c/web-platform-tests/css/css-grid/subgrid/baseline-002.html

imported/w3c/web-platform-tests/css/css-grid/subgrid/baseline-003.html
imported/w3c/web-platform-tests/css/css-grid/subgrid/baseline-004.html
imported/w3c/web-platform-tests/css/css-grid/subgrid/baseline-005.html

  • rendering/GridBaselineAlignment.cpp:

(WebCore::GridBaselineAlignment::ascentForChild const):
(WebCore::GridBaselineAlignment::descentForChild const):
(WebCore::GridBaselineAlignment::updateBaselineAlignmentContext):
(WebCore::BaselineGroup::BaselineGroup):
(WebCore::BaselineGroup::update):
(WebCore::BaselineContext::BaselineContext):
(WebCore::BaselineContext::updateSharedGroup):

  • rendering/GridBaselineAlignment.h:

(WebCore::BaselineGroup::maxAscent const):
(WebCore::BaselineGroup::maxDescent const): Deleted.

  • rendering/GridLayoutFunctions.h:
  • rendering/GridTrackSizingAlgorithm.cpp:

(WebCore::GridTrackSizingAlgorithm::canParticipateInBaselineAlignment const):
(WebCore::GridTrackSizingAlgorithm::updateBaselineAlignmentContext):
(WebCore::GridTrackSizingAlgorithm::baselineOffsetForChild const):
(WebCore::GridTrackSizingAlgorithm::cacheBaselineAlignedItem):

  • rendering/GridTrackSizingAlgorithm.h:
  • rendering/RenderGrid.cpp:

(WebCore::cacheBaselineAlignedChildren):
(WebCore::RenderGrid::computeIntrinsicLogicalWidths const):
(WebCore::RenderGrid::performGridItemsPreLayout const):
(WebCore::RenderGrid::alignSelfForChild const):
(WebCore::RenderGrid::justifySelfForChild const):
(WebCore::RenderGrid::columnAxisBaselineOffsetForChild const):
(WebCore::RenderGrid::rowAxisBaselineOffsetForChild const):

Moves the code for collecting baseline aligned children into a shared helper function, and adds
support for recursing into subgrid children (restricted to the axes that subgrid was applied).

Fixes align/justifySelfForChild to check if the child is a subgrid and overrides the result to 'stretch', so
that we're correctly stretching subgrids, not the children of subgrids (covered by new tests).

  • Property svn:eol-style set to LF
File size: 13.8 KB
Line 
1/*
2 * Copyright (C) 2017 Igalia S.L.
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 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#pragma once
26
27#include "Grid.h"
28#include "GridBaselineAlignment.h"
29#include "GridTrackSize.h"
30#include "LayoutSize.h"
31
32namespace WebCore {
33
34static const int infinity = -1;
35
36enum SizingOperation { TrackSizing, IntrinsicSizeComputation };
37
38enum class TrackSizeComputationVariant : uint8_t {
39 NotCrossingFlexibleTracks,
40 CrossingFlexibleTracks,
41};
42
43enum TrackSizeComputationPhase {
44 ResolveIntrinsicMinimums,
45 ResolveContentBasedMinimums,
46 ResolveMaxContentMinimums,
47 ResolveIntrinsicMaximums,
48 ResolveMaxContentMaximums,
49 MaximizeTracks,
50};
51
52enum class SpaceDistributionLimit : uint8_t {
53 UpToGrowthLimit,
54 BeyondGrowthLimit,
55};
56
57class GridTrackSizingAlgorithmStrategy;
58class GridItemWithSpan;
59
60class GridTrack {
61public:
62 GridTrack() = default;
63
64 const LayoutUnit& baseSize() const;
65 void setBaseSize(LayoutUnit);
66
67 const LayoutUnit& growthLimit() const;
68 bool growthLimitIsInfinite() const { return m_growthLimit == infinity; }
69 void setGrowthLimit(LayoutUnit);
70
71 bool infiniteGrowthPotential() const { return growthLimitIsInfinite() || m_infinitelyGrowable; }
72 const LayoutUnit& growthLimitIfNotInfinite() const;
73
74 const LayoutUnit& plannedSize() const { return m_plannedSize; }
75 void setPlannedSize(LayoutUnit plannedSize) { m_plannedSize = plannedSize; }
76
77 const LayoutUnit& tempSize() const { return m_tempSize; }
78 void setTempSize(const LayoutUnit&);
79 void growTempSize(const LayoutUnit&);
80
81 bool infinitelyGrowable() const { return m_infinitelyGrowable; }
82 void setInfinitelyGrowable(bool infinitelyGrowable) { m_infinitelyGrowable = infinitelyGrowable; }
83
84 void setGrowthLimitCap(std::optional<LayoutUnit>);
85 std::optional<LayoutUnit> growthLimitCap() const { return m_growthLimitCap; }
86
87 const GridTrackSize& cachedTrackSize() const { return *m_cachedTrackSize; }
88 void setCachedTrackSize(const GridTrackSize&);
89
90private:
91 bool isGrowthLimitBiggerThanBaseSize() const { return growthLimitIsInfinite() || m_growthLimit >= m_baseSize; }
92
93 void ensureGrowthLimitIsBiggerThanBaseSize();
94
95 LayoutUnit m_baseSize { 0 };
96 LayoutUnit m_growthLimit { 0 };
97 LayoutUnit m_plannedSize { 0 };
98 LayoutUnit m_tempSize { 0 };
99 std::optional<LayoutUnit> m_growthLimitCap;
100 bool m_infinitelyGrowable { false };
101 std::optional<GridTrackSize> m_cachedTrackSize;
102};
103
104class GridTrackSizingAlgorithm final {
105 friend class GridTrackSizingAlgorithmStrategy;
106
107public:
108 GridTrackSizingAlgorithm(const RenderGrid* renderGrid, Grid& grid)
109 : m_grid(grid)
110 , m_renderGrid(renderGrid)
111 , m_sizingState(ColumnSizingFirstIteration)
112 {
113 }
114
115 void setup(GridTrackSizingDirection, unsigned numTracks, SizingOperation, std::optional<LayoutUnit> availableSpace);
116 void run();
117 void reset();
118
119 // Required by RenderGrid. Try to minimize the exposed surface.
120 const Grid& grid() const { return m_grid; }
121 // FIXME (jfernandez): We should remove any public getter for this attribute
122 // and encapsulate any access in the algorithm class.
123 Grid& mutableGrid() const { return m_grid; }
124
125 const RenderGrid* renderGrid() const { return m_renderGrid; };
126
127 LayoutUnit minContentSize() const { return m_minContentSize; };
128 LayoutUnit maxContentSize() const { return m_maxContentSize; };
129
130 LayoutUnit baselineOffsetForChild(const RenderBox&, GridAxis) const;
131 std::optional<LayoutUnit> estimatedGridAreaBreadthForChild(const RenderBox&, GridTrackSizingDirection) const;
132
133 void cacheBaselineAlignedItem(const RenderBox&, GridAxis);
134 void copyBaselineItemsCache(const GridTrackSizingAlgorithm&, GridAxis);
135 void clearBaselineItemsCache();
136
137 Vector<GridTrack>& tracks(GridTrackSizingDirection direction) { return direction == ForColumns ? m_columns : m_rows; }
138 const Vector<GridTrack>& tracks(GridTrackSizingDirection direction) const { return direction == ForColumns ? m_columns : m_rows; }
139
140 std::optional<LayoutUnit> freeSpace(GridTrackSizingDirection direction) const { return direction == ForColumns ? m_freeSpaceColumns : m_freeSpaceRows; }
141 void setFreeSpace(GridTrackSizingDirection, std::optional<LayoutUnit>);
142
143 std::optional<LayoutUnit> availableSpace(GridTrackSizingDirection direction) const { return direction == ForColumns ? m_availableSpaceColumns : m_availableSpaceRows; }
144 void setAvailableSpace(GridTrackSizingDirection, std::optional<LayoutUnit>);
145
146 LayoutUnit computeTrackBasedSize() const;
147
148 bool hasAnyPercentSizedRowsIndefiniteHeight() const { return m_hasPercentSizedRowsIndefiniteHeight; }
149 bool hasAnyFlexibleMaxTrackBreadth() const { return m_hasFlexibleMaxTrackBreadth; }
150 bool hasAnyBaselineAlignmentItem() const { return !m_columnBaselineItemsMap.isEmpty() || !m_rowBaselineItemsMap.isEmpty(); }
151
152#if ASSERT_ENABLED
153 bool tracksAreWiderThanMinTrackBreadth() const;
154#endif
155
156private:
157 std::optional<LayoutUnit> availableSpace() const;
158 bool isRelativeGridLengthAsAuto(const GridLength&, GridTrackSizingDirection) const;
159 GridTrackSize calculateGridTrackSize(GridTrackSizingDirection, unsigned translatedIndex) const;
160 const GridTrackSize& rawGridTrackSize(GridTrackSizingDirection, unsigned translatedIndex) const;
161
162 // Helper methods for step 1. initializeTrackSizes().
163 LayoutUnit initialBaseSize(const GridTrackSize&) const;
164 LayoutUnit initialGrowthLimit(const GridTrackSize&, LayoutUnit baseSize) const;
165
166 // Helper methods for step 2. resolveIntrinsicTrackSizes().
167 void sizeTrackToFitNonSpanningItem(const GridSpan&, RenderBox& gridItem, GridTrack&);
168 bool spanningItemCrossesFlexibleSizedTracks(const GridSpan&) const;
169 typedef struct GridItemsSpanGroupRange GridItemsSpanGroupRange;
170 template <TrackSizeComputationVariant variant, TrackSizeComputationPhase phase> void increaseSizesToAccommodateSpanningItems(const GridItemsSpanGroupRange& gridItemsWithSpan);
171 template <TrackSizeComputationVariant variant> void increaseSizesToAccommodateSpanningItems(const GridItemsSpanGroupRange& gridItemsWithSpan);
172 LayoutUnit itemSizeForTrackSizeComputationPhase(TrackSizeComputationPhase, RenderBox&) const;
173 template <TrackSizeComputationVariant variant, TrackSizeComputationPhase phase> void distributeSpaceToTracks(Vector<GridTrack*>& tracks, Vector<GridTrack*>* growBeyondGrowthLimitsTracks, LayoutUnit& freeSpace) const;
174
175 std::optional<LayoutUnit> gridAreaBreadthForChild(const RenderBox&, GridTrackSizingDirection) const;
176
177 void computeBaselineAlignmentContext();
178 void updateBaselineAlignmentContext(const RenderBox&, GridAxis);
179 bool canParticipateInBaselineAlignment(const RenderBox&, GridAxis) const;
180 bool participateInBaselineAlignment(const RenderBox&, GridAxis) const;
181
182 bool isIntrinsicSizedGridArea(const RenderBox&, GridAxis) const;
183 void computeGridContainerIntrinsicSizes();
184
185 // Helper methods for step 4. Strech flexible tracks.
186 typedef HashSet<unsigned, DefaultHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> TrackIndexSet;
187 double computeFlexFactorUnitSize(const Vector<GridTrack>& tracks, double flexFactorSum, LayoutUnit& leftOverSpace, const Vector<unsigned, 8>& flexibleTracksIndexes, std::unique_ptr<TrackIndexSet> tracksToTreatAsInflexible = nullptr) const;
188 void computeFlexSizedTracksGrowth(double flexFraction, Vector<LayoutUnit>& increments, LayoutUnit& totalGrowth) const;
189 double findFrUnitSize(const GridSpan& tracksSpan, LayoutUnit leftOverSpace) const;
190
191 // Track sizing algorithm steps. Note that the "Maximize Tracks" step is done
192 // entirely inside the strategies, that's why we don't need an additional
193 // method at thise level.
194 void initializeTrackSizes();
195 void resolveIntrinsicTrackSizes();
196 void stretchFlexibleTracks(std::optional<LayoutUnit> freeSpace);
197 void stretchAutoTracks();
198
199 void accumulateIntrinsicSizesForTrack(GridTrack&, GridIterator&, Vector<GridItemWithSpan>& itemsSortedByIncreasingSpan, Vector<GridItemWithSpan>& itemsCrossingFlexibleTracks, HashSet<RenderBox*>& itemsSet);
200
201 bool copyUsedTrackSizesForSubgrid();
202
203 // State machine.
204 void advanceNextState();
205 bool isValidTransition() const;
206
207 // Data.
208 bool wasSetup() const { return !!m_strategy; }
209 bool m_needsSetup { true };
210 bool m_hasPercentSizedRowsIndefiniteHeight { false };
211 bool m_hasFlexibleMaxTrackBreadth { false };
212 std::optional<LayoutUnit> m_availableSpaceRows;
213 std::optional<LayoutUnit> m_availableSpaceColumns;
214
215 std::optional<LayoutUnit> m_freeSpaceColumns;
216 std::optional<LayoutUnit> m_freeSpaceRows;
217
218 // We need to keep both alive in order to properly size grids with orthogonal
219 // writing modes.
220 Vector<GridTrack> m_columns;
221 Vector<GridTrack> m_rows;
222 Vector<unsigned> m_contentSizedTracksIndex;
223 Vector<unsigned> m_flexibleSizedTracksIndex;
224 Vector<unsigned> m_autoSizedTracksForStretchIndex;
225
226 GridTrackSizingDirection m_direction;
227 SizingOperation m_sizingOperation;
228
229 Grid& m_grid;
230
231 const RenderGrid* m_renderGrid;
232 std::unique_ptr<GridTrackSizingAlgorithmStrategy> m_strategy;
233
234 // The track sizing algorithm is used for both layout and intrinsic size
235 // computation. We're normally just interested in intrinsic inline sizes
236 // (a.k.a widths in most of the cases) for the computeIntrinsicLogicalWidths()
237 // computations. That's why we don't need to keep around different values for
238 // rows/columns.
239 LayoutUnit m_minContentSize;
240 LayoutUnit m_maxContentSize;
241
242 enum SizingState {
243 ColumnSizingFirstIteration,
244 ColumnSizingExtraIterationForSizeContainment,
245 RowSizingFirstIteration,
246 RowSizingExtraIterationForSizeContainment,
247 ColumnSizingSecondIteration,
248 RowSizingSecondIteration
249 };
250 SizingState m_sizingState;
251
252 GridBaselineAlignment m_baselineAlignment;
253 typedef HashMap<const RenderBox*, bool> BaselineItemsCache;
254 BaselineItemsCache m_columnBaselineItemsMap;
255 BaselineItemsCache m_rowBaselineItemsMap;
256
257 // This is a RAII class used to ensure that the track sizing algorithm is
258 // executed as it is suppossed to be, i.e., first resolve columns and then
259 // rows. Only if required a second iteration is run following the same order,
260 // first columns and then rows.
261 class StateMachine {
262 public:
263 StateMachine(GridTrackSizingAlgorithm&);
264 ~StateMachine();
265
266 private:
267 GridTrackSizingAlgorithm& m_algorithm;
268 };
269};
270
271class GridTrackSizingAlgorithmStrategy {
272 WTF_MAKE_FAST_ALLOCATED;
273public:
274 virtual LayoutUnit minContentForChild(RenderBox&) const;
275 LayoutUnit maxContentForChild(RenderBox&) const;
276 LayoutUnit minSizeForChild(RenderBox&) const;
277
278 virtual ~GridTrackSizingAlgorithmStrategy() = default;
279
280 virtual void maximizeTracks(Vector<GridTrack>&, std::optional<LayoutUnit>& freeSpace) = 0;
281 virtual double findUsedFlexFraction(Vector<unsigned>& flexibleSizedTracksIndex, GridTrackSizingDirection, std::optional<LayoutUnit> initialFreeSpace) const = 0;
282 virtual bool recomputeUsedFlexFractionIfNeeded(double& flexFraction, LayoutUnit& totalGrowth) const = 0;
283 virtual LayoutUnit freeSpaceForStretchAutoTracksStep() const = 0;
284 virtual bool isComputingSizeContainment() const = 0;
285 virtual bool isComputingInlineSizeContainment() const = 0;
286
287protected:
288 GridTrackSizingAlgorithmStrategy(GridTrackSizingAlgorithm& algorithm)
289 : m_algorithm(algorithm) { }
290
291 virtual LayoutUnit minLogicalSizeForChild(RenderBox&, const Length& childMinSize, std::optional<LayoutUnit> availableSize) const;
292 virtual void layoutGridItemForMinSizeComputation(RenderBox&, bool overrideSizeHasChanged) const = 0;
293
294 LayoutUnit logicalHeightForChild(RenderBox&) const;
295 bool updateOverridingContainingBlockContentSizeForChild(RenderBox&, GridTrackSizingDirection, std::optional<LayoutUnit> = std::nullopt) const;
296
297 // GridTrackSizingAlgorithm accessors for subclasses.
298 LayoutUnit computeTrackBasedSize() const { return m_algorithm.computeTrackBasedSize(); }
299 GridTrackSizingDirection direction() const { return m_algorithm.m_direction; }
300 double findFrUnitSize(const GridSpan& tracksSpan, LayoutUnit leftOverSpace) const { return m_algorithm.findFrUnitSize(tracksSpan, leftOverSpace); }
301 void distributeSpaceToTracks(Vector<GridTrack*>& tracks, LayoutUnit& availableLogicalSpace) const { m_algorithm.distributeSpaceToTracks<TrackSizeComputationVariant::NotCrossingFlexibleTracks, MaximizeTracks>(tracks, nullptr, availableLogicalSpace); }
302 const RenderGrid* renderGrid() const { return m_algorithm.m_renderGrid; }
303 std::optional<LayoutUnit> availableSpace() const { return m_algorithm.availableSpace(); }
304
305 GridTrackSizingAlgorithm& m_algorithm;
306};
307
308} // namespace WebCore
Note: See TracBrowser for help on using the repository browser.