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