This source file includes following definitions.
- m_largestOrdinal
- reset
- first
- next
- notFirstOrdinalValue
- createAnonymous
- marginWidthForChild
- childDoesNotAffectWidthOrFlexing
- contentWidthForChild
- contentHeightForChild
- styleWillChange
- computeIntrinsicLogicalWidths
- computePreferredLogicalWidths
- layoutBlock
- gatherFlexChildrenInfo
- layoutHorizontalBox
- layoutVerticalBox
- applyLineClamp
- clearLineClamp
- placeChild
- allowedChildFlex
- renderName
#include "config.h"
#include "core/rendering/RenderDeprecatedFlexibleBox.h"
#include "core/frame/UseCounter.h"
#include "core/rendering/LayoutRepainter.h"
#include "core/rendering/RenderLayer.h"
#include "core/rendering/RenderView.h"
#include "platform/fonts/Font.h"
#include "wtf/StdLibExtras.h"
#include "wtf/unicode/CharacterNames.h"
using namespace std;
namespace WebCore {
class FlexBoxIterator {
public:
FlexBoxIterator(RenderDeprecatedFlexibleBox* parent)
: m_box(parent)
, m_largestOrdinal(1)
{
if (m_box->style()->boxOrient() == HORIZONTAL && !m_box->style()->isLeftToRightDirection())
m_forward = m_box->style()->boxDirection() != BNORMAL;
else
m_forward = m_box->style()->boxDirection() == BNORMAL;
if (!m_forward) {
RenderBox* child = m_box->firstChildBox();
while (child) {
if (child->style()->boxOrdinalGroup() > m_largestOrdinal)
m_largestOrdinal = child->style()->boxOrdinalGroup();
child = child->nextSiblingBox();
}
}
reset();
}
void reset()
{
m_currentChild = 0;
m_ordinalIteration = -1;
}
RenderBox* first()
{
reset();
return next();
}
RenderBox* next()
{
do {
if (!m_currentChild) {
++m_ordinalIteration;
if (!m_ordinalIteration)
m_currentOrdinal = m_forward ? 1 : m_largestOrdinal;
else {
if (static_cast<size_t>(m_ordinalIteration) >= m_ordinalValues.size() + 1)
return 0;
if (m_ordinalValues.size() != m_sortedOrdinalValues.size()) {
copyToVector(m_ordinalValues, m_sortedOrdinalValues);
sort(m_sortedOrdinalValues.begin(), m_sortedOrdinalValues.end());
}
m_currentOrdinal = m_forward ? m_sortedOrdinalValues[m_ordinalIteration - 1] : m_sortedOrdinalValues[m_sortedOrdinalValues.size() - m_ordinalIteration];
}
m_currentChild = m_forward ? m_box->firstChildBox() : m_box->lastChildBox();
} else
m_currentChild = m_forward ? m_currentChild->nextSiblingBox() : m_currentChild->previousSiblingBox();
if (m_currentChild && notFirstOrdinalValue())
m_ordinalValues.add(m_currentChild->style()->boxOrdinalGroup());
} while (!m_currentChild || (!m_currentChild->isAnonymous()
&& m_currentChild->style()->boxOrdinalGroup() != m_currentOrdinal));
return m_currentChild;
}
private:
bool notFirstOrdinalValue()
{
unsigned int firstOrdinalValue = m_forward ? 1 : m_largestOrdinal;
return m_currentOrdinal == firstOrdinalValue && m_currentChild->style()->boxOrdinalGroup() != firstOrdinalValue;
}
RenderDeprecatedFlexibleBox* m_box;
RenderBox* m_currentChild;
bool m_forward;
unsigned int m_currentOrdinal;
unsigned int m_largestOrdinal;
HashSet<unsigned int> m_ordinalValues;
Vector<unsigned int> m_sortedOrdinalValues;
int m_ordinalIteration;
};
RenderDeprecatedFlexibleBox::RenderDeprecatedFlexibleBox(Element* element)
: RenderBlock(element)
{
setChildrenInline(false);
m_stretchingChildren = false;
if (!isAnonymous()) {
const KURL& url = document().url();
if (url.protocolIs("chrome"))
UseCounter::count(document(), UseCounter::DeprecatedFlexboxChrome);
else if (url.protocolIs("chrome-extension"))
UseCounter::count(document(), UseCounter::DeprecatedFlexboxChromeExtension);
else
UseCounter::count(document(), UseCounter::DeprecatedFlexboxWebContent);
}
}
RenderDeprecatedFlexibleBox::~RenderDeprecatedFlexibleBox()
{
}
RenderDeprecatedFlexibleBox* RenderDeprecatedFlexibleBox::createAnonymous(Document* document)
{
RenderDeprecatedFlexibleBox* renderer = new RenderDeprecatedFlexibleBox(0);
renderer->setDocumentForAnonymous(document);
return renderer;
}
static LayoutUnit marginWidthForChild(RenderBox* child)
{
Length marginLeft = child->style()->marginLeft();
Length marginRight = child->style()->marginRight();
LayoutUnit margin = 0;
if (marginLeft.isFixed())
margin += marginLeft.value();
if (marginRight.isFixed())
margin += marginRight.value();
return margin;
}
static bool childDoesNotAffectWidthOrFlexing(RenderObject* child)
{
return child->isOutOfFlowPositioned() || child->style()->visibility() == COLLAPSE;
}
static LayoutUnit contentWidthForChild(RenderBox* child)
{
if (child->hasOverrideWidth())
return child->overrideLogicalContentWidth();
return child->logicalWidth() - child->borderAndPaddingLogicalWidth();
}
static LayoutUnit contentHeightForChild(RenderBox* child)
{
if (child->hasOverrideHeight())
return child->overrideLogicalContentHeight();
return child->logicalHeight() - child->borderAndPaddingLogicalHeight();
}
void RenderDeprecatedFlexibleBox::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
{
RenderStyle* oldStyle = style();
if (oldStyle && !oldStyle->lineClamp().isNone() && newStyle.lineClamp().isNone())
clearLineClamp();
RenderBlock::styleWillChange(diff, newStyle);
}
void RenderDeprecatedFlexibleBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
{
if (hasMultipleLines() || isVertical()) {
for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
if (childDoesNotAffectWidthOrFlexing(child))
continue;
LayoutUnit margin = marginWidthForChild(child);
LayoutUnit width = child->minPreferredLogicalWidth() + margin;
minLogicalWidth = max(width, minLogicalWidth);
width = child->maxPreferredLogicalWidth() + margin;
maxLogicalWidth = max(width, maxLogicalWidth);
}
} else {
for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
if (childDoesNotAffectWidthOrFlexing(child))
continue;
LayoutUnit margin = marginWidthForChild(child);
minLogicalWidth += child->minPreferredLogicalWidth() + margin;
maxLogicalWidth += child->maxPreferredLogicalWidth() + margin;
}
}
maxLogicalWidth = max(minLogicalWidth, maxLogicalWidth);
LayoutUnit scrollbarWidth = instrinsicScrollbarLogicalWidth();
maxLogicalWidth += scrollbarWidth;
minLogicalWidth += scrollbarWidth;
}
void RenderDeprecatedFlexibleBox::computePreferredLogicalWidths()
{
ASSERT(preferredLogicalWidthsDirty());
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
if (style()->width().isFixed() && style()->width().value() > 0)
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->width().value());
else
computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
}
if (style()->maxWidth().isFixed()) {
m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
}
LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
m_minPreferredLogicalWidth += borderAndPadding;
m_maxPreferredLogicalWidth += borderAndPadding;
clearPreferredLogicalWidthsDirty();
}
void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren)
{
ASSERT(needsLayout());
if (!relayoutChildren && simplifiedLayout())
return;
LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
{
LayoutStateMaintainer statePusher(*this, locationOffset());
LayoutSize previousSize = size();
updateLogicalWidth();
updateLogicalHeight();
if (previousSize != size()
|| (parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
&& parent()->style()->boxAlign() == BSTRETCH))
relayoutChildren = true;
setHeight(0);
m_stretchingChildren = false;
if (isHorizontal())
layoutHorizontalBox(relayoutChildren);
else
layoutVerticalBox(relayoutChildren);
LayoutUnit oldClientAfterEdge = clientLogicalBottom();
updateLogicalHeight();
if (previousSize.height() != height())
relayoutChildren = true;
layoutPositionedObjects(relayoutChildren || isRoot());
computeRegionRangeForBlock(flowThreadContainingBlock());
computeOverflow(oldClientAfterEdge);
}
updateLayerTransform();
if (view()->layoutState()->pageLogicalHeight())
setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(*this, logicalTop()));
if (hasOverflowClip())
layer()->scrollableArea()->updateAfterLayout();
repainter.repaintAfterLayout();
clearNeedsLayout();
}
static void gatherFlexChildrenInfo(FlexBoxIterator& iterator, bool relayoutChildren, unsigned int& highestFlexGroup, unsigned int& lowestFlexGroup, bool& haveFlex)
{
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
if (!childDoesNotAffectWidthOrFlexing(child) && child->style()->boxFlex() > 0.0f) {
child->clearOverrideSize();
if (!relayoutChildren)
child->setChildNeedsLayout(MarkOnlyThis);
haveFlex = true;
unsigned int flexGroup = child->style()->boxFlexGroup();
if (lowestFlexGroup == 0)
lowestFlexGroup = flexGroup;
if (flexGroup < lowestFlexGroup)
lowestFlexGroup = flexGroup;
if (flexGroup > highestFlexGroup)
highestFlexGroup = flexGroup;
}
}
}
void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
{
LayoutUnit toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
LayoutUnit yPos = borderTop() + paddingTop();
LayoutUnit xPos = borderLeft() + paddingLeft();
bool heightSpecified = false;
LayoutUnit oldHeight = 0;
LayoutUnit remainingSpace = 0;
FlexBoxIterator iterator(this);
unsigned int highestFlexGroup = 0;
unsigned int lowestFlexGroup = 0;
bool haveFlex = false, flexingChildren = false;
gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
RenderBlock::startDelayUpdateScrollInfo();
do {
setHeight(yPos);
xPos = borderLeft() + paddingLeft();
LayoutUnit maxAscent = 0, maxDescent = 0;
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
if (child->isOutOfFlowPositioned())
continue;
SubtreeLayoutScope layoutScope(child);
if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())))
layoutScope.setChildNeedsLayout(child);
child->computeAndSetBlockDirectionMargins(this);
if (!child->needsLayout())
child->markForPaginationRelayoutIfNeeded(layoutScope);
child->layoutIfNeeded();
if (style()->boxAlign() == BBASELINE) {
LayoutUnit ascent = child->firstLineBoxBaseline();
if (ascent == -1)
ascent = child->height() + child->marginBottom();
ascent += child->marginTop();
LayoutUnit descent = (child->height() + child->marginHeight()) - ascent;
maxAscent = max(maxAscent, ascent);
maxDescent = max(maxDescent, descent);
setHeight(max(yPos + maxAscent + maxDescent, height()));
}
else
setHeight(max(height(), yPos + child->height() + child->marginHeight()));
}
if (!iterator.first() && hasLineIfEmpty())
setHeight(height() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
setHeight(height() + toAdd);
oldHeight = height();
updateLogicalHeight();
relayoutChildren = false;
if (oldHeight != height())
heightSpecified = true;
m_stretchingChildren = (style()->boxAlign() == BSTRETCH);
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
if (child->isOutOfFlowPositioned()) {
child->containingBlock()->insertPositionedObject(child);
RenderLayer* childLayer = child->layer();
childLayer->setStaticInlinePosition(xPos);
if (childLayer->staticBlockPosition() != yPos) {
childLayer->setStaticBlockPosition(yPos);
if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
child->setChildNeedsLayout(MarkOnlyThis);
}
continue;
}
if (child->style()->visibility() == COLLAPSE) {
child->layoutIfNeeded();
continue;
}
SubtreeLayoutScope layoutScope(child);
LayoutUnit oldChildHeight = child->height();
child->updateLogicalHeight();
if (oldChildHeight != child->height())
layoutScope.setChildNeedsLayout(child);
if (!child->needsLayout())
child->markForPaginationRelayoutIfNeeded(layoutScope);
child->layoutIfNeeded();
xPos += child->marginLeft();
LayoutUnit childY = yPos;
switch (style()->boxAlign()) {
case BCENTER:
childY += child->marginTop() + max<LayoutUnit>(0, (contentHeight() - (child->height() + child->marginHeight())) / 2);
break;
case BBASELINE: {
LayoutUnit 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, LayoutPoint(xPos, childY));
xPos += child->width() + child->marginRight();
}
remainingSpace = borderLeft() + paddingLeft() + contentWidth() - xPos;
m_stretchingChildren = false;
if (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 i = start; i <= end && remainingSpace; i++) {
LayoutUnit groupRemainingSpace = remainingSpace;
do {
LayoutUnit groupRemainingSpaceAtBeginning = groupRemainingSpace;
float totalFlex = 0.0f;
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
if (allowedChildFlex(child, expanding, i))
totalFlex += child->style()->boxFlex();
}
LayoutUnit spaceAvailableThisPass = groupRemainingSpace;
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
LayoutUnit allowedFlex = allowedChildFlex(child, expanding, i);
if (allowedFlex) {
LayoutUnit projectedFlex = (allowedFlex == LayoutUnit::max()) ? allowedFlex : LayoutUnit(allowedFlex * (totalFlex / child->style()->boxFlex()));
spaceAvailableThisPass = expanding ? min(spaceAvailableThisPass, projectedFlex) : max(spaceAvailableThisPass, projectedFlex);
}
}
if (!spaceAvailableThisPass || totalFlex == 0.0f) {
groupRemainingSpace = 0;
continue;
}
for (RenderBox* child = iterator.first(); child && spaceAvailableThisPass && totalFlex; child = iterator.next()) {
if (child->style()->visibility() == COLLAPSE)
continue;
if (allowedChildFlex(child, expanding, i)) {
LayoutUnit spaceAdd = LayoutUnit(spaceAvailableThisPass * (child->style()->boxFlex() / totalFlex));
if (spaceAdd) {
child->setOverrideLogicalContentWidth(contentWidthForChild(child) + spaceAdd);
flexingChildren = true;
relayoutChildren = true;
}
spaceAvailableThisPass -= spaceAdd;
remainingSpace -= spaceAdd;
groupRemainingSpace -= spaceAdd;
totalFlex -= child->style()->boxFlex();
}
}
if (groupRemainingSpace == groupRemainingSpaceAtBeginning) {
LayoutUnit spaceAdd = groupRemainingSpace > 0 ? 1 : -1;
for (RenderBox* child = iterator.first(); child && groupRemainingSpace; child = iterator.next()) {
if (allowedChildFlex(child, expanding, i)) {
child->setOverrideLogicalContentWidth(contentWidthForChild(child) + spaceAdd);
flexingChildren = true;
relayoutChildren = true;
remainingSpace -= spaceAdd;
groupRemainingSpace -= spaceAdd;
}
}
}
} while (absoluteValue(groupRemainingSpace) >= 1);
}
if (haveFlex && !flexingChildren)
haveFlex = false;
}
} while (haveFlex);
RenderBlock::finishDelayUpdateScrollInfo();
if (remainingSpace > 0 && ((style()->isLeftToRightDirection() && style()->boxPack() != Start)
|| (!style()->isLeftToRightDirection() && style()->boxPack() != End))) {
LayoutUnit offset = 0;
if (style()->boxPack() == Justify) {
int totalChildren = 0;
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
if (childDoesNotAffectWidthOrFlexing(child))
continue;
++totalChildren;
}
if (totalChildren > 1) {
--totalChildren;
bool firstChild = true;
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
if (childDoesNotAffectWidthOrFlexing(child))
continue;
if (firstChild) {
firstChild = false;
continue;
}
offset += remainingSpace/totalChildren;
remainingSpace -= (remainingSpace/totalChildren);
--totalChildren;
placeChild(child, child->location() + LayoutSize(offset, 0));
}
}
} else {
if (style()->boxPack() == Center)
offset += remainingSpace / 2;
else
offset += remainingSpace;
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
if (childDoesNotAffectWidthOrFlexing(child))
continue;
placeChild(child, child->location() + LayoutSize(offset, 0));
}
}
}
if (heightSpecified)
setHeight(oldHeight);
}
void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren)
{
LayoutUnit yPos = borderTop() + paddingTop();
LayoutUnit toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
bool heightSpecified = false;
LayoutUnit oldHeight = 0;
LayoutUnit remainingSpace = 0;
FlexBoxIterator iterator(this);
unsigned int highestFlexGroup = 0;
unsigned int lowestFlexGroup = 0;
bool haveFlex = false, flexingChildren = false;
gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
bool haveLineClamp = !style()->lineClamp().isNone();
if (haveLineClamp)
applyLineClamp(iterator, relayoutChildren);
RenderBlock::startDelayUpdateScrollInfo();
do {
setHeight(borderTop() + paddingTop());
LayoutUnit minHeight = height() + toAdd;
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
if (child->isOutOfFlowPositioned()) {
child->containingBlock()->insertPositionedObject(child);
RenderLayer* childLayer = child->layer();
childLayer->setStaticInlinePosition(borderStart() + paddingStart());
if (childLayer->staticBlockPosition() != height()) {
childLayer->setStaticBlockPosition(height());
if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
child->setChildNeedsLayout(MarkOnlyThis);
}
continue;
}
SubtreeLayoutScope layoutScope(child);
if (!haveLineClamp && (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))))
layoutScope.setChildNeedsLayout(child);
if (child->style()->visibility() == COLLAPSE) {
child->layoutIfNeeded();
continue;
}
child->computeAndSetBlockDirectionMargins(this);
setHeight(height() + child->marginTop());
if (!child->needsLayout())
child->markForPaginationRelayoutIfNeeded(layoutScope);
child->layoutIfNeeded();
LayoutUnit childX = borderLeft() + paddingLeft();
switch (style()->boxAlign()) {
case BCENTER:
case BBASELINE:
childX += child->marginLeft() + max<LayoutUnit>(0, (contentWidth() - (child->width() + child->marginWidth())) / 2);
break;
case BEND:
if (!style()->isLeftToRightDirection())
childX += child->marginLeft();
else
childX += contentWidth() - child->marginRight() - child->width();
break;
default:
if (style()->isLeftToRightDirection())
childX += child->marginLeft();
else
childX += contentWidth() - child->marginRight() - child->width();
break;
}
placeChild(child, LayoutPoint(childX, height()));
setHeight(height() + child->height() + child->marginBottom());
}
yPos = height();
if (!iterator.first() && hasLineIfEmpty())
setHeight(height() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
setHeight(height() + toAdd);
if (height() < minHeight)
setHeight(minHeight);
oldHeight = height();
updateLogicalHeight();
if (oldHeight != height())
heightSpecified = true;
remainingSpace = borderTop() + paddingTop() + contentHeight() - yPos;
if (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 i = start; i <= end && remainingSpace; i++) {
LayoutUnit groupRemainingSpace = remainingSpace;
do {
LayoutUnit groupRemainingSpaceAtBeginning = groupRemainingSpace;
float totalFlex = 0.0f;
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
if (allowedChildFlex(child, expanding, i))
totalFlex += child->style()->boxFlex();
}
LayoutUnit spaceAvailableThisPass = groupRemainingSpace;
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
LayoutUnit allowedFlex = allowedChildFlex(child, expanding, i);
if (allowedFlex) {
LayoutUnit projectedFlex = (allowedFlex == LayoutUnit::max()) ? allowedFlex : static_cast<LayoutUnit>(allowedFlex * (totalFlex / child->style()->boxFlex()));
spaceAvailableThisPass = expanding ? min(spaceAvailableThisPass, projectedFlex) : max(spaceAvailableThisPass, projectedFlex);
}
}
if (!spaceAvailableThisPass || totalFlex == 0.0f) {
groupRemainingSpace = 0;
continue;
}
for (RenderBox* child = iterator.first(); child && spaceAvailableThisPass && totalFlex; child = iterator.next()) {
if (allowedChildFlex(child, expanding, i)) {
LayoutUnit spaceAdd = static_cast<LayoutUnit>(spaceAvailableThisPass * (child->style()->boxFlex() / totalFlex));
if (spaceAdd) {
child->setOverrideLogicalContentHeight(contentHeightForChild(child) + spaceAdd);
flexingChildren = true;
relayoutChildren = true;
}
spaceAvailableThisPass -= spaceAdd;
remainingSpace -= spaceAdd;
groupRemainingSpace -= spaceAdd;
totalFlex -= child->style()->boxFlex();
}
}
if (groupRemainingSpace == groupRemainingSpaceAtBeginning) {
LayoutUnit spaceAdd = groupRemainingSpace > 0 ? 1 : -1;
for (RenderBox* child = iterator.first(); child && groupRemainingSpace; child = iterator.next()) {
if (allowedChildFlex(child, expanding, i)) {
child->setOverrideLogicalContentHeight(contentHeightForChild(child) + spaceAdd);
flexingChildren = true;
relayoutChildren = true;
remainingSpace -= spaceAdd;
groupRemainingSpace -= spaceAdd;
}
}
}
} while (absoluteValue(groupRemainingSpace) >= 1);
}
if (haveFlex && !flexingChildren)
haveFlex = false;
}
} while (haveFlex);
RenderBlock::finishDelayUpdateScrollInfo();
if (style()->boxPack() != Start && remainingSpace > 0) {
LayoutUnit offset = 0;
if (style()->boxPack() == Justify) {
int totalChildren = 0;
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
if (childDoesNotAffectWidthOrFlexing(child))
continue;
++totalChildren;
}
if (totalChildren > 1) {
--totalChildren;
bool firstChild = true;
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
if (childDoesNotAffectWidthOrFlexing(child))
continue;
if (firstChild) {
firstChild = false;
continue;
}
offset += remainingSpace/totalChildren;
remainingSpace -= (remainingSpace/totalChildren);
--totalChildren;
placeChild(child, child->location() + LayoutSize(0, offset));
}
}
} else {
if (style()->boxPack() == Center)
offset += remainingSpace / 2;
else
offset += remainingSpace;
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
if (childDoesNotAffectWidthOrFlexing(child))
continue;
placeChild(child, child->location() + LayoutSize(0, offset));
}
}
}
if (heightSpecified)
setHeight(oldHeight);
}
void RenderDeprecatedFlexibleBox::applyLineClamp(FlexBoxIterator& iterator, bool relayoutChildren)
{
UseCounter::count(document(), UseCounter::LineClamp);
int maxLineCount = 0;
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
if (childDoesNotAffectWidthOrFlexing(child))
continue;
child->clearOverrideSize();
if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))
|| (child->style()->height().isAuto() && child->isRenderBlock())) {
child->setChildNeedsLayout(MarkOnlyThis);
if (child->isRenderBlock()) {
toRenderBlock(child)->markPositionedObjectsForLayout();
toRenderBlock(child)->clearTruncation();
}
}
child->layoutIfNeeded();
if (child->style()->height().isAuto() && child->isRenderBlock())
maxLineCount = max(maxLineCount, toRenderBlock(child)->lineCount());
}
LineClampValue lineClamp = style()->lineClamp();
int numVisibleLines = lineClamp.isPercentage() ? max(1, (maxLineCount + 1) * lineClamp.value() / 100) : lineClamp.value();
if (numVisibleLines >= maxLineCount)
return;
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
if (childDoesNotAffectWidthOrFlexing(child) || !child->style()->height().isAuto() || !child->isRenderBlock())
continue;
RenderBlock* blockChild = toRenderBlock(child);
int lineCount = blockChild->lineCount();
if (lineCount <= numVisibleLines)
continue;
LayoutUnit newHeight = blockChild->heightForLineCount(numVisibleLines);
if (newHeight == child->height())
continue;
child->setOverrideLogicalContentHeight(newHeight - child->borderAndPaddingHeight());
child->forceChildLayout();
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();
float totalWidth;
InlineBox* anchorBox = lastLine->lastChild();
if (anchorBox && anchorBox->renderer().style()->isLink())
totalWidth = anchorBox->logicalWidth() + font.width(RenderBlockFlow::constructTextRun(this, font, ellipsisAndSpace, 2, style(), style()->direction()));
else {
anchorBox = 0;
totalWidth = font.width(RenderBlockFlow::constructTextRun(this, font, &horizontalEllipsis, 1, style(), style()->direction()));
}
RenderBlockFlow& destBlock = lastVisibleLine->block();
RenderBlockFlow& srcBlock = lastLine->block();
if (!srcBlock.style()->isLeftToRightDirection())
continue;
bool leftToRight = destBlock.style()->isLeftToRightDirection();
if (!leftToRight)
continue;
LayoutUnit blockRightEdge = destBlock.logicalRightOffsetForLine(lastVisibleLine->y(), false);
if (!lastVisibleLine->lineCanAccommodateEllipsis(leftToRight, blockRightEdge, lastVisibleLine->x() + lastVisibleLine->logicalWidth(), totalWidth))
continue;
LayoutUnit blockLeftEdge = destBlock.logicalLeftOffsetForLine(lastVisibleLine->y(), false);
lastVisibleLine->placeEllipsis(anchorBox ? ellipsisAndSpaceStr : ellipsisStr, leftToRight, blockLeftEdge.toFloat(), blockRightEdge.toFloat(), totalWidth, anchorBox);
destBlock.setHasMarkupTruncation(true);
}
}
void RenderDeprecatedFlexibleBox::clearLineClamp()
{
FlexBoxIterator iterator(this);
for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
if (childDoesNotAffectWidthOrFlexing(child))
continue;
child->clearOverrideSize();
if ((child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))
|| (child->style()->height().isAuto() && child->isRenderBlock())) {
child->setChildNeedsLayout();
if (child->isRenderBlock()) {
toRenderBlock(child)->markPositionedObjectsForLayout();
toRenderBlock(child)->clearTruncation();
}
}
}
}
void RenderDeprecatedFlexibleBox::placeChild(RenderBox* child, const LayoutPoint& location)
{
LayoutRect oldRect = child->frameRect();
child->setLocation(location);
if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
child->repaintDuringLayoutIfMoved(oldRect);
}
LayoutUnit RenderDeprecatedFlexibleBox::allowedChildFlex(RenderBox* child, bool expanding, unsigned int group)
{
if (childDoesNotAffectWidthOrFlexing(child) || child->style()->boxFlex() == 0.0f || child->style()->boxFlexGroup() != group)
return 0;
if (expanding) {
if (isHorizontal()) {
LayoutUnit maxWidth = LayoutUnit::max();
LayoutUnit width = contentWidthForChild(child);
if (!child->style()->maxWidth().isUndefined() && child->style()->maxWidth().isFixed())
maxWidth = child->style()->maxWidth().value();
else if (child->style()->maxWidth().type() == Intrinsic)
maxWidth = child->maxPreferredLogicalWidth();
else if (child->style()->maxWidth().type() == MinIntrinsic)
maxWidth = child->minPreferredLogicalWidth();
if (maxWidth == LayoutUnit::max())
return maxWidth;
return max<LayoutUnit>(0, maxWidth - width);
} else {
LayoutUnit maxHeight = LayoutUnit::max();
LayoutUnit height = contentHeightForChild(child);
if (!child->style()->maxHeight().isUndefined() && child->style()->maxHeight().isFixed())
maxHeight = child->style()->maxHeight().value();
if (maxHeight == LayoutUnit::max())
return maxHeight;
return max<LayoutUnit>(0, maxHeight - height);
}
}
if (isHorizontal()) {
LayoutUnit minWidth = child->minPreferredLogicalWidth();
LayoutUnit width = contentWidthForChild(child);
if (child->style()->minWidth().isFixed())
minWidth = child->style()->minWidth().value();
else if (child->style()->minWidth().type() == Intrinsic)
minWidth = child->maxPreferredLogicalWidth();
else if (child->style()->minWidth().type() == MinIntrinsic)
minWidth = child->minPreferredLogicalWidth();
else if (child->style()->minWidth().type() == Auto)
minWidth = 0;
LayoutUnit allowedShrinkage = min<LayoutUnit>(0, minWidth - width);
return allowedShrinkage;
} else {
Length minHeight = child->style()->minHeight();
if (minHeight.isFixed() || minHeight.isAuto()) {
LayoutUnit minHeight = child->style()->minHeight().value();
LayoutUnit height = contentHeightForChild(child);
LayoutUnit allowedShrinkage = min<LayoutUnit>(0, minHeight - height);
return allowedShrinkage;
}
}
return 0;
}
const char* RenderDeprecatedFlexibleBox::renderName() const
{
if (isFloating())
return "RenderDeprecatedFlexibleBox (floating)";
if (isOutOfFlowPositioned())
return "RenderDeprecatedFlexibleBox (positioned)";
if (isPseudoElement())
return "RenderDeprecatedFlexibleBox (generated)";
if (isAnonymous())
return "RenderDeprecatedFlexibleBox (generated)";
if (isRelPositioned())
return "RenderDeprecatedFlexibleBox (relative positioned)";
return "RenderDeprecatedFlexibleBox";
}
}