📄 render_block.cpp
字号:
// The remerge has knocked us down to containing only a single anonymous // box. We can go ahead and pull the content right back up into our // box. RenderObject* anonBlock = removeChildNode(prev); m_childrenInline = true; RenderObject* o = anonBlock->firstChild(); while (o) { RenderObject* no = o; o = no->nextSibling(); appendChildNode(anonBlock->removeChildNode(no)); no->setNeedsLayoutAndMinMaxRecalc(); } // Nuke the now-empty block. anonBlock->detach(); }}bool RenderBlock::isSelfCollapsingBlock() const{ // We are not self-collapsing if we // (a) have a non-zero height according to layout (an optimization to avoid wasting time) // (b) are a table, // (c) have border/padding, // (d) have a min-height if (m_height > 0 || isTable() || (borderBottom() + paddingBottom() + borderTop() + paddingTop()) != 0 || style()->minHeight().value > 0) return false; // If the height is 0 or auto, then whether or not we are a self-collapsing block depends // on whether we have content that is all self-collapsing or not. if (style()->height().isVariable() || (style()->height().isFixed() && style()->height().value == 0)) { // If the block has inline children, see if we generated any line boxes. If we have any // line boxes, then we can't be self-collapsing, since we have content. if (childrenInline()) return !firstLineBox(); // Whether or not we collapse is dependent on whether all our normal flow children // are also self-collapsing. for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isFloatingOrPositioned()) continue; if (!child->isSelfCollapsingBlock()) return false; } return true; } return false;}void RenderBlock::layout(){ // Table cells call layoutBlock directly, so don't add any logic here. Put code into // layoutBlock(). layoutBlock(false);}void RenderBlock::layoutBlock(bool relayoutChildren){ // kdDebug( 6040 ) << renderName() << " " << this << "::layoutBlock() start" << endl; // QTime t; // t.start(); KHTMLAssert( needsLayout() ); KHTMLAssert( minMaxKnown() ); if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can return; // cause us to come in here. Just bail. -dwh if (!relayoutChildren && posChildNeedsLayout() && !normalChildNeedsLayout() && !selfNeedsLayout()) { // All we have to is lay out our positioned objects. layoutPositionedObjects(relayoutChildren); if (hasOverflowClip()) m_layer->updateScrollInfoAfterLayout(); setNeedsLayout(false); return; } QRect oldBounds, oldFullBounds; bool checkForRepaint = checkForRepaintDuringLayout(); if (checkForRepaint) getAbsoluteRepaintRectIncludingFloats(oldBounds, oldFullBounds); int oldWidth = m_width; calcWidth(); m_overflowWidth = m_width; if ( oldWidth != m_width ) relayoutChildren = true; // kdDebug( 6040 ) << floatingObjects << "," << oldWidth << "," // << m_width << ","<< needsLayout() << "," << isAnonymous() << "," // << "," << isPositioned() << endl;#ifdef DEBUG_LAYOUT kdDebug( 6040 ) << renderName() << "(RenderBlock) " << this << " ::layout() width=" << m_width << ", needsLayout=" << needsLayout() << endl; if(containingBlock() == static_cast<RenderObject *>(this)) kdDebug( 6040 ) << renderName() << ": containingBlock == this" << endl;#endif clearFloats(); m_height = 0; m_overflowHeight = 0; m_clearStatus = CNONE; // We use four values, maxTopPos, maxPosNeg, maxBottomPos, and maxBottomNeg, to track // our current maximal positive and negative margins. These values are used when we // are collapsed with adjacent blocks, so for example, if you have block A and B // collapsing together, then you'd take the maximal positive margin from both A and B // and subtract it from the maximal negative margin from both A and B to get the // true collapsed margin. This algorithm is recursive, so when we finish layout() // our block knows its current maximal positive/negative values. // // Start out by setting our margin values to our current margins. Table cells have // no margins, so we don't fill in the values for table cells. if (!isTableCell()) { initMaxMarginValues(); m_topMarginQuirk = style()->marginTop().quirk; m_bottomMarginQuirk = style()->marginBottom().quirk; if (element() && element()->id() == ID_FORM && element()->isMalformed()) // See if this form is malformed (i.e., unclosed). If so, don't give the form // a bottom margin. m_maxBottomPosMargin = m_maxBottomNegMargin = 0; } if (scrollsOverflow()) { // For overflow:scroll blocks, ensure we have both scrollbars in place always. if (style()->overflow() == OSCROLL) { m_layer->setHasHorizontalScrollbar(true); m_layer->setHasVerticalScrollbar(true); } // Move the scrollbars aside during layout. The layer will move them back when it // does painting or event handling. m_layer->moveScrollbarsAside(); } // kdDebug( 6040 ) << "childrenInline()=" << childrenInline() << endl; QRect repaintRect(0,0,0,0); if (childrenInline()) repaintRect = layoutInlineChildren( relayoutChildren ); else layoutBlockChildren( relayoutChildren ); // Expand our intrinsic height to encompass floats. int toAdd = borderBottom() + paddingBottom(); if (includeScrollbarSize()) toAdd += m_layer->horizontalScrollbarHeight(); if ( hasOverhangingFloats() && (isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBox())) ) 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 -= paddingBottom() + borderBottom(); 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()) { KHTMLAssert(lastChild()->isRenderBlock()); m_height = lastChild()->yPos() + static_cast<RenderBlock*>(lastChild())->floatBottom(); m_height += borderBottom() + paddingBottom(); } if (m_overflowHeight > m_height && !hasOverflowClip()) m_height = m_overflowHeight + borderBottom() + paddingBottom(); } if( hasOverhangingFloats() && (isFloating() || isTableCell())) { m_height = floatBottom(); m_height += borderBottom() + paddingBottom(); } layoutPositionedObjects( relayoutChildren ); //kdDebug() << renderName() << " layout width=" << m_width << " height=" << m_height << endl; // Always ensure our overflow width/height are at least as large as our width/height. if (m_overflowWidth < m_width) m_overflowWidth = m_width; if (m_overflowHeight < m_height) m_overflowHeight = m_height; // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if // we overflow or not. if (hasOverflowClip()) m_layer->updateScrollInfoAfterLayout(); // Repaint with our new bounds if they are different from our old bounds. bool didFullRepaint = false; if (checkForRepaint) didFullRepaint = repaintAfterLayoutIfNeeded(oldBounds, oldFullBounds); if (!didFullRepaint && !repaintRect.isEmpty()) { RenderCanvas* c = canvas(); if (c && c->view()) c->view()->addRepaintInfo(this, repaintRect); // We need to do a partial repaint of our content. } setNeedsLayout(false);}void RenderBlock::layoutBlockChildren( bool relayoutChildren ){#ifdef DEBUG_LAYOUT kdDebug( 6040 ) << renderName() << " layoutBlockChildren( " << this <<" ), relayoutChildren="<< relayoutChildren << endl;#endif int xPos = borderLeft() + paddingLeft(); if( style()->direction() == RTL ) xPos = m_width - paddingRight() - borderRight(); int toAdd = borderBottom() + paddingBottom(); if (includeScrollbarSize()) toAdd += m_layer->horizontalScrollbarHeight(); m_height = borderTop() + paddingTop(); // Fieldsets need to find their legend and position it inside the border of the object. // The legend then gets skipped during normal layout. RenderObject* legend = layoutLegend(relayoutChildren); int minHeight = m_height + toAdd; m_overflowHeight = m_height; RenderObject* child = firstChild(); RenderBlock* prevFlow = 0; RenderObject* prevBlock = 0; // A compact child that needs to be collapsed into the margin of the following block. RenderObject* compactChild = 0; // The block with the open margin that the compact child is going to place itself within. RenderObject* blockForCompactChild = 0; // For compact children that don't fit, we lay them out as though they are blocks. This // boolean allows us to temporarily treat a compact like a block and lets us know we need // to turn the block back into a compact when we're done laying out. bool treatCompactAsBlock = false; // Whether or not we can collapse our own margins with our children. We don't do this // if we had any border/padding (obviously), if we're the root or HTML elements, or if // we're positioned, floating, a table cell. // For now we only worry about the top border/padding. We will update the variable's // value when it comes time to check against the bottom border/padding. bool canCollapseWithChildren = !isCanvas() && !isRoot() && !isPositioned() && !isFloating() && !isTableCell() && !hasOverflowClip() && !isInlineBlockOrInlineTable(); bool canCollapseTopWithChildren = canCollapseWithChildren && (m_height == 0); // If any height other than auto is specified in CSS, then we don't collapse our bottom // margins with our children's margins. To do otherwise would be to risk odd visual // effects when the children overflow out of the parent block and yet still collapse // with it. We also don't collapse if we had any bottom border/padding (represented by // |toAdd|). bool canCollapseBottomWithChildren = canCollapseWithChildren && (toAdd == 0) && (style()->height().isVariable() && style()->height().value == 0); // Whether or not we are a quirky container, i.e., do we collapse away top and bottom // margins in our container. bool quirkContainer = isTableCell() || isBody(); // This flag tracks whether the child should collapse with the top margins of the block. // It can remain set through multiple iterations as long as we keep encountering // self-collapsing blocks. bool topMarginContributor = true; // These flags track the previous maximal positive and negative margins. int prevPosMargin = canCollapseTopWithChildren ? maxTopMargin(true) : 0; int prevNegMargin = canCollapseTopWithChildren ? maxTopMargin(false) : 0; // Whether or not we encountered an element with clear set that actually had to // be pushed down below a float. bool clearOccurred = false; // If our last normal flow child was a self-collapsing block that cleared a float, // we track it in this variable. bool selfCollapsingBlockClearedFloat = false; bool topChildQuirk = false; bool bottomChildQuirk = false; bool determinedTopQuirk = false; bool strictMode = !style()->htmlHacks(); //kdDebug() << "RenderBlock::layoutBlockChildren " << prevMargin << endl; // QTime t; // t.start(); while( child != 0 ) { // Sometimes an element will be shoved down away from a previous sibling, e.g., when // clearing to pass beyond a float. In this case, you don't need to collapse. This // boolean is updated with each iteration through our child list to reflect whether // that particular child should be collapsed with its previous sibling (or with the top // of the block). bool shouldCollapseChild = true; int oldTopPosMargin = m_maxTopPosMargin;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -