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