RenderFlexibleBox.cpp [plain text]
#include "config.h"
#include "RenderFlexibleBox.h"
#include "CharacterNames.h"
#include "RenderLayer.h"
#include "RenderView.h"
#include <wtf/StdLibExtras.h>
using namespace std;
namespace WebCore {
class FlexBoxIterator {
public:
FlexBoxIterator(RenderFlexibleBox* parent)
{
box = parent;
if (box->style()->boxOrient() == HORIZONTAL && box->style()->direction() == RTL)
forward = box->style()->boxDirection() != BNORMAL;
else
forward = box->style()->boxDirection() == BNORMAL;
lastOrdinal = 1;
if (!forward) {
RenderBox* child = box->firstChildBox();
while (child) {
if (child->style()->boxOrdinalGroup() > lastOrdinal)
lastOrdinal = child->style()->boxOrdinalGroup();
child = child->nextSiblingBox();
}
}
reset();
}
void reset()
{
current = 0;
currentOrdinal = forward ? 0 : lastOrdinal+1;
}
RenderBox* first()
{
reset();
return next();
}
RenderBox* next()
{
do {
if (!current) {
if (forward) {
currentOrdinal++;
if (currentOrdinal > lastOrdinal)
return 0;
current = box->firstChildBox();
} else {
currentOrdinal--;
if (currentOrdinal == 0)
return 0;
current = box->lastChildBox();
}
}
else
current = forward ? current->nextSiblingBox() : current->previousSiblingBox();
if (current && current->style()->boxOrdinalGroup() > lastOrdinal)
lastOrdinal = current->style()->boxOrdinalGroup();
} while (!current || current->style()->boxOrdinalGroup() != currentOrdinal ||
current->style()->visibility() == COLLAPSE);
return current;
}
private:
RenderFlexibleBox* box;
RenderBox* current;
bool forward;
unsigned int currentOrdinal;
unsigned int lastOrdinal;
};
RenderFlexibleBox::RenderFlexibleBox(Node* node)
:RenderBlock(node)
{
setChildrenInline(false); m_flexingChildren = m_stretchingChildren = false;
}
RenderFlexibleBox::~RenderFlexibleBox()
{
}
void RenderFlexibleBox::calcHorizontalPrefWidths()
{
for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
if (child->isPositioned() || child->style()->visibility() == COLLAPSE)
continue;
Length ml = child->style()->marginLeft();
Length mr = child->style()->marginRight();
int margin = 0, marginLeft = 0, marginRight = 0;
if (ml.isFixed())
marginLeft += ml.value();
if (mr.isFixed())
marginRight += mr.value();
margin = marginLeft + marginRight;
m_minPrefWidth += child->minPrefWidth() + margin;
m_maxPrefWidth += child->maxPrefWidth() + margin;
}
}
void RenderFlexibleBox::calcVerticalPrefWidths()
{
for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
if (child->isPositioned() || child->style()->visibility() == COLLAPSE)
continue;
Length ml = child->style()->marginLeft();
Length mr = child->style()->marginRight();
int margin = 0;
if (ml.isFixed())
margin += ml.value();
if (mr.isFixed())
margin += mr.value();
int w = child->minPrefWidth() + margin;
m_minPrefWidth = max(w, m_minPrefWidth);
w = child->maxPrefWidth() + margin;
m_maxPrefWidth = max(w, m_maxPrefWidth);
}
}
void RenderFlexibleBox::calcPrefWidths()
{
ASSERT(prefWidthsDirty());
if (style()->width().isFixed() && style()->width().value() > 0)
m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value());
else {
m_minPrefWidth = m_maxPrefWidth = 0;
if (hasMultipleLines() || isVertical())
calcVerticalPrefWidths();
else
calcHorizontalPrefWidths();
m_maxPrefWidth = max(m_minPrefWidth, m_maxPrefWidth);
}
if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
}
if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
}
int toAdd = borderAndPaddingWidth();
if (hasOverflowClip() && style()->overflowY() == OSCROLL)
toAdd += verticalScrollbarWidth();
m_minPrefWidth += toAdd;
m_maxPrefWidth += toAdd;
setPrefWidthsDirty(false);
}
void RenderFlexibleBox::layoutBlock(bool relayoutChildren)
{
ASSERT(needsLayout());
if (!relayoutChildren && layoutOnlyPositionedObjects())
return;
LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasTransform() || hasReflection());
int previousWidth = width();
int previousHeight = height();
calcWidth();
calcHeight();
m_overflow.clear();
if (previousWidth != width() || previousHeight != height() ||
(parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL &&
parent()->style()->boxAlign() == BSTRETCH))
relayoutChildren = true;
setHeight(0);
m_flexingChildren = m_stretchingChildren = false;
initMaxMarginValues();
if (scrollsOverflow()) {
if (style()->overflowX() == OSCROLL)
layer()->setHasHorizontalScrollbar(true);
if (style()->overflowY() == OSCROLL)
layer()->setHasVerticalScrollbar(true);
}
if (isHorizontal())
layoutHorizontalBox(relayoutChildren);
else
layoutVerticalBox(relayoutChildren);
calcHeight();
if (previousHeight != height())
relayoutChildren = true;
layoutPositionedObjects(relayoutChildren || isRoot());
if (!isFloatingOrPositioned() && height() == 0) {
int pos = maxTopPosMargin();
int neg = maxTopNegMargin();
if (maxBottomPosMargin() > pos)
pos = maxBottomPosMargin();
if (maxBottomNegMargin() > neg)
neg = maxBottomNegMargin();
setMaxTopMargins(pos, neg);
setMaxBottomMargins(0, 0);
}
FlexBoxIterator iterator(this);
for (RenderBox* child = iterator.first(); child; child = iterator.next())
addOverflowFromChild(child);
addShadowOverflow();
statePusher.pop();
if (hasOverflowClip())
layer()->updateScrollInfoAfterLayout();
repainter.repaintAfterLayout();
setNeedsLayout(false);
}
static void gatherFlexChildrenInfo(FlexBoxIterator& iterator, bool relayoutChildren, unsigned int& highestFlexGroup, unsigned int& lowestFlexGroup, bool& haveFlex)
{
RenderBox* child = iterator.first();
while (child) {
if (!child->isPositioned() && child->style()->boxFlex() > 0.0f) {
child->setOverrideSize(-1);
if (!relayoutChildren)
child->setChildNeedsLayout(true, false);
haveFlex = true;
unsigned int flexGroup = child->style()->boxFlexGroup();
if (lowestFlexGroup == 0)
lowestFlexGroup = flexGroup;
if (flexGroup < lowestFlexGroup)
lowestFlexGroup = flexGroup;
if (flexGroup > highestFlexGroup)
highestFlexGroup = flexGroup;
}
child = iterator.next();
}
}
void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
{
int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
int yPos = borderTop() + paddingTop();
int xPos = borderLeft() + paddingLeft();
bool heightSpecified = false;
int oldHeight = 0;
int remainingSpace = 0;
FlexBoxIterator iterator(this);
unsigned int highestFlexGroup = 0;
unsigned int lowestFlexGroup = 0;
bool haveFlex = false;
gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
RenderBox* child;
RenderBlock::startDelayUpdateScrollInfo();
do {
setHeight(yPos);
xPos = borderLeft() + paddingLeft();
int maxAscent = 0, maxDescent = 0;
child = iterator.first();
while (child) {
if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())))
child->setChildNeedsLayout(true, false);
if (child->isPositioned()) {
child = iterator.next();
continue;
}
child->calcVerticalMargins();
child->layoutIfNeeded();
if (style()->boxAlign() == BBASELINE) {
int ascent = child->firstLineBoxBaseline();
if (ascent == -1)
ascent = child->height() + child->marginBottom();
ascent += child->marginTop();
int descent = (child->marginTop() + child->height() + child->marginBottom()) - ascent;
maxAscent = max(maxAscent, ascent);
maxDescent = max(maxDescent, descent);
setHeight(max(yPos + maxAscent + maxDescent, height()));
}
else
setHeight(max(height(), yPos + child->marginTop() + child->height() + child->marginBottom()));
child = iterator.next();
}
if (!iterator.first() && hasLineIfEmpty())
setHeight(height() + lineHeight(true, true));
setHeight(height() + toAdd);
oldHeight = height();
calcHeight();
relayoutChildren = false;
if (oldHeight != height())
heightSpecified = true;
m_stretchingChildren = (style()->boxAlign() == BSTRETCH);
child = iterator.first();
while (child) {
if (child->isPositioned()) {
child->containingBlock()->insertPositionedObject(child);
if (child->style()->hasStaticX()) {
if (style()->direction() == LTR)
child->layer()->setStaticX(xPos);
else child->layer()->setStaticX(width() - xPos);
}
if (child->style()->hasStaticY()) {
RenderLayer* childLayer = child->layer();
if (childLayer->staticY() != yPos) {
child->layer()->setStaticY(yPos);
child->setChildNeedsLayout(true, false);
}
}
child = iterator.next();
continue;
}
int oldChildHeight = child->height();
child->calcHeight();
if (oldChildHeight != child->height())
child->setChildNeedsLayout(true, false);
child->layoutIfNeeded();
xPos += child->marginLeft();
int childY = yPos;
switch (style()->boxAlign()) {
case BCENTER:
childY += child->marginTop() + max(0, (contentHeight() - (child->height() + child->marginTop() + child->marginBottom()))/2);
break;
case BBASELINE: {
int ascent = child->firstLineBoxBaseline();
if (ascent == -1)
ascent = child->height() + child->marginBottom();
ascent += child->marginTop();
childY += child->marginTop() + (maxAscent - ascent);
break;
}
case BEND:
childY += contentHeight() - child->marginBottom() - child->height();
break;
default: childY += child->marginTop();
break;
}
placeChild(child, xPos, childY);
xPos += child->width() + child->marginRight();
child = iterator.next();
}
remainingSpace = borderLeft() + paddingLeft() + contentWidth() - xPos;
m_stretchingChildren = false;
if (m_flexingChildren)
haveFlex = false; else if (haveFlex) {
if (!remainingSpace)
break;
bool expanding = remainingSpace > 0;
unsigned int start = expanding ? lowestFlexGroup : highestFlexGroup;
unsigned int end = expanding? highestFlexGroup : lowestFlexGroup;
for (unsigned int i = start; i <= end && remainingSpace; i++) {
int groupRemainingSpace = remainingSpace;
do {
int groupRemainingSpaceAtBeginning = groupRemainingSpace;
float totalFlex = 0.0f;
child = iterator.first();
while (child) {
if (allowedChildFlex(child, expanding, i))
totalFlex += child->style()->boxFlex();
child = iterator.next();
}
child = iterator.first();
int spaceAvailableThisPass = groupRemainingSpace;
while (child) {
int allowedFlex = allowedChildFlex(child, expanding, i);
if (allowedFlex) {
int projectedFlex = (allowedFlex == INT_MAX) ? allowedFlex : (int)(allowedFlex * (totalFlex / child->style()->boxFlex()));
spaceAvailableThisPass = expanding ? min(spaceAvailableThisPass, projectedFlex) : max(spaceAvailableThisPass, projectedFlex);
}
child = iterator.next();
}
if (!spaceAvailableThisPass || totalFlex == 0.0f) {
groupRemainingSpace = 0;
continue;
}
child = iterator.first();
while (child && spaceAvailableThisPass && totalFlex) {
if (allowedChildFlex(child, expanding, i)) {
int spaceAdd = (int)(spaceAvailableThisPass * (child->style()->boxFlex()/totalFlex));
if (spaceAdd) {
child->setOverrideSize(child->overrideWidth() + spaceAdd);
m_flexingChildren = true;
relayoutChildren = true;
}
spaceAvailableThisPass -= spaceAdd;
remainingSpace -= spaceAdd;
groupRemainingSpace -= spaceAdd;
totalFlex -= child->style()->boxFlex();
}
child = iterator.next();
}
if (groupRemainingSpace == groupRemainingSpaceAtBeginning) {
child = iterator.first();
int spaceAdd = groupRemainingSpace > 0 ? 1 : -1;
while (child && groupRemainingSpace) {
if (allowedChildFlex(child, expanding, i)) {
child->setOverrideSize(child->overrideWidth() + spaceAdd);
m_flexingChildren = true;
relayoutChildren = true;
remainingSpace -= spaceAdd;
groupRemainingSpace -= spaceAdd;
}
child = iterator.next();
}
}
} while (groupRemainingSpace);
}
if (haveFlex && !m_flexingChildren)
haveFlex = false;
}
} while (haveFlex);
m_flexingChildren = false;
RenderBlock::finishDelayUpdateScrollInfo();
if (remainingSpace > 0 && ((style()->direction() == LTR && style()->boxPack() != BSTART) ||
(style()->direction() == RTL && style()->boxPack() != BEND))) {
int offset = 0;
if (style()->boxPack() == BJUSTIFY) {
int totalChildren = 0;
child = iterator.first();
while (child) {
if (child->isPositioned()) {
child = iterator.next();
continue;
}
totalChildren++;
child = iterator.next();
}
if (totalChildren > 1) {
totalChildren--;
bool firstChild = true;
child = iterator.first();
while (child) {
if (child->isPositioned()) {
child = iterator.next();
continue;
}
if (firstChild) {
firstChild = false;
child = iterator.next();
continue;
}
offset += remainingSpace/totalChildren;
remainingSpace -= (remainingSpace/totalChildren);
totalChildren--;
placeChild(child, child->x()+offset, child->y());
child = iterator.next();
}
}
} else {
if (style()->boxPack() == BCENTER)
offset += remainingSpace/2;
else offset += remainingSpace;
child = iterator.first();
while (child) {
if (child->isPositioned()) {
child = iterator.next();
continue;
}
placeChild(child, child->x()+offset, child->y());
child = iterator.next();
}
}
}
if (heightSpecified)
setHeight(oldHeight);
}
void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
{
int xPos = borderLeft() + paddingLeft();
int yPos = borderTop() + paddingTop();
if (style()->direction() == RTL)
xPos = width() - paddingRight() - borderRight();
int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
bool heightSpecified = false;
int oldHeight = 0;
int remainingSpace = 0;
FlexBoxIterator iterator(this);
unsigned int highestFlexGroup = 0;
unsigned int lowestFlexGroup = 0;
bool haveFlex = false;
gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
RenderBox* child;
bool haveLineClamp = !style()->lineClamp().isNone();
if (haveLineClamp) {
int maxLineCount = 0;
child = iterator.first();
while (child) {
if (!child->isPositioned()) {
if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())) ||
(child->style()->height().isAuto() && child->isBlockFlow())) {
child->setChildNeedsLayout(true, false);
if (child->isRenderBlock()) {
toRenderBlock(child)->markPositionedObjectsForLayout();
toRenderBlock(child)->clearTruncation();
}
}
child->layoutIfNeeded();
if (child->style()->height().isAuto() && child->isBlockFlow())
maxLineCount = max(maxLineCount, toRenderBlock(child)->lineCount());
}
child = iterator.next();
}
LineClampValue lineClamp = style()->lineClamp();
int numVisibleLines = lineClamp.isPercentage() ? max(1, (maxLineCount + 1) * lineClamp.value() / 100) : lineClamp.value();
if (numVisibleLines < maxLineCount) {
for (child = iterator.first(); child; child = iterator.next()) {
if (child->isPositioned() || !child->style()->height().isAuto() || !child->isBlockFlow())
continue;
RenderBlock* blockChild = toRenderBlock(child);
int lineCount = blockChild->lineCount();
if (lineCount <= numVisibleLines)
continue;
int newHeight = blockChild->heightForLineCount(numVisibleLines);
if (newHeight == child->height())
continue;
child->setChildNeedsLayout(true, false);
child->setOverrideSize(newHeight);
m_flexingChildren = true;
child->layoutIfNeeded();
m_flexingChildren = false;
child->setOverrideSize(-1);
if (style()->direction() != LTR)
continue;
RootInlineBox* lastLine = blockChild->lineAtIndex(lineCount-1);
if (!lastLine)
continue;
RootInlineBox* lastVisibleLine = blockChild->lineAtIndex(numVisibleLines-1);
if (!lastVisibleLine)
continue;
const UChar ellipsisAndSpace[2] = { horizontalEllipsis, ' ' };
DEFINE_STATIC_LOCAL(AtomicString, ellipsisAndSpaceStr, (ellipsisAndSpace, 2));
DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
const Font& font = style(numVisibleLines == 1)->font();
int totalWidth;
InlineBox* anchorBox = lastLine->lastChild();
if (anchorBox && anchorBox->renderer()->node() && anchorBox->renderer()->node()->isLink())
totalWidth = anchorBox->width() + font.width(TextRun(ellipsisAndSpace, 2));
else {
anchorBox = 0;
totalWidth = font.width(TextRun(&horizontalEllipsis, 1));
}
RenderBlock* destBlock = toRenderBlock(lastVisibleLine->renderer());
RenderBlock* srcBlock = toRenderBlock(lastLine->renderer());
if (srcBlock->style()->direction() != LTR)
continue;
if (destBlock->style()->direction() != LTR)
continue;
int ltr = true;
int blockRightEdge = destBlock->rightOffset(lastVisibleLine->y(), false);
int blockLeftEdge = destBlock->leftOffset(lastVisibleLine->y(), false);
int blockEdge = ltr ? blockRightEdge : blockLeftEdge;
if (!lastVisibleLine->canAccommodateEllipsis(ltr, blockEdge,
lastVisibleLine->x() + lastVisibleLine->width(),
totalWidth))
continue;
lastVisibleLine->placeEllipsis(anchorBox ? ellipsisAndSpaceStr : ellipsisStr, ltr, blockLeftEdge, blockRightEdge, totalWidth, anchorBox);
destBlock->setHasMarkupTruncation(true);
}
}
}
RenderBlock::startDelayUpdateScrollInfo();
do {
setHeight(borderTop() + paddingTop());
int minHeight = height() + toAdd;
child = iterator.first();
while (child) {
if (!haveLineClamp && (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))))
child->setChildNeedsLayout(true, false);
if (child->isPositioned()) {
child->containingBlock()->insertPositionedObject(child);
if (child->style()->hasStaticX()) {
if (style()->direction() == LTR)
child->layer()->setStaticX(borderLeft()+paddingLeft());
else
child->layer()->setStaticX(borderRight()+paddingRight());
}
if (child->style()->hasStaticY()) {
RenderLayer* childLayer = child->layer();
if (childLayer->staticY() != height()) {
child->layer()->setStaticY(height());
child->setChildNeedsLayout(true, false);
}
}
child = iterator.next();
continue;
}
child->calcVerticalMargins();
setHeight(height() + child->marginTop());
child->layoutIfNeeded();
int childX = borderLeft() + paddingLeft();
switch (style()->boxAlign()) {
case BCENTER:
case BBASELINE: childX += child->marginLeft() + max(0, (contentWidth() - (child->width() + child->marginLeft() + child->marginRight()))/2);
break;
case BEND:
if (style()->direction() == RTL)
childX += child->marginLeft();
else
childX += contentWidth() - child->marginRight() - child->width();
break;
default: if (style()->direction() == LTR)
childX += child->marginLeft();
else
childX += contentWidth() - child->marginRight() - child->width();
break;
}
placeChild(child, childX, height());
setHeight(height() + child->height() + child->marginBottom());
child = iterator.next();
}
yPos = height();
if (!iterator.first() && hasLineIfEmpty())
setHeight(height() + lineHeight(true, true));
setHeight(height() + toAdd);
if (height() < minHeight)
setHeight(minHeight);
oldHeight = height();
calcHeight();
if (oldHeight != height())
heightSpecified = true;
remainingSpace = borderTop() + paddingTop() + contentHeight() - yPos;
if (m_flexingChildren)
haveFlex = false; else if (haveFlex) {
if (!remainingSpace)
break;
bool expanding = remainingSpace > 0;
unsigned int start = expanding ? lowestFlexGroup : highestFlexGroup;
unsigned int end = expanding? highestFlexGroup : lowestFlexGroup;
for (unsigned int i = start; i <= end && remainingSpace; i++) {
int groupRemainingSpace = remainingSpace;
do {
int groupRemainingSpaceAtBeginning = groupRemainingSpace;
float totalFlex = 0.0f;
child = iterator.first();
while (child) {
if (allowedChildFlex(child, expanding, i))
totalFlex += child->style()->boxFlex();
child = iterator.next();
}
child = iterator.first();
int spaceAvailableThisPass = groupRemainingSpace;
while (child) {
int allowedFlex = allowedChildFlex(child, expanding, i);
if (allowedFlex) {
int projectedFlex = (allowedFlex == INT_MAX) ? allowedFlex : (int)(allowedFlex * (totalFlex / child->style()->boxFlex()));
spaceAvailableThisPass = expanding ? min(spaceAvailableThisPass, projectedFlex) : max(spaceAvailableThisPass, projectedFlex);
}
child = iterator.next();
}
if (!spaceAvailableThisPass || totalFlex == 0.0f) {
groupRemainingSpace = 0;
continue;
}
child = iterator.first();
while (child && spaceAvailableThisPass && totalFlex) {
if (allowedChildFlex(child, expanding, i)) {
int spaceAdd = (int)(spaceAvailableThisPass * (child->style()->boxFlex()/totalFlex));
if (spaceAdd) {
child->setOverrideSize(child->overrideHeight() + spaceAdd);
m_flexingChildren = true;
relayoutChildren = true;
}
spaceAvailableThisPass -= spaceAdd;
remainingSpace -= spaceAdd;
groupRemainingSpace -= spaceAdd;
totalFlex -= child->style()->boxFlex();
}
child = iterator.next();
}
if (groupRemainingSpace == groupRemainingSpaceAtBeginning) {
child = iterator.first();
int spaceAdd = groupRemainingSpace > 0 ? 1 : -1;
while (child && groupRemainingSpace) {
if (allowedChildFlex(child, expanding, i)) {
child->setOverrideSize(child->overrideHeight() + spaceAdd);
m_flexingChildren = true;
relayoutChildren = true;
remainingSpace -= spaceAdd;
groupRemainingSpace -= spaceAdd;
}
child = iterator.next();
}
}
} while (groupRemainingSpace);
}
if (haveFlex && !m_flexingChildren)
haveFlex = false;
}
} while (haveFlex);
RenderBlock::finishDelayUpdateScrollInfo();
if (style()->boxPack() != BSTART && remainingSpace > 0) {
int offset = 0;
if (style()->boxPack() == BJUSTIFY) {
int totalChildren = 0;
child = iterator.first();
while (child) {
if (child->isPositioned()) {
child = iterator.next();
continue;
}
totalChildren++;
child = iterator.next();
}
if (totalChildren > 1) {
totalChildren--;
bool firstChild = true;
child = iterator.first();
while (child) {
if (child->isPositioned()) {
child = iterator.next();
continue;
}
if (firstChild) {
firstChild = false;
child = iterator.next();
continue;
}
offset += remainingSpace/totalChildren;
remainingSpace -= (remainingSpace/totalChildren);
totalChildren--;
placeChild(child, child->x(), child->y()+offset);
child = iterator.next();
}
}
} else {
if (style()->boxPack() == BCENTER)
offset += remainingSpace/2;
else offset += remainingSpace;
child = iterator.first();
while (child) {
if (child->isPositioned()) {
child = iterator.next();
continue;
}
placeChild(child, child->x(), child->y()+offset);
child = iterator.next();
}
}
}
if (heightSpecified)
setHeight(oldHeight);
}
void RenderFlexibleBox::placeChild(RenderBox* child, int x, int y)
{
IntRect oldRect(child->x(), child->y() , child->width(), child->height());
child->setLocation(x, y);
if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
child->repaintDuringLayoutIfMoved(oldRect);
}
int RenderFlexibleBox::allowedChildFlex(RenderBox* child, bool expanding, unsigned int group)
{
if (child->isPositioned() || child->style()->boxFlex() == 0.0f || child->style()->boxFlexGroup() != group)
return 0;
if (expanding) {
if (isHorizontal()) {
int maxW = INT_MAX;
int w = child->overrideWidth() - child->borderAndPaddingWidth();
if (!child->style()->maxWidth().isUndefined() &&
child->style()->maxWidth().isFixed())
maxW = child->style()->maxWidth().value();
else if (child->style()->maxWidth().type() == Intrinsic)
maxW = child->maxPrefWidth();
else if (child->style()->maxWidth().type() == MinIntrinsic)
maxW = child->minPrefWidth();
if (maxW == INT_MAX)
return maxW;
return max(0, maxW - w);
} else {
int maxH = INT_MAX;
int h = child->overrideHeight() - child->borderAndPaddingHeight();
if (!child->style()->maxHeight().isUndefined() &&
child->style()->maxHeight().isFixed())
maxH = child->style()->maxHeight().value();
if (maxH == INT_MAX)
return maxH;
return max(0, maxH - h);
}
}
if (isHorizontal()) {
int minW = child->minPrefWidth();
int w = child->overrideWidth() - child->borderAndPaddingWidth();
if (child->style()->minWidth().isFixed())
minW = child->style()->minWidth().value();
else if (child->style()->minWidth().type() == Intrinsic)
minW = child->maxPrefWidth();
else if (child->style()->minWidth().type() == MinIntrinsic)
minW = child->minPrefWidth();
int allowedShrinkage = min(0, minW - w);
return allowedShrinkage;
} else {
if (child->style()->minHeight().isFixed()) {
int minH = child->style()->minHeight().value();
int h = child->overrideHeight() - child->borderAndPaddingHeight();
int allowedShrinkage = min(0, minH - h);
return allowedShrinkage;
}
}
return 0;
}
const char *RenderFlexibleBox::renderName() const
{
if (isFloating())
return "RenderFlexibleBox (floating)";
if (isPositioned())
return "RenderFlexibleBox (positioned)";
if (isAnonymous())
return "RenderFlexibleBox (generated)";
if (isRelPositioned())
return "RenderFlexibleBox (relative positioned)";
return "RenderFlexibleBox";
}
}