Setting width overrides intrinsic min-width/max-width on flexboxes and their subclasses
[WebKit-https.git] / Source / WebCore / rendering / RenderDeprecatedFlexibleBox.cpp
1 /*
2  * This file is part of the render object implementation for KHTML.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
6  * Copyright (C) 2003 Apple Computer, Inc.
7  *
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.
12  *
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.
17  *
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.
22  *
23  */
24
25 #include "config.h"
26 #include "RenderDeprecatedFlexibleBox.h"
27
28 #include "Font.h"
29 #include "LayoutRepainter.h"
30 #include "RenderLayer.h"
31 #include "RenderView.h"
32 #include <wtf/StdLibExtras.h>
33 #include <wtf/unicode/CharacterNames.h>
34
35 using namespace std;
36
37 namespace WebCore {
38
39 class FlexBoxIterator {
40 public:
41     FlexBoxIterator(RenderDeprecatedFlexibleBox* parent)
42         : m_box(parent)
43         , m_largestOrdinal(1)
44     {
45         if (m_box->style()->boxOrient() == HORIZONTAL && !m_box->style()->isLeftToRightDirection())
46             m_forward = m_box->style()->boxDirection() != BNORMAL;
47         else
48             m_forward = m_box->style()->boxDirection() == BNORMAL;
49         if (!m_forward) {
50             // No choice, since we're going backwards, we have to find out the highest ordinal up front.
51             RenderBox* child = m_box->firstChildBox();
52             while (child) {
53                 if (child->style()->boxOrdinalGroup() > m_largestOrdinal)
54                     m_largestOrdinal = child->style()->boxOrdinalGroup();
55                 child = child->nextSiblingBox();
56             }
57         }
58
59         reset();
60     }
61
62     void reset()
63     {
64         m_currentChild = 0;
65         m_ordinalIteration = -1;
66     }
67
68     RenderBox* first()
69     {
70         reset();
71         return next();
72     }
73
74     RenderBox* next()
75     {
76         do {
77             if (!m_currentChild) {
78                 ++m_ordinalIteration;
79
80                 if (!m_ordinalIteration)
81                     m_currentOrdinal = m_forward ? 1 : m_largestOrdinal;
82                 else {
83                     if (m_ordinalIteration >= m_ordinalValues.size() + 1)
84                         return 0;
85
86                     // Only copy+sort the values once per layout even if the iterator is reset.
87                     if (static_cast<size_t>(m_ordinalValues.size()) != m_sortedOrdinalValues.size()) {
88                         copyToVector(m_ordinalValues, m_sortedOrdinalValues);
89                         sort(m_sortedOrdinalValues.begin(), m_sortedOrdinalValues.end());
90                     }
91                     m_currentOrdinal = m_forward ? m_sortedOrdinalValues[m_ordinalIteration - 1] : m_sortedOrdinalValues[m_sortedOrdinalValues.size() - m_ordinalIteration];
92                 }
93
94                 m_currentChild = m_forward ? m_box->firstChildBox() : m_box->lastChildBox();
95             } else
96                 m_currentChild = m_forward ? m_currentChild->nextSiblingBox() : m_currentChild->previousSiblingBox();
97
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;
103     }
104
105 private:
106     bool notFirstOrdinalValue()
107     {
108         unsigned int firstOrdinalValue = m_forward ? 1 : m_largestOrdinal;
109         return m_currentOrdinal == firstOrdinalValue && m_currentChild->style()->boxOrdinalGroup() != firstOrdinalValue;
110     }
111
112     RenderDeprecatedFlexibleBox* m_box;
113     RenderBox* m_currentChild;
114     bool m_forward;
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;
120 };
121
122 RenderDeprecatedFlexibleBox::RenderDeprecatedFlexibleBox(Node* node)
123     : RenderBlock(node)
124 {
125     setChildrenInline(false); // All of our children must be block-level
126     m_stretchingChildren = false;
127 }
128
129 RenderDeprecatedFlexibleBox::~RenderDeprecatedFlexibleBox()
130 {
131 }
132
133 static LayoutUnit marginWidthForChild(RenderBox* child)
134 {
135     // A margin basically has three types: fixed, percentage, and auto (variable).
136     // Auto and percentage margins simply become 0 when computing min/max width.
137     // Fixed margins can be added in as is.
138     Length marginLeft = child->style()->marginLeft();
139     Length marginRight = child->style()->marginRight();
140     LayoutUnit margin = 0;
141     if (marginLeft.isFixed())
142         margin += marginLeft.value();
143     if (marginRight.isFixed())
144         margin += marginRight.value();
145     return margin;
146 }
147
148 static bool childDoesNotAffectWidthOrFlexing(RenderObject* child)
149 {
150     // Positioned children and collapsed children don't affect the min/max width.
151     return child->isOutOfFlowPositioned() || child->style()->visibility() == COLLAPSE;
152 }
153
154 static LayoutUnit contentWidthForChild(RenderBox* child)
155 {
156     if (child->hasOverrideWidth())
157         return child->overrideLogicalContentWidth();
158     return child->logicalWidth() - child->borderAndPaddingLogicalWidth();
159 }
160
161 static LayoutUnit contentHeightForChild(RenderBox* child)
162 {
163     if (child->hasOverrideHeight())
164         return child->overrideLogicalContentHeight();
165     return child->logicalHeight() - child->borderAndPaddingLogicalHeight();
166 }
167
168 void RenderDeprecatedFlexibleBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
169 {
170     RenderStyle* oldStyle = style();
171     if (oldStyle && !oldStyle->lineClamp().isNone() && newStyle->lineClamp().isNone())
172         clearLineClamp();
173
174     RenderBlock::styleWillChange(diff, newStyle);
175 }
176
177 void RenderDeprecatedFlexibleBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
178 {
179     if (hasMultipleLines() || isVertical()) {
180         for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
181             if (childDoesNotAffectWidthOrFlexing(child))
182                 continue;
183
184             LayoutUnit margin = marginWidthForChild(child);
185             LayoutUnit width = child->minPreferredLogicalWidth() + margin;
186             minLogicalWidth = max(width, minLogicalWidth);
187
188             width = child->maxPreferredLogicalWidth() + margin;
189             maxLogicalWidth = max(width, maxLogicalWidth);
190         }
191     } else {
192         for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
193             if (childDoesNotAffectWidthOrFlexing(child))
194                 continue;
195
196             LayoutUnit margin = marginWidthForChild(child);
197             minLogicalWidth += child->minPreferredLogicalWidth() + margin;
198             maxLogicalWidth += child->maxPreferredLogicalWidth() + margin;
199         }
200     }
201
202     maxLogicalWidth = max(minLogicalWidth, maxLogicalWidth);
203
204     LayoutUnit scrollbarWidth = instrinsicScrollbarLogicalWidth();
205     maxLogicalWidth += scrollbarWidth;
206     minLogicalWidth += scrollbarWidth;
207 }
208
209 void RenderDeprecatedFlexibleBox::computePreferredLogicalWidths()
210 {
211     ASSERT(preferredLogicalWidthsDirty());
212
213     m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
214     if (style()->width().isFixed() && style()->width().value() > 0)
215         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->width().value());
216     else
217         computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
218
219     if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
220         m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
221         m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
222     }
223
224     if (style()->maxWidth().isFixed()) {
225         m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
226         m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
227     }
228
229     LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
230     m_minPreferredLogicalWidth += borderAndPadding;
231     m_maxPreferredLogicalWidth += borderAndPadding;
232
233     setPreferredLogicalWidthsDirty(false);
234 }
235
236 void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
237 {
238     ASSERT(needsLayout());
239
240     if (!relayoutChildren && simplifiedLayout())
241         return;
242
243     LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
244     LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
245
246     if (inRenderFlowThread()) {
247         // Regions changing widths can force us to relayout our children.
248         if (logicalWidthChangedInRegions())
249             relayoutChildren = true;
250     }
251     updateRegionsAndExclusionsLogicalSize();
252
253     LayoutSize previousSize = size();
254
255     updateLogicalWidth();
256     updateLogicalHeight();
257
258     m_overflow.clear();
259
260     if (previousSize != size()
261         || (parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
262         && parent()->style()->boxAlign() == BSTRETCH))
263         relayoutChildren = true;
264
265     setHeight(0);
266
267     m_stretchingChildren = false;
268
269     initMaxMarginValues();
270
271     if (isHorizontal())
272         layoutHorizontalBox(relayoutChildren);
273     else
274         layoutVerticalBox(relayoutChildren);
275
276     LayoutUnit oldClientAfterEdge = clientLogicalBottom();
277     updateLogicalHeight();
278
279     if (previousSize.height() != height())
280         relayoutChildren = true;
281
282     layoutPositionedObjects(relayoutChildren || isRoot());
283
284     computeRegionRangeForBlock();
285
286     if (!isFloatingOrOutOfFlowPositioned() && height() == 0) {
287         // We are a block with no border and padding and a computed height
288         // of 0.  The CSS spec states that zero-height blocks collapse their margins
289         // together.
290         // When blocks are self-collapsing, we just use the top margin values and set the
291         // bottom margin max values to 0.  This way we don't factor in the values
292         // twice when we collapse with our previous vertically adjacent and
293         // following vertically adjacent blocks.
294         LayoutUnit pos = maxPositiveMarginBefore();
295         LayoutUnit neg = maxNegativeMarginBefore();
296         if (maxPositiveMarginAfter() > pos)
297             pos = maxPositiveMarginAfter();
298         if (maxNegativeMarginAfter() > neg)
299             neg = maxNegativeMarginAfter();
300         setMaxMarginBeforeValues(pos, neg);
301         setMaxMarginAfterValues(0, 0);
302     }
303
304     computeOverflow(oldClientAfterEdge);
305
306     statePusher.pop();
307
308     updateLayerTransform();
309
310     if (view()->layoutState()->pageLogicalHeight())
311         setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(this, logicalTop()));
312
313     // Update our scrollbars if we're overflow:auto/scroll/hidden now that we know if
314     // we overflow or not.
315     if (hasOverflowClip())
316         layer()->updateScrollInfoAfterLayout();
317
318     // Repaint with our new bounds if they are different from our old bounds.
319     repainter.repaintAfterLayout();
320
321     setNeedsLayout(false);
322 }
323
324 // The first walk over our kids is to find out if we have any flexible children.
325 static void gatherFlexChildrenInfo(FlexBoxIterator& iterator, bool relayoutChildren, unsigned int& highestFlexGroup, unsigned int& lowestFlexGroup, bool& haveFlex)
326 {
327     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
328         // Check to see if this child flexes.
329         if (!childDoesNotAffectWidthOrFlexing(child) && child->style()->boxFlex() > 0.0f) {
330             // We always have to lay out flexible objects again, since the flex distribution
331             // may have changed, and we need to reallocate space.
332             child->clearOverrideSize();
333             if (!relayoutChildren)
334                 child->setChildNeedsLayout(true, MarkOnlyThis);
335             haveFlex = true;
336             unsigned int flexGroup = child->style()->boxFlexGroup();
337             if (lowestFlexGroup == 0)
338                 lowestFlexGroup = flexGroup;
339             if (flexGroup < lowestFlexGroup)
340                 lowestFlexGroup = flexGroup;
341             if (flexGroup > highestFlexGroup)
342                 highestFlexGroup = flexGroup;
343         }
344     }
345 }
346
347 void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
348 {
349     LayoutUnit toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
350     LayoutUnit yPos = borderTop() + paddingTop();
351     LayoutUnit xPos = borderLeft() + paddingLeft();
352     bool heightSpecified = false;
353     LayoutUnit oldHeight = 0;
354
355     LayoutUnit remainingSpace = 0;
356
357
358     FlexBoxIterator iterator(this);
359     unsigned int highestFlexGroup = 0;
360     unsigned int lowestFlexGroup = 0;
361     bool haveFlex = false, flexingChildren = false;
362     gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
363
364     RenderBlock::startDelayUpdateScrollInfo();
365
366     // We do 2 passes.  The first pass is simply to lay everyone out at
367     // their preferred widths.  The second pass handles flexing the children.
368     do {
369         // Reset our height.
370         setHeight(yPos);
371
372         xPos = borderLeft() + paddingLeft();
373
374         // Our first pass is done without flexing.  We simply lay the children
375         // out within the box.  We have to do a layout first in order to determine
376         // our box's intrinsic height.
377         LayoutUnit maxAscent = 0, maxDescent = 0;
378         for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
379             // make sure we relayout children if we need it.
380             if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())))
381                 child->setChildNeedsLayout(true, MarkOnlyThis);
382
383             if (child->isOutOfFlowPositioned())
384                 continue;
385
386             // Compute the child's vertical margins.
387             child->computeAndSetBlockDirectionMargins(this);
388
389             if (!child->needsLayout())
390                 child->markForPaginationRelayoutIfNeeded();
391
392             // Now do the layout.
393             child->layoutIfNeeded();
394
395             // Update our height and overflow height.
396             if (style()->boxAlign() == BBASELINE) {
397                 LayoutUnit ascent = child->firstLineBoxBaseline();
398                 if (ascent == -1)
399                     ascent = child->height() + child->marginBottom();
400                 ascent += child->marginTop();
401                 LayoutUnit descent = (child->height() + child->marginHeight()) - ascent;
402
403                 // Update our maximum ascent.
404                 maxAscent = max(maxAscent, ascent);
405
406                 // Update our maximum descent.
407                 maxDescent = max(maxDescent, descent);
408
409                 // Now update our height.
410                 setHeight(max(yPos + maxAscent + maxDescent, height()));
411             }
412             else
413                 setHeight(max(height(), yPos + child->height() + child->marginHeight()));
414         }
415
416         if (!iterator.first() && hasLineIfEmpty())
417             setHeight(height() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
418
419         setHeight(height() + toAdd);
420
421         oldHeight = height();
422         updateLogicalHeight();
423
424         relayoutChildren = false;
425         if (oldHeight != height())
426             heightSpecified = true;
427
428         // Now that our height is actually known, we can place our boxes.
429         m_stretchingChildren = (style()->boxAlign() == BSTRETCH);
430         for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
431             if (child->isOutOfFlowPositioned()) {
432                 child->containingBlock()->insertPositionedObject(child);
433                 RenderLayer* childLayer = child->layer();
434                 childLayer->setStaticInlinePosition(xPos); // FIXME: Not right for regions.
435                 if (childLayer->staticBlockPosition() != yPos) {
436                     childLayer->setStaticBlockPosition(yPos);
437                     if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
438                         child->setChildNeedsLayout(true, MarkOnlyThis);
439                 }
440                 continue;
441             }
442             
443             if (child->style()->visibility() == COLLAPSE) {
444                 // visibility: collapsed children do not participate in our positioning.
445                 // But we need to lay them down.
446                 child->layoutIfNeeded();
447                 continue;
448             }
449
450
451             // We need to see if this child's height has changed, since we make block elements
452             // fill the height of a containing box by default.
453             // Now do a layout.
454             LayoutUnit oldChildHeight = child->height();
455             child->updateLogicalHeight();
456             if (oldChildHeight != child->height())
457                 child->setChildNeedsLayout(true, MarkOnlyThis);
458
459             if (!child->needsLayout())
460                 child->markForPaginationRelayoutIfNeeded();
461
462             child->layoutIfNeeded();
463
464             // We can place the child now, using our value of box-align.
465             xPos += child->marginLeft();
466             LayoutUnit childY = yPos;
467             switch (style()->boxAlign()) {
468                 case BCENTER:
469                     childY += child->marginTop() + max<LayoutUnit>(0, (contentHeight() - (child->height() + child->marginHeight())) / 2);
470                     break;
471                 case BBASELINE: {
472                     LayoutUnit ascent = child->firstLineBoxBaseline();
473                     if (ascent == -1)
474                         ascent = child->height() + child->marginBottom();
475                     ascent += child->marginTop();
476                     childY += child->marginTop() + (maxAscent - ascent);
477                     break;
478                 }
479                 case BEND:
480                     childY += contentHeight() - child->marginBottom() - child->height();
481                     break;
482                 default: // BSTART
483                     childY += child->marginTop();
484                     break;
485             }
486
487             placeChild(child, LayoutPoint(xPos, childY));
488
489             xPos += child->width() + child->marginRight();
490         }
491
492         remainingSpace = borderLeft() + paddingLeft() + contentWidth() - xPos;
493
494         m_stretchingChildren = false;
495         if (flexingChildren)
496             haveFlex = false; // We're done.
497         else if (haveFlex) {
498             // We have some flexible objects.  See if we need to grow/shrink them at all.
499             if (!remainingSpace)
500                 break;
501
502             // Allocate the remaining space among the flexible objects.  If we are trying to
503             // grow, then we go from the lowest flex group to the highest flex group.  For shrinking,
504             // we go from the highest flex group to the lowest group.
505             bool expanding = remainingSpace > 0;
506             unsigned int start = expanding ? lowestFlexGroup : highestFlexGroup;
507             unsigned int end = expanding? highestFlexGroup : lowestFlexGroup;
508             for (unsigned int i = start; i <= end && remainingSpace; i++) {
509                 // Always start off by assuming the group can get all the remaining space.
510                 LayoutUnit groupRemainingSpace = remainingSpace;
511                 do {
512                     // Flexing consists of multiple passes, since we have to change ratios every time an object hits its max/min-width
513                     // For a given pass, we always start off by computing the totalFlex of all objects that can grow/shrink at all, and
514                     // computing the allowed growth before an object hits its min/max width (and thus
515                     // forces a totalFlex recomputation).
516                     LayoutUnit groupRemainingSpaceAtBeginning = groupRemainingSpace;
517                     float totalFlex = 0.0f;
518                     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
519                         if (allowedChildFlex(child, expanding, i))
520                             totalFlex += child->style()->boxFlex();
521                     }
522                     LayoutUnit spaceAvailableThisPass = groupRemainingSpace;
523                     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
524                         LayoutUnit allowedFlex = allowedChildFlex(child, expanding, i);
525                         if (allowedFlex) {
526                             LayoutUnit projectedFlex = (allowedFlex == LayoutUnit::max()) ? allowedFlex : LayoutUnit(allowedFlex * (totalFlex / child->style()->boxFlex()));
527                             spaceAvailableThisPass = expanding ? min(spaceAvailableThisPass, projectedFlex) : max(spaceAvailableThisPass, projectedFlex);
528                         }
529                     }
530
531                     // The flex groups may not have any flexible objects this time around.
532                     if (!spaceAvailableThisPass || totalFlex == 0.0f) {
533                         // If we just couldn't grow/shrink any more, then it's time to transition to the next flex group.
534                         groupRemainingSpace = 0;
535                         continue;
536                     }
537
538                     // Now distribute the space to objects.
539                     for (RenderBox* child = iterator.first(); child && spaceAvailableThisPass && totalFlex; child = iterator.next()) {
540                         if (child->style()->visibility() == COLLAPSE)
541                             continue;
542
543                         if (allowedChildFlex(child, expanding, i)) {
544                             LayoutUnit spaceAdd = LayoutUnit(spaceAvailableThisPass * (child->style()->boxFlex() / totalFlex));
545                             if (spaceAdd) {
546                                 child->setOverrideLogicalContentWidth(contentWidthForChild(child) + spaceAdd);
547                                 flexingChildren = true;
548                                 relayoutChildren = true;
549                             }
550
551                             spaceAvailableThisPass -= spaceAdd;
552                             remainingSpace -= spaceAdd;
553                             groupRemainingSpace -= spaceAdd;
554
555                             totalFlex -= child->style()->boxFlex();
556                         }
557                     }
558                     if (groupRemainingSpace == groupRemainingSpaceAtBeginning) {
559                         // This is not advancing, avoid getting stuck by distributing the remaining pixels.
560                         LayoutUnit spaceAdd = groupRemainingSpace > 0 ? 1 : -1;
561                         for (RenderBox* child = iterator.first(); child && groupRemainingSpace; child = iterator.next()) {
562                             if (allowedChildFlex(child, expanding, i)) {
563                                 child->setOverrideLogicalContentWidth(contentWidthForChild(child) + spaceAdd);
564                                 flexingChildren = true;
565                                 relayoutChildren = true;
566                                 remainingSpace -= spaceAdd;
567                                 groupRemainingSpace -= spaceAdd;
568                             }
569                         }
570                     }
571                 } while (absoluteValue(groupRemainingSpace) >= 1);
572             }
573
574             // We didn't find any children that could grow.
575             if (haveFlex && !flexingChildren)
576                 haveFlex = false;
577         }
578     } while (haveFlex);
579
580     RenderBlock::finishDelayUpdateScrollInfo();
581
582     if (remainingSpace > 0 && ((style()->isLeftToRightDirection() && style()->boxPack() != Start)
583         || (!style()->isLeftToRightDirection() && style()->boxPack() != End))) {
584         // Children must be repositioned.
585         LayoutUnit offset = 0;
586         if (style()->boxPack() == Justify) {
587             // Determine the total number of children.
588             int totalChildren = 0;
589             for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
590                 if (childDoesNotAffectWidthOrFlexing(child))
591                     continue;
592                 ++totalChildren;
593             }
594
595             // Iterate over the children and space them out according to the
596             // justification level.
597             if (totalChildren > 1) {
598                 --totalChildren;
599                 bool firstChild = true;
600                 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
601                     if (childDoesNotAffectWidthOrFlexing(child))
602                         continue;
603
604                     if (firstChild) {
605                         firstChild = false;
606                         continue;
607                     }
608
609                     offset += remainingSpace/totalChildren;
610                     remainingSpace -= (remainingSpace/totalChildren);
611                     --totalChildren;
612
613                     placeChild(child, child->location() + LayoutSize(offset, 0));
614                 }
615             }
616         } else {
617             if (style()->boxPack() == Center)
618                 offset += remainingSpace / 2;
619             else // END for LTR, START for RTL
620                 offset += remainingSpace;
621             for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
622                 if (childDoesNotAffectWidthOrFlexing(child))
623                     continue;
624
625                 placeChild(child, child->location() + LayoutSize(offset, 0));
626             }
627         }
628     }
629
630     // So that the computeLogicalHeight in layoutBlock() knows to relayout positioned objects because of
631     // a height change, we revert our height back to the intrinsic height before returning.
632     if (heightSpecified)
633         setHeight(oldHeight);
634 }
635
636 void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren)
637 {
638     LayoutUnit yPos = borderTop() + paddingTop();
639     LayoutUnit toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
640     bool heightSpecified = false;
641     LayoutUnit oldHeight = 0;
642
643     LayoutUnit remainingSpace = 0;
644
645     FlexBoxIterator iterator(this);
646     unsigned int highestFlexGroup = 0;
647     unsigned int lowestFlexGroup = 0;
648     bool haveFlex = false, flexingChildren = false;
649     gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
650
651     // We confine the line clamp ugliness to vertical flexible boxes (thus keeping it out of
652     // mainstream block layout); this is not really part of the XUL box model.
653     bool haveLineClamp = !style()->lineClamp().isNone();
654     if (haveLineClamp)
655         applyLineClamp(iterator, relayoutChildren);
656
657     RenderBlock::startDelayUpdateScrollInfo();
658
659     // We do 2 passes.  The first pass is simply to lay everyone out at
660     // their preferred widths.  The second pass handles flexing the children.
661     // Our first pass is done without flexing.  We simply lay the children
662     // out within the box.
663     do {
664         setHeight(borderTop() + paddingTop());
665         LayoutUnit minHeight = height() + toAdd;
666
667         for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
668             // Make sure we relayout children if we need it.
669             if (!haveLineClamp && (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))))
670                 child->setChildNeedsLayout(true, MarkOnlyThis);
671
672             if (child->isOutOfFlowPositioned()) {
673                 child->containingBlock()->insertPositionedObject(child);
674                 RenderLayer* childLayer = child->layer();
675                 childLayer->setStaticInlinePosition(borderStart() + paddingStart()); // FIXME: Not right for regions.
676                 if (childLayer->staticBlockPosition() != height()) {
677                     childLayer->setStaticBlockPosition(height());
678                     if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
679                         child->setChildNeedsLayout(true, MarkOnlyThis);
680                 }
681                 continue;
682             }
683             
684             if (child->style()->visibility() == COLLAPSE) {
685                 // visibility: collapsed children do not participate in our positioning.
686                 // But we need to lay them down.
687                 child->layoutIfNeeded();
688                 continue;
689             }
690
691             // Compute the child's vertical margins.
692             child->computeAndSetBlockDirectionMargins(this);
693
694             // Add in the child's marginTop to our height.
695             setHeight(height() + child->marginTop());
696
697             if (!child->needsLayout())
698                 child->markForPaginationRelayoutIfNeeded();
699
700             // Now do a layout.
701             child->layoutIfNeeded();
702
703             // We can place the child now, using our value of box-align.
704             LayoutUnit childX = borderLeft() + paddingLeft();
705             switch (style()->boxAlign()) {
706                 case BCENTER:
707                 case BBASELINE: // Baseline just maps to center for vertical boxes
708                     childX += child->marginLeft() + max<LayoutUnit>(0, (contentWidth() - (child->width() + child->marginWidth())) / 2);
709                     break;
710                 case BEND:
711                     if (!style()->isLeftToRightDirection())
712                         childX += child->marginLeft();
713                     else
714                         childX += contentWidth() - child->marginRight() - child->width();
715                     break;
716                 default: // BSTART/BSTRETCH
717                     if (style()->isLeftToRightDirection())
718                         childX += child->marginLeft();
719                     else
720                         childX += contentWidth() - child->marginRight() - child->width();
721                     break;
722             }
723
724             // Place the child.
725             placeChild(child, LayoutPoint(childX, height()));
726             setHeight(height() + child->height() + child->marginBottom());
727         }
728
729         yPos = height();
730
731         if (!iterator.first() && hasLineIfEmpty())
732             setHeight(height() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
733
734         setHeight(height() + toAdd);
735
736         // Negative margins can cause our height to shrink below our minimal height (border/padding).
737         // If this happens, ensure that the computed height is increased to the minimal height.
738         if (height() < minHeight)
739             setHeight(minHeight);
740
741         // Now we have to calc our height, so we know how much space we have remaining.
742         oldHeight = height();
743         updateLogicalHeight();
744         if (oldHeight != height())
745             heightSpecified = true;
746
747         remainingSpace = borderTop() + paddingTop() + contentHeight() - yPos;
748
749         if (flexingChildren)
750             haveFlex = false; // We're done.
751         else if (haveFlex) {
752             // We have some flexible objects.  See if we need to grow/shrink them at all.
753             if (!remainingSpace)
754                 break;
755
756             // Allocate the remaining space among the flexible objects.  If we are trying to
757             // grow, then we go from the lowest flex group to the highest flex group.  For shrinking,
758             // we go from the highest flex group to the lowest group.
759             bool expanding = remainingSpace > 0;
760             unsigned int start = expanding ? lowestFlexGroup : highestFlexGroup;
761             unsigned int end = expanding? highestFlexGroup : lowestFlexGroup;
762             for (unsigned int i = start; i <= end && remainingSpace; i++) {
763                 // Always start off by assuming the group can get all the remaining space.
764                 LayoutUnit groupRemainingSpace = remainingSpace;
765                 do {
766                     // Flexing consists of multiple passes, since we have to change ratios every time an object hits its max/min-width
767                     // For a given pass, we always start off by computing the totalFlex of all objects that can grow/shrink at all, and
768                     // computing the allowed growth before an object hits its min/max width (and thus
769                     // forces a totalFlex recomputation).
770                     LayoutUnit groupRemainingSpaceAtBeginning = groupRemainingSpace;
771                     float totalFlex = 0.0f;
772                     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
773                         if (allowedChildFlex(child, expanding, i))
774                             totalFlex += child->style()->boxFlex();
775                     }
776                     LayoutUnit spaceAvailableThisPass = groupRemainingSpace;
777                     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
778                         LayoutUnit allowedFlex = allowedChildFlex(child, expanding, i);
779                         if (allowedFlex) {
780                             LayoutUnit projectedFlex = (allowedFlex == LayoutUnit::max()) ? allowedFlex : static_cast<LayoutUnit>(allowedFlex * (totalFlex / child->style()->boxFlex()));
781                             spaceAvailableThisPass = expanding ? min(spaceAvailableThisPass, projectedFlex) : max(spaceAvailableThisPass, projectedFlex);
782                         }
783                     }
784
785                     // The flex groups may not have any flexible objects this time around.
786                     if (!spaceAvailableThisPass || totalFlex == 0.0f) {
787                         // If we just couldn't grow/shrink any more, then it's time to transition to the next flex group.
788                         groupRemainingSpace = 0;
789                         continue;
790                     }
791
792                     // Now distribute the space to objects.
793                     for (RenderBox* child = iterator.first(); child && spaceAvailableThisPass && totalFlex; child = iterator.next()) {
794                         if (allowedChildFlex(child, expanding, i)) {
795                             LayoutUnit spaceAdd = static_cast<LayoutUnit>(spaceAvailableThisPass * (child->style()->boxFlex() / totalFlex));
796                             if (spaceAdd) {
797                                 child->setOverrideLogicalContentHeight(contentHeightForChild(child) + spaceAdd);
798                                 flexingChildren = true;
799                                 relayoutChildren = true;
800                             }
801
802                             spaceAvailableThisPass -= spaceAdd;
803                             remainingSpace -= spaceAdd;
804                             groupRemainingSpace -= spaceAdd;
805
806                             totalFlex -= child->style()->boxFlex();
807                         }
808                     }
809                     if (groupRemainingSpace == groupRemainingSpaceAtBeginning) {
810                         // This is not advancing, avoid getting stuck by distributing the remaining pixels.
811                         LayoutUnit spaceAdd = groupRemainingSpace > 0 ? 1 : -1;
812                         for (RenderBox* child = iterator.first(); child && groupRemainingSpace; child = iterator.next()) {
813                             if (allowedChildFlex(child, expanding, i)) {
814                                 child->setOverrideLogicalContentHeight(contentHeightForChild(child) + spaceAdd);
815                                 flexingChildren = true;
816                                 relayoutChildren = true;
817                                 remainingSpace -= spaceAdd;
818                                 groupRemainingSpace -= spaceAdd;
819                             }
820                         }
821                     }
822                 } while (absoluteValue(groupRemainingSpace) >= 1);
823             }
824
825             // We didn't find any children that could grow.
826             if (haveFlex && !flexingChildren)
827                 haveFlex = false;
828         }
829     } while (haveFlex);
830
831     RenderBlock::finishDelayUpdateScrollInfo();
832
833     if (style()->boxPack() != Start && remainingSpace > 0) {
834         // Children must be repositioned.
835         LayoutUnit offset = 0;
836         if (style()->boxPack() == Justify) {
837             // Determine the total number of children.
838             int totalChildren = 0;
839             for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
840                 if (childDoesNotAffectWidthOrFlexing(child))
841                     continue;
842
843                 ++totalChildren;
844             }
845
846             // Iterate over the children and space them out according to the
847             // justification level.
848             if (totalChildren > 1) {
849                 --totalChildren;
850                 bool firstChild = true;
851                 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
852                     if (childDoesNotAffectWidthOrFlexing(child))
853                         continue;
854
855                     if (firstChild) {
856                         firstChild = false;
857                         continue;
858                     }
859
860                     offset += remainingSpace/totalChildren;
861                     remainingSpace -= (remainingSpace/totalChildren);
862                     --totalChildren;
863                     placeChild(child, child->location() + LayoutSize(0, offset));
864                 }
865             }
866         } else {
867             if (style()->boxPack() == Center)
868                 offset += remainingSpace / 2;
869             else // END
870                 offset += remainingSpace;
871             for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
872                 if (childDoesNotAffectWidthOrFlexing(child))
873                     continue;
874                 placeChild(child, child->location() + LayoutSize(0, offset));
875             }
876         }
877     }
878
879     // So that the computeLogicalHeight in layoutBlock() knows to relayout positioned objects because of
880     // a height change, we revert our height back to the intrinsic height before returning.
881     if (heightSpecified)
882         setHeight(oldHeight);
883 }
884
885 void RenderDeprecatedFlexibleBox::applyLineClamp(FlexBoxIterator& iterator, bool relayoutChildren)
886 {
887     int maxLineCount = 0;
888     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
889         if (childDoesNotAffectWidthOrFlexing(child))
890             continue;
891
892         child->clearOverrideSize();
893         if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))
894             || (child->style()->height().isAuto() && child->isBlockFlow())) {
895             child->setChildNeedsLayout(true, MarkOnlyThis);
896
897             // Dirty all the positioned objects.
898             if (child->isRenderBlock()) {
899                 toRenderBlock(child)->markPositionedObjectsForLayout();
900                 toRenderBlock(child)->clearTruncation();
901             }
902         }
903         child->layoutIfNeeded();
904         if (child->style()->height().isAuto() && child->isBlockFlow())
905             maxLineCount = max(maxLineCount, toRenderBlock(child)->lineCount());
906     }
907
908     // Get the number of lines and then alter all block flow children with auto height to use the
909     // specified height. We always try to leave room for at least one line.
910     LineClampValue lineClamp = style()->lineClamp();
911     int numVisibleLines = lineClamp.isPercentage() ? max(1, (maxLineCount + 1) * lineClamp.value() / 100) : lineClamp.value();
912     if (numVisibleLines >= maxLineCount)
913         return;
914
915     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
916         if (childDoesNotAffectWidthOrFlexing(child) || !child->style()->height().isAuto() || !child->isBlockFlow())
917             continue;
918
919         RenderBlock* blockChild = toRenderBlock(child);
920         int lineCount = blockChild->lineCount();
921         if (lineCount <= numVisibleLines)
922             continue;
923
924         LayoutUnit newHeight = blockChild->heightForLineCount(numVisibleLines);
925         if (newHeight == child->height())
926             continue;
927
928         child->setChildNeedsLayout(true, MarkOnlyThis);
929         child->setOverrideLogicalContentHeight(newHeight - child->borderAndPaddingHeight());
930         child->layoutIfNeeded();
931
932         // FIXME: For now don't support RTL.
933         if (style()->direction() != LTR)
934             continue;
935
936         // Get the last line
937         RootInlineBox* lastLine = blockChild->lineAtIndex(lineCount - 1);
938         if (!lastLine)
939             continue;
940
941         RootInlineBox* lastVisibleLine = blockChild->lineAtIndex(numVisibleLines - 1);
942         if (!lastVisibleLine)
943             continue;
944
945         const UChar ellipsisAndSpace[2] = { horizontalEllipsis, ' ' };
946         DEFINE_STATIC_LOCAL(AtomicString, ellipsisAndSpaceStr, (ellipsisAndSpace, 2));
947         DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
948         const Font& font = style(numVisibleLines == 1)->font();
949
950         // 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
951         LayoutUnit totalWidth;
952         InlineBox* anchorBox = lastLine->lastChild();
953         if (anchorBox && anchorBox->renderer()->style()->isLink())
954             totalWidth = anchorBox->logicalWidth() + font.width(constructTextRun(this, font, ellipsisAndSpace, 2, style()));
955         else {
956             anchorBox = 0;
957             totalWidth = font.width(constructTextRun(this, font, &horizontalEllipsis, 1, style()));
958         }
959
960         // See if this width can be accommodated on the last visible line
961         RenderBlock* destBlock = toRenderBlock(lastVisibleLine->renderer());
962         RenderBlock* srcBlock = toRenderBlock(lastLine->renderer());
963
964         // FIXME: Directions of src/destBlock could be different from our direction and from one another.
965         if (!srcBlock->style()->isLeftToRightDirection())
966             continue;
967
968         bool leftToRight = destBlock->style()->isLeftToRightDirection();
969         if (!leftToRight)
970             continue;
971
972         LayoutUnit blockRightEdge = destBlock->logicalRightOffsetForLine(lastVisibleLine->y(), false);
973         if (!lastVisibleLine->lineCanAccommodateEllipsis(leftToRight, blockRightEdge, lastVisibleLine->x() + lastVisibleLine->logicalWidth(), totalWidth))
974             continue;
975
976         // Let the truncation code kick in.
977         // FIXME: the text alignment should be recomputed after the width changes due to truncation.
978         LayoutUnit blockLeftEdge = destBlock->logicalLeftOffsetForLine(lastVisibleLine->y(), false);
979         lastVisibleLine->placeEllipsis(anchorBox ? ellipsisAndSpaceStr : ellipsisStr, leftToRight, blockLeftEdge, blockRightEdge, totalWidth, anchorBox);
980         destBlock->setHasMarkupTruncation(true);
981     }
982 }
983
984 void RenderDeprecatedFlexibleBox::clearLineClamp()
985 {
986     FlexBoxIterator iterator(this);
987     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
988         if (childDoesNotAffectWidthOrFlexing(child))
989             continue;
990
991         child->clearOverrideSize();
992         if ((child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))
993             || (child->style()->height().isAuto() && child->isBlockFlow())) {
994             child->setChildNeedsLayout(true);
995
996             if (child->isRenderBlock()) {
997                 toRenderBlock(child)->markPositionedObjectsForLayout();
998                 toRenderBlock(child)->clearTruncation();
999             }
1000         }
1001     }
1002 }
1003
1004 void RenderDeprecatedFlexibleBox::placeChild(RenderBox* child, const LayoutPoint& location)
1005 {
1006     LayoutRect oldRect = child->frameRect();
1007
1008     // Place the child.
1009     child->setLocation(location);
1010
1011     // If the child moved, we have to repaint it as well as any floating/positioned
1012     // descendants.  An exception is if we need a layout.  In this case, we know we're going to
1013     // repaint ourselves (and the child) anyway.
1014     if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
1015         child->repaintDuringLayoutIfMoved(oldRect);
1016 }
1017
1018 LayoutUnit RenderDeprecatedFlexibleBox::allowedChildFlex(RenderBox* child, bool expanding, unsigned int group)
1019 {
1020     if (childDoesNotAffectWidthOrFlexing(child) || child->style()->boxFlex() == 0.0f || child->style()->boxFlexGroup() != group)
1021         return 0;
1022
1023     if (expanding) {
1024         if (isHorizontal()) {
1025             // FIXME: For now just handle fixed values.
1026             LayoutUnit maxWidth = LayoutUnit::max();
1027             LayoutUnit width = contentWidthForChild(child);
1028             if (!child->style()->maxWidth().isUndefined() && child->style()->maxWidth().isFixed())
1029                 maxWidth = child->style()->maxWidth().value();
1030             else if (child->style()->maxWidth().type() == Intrinsic)
1031                 maxWidth = child->maxPreferredLogicalWidth();
1032             else if (child->style()->maxWidth().type() == MinIntrinsic)
1033                 maxWidth = child->minPreferredLogicalWidth();
1034             if (maxWidth == LayoutUnit::max())
1035                 return maxWidth;
1036             return max<LayoutUnit>(0, maxWidth - width);
1037         } else {
1038             // FIXME: For now just handle fixed values.
1039             LayoutUnit maxHeight = LayoutUnit::max();
1040             LayoutUnit height = contentHeightForChild(child);
1041             if (!child->style()->maxHeight().isUndefined() && child->style()->maxHeight().isFixed())
1042                 maxHeight = child->style()->maxHeight().value();
1043             if (maxHeight == LayoutUnit::max())
1044                 return maxHeight;
1045             return max<LayoutUnit>(0, maxHeight - height);
1046         }
1047     }
1048
1049     // FIXME: For now just handle fixed values.
1050     if (isHorizontal()) {
1051         LayoutUnit minWidth = child->minPreferredLogicalWidth();
1052         LayoutUnit width = contentWidthForChild(child);
1053         if (child->style()->minWidth().isFixed())
1054             minWidth = child->style()->minWidth().value();
1055         else if (child->style()->minWidth().type() == Intrinsic)
1056             minWidth = child->maxPreferredLogicalWidth();
1057         else if (child->style()->minWidth().type() == MinIntrinsic)
1058             minWidth = child->minPreferredLogicalWidth();
1059         else if (child->style()->minWidth().type() == Auto)
1060             minWidth = 0;
1061
1062         LayoutUnit allowedShrinkage = min<LayoutUnit>(0, minWidth - width);
1063         return allowedShrinkage;
1064     } else {
1065         Length minHeight = child->style()->minHeight();
1066         if (minHeight.isFixed() || minHeight.isAuto()) {
1067             LayoutUnit minHeight = child->style()->minHeight().value();
1068             LayoutUnit height = contentHeightForChild(child);
1069             LayoutUnit allowedShrinkage = min<LayoutUnit>(0, minHeight - height);
1070             return allowedShrinkage;
1071         }
1072     }
1073
1074     return 0;
1075 }
1076
1077 const char* RenderDeprecatedFlexibleBox::renderName() const
1078 {
1079     if (isFloating())
1080         return "RenderDeprecatedFlexibleBox (floating)";
1081     if (isOutOfFlowPositioned())
1082         return "RenderDeprecatedFlexibleBox (positioned)";
1083     // FIXME: Temporary hack while the new generated content system is being implemented.
1084     if (isPseudoElement())
1085         return "RenderDeprecatedFlexibleBox (generated)";
1086     if (isAnonymous())
1087         return "RenderDeprecatedFlexibleBox (generated)";
1088     if (isRelPositioned())
1089         return "RenderDeprecatedFlexibleBox (relative positioned)";
1090     return "RenderDeprecatedFlexibleBox";
1091 }
1092
1093 } // namespace WebCore