OLD | NEW |
| (Empty) |
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 "config.h" | |
27 #include "core/rendering/RenderGrid.h" | |
28 | |
29 #include "core/layout/Layer.h" | |
30 #include "core/layout/TextAutosizer.h" | |
31 #include "core/layout/style/GridCoordinate.h" | |
32 #include "core/layout/style/LayoutStyle.h" | |
33 #include "core/paint/GridPainter.h" | |
34 #include "core/rendering/RenderView.h" | |
35 #include "platform/LengthFunctions.h" | |
36 | |
37 namespace blink { | |
38 | |
39 static const int infinity = -1; | |
40 | |
41 class GridTrack { | |
42 public: | |
43 GridTrack() | |
44 : m_baseSize(0) | |
45 , m_growthLimit(0) | |
46 , m_plannedIncrease(0) | |
47 { | |
48 } | |
49 | |
50 const LayoutUnit& baseSize() const | |
51 { | |
52 ASSERT(isGrowthLimitBiggerThanBaseSize()); | |
53 return m_baseSize; | |
54 } | |
55 | |
56 const LayoutUnit& growthLimit() const | |
57 { | |
58 ASSERT(isGrowthLimitBiggerThanBaseSize()); | |
59 return m_growthLimit; | |
60 } | |
61 | |
62 void setBaseSize(LayoutUnit baseSize) | |
63 { | |
64 m_baseSize = baseSize; | |
65 ensureGrowthLimitIsBiggerThanBaseSize(); | |
66 } | |
67 | |
68 void setGrowthLimit(LayoutUnit growthLimit) | |
69 { | |
70 m_growthLimit = growthLimit; | |
71 ensureGrowthLimitIsBiggerThanBaseSize(); | |
72 } | |
73 | |
74 void growBaseSize(LayoutUnit growth) | |
75 { | |
76 ASSERT(growth >= 0); | |
77 m_baseSize += growth; | |
78 ensureGrowthLimitIsBiggerThanBaseSize(); | |
79 } | |
80 | |
81 void growGrowthLimit(LayoutUnit growth) | |
82 { | |
83 ASSERT(growth >= 0); | |
84 if (m_growthLimit == infinity) | |
85 m_growthLimit = m_baseSize + growth; | |
86 else | |
87 m_growthLimit += growth; | |
88 | |
89 ASSERT(m_growthLimit >= m_baseSize); | |
90 } | |
91 | |
92 bool growthLimitIsInfinite() const | |
93 { | |
94 return m_growthLimit == infinity; | |
95 } | |
96 | |
97 const LayoutUnit& growthLimitIfNotInfinite() const | |
98 { | |
99 ASSERT(isGrowthLimitBiggerThanBaseSize()); | |
100 return (m_growthLimit == infinity) ? m_baseSize : m_growthLimit; | |
101 } | |
102 | |
103 const LayoutUnit& plannedIncrease() const { return m_plannedIncrease; } | |
104 | |
105 void growPlannedIncrease(const LayoutUnit& plannedIncrease) | |
106 { | |
107 ASSERT(plannedIncrease >= 0); | |
108 m_plannedIncrease += plannedIncrease; | |
109 } | |
110 | |
111 void updateFromPlannedIncrease(RenderGrid::AccumulatorGrowFunction trackGrow
thFunction) | |
112 { | |
113 if (m_plannedIncrease == 0) | |
114 return; | |
115 | |
116 (this->*trackGrowthFunction)(m_plannedIncrease); | |
117 m_plannedIncrease = 0; | |
118 } | |
119 | |
120 private: | |
121 bool isGrowthLimitBiggerThanBaseSize() const { return growthLimitIsInfinite(
) || m_growthLimit >= m_baseSize; } | |
122 | |
123 void ensureGrowthLimitIsBiggerThanBaseSize() | |
124 { | |
125 if (m_growthLimit != infinity && m_growthLimit < m_baseSize) | |
126 m_growthLimit = m_baseSize; | |
127 } | |
128 | |
129 LayoutUnit m_baseSize; | |
130 LayoutUnit m_growthLimit; | |
131 LayoutUnit m_plannedIncrease; | |
132 }; | |
133 | |
134 struct GridTrackForNormalization { | |
135 GridTrackForNormalization(const GridTrack& track, double flex) | |
136 : m_track(&track) | |
137 , m_flex(flex) | |
138 , m_normalizedFlexValue(track.baseSize() / flex) | |
139 { | |
140 } | |
141 | |
142 // Required by std::sort. | |
143 GridTrackForNormalization& operator=(const GridTrackForNormalization& o) | |
144 { | |
145 m_track = o.m_track; | |
146 m_flex = o.m_flex; | |
147 m_normalizedFlexValue = o.m_normalizedFlexValue; | |
148 return *this; | |
149 } | |
150 | |
151 const GridTrack* m_track; | |
152 double m_flex; | |
153 LayoutUnit m_normalizedFlexValue; | |
154 }; | |
155 | |
156 class RenderGrid::GridIterator { | |
157 WTF_MAKE_NONCOPYABLE(GridIterator); | |
158 public: | |
159 // |direction| is the direction that is fixed to |fixedTrackIndex| so e.g | |
160 // GridIterator(m_grid, ForColumns, 1) will walk over the rows of the 2nd co
lumn. | |
161 GridIterator(const GridRepresentation& grid, GridTrackSizingDirection direct
ion, size_t fixedTrackIndex, size_t varyingTrackIndex = 0) | |
162 : m_grid(grid) | |
163 , m_direction(direction) | |
164 , m_rowIndex((direction == ForColumns) ? varyingTrackIndex : fixedTrackI
ndex) | |
165 , m_columnIndex((direction == ForColumns) ? fixedTrackIndex : varyingTra
ckIndex) | |
166 , m_childIndex(0) | |
167 { | |
168 ASSERT(m_rowIndex < m_grid.size()); | |
169 ASSERT(m_columnIndex < m_grid[0].size()); | |
170 } | |
171 | |
172 LayoutBox* nextGridItem() | |
173 { | |
174 ASSERT(!m_grid.isEmpty()); | |
175 | |
176 size_t& varyingTrackIndex = (m_direction == ForColumns) ? m_rowIndex : m
_columnIndex; | |
177 const size_t endOfVaryingTrackIndex = (m_direction == ForColumns) ? m_gr
id.size() : m_grid[0].size(); | |
178 for (; varyingTrackIndex < endOfVaryingTrackIndex; ++varyingTrackIndex)
{ | |
179 const GridCell& children = m_grid[m_rowIndex][m_columnIndex]; | |
180 if (m_childIndex < children.size()) | |
181 return children[m_childIndex++]; | |
182 | |
183 m_childIndex = 0; | |
184 } | |
185 return 0; | |
186 } | |
187 | |
188 bool checkEmptyCells(size_t rowSpan, size_t columnSpan) const | |
189 { | |
190 // Ignore cells outside current grid as we will grow it later if needed. | |
191 size_t maxRows = std::min(m_rowIndex + rowSpan, m_grid.size()); | |
192 size_t maxColumns = std::min(m_columnIndex + columnSpan, m_grid[0].size(
)); | |
193 | |
194 // This adds a O(N^2) behavior that shouldn't be a big deal as we expect
spanning areas to be small. | |
195 for (size_t row = m_rowIndex; row < maxRows; ++row) { | |
196 for (size_t column = m_columnIndex; column < maxColumns; ++column) { | |
197 const GridCell& children = m_grid[row][column]; | |
198 if (!children.isEmpty()) | |
199 return false; | |
200 } | |
201 } | |
202 | |
203 return true; | |
204 } | |
205 | |
206 PassOwnPtr<GridCoordinate> nextEmptyGridArea(size_t fixedTrackSpan, size_t v
aryingTrackSpan) | |
207 { | |
208 ASSERT(!m_grid.isEmpty()); | |
209 ASSERT(fixedTrackSpan >= 1 && varyingTrackSpan >= 1); | |
210 | |
211 size_t rowSpan = (m_direction == ForColumns) ? varyingTrackSpan : fixedT
rackSpan; | |
212 size_t columnSpan = (m_direction == ForColumns) ? fixedTrackSpan : varyi
ngTrackSpan; | |
213 | |
214 size_t& varyingTrackIndex = (m_direction == ForColumns) ? m_rowIndex : m
_columnIndex; | |
215 const size_t endOfVaryingTrackIndex = (m_direction == ForColumns) ? m_gr
id.size() : m_grid[0].size(); | |
216 for (; varyingTrackIndex < endOfVaryingTrackIndex; ++varyingTrackIndex)
{ | |
217 if (checkEmptyCells(rowSpan, columnSpan)) { | |
218 OwnPtr<GridCoordinate> result = adoptPtr(new GridCoordinate(Grid
Span(m_rowIndex, m_rowIndex + rowSpan - 1), GridSpan(m_columnIndex, m_columnInde
x + columnSpan - 1))); | |
219 // Advance the iterator to avoid an infinite loop where we would
return the same grid area over and over. | |
220 ++varyingTrackIndex; | |
221 return result.release(); | |
222 } | |
223 } | |
224 return nullptr; | |
225 } | |
226 | |
227 private: | |
228 const GridRepresentation& m_grid; | |
229 GridTrackSizingDirection m_direction; | |
230 size_t m_rowIndex; | |
231 size_t m_columnIndex; | |
232 size_t m_childIndex; | |
233 }; | |
234 | |
235 struct RenderGrid::GridSizingData { | |
236 WTF_MAKE_NONCOPYABLE(GridSizingData); | |
237 STACK_ALLOCATED(); | |
238 public: | |
239 GridSizingData(size_t gridColumnCount, size_t gridRowCount) | |
240 : columnTracks(gridColumnCount) | |
241 , rowTracks(gridRowCount) | |
242 { | |
243 } | |
244 | |
245 Vector<GridTrack> columnTracks; | |
246 Vector<GridTrack> rowTracks; | |
247 Vector<size_t> contentSizedTracksIndex; | |
248 | |
249 // Performance optimization: hold onto these Vectors until the end of Layout
to avoid repeated malloc / free. | |
250 Vector<GridTrack*> filteredTracks; | |
251 Vector<GridItemWithSpan> itemsSortedByIncreasingSpan; | |
252 Vector<GridTrack*> growBeyondGrowthLimitsTracks; | |
253 }; | |
254 | |
255 RenderGrid::RenderGrid(Element* element) | |
256 : RenderBlock(element) | |
257 , m_gridIsDirty(true) | |
258 , m_orderIterator(this) | |
259 { | |
260 ASSERT(!childrenInline()); | |
261 } | |
262 | |
263 RenderGrid::~RenderGrid() | |
264 { | |
265 } | |
266 | |
267 void RenderGrid::addChild(LayoutObject* newChild, LayoutObject* beforeChild) | |
268 { | |
269 RenderBlock::addChild(newChild, beforeChild); | |
270 | |
271 if (gridIsDirty()) | |
272 return; | |
273 | |
274 // The grid needs to be recomputed as it might contain auto-placed items tha
t will change their position. | |
275 dirtyGrid(); | |
276 return; | |
277 } | |
278 | |
279 void RenderGrid::removeChild(LayoutObject* child) | |
280 { | |
281 RenderBlock::removeChild(child); | |
282 | |
283 if (gridIsDirty()) | |
284 return; | |
285 | |
286 // The grid needs to be recomputed as it might contain auto-placed items tha
t will change their position. | |
287 dirtyGrid(); | |
288 return; | |
289 } | |
290 | |
291 void RenderGrid::styleDidChange(StyleDifference diff, const LayoutStyle* oldStyl
e) | |
292 { | |
293 RenderBlock::styleDidChange(diff, oldStyle); | |
294 if (!oldStyle) | |
295 return; | |
296 | |
297 // FIXME: The following checks could be narrowed down if we kept track of wh
ich type of grid items we have: | |
298 // - explicit grid size changes impact negative explicitely positioned and a
uto-placed grid items. | |
299 // - named grid lines only impact grid items with named grid lines. | |
300 // - auto-flow changes only impacts auto-placed children. | |
301 | |
302 if (explicitGridDidResize(*oldStyle) | |
303 || namedGridLinesDefinitionDidChange(*oldStyle) | |
304 || oldStyle->gridAutoFlow() != styleRef().gridAutoFlow()) | |
305 dirtyGrid(); | |
306 } | |
307 | |
308 bool RenderGrid::explicitGridDidResize(const LayoutStyle& oldStyle) const | |
309 { | |
310 return oldStyle.gridTemplateColumns().size() != styleRef().gridTemplateColum
ns().size() | |
311 || oldStyle.gridTemplateRows().size() != styleRef().gridTemplateRows().s
ize(); | |
312 } | |
313 | |
314 bool RenderGrid::namedGridLinesDefinitionDidChange(const LayoutStyle& oldStyle)
const | |
315 { | |
316 return oldStyle.namedGridRowLines() != styleRef().namedGridRowLines() | |
317 || oldStyle.namedGridColumnLines() != styleRef().namedGridColumnLines(); | |
318 } | |
319 | |
320 void RenderGrid::layoutBlock(bool relayoutChildren) | |
321 { | |
322 ASSERT(needsLayout()); | |
323 | |
324 if (!relayoutChildren && simplifiedLayout()) | |
325 return; | |
326 | |
327 // FIXME: Much of this method is boiler plate that matches LayoutBox::layout
Block and Render*FlexibleBox::layoutBlock. | |
328 // It would be nice to refactor some of the duplicate code. | |
329 { | |
330 // LayoutState needs this deliberate scope to pop before updating scroll
information (which | |
331 // may trigger relayout). | |
332 LayoutState state(*this, locationOffset()); | |
333 | |
334 LayoutSize previousSize = size(); | |
335 | |
336 setLogicalHeight(0); | |
337 updateLogicalWidth(); | |
338 | |
339 TextAutosizer::LayoutScope textAutosizerLayoutScope(this); | |
340 | |
341 layoutGridItems(); | |
342 | |
343 LayoutUnit oldClientAfterEdge = clientLogicalBottom(); | |
344 updateLogicalHeight(); | |
345 | |
346 if (size() != previousSize) | |
347 relayoutChildren = true; | |
348 | |
349 layoutPositionedObjects(relayoutChildren || isDocumentElement()); | |
350 | |
351 computeOverflow(oldClientAfterEdge); | |
352 } | |
353 | |
354 updateLayerTransformAfterLayout(); | |
355 | |
356 // Update our scroll information if we're overflow:auto/scroll/hidden now th
at we know if | |
357 // we overflow or not. | |
358 if (hasOverflowClip()) | |
359 layer()->scrollableArea()->updateAfterLayout(); | |
360 | |
361 clearNeedsLayout(); | |
362 } | |
363 | |
364 void RenderGrid::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, Layo
utUnit& maxLogicalWidth) const | |
365 { | |
366 const_cast<RenderGrid*>(this)->placeItemsOnGrid(); | |
367 | |
368 GridSizingData sizingData(gridColumnCount(), gridRowCount()); | |
369 LayoutUnit availableLogicalSpace = 0; | |
370 const_cast<RenderGrid*>(this)->computeUsedBreadthOfGridTracks(ForColumns, si
zingData, availableLogicalSpace); | |
371 | |
372 for (const auto& column : sizingData.columnTracks) { | |
373 const LayoutUnit& minTrackBreadth = column.baseSize(); | |
374 const LayoutUnit& maxTrackBreadth = column.growthLimit(); | |
375 | |
376 minLogicalWidth += minTrackBreadth; | |
377 maxLogicalWidth += maxTrackBreadth; | |
378 | |
379 LayoutUnit scrollbarWidth = intrinsicScrollbarLogicalWidth(); | |
380 maxLogicalWidth += scrollbarWidth; | |
381 minLogicalWidth += scrollbarWidth; | |
382 } | |
383 } | |
384 | |
385 void RenderGrid::computePreferredLogicalWidths() | |
386 { | |
387 ASSERT(preferredLogicalWidthsDirty()); | |
388 | |
389 m_minPreferredLogicalWidth = 0; | |
390 m_maxPreferredLogicalWidth = 0; | |
391 | |
392 // FIXME: We don't take our own logical width into account. Once we do, we n
eed to make sure | |
393 // we apply (and test the interaction with) min-width / max-width. | |
394 | |
395 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogi
calWidth); | |
396 | |
397 LayoutUnit borderAndPaddingInInlineDirection = borderAndPaddingLogicalWidth(
); | |
398 m_minPreferredLogicalWidth += borderAndPaddingInInlineDirection; | |
399 m_maxPreferredLogicalWidth += borderAndPaddingInInlineDirection; | |
400 | |
401 clearPreferredLogicalWidthsDirty(); | |
402 } | |
403 | |
404 void RenderGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection directi
on, GridSizingData& sizingData) | |
405 { | |
406 LayoutUnit availableLogicalSpace = (direction == ForColumns) ? availableLogi
calWidth() : availableLogicalHeight(IncludeMarginBorderPadding); | |
407 computeUsedBreadthOfGridTracks(direction, sizingData, availableLogicalSpace)
; | |
408 } | |
409 | |
410 bool RenderGrid::gridElementIsShrinkToFit() | |
411 { | |
412 return isFloatingOrOutOfFlowPositioned(); | |
413 } | |
414 | |
415 void RenderGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection directi
on, GridSizingData& sizingData, LayoutUnit& freeSpace) | |
416 { | |
417 const LayoutUnit initialFreeSpace = freeSpace; | |
418 Vector<GridTrack>& tracks = (direction == ForColumns) ? sizingData.columnTra
cks : sizingData.rowTracks; | |
419 Vector<size_t> flexibleSizedTracksIndex; | |
420 sizingData.contentSizedTracksIndex.shrink(0); | |
421 | |
422 // 1. Initialize per Grid track variables. | |
423 for (size_t i = 0; i < tracks.size(); ++i) { | |
424 GridTrack& track = tracks[i]; | |
425 GridTrackSize trackSize = gridTrackSize(direction, i); | |
426 const GridLength& minTrackBreadth = trackSize.minTrackBreadth(); | |
427 const GridLength& maxTrackBreadth = trackSize.maxTrackBreadth(); | |
428 | |
429 track.setBaseSize(computeUsedBreadthOfMinLength(direction, minTrackBread
th)); | |
430 track.setGrowthLimit(computeUsedBreadthOfMaxLength(direction, maxTrackBr
eadth, track.baseSize())); | |
431 | |
432 if (trackSize.isContentSized()) | |
433 sizingData.contentSizedTracksIndex.append(i); | |
434 if (trackSize.maxTrackBreadth().isFlex()) | |
435 flexibleSizedTracksIndex.append(i); | |
436 } | |
437 | |
438 // 2. Resolve content-based TrackSizingFunctions. | |
439 if (!sizingData.contentSizedTracksIndex.isEmpty()) | |
440 resolveContentBasedTrackSizingFunctions(direction, sizingData, freeSpace
); | |
441 | |
442 for (const auto& track: tracks) { | |
443 ASSERT(!track.growthLimitIsInfinite()); | |
444 freeSpace -= track.baseSize(); | |
445 } | |
446 | |
447 const bool hasUndefinedRemainingSpace = (direction == ForRows) ? style()->lo
gicalHeight().isAuto() : gridElementIsShrinkToFit(); | |
448 | |
449 if (!hasUndefinedRemainingSpace && freeSpace <= 0) | |
450 return; | |
451 | |
452 // 3. Grow all Grid tracks in GridTracks from their baseSize up to their gro
wthLimit value until freeSpace is exhausted. | |
453 const size_t tracksSize = tracks.size(); | |
454 if (!hasUndefinedRemainingSpace) { | |
455 Vector<GridTrack*> tracksForDistribution(tracksSize); | |
456 for (size_t i = 0; i < tracksSize; ++i) | |
457 tracksForDistribution[i] = tracks.data() + i; | |
458 | |
459 distributeSpaceToTracks(tracksForDistribution, nullptr, &GridTrack::base
Size, &GridTrack::growBaseSize, sizingData, freeSpace); | |
460 } else { | |
461 for (auto& track : tracks) | |
462 track.setBaseSize(track.growthLimit()); | |
463 } | |
464 | |
465 if (flexibleSizedTracksIndex.isEmpty()) | |
466 return; | |
467 | |
468 // 4. Grow all Grid tracks having a fraction as the MaxTrackSizingFunction. | |
469 double normalizedFractionBreadth = 0; | |
470 if (!hasUndefinedRemainingSpace) { | |
471 normalizedFractionBreadth = computeNormalizedFractionBreadth(tracks, Gri
dSpan(0, tracks.size() - 1), direction, initialFreeSpace); | |
472 } else { | |
473 for (const auto& trackIndex : flexibleSizedTracksIndex) { | |
474 GridTrackSize trackSize = gridTrackSize(direction, trackIndex); | |
475 normalizedFractionBreadth = std::max(normalizedFractionBreadth, trac
ks[trackIndex].baseSize() / trackSize.maxTrackBreadth().flex()); | |
476 } | |
477 | |
478 for (size_t i = 0; i < flexibleSizedTracksIndex.size(); ++i) { | |
479 GridIterator iterator(m_grid, direction, flexibleSizedTracksIndex[i]
); | |
480 while (LayoutBox* gridItem = iterator.nextGridItem()) { | |
481 const GridCoordinate coordinate = cachedGridCoordinate(*gridItem
); | |
482 const GridSpan span = (direction == ForColumns) ? coordinate.col
umns : coordinate.rows; | |
483 | |
484 // Do not include already processed items. | |
485 if (i > 0 && span.resolvedInitialPosition.toInt() <= flexibleSiz
edTracksIndex[i - 1]) | |
486 continue; | |
487 | |
488 double itemNormalizedFlexBreadth = computeNormalizedFractionBrea
dth(tracks, span, direction, maxContentForChild(*gridItem, direction, sizingData
.columnTracks)); | |
489 normalizedFractionBreadth = std::max(normalizedFractionBreadth,
itemNormalizedFlexBreadth); | |
490 } | |
491 } | |
492 } | |
493 | |
494 for (const auto& trackIndex : flexibleSizedTracksIndex) { | |
495 GridTrackSize trackSize = gridTrackSize(direction, trackIndex); | |
496 | |
497 LayoutUnit baseSize = std::max<LayoutUnit>(tracks[trackIndex].baseSize()
, normalizedFractionBreadth * trackSize.maxTrackBreadth().flex()); | |
498 tracks[trackIndex].setBaseSize(baseSize); | |
499 freeSpace -= baseSize; | |
500 } | |
501 | |
502 // FIXME: Should ASSERT flexible tracks exhaust the freeSpace ? (see issue 7
39613002). | |
503 } | |
504 | |
505 LayoutUnit RenderGrid::computeUsedBreadthOfMinLength(GridTrackSizingDirection di
rection, const GridLength& gridLength) const | |
506 { | |
507 if (gridLength.isFlex()) | |
508 return 0; | |
509 | |
510 const Length& trackLength = gridLength.length(); | |
511 ASSERT(!trackLength.isAuto()); | |
512 if (trackLength.isSpecified()) | |
513 return computeUsedBreadthOfSpecifiedLength(direction, trackLength); | |
514 | |
515 ASSERT(trackLength.isMinContent() || trackLength.isMaxContent()); | |
516 return 0; | |
517 } | |
518 | |
519 LayoutUnit RenderGrid::computeUsedBreadthOfMaxLength(GridTrackSizingDirection di
rection, const GridLength& gridLength, LayoutUnit usedBreadth) const | |
520 { | |
521 if (gridLength.isFlex()) | |
522 return usedBreadth; | |
523 | |
524 const Length& trackLength = gridLength.length(); | |
525 ASSERT(!trackLength.isAuto()); | |
526 if (trackLength.isSpecified()) { | |
527 LayoutUnit computedBreadth = computeUsedBreadthOfSpecifiedLength(directi
on, trackLength); | |
528 ASSERT(computedBreadth != infinity); | |
529 return computedBreadth; | |
530 } | |
531 | |
532 ASSERT(trackLength.isMinContent() || trackLength.isMaxContent()); | |
533 return infinity; | |
534 } | |
535 | |
536 LayoutUnit RenderGrid::computeUsedBreadthOfSpecifiedLength(GridTrackSizingDirect
ion direction, const Length& trackLength) const | |
537 { | |
538 ASSERT(trackLength.isSpecified()); | |
539 // FIXME: The -1 here should be replaced by whatever the intrinsic height of
the grid is. | |
540 return valueForLength(trackLength, direction == ForColumns ? logicalWidth()
: computeContentLogicalHeight(style()->logicalHeight(), -1)); | |
541 } | |
542 | |
543 static bool sortByGridNormalizedFlexValue(const GridTrackForNormalization& track
1, const GridTrackForNormalization& track2) | |
544 { | |
545 return track1.m_normalizedFlexValue < track2.m_normalizedFlexValue; | |
546 } | |
547 | |
548 double RenderGrid::computeNormalizedFractionBreadth(Vector<GridTrack>& tracks, c
onst GridSpan& tracksSpan, GridTrackSizingDirection direction, LayoutUnit spaceT
oFill) const | |
549 { | |
550 LayoutUnit allocatedSpace; | |
551 Vector<GridTrackForNormalization> tracksForNormalization; | |
552 for (const auto& resolvedPosition : tracksSpan) { | |
553 GridTrack& track = tracks[resolvedPosition.toInt()]; | |
554 allocatedSpace += track.baseSize(); | |
555 | |
556 GridTrackSize trackSize = gridTrackSize(direction, resolvedPosition.toIn
t()); | |
557 if (!trackSize.maxTrackBreadth().isFlex()) | |
558 continue; | |
559 | |
560 tracksForNormalization.append(GridTrackForNormalization(track, trackSize
.maxTrackBreadth().flex())); | |
561 } | |
562 | |
563 // The function is not called if we don't have <flex> grid tracks | |
564 ASSERT(!tracksForNormalization.isEmpty()); | |
565 | |
566 std::sort(tracksForNormalization.begin(), tracksForNormalization.end(), sort
ByGridNormalizedFlexValue); | |
567 | |
568 // These values work together: as we walk over our grid tracks, we increase
fractionValueBasedOnGridItemsRatio | |
569 // to match a grid track's usedBreadth to <flex> ratio until the total fract
ions sized grid tracks wouldn't | |
570 // fit into availableLogicalSpaceIgnoringFractionTracks. | |
571 double accumulatedFractions = 0; | |
572 LayoutUnit fractionValueBasedOnGridItemsRatio = 0; | |
573 LayoutUnit availableLogicalSpaceIgnoringFractionTracks = spaceToFill - alloc
atedSpace; | |
574 | |
575 for (const auto& track : tracksForNormalization) { | |
576 if (track.m_normalizedFlexValue > fractionValueBasedOnGridItemsRatio) { | |
577 // If the normalized flex value (we ordered |tracksForNormalization|
by increasing normalized flex value) | |
578 // will make us overflow our container, then stop. We have the previ
ous step's ratio is the best fit. | |
579 if (track.m_normalizedFlexValue * accumulatedFractions > availableLo
gicalSpaceIgnoringFractionTracks) | |
580 break; | |
581 | |
582 fractionValueBasedOnGridItemsRatio = track.m_normalizedFlexValue; | |
583 } | |
584 | |
585 accumulatedFractions += track.m_flex; | |
586 // This item was processed so we re-add its used breadth to the availabl
e space to accurately count the remaining space. | |
587 availableLogicalSpaceIgnoringFractionTracks += track.m_track->baseSize()
; | |
588 } | |
589 | |
590 return availableLogicalSpaceIgnoringFractionTracks / accumulatedFractions; | |
591 } | |
592 | |
593 bool RenderGrid::hasDefiniteLogicalSize(GridTrackSizingDirection direction) cons
t | |
594 { | |
595 return (direction == ForRows) ? hasDefiniteLogicalHeight() : hasDefiniteLogi
calWidth(); | |
596 } | |
597 | |
598 GridTrackSize RenderGrid::gridTrackSize(GridTrackSizingDirection direction, size
_t i) const | |
599 { | |
600 bool isForColumns = direction == ForColumns; | |
601 const Vector<GridTrackSize>& trackStyles = isForColumns ? style()->gridTempl
ateColumns() : style()->gridTemplateRows(); | |
602 const GridTrackSize& trackSize = (i >= trackStyles.size()) ? (isForColumns ?
style()->gridAutoColumns() : style()->gridAutoRows()) : trackStyles[i]; | |
603 | |
604 // If the logical width/height of the grid container is indefinite, percenta
ge values are treated as <auto> (or in | |
605 // the case of minmax() as min-content for the first position and max-conten
t for the second). | |
606 if (!hasDefiniteLogicalSize(direction)) { | |
607 const GridLength& oldMinTrackBreadth = trackSize.minTrackBreadth(); | |
608 const GridLength& oldMaxTrackBreadth = trackSize.maxTrackBreadth(); | |
609 return GridTrackSize(oldMinTrackBreadth.isPercentage() ? Length(MinConte
nt) : oldMinTrackBreadth, oldMaxTrackBreadth.isPercentage() ? Length(MaxContent)
: oldMaxTrackBreadth); | |
610 } | |
611 | |
612 return trackSize; | |
613 } | |
614 | |
615 LayoutUnit RenderGrid::logicalHeightForChild(LayoutBox& child, Vector<GridTrack>
& columnTracks) | |
616 { | |
617 SubtreeLayoutScope layoutScope(child); | |
618 LayoutUnit oldOverrideContainingBlockContentLogicalWidth = child.hasOverride
ContainingBlockLogicalWidth() ? child.overrideContainingBlockContentLogicalWidth
() : LayoutUnit(); | |
619 LayoutUnit overrideContainingBlockContentLogicalWidth = gridAreaBreadthForCh
ild(child, ForColumns, columnTracks); | |
620 if (child.style()->logicalHeight().isPercent() || oldOverrideContainingBlock
ContentLogicalWidth != overrideContainingBlockContentLogicalWidth) | |
621 layoutScope.setNeedsLayout(&child); | |
622 | |
623 child.clearOverrideLogicalContentHeight(); | |
624 | |
625 child.setOverrideContainingBlockContentLogicalWidth(overrideContainingBlockC
ontentLogicalWidth); | |
626 // If |child| has a percentage logical height, we shouldn't let it override
its intrinsic height, which is | |
627 // what we are interested in here. Thus we need to set the override logical
height to -1 (no possible resolution). | |
628 child.setOverrideContainingBlockContentLogicalHeight(-1); | |
629 child.layoutIfNeeded(); | |
630 return child.logicalHeight() + child.marginLogicalHeight(); | |
631 } | |
632 | |
633 LayoutUnit RenderGrid::minContentForChild(LayoutBox& child, GridTrackSizingDirec
tion direction, Vector<GridTrack>& columnTracks) | |
634 { | |
635 bool hasOrthogonalWritingMode = child.isHorizontalWritingMode() != isHorizon
talWritingMode(); | |
636 // FIXME: Properly support orthogonal writing mode. | |
637 if (hasOrthogonalWritingMode) | |
638 return 0; | |
639 | |
640 if (direction == ForColumns) { | |
641 // FIXME: It's unclear if we should return the intrinsic width or the pr
eferred width. | |
642 // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html | |
643 return child.minPreferredLogicalWidth() + marginIntrinsicLogicalWidthFor
Child(child); | |
644 } | |
645 | |
646 return logicalHeightForChild(child, columnTracks); | |
647 } | |
648 | |
649 LayoutUnit RenderGrid::maxContentForChild(LayoutBox& child, GridTrackSizingDirec
tion direction, Vector<GridTrack>& columnTracks) | |
650 { | |
651 bool hasOrthogonalWritingMode = child.isHorizontalWritingMode() != isHorizon
talWritingMode(); | |
652 // FIXME: Properly support orthogonal writing mode. | |
653 if (hasOrthogonalWritingMode) | |
654 return LayoutUnit(); | |
655 | |
656 if (direction == ForColumns) { | |
657 // FIXME: It's unclear if we should return the intrinsic width or the pr
eferred width. | |
658 // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html | |
659 return child.maxPreferredLogicalWidth() + marginIntrinsicLogicalWidthFor
Child(child); | |
660 } | |
661 | |
662 return logicalHeightForChild(child, columnTracks); | |
663 } | |
664 | |
665 // We're basically using a class instead of a std::pair for two reasons. First o
f all, accessing gridItem() or | |
666 // coordinate() is much more self-explanatory that using .first or .second membe
rs in the pair. Secondly the class | |
667 // allows us to precompute the value of the span, something which is quite conve
nient for the sorting. Having a | |
668 // std::pair<LayoutBox*, size_t> does not work either because we still need the
GridCoordinate so we'd have to add an | |
669 // extra hash lookup for each item at the beginning of RenderGrid::resolveConten
tBasedTrackSizingFunctionsForItems(). | |
670 class GridItemWithSpan { | |
671 public: | |
672 GridItemWithSpan(LayoutBox& gridItem, const GridCoordinate& coordinate, Grid
TrackSizingDirection direction) | |
673 : m_gridItem(&gridItem) | |
674 , m_coordinate(coordinate) | |
675 { | |
676 const GridSpan& span = (direction == ForRows) ? coordinate.rows : coordi
nate.columns; | |
677 m_span = span.resolvedFinalPosition.toInt() - span.resolvedInitialPositi
on.toInt() + 1; | |
678 } | |
679 | |
680 LayoutBox& gridItem() const { return *m_gridItem; } | |
681 GridCoordinate coordinate() const { return m_coordinate; } | |
682 #if ENABLE(ASSERT) | |
683 size_t span() const { return m_span; } | |
684 #endif | |
685 | |
686 bool operator<(const GridItemWithSpan other) const { return m_span < other.m
_span; } | |
687 | |
688 private: | |
689 LayoutBox* m_gridItem; | |
690 GridCoordinate m_coordinate; | |
691 size_t m_span; | |
692 }; | |
693 | |
694 bool RenderGrid::spanningItemCrossesFlexibleSizedTracks(const GridCoordinate& co
ordinate, GridTrackSizingDirection direction) const | |
695 { | |
696 const GridResolvedPosition initialTrackPosition = (direction == ForColumns)
? coordinate.columns.resolvedInitialPosition : coordinate.rows.resolvedInitialPo
sition; | |
697 const GridResolvedPosition finalTrackPosition = (direction == ForColumns) ?
coordinate.columns.resolvedFinalPosition : coordinate.rows.resolvedFinalPosition
; | |
698 | |
699 for (GridResolvedPosition trackPosition = initialTrackPosition; trackPositio
n <= finalTrackPosition; ++trackPosition) { | |
700 const GridTrackSize& trackSize = gridTrackSize(direction, trackPosition.
toInt()); | |
701 if (trackSize.minTrackBreadth().isFlex() || trackSize.maxTrackBreadth().
isFlex()) | |
702 return true; | |
703 } | |
704 | |
705 return false; | |
706 } | |
707 | |
708 static inline size_t integerSpanForDirection(const GridCoordinate& coordinate, G
ridTrackSizingDirection direction) | |
709 { | |
710 return (direction == ForRows) ? coordinate.rows.integerSpan() : coordinate.c
olumns.integerSpan(); | |
711 } | |
712 | |
713 void RenderGrid::resolveContentBasedTrackSizingFunctions(GridTrackSizingDirectio
n direction, GridSizingData& sizingData, LayoutUnit& availableLogicalSpace) | |
714 { | |
715 sizingData.itemsSortedByIncreasingSpan.shrink(0); | |
716 HashSet<LayoutBox*> itemsSet; | |
717 for (const auto& trackIndex : sizingData.contentSizedTracksIndex) { | |
718 GridIterator iterator(m_grid, direction, trackIndex); | |
719 GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[t
rackIndex] : sizingData.rowTracks[trackIndex]; | |
720 while (LayoutBox* gridItem = iterator.nextGridItem()) { | |
721 if (itemsSet.add(gridItem).isNewEntry) { | |
722 const GridCoordinate& coordinate = cachedGridCoordinate(*gridIte
m); | |
723 if (integerSpanForDirection(coordinate, direction) == 1) { | |
724 resolveContentBasedTrackSizingFunctionsForNonSpanningItems(d
irection, coordinate, *gridItem, track, sizingData.columnTracks); | |
725 } else if (!spanningItemCrossesFlexibleSizedTracks(coordinate, d
irection)) { | |
726 sizingData.itemsSortedByIncreasingSpan.append(GridItemWithSp
an(*gridItem, coordinate, direction)); | |
727 } | |
728 } | |
729 } | |
730 } | |
731 std::sort(sizingData.itemsSortedByIncreasingSpan.begin(), sizingData.itemsSo
rtedByIncreasingSpan.end()); | |
732 | |
733 Vector<GridItemWithSpan>::iterator end = sizingData.itemsSortedByIncreasingS
pan.end(); | |
734 for (Vector<GridItemWithSpan>::iterator it = sizingData.itemsSortedByIncreas
ingSpan.begin(); it != end; ++it) { | |
735 GridItemWithSpan itemWithSpan = *it; | |
736 resolveContentBasedTrackSizingFunctionsForItems(direction, sizingData, i
temWithSpan, &GridTrackSize::hasMinOrMaxContentMinTrackBreadth, &RenderGrid::min
ContentForChild, &GridTrack::baseSize, &GridTrack::growBaseSize, &GridTrackSize:
:hasMinContentMinTrackBreadthAndMinOrMaxContentMaxTrackBreadth); | |
737 resolveContentBasedTrackSizingFunctionsForItems(direction, sizingData, i
temWithSpan, &GridTrackSize::hasMaxContentMinTrackBreadth, &RenderGrid::maxConte
ntForChild, &GridTrack::baseSize, &GridTrack::growBaseSize, &GridTrackSize::hasM
axContentMinTrackBreadthAndMaxContentMaxTrackBreadth); | |
738 resolveContentBasedTrackSizingFunctionsForItems(direction, sizingData, i
temWithSpan, &GridTrackSize::hasMinOrMaxContentMaxTrackBreadth, &RenderGrid::min
ContentForChild, &GridTrack::growthLimitIfNotInfinite, &GridTrack::growGrowthLim
it); | |
739 resolveContentBasedTrackSizingFunctionsForItems(direction, sizingData, i
temWithSpan, &GridTrackSize::hasMaxContentMaxTrackBreadth, &RenderGrid::maxConte
ntForChild, &GridTrack::growthLimitIfNotInfinite, &GridTrack::growGrowthLimit); | |
740 } | |
741 | |
742 for (const auto& trackIndex : sizingData.contentSizedTracksIndex) { | |
743 GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[t
rackIndex] : sizingData.rowTracks[trackIndex]; | |
744 if (track.growthLimitIsInfinite()) | |
745 track.setGrowthLimit(track.baseSize()); | |
746 } | |
747 } | |
748 | |
749 void RenderGrid::resolveContentBasedTrackSizingFunctionsForNonSpanningItems(Grid
TrackSizingDirection direction, const GridCoordinate& coordinate, LayoutBox& gri
dItem, GridTrack& track, Vector<GridTrack>& columnTracks) | |
750 { | |
751 const GridResolvedPosition trackPosition = (direction == ForColumns) ? coord
inate.columns.resolvedInitialPosition : coordinate.rows.resolvedInitialPosition; | |
752 GridTrackSize trackSize = gridTrackSize(direction, trackPosition.toInt()); | |
753 | |
754 if (trackSize.hasMinContentMinTrackBreadth()) | |
755 track.setBaseSize(std::max(track.baseSize(), minContentForChild(gridItem
, direction, columnTracks))); | |
756 else if (trackSize.hasMaxContentMinTrackBreadth()) | |
757 track.setBaseSize(std::max(track.baseSize(), maxContentForChild(gridItem
, direction, columnTracks))); | |
758 | |
759 if (trackSize.hasMinContentMaxTrackBreadth()) | |
760 track.setGrowthLimit(std::max(track.growthLimit(), minContentForChild(gr
idItem, direction, columnTracks))); | |
761 else if (trackSize.hasMaxContentMaxTrackBreadth()) | |
762 track.setGrowthLimit(std::max(track.growthLimit(), maxContentForChild(gr
idItem, direction, columnTracks))); | |
763 } | |
764 | |
765 void RenderGrid::resolveContentBasedTrackSizingFunctionsForItems(GridTrackSizing
Direction direction, GridSizingData& sizingData, GridItemWithSpan& gridItemWithS
pan, FilterFunction filterFunction, SizingFunction sizingFunction, AccumulatorGe
tter trackGetter, AccumulatorGrowFunction trackGrowthFunction, FilterFunction gr
owAboveMaxBreadthFilterFunction) | |
766 { | |
767 ASSERT(gridItemWithSpan.span() > 1); | |
768 const GridCoordinate coordinate = gridItemWithSpan.coordinate(); | |
769 const GridSpan& itemSpan = (direction == ForColumns) ? coordinate.columns :
coordinate.rows; | |
770 | |
771 sizingData.growBeyondGrowthLimitsTracks.shrink(0); | |
772 sizingData.filteredTracks.shrink(0); | |
773 LayoutUnit spanningTracksSize; | |
774 for (const auto& trackPosition : itemSpan) { | |
775 GridTrackSize trackSize = gridTrackSize(direction, trackPosition.toInt()
); | |
776 GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[t
rackPosition.toInt()] : sizingData.rowTracks[trackPosition.toInt()]; | |
777 spanningTracksSize += (track.*trackGetter)(); | |
778 if (!(trackSize.*filterFunction)()) | |
779 continue; | |
780 | |
781 sizingData.filteredTracks.append(&track); | |
782 | |
783 if (!growAboveMaxBreadthFilterFunction || (trackSize.*growAboveMaxBreadt
hFilterFunction)()) | |
784 sizingData.growBeyondGrowthLimitsTracks.append(&track); | |
785 } | |
786 | |
787 if (sizingData.filteredTracks.isEmpty()) | |
788 return; | |
789 | |
790 // Specs mandate to floor extraSpace to 0. Instead we directly avoid the fun
ction call in those cases as it will be | |
791 // a noop in terms of track sizing. | |
792 LayoutUnit extraSpace = (this->*sizingFunction)(gridItemWithSpan.gridItem(),
direction, sizingData.columnTracks) - spanningTracksSize; | |
793 if (extraSpace > 0) { | |
794 Vector<GridTrack*>* tracksToGrowBeyondGrowthLimits = sizingData.growBeyo
ndGrowthLimitsTracks.isEmpty() ? &sizingData.filteredTracks : &sizingData.growBe
yondGrowthLimitsTracks; | |
795 distributeSpaceToTracks(sizingData.filteredTracks, tracksToGrowBeyondGro
wthLimits, trackGetter, trackGrowthFunction, sizingData, extraSpace); | |
796 } | |
797 } | |
798 | |
799 static bool sortByGridTrackGrowthPotential(const GridTrack* track1, const GridTr
ack* track2) | |
800 { | |
801 // This check ensures that we respect the irreflexivity property of the stri
ct weak ordering required by std::sort | |
802 // (forall x: NOT x < x). | |
803 if (track1->growthLimitIsInfinite() && track2->growthLimitIsInfinite()) | |
804 return false; | |
805 | |
806 if (track1->growthLimitIsInfinite() || track2->growthLimitIsInfinite()) | |
807 return track2->growthLimitIsInfinite(); | |
808 | |
809 return (track1->growthLimit() - track1->baseSize()) < (track2->growthLimit()
- track2->baseSize()); | |
810 } | |
811 | |
812 void RenderGrid::distributeSpaceToTracks(Vector<GridTrack*>& tracks, const Vecto
r<GridTrack*>* growBeyondGrowthLimitsTracks, AccumulatorGetter trackGetter, Accu
mulatorGrowFunction trackGrowthFunction, GridSizingData& sizingData, LayoutUnit&
availableLogicalSpace) | |
813 { | |
814 ASSERT(availableLogicalSpace > 0); | |
815 std::sort(tracks.begin(), tracks.end(), sortByGridTrackGrowthPotential); | |
816 | |
817 size_t tracksSize = tracks.size(); | |
818 for (size_t i = 0; i < tracksSize; ++i) { | |
819 GridTrack& track = *tracks[i]; | |
820 ASSERT(track.plannedIncrease() == 0); | |
821 LayoutUnit availableLogicalSpaceShare = availableLogicalSpace / (tracksS
ize - i); | |
822 const LayoutUnit& trackBreadth = (track.*trackGetter)(); | |
823 LayoutUnit growthShare = track.growthLimitIsInfinite() ? availableLogica
lSpaceShare : std::min(availableLogicalSpaceShare, track.growthLimit() - trackBr
eadth); | |
824 // We should never shrink any grid track or else we can't guarantee we a
bide by our min-sizing function. | |
825 if (growthShare > 0) { | |
826 track.growPlannedIncrease(growthShare); | |
827 availableLogicalSpace -= growthShare; | |
828 } | |
829 } | |
830 | |
831 if (availableLogicalSpace > 0 && growBeyondGrowthLimitsTracks) { | |
832 size_t tracksGrowingAboveMaxBreadthSize = growBeyondGrowthLimitsTracks->
size(); | |
833 for (size_t i = 0; i < tracksGrowingAboveMaxBreadthSize; ++i) { | |
834 GridTrack* track = growBeyondGrowthLimitsTracks->at(i); | |
835 LayoutUnit growthShare = availableLogicalSpace / (tracksGrowingAbove
MaxBreadthSize - i); | |
836 track->growPlannedIncrease(growthShare); | |
837 availableLogicalSpace -= growthShare; | |
838 } | |
839 } | |
840 | |
841 for (auto* track: tracks) { | |
842 track->updateFromPlannedIncrease(trackGrowthFunction); | |
843 ASSERT(track->plannedIncrease() == 0); | |
844 } | |
845 } | |
846 | |
847 #if ENABLE(ASSERT) | |
848 bool RenderGrid::tracksAreWiderThanMinTrackBreadth(GridTrackSizingDirection dire
ction, const Vector<GridTrack>& tracks) | |
849 { | |
850 for (size_t i = 0; i < tracks.size(); ++i) { | |
851 GridTrackSize trackSize = gridTrackSize(direction, i); | |
852 const GridLength& minTrackBreadth = trackSize.minTrackBreadth(); | |
853 if (computeUsedBreadthOfMinLength(direction, minTrackBreadth) > tracks[i
].baseSize()) | |
854 return false; | |
855 } | |
856 return true; | |
857 } | |
858 #endif | |
859 | |
860 void RenderGrid::ensureGridSize(size_t maximumRowIndex, size_t maximumColumnInde
x) | |
861 { | |
862 const size_t oldRowSize = gridRowCount(); | |
863 if (maximumRowIndex >= oldRowSize) { | |
864 m_grid.grow(maximumRowIndex + 1); | |
865 for (size_t row = oldRowSize; row < gridRowCount(); ++row) | |
866 m_grid[row].grow(gridColumnCount()); | |
867 } | |
868 | |
869 if (maximumColumnIndex >= gridColumnCount()) { | |
870 for (size_t row = 0; row < gridRowCount(); ++row) | |
871 m_grid[row].grow(maximumColumnIndex + 1); | |
872 } | |
873 } | |
874 | |
875 void RenderGrid::insertItemIntoGrid(LayoutBox& child, const GridCoordinate& coor
dinate) | |
876 { | |
877 ensureGridSize(coordinate.rows.resolvedFinalPosition.toInt(), coordinate.col
umns.resolvedFinalPosition.toInt()); | |
878 | |
879 for (GridSpan::iterator row = coordinate.rows.begin(); row != coordinate.row
s.end(); ++row) { | |
880 for (GridSpan::iterator column = coordinate.columns.begin(); column != c
oordinate.columns.end(); ++column) | |
881 m_grid[row.toInt()][column.toInt()].append(&child); | |
882 } | |
883 | |
884 RELEASE_ASSERT(!m_gridItemCoordinate.contains(&child)); | |
885 m_gridItemCoordinate.set(&child, coordinate); | |
886 } | |
887 | |
888 void RenderGrid::placeItemsOnGrid() | |
889 { | |
890 if (!gridIsDirty()) | |
891 return; | |
892 | |
893 ASSERT(m_gridItemCoordinate.isEmpty()); | |
894 | |
895 populateExplicitGridAndOrderIterator(); | |
896 | |
897 // We clear the dirty bit here as the grid sizes have been updated, this mea
ns | |
898 // that we can safely call gridRowCount() / gridColumnCount(). | |
899 m_gridIsDirty = false; | |
900 | |
901 Vector<LayoutBox*> autoMajorAxisAutoGridItems; | |
902 Vector<LayoutBox*> specifiedMajorAxisAutoGridItems; | |
903 for (LayoutBox* child = m_orderIterator.first(); child; child = m_orderItera
tor.next()) { | |
904 if (child->isOutOfFlowPositioned()) | |
905 continue; | |
906 | |
907 OwnPtr<GridSpan> rowPositions = GridResolvedPosition::resolveGridPositio
nsFromStyle(*style(), *child, ForRows); | |
908 OwnPtr<GridSpan> columnPositions = GridResolvedPosition::resolveGridPosi
tionsFromStyle(*style(), *child, ForColumns); | |
909 if (!rowPositions || !columnPositions) { | |
910 GridSpan* majorAxisPositions = (autoPlacementMajorAxisDirection() ==
ForColumns) ? columnPositions.get() : rowPositions.get(); | |
911 if (!majorAxisPositions) | |
912 autoMajorAxisAutoGridItems.append(child); | |
913 else | |
914 specifiedMajorAxisAutoGridItems.append(child); | |
915 continue; | |
916 } | |
917 insertItemIntoGrid(*child, GridCoordinate(*rowPositions, *columnPosition
s)); | |
918 } | |
919 | |
920 ASSERT(gridRowCount() >= GridResolvedPosition::explicitGridRowCount(*style()
)); | |
921 ASSERT(gridColumnCount() >= GridResolvedPosition::explicitGridColumnCount(*s
tyle())); | |
922 | |
923 placeSpecifiedMajorAxisItemsOnGrid(specifiedMajorAxisAutoGridItems); | |
924 placeAutoMajorAxisItemsOnGrid(autoMajorAxisAutoGridItems); | |
925 | |
926 m_grid.shrinkToFit(); | |
927 } | |
928 | |
929 void RenderGrid::populateExplicitGridAndOrderIterator() | |
930 { | |
931 OrderIteratorPopulator populator(m_orderIterator); | |
932 | |
933 size_t maximumRowIndex = std::max<size_t>(1, GridResolvedPosition::explicitG
ridRowCount(*style())); | |
934 size_t maximumColumnIndex = std::max<size_t>(1, GridResolvedPosition::explic
itGridColumnCount(*style())); | |
935 | |
936 ASSERT(m_gridItemsIndexesMap.isEmpty()); | |
937 size_t childIndex = 0; | |
938 for (LayoutBox* child = firstChildBox(); child; child = child->nextInFlowSib
lingBox()) { | |
939 populator.collectChild(child); | |
940 m_gridItemsIndexesMap.set(child, childIndex++); | |
941 | |
942 // This function bypasses the cache (cachedGridCoordinate()) as it is us
ed to build it. | |
943 OwnPtr<GridSpan> rowPositions = GridResolvedPosition::resolveGridPositio
nsFromStyle(*style(), *child, ForRows); | |
944 OwnPtr<GridSpan> columnPositions = GridResolvedPosition::resolveGridPosi
tionsFromStyle(*style(), *child, ForColumns); | |
945 | |
946 // |positions| is 0 if we need to run the auto-placement algorithm. | |
947 if (rowPositions) { | |
948 maximumRowIndex = std::max<size_t>(maximumRowIndex, rowPositions->re
solvedFinalPosition.next().toInt()); | |
949 } else { | |
950 // Grow the grid for items with a definite row span, getting the lar
gest such span. | |
951 GridSpan positions = GridResolvedPosition::resolveGridPositionsFromA
utoPlacementPosition(*style(), *child, ForRows, GridResolvedPosition(0)); | |
952 maximumRowIndex = std::max<size_t>(maximumRowIndex, positions.resolv
edFinalPosition.next().toInt()); | |
953 } | |
954 | |
955 if (columnPositions) { | |
956 maximumColumnIndex = std::max<size_t>(maximumColumnIndex, columnPosi
tions->resolvedFinalPosition.next().toInt()); | |
957 } else { | |
958 // Grow the grid for items with a definite column span, getting the
largest such span. | |
959 GridSpan positions = GridResolvedPosition::resolveGridPositionsFromA
utoPlacementPosition(*style(), *child, ForColumns, GridResolvedPosition(0)); | |
960 maximumColumnIndex = std::max<size_t>(maximumColumnIndex, positions.
resolvedFinalPosition.next().toInt()); | |
961 } | |
962 } | |
963 | |
964 m_grid.grow(maximumRowIndex); | |
965 for (auto& column : m_grid) | |
966 column.grow(maximumColumnIndex); | |
967 } | |
968 | |
969 PassOwnPtr<GridCoordinate> RenderGrid::createEmptyGridAreaAtSpecifiedPositionsOu
tsideGrid(const LayoutBox& gridItem, GridTrackSizingDirection specifiedDirection
, const GridSpan& specifiedPositions) const | |
970 { | |
971 GridTrackSizingDirection crossDirection = specifiedDirection == ForColumns ?
ForRows : ForColumns; | |
972 const size_t endOfCrossDirection = crossDirection == ForColumns ? gridColumn
Count() : gridRowCount(); | |
973 GridSpan crossDirectionPositions = GridResolvedPosition::resolveGridPosition
sFromAutoPlacementPosition(*style(), gridItem, crossDirection, GridResolvedPosit
ion(endOfCrossDirection)); | |
974 return adoptPtr(new GridCoordinate(specifiedDirection == ForColumns ? crossD
irectionPositions : specifiedPositions, specifiedDirection == ForColumns ? speci
fiedPositions : crossDirectionPositions)); | |
975 } | |
976 | |
977 void RenderGrid::placeSpecifiedMajorAxisItemsOnGrid(const Vector<LayoutBox*>& au
toGridItems) | |
978 { | |
979 bool isForColumns = autoPlacementMajorAxisDirection() == ForColumns; | |
980 bool isGridAutoFlowDense = style()->isGridAutoFlowAlgorithmDense(); | |
981 | |
982 // Mapping between the major axis tracks (rows or columns) and the last auto
-placed item's position inserted on | |
983 // that track. This is needed to implement "sparse" packing for items locked
to a given track. | |
984 // See http://dev.w3.org/csswg/css-grid/#auto-placement-algo | |
985 HashMap<unsigned, unsigned, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZe
roKeyHashTraits<unsigned>> minorAxisCursors; | |
986 | |
987 for (const auto& autoGridItem : autoGridItems) { | |
988 OwnPtr<GridSpan> majorAxisPositions = GridResolvedPosition::resolveGridP
ositionsFromStyle(*style(), *autoGridItem, autoPlacementMajorAxisDirection()); | |
989 GridSpan minorAxisPositions = GridResolvedPosition::resolveGridPositions
FromAutoPlacementPosition(*style(), *autoGridItem, autoPlacementMinorAxisDirecti
on(), GridResolvedPosition(0)); | |
990 unsigned majorAxisInitialPosition = majorAxisPositions->resolvedInitialP
osition.toInt(); | |
991 | |
992 GridIterator iterator(m_grid, autoPlacementMajorAxisDirection(), majorAx
isPositions->resolvedInitialPosition.toInt(), isGridAutoFlowDense ? 0 : minorAxi
sCursors.get(majorAxisInitialPosition)); | |
993 OwnPtr<GridCoordinate> emptyGridArea = iterator.nextEmptyGridArea(majorA
xisPositions->integerSpan(), minorAxisPositions.integerSpan()); | |
994 if (!emptyGridArea) | |
995 emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(*
autoGridItem, autoPlacementMajorAxisDirection(), *majorAxisPositions); | |
996 insertItemIntoGrid(*autoGridItem, *emptyGridArea); | |
997 | |
998 if (!isGridAutoFlowDense) | |
999 minorAxisCursors.set(majorAxisInitialPosition, isForColumns ? emptyG
ridArea->rows.resolvedInitialPosition.toInt() : emptyGridArea->columns.resolvedI
nitialPosition.toInt()); | |
1000 } | |
1001 } | |
1002 | |
1003 void RenderGrid::placeAutoMajorAxisItemsOnGrid(const Vector<LayoutBox*>& autoGri
dItems) | |
1004 { | |
1005 std::pair<size_t, size_t> autoPlacementCursor = std::make_pair(0, 0); | |
1006 bool isGridAutoFlowDense = style()->isGridAutoFlowAlgorithmDense(); | |
1007 | |
1008 for (const auto& autoGridItem : autoGridItems) { | |
1009 placeAutoMajorAxisItemOnGrid(*autoGridItem, autoPlacementCursor); | |
1010 | |
1011 // If grid-auto-flow is dense, reset auto-placement cursor. | |
1012 if (isGridAutoFlowDense) { | |
1013 autoPlacementCursor.first = 0; | |
1014 autoPlacementCursor.second = 0; | |
1015 } | |
1016 } | |
1017 } | |
1018 | |
1019 void RenderGrid::placeAutoMajorAxisItemOnGrid(LayoutBox& gridItem, std::pair<siz
e_t, size_t>& autoPlacementCursor) | |
1020 { | |
1021 OwnPtr<GridSpan> minorAxisPositions = GridResolvedPosition::resolveGridPosit
ionsFromStyle(*style(), gridItem, autoPlacementMinorAxisDirection()); | |
1022 ASSERT(!GridResolvedPosition::resolveGridPositionsFromStyle(*style(), gridIt
em, autoPlacementMajorAxisDirection())); | |
1023 GridSpan majorAxisPositions = GridResolvedPosition::resolveGridPositionsFrom
AutoPlacementPosition(*style(), gridItem, autoPlacementMajorAxisDirection(), Gri
dResolvedPosition(0)); | |
1024 | |
1025 const size_t endOfMajorAxis = (autoPlacementMajorAxisDirection() == ForColum
ns) ? gridColumnCount() : gridRowCount(); | |
1026 size_t majorAxisAutoPlacementCursor = autoPlacementMajorAxisDirection() == F
orColumns ? autoPlacementCursor.second : autoPlacementCursor.first; | |
1027 size_t minorAxisAutoPlacementCursor = autoPlacementMajorAxisDirection() == F
orColumns ? autoPlacementCursor.first : autoPlacementCursor.second; | |
1028 | |
1029 OwnPtr<GridCoordinate> emptyGridArea; | |
1030 if (minorAxisPositions) { | |
1031 // Move to the next track in major axis if initial position in minor axi
s is before auto-placement cursor. | |
1032 if (minorAxisPositions->resolvedInitialPosition.toInt() < minorAxisAutoP
lacementCursor) | |
1033 majorAxisAutoPlacementCursor++; | |
1034 | |
1035 if (majorAxisAutoPlacementCursor < endOfMajorAxis) { | |
1036 GridIterator iterator(m_grid, autoPlacementMinorAxisDirection(), min
orAxisPositions->resolvedInitialPosition.toInt(), majorAxisAutoPlacementCursor); | |
1037 emptyGridArea = iterator.nextEmptyGridArea(minorAxisPositions->integ
erSpan(), majorAxisPositions.integerSpan()); | |
1038 } | |
1039 | |
1040 if (!emptyGridArea) | |
1041 emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(g
ridItem, autoPlacementMinorAxisDirection(), *minorAxisPositions); | |
1042 } else { | |
1043 GridSpan minorAxisPositions = GridResolvedPosition::resolveGridPositions
FromAutoPlacementPosition(*style(), gridItem, autoPlacementMinorAxisDirection(),
GridResolvedPosition(0)); | |
1044 | |
1045 for (size_t majorAxisIndex = majorAxisAutoPlacementCursor; majorAxisInde
x < endOfMajorAxis; ++majorAxisIndex) { | |
1046 GridIterator iterator(m_grid, autoPlacementMajorAxisDirection(), maj
orAxisIndex, minorAxisAutoPlacementCursor); | |
1047 emptyGridArea = iterator.nextEmptyGridArea(majorAxisPositions.intege
rSpan(), minorAxisPositions.integerSpan()); | |
1048 | |
1049 if (emptyGridArea) { | |
1050 // Check that it fits in the minor axis direction, as we shouldn
't grow in that direction here (it was already managed in populateExplicitGridAn
dOrderIterator()). | |
1051 GridResolvedPosition minorAxisFinalPositionIndex = autoPlacement
MinorAxisDirection() == ForColumns ? emptyGridArea->columns.resolvedFinalPositio
n : emptyGridArea->rows.resolvedFinalPosition; | |
1052 const size_t endOfMinorAxis = autoPlacementMinorAxisDirection()
== ForColumns ? gridColumnCount() : gridRowCount(); | |
1053 if (minorAxisFinalPositionIndex.toInt() < endOfMinorAxis) | |
1054 break; | |
1055 | |
1056 // Discard empty grid area as it does not fit in the minor axis
direction. | |
1057 // We don't need to create a new empty grid area yet as we might
find a valid one in the next iteration. | |
1058 emptyGridArea = nullptr; | |
1059 } | |
1060 | |
1061 // As we're moving to the next track in the major axis we should res
et the auto-placement cursor in the minor axis. | |
1062 minorAxisAutoPlacementCursor = 0; | |
1063 } | |
1064 | |
1065 if (!emptyGridArea) | |
1066 emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(g
ridItem, autoPlacementMinorAxisDirection(), minorAxisPositions); | |
1067 } | |
1068 | |
1069 insertItemIntoGrid(gridItem, *emptyGridArea); | |
1070 // Move auto-placement cursor to the new position. | |
1071 autoPlacementCursor.first = emptyGridArea->rows.resolvedInitialPosition.toIn
t(); | |
1072 autoPlacementCursor.second = emptyGridArea->columns.resolvedInitialPosition.
toInt(); | |
1073 } | |
1074 | |
1075 GridTrackSizingDirection RenderGrid::autoPlacementMajorAxisDirection() const | |
1076 { | |
1077 return style()->isGridAutoFlowDirectionColumn() ? ForColumns : ForRows; | |
1078 } | |
1079 | |
1080 GridTrackSizingDirection RenderGrid::autoPlacementMinorAxisDirection() const | |
1081 { | |
1082 return style()->isGridAutoFlowDirectionColumn() ? ForRows : ForColumns; | |
1083 } | |
1084 | |
1085 void RenderGrid::dirtyGrid() | |
1086 { | |
1087 // Even if this could be redundant, it could be seen as a defensive strategy
against | |
1088 // style changes events happening during the layout phase or even while the
painting process | |
1089 // is still ongoing. | |
1090 // Forcing a new layout for the Grid render would cancel any ongoing paintin
g and ensure | |
1091 // the grid and its children are correctly laid out according to the new sty
le rules. | |
1092 setNeedsLayout(); | |
1093 | |
1094 m_grid.resize(0); | |
1095 m_gridItemCoordinate.clear(); | |
1096 m_gridIsDirty = true; | |
1097 m_gridItemsOverflowingGridArea.resize(0); | |
1098 m_gridItemsIndexesMap.clear(); | |
1099 } | |
1100 | |
1101 void RenderGrid::layoutGridItems() | |
1102 { | |
1103 placeItemsOnGrid(); | |
1104 | |
1105 LayoutUnit availableSpaceForColumns = availableLogicalWidth(); | |
1106 LayoutUnit availableSpaceForRows = availableLogicalHeight(IncludeMarginBorde
rPadding); | |
1107 GridSizingData sizingData(gridColumnCount(), gridRowCount()); | |
1108 computeUsedBreadthOfGridTracks(ForColumns, sizingData, availableSpaceForColu
mns); | |
1109 ASSERT(tracksAreWiderThanMinTrackBreadth(ForColumns, sizingData.columnTracks
)); | |
1110 computeUsedBreadthOfGridTracks(ForRows, sizingData, availableSpaceForRows); | |
1111 ASSERT(tracksAreWiderThanMinTrackBreadth(ForRows, sizingData.rowTracks)); | |
1112 | |
1113 populateGridPositions(sizingData, availableSpaceForColumns, availableSpaceFo
rRows); | |
1114 m_gridItemsOverflowingGridArea.resize(0); | |
1115 | |
1116 LayoutUnit columnOffset = contentPositionAndDistributionColumnOffset(availab
leSpaceForColumns, style()->justifyContent(), style()->justifyContentDistributio
n(), style()->justifyContentOverflowAlignment(), m_columnPositions.size() - 1); | |
1117 LayoutUnit rowOffset = contentPositionAndDistributionRowOffset(availableSpac
eForRows, style()->alignContent(), style()->alignContentDistribution(), style()-
>alignContentOverflowAlignment(), m_rowPositions.size() - 1); | |
1118 LayoutSize contentPositionOffset(columnOffset, rowOffset); | |
1119 | |
1120 for (LayoutBox* child = firstChildBox(); child; child = child->nextSiblingBo
x()) { | |
1121 if (child->isOutOfFlowPositioned()) { | |
1122 child->containingBlock()->insertPositionedObject(child); | |
1123 continue; | |
1124 } | |
1125 | |
1126 // Because the grid area cannot be styled, we don't need to adjust | |
1127 // the grid breadth to account for 'box-sizing'. | |
1128 LayoutUnit oldOverrideContainingBlockContentLogicalWidth = child->hasOve
rrideContainingBlockLogicalWidth() ? child->overrideContainingBlockContentLogica
lWidth() : LayoutUnit(); | |
1129 LayoutUnit oldOverrideContainingBlockContentLogicalHeight = child->hasOv
errideContainingBlockLogicalHeight() ? child->overrideContainingBlockContentLogi
calHeight() : LayoutUnit(); | |
1130 | |
1131 LayoutUnit overrideContainingBlockContentLogicalWidth = gridAreaBreadthF
orChild(*child, ForColumns, sizingData.columnTracks); | |
1132 LayoutUnit overrideContainingBlockContentLogicalHeight = gridAreaBreadth
ForChild(*child, ForRows, sizingData.rowTracks); | |
1133 | |
1134 SubtreeLayoutScope layoutScope(*child); | |
1135 if (oldOverrideContainingBlockContentLogicalWidth != overrideContainingB
lockContentLogicalWidth || (oldOverrideContainingBlockContentLogicalHeight != ov
errideContainingBlockContentLogicalHeight && child->hasRelativeLogicalHeight())) | |
1136 layoutScope.setNeedsLayout(child); | |
1137 | |
1138 child->setOverrideContainingBlockContentLogicalWidth(overrideContainingB
lockContentLogicalWidth); | |
1139 child->setOverrideContainingBlockContentLogicalHeight(overrideContaining
BlockContentLogicalHeight); | |
1140 | |
1141 // Stretching logic might force a child layout, so we need to run it bef
ore the layoutIfNeeded | |
1142 // call to avoid unnecessary relayouts. This might imply that child marg
ins, needed to correctly | |
1143 // determine the available space before stretching, are not set yet. | |
1144 applyStretchAlignmentToChildIfNeeded(*child, overrideContainingBlockCont
entLogicalHeight); | |
1145 | |
1146 child->layoutIfNeeded(); | |
1147 | |
1148 #if ENABLE(ASSERT) | |
1149 const GridCoordinate& coordinate = cachedGridCoordinate(*child); | |
1150 ASSERT(coordinate.columns.resolvedInitialPosition.toInt() < sizingData.c
olumnTracks.size()); | |
1151 ASSERT(coordinate.rows.resolvedInitialPosition.toInt() < sizingData.rowT
racks.size()); | |
1152 #endif | |
1153 child->setLogicalLocation(findChildLogicalPosition(*child, contentPositi
onOffset)); | |
1154 | |
1155 // Keep track of children overflowing their grid area as we might need t
o paint them even if the grid-area is | |
1156 // not visible | |
1157 if (child->logicalHeight() > overrideContainingBlockContentLogicalHeight | |
1158 || child->logicalWidth() > overrideContainingBlockContentLogicalWidt
h) | |
1159 m_gridItemsOverflowingGridArea.append(child); | |
1160 } | |
1161 | |
1162 for (const auto& row : sizingData.rowTracks) | |
1163 setLogicalHeight(logicalHeight() + row.baseSize()); | |
1164 | |
1165 // Min / max logical height is handled by the call to updateLogicalHeight in
layoutBlock. | |
1166 | |
1167 setLogicalHeight(logicalHeight() + borderAndPaddingLogicalHeight()); | |
1168 } | |
1169 | |
1170 void RenderGrid::layoutPositionedObjects(bool relayoutChildren, PositionedLayout
Behavior info) | |
1171 { | |
1172 TrackedRendererListHashSet* positionedDescendants = positionedObjects(); | |
1173 if (!positionedDescendants) | |
1174 return; | |
1175 | |
1176 bool containerHasHorizontalWritingMode = isHorizontalWritingMode(); | |
1177 for (auto* child : *positionedDescendants) { | |
1178 bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != cont
ainerHasHorizontalWritingMode; | |
1179 if (hasOrthogonalWritingMode) { | |
1180 // FIXME: Properly support orthogonal writing mode. | |
1181 continue; | |
1182 } | |
1183 | |
1184 // FIXME: Detect properly if start/end is auto for inexistent named grid
lines. | |
1185 bool columnStartIsAuto = child->style()->gridColumnStart().isAuto(); | |
1186 LayoutUnit columnOffset = LayoutUnit(0); | |
1187 LayoutUnit columnBreadth = LayoutUnit(0); | |
1188 offsetAndBreadthForPositionedChild(*child, ForColumns, columnStartIsAuto
, child->style()->gridColumnEnd().isAuto(), columnOffset, columnBreadth); | |
1189 bool rowStartIsAuto = child->style()->gridRowStart().isAuto(); | |
1190 LayoutUnit rowOffset = LayoutUnit(0); | |
1191 LayoutUnit rowBreadth = LayoutUnit(0); | |
1192 offsetAndBreadthForPositionedChild(*child, ForRows, rowStartIsAuto, chil
d->style()->gridRowEnd().isAuto(), rowOffset, rowBreadth); | |
1193 | |
1194 child->setOverrideContainingBlockContentLogicalWidth(columnBreadth); | |
1195 child->setOverrideContainingBlockContentLogicalHeight(rowBreadth); | |
1196 child->setExtraInlineOffset(columnOffset); | |
1197 child->setExtraBlockOffset(rowOffset); | |
1198 | |
1199 if (child->parent() == this) { | |
1200 // If column/row start is not auto the padding has been already comp
uted in offsetAndBreadthForPositionedChild(). | |
1201 Layer* childLayer = child->layer(); | |
1202 if (columnStartIsAuto) | |
1203 childLayer->setStaticInlinePosition(borderAndPaddingStart()); | |
1204 else | |
1205 childLayer->setStaticInlinePosition(borderStart() + columnOffset
); | |
1206 if (rowStartIsAuto) | |
1207 childLayer->setStaticBlockPosition(borderAndPaddingBefore()); | |
1208 else | |
1209 childLayer->setStaticBlockPosition(borderBefore() + rowOffset); | |
1210 } | |
1211 } | |
1212 | |
1213 RenderBlock::layoutPositionedObjects(relayoutChildren, info); | |
1214 } | |
1215 | |
1216 void RenderGrid::offsetAndBreadthForPositionedChild(const LayoutBox& child, Grid
TrackSizingDirection direction, bool startIsAuto, bool endIsAuto, LayoutUnit& of
fset, LayoutUnit& breadth) | |
1217 { | |
1218 ASSERT(child.isHorizontalWritingMode() == isHorizontalWritingMode()); | |
1219 | |
1220 OwnPtr<GridSpan> positions = GridResolvedPosition::resolveGridPositionsFromS
tyle(*style(), child, direction); | |
1221 if (!positions) { | |
1222 offset = LayoutUnit(0); | |
1223 breadth = (direction == ForColumns) ? clientLogicalWidth() : clientLogic
alHeight(); | |
1224 return; | |
1225 } | |
1226 | |
1227 GridResolvedPosition firstPosition = GridResolvedPosition(0); | |
1228 GridResolvedPosition initialPosition = startIsAuto ? firstPosition : positio
ns->resolvedInitialPosition; | |
1229 GridResolvedPosition lastPosition = GridResolvedPosition((direction == ForCo
lumns ? gridColumnCount() : gridRowCount()) - 1); | |
1230 GridResolvedPosition finalPosition = endIsAuto ? lastPosition : positions->r
esolvedFinalPosition; | |
1231 | |
1232 // Positioned children do not grow the grid, so we need to clamp the positio
ns to avoid ending up outside of it. | |
1233 initialPosition = std::min<GridResolvedPosition>(initialPosition, lastPositi
on); | |
1234 finalPosition = std::min<GridResolvedPosition>(finalPosition, lastPosition); | |
1235 | |
1236 LayoutUnit start = startIsAuto ? LayoutUnit(0) : (direction == ForColumns) ?
m_columnPositions[initialPosition.toInt()] : m_rowPositions[initialPosition.to
Int()]; | |
1237 LayoutUnit end = endIsAuto ? (direction == ForColumns) ? logicalWidth() : lo
gicalHeight() : (direction == ForColumns) ? m_columnPositions[finalPosition.nex
t().toInt()] : m_rowPositions[finalPosition.next().toInt()]; | |
1238 | |
1239 breadth = end - start; | |
1240 | |
1241 if (startIsAuto) | |
1242 breadth -= (direction == ForColumns) ? borderStart() : borderBefore(); | |
1243 else | |
1244 start -= ((direction == ForColumns) ? borderStart() : borderBefore()); | |
1245 | |
1246 if (endIsAuto) { | |
1247 breadth -= (direction == ForColumns) ? borderEnd() : borderAfter(); | |
1248 breadth -= scrollbarLogicalWidth(); | |
1249 } | |
1250 | |
1251 offset = start; | |
1252 } | |
1253 | |
1254 GridCoordinate RenderGrid::cachedGridCoordinate(const LayoutBox& gridItem) const | |
1255 { | |
1256 ASSERT(m_gridItemCoordinate.contains(&gridItem)); | |
1257 return m_gridItemCoordinate.get(&gridItem); | |
1258 } | |
1259 | |
1260 LayoutUnit RenderGrid::gridAreaBreadthForChild(const LayoutBox& child, GridTrack
SizingDirection direction, const Vector<GridTrack>& tracks) const | |
1261 { | |
1262 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
1263 const GridSpan& span = (direction == ForColumns) ? coordinate.columns : coor
dinate.rows; | |
1264 LayoutUnit gridAreaBreadth = 0; | |
1265 for (GridSpan::iterator trackPosition = span.begin(); trackPosition != span.
end(); ++trackPosition) | |
1266 gridAreaBreadth += tracks[trackPosition.toInt()].baseSize(); | |
1267 return gridAreaBreadth; | |
1268 } | |
1269 | |
1270 void RenderGrid::populateGridPositions(const GridSizingData& sizingData, LayoutU
nit availableSpaceForColumns, LayoutUnit availableSpaceForRows) | |
1271 { | |
1272 unsigned numberOfColumnTracks = sizingData.columnTracks.size(); | |
1273 unsigned numberOfRowTracks = sizingData.rowTracks.size(); | |
1274 | |
1275 m_columnPositions.resize(numberOfColumnTracks + 1); | |
1276 m_columnPositions[0] = borderAndPaddingStart(); | |
1277 for (unsigned i = 0; i < numberOfColumnTracks; ++i) | |
1278 m_columnPositions[i + 1] = m_columnPositions[i] + sizingData.columnTrack
s[i].baseSize(); | |
1279 | |
1280 m_rowPositions.resize(numberOfRowTracks + 1); | |
1281 m_rowPositions[0] = borderAndPaddingBefore(); | |
1282 for (unsigned i = 0; i < numberOfRowTracks; ++i) | |
1283 m_rowPositions[i + 1] = m_rowPositions[i] + sizingData.rowTracks[i].base
Size(); | |
1284 } | |
1285 | |
1286 static LayoutUnit computeOverflowAlignmentOffset(OverflowAlignment overflow, Lay
outUnit startOfTrack, LayoutUnit endOfTrack, LayoutUnit childBreadth) | |
1287 { | |
1288 LayoutUnit trackBreadth = endOfTrack - startOfTrack; | |
1289 LayoutUnit offset = trackBreadth - childBreadth; | |
1290 | |
1291 // If overflow is 'safe', we have to make sure we don't overflow the 'start' | |
1292 // edge (potentially cause some data loss as the overflow is unreachable). | |
1293 if (overflow == OverflowAlignmentSafe) | |
1294 offset = std::max<LayoutUnit>(0, offset); | |
1295 | |
1296 // If we overflow our alignment container and overflow is 'true' (default),
we | |
1297 // ignore the overflow and just return the value regardless (which may cause
data | |
1298 // loss as we overflow the 'start' edge). | |
1299 return offset; | |
1300 } | |
1301 | |
1302 LayoutUnit RenderGrid::startOfColumnForChild(const LayoutBox& child) const | |
1303 { | |
1304 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
1305 LayoutUnit startOfColumn = m_columnPositions[coordinate.columns.resolvedInit
ialPosition.toInt()]; | |
1306 // The grid items should be inside the grid container's border box, that's w
hy they need to be shifted. | |
1307 return startOfColumn + marginStartForChild(child); | |
1308 } | |
1309 | |
1310 LayoutUnit RenderGrid::endOfColumnForChild(const LayoutBox& child) const | |
1311 { | |
1312 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
1313 LayoutUnit startOfColumn = m_columnPositions[coordinate.columns.resolvedInit
ialPosition.toInt()]; | |
1314 // The grid items should be inside the grid container's border box, that's w
hy they need to be shifted. | |
1315 LayoutUnit columnPosition = startOfColumn + marginStartForChild(child); | |
1316 | |
1317 LayoutUnit endOfColumn = m_columnPositions[coordinate.columns.resolvedFinalP
osition.next().toInt()]; | |
1318 // FIXME: This might not work as expected with orthogonal writing-modes. | |
1319 LayoutUnit offsetFromColumnPosition = computeOverflowAlignmentOffset(child.s
tyle()->justifySelfOverflowAlignment(), startOfColumn, endOfColumn, child.logica
lWidth() + child.marginLogicalWidth()); | |
1320 | |
1321 return columnPosition + offsetFromColumnPosition; | |
1322 } | |
1323 | |
1324 LayoutUnit RenderGrid::columnPositionLeft(const LayoutBox& child) const | |
1325 { | |
1326 if (style()->isLeftToRightDirection()) | |
1327 return startOfColumnForChild(child); | |
1328 | |
1329 return endOfColumnForChild(child); | |
1330 } | |
1331 | |
1332 LayoutUnit RenderGrid::columnPositionRight(const LayoutBox& child) const | |
1333 { | |
1334 if (!style()->isLeftToRightDirection()) | |
1335 return startOfColumnForChild(child); | |
1336 | |
1337 return endOfColumnForChild(child); | |
1338 } | |
1339 | |
1340 LayoutUnit RenderGrid::centeredColumnPositionForChild(const LayoutBox& child) co
nst | |
1341 { | |
1342 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
1343 LayoutUnit startOfColumn = m_columnPositions[coordinate.columns.resolvedInit
ialPosition.toInt()]; | |
1344 LayoutUnit endOfColumn = m_columnPositions[coordinate.columns.resolvedFinalP
osition.next().toInt()]; | |
1345 LayoutUnit columnPosition = startOfColumn + marginStartForChild(child); | |
1346 // FIXME: This might not work as expected with orthogonal writing-modes. | |
1347 LayoutUnit offsetFromColumnPosition = computeOverflowAlignmentOffset(child.s
tyle()->justifySelfOverflowAlignment(), startOfColumn, endOfColumn, child.logica
lWidth() + child.marginLogicalWidth()); | |
1348 | |
1349 return columnPosition + offsetFromColumnPosition / 2; | |
1350 } | |
1351 | |
1352 LayoutUnit RenderGrid::columnPositionForChild(const LayoutBox& child) const | |
1353 { | |
1354 bool hasOrthogonalWritingMode = child.isHorizontalWritingMode() != isHorizon
talWritingMode(); | |
1355 | |
1356 switch (LayoutStyle::resolveJustification(styleRef(), child.styleRef(), Item
PositionStretch)) { | |
1357 case ItemPositionSelfStart: | |
1358 // For orthogonal writing-modes, this computes to 'start' | |
1359 // FIXME: grid track sizing and positioning do not support orthogonal mo
des yet. | |
1360 if (hasOrthogonalWritingMode) | |
1361 return startOfColumnForChild(child); | |
1362 | |
1363 // self-start is based on the child's direction. That's why we need to c
heck against the grid container's direction. | |
1364 if (child.style()->direction() != style()->direction()) | |
1365 return endOfColumnForChild(child); | |
1366 | |
1367 return startOfColumnForChild(child); | |
1368 case ItemPositionSelfEnd: | |
1369 // For orthogonal writing-modes, this computes to 'start' | |
1370 // FIXME: grid track sizing and positioning do not support orthogonal mo
des yet. | |
1371 if (hasOrthogonalWritingMode) | |
1372 return endOfColumnForChild(child); | |
1373 | |
1374 // self-end is based on the child's direction. That's why we need to che
ck against the grid container's direction. | |
1375 if (child.style()->direction() != style()->direction()) | |
1376 return startOfColumnForChild(child); | |
1377 | |
1378 return endOfColumnForChild(child); | |
1379 case ItemPositionFlexStart: | |
1380 // Only used in flex layout, for other layout, it's equivalent to 'start
'. | |
1381 return startOfColumnForChild(child); | |
1382 case ItemPositionFlexEnd: | |
1383 // Only used in flex layout, for other layout, it's equivalent to 'end'. | |
1384 return endOfColumnForChild(child); | |
1385 case ItemPositionLeft: | |
1386 return columnPositionLeft(child); | |
1387 case ItemPositionRight: | |
1388 return columnPositionRight(child); | |
1389 case ItemPositionCenter: | |
1390 return centeredColumnPositionForChild(child); | |
1391 case ItemPositionStart: | |
1392 return startOfColumnForChild(child); | |
1393 case ItemPositionEnd: | |
1394 return endOfColumnForChild(child); | |
1395 case ItemPositionAuto: | |
1396 break; | |
1397 case ItemPositionStretch: | |
1398 return startOfColumnForChild(child); | |
1399 case ItemPositionBaseline: | |
1400 case ItemPositionLastBaseline: | |
1401 // FIXME: Implement the previous values. For now, we always 'start' alig
n the child. | |
1402 return startOfColumnForChild(child); | |
1403 } | |
1404 | |
1405 ASSERT_NOT_REACHED(); | |
1406 return 0; | |
1407 } | |
1408 | |
1409 LayoutUnit RenderGrid::endOfRowForChild(const LayoutBox& child) const | |
1410 { | |
1411 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
1412 | |
1413 LayoutUnit startOfRow = m_rowPositions[coordinate.rows.resolvedInitialPositi
on.toInt()]; | |
1414 // The grid items should be inside the grid container's border box, that's w
hy they need to be shifted. | |
1415 LayoutUnit rowPosition = startOfRow + marginBeforeForChild(child); | |
1416 | |
1417 LayoutUnit endOfRow = m_rowPositions[coordinate.rows.resolvedFinalPosition.n
ext().toInt()]; | |
1418 LayoutUnit offsetFromRowPosition = computeOverflowAlignmentOffset(child.styl
e()->alignSelfOverflowAlignment(), startOfRow, endOfRow, child.logicalHeight() +
child.marginLogicalHeight()); | |
1419 | |
1420 return rowPosition + offsetFromRowPosition; | |
1421 } | |
1422 | |
1423 LayoutUnit RenderGrid::startOfRowForChild(const LayoutBox& child) const | |
1424 { | |
1425 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
1426 | |
1427 LayoutUnit startOfRow = m_rowPositions[coordinate.rows.resolvedInitialPositi
on.toInt()]; | |
1428 // The grid items should be inside the grid container's border box, that's w
hy they need to be shifted. | |
1429 LayoutUnit rowPosition = startOfRow + marginBeforeForChild(child); | |
1430 | |
1431 return rowPosition; | |
1432 } | |
1433 | |
1434 LayoutUnit RenderGrid::centeredRowPositionForChild(const LayoutBox& child) const | |
1435 { | |
1436 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
1437 | |
1438 // The grid items should be inside the grid container's border box, that's w
hy they need to be shifted. | |
1439 LayoutUnit startOfRow = m_rowPositions[coordinate.rows.resolvedInitialPositi
on.toInt()]; | |
1440 LayoutUnit endOfRow = m_rowPositions[coordinate.rows.resolvedFinalPosition.n
ext().toInt()]; | |
1441 LayoutUnit rowPosition = startOfRow + marginBeforeForChild(child); | |
1442 LayoutUnit offsetFromRowPosition = computeOverflowAlignmentOffset(child.styl
e()->alignSelfOverflowAlignment(), startOfRow, endOfRow, child.logicalHeight() +
child.marginLogicalHeight()); | |
1443 | |
1444 return rowPosition + offsetFromRowPosition / 2; | |
1445 } | |
1446 | |
1447 static inline LayoutUnit constrainedChildIntrinsicContentLogicalHeight(const Lay
outBox& child) | |
1448 { | |
1449 LayoutUnit childIntrinsicContentLogicalHeight = child.intrinsicContentLogica
lHeight(); | |
1450 return child.constrainLogicalHeightByMinMax(childIntrinsicContentLogicalHeig
ht + child.borderAndPaddingLogicalHeight(), childIntrinsicContentLogicalHeight); | |
1451 } | |
1452 | |
1453 bool RenderGrid::allowedToStretchLogicalHeightForChild(const LayoutBox& child) c
onst | |
1454 { | |
1455 return child.style()->logicalHeight().isAuto() && !child.style()->marginBefo
reUsing(style()).isAuto() && !child.style()->marginAfterUsing(style()).isAuto(); | |
1456 } | |
1457 | |
1458 // FIXME: This logic is shared by RenderFlexibleBox, so it should be moved to La
youtBox. | |
1459 bool RenderGrid::needToStretchChildLogicalHeight(const LayoutBox& child) const | |
1460 { | |
1461 if (LayoutStyle::resolveAlignment(styleRef(), child.styleRef(), ItemPosition
Stretch) != ItemPositionStretch) | |
1462 return false; | |
1463 | |
1464 return isHorizontalWritingMode() && child.style()->height().isAuto(); | |
1465 } | |
1466 | |
1467 // FIXME: This logic is shared by RenderFlexibleBox, so it should be moved to La
youtBox. | |
1468 LayoutUnit RenderGrid::childIntrinsicHeight(const LayoutBox& child) const | |
1469 { | |
1470 if (child.isHorizontalWritingMode() && needToStretchChildLogicalHeight(child
)) | |
1471 return constrainedChildIntrinsicContentLogicalHeight(child); | |
1472 return child.size().height(); | |
1473 } | |
1474 | |
1475 // FIXME: This logic is shared by RenderFlexibleBox, so it should be moved to La
youtBox. | |
1476 LayoutUnit RenderGrid::childIntrinsicWidth(const LayoutBox& child) const | |
1477 { | |
1478 if (!child.isHorizontalWritingMode() && needToStretchChildLogicalHeight(chil
d)) | |
1479 return constrainedChildIntrinsicContentLogicalHeight(child); | |
1480 return child.size().width(); | |
1481 } | |
1482 | |
1483 // FIXME: This logic is shared by RenderFlexibleBox, so it should be moved to La
youtBox. | |
1484 LayoutUnit RenderGrid::intrinsicLogicalHeightForChild(const LayoutBox& child) co
nst | |
1485 { | |
1486 return isHorizontalWritingMode() ? childIntrinsicHeight(child) : childIntrin
sicWidth(child); | |
1487 } | |
1488 | |
1489 // FIXME: This logic is shared by RenderFlexibleBox, so it should be moved to La
youtBox. | |
1490 LayoutUnit RenderGrid::marginLogicalHeightForChild(const LayoutBox& child) const | |
1491 { | |
1492 return isHorizontalWritingMode() ? child.marginHeight() : child.marginWidth(
); | |
1493 } | |
1494 | |
1495 LayoutUnit RenderGrid::computeMarginLogicalHeightForChild(const LayoutBox& child
) const | |
1496 { | |
1497 LayoutUnit marginBefore; | |
1498 LayoutUnit marginAfter; | |
1499 child.computeMarginsForDirection(BlockDirection, this, child.containingBlock
LogicalWidthForContent(), child.logicalHeight(), marginBefore, marginAfter, | |
1500 child.style()->marginBeforeUsing(style()), | |
1501 child.style()->marginAfterUsing(style())); | |
1502 | |
1503 return marginBefore + marginAfter; | |
1504 } | |
1505 | |
1506 LayoutUnit RenderGrid::availableAlignmentSpaceForChildBeforeStretching(LayoutUni
t gridAreaBreadthForChild, const LayoutBox& child) const | |
1507 { | |
1508 LayoutUnit childMarginLogicalHeight = marginLogicalHeightForChild(child); | |
1509 | |
1510 // Because we want to avoid multiple layouts, stretching logic might be perf
ormed before | |
1511 // children are laid out, so we can't use the child cached values. Hence, we
need to | |
1512 // compute margins in order to determine the available height before stretch
ing. | |
1513 if (childMarginLogicalHeight == 0) | |
1514 childMarginLogicalHeight = computeMarginLogicalHeightForChild(child); | |
1515 | |
1516 LayoutUnit childLogicalHeight = childMarginLogicalHeight + intrinsicLogicalH
eightForChild(child); | |
1517 return gridAreaBreadthForChild - childLogicalHeight; | |
1518 } | |
1519 | |
1520 // FIXME: This logic is shared by RenderFlexibleBox, so it should be moved to La
youtBox. | |
1521 void RenderGrid::applyStretchAlignmentToChildIfNeeded(LayoutBox& child, LayoutUn
it gridAreaBreadthForChild) | |
1522 { | |
1523 if (LayoutStyle::resolveAlignment(styleRef(), child.styleRef(), ItemPosition
Stretch) != ItemPositionStretch) | |
1524 return; | |
1525 | |
1526 bool hasOrthogonalWritingMode = child.isHorizontalWritingMode() != isHorizon
talWritingMode(); | |
1527 if (allowedToStretchLogicalHeightForChild(child)) { | |
1528 // FIXME: If the child has orthogonal flow, then it already has an overr
ide height set, so use it. | |
1529 // FIXME: grid track sizing and positioning do not support orthogonal mo
des yet. | |
1530 if (!hasOrthogonalWritingMode) { | |
1531 LayoutUnit heightBeforeStretching = needToStretchChildLogicalHeight(
child) ? constrainedChildIntrinsicContentLogicalHeight(child) : child.logicalHei
ght(); | |
1532 LayoutUnit stretchedLogicalHeight = heightBeforeStretching + availab
leAlignmentSpaceForChildBeforeStretching(gridAreaBreadthForChild, child); | |
1533 LayoutUnit desiredLogicalHeight = child.constrainLogicalHeightByMinM
ax(stretchedLogicalHeight, heightBeforeStretching - child.borderAndPaddingLogica
lHeight()); | |
1534 LayoutUnit desiredLogicalContentHeight = desiredLogicalHeight - chil
d.borderAndPaddingLogicalHeight(); | |
1535 | |
1536 // FIXME: Can avoid laying out here in some cases. See https://webki
t.org/b/87905. | |
1537 if (desiredLogicalHeight != child.logicalHeight() || !child.hasOverr
ideHeight() || desiredLogicalContentHeight != child.overrideLogicalContentHeight
()) { | |
1538 child.setOverrideLogicalContentHeight(desiredLogicalContentHeigh
t); | |
1539 child.setLogicalHeight(0); | |
1540 child.forceChildLayout(); | |
1541 } | |
1542 } | |
1543 } | |
1544 } | |
1545 | |
1546 LayoutUnit RenderGrid::rowPositionForChild(const LayoutBox& child) const | |
1547 { | |
1548 bool hasOrthogonalWritingMode = child.isHorizontalWritingMode() != isHorizon
talWritingMode(); | |
1549 switch (LayoutStyle::resolveAlignment(styleRef(), child.styleRef(), ItemPosi
tionStretch)) { | |
1550 case ItemPositionSelfStart: | |
1551 // If orthogonal writing-modes, this computes to 'start'. | |
1552 // FIXME: grid track sizing and positioning do not support orthogonal mo
des yet. | |
1553 if (hasOrthogonalWritingMode) | |
1554 return startOfRowForChild(child); | |
1555 | |
1556 // self-start is based on the child's block axis direction. That's why w
e need to check against the grid container's block flow. | |
1557 if (child.style()->writingMode() != style()->writingMode()) | |
1558 return endOfRowForChild(child); | |
1559 | |
1560 return startOfRowForChild(child); | |
1561 case ItemPositionSelfEnd: | |
1562 // If orthogonal writing-modes, this computes to 'end'. | |
1563 // FIXME: grid track sizing and positioning do not support orthogonal mo
des yet. | |
1564 if (hasOrthogonalWritingMode) | |
1565 return endOfRowForChild(child); | |
1566 | |
1567 // self-end is based on the child's block axis direction. That's why we
need to check against the grid container's block flow. | |
1568 if (child.style()->writingMode() != style()->writingMode()) | |
1569 return startOfRowForChild(child); | |
1570 | |
1571 return endOfRowForChild(child); | |
1572 case ItemPositionLeft: | |
1573 // The alignment axis (column axis) and the inline axis are parallell in | |
1574 // orthogonal writing mode. | |
1575 // FIXME: grid track sizing and positioning do not support orthogonal mo
des yet. | |
1576 if (hasOrthogonalWritingMode) | |
1577 return startOfRowForChild(child); | |
1578 | |
1579 // Otherwise this this is equivalent to 'start'. | |
1580 return startOfRowForChild(child); | |
1581 case ItemPositionRight: | |
1582 // The alignment axis (column axis) and the inline axis are parallell in | |
1583 // orthogonal writing mode. | |
1584 // FIXME: grid track sizing and positioning do not support orthogonal mo
des yet. | |
1585 if (hasOrthogonalWritingMode) | |
1586 return endOfRowForChild(child); | |
1587 | |
1588 // Otherwise this this is equivalent to 'start'. | |
1589 return startOfRowForChild(child); | |
1590 case ItemPositionCenter: | |
1591 return centeredRowPositionForChild(child); | |
1592 // Only used in flex layout, for other layout, it's equivalent to 'start
'. | |
1593 case ItemPositionFlexStart: | |
1594 case ItemPositionStart: | |
1595 return startOfRowForChild(child); | |
1596 // Only used in flex layout, for other layout, it's equivalent to 'end'. | |
1597 case ItemPositionFlexEnd: | |
1598 case ItemPositionEnd: | |
1599 return endOfRowForChild(child); | |
1600 case ItemPositionStretch: | |
1601 return startOfRowForChild(child); | |
1602 case ItemPositionBaseline: | |
1603 case ItemPositionLastBaseline: | |
1604 // FIXME: Implement the ItemPositionBaseline value. For now, we always '
start' align the child. | |
1605 return startOfRowForChild(child); | |
1606 case ItemPositionAuto: | |
1607 break; | |
1608 } | |
1609 | |
1610 ASSERT_NOT_REACHED(); | |
1611 return 0; | |
1612 } | |
1613 | |
1614 ContentPosition static resolveContentDistributionFallback(ContentDistributionTyp
e distribution) | |
1615 { | |
1616 switch (distribution) { | |
1617 case ContentDistributionSpaceBetween: | |
1618 return ContentPositionStart; | |
1619 case ContentDistributionSpaceAround: | |
1620 return ContentPositionCenter; | |
1621 case ContentDistributionSpaceEvenly: | |
1622 return ContentPositionCenter; | |
1623 case ContentDistributionStretch: | |
1624 return ContentPositionStart; | |
1625 case ContentDistributionDefault: | |
1626 return ContentPositionAuto; | |
1627 } | |
1628 | |
1629 ASSERT_NOT_REACHED(); | |
1630 return ContentPositionAuto; | |
1631 } | |
1632 | |
1633 static inline LayoutUnit offsetToStartEdge(bool isLeftToRight, LayoutUnit availa
bleSpace) | |
1634 { | |
1635 return isLeftToRight ? LayoutUnit(0) : availableSpace; | |
1636 } | |
1637 | |
1638 static inline LayoutUnit offsetToEndEdge(bool isLeftToRight, LayoutUnit availabl
eSpace) | |
1639 { | |
1640 return !isLeftToRight ? LayoutUnit(0) : availableSpace; | |
1641 } | |
1642 | |
1643 LayoutUnit RenderGrid::contentPositionAndDistributionColumnOffset(LayoutUnit ava
ilableFreeSpace, ContentPosition position, ContentDistributionType distribution,
OverflowAlignment overflow, unsigned numberOfGridTracks) const | |
1644 { | |
1645 if (overflow == OverflowAlignmentSafe && availableFreeSpace <= 0) | |
1646 return 0; | |
1647 | |
1648 // FIXME: for the time being, spec states that it will always fallback for G
rids, but | |
1649 // discussion is ongoing. | |
1650 if (distribution != ContentDistributionDefault && position == ContentPositio
nAuto) | |
1651 position = resolveContentDistributionFallback(distribution); | |
1652 | |
1653 switch (position) { | |
1654 case ContentPositionLeft: | |
1655 return 0; | |
1656 case ContentPositionRight: | |
1657 return availableFreeSpace; | |
1658 case ContentPositionCenter: | |
1659 return availableFreeSpace / 2; | |
1660 case ContentPositionFlexEnd: | |
1661 // Only used in flex layout, for other layout, it's equivalent to 'end'. | |
1662 case ContentPositionEnd: | |
1663 return offsetToEndEdge(style()->isLeftToRightDirection(), availableFreeS
pace); | |
1664 case ContentPositionFlexStart: | |
1665 // Only used in flex layout, for other layout, it's equivalent to 'start
'. | |
1666 case ContentPositionStart: | |
1667 return offsetToStartEdge(style()->isLeftToRightDirection(), availableFre
eSpace); | |
1668 case ContentPositionBaseline: | |
1669 case ContentPositionLastBaseline: | |
1670 // FIXME: Implement the previous values. For now, we always 'start' alig
n. | |
1671 // crbug.com/234191 | |
1672 return offsetToStartEdge(style()->isLeftToRightDirection(), availableFre
eSpace); | |
1673 case ContentPositionAuto: | |
1674 break; | |
1675 } | |
1676 | |
1677 ASSERT_NOT_REACHED(); | |
1678 return 0; | |
1679 } | |
1680 | |
1681 LayoutUnit RenderGrid::contentPositionAndDistributionRowOffset(LayoutUnit availa
bleFreeSpace, ContentPosition position, ContentDistributionType distribution, Ov
erflowAlignment overflow, unsigned numberOfGridTracks) const | |
1682 { | |
1683 if (overflow == OverflowAlignmentSafe && availableFreeSpace <= 0) | |
1684 return 0; | |
1685 | |
1686 // FIXME: for the time being, spec states that it will always fallback for G
rids, but | |
1687 // discussion is ongoing. | |
1688 if (distribution != ContentDistributionDefault && position == ContentPositio
nAuto) | |
1689 position = resolveContentDistributionFallback(distribution); | |
1690 | |
1691 switch (position) { | |
1692 case ContentPositionLeft: | |
1693 // The align-content's axis is always orthogonal to the inline-axis. | |
1694 return 0; | |
1695 case ContentPositionRight: | |
1696 // The align-content's axis is always orthogonal to the inline-axis. | |
1697 return 0; | |
1698 case ContentPositionCenter: | |
1699 return availableFreeSpace / 2; | |
1700 case ContentPositionFlexEnd: | |
1701 // Only used in flex layout, for other layout, it's equivalent to 'End'. | |
1702 case ContentPositionEnd: | |
1703 return availableFreeSpace; | |
1704 case ContentPositionFlexStart: | |
1705 // Only used in flex layout, for other layout, it's equivalent to 'Start
'. | |
1706 case ContentPositionStart: | |
1707 return 0; | |
1708 case ContentPositionBaseline: | |
1709 case ContentPositionLastBaseline: | |
1710 // FIXME: Implement the previous values. For now, we always start align. | |
1711 // crbug.com/234191 | |
1712 return 0; | |
1713 case ContentPositionAuto: | |
1714 break; | |
1715 } | |
1716 | |
1717 ASSERT_NOT_REACHED(); | |
1718 return 0; | |
1719 } | |
1720 | |
1721 LayoutPoint RenderGrid::findChildLogicalPosition(const LayoutBox& child, LayoutS
ize contentAlignmentOffset) const | |
1722 { | |
1723 LayoutUnit columnPosition = columnPositionForChild(child); | |
1724 // We stored m_columnPositions's data ignoring the direction, hence we might
need now | |
1725 // to translate positions from RTL to LTR, as it's more convenient for paint
ing. | |
1726 if (!style()->isLeftToRightDirection()) | |
1727 columnPosition = (m_columnPositions[m_columnPositions.size() - 1] + bord
erAndPaddingLogicalLeft()) - columnPosition - child.logicalWidth(); | |
1728 | |
1729 // The Content Alignment offset accounts for the RTL to LTR flip. | |
1730 LayoutPoint childLocation(columnPosition, rowPositionForChild(child)); | |
1731 childLocation.move(contentAlignmentOffset); | |
1732 | |
1733 return childLocation; | |
1734 } | |
1735 | |
1736 void RenderGrid::paintChildren(const PaintInfo& paintInfo, const LayoutPoint& pa
intOffset) | |
1737 { | |
1738 GridPainter(*this).paintChildren(paintInfo, paintOffset); | |
1739 } | |
1740 | |
1741 const char* RenderGrid::renderName() const | |
1742 { | |
1743 if (isFloating()) | |
1744 return "RenderGrid (floating)"; | |
1745 if (isOutOfFlowPositioned()) | |
1746 return "RenderGrid (positioned)"; | |
1747 if (isAnonymous()) | |
1748 return "RenderGrid (generated)"; | |
1749 if (isRelPositioned()) | |
1750 return "RenderGrid (relative positioned)"; | |
1751 return "RenderGrid"; | |
1752 } | |
1753 | |
1754 } // namespace blink | |
OLD | NEW |