📄 render_block.cpp
字号:
int posTop = child->maxTopMargin(true); int negTop = child->maxTopMargin(false); // For self-collapsing blocks, collapse our bottom margins into our // top to get new posTop and negTop values. if (child->isSelfCollapsingBlock()) { posTop = kMax(posTop, (int)child->maxBottomMargin(true)); negTop = kMax(negTop, (int)child->maxBottomMargin(false)); } // See if the top margin is quirky. We only care if this child has // margins that will collapse with us. bool topQuirk = child->isTopMarginQuirk() /*|| style()->marginTopCollapse() == MDISCARD*/; if (marginInfo.canCollapseWithTop()) { // This child is collapsing with the top of the // block. If it has larger margin values, then we need to update // our own maximal values. if (!style()->htmlHacks() || !marginInfo.quirkContainer() || !topQuirk) { m_maxTopPosMargin = kMax(posTop, (int)m_maxTopPosMargin); m_maxTopNegMargin = kMax(negTop, (int)m_maxTopNegMargin); } // The minute any of the margins involved isn't a quirk, don't // collapse it away, even if the margin is smaller (www.webreference.com // has an example of this, a <dt> with 0.8em author-specified inside // a <dl> inside a <td>. if (!marginInfo.determinedTopQuirk() && !topQuirk && (posTop-negTop)) { m_topMarginQuirk = false; marginInfo.setDeterminedTopQuirk(true); } if (!marginInfo.determinedTopQuirk() && topQuirk && marginTop() == 0) // We have no top margin and our top child has a quirky margin. // We will pick up this quirky margin and pass it through. // This deals with the <td><div><p> case. // Don't do this for a block that split two inlines though. You do // still apply margins in this case. m_topMarginQuirk = true; } if (marginInfo.quirkContainer() && marginInfo.atTopOfBlock() && (posTop - negTop)) marginInfo.setTopQuirk(topQuirk); int ypos = m_height; if (child->isSelfCollapsingBlock()) { // This child has no height. We need to compute our // position before we collapse the child's margins together, // so that we can get an accurate position for the zero-height block. int collapsedTopPos = kMax(marginInfo.posMargin(), (int)child->maxTopMargin(true)); int collapsedTopNeg = kMax(marginInfo.negMargin(), (int)child->maxTopMargin(false)); marginInfo.setMargin(collapsedTopPos, collapsedTopNeg); // Now collapse the child's margins together, which means examining our // bottom margin values as well. marginInfo.setPosMarginIfLarger(child->maxBottomMargin(true)); marginInfo.setNegMarginIfLarger(child->maxBottomMargin(false)); if (!marginInfo.canCollapseWithTop()) // We need to make sure that the position of the self-collapsing block // is correct, since it could have overflowing content // that needs to be positioned correctly (e.g., a block that // had a specified height of 0 but that actually had subcontent). ypos = m_height + collapsedTopPos - collapsedTopNeg; } else {#ifdef APPLE_CHANGES if (child->style()->marginTopCollapse() == MSEPARATE) { m_height += marginInfo.margin() + child->marginTop(); ypos = m_height; } else#endif if (!marginInfo.atTopOfBlock() || (!marginInfo.canCollapseTopWithChildren() && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.topQuirk()))) { // We're collapsing with a previous sibling's margins and not // with the top of the block. m_height += kMax(marginInfo.posMargin(), posTop) - kMax(marginInfo.negMargin(), negTop); ypos = m_height; } marginInfo.setPosMargin(child->maxBottomMargin(true)); marginInfo.setNegMargin(child->maxBottomMargin(false)); if (marginInfo.margin()) marginInfo.setBottomQuirk(child->isBottomMarginQuirk() /*|| style()->marginBottomCollapse() == MDISCARD*/); marginInfo.setSelfCollapsingBlockClearedFloat(false); } child->setPos(child->xPos(), ypos); if (ypos != yPosEstimate) { if (child->style()->width().isPercent() && child->usesLineWidth()) // The child's width is a percentage of the line width. // When the child shifts to clear an item, its width can // change (because it has more available line width). // So go ahead and mark the item as dirty. child->setChildNeedsLayout(true); if (!child->flowAroundFloats() || child->hasFloats()) child->markAllDescendantsWithFloatsForLayout(); // Our guess was wrong. Make the child lay itself out again. child->layoutIfNeeded(); }}void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin){ int heightIncrease = getClearDelta(child); if (heightIncrease) { // The child needs to be lowered. Move the child so that it just clears the float. child->setPos(child->xPos(), child->yPos() + heightIncrease); // Increase our height by the amount we had to clear. if (!child->isSelfCollapsingBlock()) m_height += heightIncrease; else { // For self-collapsing blocks that clear, they may end up collapsing // into the bottom of the parent block. We simulate this behavior by // setting our positive margin value to compensate for the clear. marginInfo.setPosMargin(kMax(0, child->yPos() - m_height)); marginInfo.setNegMargin(0); marginInfo.setSelfCollapsingBlockClearedFloat(true); } if (marginInfo.canCollapseWithTop()) { // We can no longer collapse with the top of the block since a clear // occurred. The empty blocks collapse into the cleared block. // FIXME: This isn't quite correct. Need clarification for what to do // if the height the cleared block is offset by is smaller than the // margins involved. m_maxTopPosMargin = oldTopPosMargin; m_maxTopNegMargin = oldTopNegMargin; marginInfo.setAtTopOfBlock(false); } // If our value of clear caused us to be repositioned vertically to be // underneath a float, we might have to do another layout to take into account // the extra space we now have available. if (!child->style()->width().isFixed() && child->usesLineWidth()) // The child's width is a percentage of the line width. // When the child shifts to clear an item, its width can // change (because it has more available line width). // So go ahead and mark the item as dirty. child->setChildNeedsLayout(true); if (child->hasFloats()) child->markAllDescendantsWithFloatsForLayout(); child->layoutIfNeeded(); }}bool RenderBlock::canClear(RenderObject *child, PageBreakLevel level){ KHTMLAssert(child->parent() && child->parent() == this); KHTMLAssert(canvas()->pagedMode()); // Positioned elements cannot be moved. Only normal flow and floating. if (child->isPositioned() || child->isRelPositioned()) return false; switch(level) { case PageBreakNormal: // check page-break-inside: avoid if (!style()->pageBreakInside()) // we cannot, but can our parent? if(!parent()->canClear(this, level)) return false; case PageBreakHarder: // check page-break-after/before: avoid if (m_avoidPageBreak) // we cannot, but can our parent? if(!parent()->canClear(this, level)) return false; case PageBreakForced: // child is larger than page-height and is forced to break if(child->height() > canvas()->pageHeight()) return false; return true; } assert(false); return false;}void RenderBlock::clearPageBreak(RenderObject* child, int pageBottom){ KHTMLAssert(child->parent() && child->parent() == this); KHTMLAssert(canvas()->pagedMode()); if (child->yPos() >= pageBottom) return; int heightIncrease = 0; heightIncrease = pageBottom - child->yPos(); // ### should never happen, canClear should have been called to detect it. if (child->height() > canvas()->pageHeight()) { kdDebug(6040) << "### child is too large to clear: " << child->height() << " > " << canvas()->pageHeight() << endl; return; } // The child needs to be lowered. Move the child so that it just clears the break. child->setPos(child->xPos(), pageBottom);#ifdef PAGE_DEBUG kdDebug(6040) << "Cleared block " << heightIncrease << "px" << endl;#endif // Increase our height by the amount we had to clear. m_height += heightIncrease; // We might have to do another layout to take into account // the extra space we now have available. if (!child->style()->width().isFixed() && child->usesLineWidth()) // The child's width is a percentage of the line width. // When the child shifts to clear a page-break, its width can // change (because it has more available line width). // So go ahead and mark the item as dirty. child->setChildNeedsLayout(true); if (child->hasFloats()) child->markAllDescendantsWithFloatsForLayout(); if (child->containsPageBreak()) child->setNeedsLayout(true); child->layoutIfNeeded(); child->setAfterPageBreak(true);}int RenderBlock::estimateVerticalPosition(RenderObject* child, const MarginInfo& marginInfo){ // FIXME: We need to eliminate the estimation of vertical position, because // when it's wrong we sometimes trigger a pathological relayout if there are // intruding floats. int yPosEstimate = m_height; if (!marginInfo.canCollapseWithTop()) { int childMarginTop = child->selfNeedsLayout() ? child->marginTop() : child->collapsedMarginTop(); yPosEstimate += kMax(marginInfo.margin(), childMarginTop); } return yPosEstimate;}void RenderBlock::determineHorizontalPosition(RenderObject* child){ if (style()->direction() == LTR) { int xPos = borderLeft() + paddingLeft(); // Add in our left margin. int chPos = xPos + child->marginLeft(); // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need // to shift over as necessary to dodge any floats that might get in the way. if (child->flowAroundFloats()) { int leftOff = leftOffset(m_height); if (style()->textAlign() != KHTML_CENTER && !child->style()->marginLeft().isVariable()) { if (child->marginLeft() < 0) leftOff += child->marginLeft(); chPos = kMax(chPos, leftOff); // Let the float sit in the child's margin if it can fit. } else if (leftOff != xPos) { // The object is shifting right. The object might be centered, so we need to // recalculate our horizontal margins. Note that the containing block content // width computation will take into account the delta between |leftOff| and |xPos| // so that we can just pass the content width in directly to the |calcHorizontalMargins| // function. static_cast<RenderBox*>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos())); chPos = leftOff + child->marginLeft(); } } child->setPos(chPos, child->yPos()); } else { int xPos = m_width - borderRight() - paddingRight(); if (m_layer && style()->scrollsOverflow()) xPos -= m_layer->verticalScrollbarWidth(); int chPos = xPos - (child->width() + child->marginRight()); if (child->flowAroundFloats()) { int rightOff = rightOffset(m_height); if (style()->textAlign() != KHTML_CENTER && !child->style()->marginRight().isVariable()) { if (child->marginRight() < 0) rightOff -= child->marginRight(); chPos = kMin(chPos, rightOff - child->width()); // Let the float sit in the child's margin if it can fit. } else if (rightOff != xPos) { // The object is shifting left. The object might be centered, so we need to // recalculate our horizontal margins. Note that the containing block content // width computation will take into account the delta between |rightOff| and |xPos| // so that we can just pass the content width in directly to the |calcHorizontalMargins| // function. static_cast<RenderBox*>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos())); chPos = rightOff - child->marginRight() - child->width(); } } child->setPos(chPos, child->yPos()); }}void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo){ if (marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop()) { // Update our max pos/neg bottom margins, since we collapsed our bottom margins // with our children. m_maxBottomPosMargin = kMax((int)m_maxBottomPosMargin, marginInfo.posMargin()); m_maxBottomNegMargin = kMax((int)m_maxBottomNegMargin, marginInfo.negMargin()); if (!marginInfo.bottomQuirk()) m_bottomMarginQuirk = false; if (marginInfo.bottomQuirk() && marginBottom() == 0) // We have no bottom margin and our last child has a quirky margin. // We will pick up this quirky margin and pass it through. // This deals with the <td><div><p> case. m_bottomMarginQuirk = true; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -