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