2 * This file is part of the render object implementation for KHTML.
4 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5 * (C) 1999 Antti Koivisto (koivisto@kde.org)
6 * Copyright (C) 2003 Apple Computer, Inc.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
26 #include "core/rendering/RenderDeprecatedFlexibleBox.h"
28 #include "core/frame/UseCounter.h"
29 #include "core/rendering/RenderLayer.h"
30 #include "core/rendering/RenderView.h"
31 #include "core/rendering/TextAutosizer.h"
32 #include "core/rendering/TextRunConstructor.h"
33 #include "platform/fonts/Font.h"
34 #include "wtf/StdLibExtras.h"
35 #include "wtf/unicode/CharacterNames.h"
39 class FlexBoxIterator {
41 FlexBoxIterator(RenderDeprecatedFlexibleBox* parent)
45 if (m_box->style()->boxOrient() == HORIZONTAL && !m_box->style()->isLeftToRightDirection())
46 m_forward = m_box->style()->boxDirection() != BNORMAL;
48 m_forward = m_box->style()->boxDirection() == BNORMAL;
50 // No choice, since we're going backwards, we have to find out the highest ordinal up front.
51 RenderBox* child = m_box->firstChildBox();
53 if (child->style()->boxOrdinalGroup() > m_largestOrdinal)
54 m_largestOrdinal = child->style()->boxOrdinalGroup();
55 child = child->nextSiblingBox();
65 m_ordinalIteration = -1;
77 if (!m_currentChild) {
80 if (!m_ordinalIteration)
81 m_currentOrdinal = m_forward ? 1 : m_largestOrdinal;
83 if (static_cast<size_t>(m_ordinalIteration) >= m_ordinalValues.size() + 1)
86 // Only copy+sort the values once per layout even if the iterator is reset.
87 if (m_ordinalValues.size() != m_sortedOrdinalValues.size()) {
88 copyToVector(m_ordinalValues, m_sortedOrdinalValues);
89 std::sort(m_sortedOrdinalValues.begin(), m_sortedOrdinalValues.end());
91 m_currentOrdinal = m_forward ? m_sortedOrdinalValues[m_ordinalIteration - 1] : m_sortedOrdinalValues[m_sortedOrdinalValues.size() - m_ordinalIteration];
94 m_currentChild = m_forward ? m_box->firstChildBox() : m_box->lastChildBox();
96 m_currentChild = m_forward ? m_currentChild->nextSiblingBox() : m_currentChild->previousSiblingBox();
98 if (m_currentChild && notFirstOrdinalValue())
99 m_ordinalValues.add(m_currentChild->style()->boxOrdinalGroup());
100 } while (!m_currentChild || (!m_currentChild->isAnonymous()
101 && m_currentChild->style()->boxOrdinalGroup() != m_currentOrdinal));
102 return m_currentChild;
106 bool notFirstOrdinalValue()
108 unsigned int firstOrdinalValue = m_forward ? 1 : m_largestOrdinal;
109 return m_currentOrdinal == firstOrdinalValue && m_currentChild->style()->boxOrdinalGroup() != firstOrdinalValue;
112 RenderDeprecatedFlexibleBox* m_box;
113 RenderBox* m_currentChild;
115 unsigned int m_currentOrdinal;
116 unsigned int m_largestOrdinal;
117 HashSet<unsigned int> m_ordinalValues;
118 Vector<unsigned int> m_sortedOrdinalValues;
119 int m_ordinalIteration;
122 RenderDeprecatedFlexibleBox::RenderDeprecatedFlexibleBox(Element& element)
123 : RenderBlock(&element)
125 ASSERT(!childrenInline());
126 m_stretchingChildren = false;
127 if (!isAnonymous()) {
128 const KURL& url = document().url();
129 if (url.protocolIs("chrome"))
130 UseCounter::count(document(), UseCounter::DeprecatedFlexboxChrome);
131 else if (url.protocolIs("chrome-extension"))
132 UseCounter::count(document(), UseCounter::DeprecatedFlexboxChromeExtension);
134 UseCounter::count(document(), UseCounter::DeprecatedFlexboxWebContent);
138 RenderDeprecatedFlexibleBox::~RenderDeprecatedFlexibleBox()
142 static LayoutUnit marginWidthForChild(RenderBox* child)
144 // A margin basically has three types: fixed, percentage, and auto (variable).
145 // Auto and percentage margins simply become 0 when computing min/max width.
146 // Fixed margins can be added in as is.
147 Length marginLeft = child->style()->marginLeft();
148 Length marginRight = child->style()->marginRight();
149 LayoutUnit margin = 0;
150 if (marginLeft.isFixed())
151 margin += marginLeft.value();
152 if (marginRight.isFixed())
153 margin += marginRight.value();
157 static bool childDoesNotAffectWidthOrFlexing(RenderObject* child)
159 // Positioned children and collapsed children don't affect the min/max width.
160 return child->isOutOfFlowPositioned() || child->style()->visibility() == COLLAPSE;
163 static LayoutUnit contentWidthForChild(RenderBox* child)
165 if (child->hasOverrideWidth())
166 return child->overrideLogicalContentWidth();
167 return child->logicalWidth() - child->borderAndPaddingLogicalWidth();
170 static LayoutUnit contentHeightForChild(RenderBox* child)
172 if (child->hasOverrideHeight())
173 return child->overrideLogicalContentHeight();
174 return child->logicalHeight() - child->borderAndPaddingLogicalHeight();
177 void RenderDeprecatedFlexibleBox::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
179 RenderStyle* oldStyle = style();
180 if (oldStyle && !oldStyle->lineClamp().isNone() && newStyle.lineClamp().isNone())
183 RenderBlock::styleWillChange(diff, newStyle);
186 void RenderDeprecatedFlexibleBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
188 if (hasMultipleLines() || isVertical()) {
189 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
190 if (childDoesNotAffectWidthOrFlexing(child))
193 LayoutUnit margin = marginWidthForChild(child);
194 LayoutUnit width = child->minPreferredLogicalWidth() + margin;
195 minLogicalWidth = std::max(width, minLogicalWidth);
197 width = child->maxPreferredLogicalWidth() + margin;
198 maxLogicalWidth = std::max(width, maxLogicalWidth);
201 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
202 if (childDoesNotAffectWidthOrFlexing(child))
205 LayoutUnit margin = marginWidthForChild(child);
206 minLogicalWidth += child->minPreferredLogicalWidth() + margin;
207 maxLogicalWidth += child->maxPreferredLogicalWidth() + margin;
211 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
213 LayoutUnit scrollbarWidth = instrinsicScrollbarLogicalWidth();
214 maxLogicalWidth += scrollbarWidth;
215 minLogicalWidth += scrollbarWidth;
218 void RenderDeprecatedFlexibleBox::computePreferredLogicalWidths()
220 ASSERT(preferredLogicalWidthsDirty());
222 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
223 RenderStyle* styleToUse = style();
225 if (styleToUse->width().isFixed() && styleToUse->width().value() > 0)
226 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->width().value());
228 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
230 if (styleToUse->minWidth().isFixed() && styleToUse->minWidth().value() > 0) {
231 m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->minWidth().value()));
232 m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->minWidth().value()));
235 if (styleToUse->maxWidth().isFixed()) {
236 m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->maxWidth().value()));
237 m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->maxWidth().value()));
240 LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
241 m_minPreferredLogicalWidth += borderAndPadding;
242 m_maxPreferredLogicalWidth += borderAndPadding;
244 clearPreferredLogicalWidthsDirty();
247 void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren)
249 ASSERT(needsLayout());
251 if (!relayoutChildren && simplifiedLayout())
255 // LayoutState needs this deliberate scope to pop before paint invalidation.
256 LayoutState state(*this, locationOffset());
258 LayoutSize previousSize = size();
260 updateLogicalWidth();
261 updateLogicalHeight();
263 TextAutosizer::LayoutScope textAutosizerLayoutScope(this);
265 if (previousSize != size()
266 || (parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
267 && parent()->style()->boxAlign() == BSTRETCH))
268 relayoutChildren = true;
272 m_stretchingChildren = false;
275 layoutHorizontalBox(relayoutChildren);
277 layoutVerticalBox(relayoutChildren);
279 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
280 updateLogicalHeight();
282 if (previousSize.height() != height())
283 relayoutChildren = true;
285 layoutPositionedObjects(relayoutChildren || isDocumentElement());
287 computeOverflow(oldClientAfterEdge);
290 updateLayerTransformAfterLayout();
292 if (view()->layoutState()->pageLogicalHeight())
293 setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(*this, logicalTop()));
295 // Update our scrollbars if we're overflow:auto/scroll/hidden now that we know if
296 // we overflow or not.
297 if (hasOverflowClip())
298 layer()->scrollableArea()->updateAfterLayout();
303 // The first walk over our kids is to find out if we have any flexible children.
304 static void gatherFlexChildrenInfo(FlexBoxIterator& iterator, bool relayoutChildren, unsigned int& highestFlexGroup, unsigned int& lowestFlexGroup, bool& haveFlex)
306 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
307 // Check to see if this child flexes.
308 if (!childDoesNotAffectWidthOrFlexing(child) && child->style()->boxFlex() > 0.0f) {
309 // We always have to lay out flexible objects again, since the flex distribution
310 // may have changed, and we need to reallocate space.
311 child->clearOverrideSize();
312 if (!relayoutChildren)
313 child->setChildNeedsLayout(MarkOnlyThis);
315 unsigned int flexGroup = child->style()->boxFlexGroup();
316 if (lowestFlexGroup == 0)
317 lowestFlexGroup = flexGroup;
318 if (flexGroup < lowestFlexGroup)
319 lowestFlexGroup = flexGroup;
320 if (flexGroup > highestFlexGroup)
321 highestFlexGroup = flexGroup;
326 void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
328 LayoutUnit toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
329 LayoutUnit yPos = borderTop() + paddingTop();
330 LayoutUnit xPos = borderLeft() + paddingLeft();
331 bool heightSpecified = false;
332 LayoutUnit oldHeight = 0;
334 LayoutUnit remainingSpace = 0;
337 FlexBoxIterator iterator(this);
338 unsigned int highestFlexGroup = 0;
339 unsigned int lowestFlexGroup = 0;
340 bool haveFlex = false, flexingChildren = false;
341 gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
343 RenderBlock::startDelayUpdateScrollInfo();
345 // We do 2 passes. The first pass is simply to lay everyone out at
346 // their preferred widths. The second pass handles flexing the children.
351 xPos = borderLeft() + paddingLeft();
353 // Our first pass is done without flexing. We simply lay the children
354 // out within the box. We have to do a layout first in order to determine
355 // our box's intrinsic height.
356 LayoutUnit maxAscent = 0, maxDescent = 0;
357 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
358 if (child->isOutOfFlowPositioned())
361 SubtreeLayoutScope layoutScope(*child);
362 if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())))
363 layoutScope.setChildNeedsLayout(child);
365 // Compute the child's vertical margins.
366 child->computeAndSetBlockDirectionMargins(this);
368 if (!child->needsLayout())
369 child->markForPaginationRelayoutIfNeeded(layoutScope);
371 // Now do the layout.
372 child->layoutIfNeeded();
374 // Update our height and overflow height.
375 if (style()->boxAlign() == BBASELINE) {
376 LayoutUnit ascent = child->firstLineBoxBaseline();
378 ascent = child->height() + child->marginBottom();
379 ascent += child->marginTop();
380 LayoutUnit descent = (child->height() + child->marginHeight()) - ascent;
382 // Update our maximum ascent.
383 maxAscent = std::max(maxAscent, ascent);
385 // Update our maximum descent.
386 maxDescent = std::max(maxDescent, descent);
388 // Now update our height.
389 setHeight(std::max(yPos + maxAscent + maxDescent, height()));
391 setHeight(std::max(height(), yPos + child->height() + child->marginHeight()));
395 if (!iterator.first() && hasLineIfEmpty())
396 setHeight(height() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
398 setHeight(height() + toAdd);
400 oldHeight = height();
401 updateLogicalHeight();
403 relayoutChildren = false;
404 if (oldHeight != height())
405 heightSpecified = true;
407 // Now that our height is actually known, we can place our boxes.
408 m_stretchingChildren = (style()->boxAlign() == BSTRETCH);
409 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
410 if (child->isOutOfFlowPositioned()) {
411 child->containingBlock()->insertPositionedObject(child);
412 RenderLayer* childLayer = child->layer();
413 childLayer->setStaticInlinePosition(xPos);
414 if (childLayer->staticBlockPosition() != yPos) {
415 childLayer->setStaticBlockPosition(yPos);
416 if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
417 child->setChildNeedsLayout(MarkOnlyThis);
422 if (child->style()->visibility() == COLLAPSE) {
423 // visibility: collapsed children do not participate in our positioning.
424 // But we need to lay them down.
425 child->layoutIfNeeded();
429 SubtreeLayoutScope layoutScope(*child);
431 // We need to see if this child's height has changed, since we make block elements
432 // fill the height of a containing box by default.
434 LayoutUnit oldChildHeight = child->height();
435 child->updateLogicalHeight();
436 if (oldChildHeight != child->height())
437 layoutScope.setChildNeedsLayout(child);
439 if (!child->needsLayout())
440 child->markForPaginationRelayoutIfNeeded(layoutScope);
442 child->layoutIfNeeded();
444 // We can place the child now, using our value of box-align.
445 xPos += child->marginLeft();
446 LayoutUnit childY = yPos;
447 switch (style()->boxAlign()) {
449 childY += child->marginTop() + std::max<LayoutUnit>(0, (contentHeight() - (child->height() + child->marginHeight())) / 2);
452 LayoutUnit ascent = child->firstLineBoxBaseline();
454 ascent = child->height() + child->marginBottom();
455 ascent += child->marginTop();
456 childY += child->marginTop() + (maxAscent - ascent);
460 childY += contentHeight() - child->marginBottom() - child->height();
463 childY += child->marginTop();
467 placeChild(child, LayoutPoint(xPos, childY));
469 xPos += child->width() + child->marginRight();
472 remainingSpace = borderLeft() + paddingLeft() + contentWidth() - xPos;
474 m_stretchingChildren = false;
476 haveFlex = false; // We're done.
478 // We have some flexible objects. See if we need to grow/shrink them at all.
482 // Allocate the remaining space among the flexible objects. If we are trying to
483 // grow, then we go from the lowest flex group to the highest flex group. For shrinking,
484 // we go from the highest flex group to the lowest group.
485 bool expanding = remainingSpace > 0;
486 unsigned int start = expanding ? lowestFlexGroup : highestFlexGroup;
487 unsigned int end = expanding? highestFlexGroup : lowestFlexGroup;
488 for (unsigned i = start; i <= end && remainingSpace; i++) {
489 // Always start off by assuming the group can get all the remaining space.
490 LayoutUnit groupRemainingSpace = remainingSpace;
492 // Flexing consists of multiple passes, since we have to change ratios every time an object hits its max/min-width
493 // For a given pass, we always start off by computing the totalFlex of all objects that can grow/shrink at all, and
494 // computing the allowed growth before an object hits its min/max width (and thus
495 // forces a totalFlex recomputation).
496 LayoutUnit groupRemainingSpaceAtBeginning = groupRemainingSpace;
497 float totalFlex = 0.0f;
498 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
499 if (allowedChildFlex(child, expanding, i))
500 totalFlex += child->style()->boxFlex();
502 LayoutUnit spaceAvailableThisPass = groupRemainingSpace;
503 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
504 LayoutUnit allowedFlex = allowedChildFlex(child, expanding, i);
506 LayoutUnit projectedFlex = (allowedFlex == LayoutUnit::max()) ? allowedFlex : LayoutUnit(allowedFlex * (totalFlex / child->style()->boxFlex()));
507 spaceAvailableThisPass = expanding ? std::min(spaceAvailableThisPass, projectedFlex) : std::max(spaceAvailableThisPass, projectedFlex);
511 // The flex groups may not have any flexible objects this time around.
512 if (!spaceAvailableThisPass || totalFlex == 0.0f) {
513 // If we just couldn't grow/shrink any more, then it's time to transition to the next flex group.
514 groupRemainingSpace = 0;
518 // Now distribute the space to objects.
519 for (RenderBox* child = iterator.first(); child && spaceAvailableThisPass && totalFlex; child = iterator.next()) {
520 if (child->style()->visibility() == COLLAPSE)
523 if (allowedChildFlex(child, expanding, i)) {
524 LayoutUnit spaceAdd = LayoutUnit(spaceAvailableThisPass * (child->style()->boxFlex() / totalFlex));
526 child->setOverrideLogicalContentWidth(contentWidthForChild(child) + spaceAdd);
527 flexingChildren = true;
528 relayoutChildren = true;
531 spaceAvailableThisPass -= spaceAdd;
532 remainingSpace -= spaceAdd;
533 groupRemainingSpace -= spaceAdd;
535 totalFlex -= child->style()->boxFlex();
538 if (groupRemainingSpace == groupRemainingSpaceAtBeginning) {
539 // This is not advancing, avoid getting stuck by distributing the remaining pixels.
540 LayoutUnit spaceAdd = groupRemainingSpace > 0 ? 1 : -1;
541 for (RenderBox* child = iterator.first(); child && groupRemainingSpace; child = iterator.next()) {
542 if (allowedChildFlex(child, expanding, i)) {
543 child->setOverrideLogicalContentWidth(contentWidthForChild(child) + spaceAdd);
544 flexingChildren = true;
545 relayoutChildren = true;
546 remainingSpace -= spaceAdd;
547 groupRemainingSpace -= spaceAdd;
551 } while (absoluteValue(groupRemainingSpace) >= 1);
554 // We didn't find any children that could grow.
555 if (haveFlex && !flexingChildren)
560 RenderBlock::finishDelayUpdateScrollInfo();
562 if (remainingSpace > 0 && ((style()->isLeftToRightDirection() && style()->boxPack() != Start)
563 || (!style()->isLeftToRightDirection() && style()->boxPack() != End))) {
564 // Children must be repositioned.
565 LayoutUnit offset = 0;
566 if (style()->boxPack() == Justify) {
567 // Determine the total number of children.
568 int totalChildren = 0;
569 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
570 if (childDoesNotAffectWidthOrFlexing(child))
575 // Iterate over the children and space them out according to the
576 // justification level.
577 if (totalChildren > 1) {
579 bool firstChild = true;
580 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
581 if (childDoesNotAffectWidthOrFlexing(child))
589 offset += remainingSpace/totalChildren;
590 remainingSpace -= (remainingSpace/totalChildren);
593 placeChild(child, child->location() + LayoutSize(offset, 0));
597 if (style()->boxPack() == Center)
598 offset += remainingSpace / 2;
599 else // END for LTR, START for RTL
600 offset += remainingSpace;
601 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
602 if (childDoesNotAffectWidthOrFlexing(child))
605 placeChild(child, child->location() + LayoutSize(offset, 0));
610 // So that the computeLogicalHeight in layoutBlock() knows to relayout positioned objects because of
611 // a height change, we revert our height back to the intrinsic height before returning.
613 setHeight(oldHeight);
616 void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren)
618 LayoutUnit yPos = borderTop() + paddingTop();
619 LayoutUnit toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
620 bool heightSpecified = false;
621 LayoutUnit oldHeight = 0;
623 LayoutUnit remainingSpace = 0;
625 FlexBoxIterator iterator(this);
626 unsigned int highestFlexGroup = 0;
627 unsigned int lowestFlexGroup = 0;
628 bool haveFlex = false, flexingChildren = false;
629 gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
631 // We confine the line clamp ugliness to vertical flexible boxes (thus keeping it out of
632 // mainstream block layout); this is not really part of the XUL box model.
633 bool haveLineClamp = !style()->lineClamp().isNone();
635 applyLineClamp(iterator, relayoutChildren);
637 RenderBlock::startDelayUpdateScrollInfo();
639 // We do 2 passes. The first pass is simply to lay everyone out at
640 // their preferred widths. The second pass handles flexing the children.
641 // Our first pass is done without flexing. We simply lay the children
642 // out within the box.
644 setHeight(borderTop() + paddingTop());
645 LayoutUnit minHeight = height() + toAdd;
647 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
648 if (child->isOutOfFlowPositioned()) {
649 child->containingBlock()->insertPositionedObject(child);
650 RenderLayer* childLayer = child->layer();
651 childLayer->setStaticInlinePosition(borderStart() + paddingStart());
652 if (childLayer->staticBlockPosition() != height()) {
653 childLayer->setStaticBlockPosition(height());
654 if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
655 child->setChildNeedsLayout(MarkOnlyThis);
660 SubtreeLayoutScope layoutScope(*child);
661 if (!haveLineClamp && (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))))
662 layoutScope.setChildNeedsLayout(child);
664 if (child->style()->visibility() == COLLAPSE) {
665 // visibility: collapsed children do not participate in our positioning.
666 // But we need to lay them down.
667 child->layoutIfNeeded();
671 // Compute the child's vertical margins.
672 child->computeAndSetBlockDirectionMargins(this);
674 // Add in the child's marginTop to our height.
675 setHeight(height() + child->marginTop());
677 if (!child->needsLayout())
678 child->markForPaginationRelayoutIfNeeded(layoutScope);
681 child->layoutIfNeeded();
683 // We can place the child now, using our value of box-align.
684 LayoutUnit childX = borderLeft() + paddingLeft();
685 switch (style()->boxAlign()) {
687 case BBASELINE: // Baseline just maps to center for vertical boxes
688 childX += child->marginLeft() + std::max<LayoutUnit>(0, (contentWidth() - (child->width() + child->marginWidth())) / 2);
691 if (!style()->isLeftToRightDirection())
692 childX += child->marginLeft();
694 childX += contentWidth() - child->marginRight() - child->width();
696 default: // BSTART/BSTRETCH
697 if (style()->isLeftToRightDirection())
698 childX += child->marginLeft();
700 childX += contentWidth() - child->marginRight() - child->width();
705 placeChild(child, LayoutPoint(childX, height()));
706 setHeight(height() + child->height() + child->marginBottom());
711 if (!iterator.first() && hasLineIfEmpty())
712 setHeight(height() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
714 setHeight(height() + toAdd);
716 // Negative margins can cause our height to shrink below our minimal height (border/padding).
717 // If this happens, ensure that the computed height is increased to the minimal height.
718 if (height() < minHeight)
719 setHeight(minHeight);
721 // Now we have to calc our height, so we know how much space we have remaining.
722 oldHeight = height();
723 updateLogicalHeight();
724 if (oldHeight != height())
725 heightSpecified = true;
727 remainingSpace = borderTop() + paddingTop() + contentHeight() - yPos;
730 haveFlex = false; // We're done.
732 // We have some flexible objects. See if we need to grow/shrink them at all.
736 // Allocate the remaining space among the flexible objects. If we are trying to
737 // grow, then we go from the lowest flex group to the highest flex group. For shrinking,
738 // we go from the highest flex group to the lowest group.
739 bool expanding = remainingSpace > 0;
740 unsigned int start = expanding ? lowestFlexGroup : highestFlexGroup;
741 unsigned int end = expanding? highestFlexGroup : lowestFlexGroup;
742 for (unsigned i = start; i <= end && remainingSpace; i++) {
743 // Always start off by assuming the group can get all the remaining space.
744 LayoutUnit groupRemainingSpace = remainingSpace;
746 // Flexing consists of multiple passes, since we have to change ratios every time an object hits its max/min-width
747 // For a given pass, we always start off by computing the totalFlex of all objects that can grow/shrink at all, and
748 // computing the allowed growth before an object hits its min/max width (and thus
749 // forces a totalFlex recomputation).
750 LayoutUnit groupRemainingSpaceAtBeginning = groupRemainingSpace;
751 float totalFlex = 0.0f;
752 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
753 if (allowedChildFlex(child, expanding, i))
754 totalFlex += child->style()->boxFlex();
756 LayoutUnit spaceAvailableThisPass = groupRemainingSpace;
757 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
758 LayoutUnit allowedFlex = allowedChildFlex(child, expanding, i);
760 LayoutUnit projectedFlex = (allowedFlex == LayoutUnit::max()) ? allowedFlex : static_cast<LayoutUnit>(allowedFlex * (totalFlex / child->style()->boxFlex()));
761 spaceAvailableThisPass = expanding ? std::min(spaceAvailableThisPass, projectedFlex) : std::max(spaceAvailableThisPass, projectedFlex);
765 // The flex groups may not have any flexible objects this time around.
766 if (!spaceAvailableThisPass || totalFlex == 0.0f) {
767 // If we just couldn't grow/shrink any more, then it's time to transition to the next flex group.
768 groupRemainingSpace = 0;
772 // Now distribute the space to objects.
773 for (RenderBox* child = iterator.first(); child && spaceAvailableThisPass && totalFlex; child = iterator.next()) {
774 if (allowedChildFlex(child, expanding, i)) {
775 LayoutUnit spaceAdd = static_cast<LayoutUnit>(spaceAvailableThisPass * (child->style()->boxFlex() / totalFlex));
777 child->setOverrideLogicalContentHeight(contentHeightForChild(child) + spaceAdd);
778 flexingChildren = true;
779 relayoutChildren = true;
782 spaceAvailableThisPass -= spaceAdd;
783 remainingSpace -= spaceAdd;
784 groupRemainingSpace -= spaceAdd;
786 totalFlex -= child->style()->boxFlex();
789 if (groupRemainingSpace == groupRemainingSpaceAtBeginning) {
790 // This is not advancing, avoid getting stuck by distributing the remaining pixels.
791 LayoutUnit spaceAdd = groupRemainingSpace > 0 ? 1 : -1;
792 for (RenderBox* child = iterator.first(); child && groupRemainingSpace; child = iterator.next()) {
793 if (allowedChildFlex(child, expanding, i)) {
794 child->setOverrideLogicalContentHeight(contentHeightForChild(child) + spaceAdd);
795 flexingChildren = true;
796 relayoutChildren = true;
797 remainingSpace -= spaceAdd;
798 groupRemainingSpace -= spaceAdd;
802 } while (absoluteValue(groupRemainingSpace) >= 1);
805 // We didn't find any children that could grow.
806 if (haveFlex && !flexingChildren)
811 RenderBlock::finishDelayUpdateScrollInfo();
813 if (style()->boxPack() != Start && remainingSpace > 0) {
814 // Children must be repositioned.
815 LayoutUnit offset = 0;
816 if (style()->boxPack() == Justify) {
817 // Determine the total number of children.
818 int totalChildren = 0;
819 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
820 if (childDoesNotAffectWidthOrFlexing(child))
826 // Iterate over the children and space them out according to the
827 // justification level.
828 if (totalChildren > 1) {
830 bool firstChild = true;
831 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
832 if (childDoesNotAffectWidthOrFlexing(child))
840 offset += remainingSpace/totalChildren;
841 remainingSpace -= (remainingSpace/totalChildren);
843 placeChild(child, child->location() + LayoutSize(0, offset));
847 if (style()->boxPack() == Center)
848 offset += remainingSpace / 2;
850 offset += remainingSpace;
851 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
852 if (childDoesNotAffectWidthOrFlexing(child))
854 placeChild(child, child->location() + LayoutSize(0, offset));
859 // So that the computeLogicalHeight in layoutBlock() knows to relayout positioned objects because of
860 // a height change, we revert our height back to the intrinsic height before returning.
862 setHeight(oldHeight);
865 void RenderDeprecatedFlexibleBox::applyLineClamp(FlexBoxIterator& iterator, bool relayoutChildren)
867 UseCounter::count(document(), UseCounter::LineClamp);
869 int maxLineCount = 0;
870 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
871 if (childDoesNotAffectWidthOrFlexing(child))
874 child->clearOverrideSize();
875 if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))
876 || (child->style()->height().isAuto() && child->isRenderBlock())) {
877 child->setChildNeedsLayout(MarkOnlyThis);
879 // Dirty all the positioned objects.
880 if (child->isRenderBlock()) {
881 toRenderBlock(child)->markPositionedObjectsForLayout();
882 toRenderBlock(child)->clearTruncation();
885 child->layoutIfNeeded();
886 if (child->style()->height().isAuto() && child->isRenderBlock())
887 maxLineCount = std::max(maxLineCount, toRenderBlock(child)->lineCount());
890 // Get the number of lines and then alter all block flow children with auto height to use the
891 // specified height. We always try to leave room for at least one line.
892 LineClampValue lineClamp = style()->lineClamp();
893 int numVisibleLines = lineClamp.isPercentage() ? std::max(1, (maxLineCount + 1) * lineClamp.value() / 100) : lineClamp.value();
894 if (numVisibleLines >= maxLineCount)
897 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
898 if (childDoesNotAffectWidthOrFlexing(child) || !child->style()->height().isAuto() || !child->isRenderBlock())
901 RenderBlock* blockChild = toRenderBlock(child);
902 int lineCount = blockChild->lineCount();
903 if (lineCount <= numVisibleLines)
906 LayoutUnit newHeight = blockChild->heightForLineCount(numVisibleLines);
907 if (newHeight == child->height())
910 child->setOverrideLogicalContentHeight(newHeight - child->borderAndPaddingHeight());
911 child->forceChildLayout();
913 // FIXME: For now don't support RTL.
914 if (style()->direction() != LTR)
918 RootInlineBox* lastLine = blockChild->lineAtIndex(lineCount - 1);
922 RootInlineBox* lastVisibleLine = blockChild->lineAtIndex(numVisibleLines - 1);
923 if (!lastVisibleLine)
926 const UChar ellipsisAndSpace[2] = { horizontalEllipsis, ' ' };
927 DEFINE_STATIC_LOCAL(AtomicString, ellipsisAndSpaceStr, (ellipsisAndSpace, 2));
928 DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
929 const Font& font = style(numVisibleLines == 1)->font();
931 // Get ellipsis width, and if the last child is an anchor, it will go after the ellipsis, so add in a space and the anchor width too
933 InlineBox* anchorBox = lastLine->lastChild();
934 if (anchorBox && anchorBox->renderer().style()->isLink())
935 totalWidth = anchorBox->logicalWidth() + font.width(constructTextRun(this, font, ellipsisAndSpace, 2, style(), style()->direction()));
938 totalWidth = font.width(constructTextRun(this, font, &horizontalEllipsis, 1, style(), style()->direction()));
941 // See if this width can be accommodated on the last visible line
942 RenderBlockFlow& destBlock = lastVisibleLine->block();
943 RenderBlockFlow& srcBlock = lastLine->block();
945 // FIXME: Directions of src/destBlock could be different from our direction and from one another.
946 if (!srcBlock.style()->isLeftToRightDirection())
949 bool leftToRight = destBlock.style()->isLeftToRightDirection();
953 LayoutUnit blockRightEdge = destBlock.logicalRightOffsetForLine(lastVisibleLine->y(), false);
954 if (!lastVisibleLine->lineCanAccommodateEllipsis(leftToRight, blockRightEdge, lastVisibleLine->x() + lastVisibleLine->logicalWidth(), totalWidth))
957 // Let the truncation code kick in.
958 // FIXME: the text alignment should be recomputed after the width changes due to truncation.
959 LayoutUnit blockLeftEdge = destBlock.logicalLeftOffsetForLine(lastVisibleLine->y(), false);
960 lastVisibleLine->placeEllipsis(anchorBox ? ellipsisAndSpaceStr : ellipsisStr, leftToRight, blockLeftEdge.toFloat(), blockRightEdge.toFloat(), totalWidth, anchorBox);
961 destBlock.setHasMarkupTruncation(true);
965 void RenderDeprecatedFlexibleBox::clearLineClamp()
967 FlexBoxIterator iterator(this);
968 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
969 if (childDoesNotAffectWidthOrFlexing(child))
972 child->clearOverrideSize();
973 if ((child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))
974 || (child->style()->height().isAuto() && child->isRenderBlock())) {
975 child->setChildNeedsLayout();
977 if (child->isRenderBlock()) {
978 toRenderBlock(child)->markPositionedObjectsForLayout();
979 toRenderBlock(child)->clearTruncation();
985 void RenderDeprecatedFlexibleBox::placeChild(RenderBox* child, const LayoutPoint& location)
987 // FIXME Investigate if this can be removed based on other flags. crbug.com/370010
988 child->setMayNeedPaintInvalidation(true);
991 child->setLocation(location);
994 LayoutUnit RenderDeprecatedFlexibleBox::allowedChildFlex(RenderBox* child, bool expanding, unsigned int group)
996 if (childDoesNotAffectWidthOrFlexing(child) || child->style()->boxFlex() == 0.0f || child->style()->boxFlexGroup() != group)
1000 if (isHorizontal()) {
1001 // FIXME: For now just handle fixed values.
1002 LayoutUnit maxWidth = LayoutUnit::max();
1003 LayoutUnit width = contentWidthForChild(child);
1004 if (child->style()->maxWidth().isFixed())
1005 maxWidth = child->style()->maxWidth().value();
1006 else if (child->style()->maxWidth().type() == Intrinsic)
1007 maxWidth = child->maxPreferredLogicalWidth();
1008 else if (child->style()->maxWidth().type() == MinIntrinsic)
1009 maxWidth = child->minPreferredLogicalWidth();
1010 if (maxWidth == LayoutUnit::max())
1012 return std::max<LayoutUnit>(0, maxWidth - width);
1014 // FIXME: For now just handle fixed values.
1015 LayoutUnit maxHeight = LayoutUnit::max();
1016 LayoutUnit height = contentHeightForChild(child);
1017 if (child->style()->maxHeight().isFixed())
1018 maxHeight = child->style()->maxHeight().value();
1019 if (maxHeight == LayoutUnit::max())
1021 return std::max<LayoutUnit>(0, maxHeight - height);
1025 // FIXME: For now just handle fixed values.
1026 if (isHorizontal()) {
1027 LayoutUnit minWidth = child->minPreferredLogicalWidth();
1028 LayoutUnit width = contentWidthForChild(child);
1029 if (child->style()->minWidth().isFixed())
1030 minWidth = child->style()->minWidth().value();
1031 else if (child->style()->minWidth().type() == Intrinsic)
1032 minWidth = child->maxPreferredLogicalWidth();
1033 else if (child->style()->minWidth().type() == MinIntrinsic)
1034 minWidth = child->minPreferredLogicalWidth();
1035 else if (child->style()->minWidth().type() == Auto)
1038 LayoutUnit allowedShrinkage = std::min<LayoutUnit>(0, minWidth - width);
1039 return allowedShrinkage;
1041 Length minHeight = child->style()->minHeight();
1042 if (minHeight.isFixed() || minHeight.isAuto()) {
1043 LayoutUnit minHeight = child->style()->minHeight().value();
1044 LayoutUnit height = contentHeightForChild(child);
1045 LayoutUnit allowedShrinkage = std::min<LayoutUnit>(0, minHeight - height);
1046 return allowedShrinkage;
1053 const char* RenderDeprecatedFlexibleBox::renderName() const
1056 return "RenderDeprecatedFlexibleBox (floating)";
1057 if (isOutOfFlowPositioned())
1058 return "RenderDeprecatedFlexibleBox (positioned)";
1059 // FIXME: Cleanup isPseudoElement duplication with other renderName methods.
1061 if (isPseudoElement()) {
1062 if (style()->styleType() == BEFORE)
1063 return "RenderDeprecatedFlexibleBox (pseudo:before)";
1064 if (style()->styleType() == AFTER)
1065 return "RenderDeprecatedFlexibleBox (pseudo:after)";
1066 if (style()->styleType() == BACKDROP)
1067 return "RenderDeprecatedFlexibleBox (pseudo:backdrop)";
1068 ASSERT_NOT_REACHED();
1071 return "RenderDeprecatedFlexibleBox (generated)";
1072 if (isRelPositioned())
1073 return "RenderDeprecatedFlexibleBox (relative positioned)";
1074 return "RenderDeprecatedFlexibleBox";
1077 } // namespace blink