📄 render_block.cpp
字号:
// Move the scrollbars aside during layout. The layer will move them back when it // does painting or event handling. m_layer->moveScrollbarsAside(); } // A quirk that has become an unfortunate standard. Positioned elements, floating elements // and table cells don't ever collapse their margins with either themselves or their // children. bool canCollapseOwnMargins = !isPositioned() && !isFloating() && !isTableCell(); setContainsPageBreak(false); if (childrenInline()) layoutInlineChildren( relayoutChildren ); else layoutBlockChildren( relayoutChildren ); // Expand our intrinsic height to encompass floats. int toAdd = borderBottom() + paddingBottom(); if (m_layer && style()->scrollsOverflow() && style()->height().isVariable()) toAdd += m_layer->horizontalScrollbarHeight(); if ( hasOverhangingFloats() && (isFloatingOrPositioned() || flowAroundFloats()) ) m_overflowHeight = m_height = floatBottom() + toAdd; int 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; } if (isTableCell()) { // Table cells need to grow to accommodate both overhanging floats and // blocks that have overflowed content. // Check for an overhanging float first. // FIXME: This needs to look at the last flow, not the last child. if (lastChild() && lastChild()->hasOverhangingFloats() && !lastChild()->style()->hidesOverflow()) { KHTMLAssert(lastChild()->isRenderBlock()); m_height = lastChild()->yPos() + static_cast<RenderBlock*>(lastChild())->floatBottom(); m_height += borderBottom() + paddingBottom(); } if (m_overflowHeight > m_height && !style()->hidesOverflow()) m_height = m_overflowHeight + borderBottom() + paddingBottom(); } if( hasOverhangingFloats() && ((isFloating() && style()->height().isVariable()) || isTableCell())) { m_height = floatBottom(); m_height += borderBottom() + paddingBottom(); } if (canvas()->pagedMode()) {#ifdef PAGE_DEBUG kdDebug(6040) << renderName() << " Page Bottom: " << pageTopAfter(0) << endl; kdDebug(6040) << renderName() << " Bottom: " << m_height << endl;#endif bool needsPageBreak = false; int xpage = crossesPageBreak(0, m_height); if (xpage) { needsPageBreak = true;#ifdef PAGE_DEBUG kdDebug( 6040 ) << renderName() << " crosses to page " << xpage << endl;#endif } if (needsPageBreak && !containsPageBreak()) { setNeedsPageClear(true);#ifdef PAGE_DEBUG kdDebug( 6040 ) << renderName() << " marked for page-clear" << endl;#endif } } layoutPositionedObjects( relayoutChildren ); // Always ensure our overflow width/height are at least as large as our width/height. m_overflowWidth = kMax(m_overflowWidth, (int)m_width); m_overflowHeight = kMax(m_overflowHeight, m_height); if (canCollapseOwnMargins && 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; } // Update our scrollbars if we're overflow:auto/scroll now that we know if // we overflow or not. if (style()->hidesOverflow() && m_layer) m_layer->checkScrollbarsAfterLayout(); setNeedsLayout(false);}void RenderBlock::adjustPositionedBlock(RenderObject* child, const MarginInfo& marginInfo){ if (child->isBox() && child->hasStaticX()) { if (style()->direction() == LTR) static_cast<RenderBox*>(child)->setStaticX(borderLeft() + paddingLeft()); else static_cast<RenderBox*>(child)->setStaticX(borderRight() + paddingRight()); } if (child->isBox() && child->hasStaticY()) { int marginOffset = 0; if (!marginInfo.canCollapseWithTop()) { int collapsedTopPos = marginInfo.posMargin(); int collapsedTopNeg = marginInfo.negMargin(); bool posMargin = child->marginTop() >= 0; if (posMargin && child->marginTop() > collapsedTopPos) collapsedTopPos = child->marginTop(); else if (!posMargin && child->marginTop() > collapsedTopNeg) collapsedTopNeg = child->marginTop(); marginOffset += (collapsedTopPos - collapsedTopNeg) - child->marginTop(); } static_cast<RenderBox*>(child)->setStaticY(m_height + marginOffset); }}void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo){ // The float should be positioned taking into account the bottom margin // of the previous flow. We add that margin into the height, get the // float positioned properly, and then subtract the margin out of the // height again. In the case of self-collapsing blocks, we always just // use the top margins, since the self-collapsing block collapsed its // own bottom margin into its top margin. // // Note also that the previous flow may collapse its margin into the top of // our block. If this is the case, then we do not add the margin in to our // height when computing the position of the float. This condition can be tested // for by simply calling canCollapseWithTop. See // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for // an example of this scenario. int marginOffset = marginInfo.canCollapseWithTop() ? 0 : marginInfo.margin(); m_height += marginOffset; positionNewFloats(); m_height -= marginOffset;}RenderObject* RenderBlock::handleSpecialChild(RenderObject* child, const MarginInfo& marginInfo, CompactInfo& compactInfo, bool& handled){ // Handle positioned children first. RenderObject* next = handlePositionedChild(child, marginInfo, handled); if (handled) return next; // Handle floating children next. next = handleFloatingChild(child, marginInfo, handled); if (handled) return next; // See if we have a compact element. If we do, then try to tuck the compact element into the margin space of the next block. next = handleCompactChild(child, compactInfo, marginInfo, handled); if (handled) return next; // Finally, see if we have a run-in element. return handleRunInChild(child, handled);}RenderObject* RenderBlock::handlePositionedChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled){ if (child->isPositioned()) { handled = true; child->containingBlock()->insertPositionedObject(child); adjustPositionedBlock(child, marginInfo); return child->nextSibling(); } return 0;}RenderObject* RenderBlock::handleFloatingChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled){ if (child->isFloating()) { handled = true; insertFloatingObject(child); adjustFloatingBlock(marginInfo); return child->nextSibling(); } return 0;}static inline bool isAnonymousWhitespace( RenderObject* o ) { if (!o->isAnonymous()) return false; RenderObject *fc = o->firstChild(); return fc && fc == o->lastChild() && fc->isText() && static_cast<RenderText *>(fc)->stringLength() == 1 && static_cast<RenderText *>(fc)->text()[0].unicode() == ' ';}RenderObject* RenderBlock::handleCompactChild(RenderObject* child, CompactInfo& compactInfo, const MarginInfo& marginInfo, bool& handled){ // FIXME: We only deal with one compact at a time. It is unclear what should be // done if multiple contiguous compacts are encountered. For now we assume that // compact A followed by another compact B should simply be treated as block A. if (child->isCompact() && !compactInfo.compact() && (child->childrenInline() || child->isReplaced())) { // Get the next non-positioned/non-floating RenderBlock. RenderObject* next = child->nextSibling(); RenderObject* curr = next; while (curr && (curr->isFloatingOrPositioned() || isAnonymousWhitespace(curr)) ) curr = curr->nextSibling(); if (curr && curr->isRenderBlock() && !curr->isCompact() && !curr->isRunIn()) { curr->calcWidth(); // So that horizontal margins are correct. // Need to compute margins for the child as though it is a block. child->style()->setDisplay(BLOCK); child->calcWidth(); child->style()->setDisplay(COMPACT); int childMargins = child->marginLeft() + child->marginRight(); int margin = style()->direction() == LTR ? curr->marginLeft() : curr->marginRight(); if (margin >= (childMargins + child->maxWidth())) { // The compact will fit in the margin. handled = true; compactInfo.set(child, curr); child->layoutIfNeeded(); int off = marginInfo.margin(); m_height += off + curr->marginTop() < child->marginTop() ? child->marginTop() - curr->marginTop() -off: 0; child->setPos(0,0); // This position will be updated to reflect the compact's // desired position and the line box for the compact will // pick that position up. return next; } } } return 0;}void RenderBlock::insertCompactIfNeeded(RenderObject* child, CompactInfo& compactInfo){ if (compactInfo.matches(child)) { // We have a compact child to squeeze in. RenderObject* compactChild = compactInfo.compact(); int compactXPos = borderLeft() + paddingLeft() + compactChild->marginLeft(); if (style()->direction() == RTL) { compactChild->calcWidth(); // have to do this because of the capped maxwidth compactXPos = width() - borderRight() - paddingRight() - compactChild->width() - compactChild->marginRight(); } int compactYPos = child->yPos() + child->borderTop() + child->paddingTop() - compactChild->paddingTop() - compactChild->borderTop(); int adj = 0; KHTMLAssert(child->isRenderBlock()); InlineRunBox *b = static_cast<RenderBlock*>(child)->firstLineBox(); InlineRunBox *c = static_cast<RenderBlock*>(compactChild)->firstLineBox(); if (b && c) { // adjust our vertical position int vpos = compactChild->getVerticalPosition( true, child ); if (vpos == PositionBottom) adj = b->height() > c->height() ? (b->height() + b->yPos() - c->height() - c->yPos()) : 0; else if (vpos == PositionTop) adj = b->yPos() - c->yPos(); else adj = vpos; compactYPos += adj; } Length newLineHeight( kMax(compactChild->lineHeight(true)+adj, (int)child->lineHeight(true)), khtml::Fixed); child->style()->setLineHeight( newLineHeight ); child->setNeedsLayout( true, false ); child->layout(); compactChild->setPos(compactXPos, compactYPos); // Set the x position. compactInfo.clear(); }}RenderObject* RenderBlock::handleRunInChild(RenderObject* child, bool& handled){ // See if we have a run-in element with inline children. If the // children aren't inline, then just treat the run-in as a normal // block. if (child->isRunIn() && (child->childrenInline() || child->isReplaced())) { // Get the next non-positioned/non-floating RenderBlock. RenderObject* curr = child->nextSibling(); while (curr && (curr->isFloatingOrPositioned() || isAnonymousWhitespace(curr)) ) curr = curr->nextSibling(); if (curr && (curr->isRenderBlock() && curr->childrenInline() && !curr->isCompact() && !curr->isRunIn())) { // The block acts like an inline, so just null out its // position. handled = true; child->setInline(true); child->setPos(0,0); // Remove the child. RenderObject* next = child->nextSibling(); removeChildNode(child); // Now insert the child under |curr|. curr->insertChildNode(child, curr->firstChild()); return next; } } return 0;}void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, int yPosEstimate){ // Get our max pos and neg top margins.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -