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