📄 renderblock.cpp
字号:
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. setBottomMarginQuirk(true); }}void RenderBlock::handleBottomOfBlock(int top, int bottom, MarginInfo& marginInfo){ // If our last flow was a self-collapsing block that cleared a float, then we don't // collapse it with the bottom of the block. if (!marginInfo.selfCollapsingBlockClearedFloat()) marginInfo.setAtBottomOfBlock(true); else { // We have to special case the negative margin situation (where the collapsed // margin of the self-collapsing block is negative), since there's no need // to make an adjustment in that case. if (marginInfo.margin() < 0) marginInfo.clearMargin(); } // If we can't collapse with children then go ahead and add in the bottom margin. if (!marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop() && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.bottomQuirk())) setHeight(height() + marginInfo.margin()); // Now add in our bottom border/padding. setHeight(height() + bottom); // Negative margins can cause our height to shrink below our minimal height (border/padding). // If this happens, ensure that the computed height is increased to the minimal height. setHeight(max(height(), top + bottom)); // Always make sure our overflow height is at least our height. m_overflowHeight = max(height(), m_overflowHeight); // Update our bottom collapsed margin info. setCollapsedBottomMargin(marginInfo);}void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom){ if (gPercentHeightDescendantsMap) { if (HashSet<RenderBox*>* descendants = gPercentHeightDescendantsMap->get(this)) { HashSet<RenderBox*>::iterator end = descendants->end(); for (HashSet<RenderBox*>::iterator it = descendants->begin(); it != end; ++it) { RenderBox* box = *it; while (box != this) { if (box->normalChildNeedsLayout()) break; box->setChildNeedsLayout(true, false); box = box->containingBlock(); ASSERT(box); if (!box) break; } } } } int top = borderTop() + paddingTop(); int bottom = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); m_overflowHeight = top; setHeight(m_overflowHeight); // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts, MarginInfo marginInfo(this, top, bottom); // 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 previousFloatBottom = 0; maxFloatBottom = 0; RenderBox* child = firstChildBox(); while (child) { if (legend == child) { child = child->nextSiblingBox(); continue; // Skip the legend, since it has already been positioned up in the fieldset's border. } int oldTopPosMargin = maxTopPosMargin(); int oldTopNegMargin = maxTopNegMargin(); // Make sure we layout children if they need it. // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into // an auto value. Add a method to determine this, so that we can avoid the relayout. if (relayoutChildren || ((child->style()->height().isPercent() || child->style()->minHeight().isPercent() || child->style()->maxHeight().isPercent()) && !isRenderView())) child->setChildNeedsLayout(true, false); // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths. if (relayoutChildren && (child->style()->paddingLeft().isPercent() || child->style()->paddingRight().isPercent())) child->setPrefWidthsDirty(true, false); // Handle the four types of special elements first. These include positioned content, floating content, compacts and // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks. bool handled = false; RenderBox* next = handleSpecialChild(child, marginInfo, handled); if (handled) { child = next; continue; } // The child is a normal flow object. Compute its vertical margins now. child->calcVerticalMargins(); // Do not allow a collapse if the margin top collapse style is set to SEPARATE. if (child->style()->marginTopCollapse() == MSEPARATE) { marginInfo.setAtTopOfBlock(false); marginInfo.clearMargin(); } // Try to guess our correct y position. In most cases this guess will // be correct. Only if we're wrong (when we compute the real y position) // will we have to potentially relayout. int yPosEstimate = estimateVerticalPosition(child, marginInfo); // Cache our old rect so that we can dirty the proper repaint rects if the child moves. IntRect oldRect(child->x(), child->y() , child->width(), child->height());#ifndef NDEBUG IntSize oldLayoutDelta = view()->layoutDelta();#endif // Go ahead and position the child as though it didn't collapse with the top. view()->addLayoutDelta(IntSize(0, child->y() - yPosEstimate)); child->setLocation(child->x(), yPosEstimate); bool markDescendantsWithFloats = false; if (yPosEstimate != oldRect.y() && !child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats()) markDescendantsWithFloats = true; else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) { // If an element might be affected by the presence of floats, then always mark it for // layout. int fb = max(previousFloatBottom, floatBottom()); if (fb > yPosEstimate) markDescendantsWithFloats = true; } if (child->isRenderBlock()) { if (markDescendantsWithFloats) toRenderBlock(child)->markAllDescendantsWithFloatsForLayout(); previousFloatBottom = max(previousFloatBottom, oldRect.y() + toRenderBlock(child)->floatBottom()); } bool childHadLayout = child->m_everHadLayout; bool childNeededLayout = child->needsLayout(); if (childNeededLayout) child->layout(); // Now determine the correct ypos based off examination of collapsing margin // values. int yBeforeClear = collapseMargins(child, marginInfo); // Now check for clear. int yAfterClear = clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin, yBeforeClear); view()->addLayoutDelta(IntSize(0, yPosEstimate - yAfterClear)); child->setLocation(child->x(), yAfterClear); // Now we have a final y position. See if it really does end up being different from our estimate. if (yAfterClear != yPosEstimate) { if (child->shrinkToAvoidFloats()) { // The child's width depends on 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, false); } if (!child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats()) toRenderBlock(child)->markAllDescendantsWithFloatsForLayout(); // Our guess was wrong. Make the child lay itself out again. child->layoutIfNeeded(); } // We are no longer at the top of the block if we encounter a non-empty child. // This has to be done after checking for clear, so that margins can be reset if a clear occurred. if (marginInfo.atTopOfBlock() && !child->isSelfCollapsingBlock()) marginInfo.setAtTopOfBlock(false); // Now place the child in the correct horizontal position determineHorizontalPosition(child); // Update our height now that the child has been placed in the correct position. setHeight(height() + child->height()); if (child->style()->marginBottomCollapse() == MSEPARATE) { setHeight(height() + child->marginBottom()); marginInfo.clearMargin(); } // If the child has overhanging floats that intrude into following siblings (or possibly out // of this block), then the parent gets notified of the floats now. if (child->isBlockFlow() && toRenderBlock(child)->containsFloats()) maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(toRenderBlock(child), -child->x(), -child->y(), !childNeededLayout)); // Update our overflow in case the child spills out the block. m_overflowTop = min(m_overflowTop, child->y() + child->overflowTop(false)); m_overflowHeight = max(m_overflowHeight, height() + child->overflowHeight(false) - child->height()); m_overflowWidth = max(child->x() + child->overflowWidth(false), m_overflowWidth); m_overflowLeft = min(child->x() + child->overflowLeft(false), m_overflowLeft); IntSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y()); if (childOffset.width() || childOffset.height()) { view()->addLayoutDelta(childOffset); // If the child moved, we have to repaint it as well as any floating/positioned // descendants. An exception is if we need a layout. In this case, we know we're going to // repaint ourselves (and the child) anyway. if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout()) child->repaintDuringLayoutIfMoved(oldRect); } if (!childHadLayout && child->checkForRepaintDuringLayout()) child->repaint(); ASSERT(oldLayoutDelta == view()->layoutDelta()); child = child->nextSiblingBox(); } // Now do the handling of the bottom of the block, adding in our bottom border/padding and // determining the correct collapsed bottom margin information. handleBottomOfBlock(top, bottom, marginInfo);}bool RenderBlock::layoutOnlyPositionedObjects(){ if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout()) return false; LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection()); if (needsPositionedMovementLayout()) { tryLayoutDoingPositionedMovementOnly(); if (needsLayout()) return false; } // All we have to is lay out our positioned objects. layoutPositionedObjects(false); statePusher.pop(); if (hasOverflowClip()) layer()->updateScrollInfoAfterLayout(); setNeedsLayout(false); return true;}void RenderBlock::layoutPositionedObjects(bool relayoutChildren){ if (m_positionedObjects) { RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { r = *it; // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is // positioned explicitly) this should not incur a performance penalty. if (relayoutChildren || (r->style()->hasStaticY() && r->parent() != this && r->parent()->isBlockFlow())) r->setChildNeedsLayout(true, false); // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths. //if (relayoutChildren && (r->style()->paddingLeft().isPercent() || r->style()->paddingRight().isPercent())) r->setPrefWidthsDirty(true, false); // We don't have to do a full layout. We just have to update our position. Try that first. If we have shrink-to-fit width // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout. if (r->needsPositionedMovementLayoutOnly()) r->tryLayoutDoingPositionedMovementOnly(); r->layoutIfNeeded(); } }}void RenderBlock::markPositionedObjectsForLayout(){ if (m_positionedObjects) { RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { r = *it; r->setChildNeedsLayout(true); } }}void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants){ // Repaint any overhanging floats (if we know we're the one to paint them). if (hasOverhangingFloats()) { // We think that we must be in a bad state if m_floatingObjects is nil at this point, so // we assert on Debug builds and nil-check Release builds. ASSERT(m_floatingObjects); if (!m_floatingObjects) return; FloatingObject* r; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating // in this
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -