📄 render_flexbox.cpp
字号:
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);
// 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
childX += child->marginLeft() + (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: // BSTART/BSTRETCH
if (style()->direction() == LTR)
childX += child->marginLeft();
else
childX += contentWidth() - child->marginRight() - child->width();
break;
}
// Place the child.
placeChild(child, childX, m_height);
m_height += child->height() + child->marginBottom();
// See if this child has made our overflow need to grow.
// XXXdwh Work with left overflow as well as right overflow.
int rightChildPos = child->xPos() + kMax(child->overflowWidth(false), child->width());
if (rightChildPos > m_overflowWidth)
m_overflowWidth = rightChildPos;
child = iterator.next();
}
yPos = m_height;
m_height += toAdd;
// Negative margins can cause our height to shrink below our minimal height (border/padding).
// If this happens, ensure that the computed height is increased to the minimal height.
if (m_height < minHeight)
m_height = minHeight;
// Always make sure our overflowheight is at least our height.
if (m_overflowHeight < m_height)
m_overflowHeight = m_height;
// Now we have to calc our height, so we know how much space we have remaining.
oldHeight = m_height;
calcHeight();
if (oldHeight != m_height)
heightSpecified = true;
remainingSpace = borderTop() + paddingTop() + contentHeight() - yPos;
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;
}
// 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->overrideHeight() + 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);
if (style()->boxPack() != BSTART && remainingSpace > 0) {
// 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(), child->yPos()+offset);
child = iterator.next();
}
}
}
else {
if (style()->boxPack() == BCENTER)
offset += remainingSpace/2;
else // END
offset += remainingSpace;
child = iterator.first();
while (child) {
if (child->isPositioned()) {
child = iterator.next();
continue;
}
placeChild(child, child->xPos(), child->yPos()+offset);
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::placeChild(RenderObject* child, int x, int y)
{
int oldChildX = child->xPos();
int oldChildY = child->yPos();
// Place the child.
child->setPos(x, y);
// If the child moved, we have to repaint it as well as any floating/positioned
// descendants. An exception is if we need a layout. In this case, we know we're going to
// repaint ourselves (and the child) anyway.
if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
child->repaintDuringLayoutIfMoved(oldChildX, oldChildY);
}
int RenderFlexibleBox::allowedChildFlex(RenderObject* child, bool expanding, unsigned int group)
{
if (child->isPositioned() || child->style()->boxFlex() == 0.0f || child->style()->boxFlexGroup() != group)
return 0;
if (expanding) {
if (isHorizontal()) {
// FIXME: For now just handle fixed values.
int maxW = INT_MAX;
int w = child->overrideWidth() - (child->borderLeft() + child->borderRight() + child->paddingLeft() + child->paddingRight());
if (child->style()->maxWidth().value != UNDEFINED &&
child->style()->maxWidth().isFixed())
maxW = child->style()->maxWidth().value;
else if (child->style()->maxWidth().type == Intrinsic)
maxW = child->maxWidth();
else if (child->style()->maxWidth().type == MinIntrinsic)
maxW = child->minWidth();
int allowedGrowth = kMax(0, maxW - w);
return allowedGrowth;
}
else {
// FIXME: For now just handle fixed values.
int maxH = INT_MAX;
int h = child->overrideHeight() - (child->borderTop() + child->borderBottom() + child->paddingTop() + child->paddingBottom());
if (child->style()->maxHeight().value != UNDEFINED &&
child->style()->maxHeight().isFixed())
maxH = child->style()->maxHeight().value;
int allowedGrowth = kMax(0, maxH - h);
return allowedGrowth;
}
}
// FIXME: For now just handle fixed values.
if (isHorizontal()) {
int minW = child->minWidth();
int w = child->contentWidth();
if (child->style()->minWidth().isFixed())
minW = child->style()->minWidth().value;
else if (child->style()->minWidth().type == Intrinsic)
minW = child->maxWidth();
else if (child->style()->minWidth().type == MinIntrinsic)
minW = child->minWidth();
int allowedShrinkage = kMin(0, minW - w);
return allowedShrinkage;
}
else {
if (child->style()->minHeight().isFixed()) {
int minH = child->style()->minHeight().value;
int h = child->contentHeight();
int allowedShrinkage = kMin(0, minH - h);
return allowedShrinkage;
}
}
return 0;
}
const char *RenderFlexibleBox::renderName() const
{
if (isFloating())
return "RenderFlexibleBox (floating)";
if (isPositioned())
return "RenderFlexibleBox (positioned)";
if (isRelPositioned())
return "RenderFlexibleBox (relative positioned)";
return "RenderFlexibleBox";
}
} // namespace khtml
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -