📄 render_flexbox.cpp
字号:
initMaxMarginValues();
if (scrollsOverflow()) {
// For overflow:scroll blocks, ensure we have both scrollbars in place always.
if (style()->overflow() == OSCROLL) {
m_layer->setHasHorizontalScrollbar(true);
m_layer->setHasVerticalScrollbar(true);
}
// Move the scrollbars aside during layout. The layer will move them back when it
// does painting or event handling.
m_layer->moveScrollbarsAside();
}
if (isHorizontal())
layoutHorizontalBox(relayoutChildren);
else
layoutVerticalBox(relayoutChildren);
oldHeight = m_height;
calcHeight();
if (oldHeight != m_height) {
relayoutChildren = true;
// If the block got expanded in size, then increase our overflowheight to match.
if (m_overflowHeight > m_height)
m_overflowHeight -= (borderBottom()+paddingBottom());
if (m_overflowHeight < m_height)
m_overflowHeight = m_height;
}
layoutPositionedObjects( relayoutChildren );
//kdDebug() << renderName() << " layout width=" << m_width << " height=" << m_height << endl;
if (!isFloatingOrPositioned() && m_height == 0) {
// We are a block with no border and padding and a computed height
// of 0. The CSS spec states that zero-height blocks collapse their margins
// together.
// When blocks are self-collapsing, we just use the top margin values and set the
// bottom margin max values to 0. This way we don't factor in the values
// twice when we collapse with our previous vertically adjacent and
// following vertically adjacent blocks.
if (m_maxBottomPosMargin > m_maxTopPosMargin)
m_maxTopPosMargin = m_maxBottomPosMargin;
if (m_maxBottomNegMargin > m_maxTopNegMargin)
m_maxTopNegMargin = m_maxBottomNegMargin;
m_maxBottomNegMargin = m_maxBottomPosMargin = 0;
}
// Always ensure our overflow width is at least as large as our width.
if (m_overflowWidth < m_width)
m_overflowWidth = m_width;
// Update our scrollbars if we're overflow:auto/scroll/hidden now that we know if
// we overflow or not.
if (hasOverflowClip())
m_layer->updateScrollInfoAfterLayout();
// Repaint with our new bounds if they are different from our old bounds.
if (checkForRepaint)
repaintAfterLayoutIfNeeded(oldBounds, oldBounds);
setNeedsLayout(false);
}
void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
{
int toAdd = borderBottom() + paddingBottom();
int yPos = borderTop() + paddingTop();
int xPos = borderLeft() + paddingLeft();
bool heightSpecified = false;
int oldHeight = 0;
unsigned int highestFlexGroup = 0;
unsigned int lowestFlexGroup = 0;
bool haveFlex = false;
int remainingSpace = 0;
m_overflowHeight = m_height;
// The first walk over our kids is to find out if we have any flexible children.
FlexBoxIterator iterator(this);
RenderObject* child = iterator.next();
while (child) {
// Check to see if this child flexes.
if (!child->isPositioned() && child->style()->boxFlex() > 0.0f) {
// We always have to lay out flexible objects again, since the flex distribution
// may have changed, and we need to reallocate space.
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();
}
// We do 2 passes. The first pass is simply to lay everyone out at
// their preferred widths. The second pass handles flexing the children.
do {
// Reset our height.
m_height = yPos;
m_overflowHeight = m_height;
xPos = borderLeft() + paddingLeft();
// Our first pass is done without flexing. We simply lay the children
// out within the box. We have to do a layout first in order to determine
// our box's intrinsic height.
int maxAscent = 0, maxDescent = 0;
child = iterator.first();
while (child) {
// make sure we relayout children if we need it.
if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())))
child->setChildNeedsLayout(true, false);
if (child->isPositioned()) {
child = iterator.next();
continue;
}
// Compute the child's vertical margins.
child->calcVerticalMargins();
// Now do the layout.
child->layoutIfNeeded();
// Update our height and overflow height.
if (style()->boxAlign() == BBASELINE) {
int ascent = child->marginTop() + child->getBaselineOfFirstLineBox();
if (ascent == -1)
ascent = child->marginTop() + child->height() + child->marginBottom();
int descent = (child->marginTop() + child->height() + child->marginBottom()) - ascent;
// Update our maximum ascent.
maxAscent = kMax(maxAscent, ascent);
// Update our maximum descent.
maxDescent = kMax(maxDescent, descent);
// Now update our height.
m_height = kMax(yPos + maxAscent + maxDescent, m_height);
}
else
m_height = kMax(m_height, yPos + child->marginTop() + child->height() + child->marginBottom());
child = iterator.next();
}
m_height += toAdd;
// Always make sure our overflowheight is at least our height.
if (m_overflowHeight < m_height)
m_overflowHeight = m_height;
oldHeight = m_height;
calcHeight();
relayoutChildren = false;
if (oldHeight != m_height) {
heightSpecified = true;
// If the block got expanded in size, then increase our overflowheight to match.
if (m_overflowHeight > m_height)
m_overflowHeight -= (borderBottom() + paddingBottom());
if (m_overflowHeight < m_height)
m_overflowHeight = m_height;
}
// Now that our height is actually known, we can place our boxes.
m_stretchingChildren = (style()->boxAlign() == BSTRETCH);
child = iterator.first();
while (child) {
if (child->isPositioned()) {
child->containingBlock()->insertPositionedObject(child);
if (child->hasStaticX()) {
if (style()->direction() == LTR)
child->setStaticX(xPos);
else child->setStaticX(width() - xPos);
}
if (child->hasStaticY())
child->setStaticY(yPos);
child = iterator.next();
continue;
}
// We need to see if this child's height has changed, since we make block elements
// fill the height of a containing box by default.
// Now do a layout.
int oldChildHeight = child->height();
static_cast<RenderBox*>(child)->calcHeight();
if (oldChildHeight != child->height())
child->setChildNeedsLayout(true, false);
child->layoutIfNeeded();
// We can place the child now, using our value of box-align.
xPos += child->marginLeft();
int childY = yPos;
switch (style()->boxAlign()) {
case BCENTER:
childY += child->marginTop() + (contentHeight() - (child->height() + child->marginTop() + child->marginBottom()))/2;
break;
case BBASELINE: {
int ascent = child->marginTop() + child->getBaselineOfFirstLineBox();
if (ascent == -1)
ascent = child->marginTop() + child->height() + child->marginBottom();
childY += child->marginTop() + (maxAscent - ascent);
break;
}
case BEND:
childY += contentHeight() - child->marginBottom() - child->height();
break;
default: // BSTART
childY += child->marginTop();
break;
}
placeChild(child, xPos, childY);
m_overflowHeight = kMax(m_overflowHeight, childY + child->overflowHeight(false));
xPos += child->width() + child->marginRight();
child = iterator.next();
}
remainingSpace = borderLeft() + paddingLeft() + contentWidth() - xPos;
m_stretchingChildren = false;
if (m_flexingChildren)
haveFlex = false; // We're done.
else if (haveFlex) {
// We have some flexible objects. See if we need to grow/shrink them at all.
if (!remainingSpace)
break;
// Allocate the remaining space among the flexible objects. If we are trying to
// grow, then we go from the lowest flex group to the highest flex group. For shrinking,
// we go from the highest flex group to the lowest group.
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++) {
// Always start off by assuming the group can get all the remaining space.
int groupRemainingSpace = remainingSpace;
do {
// Flexing consists of multiple passes, since we have to change ratios every time an object hits its max/min-width
// For a given pass, we always start off by computing the totalFlex of all objects that can grow/shrink at all, and
// computing the allowed growth before an object hits its min/max width (and thus
// forces a totalFlex recomputation).
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 ? kMin(spaceAvailableThisPass, projectedFlex) : kMax(spaceAvailableThisPass, projectedFlex);
}
child = iterator.next();
}
// The flex groups may not have any flexible objects this time around.
if (!spaceAvailableThisPass || totalFlex == 0.0f) {
// If we just couldn't grow/shrink any more, then it's time to transition to the next flex group.
groupRemainingSpace = 0;
continue;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -