📄 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 + -