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 "RenderDeprecatedFlexibleBox.h"
28 #include "LayoutRepainter.h"
29 #include "RenderLayer.h"
30 #include "RenderView.h"
31 #include <wtf/StdLibExtras.h>
32 #include <wtf/unicode/CharacterNames.h>
38 class FlexBoxIterator {
40 FlexBoxIterator(RenderDeprecatedFlexibleBox* parent)
44 if (m_box->style()->boxOrient() == HORIZONTAL && !m_box->style()->isLeftToRightDirection())
45 m_forward = m_box->style()->boxDirection() != BNORMAL;
47 m_forward = m_box->style()->boxDirection() == BNORMAL;
49 // No choice, since we're going backwards, we have to find out the highest ordinal up front.
50 RenderBox* child = m_box->firstChildBox();
52 if (child->style()->boxOrdinalGroup() > m_largestOrdinal)
53 m_largestOrdinal = child->style()->boxOrdinalGroup();
54 child = child->nextSiblingBox();
64 m_ordinalIteration = -1;
76 if (!m_currentChild) {
79 if (!m_ordinalIteration)
80 m_currentOrdinal = m_forward ? 1 : m_largestOrdinal;
82 if (m_ordinalIteration >= m_ordinalValues.size() + 1)
85 // Only copy+sort the values once per layout even if the iterator is reset.
86 if (static_cast<size_t>(m_ordinalValues.size()) != m_sortedOrdinalValues.size()) {
87 copyToVector(m_ordinalValues, m_sortedOrdinalValues);
88 sort(m_sortedOrdinalValues.begin(), m_sortedOrdinalValues.end());
90 m_currentOrdinal = m_forward ? m_sortedOrdinalValues[m_ordinalIteration - 1] : m_sortedOrdinalValues[m_sortedOrdinalValues.size() - m_ordinalIteration];
93 m_currentChild = m_forward ? m_box->firstChildBox() : m_box->lastChildBox();
95 m_currentChild = m_forward ? m_currentChild->nextSiblingBox() : m_currentChild->previousSiblingBox();
97 if (m_currentChild && notFirstOrdinalValue())
98 m_ordinalValues.add(m_currentChild->style()->boxOrdinalGroup());
99 } while (!m_currentChild || (!m_currentChild->isAnonymous()
100 && m_currentChild->style()->boxOrdinalGroup() != m_currentOrdinal));
101 return m_currentChild;
105 bool notFirstOrdinalValue()
107 unsigned int firstOrdinalValue = m_forward ? 1 : m_largestOrdinal;
108 return m_currentOrdinal == firstOrdinalValue && m_currentChild->style()->boxOrdinalGroup() != firstOrdinalValue;
111 RenderDeprecatedFlexibleBox* m_box;
112 RenderBox* m_currentChild;
114 unsigned int m_currentOrdinal;
115 unsigned int m_largestOrdinal;
116 HashSet<unsigned int> m_ordinalValues;
117 Vector<unsigned int> m_sortedOrdinalValues;
118 int m_ordinalIteration;
121 RenderDeprecatedFlexibleBox::RenderDeprecatedFlexibleBox(Node* node)
124 setChildrenInline(false); // All of our children must be block-level
125 m_flexingChildren = m_stretchingChildren = false;
128 RenderDeprecatedFlexibleBox::~RenderDeprecatedFlexibleBox()
132 static LayoutUnit marginWidthForChild(RenderBox* child)
134 // A margin basically has three types: fixed, percentage, and auto (variable).
135 // Auto and percentage margins simply become 0 when computing min/max width.
136 // Fixed margins can be added in as is.
137 Length marginLeft = child->style()->marginLeft();
138 Length marginRight = child->style()->marginRight();
139 LayoutUnit margin = 0;
140 if (marginLeft.isFixed())
141 margin += marginLeft.value();
142 if (marginRight.isFixed())
143 margin += marginRight.value();
147 static bool childDoesNotAffectWidthOrFlexing(RenderObject* child)
149 // Positioned children and collapsed children don't affect the min/max width.
150 return child->isOutOfFlowPositioned() || child->style()->visibility() == COLLAPSE;
153 void RenderDeprecatedFlexibleBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
155 RenderStyle* oldStyle = style();
156 if (oldStyle && !oldStyle->lineClamp().isNone() && newStyle->lineClamp().isNone())
159 RenderBlock::styleWillChange(diff, newStyle);
162 void RenderDeprecatedFlexibleBox::calcHorizontalPrefWidths()
164 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
165 if (childDoesNotAffectWidthOrFlexing(child))
168 LayoutUnit margin = marginWidthForChild(child);
169 m_minPreferredLogicalWidth += child->minPreferredLogicalWidth() + margin;
170 m_maxPreferredLogicalWidth += child->maxPreferredLogicalWidth() + margin;
174 void RenderDeprecatedFlexibleBox::calcVerticalPrefWidths()
176 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
177 if (childDoesNotAffectWidthOrFlexing(child))
180 LayoutUnit margin = marginWidthForChild(child);
181 LayoutUnit width = child->minPreferredLogicalWidth() + margin;
182 m_minPreferredLogicalWidth = max(width, m_minPreferredLogicalWidth);
184 width = child->maxPreferredLogicalWidth() + margin;
185 m_maxPreferredLogicalWidth = max(width, m_maxPreferredLogicalWidth);
189 void RenderDeprecatedFlexibleBox::computePreferredLogicalWidths()
191 ASSERT(preferredLogicalWidthsDirty());
193 if (style()->width().isFixed() && style()->width().value() > 0)
194 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeContentBoxLogicalWidth(style()->width().value());
196 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
198 if (hasMultipleLines() || isVertical())
199 calcVerticalPrefWidths();
201 calcHorizontalPrefWidths();
203 m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
206 if (hasOverflowClip() && style()->overflowY() == OSCROLL) {
207 layer()->setHasVerticalScrollbar(true);
208 LayoutUnit scrollbarWidth = verticalScrollbarWidth();
209 m_maxPreferredLogicalWidth += scrollbarWidth;
210 m_minPreferredLogicalWidth += scrollbarWidth;
213 if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
214 m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->minWidth().value()));
215 m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->minWidth().value()));
218 if (style()->maxWidth().isFixed()) {
219 m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->maxWidth().value()));
220 m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->maxWidth().value()));
223 LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
224 m_minPreferredLogicalWidth += borderAndPadding;
225 m_maxPreferredLogicalWidth += borderAndPadding;
227 setPreferredLogicalWidthsDirty(false);
230 void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
232 ASSERT(needsLayout());
234 if (!relayoutChildren && simplifiedLayout())
237 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
238 LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
240 if (inRenderFlowThread()) {
241 // Regions changing widths can force us to relayout our children.
242 if (logicalWidthChangedInRegions())
243 relayoutChildren = true;
245 computeInitialRegionRangeForBlock();
247 LayoutSize previousSize = size();
249 computeLogicalWidth();
250 computeLogicalHeight();
254 if (previousSize != size()
255 || (parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
256 && parent()->style()->boxAlign() == BSTRETCH))
257 relayoutChildren = true;
261 m_flexingChildren = m_stretchingChildren = false;
263 initMaxMarginValues();
265 // For overflow:scroll blocks, ensure we have both scrollbars in place always.
266 if (scrollsOverflow()) {
267 if (style()->overflowX() == OSCROLL)
268 layer()->setHasHorizontalScrollbar(true);
269 if (style()->overflowY() == OSCROLL)
270 layer()->setHasVerticalScrollbar(true);
274 layoutHorizontalBox(relayoutChildren);
276 layoutVerticalBox(relayoutChildren);
278 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
279 computeLogicalHeight();
281 if (previousSize.height() != height())
282 relayoutChildren = true;
284 layoutPositionedObjects(relayoutChildren || isRoot());
286 computeRegionRangeForBlock();
288 if (!isFloatingOrOutOfFlowPositioned() && height() == 0) {
289 // We are a block with no border and padding and a computed height
290 // of 0. The CSS spec states that zero-height blocks collapse their margins
292 // When blocks are self-collapsing, we just use the top margin values and set the
293 // bottom margin max values to 0. This way we don't factor in the values
294 // twice when we collapse with our previous vertically adjacent and
295 // following vertically adjacent blocks.
296 LayoutUnit pos = maxPositiveMarginBefore();
297 LayoutUnit neg = maxNegativeMarginBefore();
298 if (maxPositiveMarginAfter() > pos)
299 pos = maxPositiveMarginAfter();
300 if (maxNegativeMarginAfter() > neg)
301 neg = maxNegativeMarginAfter();
302 setMaxMarginBeforeValues(pos, neg);
303 setMaxMarginAfterValues(0, 0);
306 computeOverflow(oldClientAfterEdge);
310 updateLayerTransform();
312 if (view()->layoutState()->pageLogicalHeight())
313 setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(this, logicalTop()));
315 // Update our scrollbars if we're overflow:auto/scroll/hidden now that we know if
316 // we overflow or not.
317 if (hasOverflowClip())
318 layer()->updateScrollInfoAfterLayout();
320 // Repaint with our new bounds if they are different from our old bounds.
321 repainter.repaintAfterLayout();
323 setNeedsLayout(false);
326 // The first walk over our kids is to find out if we have any flexible children.
327 static void gatherFlexChildrenInfo(FlexBoxIterator& iterator, bool relayoutChildren, unsigned int& highestFlexGroup, unsigned int& lowestFlexGroup, bool& haveFlex)
329 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
330 // Check to see if this child flexes.
331 if (!childDoesNotAffectWidthOrFlexing(child) && child->style()->boxFlex() > 0.0f) {
332 // We always have to lay out flexible objects again, since the flex distribution
333 // may have changed, and we need to reallocate space.
334 child->clearOverrideSize();
335 if (!relayoutChildren)
336 child->setChildNeedsLayout(true, MarkOnlyThis);
338 unsigned int flexGroup = child->style()->boxFlexGroup();
339 if (lowestFlexGroup == 0)
340 lowestFlexGroup = flexGroup;
341 if (flexGroup < lowestFlexGroup)
342 lowestFlexGroup = flexGroup;
343 if (flexGroup > highestFlexGroup)
344 highestFlexGroup = flexGroup;
349 void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
351 LayoutUnit toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
352 LayoutUnit yPos = borderTop() + paddingTop();
353 LayoutUnit xPos = borderLeft() + paddingLeft();
354 bool heightSpecified = false;
355 LayoutUnit oldHeight = 0;
357 LayoutUnit remainingSpace = 0;
360 FlexBoxIterator iterator(this);
361 unsigned int highestFlexGroup = 0;
362 unsigned int lowestFlexGroup = 0;
363 bool haveFlex = false;
364 gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
366 RenderBlock::startDelayUpdateScrollInfo();
368 // We do 2 passes. The first pass is simply to lay everyone out at
369 // their preferred widths. The second pass handles flexing the children.
374 xPos = borderLeft() + paddingLeft();
376 // Our first pass is done without flexing. We simply lay the children
377 // out within the box. We have to do a layout first in order to determine
378 // our box's intrinsic height.
379 LayoutUnit maxAscent = 0, maxDescent = 0;
380 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
381 // make sure we relayout children if we need it.
382 if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())))
383 child->setChildNeedsLayout(true, MarkOnlyThis);
385 if (child->isOutOfFlowPositioned())
388 // Compute the child's vertical margins.
389 child->computeBlockDirectionMargins(this);
391 if (!child->needsLayout())
392 child->markForPaginationRelayoutIfNeeded();
394 // Now do the layout.
395 child->layoutIfNeeded();
397 // Update our height and overflow height.
398 if (style()->boxAlign() == BBASELINE) {
399 LayoutUnit ascent = child->firstLineBoxBaseline();
401 ascent = child->height() + child->marginBottom();
402 ascent += child->marginTop();
403 LayoutUnit descent = (child->height() + child->marginHeight()) - ascent;
405 // Update our maximum ascent.
406 maxAscent = max(maxAscent, ascent);
408 // Update our maximum descent.
409 maxDescent = max(maxDescent, descent);
411 // Now update our height.
412 setHeight(max(yPos + maxAscent + maxDescent, height()));
415 setHeight(max(height(), yPos + child->height() + child->marginHeight()));
418 if (!iterator.first() && hasLineIfEmpty())
419 setHeight(height() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
421 setHeight(height() + toAdd);
423 oldHeight = height();
424 computeLogicalHeight();
426 relayoutChildren = false;
427 if (oldHeight != height())
428 heightSpecified = true;
430 // Now that our height is actually known, we can place our boxes.
431 m_stretchingChildren = (style()->boxAlign() == BSTRETCH);
432 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
433 if (child->isOutOfFlowPositioned()) {
434 child->containingBlock()->insertPositionedObject(child);
435 RenderLayer* childLayer = child->layer();
436 childLayer->setStaticInlinePosition(xPos); // FIXME: Not right for regions.
437 if (childLayer->staticBlockPosition() != yPos) {
438 childLayer->setStaticBlockPosition(yPos);
439 if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
440 child->setChildNeedsLayout(true, MarkOnlyThis);
445 if (child->style()->visibility() == COLLAPSE) {
446 // visibility: collapsed children do not participate in our positioning.
447 // But we need to lay them down.
448 child->layoutIfNeeded();
453 // We need to see if this child's height has changed, since we make block elements
454 // fill the height of a containing box by default.
456 LayoutUnit oldChildHeight = child->height();
457 child->computeLogicalHeight();
458 if (oldChildHeight != child->height())
459 child->setChildNeedsLayout(true, MarkOnlyThis);
461 if (!child->needsLayout())
462 child->markForPaginationRelayoutIfNeeded();
464 child->layoutIfNeeded();
466 // We can place the child now, using our value of box-align.
467 xPos += child->marginLeft();
468 LayoutUnit childY = yPos;
469 switch (style()->boxAlign()) {
471 childY += child->marginTop() + max<LayoutUnit>(0, (contentHeight() - (child->height() + child->marginHeight())) / 2);
474 LayoutUnit ascent = child->firstLineBoxBaseline();
476 ascent = child->height() + child->marginBottom();
477 ascent += child->marginTop();
478 childY += child->marginTop() + (maxAscent - ascent);
482 childY += contentHeight() - child->marginBottom() - child->height();
485 childY += child->marginTop();
489 placeChild(child, LayoutPoint(xPos, childY));
491 xPos += child->width() + child->marginRight();
494 remainingSpace = borderLeft() + paddingLeft() + contentWidth() - xPos;
496 m_stretchingChildren = false;
497 if (m_flexingChildren)
498 haveFlex = false; // We're done.
500 // We have some flexible objects. See if we need to grow/shrink them at all.
504 // Allocate the remaining space among the flexible objects. If we are trying to
505 // grow, then we go from the lowest flex group to the highest flex group. For shrinking,
506 // we go from the highest flex group to the lowest group.
507 bool expanding = remainingSpace > 0;
508 unsigned int start = expanding ? lowestFlexGroup : highestFlexGroup;
509 unsigned int end = expanding? highestFlexGroup : lowestFlexGroup;
510 for (unsigned int i = start; i <= end && remainingSpace; i++) {
511 // Always start off by assuming the group can get all the remaining space.
512 LayoutUnit groupRemainingSpace = remainingSpace;
514 // Flexing consists of multiple passes, since we have to change ratios every time an object hits its max/min-width
515 // For a given pass, we always start off by computing the totalFlex of all objects that can grow/shrink at all, and
516 // computing the allowed growth before an object hits its min/max width (and thus
517 // forces a totalFlex recomputation).
518 LayoutUnit groupRemainingSpaceAtBeginning = groupRemainingSpace;
519 float totalFlex = 0.0f;
520 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
521 if (allowedChildFlex(child, expanding, i))
522 totalFlex += child->style()->boxFlex();
524 LayoutUnit spaceAvailableThisPass = groupRemainingSpace;
525 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
526 LayoutUnit allowedFlex = allowedChildFlex(child, expanding, i);
528 LayoutUnit projectedFlex = (allowedFlex == MAX_LAYOUT_UNIT) ? allowedFlex : LayoutUnit(allowedFlex * (totalFlex / child->style()->boxFlex()));
529 spaceAvailableThisPass = expanding ? min(spaceAvailableThisPass, projectedFlex) : max(spaceAvailableThisPass, projectedFlex);
533 // The flex groups may not have any flexible objects this time around.
534 if (!spaceAvailableThisPass || totalFlex == 0.0f) {
535 // If we just couldn't grow/shrink any more, then it's time to transition to the next flex group.
536 groupRemainingSpace = 0;
540 // Now distribute the space to objects.
541 for (RenderBox* child = iterator.first(); child && spaceAvailableThisPass && totalFlex; child = iterator.next()) {
542 if (child->style()->visibility() == COLLAPSE)
545 if (allowedChildFlex(child, expanding, i)) {
546 LayoutUnit spaceAdd = LayoutUnit(spaceAvailableThisPass * (child->style()->boxFlex() / totalFlex));
548 child->setOverrideLogicalContentWidth(child->overrideLogicalContentWidth() + spaceAdd);
549 m_flexingChildren = true;
550 relayoutChildren = true;
553 spaceAvailableThisPass -= spaceAdd;
554 remainingSpace -= spaceAdd;
555 groupRemainingSpace -= spaceAdd;
557 totalFlex -= child->style()->boxFlex();
560 if (groupRemainingSpace == groupRemainingSpaceAtBeginning) {
561 // This is not advancing, avoid getting stuck by distributing the remaining pixels.
562 LayoutUnit spaceAdd = groupRemainingSpace > 0 ? 1 : -1;
563 for (RenderBox* child = iterator.first(); child && groupRemainingSpace; child = iterator.next()) {
564 if (allowedChildFlex(child, expanding, i)) {
565 child->setOverrideLogicalContentWidth(child->overrideLogicalContentWidth() + spaceAdd);
566 m_flexingChildren = true;
567 relayoutChildren = true;
568 remainingSpace -= spaceAdd;
569 groupRemainingSpace -= spaceAdd;
573 } while (absoluteValue(groupRemainingSpace) >= 1);
576 // We didn't find any children that could grow.
577 if (haveFlex && !m_flexingChildren)
582 m_flexingChildren = false;
584 RenderBlock::finishDelayUpdateScrollInfo();
586 if (remainingSpace > 0 && ((style()->isLeftToRightDirection() && style()->boxPack() != Start)
587 || (!style()->isLeftToRightDirection() && style()->boxPack() != End))) {
588 // Children must be repositioned.
589 LayoutUnit offset = 0;
590 if (style()->boxPack() == Justify) {
591 // Determine the total number of children.
592 int totalChildren = 0;
593 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
594 if (childDoesNotAffectWidthOrFlexing(child))
599 // Iterate over the children and space them out according to the
600 // justification level.
601 if (totalChildren > 1) {
603 bool firstChild = true;
604 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
605 if (childDoesNotAffectWidthOrFlexing(child))
613 offset += remainingSpace/totalChildren;
614 remainingSpace -= (remainingSpace/totalChildren);
617 placeChild(child, child->location() + LayoutSize(offset, 0));
621 if (style()->boxPack() == Center)
622 offset += remainingSpace / 2;
623 else // END for LTR, START for RTL
624 offset += remainingSpace;
625 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
626 if (childDoesNotAffectWidthOrFlexing(child))
629 placeChild(child, child->location() + LayoutSize(offset, 0));
634 // So that the computeLogicalHeight in layoutBlock() knows to relayout positioned objects because of
635 // a height change, we revert our height back to the intrinsic height before returning.
637 setHeight(oldHeight);
640 void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren)
642 LayoutUnit yPos = borderTop() + paddingTop();
643 LayoutUnit toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
644 bool heightSpecified = false;
645 LayoutUnit oldHeight = 0;
647 LayoutUnit remainingSpace = 0;
649 FlexBoxIterator iterator(this);
650 unsigned int highestFlexGroup = 0;
651 unsigned int lowestFlexGroup = 0;
652 bool haveFlex = false;
653 gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
655 // We confine the line clamp ugliness to vertical flexible boxes (thus keeping it out of
656 // mainstream block layout); this is not really part of the XUL box model.
657 bool haveLineClamp = !style()->lineClamp().isNone();
659 applyLineClamp(iterator, relayoutChildren);
661 RenderBlock::startDelayUpdateScrollInfo();
663 // We do 2 passes. The first pass is simply to lay everyone out at
664 // their preferred widths. The second pass handles flexing the children.
665 // Our first pass is done without flexing. We simply lay the children
666 // out within the box.
668 setHeight(borderTop() + paddingTop());
669 LayoutUnit minHeight = height() + toAdd;
671 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
672 // Make sure we relayout children if we need it.
673 if (!haveLineClamp && (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))))
674 child->setChildNeedsLayout(true, MarkOnlyThis);
676 if (child->isOutOfFlowPositioned()) {
677 child->containingBlock()->insertPositionedObject(child);
678 RenderLayer* childLayer = child->layer();
679 childLayer->setStaticInlinePosition(borderStart() + paddingStart()); // FIXME: Not right for regions.
680 if (childLayer->staticBlockPosition() != height()) {
681 childLayer->setStaticBlockPosition(height());
682 if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
683 child->setChildNeedsLayout(true, MarkOnlyThis);
688 if (child->style()->visibility() == COLLAPSE) {
689 // visibility: collapsed children do not participate in our positioning.
690 // But we need to lay them down.
691 child->layoutIfNeeded();
695 // Compute the child's vertical margins.
696 child->computeBlockDirectionMargins(this);
698 // Add in the child's marginTop to our height.
699 setHeight(height() + child->marginTop());
701 if (!child->needsLayout())
702 child->markForPaginationRelayoutIfNeeded();
705 child->layoutIfNeeded();
707 // We can place the child now, using our value of box-align.
708 LayoutUnit childX = borderLeft() + paddingLeft();
709 switch (style()->boxAlign()) {
711 case BBASELINE: // Baseline just maps to center for vertical boxes
712 childX += child->marginLeft() + max<LayoutUnit>(0, (contentWidth() - (child->width() + child->marginWidth())) / 2);
715 if (!style()->isLeftToRightDirection())
716 childX += child->marginLeft();
718 childX += contentWidth() - child->marginRight() - child->width();
720 default: // BSTART/BSTRETCH
721 if (style()->isLeftToRightDirection())
722 childX += child->marginLeft();
724 childX += contentWidth() - child->marginRight() - child->width();
729 placeChild(child, LayoutPoint(childX, height()));
730 setHeight(height() + child->height() + child->marginBottom());
735 if (!iterator.first() && hasLineIfEmpty())
736 setHeight(height() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
738 setHeight(height() + toAdd);
740 // Negative margins can cause our height to shrink below our minimal height (border/padding).
741 // If this happens, ensure that the computed height is increased to the minimal height.
742 if (height() < minHeight)
743 setHeight(minHeight);
745 // Now we have to calc our height, so we know how much space we have remaining.
746 oldHeight = height();
747 computeLogicalHeight();
748 if (oldHeight != height())
749 heightSpecified = true;
751 remainingSpace = borderTop() + paddingTop() + contentHeight() - yPos;
753 if (m_flexingChildren)
754 haveFlex = false; // We're done.
756 // We have some flexible objects. See if we need to grow/shrink them at all.
760 // Allocate the remaining space among the flexible objects. If we are trying to
761 // grow, then we go from the lowest flex group to the highest flex group. For shrinking,
762 // we go from the highest flex group to the lowest group.
763 bool expanding = remainingSpace > 0;
764 unsigned int start = expanding ? lowestFlexGroup : highestFlexGroup;
765 unsigned int end = expanding? highestFlexGroup : lowestFlexGroup;
766 for (unsigned int i = start; i <= end && remainingSpace; i++) {
767 // Always start off by assuming the group can get all the remaining space.
768 LayoutUnit groupRemainingSpace = remainingSpace;
770 // Flexing consists of multiple passes, since we have to change ratios every time an object hits its max/min-width
771 // For a given pass, we always start off by computing the totalFlex of all objects that can grow/shrink at all, and
772 // computing the allowed growth before an object hits its min/max width (and thus
773 // forces a totalFlex recomputation).
774 LayoutUnit groupRemainingSpaceAtBeginning = groupRemainingSpace;
775 float totalFlex = 0.0f;
776 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
777 if (allowedChildFlex(child, expanding, i))
778 totalFlex += child->style()->boxFlex();
780 LayoutUnit spaceAvailableThisPass = groupRemainingSpace;
781 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
782 LayoutUnit allowedFlex = allowedChildFlex(child, expanding, i);
784 LayoutUnit projectedFlex = (allowedFlex == MAX_LAYOUT_UNIT) ? allowedFlex : static_cast<LayoutUnit>(allowedFlex * (totalFlex / child->style()->boxFlex()));
785 spaceAvailableThisPass = expanding ? min(spaceAvailableThisPass, projectedFlex) : max(spaceAvailableThisPass, projectedFlex);
789 // The flex groups may not have any flexible objects this time around.
790 if (!spaceAvailableThisPass || totalFlex == 0.0f) {
791 // If we just couldn't grow/shrink any more, then it's time to transition to the next flex group.
792 groupRemainingSpace = 0;
796 // Now distribute the space to objects.
797 for (RenderBox* child = iterator.first(); child && spaceAvailableThisPass && totalFlex; child = iterator.next()) {
798 if (allowedChildFlex(child, expanding, i)) {
799 LayoutUnit spaceAdd = static_cast<LayoutUnit>(spaceAvailableThisPass * (child->style()->boxFlex() / totalFlex));
801 child->setOverrideLogicalContentHeight(child->overrideLogicalContentHeight() + spaceAdd);
802 m_flexingChildren = true;
803 relayoutChildren = true;
806 spaceAvailableThisPass -= spaceAdd;
807 remainingSpace -= spaceAdd;
808 groupRemainingSpace -= spaceAdd;
810 totalFlex -= child->style()->boxFlex();
813 if (groupRemainingSpace == groupRemainingSpaceAtBeginning) {
814 // This is not advancing, avoid getting stuck by distributing the remaining pixels.
815 LayoutUnit spaceAdd = groupRemainingSpace > 0 ? 1 : -1;
816 for (RenderBox* child = iterator.first(); child && groupRemainingSpace; child = iterator.next()) {
817 if (allowedChildFlex(child, expanding, i)) {
818 child->setOverrideLogicalContentHeight(child->overrideLogicalContentHeight() + spaceAdd);
819 m_flexingChildren = true;
820 relayoutChildren = true;
821 remainingSpace -= spaceAdd;
822 groupRemainingSpace -= spaceAdd;
826 } while (absoluteValue(groupRemainingSpace) >= 1);
829 // We didn't find any children that could grow.
830 if (haveFlex && !m_flexingChildren)
835 RenderBlock::finishDelayUpdateScrollInfo();
837 if (style()->boxPack() != Start && remainingSpace > 0) {
838 // Children must be repositioned.
839 LayoutUnit offset = 0;
840 if (style()->boxPack() == Justify) {
841 // Determine the total number of children.
842 int totalChildren = 0;
843 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
844 if (childDoesNotAffectWidthOrFlexing(child))
850 // Iterate over the children and space them out according to the
851 // justification level.
852 if (totalChildren > 1) {
854 bool firstChild = true;
855 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
856 if (childDoesNotAffectWidthOrFlexing(child))
864 offset += remainingSpace/totalChildren;
865 remainingSpace -= (remainingSpace/totalChildren);
867 placeChild(child, child->location() + LayoutSize(0, offset));
871 if (style()->boxPack() == Center)
872 offset += remainingSpace / 2;
874 offset += remainingSpace;
875 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
876 if (childDoesNotAffectWidthOrFlexing(child))
878 placeChild(child, child->location() + LayoutSize(0, offset));
883 // So that the computeLogicalHeight in layoutBlock() knows to relayout positioned objects because of
884 // a height change, we revert our height back to the intrinsic height before returning.
886 setHeight(oldHeight);
889 void RenderDeprecatedFlexibleBox::applyLineClamp(FlexBoxIterator& iterator, bool relayoutChildren)
891 int maxLineCount = 0;
892 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
893 if (childDoesNotAffectWidthOrFlexing(child))
896 if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))
897 || (child->style()->height().isAuto() && child->isBlockFlow())) {
898 child->setChildNeedsLayout(true, MarkOnlyThis);
900 // Dirty all the positioned objects.
901 if (child->isRenderBlock()) {
902 toRenderBlock(child)->markPositionedObjectsForLayout();
903 toRenderBlock(child)->clearTruncation();
906 child->layoutIfNeeded();
907 if (child->style()->height().isAuto() && child->isBlockFlow())
908 maxLineCount = max(maxLineCount, toRenderBlock(child)->lineCount());
911 // Get the number of lines and then alter all block flow children with auto height to use the
912 // specified height. We always try to leave room for at least one line.
913 LineClampValue lineClamp = style()->lineClamp();
914 int numVisibleLines = lineClamp.isPercentage() ? max(1, (maxLineCount + 1) * lineClamp.value() / 100) : lineClamp.value();
915 if (numVisibleLines >= maxLineCount)
918 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
919 if (childDoesNotAffectWidthOrFlexing(child) || !child->style()->height().isAuto() || !child->isBlockFlow())
922 RenderBlock* blockChild = toRenderBlock(child);
923 int lineCount = blockChild->lineCount();
924 if (lineCount <= numVisibleLines)
927 LayoutUnit newHeight = blockChild->heightForLineCount(numVisibleLines);
928 if (newHeight == child->height())
931 child->setChildNeedsLayout(true, MarkOnlyThis);
932 child->setOverrideLogicalContentHeight(newHeight - child->borderAndPaddingHeight());
933 m_flexingChildren = true;
934 child->layoutIfNeeded();
935 m_flexingChildren = false;
936 child->clearOverrideSize();
938 // FIXME: For now don't support RTL.
939 if (style()->direction() != LTR)
943 RootInlineBox* lastLine = blockChild->lineAtIndex(lineCount - 1);
947 RootInlineBox* lastVisibleLine = blockChild->lineAtIndex(numVisibleLines - 1);
948 if (!lastVisibleLine)
951 const UChar ellipsisAndSpace[2] = { horizontalEllipsis, ' ' };
952 DEFINE_STATIC_LOCAL(AtomicString, ellipsisAndSpaceStr, (ellipsisAndSpace, 2));
953 DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
954 const Font& font = style(numVisibleLines == 1)->font();
956 // 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
957 LayoutUnit totalWidth;
958 InlineBox* anchorBox = lastLine->lastChild();
959 if (anchorBox && anchorBox->renderer()->style()->isLink())
960 totalWidth = anchorBox->logicalWidth() + font.width(constructTextRun(this, font, ellipsisAndSpace, 2, style()));
963 totalWidth = font.width(constructTextRun(this, font, &horizontalEllipsis, 1, style()));
966 // See if this width can be accommodated on the last visible line
967 RenderBlock* destBlock = toRenderBlock(lastVisibleLine->renderer());
968 RenderBlock* srcBlock = toRenderBlock(lastLine->renderer());
970 // FIXME: Directions of src/destBlock could be different from our direction and from one another.
971 if (!srcBlock->style()->isLeftToRightDirection())
974 bool leftToRight = destBlock->style()->isLeftToRightDirection();
978 LayoutUnit blockRightEdge = destBlock->logicalRightOffsetForLine(lastVisibleLine->y(), false);
979 LayoutUnit blockLeftEdge = destBlock->logicalLeftOffsetForLine(lastVisibleLine->y(), false);
981 LayoutUnit blockEdge = leftToRight ? blockRightEdge : blockLeftEdge;
982 if (!lastVisibleLine->lineCanAccommodateEllipsis(leftToRight, blockEdge, lastVisibleLine->x() + lastVisibleLine->logicalWidth(), totalWidth))
985 // Let the truncation code kick in.
986 // FIXME: the text alignment should be recomputed after the width changes due to truncation.
987 lastVisibleLine->placeEllipsis(anchorBox ? ellipsisAndSpaceStr : ellipsisStr, leftToRight, blockLeftEdge, blockRightEdge, totalWidth, anchorBox);
988 destBlock->setHasMarkupTruncation(true);
992 void RenderDeprecatedFlexibleBox::clearLineClamp()
994 FlexBoxIterator iterator(this);
995 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
996 if (childDoesNotAffectWidthOrFlexing(child))
999 if ((child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))
1000 || (child->style()->height().isAuto() && child->isBlockFlow())) {
1001 child->setChildNeedsLayout(true);
1003 if (child->isRenderBlock()) {
1004 toRenderBlock(child)->markPositionedObjectsForLayout();
1005 toRenderBlock(child)->clearTruncation();
1011 void RenderDeprecatedFlexibleBox::placeChild(RenderBox* child, const LayoutPoint& location)
1013 LayoutRect oldRect = child->frameRect();
1016 child->setLocation(location);
1018 // If the child moved, we have to repaint it as well as any floating/positioned
1019 // descendants. An exception is if we need a layout. In this case, we know we're going to
1020 // repaint ourselves (and the child) anyway.
1021 if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
1022 child->repaintDuringLayoutIfMoved(oldRect);
1025 LayoutUnit RenderDeprecatedFlexibleBox::allowedChildFlex(RenderBox* child, bool expanding, unsigned int group)
1027 if (childDoesNotAffectWidthOrFlexing(child) || child->style()->boxFlex() == 0.0f || child->style()->boxFlexGroup() != group)
1031 if (isHorizontal()) {
1032 // FIXME: For now just handle fixed values.
1033 LayoutUnit maxWidth = MAX_LAYOUT_UNIT;
1034 LayoutUnit width = child->overrideLogicalContentWidth();
1035 if (!child->style()->maxWidth().isUndefined() && child->style()->maxWidth().isFixed())
1036 maxWidth = child->style()->maxWidth().value();
1037 else if (child->style()->maxWidth().type() == Intrinsic)
1038 maxWidth = child->maxPreferredLogicalWidth();
1039 else if (child->style()->maxWidth().type() == MinIntrinsic)
1040 maxWidth = child->minPreferredLogicalWidth();
1041 if (maxWidth == MAX_LAYOUT_UNIT)
1043 return max<LayoutUnit>(0, maxWidth - width);
1045 // FIXME: For now just handle fixed values.
1046 LayoutUnit maxHeight = MAX_LAYOUT_UNIT;
1047 LayoutUnit height = child->overrideLogicalContentHeight();
1048 if (!child->style()->maxHeight().isUndefined() && child->style()->maxHeight().isFixed())
1049 maxHeight = child->style()->maxHeight().value();
1050 if (maxHeight == MAX_LAYOUT_UNIT)
1052 return max<LayoutUnit>(0, maxHeight - height);
1056 // FIXME: For now just handle fixed values.
1057 if (isHorizontal()) {
1058 LayoutUnit minWidth = child->minPreferredLogicalWidth();
1059 LayoutUnit width = child->overrideLogicalContentWidth();
1060 if (child->style()->minWidth().isFixed())
1061 minWidth = child->style()->minWidth().value();
1062 else if (child->style()->minWidth().type() == Intrinsic)
1063 minWidth = child->maxPreferredLogicalWidth();
1064 else if (child->style()->minWidth().type() == MinIntrinsic)
1065 minWidth = child->minPreferredLogicalWidth();
1066 else if (child->style()->minWidth().type() == Auto)
1069 LayoutUnit allowedShrinkage = min<LayoutUnit>(0, minWidth - width);
1070 return allowedShrinkage;
1072 Length minHeight = child->style()->minHeight();
1073 if (minHeight.isFixed() || minHeight.isAuto()) {
1074 LayoutUnit minHeight = child->style()->minHeight().value();
1075 LayoutUnit height = child->overrideLogicalContentHeight();
1076 LayoutUnit allowedShrinkage = min<LayoutUnit>(0, minHeight - height);
1077 return allowedShrinkage;
1084 const char *RenderDeprecatedFlexibleBox::renderName() const
1087 return "RenderDeprecatedFlexibleBox (floating)";
1088 if (isOutOfFlowPositioned())
1089 return "RenderDeprecatedFlexibleBox (positioned)";
1091 return "RenderDeprecatedFlexibleBox (generated)";
1092 if (isRelPositioned())
1093 return "RenderDeprecatedFlexibleBox (relative positioned)";
1094 return "RenderDeprecatedFlexibleBox";
1097 } // namespace WebCore