📄 render_block.cpp
字号:
(!next || (next->isAnonymousBlock() && next->childrenInline()));
if (canDeleteAnonymousBlocks && prev && next) {
// Take all the children out of the |next| block and put them in
// the |prev| block.
prev->setNeedsLayoutAndMinMaxRecalc();
RenderObject* o = next->firstChild();
while (o) {
RenderObject* no = o;
o = no->nextSibling();
prev->appendChildNode(next->removeChildNode(no));
no->setNeedsLayoutAndMinMaxRecalc();
}
// Nuke the now-empty block.
next->detach();
}
RenderFlow::removeChild(oldChild);
RenderObject* child = prev ? prev : next;
if (canDeleteAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling()) {
// The removal 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.
setNeedsLayoutAndMinMaxRecalc();
RenderObject* anonBlock = removeChildNode(child);
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();
}
}
int RenderBlock::overflowHeight(bool includeInterior) const
{
return (!includeInterior && hasOverflowClip()) ? m_height : m_overflowHeight;
}
int RenderBlock::overflowWidth(bool includeInterior) const
{
return (!includeInterior && hasOverflowClip()) ? m_width : m_overflowWidth;
}
int RenderBlock::overflowLeft(bool includeInterior) const
{
return (!includeInterior && hasOverflowClip()) ? 0 : m_overflowLeft;
}
int RenderBlock::overflowTop(bool includeInterior) const
{
return (!includeInterior && hasOverflowClip()) ? 0 : m_overflowTop;
}
QRect RenderBlock::overflowRect(bool includeInterior) const
{
if (!includeInterior && hasOverflowClip())
return borderBox();
int l = overflowLeft(includeInterior);
int t = kMin(overflowTop(includeInterior), -borderTopExtra());
return QRect(l, t, m_overflowWidth - 2*l, m_overflowHeight + borderTopExtra() + borderBottomExtra() - 2*t);
}
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
// (e) have specified that one of our margins can't collapse using a CSS extension
if (m_height > 0 ||
isTable() || (borderBottom() + paddingBottom() + borderTop() + paddingTop()) != 0 ||
style()->minHeight().value > 0 ||
style()->marginTopCollapse() == MSEPARATE || style()->marginBottomCollapse() == MSEPARATE)
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)
{
KHTMLAssert(needsLayout());
KHTMLAssert(minMaxKnown());
if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can
return; // cause us to come in here. Just bail.
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;
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();
}
QRect repaintRect;
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 );
// Always ensure our overflow width/height are at least as large as our width/height.
m_overflowWidth = kMax(m_overflowWidth, m_width);
m_overflowHeight = kMax(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::adjustPositionedBlock(RenderObject* child, const MarginInfo& marginInfo)
{
if (child->hasStaticX()) {
if (style()->direction() == LTR)
child->setStaticX(borderLeft() + paddingLeft());
else
child->setStaticX(borderRight() + paddingRight());
}
if (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();
}
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -