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