2
* This file is part of the render object implementation for KHTML.
4
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5
* (C) 1999 Antti Koivisto (koivisto@kde.org)
6
* Copyright (C) 2003 Apple Computer, Inc.
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.
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.
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.
26
#include "RenderDeprecatedFlexibleBox.h"
29
#include "LayoutRepainter.h"
30
#include "RenderLayer.h"
31
#include "RenderView.h"
32
#include <wtf/StdLibExtras.h>
33
#include <wtf/unicode/CharacterNames.h>
39
class FlexBoxIterator {
41
FlexBoxIterator(RenderDeprecatedFlexibleBox* parent)
45
if (m_box->style()->boxOrient() == HORIZONTAL && !m_box->style()->isLeftToRightDirection())
46
m_forward = m_box->style()->boxDirection() != BNORMAL;
48
m_forward = m_box->style()->boxDirection() == BNORMAL;
50
// No choice, since we're going backwards, we have to find out the highest ordinal up front.
51
RenderBox* child = m_box->firstChildBox();
53
if (child->style()->boxOrdinalGroup() > m_largestOrdinal)
54
m_largestOrdinal = child->style()->boxOrdinalGroup();
55
child = child->nextSiblingBox();
65
m_ordinalIteration = -1;
77
if (!m_currentChild) {
80
if (!m_ordinalIteration)
81
m_currentOrdinal = m_forward ? 1 : m_largestOrdinal;
83
if (m_ordinalIteration >= m_ordinalValues.size() + 1)
86
// Only copy+sort the values once per layout even if the iterator is reset.
87
if (static_cast<size_t>(m_ordinalValues.size()) != m_sortedOrdinalValues.size()) {
88
copyToVector(m_ordinalValues, m_sortedOrdinalValues);
89
sort(m_sortedOrdinalValues.begin(), m_sortedOrdinalValues.end());
91
m_currentOrdinal = m_forward ? m_sortedOrdinalValues[m_ordinalIteration - 1] : m_sortedOrdinalValues[m_sortedOrdinalValues.size() - m_ordinalIteration];
94
m_currentChild = m_forward ? m_box->firstChildBox() : m_box->lastChildBox();
96
m_currentChild = m_forward ? m_currentChild->nextSiblingBox() : m_currentChild->previousSiblingBox();
98
if (m_currentChild && notFirstOrdinalValue())
99
m_ordinalValues.add(m_currentChild->style()->boxOrdinalGroup());
100
} while (!m_currentChild || (!m_currentChild->isAnonymous()
101
&& m_currentChild->style()->boxOrdinalGroup() != m_currentOrdinal));
102
return m_currentChild;
106
bool notFirstOrdinalValue()
108
unsigned int firstOrdinalValue = m_forward ? 1 : m_largestOrdinal;
109
return m_currentOrdinal == firstOrdinalValue && m_currentChild->style()->boxOrdinalGroup() != firstOrdinalValue;
112
RenderDeprecatedFlexibleBox* m_box;
113
RenderBox* m_currentChild;
115
unsigned int m_currentOrdinal;
116
unsigned int m_largestOrdinal;
117
HashSet<unsigned int> m_ordinalValues;
118
Vector<unsigned int> m_sortedOrdinalValues;
119
int m_ordinalIteration;
122
RenderDeprecatedFlexibleBox::RenderDeprecatedFlexibleBox(Node* node)
125
setChildrenInline(false); // All of our children must be block-level
126
m_stretchingChildren = false;
129
RenderDeprecatedFlexibleBox::~RenderDeprecatedFlexibleBox()
133
static LayoutUnit marginWidthForChild(RenderBox* child)
135
// A margin basically has three types: fixed, percentage, and auto (variable).
136
// Auto and percentage margins simply become 0 when computing min/max width.
137
// Fixed margins can be added in as is.
138
Length marginLeft = child->style()->marginLeft();
139
Length marginRight = child->style()->marginRight();
140
LayoutUnit margin = 0;
141
if (marginLeft.isFixed())
142
margin += marginLeft.value();
143
if (marginRight.isFixed())
144
margin += marginRight.value();
148
static bool childDoesNotAffectWidthOrFlexing(RenderObject* child)
150
// Positioned children and collapsed children don't affect the min/max width.
151
return child->isOutOfFlowPositioned() || child->style()->visibility() == COLLAPSE;
154
static LayoutUnit contentWidthForChild(RenderBox* child)
156
if (child->hasOverrideWidth())
157
return child->overrideLogicalContentWidth();
158
return child->logicalWidth() - child->borderAndPaddingLogicalWidth();
161
static LayoutUnit contentHeightForChild(RenderBox* child)
163
if (child->hasOverrideHeight())
164
return child->overrideLogicalContentHeight();
165
return child->logicalHeight() - child->borderAndPaddingLogicalHeight();
168
void RenderDeprecatedFlexibleBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
170
RenderStyle* oldStyle = style();
171
if (oldStyle && !oldStyle->lineClamp().isNone() && newStyle->lineClamp().isNone())
174
RenderBlock::styleWillChange(diff, newStyle);
177
void RenderDeprecatedFlexibleBox::calcHorizontalPrefWidths()
179
for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
180
if (childDoesNotAffectWidthOrFlexing(child))
183
LayoutUnit margin = marginWidthForChild(child);
184
m_minPreferredLogicalWidth += child->minPreferredLogicalWidth() + margin;
185
m_maxPreferredLogicalWidth += child->maxPreferredLogicalWidth() + margin;
189
void RenderDeprecatedFlexibleBox::calcVerticalPrefWidths()
191
for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
192
if (childDoesNotAffectWidthOrFlexing(child))
195
LayoutUnit margin = marginWidthForChild(child);
196
LayoutUnit width = child->minPreferredLogicalWidth() + margin;
197
m_minPreferredLogicalWidth = max(width, m_minPreferredLogicalWidth);
199
width = child->maxPreferredLogicalWidth() + margin;
200
m_maxPreferredLogicalWidth = max(width, m_maxPreferredLogicalWidth);
204
void RenderDeprecatedFlexibleBox::computePreferredLogicalWidths()
206
ASSERT(preferredLogicalWidthsDirty());
208
if (style()->width().isFixed() && style()->width().value() > 0)
209
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->width().value());
211
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
213
if (hasMultipleLines() || isVertical())
214
calcVerticalPrefWidths();
216
calcHorizontalPrefWidths();
218
m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
221
if (hasOverflowClip() && style()->overflowY() == OSCROLL) {
222
layer()->setHasVerticalScrollbar(true);
223
LayoutUnit scrollbarWidth = verticalScrollbarWidth();
224
m_maxPreferredLogicalWidth += scrollbarWidth;
225
m_minPreferredLogicalWidth += scrollbarWidth;
228
if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
229
m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
230
m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
233
if (style()->maxWidth().isFixed()) {
234
m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
235
m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
238
LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
239
m_minPreferredLogicalWidth += borderAndPadding;
240
m_maxPreferredLogicalWidth += borderAndPadding;
242
setPreferredLogicalWidthsDirty(false);
245
void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
247
ASSERT(needsLayout());
249
if (!relayoutChildren && simplifiedLayout())
252
LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
253
LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
255
if (inRenderFlowThread()) {
256
// Regions changing widths can force us to relayout our children.
257
if (logicalWidthChangedInRegions())
258
relayoutChildren = true;
260
updateRegionsAndExclusionsLogicalSize();
262
LayoutSize previousSize = size();
264
updateLogicalWidth();
265
updateLogicalHeight();
269
if (previousSize != size()
270
|| (parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
271
&& parent()->style()->boxAlign() == BSTRETCH))
272
relayoutChildren = true;
276
m_stretchingChildren = false;
278
initMaxMarginValues();
281
layoutHorizontalBox(relayoutChildren);
283
layoutVerticalBox(relayoutChildren);
285
LayoutUnit oldClientAfterEdge = clientLogicalBottom();
286
updateLogicalHeight();
288
if (previousSize.height() != height())
289
relayoutChildren = true;
291
layoutPositionedObjects(relayoutChildren || isRoot());
293
computeRegionRangeForBlock();
295
if (!isFloatingOrOutOfFlowPositioned() && height() == 0) {
296
// We are a block with no border and padding and a computed height
297
// of 0. The CSS spec states that zero-height blocks collapse their margins
299
// When blocks are self-collapsing, we just use the top margin values and set the
300
// bottom margin max values to 0. This way we don't factor in the values
301
// twice when we collapse with our previous vertically adjacent and
302
// following vertically adjacent blocks.
303
LayoutUnit pos = maxPositiveMarginBefore();
304
LayoutUnit neg = maxNegativeMarginBefore();
305
if (maxPositiveMarginAfter() > pos)
306
pos = maxPositiveMarginAfter();
307
if (maxNegativeMarginAfter() > neg)
308
neg = maxNegativeMarginAfter();
309
setMaxMarginBeforeValues(pos, neg);
310
setMaxMarginAfterValues(0, 0);
313
computeOverflow(oldClientAfterEdge);
317
updateLayerTransform();
319
if (view()->layoutState()->pageLogicalHeight())
320
setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(this, logicalTop()));
322
// Update our scrollbars if we're overflow:auto/scroll/hidden now that we know if
323
// we overflow or not.
324
if (hasOverflowClip())
325
layer()->updateScrollInfoAfterLayout();
327
// Repaint with our new bounds if they are different from our old bounds.
328
repainter.repaintAfterLayout();
330
setNeedsLayout(false);
333
// The first walk over our kids is to find out if we have any flexible children.
334
static void gatherFlexChildrenInfo(FlexBoxIterator& iterator, bool relayoutChildren, unsigned int& highestFlexGroup, unsigned int& lowestFlexGroup, bool& haveFlex)
336
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
337
// Check to see if this child flexes.
338
if (!childDoesNotAffectWidthOrFlexing(child) && child->style()->boxFlex() > 0.0f) {
339
// We always have to lay out flexible objects again, since the flex distribution
340
// may have changed, and we need to reallocate space.
341
child->clearOverrideSize();
342
if (!relayoutChildren)
343
child->setChildNeedsLayout(true, MarkOnlyThis);
345
unsigned int flexGroup = child->style()->boxFlexGroup();
346
if (lowestFlexGroup == 0)
347
lowestFlexGroup = flexGroup;
348
if (flexGroup < lowestFlexGroup)
349
lowestFlexGroup = flexGroup;
350
if (flexGroup > highestFlexGroup)
351
highestFlexGroup = flexGroup;
356
void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
358
LayoutUnit toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
359
LayoutUnit yPos = borderTop() + paddingTop();
360
LayoutUnit xPos = borderLeft() + paddingLeft();
361
bool heightSpecified = false;
362
LayoutUnit oldHeight = 0;
364
LayoutUnit remainingSpace = 0;
367
FlexBoxIterator iterator(this);
368
unsigned int highestFlexGroup = 0;
369
unsigned int lowestFlexGroup = 0;
370
bool haveFlex = false, flexingChildren = false;
371
gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
373
RenderBlock::startDelayUpdateScrollInfo();
375
// We do 2 passes. The first pass is simply to lay everyone out at
376
// their preferred widths. The second pass handles flexing the children.
381
xPos = borderLeft() + paddingLeft();
383
// Our first pass is done without flexing. We simply lay the children
384
// out within the box. We have to do a layout first in order to determine
385
// our box's intrinsic height.
386
LayoutUnit maxAscent = 0, maxDescent = 0;
387
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
388
// make sure we relayout children if we need it.
389
if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())))
390
child->setChildNeedsLayout(true, MarkOnlyThis);
392
if (child->isOutOfFlowPositioned())
395
// Compute the child's vertical margins.
396
child->computeAndSetBlockDirectionMargins(this);
398
if (!child->needsLayout())
399
child->markForPaginationRelayoutIfNeeded();
401
// Now do the layout.
402
child->layoutIfNeeded();
404
// Update our height and overflow height.
405
if (style()->boxAlign() == BBASELINE) {
406
LayoutUnit ascent = child->firstLineBoxBaseline();
408
ascent = child->height() + child->marginBottom();
409
ascent += child->marginTop();
410
LayoutUnit descent = (child->height() + child->marginHeight()) - ascent;
412
// Update our maximum ascent.
413
maxAscent = max(maxAscent, ascent);
415
// Update our maximum descent.
416
maxDescent = max(maxDescent, descent);
418
// Now update our height.
419
setHeight(max(yPos + maxAscent + maxDescent, height()));
422
setHeight(max(height(), yPos + child->height() + child->marginHeight()));
425
if (!iterator.first() && hasLineIfEmpty())
426
setHeight(height() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
428
setHeight(height() + toAdd);
430
oldHeight = height();
431
updateLogicalHeight();
433
relayoutChildren = false;
434
if (oldHeight != height())
435
heightSpecified = true;
437
// Now that our height is actually known, we can place our boxes.
438
m_stretchingChildren = (style()->boxAlign() == BSTRETCH);
439
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
440
if (child->isOutOfFlowPositioned()) {
441
child->containingBlock()->insertPositionedObject(child);
442
RenderLayer* childLayer = child->layer();
443
childLayer->setStaticInlinePosition(xPos); // FIXME: Not right for regions.
444
if (childLayer->staticBlockPosition() != yPos) {
445
childLayer->setStaticBlockPosition(yPos);
446
if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
447
child->setChildNeedsLayout(true, MarkOnlyThis);
452
if (child->style()->visibility() == COLLAPSE) {
453
// visibility: collapsed children do not participate in our positioning.
454
// But we need to lay them down.
455
child->layoutIfNeeded();
460
// We need to see if this child's height has changed, since we make block elements
461
// fill the height of a containing box by default.
463
LayoutUnit oldChildHeight = child->height();
464
child->updateLogicalHeight();
465
if (oldChildHeight != child->height())
466
child->setChildNeedsLayout(true, MarkOnlyThis);
468
if (!child->needsLayout())
469
child->markForPaginationRelayoutIfNeeded();
471
child->layoutIfNeeded();
473
// We can place the child now, using our value of box-align.
474
xPos += child->marginLeft();
475
LayoutUnit childY = yPos;
476
switch (style()->boxAlign()) {
478
childY += child->marginTop() + max<LayoutUnit>(0, (contentHeight() - (child->height() + child->marginHeight())) / 2);
481
LayoutUnit ascent = child->firstLineBoxBaseline();
483
ascent = child->height() + child->marginBottom();
484
ascent += child->marginTop();
485
childY += child->marginTop() + (maxAscent - ascent);
489
childY += contentHeight() - child->marginBottom() - child->height();
492
childY += child->marginTop();
496
placeChild(child, LayoutPoint(xPos, childY));
498
xPos += child->width() + child->marginRight();
501
remainingSpace = borderLeft() + paddingLeft() + contentWidth() - xPos;
503
m_stretchingChildren = false;
505
haveFlex = false; // We're done.
507
// We have some flexible objects. See if we need to grow/shrink them at all.
511
// Allocate the remaining space among the flexible objects. If we are trying to
512
// grow, then we go from the lowest flex group to the highest flex group. For shrinking,
513
// we go from the highest flex group to the lowest group.
514
bool expanding = remainingSpace > 0;
515
unsigned int start = expanding ? lowestFlexGroup : highestFlexGroup;
516
unsigned int end = expanding? highestFlexGroup : lowestFlexGroup;
517
for (unsigned int i = start; i <= end && remainingSpace; i++) {
518
// Always start off by assuming the group can get all the remaining space.
519
LayoutUnit groupRemainingSpace = remainingSpace;
521
// Flexing consists of multiple passes, since we have to change ratios every time an object hits its max/min-width
522
// For a given pass, we always start off by computing the totalFlex of all objects that can grow/shrink at all, and
523
// computing the allowed growth before an object hits its min/max width (and thus
524
// forces a totalFlex recomputation).
525
LayoutUnit groupRemainingSpaceAtBeginning = groupRemainingSpace;
526
float totalFlex = 0.0f;
527
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
528
if (allowedChildFlex(child, expanding, i))
529
totalFlex += child->style()->boxFlex();
531
LayoutUnit spaceAvailableThisPass = groupRemainingSpace;
532
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
533
LayoutUnit allowedFlex = allowedChildFlex(child, expanding, i);
535
LayoutUnit projectedFlex = (allowedFlex == LayoutUnit::max()) ? allowedFlex : LayoutUnit(allowedFlex * (totalFlex / child->style()->boxFlex()));
536
spaceAvailableThisPass = expanding ? min(spaceAvailableThisPass, projectedFlex) : max(spaceAvailableThisPass, projectedFlex);
540
// The flex groups may not have any flexible objects this time around.
541
if (!spaceAvailableThisPass || totalFlex == 0.0f) {
542
// If we just couldn't grow/shrink any more, then it's time to transition to the next flex group.
543
groupRemainingSpace = 0;
547
// Now distribute the space to objects.
548
for (RenderBox* child = iterator.first(); child && spaceAvailableThisPass && totalFlex; child = iterator.next()) {
549
if (child->style()->visibility() == COLLAPSE)
552
if (allowedChildFlex(child, expanding, i)) {
553
LayoutUnit spaceAdd = LayoutUnit(spaceAvailableThisPass * (child->style()->boxFlex() / totalFlex));
555
child->setOverrideLogicalContentWidth(contentWidthForChild(child) + spaceAdd);
556
flexingChildren = true;
557
relayoutChildren = true;
560
spaceAvailableThisPass -= spaceAdd;
561
remainingSpace -= spaceAdd;
562
groupRemainingSpace -= spaceAdd;
564
totalFlex -= child->style()->boxFlex();
567
if (groupRemainingSpace == groupRemainingSpaceAtBeginning) {
568
// This is not advancing, avoid getting stuck by distributing the remaining pixels.
569
LayoutUnit spaceAdd = groupRemainingSpace > 0 ? 1 : -1;
570
for (RenderBox* child = iterator.first(); child && groupRemainingSpace; child = iterator.next()) {
571
if (allowedChildFlex(child, expanding, i)) {
572
child->setOverrideLogicalContentWidth(contentWidthForChild(child) + spaceAdd);
573
flexingChildren = true;
574
relayoutChildren = true;
575
remainingSpace -= spaceAdd;
576
groupRemainingSpace -= spaceAdd;
580
} while (absoluteValue(groupRemainingSpace) >= 1);
583
// We didn't find any children that could grow.
584
if (haveFlex && !flexingChildren)
589
RenderBlock::finishDelayUpdateScrollInfo();
591
if (remainingSpace > 0 && ((style()->isLeftToRightDirection() && style()->boxPack() != Start)
592
|| (!style()->isLeftToRightDirection() && style()->boxPack() != End))) {
593
// Children must be repositioned.
594
LayoutUnit offset = 0;
595
if (style()->boxPack() == Justify) {
596
// Determine the total number of children.
597
int totalChildren = 0;
598
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
599
if (childDoesNotAffectWidthOrFlexing(child))
604
// Iterate over the children and space them out according to the
605
// justification level.
606
if (totalChildren > 1) {
608
bool firstChild = true;
609
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
610
if (childDoesNotAffectWidthOrFlexing(child))
618
offset += remainingSpace/totalChildren;
619
remainingSpace -= (remainingSpace/totalChildren);
622
placeChild(child, child->location() + LayoutSize(offset, 0));
626
if (style()->boxPack() == Center)
627
offset += remainingSpace / 2;
628
else // END for LTR, START for RTL
629
offset += remainingSpace;
630
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
631
if (childDoesNotAffectWidthOrFlexing(child))
634
placeChild(child, child->location() + LayoutSize(offset, 0));
639
// So that the computeLogicalHeight in layoutBlock() knows to relayout positioned objects because of
640
// a height change, we revert our height back to the intrinsic height before returning.
642
setHeight(oldHeight);
645
void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren)
647
LayoutUnit yPos = borderTop() + paddingTop();
648
LayoutUnit toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
649
bool heightSpecified = false;
650
LayoutUnit oldHeight = 0;
652
LayoutUnit remainingSpace = 0;
654
FlexBoxIterator iterator(this);
655
unsigned int highestFlexGroup = 0;
656
unsigned int lowestFlexGroup = 0;
657
bool haveFlex = false, flexingChildren = false;
658
gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
660
// We confine the line clamp ugliness to vertical flexible boxes (thus keeping it out of
661
// mainstream block layout); this is not really part of the XUL box model.
662
bool haveLineClamp = !style()->lineClamp().isNone();
664
applyLineClamp(iterator, relayoutChildren);
666
RenderBlock::startDelayUpdateScrollInfo();
668
// We do 2 passes. The first pass is simply to lay everyone out at
669
// their preferred widths. The second pass handles flexing the children.
670
// Our first pass is done without flexing. We simply lay the children
671
// out within the box.
673
setHeight(borderTop() + paddingTop());
674
LayoutUnit minHeight = height() + toAdd;
676
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
677
// Make sure we relayout children if we need it.
678
if (!haveLineClamp && (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))))
679
child->setChildNeedsLayout(true, MarkOnlyThis);
681
if (child->isOutOfFlowPositioned()) {
682
child->containingBlock()->insertPositionedObject(child);
683
RenderLayer* childLayer = child->layer();
684
childLayer->setStaticInlinePosition(borderStart() + paddingStart()); // FIXME: Not right for regions.
685
if (childLayer->staticBlockPosition() != height()) {
686
childLayer->setStaticBlockPosition(height());
687
if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
688
child->setChildNeedsLayout(true, MarkOnlyThis);
693
if (child->style()->visibility() == COLLAPSE) {
694
// visibility: collapsed children do not participate in our positioning.
695
// But we need to lay them down.
696
child->layoutIfNeeded();
700
// Compute the child's vertical margins.
701
child->computeAndSetBlockDirectionMargins(this);
703
// Add in the child's marginTop to our height.
704
setHeight(height() + child->marginTop());
706
if (!child->needsLayout())
707
child->markForPaginationRelayoutIfNeeded();
710
child->layoutIfNeeded();
712
// We can place the child now, using our value of box-align.
713
LayoutUnit childX = borderLeft() + paddingLeft();
714
switch (style()->boxAlign()) {
716
case BBASELINE: // Baseline just maps to center for vertical boxes
717
childX += child->marginLeft() + max<LayoutUnit>(0, (contentWidth() - (child->width() + child->marginWidth())) / 2);
720
if (!style()->isLeftToRightDirection())
721
childX += child->marginLeft();
723
childX += contentWidth() - child->marginRight() - child->width();
725
default: // BSTART/BSTRETCH
726
if (style()->isLeftToRightDirection())
727
childX += child->marginLeft();
729
childX += contentWidth() - child->marginRight() - child->width();
734
placeChild(child, LayoutPoint(childX, height()));
735
setHeight(height() + child->height() + child->marginBottom());
740
if (!iterator.first() && hasLineIfEmpty())
741
setHeight(height() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
743
setHeight(height() + toAdd);
745
// Negative margins can cause our height to shrink below our minimal height (border/padding).
746
// If this happens, ensure that the computed height is increased to the minimal height.
747
if (height() < minHeight)
748
setHeight(minHeight);
750
// Now we have to calc our height, so we know how much space we have remaining.
751
oldHeight = height();
752
updateLogicalHeight();
753
if (oldHeight != height())
754
heightSpecified = true;
756
remainingSpace = borderTop() + paddingTop() + contentHeight() - yPos;
759
haveFlex = false; // We're done.
761
// We have some flexible objects. See if we need to grow/shrink them at all.
765
// Allocate the remaining space among the flexible objects. If we are trying to
766
// grow, then we go from the lowest flex group to the highest flex group. For shrinking,
767
// we go from the highest flex group to the lowest group.
768
bool expanding = remainingSpace > 0;
769
unsigned int start = expanding ? lowestFlexGroup : highestFlexGroup;
770
unsigned int end = expanding? highestFlexGroup : lowestFlexGroup;
771
for (unsigned int i = start; i <= end && remainingSpace; i++) {
772
// Always start off by assuming the group can get all the remaining space.
773
LayoutUnit groupRemainingSpace = remainingSpace;
775
// Flexing consists of multiple passes, since we have to change ratios every time an object hits its max/min-width
776
// For a given pass, we always start off by computing the totalFlex of all objects that can grow/shrink at all, and
777
// computing the allowed growth before an object hits its min/max width (and thus
778
// forces a totalFlex recomputation).
779
LayoutUnit groupRemainingSpaceAtBeginning = groupRemainingSpace;
780
float totalFlex = 0.0f;
781
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
782
if (allowedChildFlex(child, expanding, i))
783
totalFlex += child->style()->boxFlex();
785
LayoutUnit spaceAvailableThisPass = groupRemainingSpace;
786
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
787
LayoutUnit allowedFlex = allowedChildFlex(child, expanding, i);
789
LayoutUnit projectedFlex = (allowedFlex == LayoutUnit::max()) ? allowedFlex : static_cast<LayoutUnit>(allowedFlex * (totalFlex / child->style()->boxFlex()));
790
spaceAvailableThisPass = expanding ? min(spaceAvailableThisPass, projectedFlex) : max(spaceAvailableThisPass, projectedFlex);
794
// The flex groups may not have any flexible objects this time around.
795
if (!spaceAvailableThisPass || totalFlex == 0.0f) {
796
// If we just couldn't grow/shrink any more, then it's time to transition to the next flex group.
797
groupRemainingSpace = 0;
801
// Now distribute the space to objects.
802
for (RenderBox* child = iterator.first(); child && spaceAvailableThisPass && totalFlex; child = iterator.next()) {
803
if (allowedChildFlex(child, expanding, i)) {
804
LayoutUnit spaceAdd = static_cast<LayoutUnit>(spaceAvailableThisPass * (child->style()->boxFlex() / totalFlex));
806
child->setOverrideLogicalContentHeight(contentHeightForChild(child) + spaceAdd);
807
flexingChildren = true;
808
relayoutChildren = true;
811
spaceAvailableThisPass -= spaceAdd;
812
remainingSpace -= spaceAdd;
813
groupRemainingSpace -= spaceAdd;
815
totalFlex -= child->style()->boxFlex();
818
if (groupRemainingSpace == groupRemainingSpaceAtBeginning) {
819
// This is not advancing, avoid getting stuck by distributing the remaining pixels.
820
LayoutUnit spaceAdd = groupRemainingSpace > 0 ? 1 : -1;
821
for (RenderBox* child = iterator.first(); child && groupRemainingSpace; child = iterator.next()) {
822
if (allowedChildFlex(child, expanding, i)) {
823
child->setOverrideLogicalContentHeight(contentHeightForChild(child) + spaceAdd);
824
flexingChildren = true;
825
relayoutChildren = true;
826
remainingSpace -= spaceAdd;
827
groupRemainingSpace -= spaceAdd;
831
} while (absoluteValue(groupRemainingSpace) >= 1);
834
// We didn't find any children that could grow.
835
if (haveFlex && !flexingChildren)
840
RenderBlock::finishDelayUpdateScrollInfo();
842
if (style()->boxPack() != Start && remainingSpace > 0) {
843
// Children must be repositioned.
844
LayoutUnit offset = 0;
845
if (style()->boxPack() == Justify) {
846
// Determine the total number of children.
847
int totalChildren = 0;
848
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
849
if (childDoesNotAffectWidthOrFlexing(child))
855
// Iterate over the children and space them out according to the
856
// justification level.
857
if (totalChildren > 1) {
859
bool firstChild = true;
860
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
861
if (childDoesNotAffectWidthOrFlexing(child))
869
offset += remainingSpace/totalChildren;
870
remainingSpace -= (remainingSpace/totalChildren);
872
placeChild(child, child->location() + LayoutSize(0, offset));
876
if (style()->boxPack() == Center)
877
offset += remainingSpace / 2;
879
offset += remainingSpace;
880
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
881
if (childDoesNotAffectWidthOrFlexing(child))
883
placeChild(child, child->location() + LayoutSize(0, offset));
888
// So that the computeLogicalHeight in layoutBlock() knows to relayout positioned objects because of
889
// a height change, we revert our height back to the intrinsic height before returning.
891
setHeight(oldHeight);
894
void RenderDeprecatedFlexibleBox::applyLineClamp(FlexBoxIterator& iterator, bool relayoutChildren)
896
int maxLineCount = 0;
897
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
898
if (childDoesNotAffectWidthOrFlexing(child))
901
child->clearOverrideSize();
902
if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))
903
|| (child->style()->height().isAuto() && child->isBlockFlow())) {
904
child->setChildNeedsLayout(true, MarkOnlyThis);
906
// Dirty all the positioned objects.
907
if (child->isRenderBlock()) {
908
toRenderBlock(child)->markPositionedObjectsForLayout();
909
toRenderBlock(child)->clearTruncation();
912
child->layoutIfNeeded();
913
if (child->style()->height().isAuto() && child->isBlockFlow())
914
maxLineCount = max(maxLineCount, toRenderBlock(child)->lineCount());
917
// Get the number of lines and then alter all block flow children with auto height to use the
918
// specified height. We always try to leave room for at least one line.
919
LineClampValue lineClamp = style()->lineClamp();
920
int numVisibleLines = lineClamp.isPercentage() ? max(1, (maxLineCount + 1) * lineClamp.value() / 100) : lineClamp.value();
921
if (numVisibleLines >= maxLineCount)
924
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
925
if (childDoesNotAffectWidthOrFlexing(child) || !child->style()->height().isAuto() || !child->isBlockFlow())
928
RenderBlock* blockChild = toRenderBlock(child);
929
int lineCount = blockChild->lineCount();
930
if (lineCount <= numVisibleLines)
933
LayoutUnit newHeight = blockChild->heightForLineCount(numVisibleLines);
934
if (newHeight == child->height())
937
child->setChildNeedsLayout(true, MarkOnlyThis);
938
child->setOverrideLogicalContentHeight(newHeight - child->borderAndPaddingHeight());
939
child->layoutIfNeeded();
941
// FIXME: For now don't support RTL.
942
if (style()->direction() != LTR)
946
RootInlineBox* lastLine = blockChild->lineAtIndex(lineCount - 1);
950
RootInlineBox* lastVisibleLine = blockChild->lineAtIndex(numVisibleLines - 1);
951
if (!lastVisibleLine)
954
const UChar ellipsisAndSpace[2] = { horizontalEllipsis, ' ' };
955
DEFINE_STATIC_LOCAL(AtomicString, ellipsisAndSpaceStr, (ellipsisAndSpace, 2));
956
DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
957
const Font& font = style(numVisibleLines == 1)->font();
959
// 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
960
LayoutUnit totalWidth;
961
InlineBox* anchorBox = lastLine->lastChild();
962
if (anchorBox && anchorBox->renderer()->style()->isLink())
963
totalWidth = anchorBox->logicalWidth() + font.width(constructTextRun(this, font, ellipsisAndSpace, 2, style()));
966
totalWidth = font.width(constructTextRun(this, font, &horizontalEllipsis, 1, style()));
969
// See if this width can be accommodated on the last visible line
970
RenderBlock* destBlock = toRenderBlock(lastVisibleLine->renderer());
971
RenderBlock* srcBlock = toRenderBlock(lastLine->renderer());
973
// FIXME: Directions of src/destBlock could be different from our direction and from one another.
974
if (!srcBlock->style()->isLeftToRightDirection())
977
bool leftToRight = destBlock->style()->isLeftToRightDirection();
981
LayoutUnit blockRightEdge = destBlock->logicalRightOffsetForLine(lastVisibleLine->y(), false);
982
if (!lastVisibleLine->lineCanAccommodateEllipsis(leftToRight, blockRightEdge, lastVisibleLine->x() + lastVisibleLine->logicalWidth(), totalWidth))
985
// Let the truncation code kick in.
986
// FIXME: the text alignment should be recomputed after the width changes due to truncation.
987
LayoutUnit blockLeftEdge = destBlock->logicalLeftOffsetForLine(lastVisibleLine->y(), false);
988
lastVisibleLine->placeEllipsis(anchorBox ? ellipsisAndSpaceStr : ellipsisStr, leftToRight, blockLeftEdge, blockRightEdge, totalWidth, anchorBox);
989
destBlock->setHasMarkupTruncation(true);
993
void RenderDeprecatedFlexibleBox::clearLineClamp()
995
FlexBoxIterator iterator(this);
996
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
997
if (childDoesNotAffectWidthOrFlexing(child))
1000
child->clearOverrideSize();
1001
if ((child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))
1002
|| (child->style()->height().isAuto() && child->isBlockFlow())) {
1003
child->setChildNeedsLayout(true);
1005
if (child->isRenderBlock()) {
1006
toRenderBlock(child)->markPositionedObjectsForLayout();
1007
toRenderBlock(child)->clearTruncation();
1013
void RenderDeprecatedFlexibleBox::placeChild(RenderBox* child, const LayoutPoint& location)
1015
LayoutRect oldRect = child->frameRect();
1018
child->setLocation(location);
1020
// If the child moved, we have to repaint it as well as any floating/positioned
1021
// descendants. An exception is if we need a layout. In this case, we know we're going to
1022
// repaint ourselves (and the child) anyway.
1023
if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
1024
child->repaintDuringLayoutIfMoved(oldRect);
1027
LayoutUnit RenderDeprecatedFlexibleBox::allowedChildFlex(RenderBox* child, bool expanding, unsigned int group)
1029
if (childDoesNotAffectWidthOrFlexing(child) || child->style()->boxFlex() == 0.0f || child->style()->boxFlexGroup() != group)
1033
if (isHorizontal()) {
1034
// FIXME: For now just handle fixed values.
1035
LayoutUnit maxWidth = LayoutUnit::max();
1036
LayoutUnit width = contentWidthForChild(child);
1037
if (!child->style()->maxWidth().isUndefined() && child->style()->maxWidth().isFixed())
1038
maxWidth = child->style()->maxWidth().value();
1039
else if (child->style()->maxWidth().type() == Intrinsic)
1040
maxWidth = child->maxPreferredLogicalWidth();
1041
else if (child->style()->maxWidth().type() == MinIntrinsic)
1042
maxWidth = child->minPreferredLogicalWidth();
1043
if (maxWidth == LayoutUnit::max())
1045
return max<LayoutUnit>(0, maxWidth - width);
1047
// FIXME: For now just handle fixed values.
1048
LayoutUnit maxHeight = LayoutUnit::max();
1049
LayoutUnit height = contentHeightForChild(child);
1050
if (!child->style()->maxHeight().isUndefined() && child->style()->maxHeight().isFixed())
1051
maxHeight = child->style()->maxHeight().value();
1052
if (maxHeight == LayoutUnit::max())
1054
return max<LayoutUnit>(0, maxHeight - height);
1058
// FIXME: For now just handle fixed values.
1059
if (isHorizontal()) {
1060
LayoutUnit minWidth = child->minPreferredLogicalWidth();
1061
LayoutUnit width = contentWidthForChild(child);
1062
if (child->style()->minWidth().isFixed())
1063
minWidth = child->style()->minWidth().value();
1064
else if (child->style()->minWidth().type() == Intrinsic)
1065
minWidth = child->maxPreferredLogicalWidth();
1066
else if (child->style()->minWidth().type() == MinIntrinsic)
1067
minWidth = child->minPreferredLogicalWidth();
1068
else if (child->style()->minWidth().type() == Auto)
1071
LayoutUnit allowedShrinkage = min<LayoutUnit>(0, minWidth - width);
1072
return allowedShrinkage;
1074
Length minHeight = child->style()->minHeight();
1075
if (minHeight.isFixed() || minHeight.isAuto()) {
1076
LayoutUnit minHeight = child->style()->minHeight().value();
1077
LayoutUnit height = contentHeightForChild(child);
1078
LayoutUnit allowedShrinkage = min<LayoutUnit>(0, minHeight - height);
1079
return allowedShrinkage;
1086
const char *RenderDeprecatedFlexibleBox::renderName() const
1089
return "RenderDeprecatedFlexibleBox (floating)";
1090
if (isOutOfFlowPositioned())
1091
return "RenderDeprecatedFlexibleBox (positioned)";
1093
return "RenderDeprecatedFlexibleBox (generated)";
1094
if (isRelPositioned())
1095
return "RenderDeprecatedFlexibleBox (relative positioned)";
1096
return "RenderDeprecatedFlexibleBox";
1099
} // namespace WebCore