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