📄 render_flexbox.cpp
字号:
// Now distribute the space to objects.
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();
}
} while (groupRemainingSpace);
}
// We didn't find any children that could grow.
if (haveFlex && !m_flexingChildren)
haveFlex = false;
}
} while (haveFlex);
m_flexingChildren = false;
if (xPos > m_overflowWidth)
m_overflowWidth = xPos;
if (remainingSpace > 0 && ((style()->direction() == LTR && style()->boxPack() != BSTART) ||
(style()->direction() == RTL && style()->boxPack() != BEND))) {
// Children must be repositioned.
int offset = 0;
if (style()->boxPack() == BJUSTIFY) {
// Determine the total number of children.
int totalChildren = 0;
child = iterator.first();
while (child) {
if (child->isPositioned()) {
child = iterator.next();
continue;
}
totalChildren++;
child = iterator.next();
}
// Iterate over the children and space them out according to the
// justification level.
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->xPos()+offset, child->yPos());
child = iterator.next();
}
}
}
else {
if (style()->boxPack() == BCENTER)
offset += remainingSpace/2;
else // END for LTR, START for RTL
offset += remainingSpace;
child = iterator.first();
while (child) {
if (child->isPositioned()) {
child = iterator.next();
continue;
}
placeChild(child, child->xPos()+offset, child->yPos());
child = iterator.next();
}
}
}
// So that the calcHeight in layoutBlock() knows to relayout positioned objects because of
// a height change, we revert our height back to the intrinsic height before returning.
if (heightSpecified)
m_height = oldHeight;
}
void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
{
int xPos = borderLeft() + paddingLeft();
int yPos = borderTop() + paddingTop();
if( style()->direction() == RTL )
xPos = m_width - paddingRight() - borderRight();
int toAdd = borderBottom() + paddingBottom();
bool heightSpecified = false;
int oldHeight = 0;
unsigned int highestFlexGroup = 0;
unsigned int lowestFlexGroup = 0;
bool haveFlex = false;
int remainingSpace = 0;
// 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);
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();
}
#if APPLE_CHANGES
// We confine the line clamp ugliness to vertical flexible boxes (thus keeping it out of
// mainstream block layout) and put it all inside APPLE_CHANGES to denote that this is not
// really part of the XUL box model.
bool haveLineClamp = style()->lineClamp() >= 0 && style()->lineClamp() <= 100;
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().isVariable() && child->isBlockFlow() && !child->needsLayout())) {
child->setChildNeedsLayout(true);
// Dirty all the positioned objects.
static_cast<RenderBlock*>(child)->markPositionedObjectsForLayout();
static_cast<RenderBlock*>(child)->clearTruncation();
}
child->layoutIfNeeded();
if (child->style()->height().isVariable() && child->isBlockFlow())
maxLineCount = kMax(maxLineCount, static_cast<RenderBlock*>(child)->lineCount());
}
child = iterator.next();
}
// Get the # of lines and then alter all block flow children with auto height to use the
// specified height.
int numVisibleLines = int((maxLineCount+1)*style()->lineClamp()/100.0);
if (numVisibleLines < maxLineCount) {
for (child = iterator.first(); child; child = iterator.next()) {
if (child->isPositioned() || !child->style()->height().isVariable() || !child->isBlockFlow())
continue;
RenderBlock* blockChild = static_cast<RenderBlock*>(child);
int lineCount = blockChild->lineCount();
if (lineCount <= numVisibleLines) continue;
int newHeight = blockChild->heightForLineCount(numVisibleLines);
if (newHeight == -1 && numVisibleLines == 0) newHeight = 0;
if (newHeight == child->height()) continue;
child->setChildNeedsLayout(true);
child->setOverrideSize(newHeight);
m_flexingChildren = true;
child->layoutIfNeeded();
m_flexingChildren = false;
child->setOverrideSize(-1);
// FIXME: For now don't support RTL.
if (style()->direction() != LTR) continue;
// Get the last line
RootInlineBox* lastLine = blockChild->lineAtIndex(lineCount-1);
if (!lastLine) continue;
// See if the last item is an anchor
InlineBox* anchorBox = lastLine->lastChild();
if (!anchorBox) continue;
if (!anchorBox->object()->element()) continue;
if (!anchorBox->object()->element()->hasAnchor()) continue;
RootInlineBox* lastVisibleLine = blockChild->lineAtIndex(numVisibleLines-1);
if (!lastVisibleLine) continue;
const unsigned short ellipsisAndSpace[2] = { 0x2026, ' ' };
static AtomicString ellipsisAndSpaceStr(ellipsisAndSpace, 2);
const Font& font = style(numVisibleLines == 1)->htmlFont();
int ellipsisAndSpaceWidth = font.width(const_cast<QChar*>(ellipsisAndSpaceStr.unicode()), 2, 0, 2, 0, 0);
// Get ellipsis width + " " + anchor width
int totalWidth = ellipsisAndSpaceWidth + anchorBox->width();
// See if this width can be accommodated on the last visible line
RenderBlock* destBlock = static_cast<RenderBlock*>(lastVisibleLine->object());
RenderBlock* srcBlock = static_cast<RenderBlock*>(lastLine->object());
// FIXME: Directions of src/destBlock could be different from our direction and from one another.
if (srcBlock->style()->direction() != LTR) continue;
if (destBlock->style()->direction() != LTR) continue;
int blockEdge = destBlock->rightOffset(lastVisibleLine->yPos());
if (!lastVisibleLine->canAccommodateEllipsis(true, blockEdge,
lastVisibleLine->xPos() + lastVisibleLine->width(),
totalWidth))
continue;
// Let the truncation code kick in.
lastVisibleLine->placeEllipsis(ellipsisAndSpaceStr, true, blockEdge, totalWidth, anchorBox);
destBlock->setHasMarkupTruncation(true);
}
}
}
#endif
// We do 2 passes. The first pass is simply to lay everyone out at
// their preferred widths. The second pass handles flexing the children.
// Our first pass is done without flexing. We simply lay the children
// out within the box.
do {
m_height = borderTop() + paddingTop();
int minHeight = m_height + toAdd;
m_overflowHeight = m_height;
child = iterator.first();
while (child) {
// make sure we relayout children if we need it.
if (!haveLineClamp && (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))))
child->setChildNeedsLayout(true);
if (child->isPositioned())
{
child->containingBlock()->insertPositionedObject(child);
if (child->hasStaticX()) {
if (style()->direction() == LTR)
child->setStaticX(borderLeft()+paddingLeft());
else
child->setStaticX(borderRight()+paddingRight());
}
if (child->hasStaticY())
child->setStaticY(m_height);
child = iterator.next();
continue;
}
// Compute the child's vertical margins.
child->calcVerticalMargins();
// Add in the child's marginTop to our height.
m_height += child->marginTop();
// Now do a layout.
child->layoutIfNeeded();
// We can place the child now, using our value of box-align.
int childX = borderLeft() + paddingLeft();
switch (style()->boxAlign()) {
case BCENTER:
case BBASELINE: // Baseline just maps to center for vertical boxes
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -