1 /*
2 * Copyright (C) 2011 Google 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 are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "core/rendering/RenderFlexibleBox.h"
33
34 #include "core/rendering/FastTextAutosizer.h"
35 #include "core/rendering/LayoutRepainter.h"
36 #include "core/rendering/RenderLayer.h"
37 #include "core/rendering/RenderView.h"
38 #include "platform/LengthFunctions.h"
39 #include "wtf/MathExtras.h"
40 #include <limits>
41
42 namespace WebCore {
43
44 struct RenderFlexibleBox::LineContext {
LineContextWebCore::RenderFlexibleBox::LineContext45 LineContext(LayoutUnit crossAxisOffset, LayoutUnit crossAxisExtent, size_t numberOfChildren, LayoutUnit maxAscent)
46 : crossAxisOffset(crossAxisOffset)
47 , crossAxisExtent(crossAxisExtent)
48 , numberOfChildren(numberOfChildren)
49 , maxAscent(maxAscent)
50 {
51 }
52
53 LayoutUnit crossAxisOffset;
54 LayoutUnit crossAxisExtent;
55 size_t numberOfChildren;
56 LayoutUnit maxAscent;
57 };
58
59 struct RenderFlexibleBox::Violation {
ViolationWebCore::RenderFlexibleBox::Violation60 Violation(RenderBox* child, LayoutUnit childSize)
61 : child(child)
62 , childSize(childSize)
63 {
64 }
65
66 RenderBox* child;
67 LayoutUnit childSize;
68 };
69
70
RenderFlexibleBox(Element * element)71 RenderFlexibleBox::RenderFlexibleBox(Element* element)
72 : RenderBlock(element)
73 , m_orderIterator(this)
74 , m_numberOfInFlowChildrenOnFirstLine(-1)
75 {
76 setChildrenInline(false); // All of our children must be block-level.
77 }
78
~RenderFlexibleBox()79 RenderFlexibleBox::~RenderFlexibleBox()
80 {
81 }
82
createAnonymous(Document * document)83 RenderFlexibleBox* RenderFlexibleBox::createAnonymous(Document* document)
84 {
85 RenderFlexibleBox* renderer = new RenderFlexibleBox(0);
86 renderer->setDocumentForAnonymous(document);
87 return renderer;
88 }
89
renderName() const90 const char* RenderFlexibleBox::renderName() const
91 {
92 return "RenderFlexibleBox";
93 }
94
computeIntrinsicLogicalWidths(LayoutUnit & minLogicalWidth,LayoutUnit & maxLogicalWidth) const95 void RenderFlexibleBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
96 {
97 // FIXME: We're ignoring flex-basis here and we shouldn't. We can't start honoring it though until
98 // the flex shorthand stops setting it to 0.
99 // See https://bugs.webkit.org/show_bug.cgi?id=116117 and http://crbug.com/240765.
100 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
101 if (child->isOutOfFlowPositioned())
102 continue;
103
104 LayoutUnit margin = marginIntrinsicLogicalWidthForChild(child);
105 bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != isHorizontalWritingMode();
106 LayoutUnit minPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->minPreferredLogicalWidth();
107 LayoutUnit maxPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->maxPreferredLogicalWidth();
108 minPreferredLogicalWidth += margin;
109 maxPreferredLogicalWidth += margin;
110 if (!isColumnFlow()) {
111 maxLogicalWidth += maxPreferredLogicalWidth;
112 if (isMultiline()) {
113 // For multiline, the min preferred width is if you put a break between each item.
114 minLogicalWidth = std::max(minLogicalWidth, minPreferredLogicalWidth);
115 } else
116 minLogicalWidth += minPreferredLogicalWidth;
117 } else {
118 minLogicalWidth = std::max(minPreferredLogicalWidth, minLogicalWidth);
119 if (isMultiline()) {
120 // For multiline, the max preferred width is if you never break between items.
121 maxLogicalWidth += maxPreferredLogicalWidth;
122 } else
123 maxLogicalWidth = std::max(maxPreferredLogicalWidth, maxLogicalWidth);
124 }
125 }
126
127 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
128
129 LayoutUnit scrollbarWidth = instrinsicScrollbarLogicalWidth();
130 maxLogicalWidth += scrollbarWidth;
131 minLogicalWidth += scrollbarWidth;
132 }
133
synthesizedBaselineFromContentBox(const RenderBox * box,LineDirectionMode direction)134 static int synthesizedBaselineFromContentBox(const RenderBox* box, LineDirectionMode direction)
135 {
136 return direction == HorizontalLine ? box->borderTop() + box->paddingTop() + box->contentHeight() : box->borderRight() + box->paddingRight() + box->contentWidth();
137 }
138
baselinePosition(FontBaseline,bool,LineDirectionMode direction,LinePositionMode mode) const139 int RenderFlexibleBox::baselinePosition(FontBaseline, bool, LineDirectionMode direction, LinePositionMode mode) const
140 {
141 ASSERT(mode == PositionOnContainingLine);
142 int baseline = firstLineBoxBaseline();
143 if (baseline == -1)
144 baseline = synthesizedBaselineFromContentBox(this, direction);
145
146 return beforeMarginInLineDirection(direction) + baseline;
147 }
148
firstLineBoxBaseline() const149 int RenderFlexibleBox::firstLineBoxBaseline() const
150 {
151 if (isWritingModeRoot() || m_numberOfInFlowChildrenOnFirstLine <= 0)
152 return -1;
153 RenderBox* baselineChild = 0;
154 int childNumber = 0;
155 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
156 if (child->isOutOfFlowPositioned())
157 continue;
158 if (alignmentForChild(child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(child)) {
159 baselineChild = child;
160 break;
161 }
162 if (!baselineChild)
163 baselineChild = child;
164
165 ++childNumber;
166 if (childNumber == m_numberOfInFlowChildrenOnFirstLine)
167 break;
168 }
169
170 if (!baselineChild)
171 return -1;
172
173 if (!isColumnFlow() && hasOrthogonalFlow(baselineChild))
174 return crossAxisExtentForChild(baselineChild) + baselineChild->logicalTop();
175 if (isColumnFlow() && !hasOrthogonalFlow(baselineChild))
176 return mainAxisExtentForChild(baselineChild) + baselineChild->logicalTop();
177
178 int baseline = baselineChild->firstLineBoxBaseline();
179 if (baseline == -1) {
180 // FIXME: We should pass |direction| into firstLineBoxBaseline and stop bailing out if we're a writing mode root.
181 // This would also fix some cases where the flexbox is orthogonal to its container.
182 LineDirectionMode direction = isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
183 return synthesizedBaselineFromContentBox(baselineChild, direction) + baselineChild->logicalTop();
184 }
185
186 return baseline + baselineChild->logicalTop();
187 }
188
inlineBlockBaseline(LineDirectionMode direction) const189 int RenderFlexibleBox::inlineBlockBaseline(LineDirectionMode direction) const
190 {
191 int baseline = firstLineBoxBaseline();
192 if (baseline != -1)
193 return baseline;
194
195 int marginAscent = direction == HorizontalLine ? marginTop() : marginRight();
196 return synthesizedBaselineFromContentBox(this, direction) + marginAscent;
197 }
198
resolveAlignment(const RenderStyle * parentStyle,const RenderStyle * childStyle)199 static ItemPosition resolveAlignment(const RenderStyle* parentStyle, const RenderStyle* childStyle)
200 {
201 ItemPosition align = childStyle->alignSelf();
202 if (align == ItemPositionAuto)
203 align = parentStyle->alignItems();
204 return align;
205 }
206
removeChild(RenderObject * child)207 void RenderFlexibleBox::removeChild(RenderObject* child)
208 {
209 RenderBlock::removeChild(child);
210 m_intrinsicSizeAlongMainAxis.remove(child);
211 }
212
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)213 void RenderFlexibleBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
214 {
215 RenderBlock::styleDidChange(diff, oldStyle);
216
217 if (oldStyle && oldStyle->alignItems() == ItemPositionStretch && diff.needsFullLayout()) {
218 // Flex items that were previously stretching need to be relayed out so we can compute new available cross axis space.
219 // This is only necessary for stretching since other alignment values don't change the size of the box.
220 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
221 ItemPosition previousAlignment = resolveAlignment(oldStyle, child->style());
222 if (previousAlignment == ItemPositionStretch && previousAlignment != resolveAlignment(style(), child->style()))
223 child->setChildNeedsLayout(MarkOnlyThis);
224 }
225 }
226 }
227
layoutBlock(bool relayoutChildren)228 void RenderFlexibleBox::layoutBlock(bool relayoutChildren)
229 {
230 ASSERT(needsLayout());
231
232 if (!relayoutChildren && simplifiedLayout())
233 return;
234
235 LayoutRepainter repainter(*this, checkForPaintInvalidationDuringLayout());
236
237 if (updateLogicalWidthAndColumnWidth())
238 relayoutChildren = true;
239
240 LayoutUnit previousHeight = logicalHeight();
241 setLogicalHeight(borderAndPaddingLogicalHeight() + scrollbarLogicalHeight());
242
243 {
244 FastTextAutosizer::LayoutScope fastTextAutosizerLayoutScope(this);
245 LayoutState state(*this, locationOffset());
246
247 m_numberOfInFlowChildrenOnFirstLine = -1;
248
249 RenderBlock::startDelayUpdateScrollInfo();
250
251 prepareOrderIteratorAndMargins();
252
253 ChildFrameRects oldChildRects;
254 appendChildFrameRects(oldChildRects);
255
256 layoutFlexItems(relayoutChildren);
257
258 RenderBlock::finishDelayUpdateScrollInfo();
259
260 if (logicalHeight() != previousHeight)
261 relayoutChildren = true;
262
263 layoutPositionedObjects(relayoutChildren || isDocumentElement());
264
265 computeRegionRangeForBlock(flowThreadContainingBlock());
266
267 repaintChildrenDuringLayoutIfMoved(oldChildRects);
268 // FIXME: css3/flexbox/repaint-rtl-column.html seems to repaint more overflow than it needs to.
269 computeOverflow(clientLogicalBottomAfterRepositioning());
270 }
271
272 updateLayerTransformAfterLayout();
273
274 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
275 // we overflow or not.
276 updateScrollInfoAfterLayout();
277
278 repainter.repaintAfterLayout();
279
280 clearNeedsLayout();
281 }
282
appendChildFrameRects(ChildFrameRects & childFrameRects)283 void RenderFlexibleBox::appendChildFrameRects(ChildFrameRects& childFrameRects)
284 {
285 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
286 if (!child->isOutOfFlowPositioned())
287 childFrameRects.append(child->frameRect());
288 }
289 }
290
repaintChildrenDuringLayoutIfMoved(const ChildFrameRects & oldChildRects)291 void RenderFlexibleBox::repaintChildrenDuringLayoutIfMoved(const ChildFrameRects& oldChildRects)
292 {
293 size_t childIndex = 0;
294 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
295 if (child->isOutOfFlowPositioned())
296 continue;
297
298 // If the child moved, we have to repaint it as well as any floating/positioned
299 // descendants. An exception is if we need a layout. In this case, we know we're going to
300 // repaint ourselves (and the child) anyway.
301 if (!selfNeedsLayout() && child->checkForPaintInvalidationDuringLayout())
302 child->repaintDuringLayoutIfMoved(oldChildRects[childIndex]);
303 ++childIndex;
304 }
305 ASSERT(childIndex == oldChildRects.size());
306 }
307
paintChildren(PaintInfo & paintInfo,const LayoutPoint & paintOffset)308 void RenderFlexibleBox::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
309 {
310 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next())
311 paintChildAsInlineBlock(child, paintInfo, paintOffset);
312 }
313
repositionLogicalHeightDependentFlexItems(Vector<LineContext> & lineContexts)314 void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(Vector<LineContext>& lineContexts)
315 {
316 LayoutUnit crossAxisStartEdge = lineContexts.isEmpty() ? LayoutUnit() : lineContexts[0].crossAxisOffset;
317 alignFlexLines(lineContexts);
318
319 alignChildren(lineContexts);
320
321 if (style()->flexWrap() == FlexWrapReverse)
322 flipForWrapReverse(lineContexts, crossAxisStartEdge);
323
324 // direction:rtl + flex-direction:column means the cross-axis direction is flipped.
325 flipForRightToLeftColumn();
326 }
327
clientLogicalBottomAfterRepositioning()328 LayoutUnit RenderFlexibleBox::clientLogicalBottomAfterRepositioning()
329 {
330 LayoutUnit maxChildLogicalBottom = 0;
331 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
332 if (child->isOutOfFlowPositioned())
333 continue;
334 LayoutUnit childLogicalBottom = logicalTopForChild(child) + logicalHeightForChild(child) + marginAfterForChild(child);
335 maxChildLogicalBottom = std::max(maxChildLogicalBottom, childLogicalBottom);
336 }
337 return std::max(clientLogicalBottom(), maxChildLogicalBottom + paddingAfter());
338 }
339
hasOrthogonalFlow(RenderBox * child) const340 bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox* child) const
341 {
342 // FIXME: If the child is a flexbox, then we need to check isHorizontalFlow.
343 return isHorizontalFlow() != child->isHorizontalWritingMode();
344 }
345
isColumnFlow() const346 bool RenderFlexibleBox::isColumnFlow() const
347 {
348 return style()->isColumnFlexDirection();
349 }
350
isHorizontalFlow() const351 bool RenderFlexibleBox::isHorizontalFlow() const
352 {
353 if (isHorizontalWritingMode())
354 return !isColumnFlow();
355 return isColumnFlow();
356 }
357
isLeftToRightFlow() const358 bool RenderFlexibleBox::isLeftToRightFlow() const
359 {
360 if (isColumnFlow())
361 return style()->writingMode() == TopToBottomWritingMode || style()->writingMode() == LeftToRightWritingMode;
362 return style()->isLeftToRightDirection() ^ (style()->flexDirection() == FlowRowReverse);
363 }
364
isMultiline() const365 bool RenderFlexibleBox::isMultiline() const
366 {
367 return style()->flexWrap() != FlexNoWrap;
368 }
369
flexBasisForChild(RenderBox * child) const370 Length RenderFlexibleBox::flexBasisForChild(RenderBox* child) const
371 {
372 Length flexLength = child->style()->flexBasis();
373 if (flexLength.isAuto())
374 flexLength = isHorizontalFlow() ? child->style()->width() : child->style()->height();
375 return flexLength;
376 }
377
crossAxisExtentForChild(RenderBox * child) const378 LayoutUnit RenderFlexibleBox::crossAxisExtentForChild(RenderBox* child) const
379 {
380 return isHorizontalFlow() ? child->height() : child->width();
381 }
382
constrainedChildIntrinsicContentLogicalHeight(RenderBox * child)383 static inline LayoutUnit constrainedChildIntrinsicContentLogicalHeight(RenderBox* child)
384 {
385 LayoutUnit childIntrinsicContentLogicalHeight = child->intrinsicContentLogicalHeight();
386 return child->constrainLogicalHeightByMinMax(childIntrinsicContentLogicalHeight + child->borderAndPaddingLogicalHeight(), childIntrinsicContentLogicalHeight);
387 }
388
childIntrinsicHeight(RenderBox * child) const389 LayoutUnit RenderFlexibleBox::childIntrinsicHeight(RenderBox* child) const
390 {
391 if (child->isHorizontalWritingMode() && needToStretchChildLogicalHeight(child))
392 return constrainedChildIntrinsicContentLogicalHeight(child);
393 return child->height();
394 }
395
childIntrinsicWidth(RenderBox * child) const396 LayoutUnit RenderFlexibleBox::childIntrinsicWidth(RenderBox* child) const
397 {
398 if (!child->isHorizontalWritingMode() && needToStretchChildLogicalHeight(child))
399 return constrainedChildIntrinsicContentLogicalHeight(child);
400 return child->width();
401 }
402
crossAxisIntrinsicExtentForChild(RenderBox * child) const403 LayoutUnit RenderFlexibleBox::crossAxisIntrinsicExtentForChild(RenderBox* child) const
404 {
405 return isHorizontalFlow() ? childIntrinsicHeight(child) : childIntrinsicWidth(child);
406 }
407
mainAxisExtentForChild(RenderBox * child) const408 LayoutUnit RenderFlexibleBox::mainAxisExtentForChild(RenderBox* child) const
409 {
410 return isHorizontalFlow() ? child->width() : child->height();
411 }
412
crossAxisExtent() const413 LayoutUnit RenderFlexibleBox::crossAxisExtent() const
414 {
415 return isHorizontalFlow() ? height() : width();
416 }
417
mainAxisExtent() const418 LayoutUnit RenderFlexibleBox::mainAxisExtent() const
419 {
420 return isHorizontalFlow() ? width() : height();
421 }
422
crossAxisContentExtent() const423 LayoutUnit RenderFlexibleBox::crossAxisContentExtent() const
424 {
425 return isHorizontalFlow() ? contentHeight() : contentWidth();
426 }
427
mainAxisContentExtent(LayoutUnit contentLogicalHeight)428 LayoutUnit RenderFlexibleBox::mainAxisContentExtent(LayoutUnit contentLogicalHeight)
429 {
430 if (isColumnFlow()) {
431 LogicalExtentComputedValues computedValues;
432 LayoutUnit borderPaddingAndScrollbar = borderAndPaddingLogicalHeight() + scrollbarLogicalHeight();
433 // FIXME: Remove this std:max once we enable saturated layout arithmetic. It's just here to handle overflow.
434 LayoutUnit borderBoxLogicalHeight = std::max(contentLogicalHeight, contentLogicalHeight + borderPaddingAndScrollbar);
435 computeLogicalHeight(borderBoxLogicalHeight, logicalTop(), computedValues);
436 if (computedValues.m_extent == LayoutUnit::max())
437 return computedValues.m_extent;
438 return std::max(LayoutUnit(0), computedValues.m_extent - borderPaddingAndScrollbar);
439 }
440 return contentLogicalWidth();
441 }
442
computeMainAxisExtentForChild(RenderBox * child,SizeType sizeType,const Length & size)443 LayoutUnit RenderFlexibleBox::computeMainAxisExtentForChild(RenderBox* child, SizeType sizeType, const Length& size)
444 {
445 // FIXME: This is wrong for orthogonal flows. It should use the flexbox's writing-mode, not the child's in order
446 // to figure out the logical height/width.
447 if (isColumnFlow()) {
448 // We don't have to check for "auto" here - computeContentLogicalHeight will just return -1 for that case anyway.
449 if (size.isIntrinsic())
450 child->layoutIfNeeded();
451 return child->computeContentLogicalHeight(size, child->logicalHeight() - child->borderAndPaddingLogicalHeight());
452 }
453 return child->computeLogicalWidthUsing(sizeType, size, contentLogicalWidth(), this) - child->borderAndPaddingLogicalWidth();
454 }
455
transformedWritingMode() const456 WritingMode RenderFlexibleBox::transformedWritingMode() const
457 {
458 WritingMode mode = style()->writingMode();
459 if (!isColumnFlow())
460 return mode;
461
462 switch (mode) {
463 case TopToBottomWritingMode:
464 case BottomToTopWritingMode:
465 return style()->isLeftToRightDirection() ? LeftToRightWritingMode : RightToLeftWritingMode;
466 case LeftToRightWritingMode:
467 case RightToLeftWritingMode:
468 return style()->isLeftToRightDirection() ? TopToBottomWritingMode : BottomToTopWritingMode;
469 }
470 ASSERT_NOT_REACHED();
471 return TopToBottomWritingMode;
472 }
473
flowAwareBorderStart() const474 LayoutUnit RenderFlexibleBox::flowAwareBorderStart() const
475 {
476 if (isHorizontalFlow())
477 return isLeftToRightFlow() ? borderLeft() : borderRight();
478 return isLeftToRightFlow() ? borderTop() : borderBottom();
479 }
480
flowAwareBorderEnd() const481 LayoutUnit RenderFlexibleBox::flowAwareBorderEnd() const
482 {
483 if (isHorizontalFlow())
484 return isLeftToRightFlow() ? borderRight() : borderLeft();
485 return isLeftToRightFlow() ? borderBottom() : borderTop();
486 }
487
flowAwareBorderBefore() const488 LayoutUnit RenderFlexibleBox::flowAwareBorderBefore() const
489 {
490 switch (transformedWritingMode()) {
491 case TopToBottomWritingMode:
492 return borderTop();
493 case BottomToTopWritingMode:
494 return borderBottom();
495 case LeftToRightWritingMode:
496 return borderLeft();
497 case RightToLeftWritingMode:
498 return borderRight();
499 }
500 ASSERT_NOT_REACHED();
501 return borderTop();
502 }
503
flowAwareBorderAfter() const504 LayoutUnit RenderFlexibleBox::flowAwareBorderAfter() const
505 {
506 switch (transformedWritingMode()) {
507 case TopToBottomWritingMode:
508 return borderBottom();
509 case BottomToTopWritingMode:
510 return borderTop();
511 case LeftToRightWritingMode:
512 return borderRight();
513 case RightToLeftWritingMode:
514 return borderLeft();
515 }
516 ASSERT_NOT_REACHED();
517 return borderTop();
518 }
519
flowAwarePaddingStart() const520 LayoutUnit RenderFlexibleBox::flowAwarePaddingStart() const
521 {
522 if (isHorizontalFlow())
523 return isLeftToRightFlow() ? paddingLeft() : paddingRight();
524 return isLeftToRightFlow() ? paddingTop() : paddingBottom();
525 }
526
flowAwarePaddingEnd() const527 LayoutUnit RenderFlexibleBox::flowAwarePaddingEnd() const
528 {
529 if (isHorizontalFlow())
530 return isLeftToRightFlow() ? paddingRight() : paddingLeft();
531 return isLeftToRightFlow() ? paddingBottom() : paddingTop();
532 }
533
flowAwarePaddingBefore() const534 LayoutUnit RenderFlexibleBox::flowAwarePaddingBefore() const
535 {
536 switch (transformedWritingMode()) {
537 case TopToBottomWritingMode:
538 return paddingTop();
539 case BottomToTopWritingMode:
540 return paddingBottom();
541 case LeftToRightWritingMode:
542 return paddingLeft();
543 case RightToLeftWritingMode:
544 return paddingRight();
545 }
546 ASSERT_NOT_REACHED();
547 return paddingTop();
548 }
549
flowAwarePaddingAfter() const550 LayoutUnit RenderFlexibleBox::flowAwarePaddingAfter() const
551 {
552 switch (transformedWritingMode()) {
553 case TopToBottomWritingMode:
554 return paddingBottom();
555 case BottomToTopWritingMode:
556 return paddingTop();
557 case LeftToRightWritingMode:
558 return paddingRight();
559 case RightToLeftWritingMode:
560 return paddingLeft();
561 }
562 ASSERT_NOT_REACHED();
563 return paddingTop();
564 }
565
flowAwareMarginStartForChild(RenderBox * child) const566 LayoutUnit RenderFlexibleBox::flowAwareMarginStartForChild(RenderBox* child) const
567 {
568 if (isHorizontalFlow())
569 return isLeftToRightFlow() ? child->marginLeft() : child->marginRight();
570 return isLeftToRightFlow() ? child->marginTop() : child->marginBottom();
571 }
572
flowAwareMarginEndForChild(RenderBox * child) const573 LayoutUnit RenderFlexibleBox::flowAwareMarginEndForChild(RenderBox* child) const
574 {
575 if (isHorizontalFlow())
576 return isLeftToRightFlow() ? child->marginRight() : child->marginLeft();
577 return isLeftToRightFlow() ? child->marginBottom() : child->marginTop();
578 }
579
flowAwareMarginBeforeForChild(RenderBox * child) const580 LayoutUnit RenderFlexibleBox::flowAwareMarginBeforeForChild(RenderBox* child) const
581 {
582 switch (transformedWritingMode()) {
583 case TopToBottomWritingMode:
584 return child->marginTop();
585 case BottomToTopWritingMode:
586 return child->marginBottom();
587 case LeftToRightWritingMode:
588 return child->marginLeft();
589 case RightToLeftWritingMode:
590 return child->marginRight();
591 }
592 ASSERT_NOT_REACHED();
593 return marginTop();
594 }
595
crossAxisMarginExtentForChild(RenderBox * child) const596 LayoutUnit RenderFlexibleBox::crossAxisMarginExtentForChild(RenderBox* child) const
597 {
598 return isHorizontalFlow() ? child->marginHeight() : child->marginWidth();
599 }
600
crossAxisScrollbarExtent() const601 LayoutUnit RenderFlexibleBox::crossAxisScrollbarExtent() const
602 {
603 return isHorizontalFlow() ? horizontalScrollbarHeight() : verticalScrollbarWidth();
604 }
605
flowAwareLocationForChild(RenderBox * child) const606 LayoutPoint RenderFlexibleBox::flowAwareLocationForChild(RenderBox* child) const
607 {
608 return isHorizontalFlow() ? child->location() : child->location().transposedPoint();
609 }
610
setFlowAwareLocationForChild(RenderBox * child,const LayoutPoint & location)611 void RenderFlexibleBox::setFlowAwareLocationForChild(RenderBox* child, const LayoutPoint& location)
612 {
613 if (isHorizontalFlow())
614 child->setLocation(location);
615 else
616 child->setLocation(location.transposedPoint());
617 }
618
mainAxisBorderAndPaddingExtentForChild(RenderBox * child) const619 LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox* child) const
620 {
621 return isHorizontalFlow() ? child->borderAndPaddingWidth() : child->borderAndPaddingHeight();
622 }
623
preferredMainAxisExtentDependsOnLayout(const Length & flexBasis,bool hasInfiniteLineLength)624 static inline bool preferredMainAxisExtentDependsOnLayout(const Length& flexBasis, bool hasInfiniteLineLength)
625 {
626 return flexBasis.isAuto() || (flexBasis.isFixed() && !flexBasis.value() && hasInfiniteLineLength);
627 }
628
childPreferredMainAxisContentExtentRequiresLayout(RenderBox * child,bool hasInfiniteLineLength) const629 bool RenderFlexibleBox::childPreferredMainAxisContentExtentRequiresLayout(RenderBox* child, bool hasInfiniteLineLength) const
630 {
631 return preferredMainAxisExtentDependsOnLayout(flexBasisForChild(child), hasInfiniteLineLength) && hasOrthogonalFlow(child);
632 }
633
preferredMainAxisContentExtentForChild(RenderBox * child,bool hasInfiniteLineLength,bool relayoutChildren)634 LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child, bool hasInfiniteLineLength, bool relayoutChildren)
635 {
636 child->clearOverrideSize();
637
638 Length flexBasis = flexBasisForChild(child);
639 if (preferredMainAxisExtentDependsOnLayout(flexBasis, hasInfiniteLineLength)) {
640 LayoutUnit mainAxisExtent;
641 if (hasOrthogonalFlow(child)) {
642 if (child->needsLayout() || relayoutChildren) {
643 m_intrinsicSizeAlongMainAxis.remove(child);
644 child->forceChildLayout();
645 m_intrinsicSizeAlongMainAxis.set(child, child->logicalHeight());
646 }
647 ASSERT(m_intrinsicSizeAlongMainAxis.contains(child));
648 mainAxisExtent = m_intrinsicSizeAlongMainAxis.get(child);
649 } else {
650 mainAxisExtent = child->maxPreferredLogicalWidth();
651 }
652 ASSERT(mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child) >= 0);
653 return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child);
654 }
655 return std::max(LayoutUnit(0), computeMainAxisExtentForChild(child, MainOrPreferredSize, flexBasis));
656 }
657
layoutFlexItems(bool relayoutChildren)658 void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren)
659 {
660 Vector<LineContext> lineContexts;
661 OrderedFlexItemList orderedChildren;
662 LayoutUnit sumFlexBaseSize;
663 double totalFlexGrow;
664 double totalWeightedFlexShrink;
665 LayoutUnit sumHypotheticalMainSize;
666
667 Vector<LayoutUnit, 16> childSizes;
668
669 m_orderIterator.first();
670 LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
671 bool hasInfiniteLineLength = false;
672 while (computeNextFlexLine(orderedChildren, sumFlexBaseSize, totalFlexGrow, totalWeightedFlexShrink, sumHypotheticalMainSize, hasInfiniteLineLength, relayoutChildren)) {
673 LayoutUnit containerMainInnerSize = mainAxisContentExtent(sumHypotheticalMainSize);
674 LayoutUnit availableFreeSpace = containerMainInnerSize - sumFlexBaseSize;
675 FlexSign flexSign = (sumHypotheticalMainSize < containerMainInnerSize) ? PositiveFlexibility : NegativeFlexibility;
676 InflexibleFlexItemSize inflexibleItems;
677 childSizes.reserveCapacity(orderedChildren.size());
678 while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, childSizes, hasInfiniteLineLength)) {
679 ASSERT(totalFlexGrow >= 0 && totalWeightedFlexShrink >= 0);
680 ASSERT(inflexibleItems.size() > 0);
681 }
682
683 layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, relayoutChildren, lineContexts, hasInfiniteLineLength);
684 }
685 if (hasLineIfEmpty()) {
686 // Even if computeNextFlexLine returns true, the flexbox might not have
687 // a line because all our children might be out of flow positioned.
688 // Instead of just checking if we have a line, make sure the flexbox
689 // has at least a line's worth of height to cover this case.
690 LayoutUnit minHeight = borderAndPaddingLogicalHeight()
691 + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes)
692 + scrollbarLogicalHeight();
693 if (height() < minHeight)
694 setLogicalHeight(minHeight);
695 }
696
697 updateLogicalHeight();
698 repositionLogicalHeightDependentFlexItems(lineContexts);
699 }
700
autoMarginOffsetInMainAxis(const OrderedFlexItemList & children,LayoutUnit & availableFreeSpace)701 LayoutUnit RenderFlexibleBox::autoMarginOffsetInMainAxis(const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace)
702 {
703 if (availableFreeSpace <= 0)
704 return 0;
705
706 int numberOfAutoMargins = 0;
707 bool isHorizontal = isHorizontalFlow();
708 for (size_t i = 0; i < children.size(); ++i) {
709 RenderBox* child = children[i];
710 if (child->isOutOfFlowPositioned())
711 continue;
712 if (isHorizontal) {
713 if (child->style()->marginLeft().isAuto())
714 ++numberOfAutoMargins;
715 if (child->style()->marginRight().isAuto())
716 ++numberOfAutoMargins;
717 } else {
718 if (child->style()->marginTop().isAuto())
719 ++numberOfAutoMargins;
720 if (child->style()->marginBottom().isAuto())
721 ++numberOfAutoMargins;
722 }
723 }
724 if (!numberOfAutoMargins)
725 return 0;
726
727 LayoutUnit sizeOfAutoMargin = availableFreeSpace / numberOfAutoMargins;
728 availableFreeSpace = 0;
729 return sizeOfAutoMargin;
730 }
731
updateAutoMarginsInMainAxis(RenderBox * child,LayoutUnit autoMarginOffset)732 void RenderFlexibleBox::updateAutoMarginsInMainAxis(RenderBox* child, LayoutUnit autoMarginOffset)
733 {
734 ASSERT(autoMarginOffset >= 0);
735
736 if (isHorizontalFlow()) {
737 if (child->style()->marginLeft().isAuto())
738 child->setMarginLeft(autoMarginOffset);
739 if (child->style()->marginRight().isAuto())
740 child->setMarginRight(autoMarginOffset);
741 } else {
742 if (child->style()->marginTop().isAuto())
743 child->setMarginTop(autoMarginOffset);
744 if (child->style()->marginBottom().isAuto())
745 child->setMarginBottom(autoMarginOffset);
746 }
747 }
748
hasAutoMarginsInCrossAxis(RenderBox * child) const749 bool RenderFlexibleBox::hasAutoMarginsInCrossAxis(RenderBox* child) const
750 {
751 if (isHorizontalFlow())
752 return child->style()->marginTop().isAuto() || child->style()->marginBottom().isAuto();
753 return child->style()->marginLeft().isAuto() || child->style()->marginRight().isAuto();
754 }
755
availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent,RenderBox * child)756 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox* child)
757 {
758 ASSERT(!child->isOutOfFlowPositioned());
759 LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child);
760 return lineCrossAxisExtent - childCrossExtent;
761 }
762
availableAlignmentSpaceForChildBeforeStretching(LayoutUnit lineCrossAxisExtent,RenderBox * child)763 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChildBeforeStretching(LayoutUnit lineCrossAxisExtent, RenderBox* child)
764 {
765 ASSERT(!child->isOutOfFlowPositioned());
766 LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisIntrinsicExtentForChild(child);
767 return lineCrossAxisExtent - childCrossExtent;
768 }
769
updateAutoMarginsInCrossAxis(RenderBox * child,LayoutUnit availableAlignmentSpace)770 bool RenderFlexibleBox::updateAutoMarginsInCrossAxis(RenderBox* child, LayoutUnit availableAlignmentSpace)
771 {
772 ASSERT(!child->isOutOfFlowPositioned());
773 ASSERT(availableAlignmentSpace >= 0);
774
775 bool isHorizontal = isHorizontalFlow();
776 Length topOrLeft = isHorizontal ? child->style()->marginTop() : child->style()->marginLeft();
777 Length bottomOrRight = isHorizontal ? child->style()->marginBottom() : child->style()->marginRight();
778 if (topOrLeft.isAuto() && bottomOrRight.isAuto()) {
779 adjustAlignmentForChild(child, availableAlignmentSpace / 2);
780 if (isHorizontal) {
781 child->setMarginTop(availableAlignmentSpace / 2);
782 child->setMarginBottom(availableAlignmentSpace / 2);
783 } else {
784 child->setMarginLeft(availableAlignmentSpace / 2);
785 child->setMarginRight(availableAlignmentSpace / 2);
786 }
787 return true;
788 }
789 bool shouldAdjustTopOrLeft = true;
790 if (isColumnFlow() && !child->style()->isLeftToRightDirection()) {
791 // For column flows, only make this adjustment if topOrLeft corresponds to the "before" margin,
792 // so that flipForRightToLeftColumn will do the right thing.
793 shouldAdjustTopOrLeft = false;
794 }
795 if (!isColumnFlow() && child->style()->isFlippedBlocksWritingMode()) {
796 // If we are a flipped writing mode, we need to adjust the opposite side. This is only needed
797 // for row flows because this only affects the block-direction axis.
798 shouldAdjustTopOrLeft = false;
799 }
800
801 if (topOrLeft.isAuto()) {
802 if (shouldAdjustTopOrLeft)
803 adjustAlignmentForChild(child, availableAlignmentSpace);
804
805 if (isHorizontal)
806 child->setMarginTop(availableAlignmentSpace);
807 else
808 child->setMarginLeft(availableAlignmentSpace);
809 return true;
810 }
811 if (bottomOrRight.isAuto()) {
812 if (!shouldAdjustTopOrLeft)
813 adjustAlignmentForChild(child, availableAlignmentSpace);
814
815 if (isHorizontal)
816 child->setMarginBottom(availableAlignmentSpace);
817 else
818 child->setMarginRight(availableAlignmentSpace);
819 return true;
820 }
821 return false;
822 }
823
marginBoxAscentForChild(RenderBox * child)824 LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox* child)
825 {
826 LayoutUnit ascent = child->firstLineBoxBaseline();
827 if (ascent == -1)
828 ascent = crossAxisExtentForChild(child);
829 return ascent + flowAwareMarginBeforeForChild(child);
830 }
831
computeChildMarginValue(Length margin)832 LayoutUnit RenderFlexibleBox::computeChildMarginValue(Length margin)
833 {
834 // When resolving the margins, we use the content size for resolving percent and calc (for percents in calc expressions) margins.
835 // Fortunately, percent margins are always computed with respect to the block's width, even for margin-top and margin-bottom.
836 LayoutUnit availableSize = contentLogicalWidth();
837 return minimumValueForLength(margin, availableSize);
838 }
839
prepareOrderIteratorAndMargins()840 void RenderFlexibleBox::prepareOrderIteratorAndMargins()
841 {
842 OrderIteratorPopulator populator(m_orderIterator);
843
844 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
845 populator.collectChild(child);
846
847 if (child->isOutOfFlowPositioned())
848 continue;
849
850 // Before running the flex algorithm, 'auto' has a margin of 0.
851 // Also, if we're not auto sizing, we don't do a layout that computes the start/end margins.
852 if (isHorizontalFlow()) {
853 child->setMarginLeft(computeChildMarginValue(child->style()->marginLeft()));
854 child->setMarginRight(computeChildMarginValue(child->style()->marginRight()));
855 } else {
856 child->setMarginTop(computeChildMarginValue(child->style()->marginTop()));
857 child->setMarginBottom(computeChildMarginValue(child->style()->marginBottom()));
858 }
859 }
860 }
861
adjustChildSizeForMinAndMax(RenderBox * child,LayoutUnit childSize)862 LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox* child, LayoutUnit childSize)
863 {
864 Length max = isHorizontalFlow() ? child->style()->maxWidth() : child->style()->maxHeight();
865 if (max.isSpecifiedOrIntrinsic()) {
866 LayoutUnit maxExtent = computeMainAxisExtentForChild(child, MaxSize, max);
867 if (maxExtent != -1 && childSize > maxExtent)
868 childSize = maxExtent;
869 }
870
871 Length min = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
872 LayoutUnit minExtent = 0;
873 if (min.isSpecifiedOrIntrinsic())
874 minExtent = computeMainAxisExtentForChild(child, MinSize, min);
875 return std::max(childSize, minExtent);
876 }
877
computeNextFlexLine(OrderedFlexItemList & orderedChildren,LayoutUnit & sumFlexBaseSize,double & totalFlexGrow,double & totalWeightedFlexShrink,LayoutUnit & sumHypotheticalMainSize,bool & hasInfiniteLineLength,bool relayoutChildren)878 bool RenderFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& sumFlexBaseSize, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& sumHypotheticalMainSize, bool& hasInfiniteLineLength, bool relayoutChildren)
879 {
880 orderedChildren.clear();
881 sumFlexBaseSize = 0;
882 totalFlexGrow = totalWeightedFlexShrink = 0;
883 sumHypotheticalMainSize = 0;
884
885 if (!m_orderIterator.currentChild())
886 return false;
887
888 LayoutUnit lineBreakLength = mainAxisContentExtent(LayoutUnit::max());
889 hasInfiniteLineLength = lineBreakLength == LayoutUnit::max();
890
891 bool lineHasInFlowItem = false;
892
893 for (RenderBox* child = m_orderIterator.currentChild(); child; child = m_orderIterator.next()) {
894 if (child->isOutOfFlowPositioned()) {
895 orderedChildren.append(child);
896 continue;
897 }
898
899 LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength, relayoutChildren);
900 LayoutUnit childMainAxisMarginBorderPadding = mainAxisBorderAndPaddingExtentForChild(child)
901 + (isHorizontalFlow() ? child->marginWidth() : child->marginHeight());
902 LayoutUnit childFlexBaseSize = childMainAxisExtent + childMainAxisMarginBorderPadding;
903
904 LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(child, childMainAxisExtent);
905 LayoutUnit childHypotheticalMainSize = childMinMaxAppliedMainAxisExtent + childMainAxisMarginBorderPadding;
906
907 if (isMultiline() && sumHypotheticalMainSize + childHypotheticalMainSize > lineBreakLength && lineHasInFlowItem)
908 break;
909 orderedChildren.append(child);
910 lineHasInFlowItem = true;
911 sumFlexBaseSize += childFlexBaseSize;
912 totalFlexGrow += child->style()->flexGrow();
913 totalWeightedFlexShrink += child->style()->flexShrink() * childMainAxisExtent;
914 sumHypotheticalMainSize += childHypotheticalMainSize;
915 }
916 return true;
917 }
918
freezeViolations(const Vector<Violation> & violations,LayoutUnit & availableFreeSpace,double & totalFlexGrow,double & totalWeightedFlexShrink,InflexibleFlexItemSize & inflexibleItems,bool hasInfiniteLineLength)919 void RenderFlexibleBox::freezeViolations(const Vector<Violation>& violations, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, bool hasInfiniteLineLength)
920 {
921 for (size_t i = 0; i < violations.size(); ++i) {
922 RenderBox* child = violations[i].child;
923 LayoutUnit childSize = violations[i].childSize;
924 LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
925 availableFreeSpace -= childSize - preferredChildSize;
926 totalFlexGrow -= child->style()->flexGrow();
927 totalWeightedFlexShrink -= child->style()->flexShrink() * preferredChildSize;
928 inflexibleItems.set(child, childSize);
929 }
930 }
931
932 // Returns true if we successfully ran the algorithm and sized the flex items.
resolveFlexibleLengths(FlexSign flexSign,const OrderedFlexItemList & children,LayoutUnit & availableFreeSpace,double & totalFlexGrow,double & totalWeightedFlexShrink,InflexibleFlexItemSize & inflexibleItems,Vector<LayoutUnit,16> & childSizes,bool hasInfiniteLineLength)933 bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, Vector<LayoutUnit, 16>& childSizes, bool hasInfiniteLineLength)
934 {
935 childSizes.resize(0);
936 LayoutUnit totalViolation = 0;
937 LayoutUnit usedFreeSpace = 0;
938 Vector<Violation> minViolations;
939 Vector<Violation> maxViolations;
940 for (size_t i = 0; i < children.size(); ++i) {
941 RenderBox* child = children[i];
942 if (child->isOutOfFlowPositioned()) {
943 childSizes.append(0);
944 continue;
945 }
946
947 if (inflexibleItems.contains(child))
948 childSizes.append(inflexibleItems.get(child));
949 else {
950 LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
951 LayoutUnit childSize = preferredChildSize;
952 double extraSpace = 0;
953 if (availableFreeSpace > 0 && totalFlexGrow > 0 && flexSign == PositiveFlexibility && std::isfinite(totalFlexGrow))
954 extraSpace = availableFreeSpace * child->style()->flexGrow() / totalFlexGrow;
955 else if (availableFreeSpace < 0 && totalWeightedFlexShrink > 0 && flexSign == NegativeFlexibility && std::isfinite(totalWeightedFlexShrink))
956 extraSpace = availableFreeSpace * child->style()->flexShrink() * preferredChildSize / totalWeightedFlexShrink;
957 if (std::isfinite(extraSpace))
958 childSize += LayoutUnit::fromFloatRound(extraSpace);
959
960 LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(child, childSize);
961 childSizes.append(adjustedChildSize);
962 usedFreeSpace += adjustedChildSize - preferredChildSize;
963
964 LayoutUnit violation = adjustedChildSize - childSize;
965 if (violation > 0)
966 minViolations.append(Violation(child, adjustedChildSize));
967 else if (violation < 0)
968 maxViolations.append(Violation(child, adjustedChildSize));
969 totalViolation += violation;
970 }
971 }
972
973 if (totalViolation)
974 freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, hasInfiniteLineLength);
975 else
976 availableFreeSpace -= usedFreeSpace;
977
978 return !totalViolation;
979 }
980
initialJustifyContentOffset(LayoutUnit availableFreeSpace,EJustifyContent justifyContent,unsigned numberOfChildren)981 static LayoutUnit initialJustifyContentOffset(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
982 {
983 if (justifyContent == JustifyFlexEnd)
984 return availableFreeSpace;
985 if (justifyContent == JustifyCenter)
986 return availableFreeSpace / 2;
987 if (justifyContent == JustifySpaceAround) {
988 if (availableFreeSpace > 0 && numberOfChildren)
989 return availableFreeSpace / (2 * numberOfChildren);
990 else
991 return availableFreeSpace / 2;
992 }
993 return 0;
994 }
995
justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace,EJustifyContent justifyContent,unsigned numberOfChildren)996 static LayoutUnit justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
997 {
998 if (availableFreeSpace > 0 && numberOfChildren > 1) {
999 if (justifyContent == JustifySpaceBetween)
1000 return availableFreeSpace / (numberOfChildren - 1);
1001 if (justifyContent == JustifySpaceAround)
1002 return availableFreeSpace / numberOfChildren;
1003 }
1004 return 0;
1005 }
1006
setLogicalOverrideSize(RenderBox * child,LayoutUnit childPreferredSize)1007 void RenderFlexibleBox::setLogicalOverrideSize(RenderBox* child, LayoutUnit childPreferredSize)
1008 {
1009 if (hasOrthogonalFlow(child))
1010 child->setOverrideLogicalContentHeight(childPreferredSize - child->borderAndPaddingLogicalHeight());
1011 else
1012 child->setOverrideLogicalContentWidth(childPreferredSize - child->borderAndPaddingLogicalWidth());
1013 }
1014
prepareChildForPositionedLayout(RenderBox * child,LayoutUnit mainAxisOffset,LayoutUnit crossAxisOffset,PositionedLayoutMode layoutMode)1015 void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox* child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset, PositionedLayoutMode layoutMode)
1016 {
1017 ASSERT(child->isOutOfFlowPositioned());
1018 child->containingBlock()->insertPositionedObject(child);
1019 RenderLayer* childLayer = child->layer();
1020 LayoutUnit inlinePosition = isColumnFlow() ? crossAxisOffset : mainAxisOffset;
1021 if (layoutMode == FlipForRowReverse && style()->flexDirection() == FlowRowReverse)
1022 inlinePosition = mainAxisExtent() - mainAxisOffset;
1023 childLayer->setStaticInlinePosition(inlinePosition);
1024
1025 LayoutUnit staticBlockPosition = isColumnFlow() ? mainAxisOffset : crossAxisOffset;
1026 if (childLayer->staticBlockPosition() != staticBlockPosition) {
1027 childLayer->setStaticBlockPosition(staticBlockPosition);
1028 if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
1029 child->setChildNeedsLayout(MarkOnlyThis);
1030 }
1031 }
1032
alignmentForChild(RenderBox * child) const1033 ItemPosition RenderFlexibleBox::alignmentForChild(RenderBox* child) const
1034 {
1035 ItemPosition align = resolveAlignment(style(), child->style());
1036
1037 if (align == ItemPositionBaseline && hasOrthogonalFlow(child))
1038 align = ItemPositionFlexStart;
1039
1040 if (style()->flexWrap() == FlexWrapReverse) {
1041 if (align == ItemPositionFlexStart)
1042 align = ItemPositionFlexEnd;
1043 else if (align == ItemPositionFlexEnd)
1044 align = ItemPositionFlexStart;
1045 }
1046
1047 return align;
1048 }
1049
numberOfInFlowPositionedChildren(const OrderedFlexItemList & children) const1050 size_t RenderFlexibleBox::numberOfInFlowPositionedChildren(const OrderedFlexItemList& children) const
1051 {
1052 size_t count = 0;
1053 for (size_t i = 0; i < children.size(); ++i) {
1054 RenderBox* child = children[i];
1055 if (!child->isOutOfFlowPositioned())
1056 ++count;
1057 }
1058 return count;
1059 }
1060
resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox * child)1061 void RenderFlexibleBox::resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox* child)
1062 {
1063 if (hasAutoMarginsInCrossAxis(child)) {
1064 child->updateLogicalHeight();
1065 if (isHorizontalFlow()) {
1066 if (child->style()->marginTop().isAuto())
1067 child->setMarginTop(0);
1068 if (child->style()->marginBottom().isAuto())
1069 child->setMarginBottom(0);
1070 } else {
1071 if (child->style()->marginLeft().isAuto())
1072 child->setMarginLeft(0);
1073 if (child->style()->marginRight().isAuto())
1074 child->setMarginRight(0);
1075 }
1076 }
1077 }
1078
needToStretchChildLogicalHeight(RenderBox * child) const1079 bool RenderFlexibleBox::needToStretchChildLogicalHeight(RenderBox* child) const
1080 {
1081 if (alignmentForChild(child) != ItemPositionStretch)
1082 return false;
1083
1084 return isHorizontalFlow() && child->style()->height().isAuto();
1085 }
1086
layoutAndPlaceChildren(LayoutUnit & crossAxisOffset,const OrderedFlexItemList & children,const Vector<LayoutUnit,16> & childSizes,LayoutUnit availableFreeSpace,bool relayoutChildren,Vector<LineContext> & lineContexts,bool hasInfiniteLineLength)1087 void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const Vector<LayoutUnit, 16>& childSizes, LayoutUnit availableFreeSpace, bool relayoutChildren, Vector<LineContext>& lineContexts, bool hasInfiniteLineLength)
1088 {
1089 ASSERT(childSizes.size() == children.size());
1090
1091 size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children);
1092 LayoutUnit autoMarginOffset = autoMarginOffsetInMainAxis(children, availableFreeSpace);
1093 LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart();
1094 mainAxisOffset += initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1095 if (style()->flexDirection() == FlowRowReverse)
1096 mainAxisOffset += isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1097
1098 LayoutUnit totalMainExtent = mainAxisExtent();
1099 LayoutUnit maxAscent = 0, maxDescent = 0; // Used when align-items: baseline.
1100 LayoutUnit maxChildCrossAxisExtent = 0;
1101 size_t seenInFlowPositionedChildren = 0;
1102 bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow();
1103 for (size_t i = 0; i < children.size(); ++i) {
1104 RenderBox* child = children[i];
1105
1106 if (child->isOutOfFlowPositioned()) {
1107 prepareChildForPositionedLayout(child, mainAxisOffset, crossAxisOffset, FlipForRowReverse);
1108 continue;
1109 }
1110
1111 // FIXME Investigate if this can be removed based on other flags. crbug.com/370010
1112 child->setMayNeedPaintInvalidation(true);
1113
1114 LayoutUnit childPreferredSize = childSizes[i] + mainAxisBorderAndPaddingExtentForChild(child);
1115 setLogicalOverrideSize(child, childPreferredSize);
1116 if (childPreferredSize != mainAxisExtentForChild(child)) {
1117 child->setChildNeedsLayout(MarkOnlyThis);
1118 } else {
1119 // To avoid double applying margin changes in updateAutoMarginsInCrossAxis, we reset the margins here.
1120 resetAutoMarginsAndLogicalTopInCrossAxis(child);
1121 }
1122 // We may have already forced relayout for orthogonal flowing children in preferredMainAxisContentExtentForChild.
1123 bool forceChildRelayout = relayoutChildren && !childPreferredMainAxisContentExtentRequiresLayout(child, hasInfiniteLineLength);
1124 updateBlockChildDirtyBitsBeforeLayout(forceChildRelayout, child);
1125 child->layoutIfNeeded();
1126
1127 updateAutoMarginsInMainAxis(child, autoMarginOffset);
1128
1129 LayoutUnit childCrossAxisMarginBoxExtent;
1130 if (alignmentForChild(child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(child)) {
1131 LayoutUnit ascent = marginBoxAscentForChild(child);
1132 LayoutUnit descent = (crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child)) - ascent;
1133
1134 maxAscent = std::max(maxAscent, ascent);
1135 maxDescent = std::max(maxDescent, descent);
1136
1137 childCrossAxisMarginBoxExtent = maxAscent + maxDescent;
1138 } else {
1139 childCrossAxisMarginBoxExtent = crossAxisIntrinsicExtentForChild(child) + crossAxisMarginExtentForChild(child);
1140 }
1141 if (!isColumnFlow())
1142 setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent()));
1143 maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent);
1144
1145 mainAxisOffset += flowAwareMarginStartForChild(child);
1146
1147 LayoutUnit childMainExtent = mainAxisExtentForChild(child);
1148 // In an RTL column situation, this will apply the margin-right/margin-end on the left.
1149 // This will be fixed later in flipForRightToLeftColumn.
1150 LayoutPoint childLocation(shouldFlipMainAxis ? totalMainExtent - mainAxisOffset - childMainExtent : mainAxisOffset,
1151 crossAxisOffset + flowAwareMarginBeforeForChild(child));
1152
1153 // FIXME: Supporting layout deltas.
1154 setFlowAwareLocationForChild(child, childLocation);
1155 mainAxisOffset += childMainExtent + flowAwareMarginEndForChild(child);
1156
1157 ++seenInFlowPositionedChildren;
1158 if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent)
1159 mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1160 }
1161
1162 if (isColumnFlow())
1163 setLogicalHeight(mainAxisOffset + flowAwareBorderEnd() + flowAwarePaddingEnd() + scrollbarLogicalHeight());
1164
1165 if (style()->flexDirection() == FlowColumnReverse) {
1166 // We have to do an extra pass for column-reverse to reposition the flex items since the start depends
1167 // on the height of the flexbox, which we only know after we've positioned all the flex items.
1168 updateLogicalHeight();
1169 layoutColumnReverse(children, crossAxisOffset, availableFreeSpace);
1170 }
1171
1172 if (m_numberOfInFlowChildrenOnFirstLine == -1)
1173 m_numberOfInFlowChildrenOnFirstLine = seenInFlowPositionedChildren;
1174 lineContexts.append(LineContext(crossAxisOffset, maxChildCrossAxisExtent, children.size(), maxAscent));
1175 crossAxisOffset += maxChildCrossAxisExtent;
1176 }
1177
layoutColumnReverse(const OrderedFlexItemList & children,LayoutUnit crossAxisOffset,LayoutUnit availableFreeSpace)1178 void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace)
1179 {
1180 // This is similar to the logic in layoutAndPlaceChildren, except we place the children
1181 // starting from the end of the flexbox. We also don't need to layout anything since we're
1182 // just moving the children to a new position.
1183 size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children);
1184 LayoutUnit mainAxisOffset = logicalHeight() - flowAwareBorderEnd() - flowAwarePaddingEnd();
1185 mainAxisOffset -= initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1186 mainAxisOffset -= isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1187
1188 size_t seenInFlowPositionedChildren = 0;
1189 for (size_t i = 0; i < children.size(); ++i) {
1190 RenderBox* child = children[i];
1191
1192 if (child->isOutOfFlowPositioned()) {
1193 child->layer()->setStaticBlockPosition(mainAxisOffset);
1194 continue;
1195 }
1196 mainAxisOffset -= mainAxisExtentForChild(child) + flowAwareMarginEndForChild(child);
1197
1198 setFlowAwareLocationForChild(child, LayoutPoint(mainAxisOffset, crossAxisOffset + flowAwareMarginBeforeForChild(child)));
1199
1200 mainAxisOffset -= flowAwareMarginStartForChild(child);
1201
1202 ++seenInFlowPositionedChildren;
1203 if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent)
1204 mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1205 }
1206 }
1207
initialAlignContentOffset(LayoutUnit availableFreeSpace,EAlignContent alignContent,unsigned numberOfLines)1208 static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1209 {
1210 if (numberOfLines <= 1)
1211 return 0;
1212 if (alignContent == AlignContentFlexEnd)
1213 return availableFreeSpace;
1214 if (alignContent == AlignContentCenter)
1215 return availableFreeSpace / 2;
1216 if (alignContent == AlignContentSpaceAround) {
1217 if (availableFreeSpace > 0 && numberOfLines)
1218 return availableFreeSpace / (2 * numberOfLines);
1219 if (availableFreeSpace < 0)
1220 return availableFreeSpace / 2;
1221 }
1222 return 0;
1223 }
1224
alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace,EAlignContent alignContent,unsigned numberOfLines)1225 static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1226 {
1227 if (availableFreeSpace > 0 && numberOfLines > 1) {
1228 if (alignContent == AlignContentSpaceBetween)
1229 return availableFreeSpace / (numberOfLines - 1);
1230 if (alignContent == AlignContentSpaceAround || alignContent == AlignContentStretch)
1231 return availableFreeSpace / numberOfLines;
1232 }
1233 return 0;
1234 }
1235
alignFlexLines(Vector<LineContext> & lineContexts)1236 void RenderFlexibleBox::alignFlexLines(Vector<LineContext>& lineContexts)
1237 {
1238 // If we have a single line flexbox or a multiline line flexbox with only one flex line,
1239 // the line height is all the available space.
1240 // For flex-direction: row, this means we need to use the height, so we do this after calling updateLogicalHeight.
1241 if (lineContexts.size() == 1) {
1242 lineContexts[0].crossAxisExtent = crossAxisContentExtent();
1243 return;
1244 }
1245
1246 if (style()->alignContent() == AlignContentFlexStart)
1247 return;
1248
1249 LayoutUnit availableCrossAxisSpace = crossAxisContentExtent();
1250 for (size_t i = 0; i < lineContexts.size(); ++i)
1251 availableCrossAxisSpace -= lineContexts[i].crossAxisExtent;
1252
1253 RenderBox* child = m_orderIterator.first();
1254 LayoutUnit lineOffset = initialAlignContentOffset(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1255 for (unsigned lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1256 lineContexts[lineNumber].crossAxisOffset += lineOffset;
1257 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next())
1258 adjustAlignmentForChild(child, lineOffset);
1259
1260 if (style()->alignContent() == AlignContentStretch && availableCrossAxisSpace > 0)
1261 lineContexts[lineNumber].crossAxisExtent += availableCrossAxisSpace / static_cast<unsigned>(lineContexts.size());
1262
1263 lineOffset += alignContentSpaceBetweenChildren(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1264 }
1265 }
1266
adjustAlignmentForChild(RenderBox * child,LayoutUnit delta)1267 void RenderFlexibleBox::adjustAlignmentForChild(RenderBox* child, LayoutUnit delta)
1268 {
1269 if (child->isOutOfFlowPositioned()) {
1270 LayoutUnit staticInlinePosition = child->layer()->staticInlinePosition();
1271 LayoutUnit staticBlockPosition = child->layer()->staticBlockPosition();
1272 LayoutUnit mainAxis = isColumnFlow() ? staticBlockPosition : staticInlinePosition;
1273 LayoutUnit crossAxis = isColumnFlow() ? staticInlinePosition : staticBlockPosition;
1274 crossAxis += delta;
1275 prepareChildForPositionedLayout(child, mainAxis, crossAxis, NoFlipForRowReverse);
1276 return;
1277 }
1278
1279 setFlowAwareLocationForChild(child, flowAwareLocationForChild(child) + LayoutSize(0, delta));
1280 }
1281
alignChildren(const Vector<LineContext> & lineContexts)1282 void RenderFlexibleBox::alignChildren(const Vector<LineContext>& lineContexts)
1283 {
1284 // Keep track of the space between the baseline edge and the after edge of the box for each line.
1285 Vector<LayoutUnit> minMarginAfterBaselines;
1286
1287 RenderBox* child = m_orderIterator.first();
1288 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1289 LayoutUnit minMarginAfterBaseline = LayoutUnit::max();
1290 LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1291 LayoutUnit maxAscent = lineContexts[lineNumber].maxAscent;
1292
1293 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1294 ASSERT(child);
1295 if (child->isOutOfFlowPositioned()) {
1296 if (style()->flexWrap() == FlexWrapReverse)
1297 adjustAlignmentForChild(child, lineCrossAxisExtent);
1298 continue;
1299 }
1300
1301 if (updateAutoMarginsInCrossAxis(child, std::max(LayoutUnit(0), availableAlignmentSpaceForChild(lineCrossAxisExtent, child))))
1302 continue;
1303
1304 switch (alignmentForChild(child)) {
1305 case ItemPositionAuto:
1306 ASSERT_NOT_REACHED();
1307 break;
1308 case ItemPositionStretch: {
1309 applyStretchAlignmentToChild(child, lineCrossAxisExtent);
1310 // Since wrap-reverse flips cross start and cross end, strech children should be aligned with the cross end.
1311 if (style()->flexWrap() == FlexWrapReverse)
1312 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
1313 break;
1314 }
1315 case ItemPositionFlexStart:
1316 break;
1317 case ItemPositionFlexEnd:
1318 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
1319 break;
1320 case ItemPositionCenter:
1321 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) / 2);
1322 break;
1323 case ItemPositionBaseline: {
1324 // FIXME: If we get here in columns, we want the use the descent, except we currently can't get the ascent/descent of orthogonal children.
1325 // https://bugs.webkit.org/show_bug.cgi?id=98076
1326 LayoutUnit ascent = marginBoxAscentForChild(child);
1327 LayoutUnit startOffset = maxAscent - ascent;
1328 adjustAlignmentForChild(child, startOffset);
1329
1330 if (style()->flexWrap() == FlexWrapReverse)
1331 minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) - startOffset);
1332 break;
1333 }
1334 case ItemPositionSelfStart:
1335 case ItemPositionSelfEnd:
1336 case ItemPositionStart:
1337 case ItemPositionEnd:
1338 case ItemPositionLeft:
1339 case ItemPositionRight:
1340 // FIXME: File a bug about implementing that. The extended grammar
1341 // is not enabled by default so we shouldn't hit this codepath.
1342 ASSERT_NOT_REACHED();
1343 break;
1344 }
1345 }
1346 minMarginAfterBaselines.append(minMarginAfterBaseline);
1347 }
1348
1349 if (style()->flexWrap() != FlexWrapReverse)
1350 return;
1351
1352 // wrap-reverse flips the cross axis start and end. For baseline alignment, this means we
1353 // need to align the after edge of baseline elements with the after edge of the flex line.
1354 child = m_orderIterator.first();
1355 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1356 LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber];
1357 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1358 ASSERT(child);
1359 if (alignmentForChild(child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(child) && minMarginAfterBaseline)
1360 adjustAlignmentForChild(child, minMarginAfterBaseline);
1361 }
1362 }
1363 }
1364
applyStretchAlignmentToChild(RenderBox * child,LayoutUnit lineCrossAxisExtent)1365 void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox* child, LayoutUnit lineCrossAxisExtent)
1366 {
1367 if (!isColumnFlow() && child->style()->logicalHeight().isAuto()) {
1368 // FIXME: If the child has orthogonal flow, then it already has an override height set, so use it.
1369 if (!hasOrthogonalFlow(child)) {
1370 LayoutUnit heightBeforeStretching = needToStretchChildLogicalHeight(child) ? constrainedChildIntrinsicContentLogicalHeight(child) : child->logicalHeight();
1371 LayoutUnit stretchedLogicalHeight = heightBeforeStretching + availableAlignmentSpaceForChildBeforeStretching(lineCrossAxisExtent, child);
1372 ASSERT(!child->needsLayout());
1373 LayoutUnit desiredLogicalHeight = child->constrainLogicalHeightByMinMax(stretchedLogicalHeight, heightBeforeStretching - child->borderAndPaddingLogicalHeight());
1374
1375 // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
1376 if (desiredLogicalHeight != child->logicalHeight()) {
1377 child->setOverrideLogicalContentHeight(desiredLogicalHeight - child->borderAndPaddingLogicalHeight());
1378 child->setLogicalHeight(0);
1379 child->forceChildLayout();
1380 }
1381 }
1382 } else if (isColumnFlow() && child->style()->logicalWidth().isAuto()) {
1383 // FIXME: If the child doesn't have orthogonal flow, then it already has an override width set, so use it.
1384 if (hasOrthogonalFlow(child)) {
1385 LayoutUnit childWidth = std::max<LayoutUnit>(0, lineCrossAxisExtent - crossAxisMarginExtentForChild(child));
1386 childWidth = child->constrainLogicalWidthByMinMax(childWidth, childWidth, this);
1387
1388 if (childWidth != child->logicalWidth()) {
1389 child->setOverrideLogicalContentWidth(childWidth - child->borderAndPaddingLogicalWidth());
1390 child->forceChildLayout();
1391 }
1392 }
1393 }
1394 }
1395
flipForRightToLeftColumn()1396 void RenderFlexibleBox::flipForRightToLeftColumn()
1397 {
1398 if (style()->isLeftToRightDirection() || !isColumnFlow())
1399 return;
1400
1401 LayoutUnit crossExtent = crossAxisExtent();
1402 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
1403 if (child->isOutOfFlowPositioned())
1404 continue;
1405 LayoutPoint location = flowAwareLocationForChild(child);
1406 // For vertical flows, setFlowAwareLocationForChild will transpose x and y,
1407 // so using the y axis for a column cross axis extent is correct.
1408 location.setY(crossExtent - crossAxisExtentForChild(child) - location.y());
1409 setFlowAwareLocationForChild(child, location);
1410 }
1411 }
1412
flipForWrapReverse(const Vector<LineContext> & lineContexts,LayoutUnit crossAxisStartEdge)1413 void RenderFlexibleBox::flipForWrapReverse(const Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge)
1414 {
1415 LayoutUnit contentExtent = crossAxisContentExtent();
1416 RenderBox* child = m_orderIterator.first();
1417 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1418 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1419 ASSERT(child);
1420 LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1421 LayoutUnit originalOffset = lineContexts[lineNumber].crossAxisOffset - crossAxisStartEdge;
1422 LayoutUnit newOffset = contentExtent - originalOffset - lineCrossAxisExtent;
1423 adjustAlignmentForChild(child, newOffset - originalOffset);
1424 }
1425 }
1426 }
1427
1428 }
1429