📄 renderbox.cpp
字号:
if (isTableCell() || (isInline() && !isReplaced())) return; if (isPositioned()) calcAbsoluteVertical(); else { calcVerticalMargins(); // For tables, calculate margins only. if (isTable()) return; Length h; bool inHorizontalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL; bool stretching = parent()->style()->boxAlign() == BSTRETCH; bool treatAsReplaced = shouldCalculateSizeAsReplaced() && (!inHorizontalBox || !stretching); bool checkMinMaxHeight = false; // The parent box is flexing us, so it has increased or decreased our height. We have to // grab our cached flexible height. if (hasOverrideSize() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL && parent()->isFlexingChildren()) h = Length(overrideSize() - borderTop() - borderBottom() - paddingTop() - paddingBottom(), Fixed); else if (treatAsReplaced) h = Length(calcReplacedHeight(), Fixed); else { h = style()->height(); checkMinMaxHeight = true; } // Block children of horizontal flexible boxes fill the height of the box. if (h.isAuto() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL && parent()->isStretchingChildren()) { h = Length(parentBox()->contentHeight() - marginTop() - marginBottom() - borderTop() - paddingTop() - borderBottom() - paddingBottom(), Fixed); checkMinMaxHeight = false; } int heightResult; if (checkMinMaxHeight) { heightResult = calcHeightUsing(style()->height()); if (heightResult == -1) heightResult = height(); int minH = calcHeightUsing(style()->minHeight()); // Leave as -1 if unset. int maxH = style()->maxHeight().isUndefined() ? heightResult : calcHeightUsing(style()->maxHeight()); if (maxH == -1) maxH = heightResult; heightResult = min(maxH, heightResult); heightResult = max(minH, heightResult); } else // The only times we don't check min/max height are when a fixed length has // been given as an override. Just use that. The value has already been adjusted // for box-sizing. heightResult = h.value() + borderTop() + borderBottom() + paddingTop() + paddingBottom(); setHeight(heightResult); } // WinIE quirk: The <html> block always fills the entire canvas in quirks mode. The <body> always fills the // <html> block in quirks mode. Only apply this quirk if the block is normal flow and no height // is specified. if (stretchesToViewHeight() && !document()->printing()) { int margins = collapsedMarginTop() + collapsedMarginBottom(); int visHeight = view()->viewHeight(); if (isRoot()) setHeight(max(height(), visHeight - margins)); else { int marginsBordersPadding = margins + parentBox()->marginTop() + parentBox()->marginBottom() + parentBox()->borderTop() + parentBox()->borderBottom() + parentBox()->paddingTop() + parentBox()->paddingBottom(); setHeight(max(height(), visHeight - marginsBordersPadding)); } }}int RenderBox::calcHeightUsing(const Length& h){ int height = -1; if (!h.isAuto()) { if (h.isFixed()) height = h.value(); else if (h.isPercent()) height = calcPercentageHeight(h); if (height != -1) { height = calcBorderBoxHeight(height); return height; } } return height;}int RenderBox::calcPercentageHeight(const Length& height){ int result = -1; bool includeBorderPadding = isTable(); RenderBlock* cb = containingBlock(); if (style()->htmlHacks()) { // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing // block that may have a specified height and then use it. In strict mode, this violates the // specification, which states that percentage heights just revert to auto if the containing // block has an auto height. while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() && cb->style()->height().isAuto()) { cb = cb->containingBlock(); cb->addPercentHeightDescendant(this); } } // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height // explicitly specified that can be used for any percentage computations. bool isPositionedWithSpecifiedHeight = cb->isPositioned() && (!cb->style()->height().isAuto() || (!cb->style()->top().isAuto() && !cb->style()->bottom().isAuto())); // Table cells violate what the CSS spec says to do with heights. Basically we // don't care if the cell specified a height or not. We just always make ourselves // be a percentage of the cell's current content height. if (cb->isTableCell()) { result = cb->overrideSize(); if (result == -1) { // Normally we would let the cell size intrinsically, but scrolling overflow has to be // treated differently, since WinIE lets scrolled overflow regions shrink as needed. // While we can't get all cases right, we can at least detect when the cell has a specified // height or when the table has a specified height. In these cases we want to initially have // no size and allow the flexing of the table or the cell to its specified height to cause us // to grow to fill the space. This could end up being wrong in some cases, but it is // preferable to the alternative (sizing intrinsically and making the row end up too big). RenderTableCell* cell = static_cast<RenderTableCell*>(cb); if (scrollsOverflowY() && (!cell->style()->height().isAuto() || !cell->table()->style()->height().isAuto())) return 0; return -1; } includeBorderPadding = true; } // Otherwise we only use our percentage height if our containing block had a specified // height. else if (cb->style()->height().isFixed()) result = cb->calcContentBoxHeight(cb->style()->height().value()); else if (cb->style()->height().isPercent() && !isPositionedWithSpecifiedHeight) { // We need to recur and compute the percentage height for our containing block. result = cb->calcPercentageHeight(cb->style()->height()); if (result != -1) result = cb->calcContentBoxHeight(result); } else if (cb->isRenderView() || (cb->isBody() && style()->htmlHacks()) || isPositionedWithSpecifiedHeight) { // Don't allow this to affect the block' height() member variable, since this // can get called while the block is still laying out its kids. int oldHeight = cb->height(); cb->calcHeight(); result = cb->contentHeight(); cb->setHeight(oldHeight); } else if (cb->isRoot() && isPositioned()) // Match the positioned objects behavior, which is that positioned objects will fill their viewport // always. Note we could only hit this case by recurring into calcPercentageHeight on a positioned containing block. result = cb->calcContentBoxHeight(cb->availableHeight()); if (result != -1) { result = height.calcValue(result); if (includeBorderPadding) { // It is necessary to use the border-box to match WinIE's broken // box model. This is essential for sizing inside // table cells using percentage heights. result -= (borderTop() + paddingTop() + borderBottom() + paddingBottom()); result = max(0, result); } } return result;}int RenderBox::calcReplacedWidth(bool includeMaxWidth) const{ int width = calcReplacedWidthUsing(style()->width()); int minW = calcReplacedWidthUsing(style()->minWidth()); int maxW = !includeMaxWidth || style()->maxWidth().isUndefined() ? width : calcReplacedWidthUsing(style()->maxWidth()); return max(minW, min(width, maxW));}int RenderBox::calcReplacedWidthUsing(Length width) const{ switch (width.type()) { case Fixed: return calcContentBoxWidth(width.value()); case Percent: { const int cw = isPositioned() ? containingBlockWidthForPositioned(toRenderBoxModelObject(container())) : containingBlockWidthForContent(); if (cw > 0) return calcContentBoxWidth(width.calcMinValue(cw)); } // fall through default: return intrinsicSize().width(); } }int RenderBox::calcReplacedHeight() const{ int height = calcReplacedHeightUsing(style()->height()); int minH = calcReplacedHeightUsing(style()->minHeight()); int maxH = style()->maxHeight().isUndefined() ? height : calcReplacedHeightUsing(style()->maxHeight()); return max(minH, min(height, maxH));}int RenderBox::calcReplacedHeightUsing(Length height) const{ switch (height.type()) { case Fixed: return calcContentBoxHeight(height.value()); case Percent: { RenderObject* cb = isPositioned() ? container() : containingBlock(); while (cb->isAnonymous()) { cb = cb->containingBlock(); toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this)); } if (cb->isPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) { ASSERT(cb->isRenderBlock()); RenderBlock* block = toRenderBlock(cb); int oldHeight = block->height(); block->calcHeight(); int newHeight = block->calcContentBoxHeight(block->contentHeight()); block->setHeight(oldHeight); return calcContentBoxHeight(height.calcValue(newHeight)); } int availableHeight = isPositioned() ? containingBlockHeightForPositioned(toRenderBoxModelObject(cb)) : toRenderBox(cb)->availableHeight(); // It is necessary to use the border-box to match WinIE's broken // box model. This is essential for sizing inside // table cells using percentage heights. if (cb->isTableCell() && (cb->style()->height().isAuto() || cb->style()->height().isPercent())) { // Don't let table cells squeeze percent-height replaced elements // <http://bugs.webkit.org/show_bug.cgi?id=15359> availableHeight = max(availableHeight, intrinsicSize().height()); return height.calcValue(availableHeight - (borderTop() + borderBottom() + paddingTop() + paddingBottom())); } return calcContentBoxHeight(height.calcValue(availableHeight)); } default: return intrinsicSize().height(); }}int RenderBox::availableHeight() const{ return availableHeightUsing(style()->height());}int RenderBox::availableHeightUsing(const Length& h) const{ if (h.isFixed()) return calcContentBoxHeight(h.value()); if (isRenderView()) return toRenderView(this)->frameView()->visibleHeight(); // We need to stop here, since we don't want to increase the height of the table // artificially. We're going to rely on this cell getting expanded to some new // height, and then when we lay out again we'll use the calculation below. if (isTableCell() && (h.isAuto() || h.isPercent())) return overrideSize() - (borderLeft() + borderRight() + paddingLeft() + paddingRight()); if (h.isPercent()) return calcContentBoxHeight(h.calcValue(containingBlock()->availableHeight())); if (isRenderBlock() && isPositioned() && style()->height().isAuto() && !(style()->top().isAuto() || style()->bottom().isAuto())) { RenderBlock* block = const_cast<RenderBlock*>(toRenderBlock(this)); int oldHeight = block->height(); block->calcHeight(); int newHeight = block->calcContentBoxHeight(block->contentHeight()); block->setHeight(oldHeight); return calcContentBoxHeight(newHeight); } return containingBlock()->availableHeight();}void RenderBox::calcVerticalMargins(){ if (isTableCell()) { m_marginTop = 0; m_marginBottom = 0; return; } // margins are calculated with respect to the _width_ of // the containing block (8.3) int cw = containingBlock()->contentWidth(); m_marginTop = style()->marginTop().calcMinValue(cw); m_marginBottom = style()->marginBottom().calcMinValue(cw);}int RenderBox::containingBlockWidthForPositioned(const RenderBoxModelObject* containingBlock) const{ if (containingBlock->isBox()) { const RenderBox* containingBlockBox = toRenderBox(containingBlock); return containingBlockBox->width() - containingBlockBox->borderLeft() - containingBlockBox->borderRight() - containingBlockBox->verticalScrollbarWidth(); } ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned()); const RenderInline* flow = toRenderInline(containingBlock); InlineFlowBox* first = flow->firstLineBox(); InlineFlowBox* last = flow->lastLineBox(); // If the containing block is empty, return a width of 0. if (!first || !last) return 0; int fromLeft; int fromRight; if (containingBlock->style()->direction() == LTR) { fromLeft = first->x() + first->borderLeft(); fromRight = last->x() + last->width() - last->borderRight(); } else { fromRight = first->x() + first->width() - first->borderRight(); fromLeft = last->x() + last->borderLeft(); } return max(0, (fromRight - fromLeft));}int RenderBox::containingBlockHeightForPositioned(const RenderBoxModelObject* containingBlock) const{ int heightResult = 0; if (containingBlock->isBox()) heightResult = toRenderBox(containingBlock)->height(); else if (containingBlock->isRenderInline()) { ASSERT(containingBlock->isRelPositioned()); heightResult = toRenderInline(containingBlock)->linesBoundingBox().height(); } return heightResult - containingBlock->borderTop() - containingBlock->borderBottom();}void RenderBox::calcAbsoluteHorizontal(){ if (isReplaced()) { calcAbsoluteHorizontalReplaced(); return; } // QUESTIONS // FIXME 1: Which RenderObject's 'direction' property should used: the // containing block (cb) as the spec seems to imply, the parent (parent()) as // was previously done
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -