Rename isPositioned to isOutOfFlowPositioned for clarity
[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 "LayoutRepainter.h"
29 #include "RenderLayer.h"
30 #include "RenderView.h"
31 #include <wtf/StdLibExtras.h>
32 #include <wtf/unicode/CharacterNames.h>
33
34 using namespace std;
35
36 namespace WebCore {
37
38 class FlexBoxIterator {
39 public:
40     FlexBoxIterator(RenderDeprecatedFlexibleBox* parent)
41         : m_box(parent)
42         , m_largestOrdinal(1)
43     {
44         if (m_box->style()->boxOrient() == HORIZONTAL && !m_box->style()->isLeftToRightDirection())
45             m_forward = m_box->style()->boxDirection() != BNORMAL;
46         else
47             m_forward = m_box->style()->boxDirection() == BNORMAL;
48         if (!m_forward) {
49             // No choice, since we're going backwards, we have to find out the highest ordinal up front.
50             RenderBox* child = m_box->firstChildBox();
51             while (child) {
52                 if (child->style()->boxOrdinalGroup() > m_largestOrdinal)
53                     m_largestOrdinal = child->style()->boxOrdinalGroup();
54                 child = child->nextSiblingBox();
55             }
56         }
57
58         reset();
59     }
60
61     void reset()
62     {
63         m_currentChild = 0;
64         m_ordinalIteration = -1;
65     }
66
67     RenderBox* first()
68     {
69         reset();
70         return next();
71     }
72
73     RenderBox* next()
74     {
75         do {
76             if (!m_currentChild) {
77                 ++m_ordinalIteration;
78
79                 if (!m_ordinalIteration)
80                     m_currentOrdinal = m_forward ? 1 : m_largestOrdinal;
81                 else {
82                     if (m_ordinalIteration >= m_ordinalValues.size() + 1)
83                         return 0;
84
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());
89                     }
90                     m_currentOrdinal = m_forward ? m_sortedOrdinalValues[m_ordinalIteration - 1] : m_sortedOrdinalValues[m_sortedOrdinalValues.size() - m_ordinalIteration];
91                 }
92
93                 m_currentChild = m_forward ? m_box->firstChildBox() : m_box->lastChildBox();
94             } else
95                 m_currentChild = m_forward ? m_currentChild->nextSiblingBox() : m_currentChild->previousSiblingBox();
96
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;
102     }
103
104 private:
105     bool notFirstOrdinalValue()
106     {
107         unsigned int firstOrdinalValue = m_forward ? 1 : m_largestOrdinal;
108         return m_currentOrdinal == firstOrdinalValue && m_currentChild->style()->boxOrdinalGroup() != firstOrdinalValue;
109     }
110
111     RenderDeprecatedFlexibleBox* m_box;
112     RenderBox* m_currentChild;
113     bool m_forward;
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;
119 };
120
121 RenderDeprecatedFlexibleBox::RenderDeprecatedFlexibleBox(Node* node)
122     : RenderBlock(node)
123 {
124     setChildrenInline(false); // All of our children must be block-level
125     m_flexingChildren = m_stretchingChildren = false;
126 }
127
128 RenderDeprecatedFlexibleBox::~RenderDeprecatedFlexibleBox()
129 {
130 }
131
132 static LayoutUnit marginWidthForChild(RenderBox* child)
133 {
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();
144     return margin;
145 }
146
147 static bool childDoesNotAffectWidthOrFlexing(RenderObject* child)
148 {
149     // Positioned children and collapsed children don't affect the min/max width.
150     return child->isOutOfFlowPositioned() || child->style()->visibility() == COLLAPSE;
151 }
152
153 void RenderDeprecatedFlexibleBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
154 {
155     RenderStyle* oldStyle = style();
156     if (oldStyle && !oldStyle->lineClamp().isNone() && newStyle->lineClamp().isNone())
157         clearLineClamp();
158
159     RenderBlock::styleWillChange(diff, newStyle);
160 }
161
162 void RenderDeprecatedFlexibleBox::calcHorizontalPrefWidths()
163 {
164     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
165         if (childDoesNotAffectWidthOrFlexing(child))
166             continue;
167
168         LayoutUnit margin = marginWidthForChild(child);
169         m_minPreferredLogicalWidth += child->minPreferredLogicalWidth() + margin;
170         m_maxPreferredLogicalWidth += child->maxPreferredLogicalWidth() + margin;
171     }
172 }
173
174 void RenderDeprecatedFlexibleBox::calcVerticalPrefWidths()
175 {
176     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
177         if (childDoesNotAffectWidthOrFlexing(child))
178             continue;
179
180         LayoutUnit margin = marginWidthForChild(child);
181         LayoutUnit width = child->minPreferredLogicalWidth() + margin;
182         m_minPreferredLogicalWidth = max(width, m_minPreferredLogicalWidth);
183
184         width = child->maxPreferredLogicalWidth() + margin;
185         m_maxPreferredLogicalWidth = max(width, m_maxPreferredLogicalWidth);
186     }
187 }
188
189 void RenderDeprecatedFlexibleBox::computePreferredLogicalWidths()
190 {
191     ASSERT(preferredLogicalWidthsDirty());
192
193     if (style()->width().isFixed() && style()->width().value() > 0)
194         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeContentBoxLogicalWidth(style()->width().value());
195     else {
196         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
197
198         if (hasMultipleLines() || isVertical())
199             calcVerticalPrefWidths();
200         else
201             calcHorizontalPrefWidths();
202
203         m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
204     }
205
206     if (hasOverflowClip() && style()->overflowY() == OSCROLL) {
207         layer()->setHasVerticalScrollbar(true);
208         LayoutUnit scrollbarWidth = verticalScrollbarWidth();
209         m_maxPreferredLogicalWidth += scrollbarWidth;
210         m_minPreferredLogicalWidth += scrollbarWidth;
211     }
212
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()));
216     }
217
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()));
221     }
222
223     LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
224     m_minPreferredLogicalWidth += borderAndPadding;
225     m_maxPreferredLogicalWidth += borderAndPadding;
226
227     setPreferredLogicalWidthsDirty(false);
228 }
229
230 void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
231 {
232     ASSERT(needsLayout());
233
234     if (!relayoutChildren && simplifiedLayout())
235         return;
236
237     LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
238     LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
239
240     if (inRenderFlowThread()) {
241         // Regions changing widths can force us to relayout our children.
242         if (logicalWidthChangedInRegions())
243             relayoutChildren = true;
244     }
245     computeInitialRegionRangeForBlock();
246
247     LayoutSize previousSize = size();
248
249     computeLogicalWidth();
250     computeLogicalHeight();
251
252     m_overflow.clear();
253
254     if (previousSize != size()
255         || (parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
256         && parent()->style()->boxAlign() == BSTRETCH))
257         relayoutChildren = true;
258
259     setHeight(0);
260
261     m_flexingChildren = m_stretchingChildren = false;
262
263     initMaxMarginValues();
264
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);
271     }
272
273     if (isHorizontal())
274         layoutHorizontalBox(relayoutChildren);
275     else
276         layoutVerticalBox(relayoutChildren);
277
278     LayoutUnit oldClientAfterEdge = clientLogicalBottom();
279     computeLogicalHeight();
280
281     if (previousSize.height() != height())
282         relayoutChildren = true;
283
284     layoutPositionedObjects(relayoutChildren || isRoot());
285
286     computeRegionRangeForBlock();
287
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
291         // together.
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);
304     }
305
306     computeOverflow(oldClientAfterEdge);
307
308     statePusher.pop();
309
310     updateLayerTransform();
311
312     if (view()->layoutState()->pageLogicalHeight())
313         setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(this, logicalTop()));
314
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();
319
320     // Repaint with our new bounds if they are different from our old bounds.
321     repainter.repaintAfterLayout();
322
323     setNeedsLayout(false);
324 }
325
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)
328 {
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);
337             haveFlex = true;
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;
345         }
346     }
347 }
348
349 void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
350 {
351     LayoutUnit toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
352     LayoutUnit yPos = borderTop() + paddingTop();
353     LayoutUnit xPos = borderLeft() + paddingLeft();
354     bool heightSpecified = false;
355     LayoutUnit oldHeight = 0;
356
357     LayoutUnit remainingSpace = 0;
358
359
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);
365
366     RenderBlock::startDelayUpdateScrollInfo();
367
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.
370     do {
371         // Reset our height.
372         setHeight(yPos);
373
374         xPos = borderLeft() + paddingLeft();
375
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);
384
385             if (child->isOutOfFlowPositioned())
386                 continue;
387
388             // Compute the child's vertical margins.
389             child->computeBlockDirectionMargins(this);
390
391             if (!child->needsLayout())
392                 child->markForPaginationRelayoutIfNeeded();
393
394             // Now do the layout.
395             child->layoutIfNeeded();
396
397             // Update our height and overflow height.
398             if (style()->boxAlign() == BBASELINE) {
399                 LayoutUnit ascent = child->firstLineBoxBaseline();
400                 if (ascent == -1)
401                     ascent = child->height() + child->marginBottom();
402                 ascent += child->marginTop();
403                 LayoutUnit descent = (child->height() + child->marginHeight()) - ascent;
404
405                 // Update our maximum ascent.
406                 maxAscent = max(maxAscent, ascent);
407
408                 // Update our maximum descent.
409                 maxDescent = max(maxDescent, descent);
410
411                 // Now update our height.
412                 setHeight(max(yPos + maxAscent + maxDescent, height()));
413             }
414             else
415                 setHeight(max(height(), yPos + child->height() + child->marginHeight()));
416         }
417
418         if (!iterator.first() && hasLineIfEmpty())
419             setHeight(height() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
420
421         setHeight(height() + toAdd);
422
423         oldHeight = height();
424         computeLogicalHeight();
425
426         relayoutChildren = false;
427         if (oldHeight != height())
428             heightSpecified = true;
429
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);
441                 }
442                 continue;
443             }
444             
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();
449                 continue;
450             }
451
452
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.
455             // Now do a layout.
456             LayoutUnit oldChildHeight = child->height();
457             child->computeLogicalHeight();
458             if (oldChildHeight != child->height())
459                 child->setChildNeedsLayout(true, MarkOnlyThis);
460
461             if (!child->needsLayout())
462                 child->markForPaginationRelayoutIfNeeded();
463
464             child->layoutIfNeeded();
465
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()) {
470                 case BCENTER:
471                     childY += child->marginTop() + max<LayoutUnit>(0, (contentHeight() - (child->height() + child->marginHeight())) / 2);
472                     break;
473                 case BBASELINE: {
474                     LayoutUnit ascent = child->firstLineBoxBaseline();
475                     if (ascent == -1)
476                         ascent = child->height() + child->marginBottom();
477                     ascent += child->marginTop();
478                     childY += child->marginTop() + (maxAscent - ascent);
479                     break;
480                 }
481                 case BEND:
482                     childY += contentHeight() - child->marginBottom() - child->height();
483                     break;
484                 default: // BSTART
485                     childY += child->marginTop();
486                     break;
487             }
488
489             placeChild(child, LayoutPoint(xPos, childY));
490
491             xPos += child->width() + child->marginRight();
492         }
493
494         remainingSpace = borderLeft() + paddingLeft() + contentWidth() - xPos;
495
496         m_stretchingChildren = false;
497         if (m_flexingChildren)
498             haveFlex = false; // We're done.
499         else if (haveFlex) {
500             // We have some flexible objects.  See if we need to grow/shrink them at all.
501             if (!remainingSpace)
502                 break;
503
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;
513                 do {
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();
523                     }
524                     LayoutUnit spaceAvailableThisPass = groupRemainingSpace;
525                     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
526                         LayoutUnit allowedFlex = allowedChildFlex(child, expanding, i);
527                         if (allowedFlex) {
528                             LayoutUnit projectedFlex = (allowedFlex == MAX_LAYOUT_UNIT) ? allowedFlex : LayoutUnit(allowedFlex * (totalFlex / child->style()->boxFlex()));
529                             spaceAvailableThisPass = expanding ? min(spaceAvailableThisPass, projectedFlex) : max(spaceAvailableThisPass, projectedFlex);
530                         }
531                     }
532
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;
537                         continue;
538                     }
539
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)
543                             continue;
544
545                         if (allowedChildFlex(child, expanding, i)) {
546                             LayoutUnit spaceAdd = LayoutUnit(spaceAvailableThisPass * (child->style()->boxFlex() / totalFlex));
547                             if (spaceAdd) {
548                                 child->setOverrideLogicalContentWidth(child->overrideLogicalContentWidth() + spaceAdd);
549                                 m_flexingChildren = true;
550                                 relayoutChildren = true;
551                             }
552
553                             spaceAvailableThisPass -= spaceAdd;
554                             remainingSpace -= spaceAdd;
555                             groupRemainingSpace -= spaceAdd;
556
557                             totalFlex -= child->style()->boxFlex();
558                         }
559                     }
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;
570                             }
571                         }
572                     }
573                 } while (absoluteValue(groupRemainingSpace) >= 1);
574             }
575
576             // We didn't find any children that could grow.
577             if (haveFlex && !m_flexingChildren)
578                 haveFlex = false;
579         }
580     } while (haveFlex);
581
582     m_flexingChildren = false;
583
584     RenderBlock::finishDelayUpdateScrollInfo();
585
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))
595                     continue;
596                 ++totalChildren;
597             }
598
599             // Iterate over the children and space them out according to the
600             // justification level.
601             if (totalChildren > 1) {
602                 --totalChildren;
603                 bool firstChild = true;
604                 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
605                     if (childDoesNotAffectWidthOrFlexing(child))
606                         continue;
607
608                     if (firstChild) {
609                         firstChild = false;
610                         continue;
611                     }
612
613                     offset += remainingSpace/totalChildren;
614                     remainingSpace -= (remainingSpace/totalChildren);
615                     --totalChildren;
616
617                     placeChild(child, child->location() + LayoutSize(offset, 0));
618                 }
619             }
620         } else {
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))
627                     continue;
628
629                 placeChild(child, child->location() + LayoutSize(offset, 0));
630             }
631         }
632     }
633
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.
636     if (heightSpecified)
637         setHeight(oldHeight);
638 }
639
640 void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren)
641 {
642     LayoutUnit yPos = borderTop() + paddingTop();
643     LayoutUnit toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
644     bool heightSpecified = false;
645     LayoutUnit oldHeight = 0;
646
647     LayoutUnit remainingSpace = 0;
648
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);
654
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();
658     if (haveLineClamp)
659         applyLineClamp(iterator, relayoutChildren);
660
661     RenderBlock::startDelayUpdateScrollInfo();
662
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.
667     do {
668         setHeight(borderTop() + paddingTop());
669         LayoutUnit minHeight = height() + toAdd;
670
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);
675
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);
684                 }
685                 continue;
686             }
687             
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();
692                 continue;
693             }
694
695             // Compute the child's vertical margins.
696             child->computeBlockDirectionMargins(this);
697
698             // Add in the child's marginTop to our height.
699             setHeight(height() + child->marginTop());
700
701             if (!child->needsLayout())
702                 child->markForPaginationRelayoutIfNeeded();
703
704             // Now do a layout.
705             child->layoutIfNeeded();
706
707             // We can place the child now, using our value of box-align.
708             LayoutUnit childX = borderLeft() + paddingLeft();
709             switch (style()->boxAlign()) {
710                 case BCENTER:
711                 case BBASELINE: // Baseline just maps to center for vertical boxes
712                     childX += child->marginLeft() + max<LayoutUnit>(0, (contentWidth() - (child->width() + child->marginWidth())) / 2);
713                     break;
714                 case BEND:
715                     if (!style()->isLeftToRightDirection())
716                         childX += child->marginLeft();
717                     else
718                         childX += contentWidth() - child->marginRight() - child->width();
719                     break;
720                 default: // BSTART/BSTRETCH
721                     if (style()->isLeftToRightDirection())
722                         childX += child->marginLeft();
723                     else
724                         childX += contentWidth() - child->marginRight() - child->width();
725                     break;
726             }
727
728             // Place the child.
729             placeChild(child, LayoutPoint(childX, height()));
730             setHeight(height() + child->height() + child->marginBottom());
731         }
732
733         yPos = height();
734
735         if (!iterator.first() && hasLineIfEmpty())
736             setHeight(height() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
737
738         setHeight(height() + toAdd);
739
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);
744
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;
750
751         remainingSpace = borderTop() + paddingTop() + contentHeight() - yPos;
752
753         if (m_flexingChildren)
754             haveFlex = false; // We're done.
755         else if (haveFlex) {
756             // We have some flexible objects.  See if we need to grow/shrink them at all.
757             if (!remainingSpace)
758                 break;
759
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;
769                 do {
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();
779                     }
780                     LayoutUnit spaceAvailableThisPass = groupRemainingSpace;
781                     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
782                         LayoutUnit allowedFlex = allowedChildFlex(child, expanding, i);
783                         if (allowedFlex) {
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);
786                         }
787                     }
788
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;
793                         continue;
794                     }
795
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));
800                             if (spaceAdd) {
801                                 child->setOverrideLogicalContentHeight(child->overrideLogicalContentHeight() + spaceAdd);
802                                 m_flexingChildren = true;
803                                 relayoutChildren = true;
804                             }
805
806                             spaceAvailableThisPass -= spaceAdd;
807                             remainingSpace -= spaceAdd;
808                             groupRemainingSpace -= spaceAdd;
809
810                             totalFlex -= child->style()->boxFlex();
811                         }
812                     }
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;
823                             }
824                         }
825                     }
826                 } while (absoluteValue(groupRemainingSpace) >= 1);
827             }
828
829             // We didn't find any children that could grow.
830             if (haveFlex && !m_flexingChildren)
831                 haveFlex = false;
832         }
833     } while (haveFlex);
834
835     RenderBlock::finishDelayUpdateScrollInfo();
836
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))
845                     continue;
846
847                 ++totalChildren;
848             }
849
850             // Iterate over the children and space them out according to the
851             // justification level.
852             if (totalChildren > 1) {
853                 --totalChildren;
854                 bool firstChild = true;
855                 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
856                     if (childDoesNotAffectWidthOrFlexing(child))
857                         continue;
858
859                     if (firstChild) {
860                         firstChild = false;
861                         continue;
862                     }
863
864                     offset += remainingSpace/totalChildren;
865                     remainingSpace -= (remainingSpace/totalChildren);
866                     --totalChildren;
867                     placeChild(child, child->location() + LayoutSize(0, offset));
868                 }
869             }
870         } else {
871             if (style()->boxPack() == Center)
872                 offset += remainingSpace / 2;
873             else // END
874                 offset += remainingSpace;
875             for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
876                 if (childDoesNotAffectWidthOrFlexing(child))
877                     continue;
878                 placeChild(child, child->location() + LayoutSize(0, offset));
879             }
880         }
881     }
882
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.
885     if (heightSpecified)
886         setHeight(oldHeight);
887 }
888
889 void RenderDeprecatedFlexibleBox::applyLineClamp(FlexBoxIterator& iterator, bool relayoutChildren)
890 {
891     int maxLineCount = 0;
892     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
893         if (childDoesNotAffectWidthOrFlexing(child))
894             continue;
895
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);
899
900             // Dirty all the positioned objects.
901             if (child->isRenderBlock()) {
902                 toRenderBlock(child)->markPositionedObjectsForLayout();
903                 toRenderBlock(child)->clearTruncation();
904             }
905         }
906         child->layoutIfNeeded();
907         if (child->style()->height().isAuto() && child->isBlockFlow())
908             maxLineCount = max(maxLineCount, toRenderBlock(child)->lineCount());
909     }
910
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)
916         return;
917
918     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
919         if (childDoesNotAffectWidthOrFlexing(child) || !child->style()->height().isAuto() || !child->isBlockFlow())
920             continue;
921
922         RenderBlock* blockChild = toRenderBlock(child);
923         int lineCount = blockChild->lineCount();
924         if (lineCount <= numVisibleLines)
925             continue;
926
927         LayoutUnit newHeight = blockChild->heightForLineCount(numVisibleLines);
928         if (newHeight == child->height())
929             continue;
930
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();
937
938         // FIXME: For now don't support RTL.
939         if (style()->direction() != LTR)
940             continue;
941
942         // Get the last line
943         RootInlineBox* lastLine = blockChild->lineAtIndex(lineCount - 1);
944         if (!lastLine)
945             continue;
946
947         RootInlineBox* lastVisibleLine = blockChild->lineAtIndex(numVisibleLines - 1);
948         if (!lastVisibleLine)
949             continue;
950
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();
955
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()));
961         else {
962             anchorBox = 0;
963             totalWidth = font.width(constructTextRun(this, font, &horizontalEllipsis, 1, style()));
964         }
965
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());
969
970         // FIXME: Directions of src/destBlock could be different from our direction and from one another.
971         if (!srcBlock->style()->isLeftToRightDirection())
972             continue;
973
974         bool leftToRight = destBlock->style()->isLeftToRightDirection();
975         if (!leftToRight)
976             continue;
977
978         LayoutUnit blockRightEdge = destBlock->logicalRightOffsetForLine(lastVisibleLine->y(), false);
979         LayoutUnit blockLeftEdge = destBlock->logicalLeftOffsetForLine(lastVisibleLine->y(), false);
980
981         LayoutUnit blockEdge = leftToRight ? blockRightEdge : blockLeftEdge;
982         if (!lastVisibleLine->lineCanAccommodateEllipsis(leftToRight, blockEdge, lastVisibleLine->x() + lastVisibleLine->logicalWidth(), totalWidth))
983             continue;
984
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);
989     }
990 }
991
992 void RenderDeprecatedFlexibleBox::clearLineClamp()
993 {
994     FlexBoxIterator iterator(this);
995     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
996         if (childDoesNotAffectWidthOrFlexing(child))
997             continue;
998
999         if ((child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))
1000             || (child->style()->height().isAuto() && child->isBlockFlow())) {
1001             child->setChildNeedsLayout(true);
1002
1003             if (child->isRenderBlock()) {
1004                 toRenderBlock(child)->markPositionedObjectsForLayout();
1005                 toRenderBlock(child)->clearTruncation();
1006             }
1007         }
1008     }
1009 }
1010
1011 void RenderDeprecatedFlexibleBox::placeChild(RenderBox* child, const LayoutPoint& location)
1012 {
1013     LayoutRect oldRect = child->frameRect();
1014
1015     // Place the child.
1016     child->setLocation(location);
1017
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);
1023 }
1024
1025 LayoutUnit RenderDeprecatedFlexibleBox::allowedChildFlex(RenderBox* child, bool expanding, unsigned int group)
1026 {
1027     if (childDoesNotAffectWidthOrFlexing(child) || child->style()->boxFlex() == 0.0f || child->style()->boxFlexGroup() != group)
1028         return 0;
1029
1030     if (expanding) {
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)
1042                 return maxWidth;
1043             return max<LayoutUnit>(0, maxWidth - width);
1044         } else {
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)
1051                 return maxHeight;
1052             return max<LayoutUnit>(0, maxHeight - height);
1053         }
1054     }
1055
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
1067         LayoutUnit allowedShrinkage = min<LayoutUnit>(0, minWidth - width);
1068         return allowedShrinkage;
1069     } else {
1070         if (child->style()->minHeight().isFixed()) {
1071             LayoutUnit minHeight = child->style()->minHeight().value();
1072             LayoutUnit height = child->overrideLogicalContentHeight();
1073             LayoutUnit allowedShrinkage = min<LayoutUnit>(0, minHeight - height);
1074             return allowedShrinkage;
1075         }
1076     }
1077
1078     return 0;
1079 }
1080
1081 const char *RenderDeprecatedFlexibleBox::renderName() const
1082 {
1083     if (isFloating())
1084         return "RenderDeprecatedFlexibleBox (floating)";
1085     if (isOutOfFlowPositioned())
1086         return "RenderDeprecatedFlexibleBox (positioned)";
1087     if (isAnonymous())
1088         return "RenderDeprecatedFlexibleBox (generated)";
1089     if (isRelPositioned())
1090         return "RenderDeprecatedFlexibleBox (relative positioned)";
1091     return "RenderDeprecatedFlexibleBox";
1092 }
1093
1094 } // namespace WebCore