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