void FrameView::layout(bool allowSubtree) {
if (m_midLayout)
return;
// Always ensure our styleinfo is
up-to-date. This can happen in situations where the layout beats any sort of style recalc update that
needs to occur.
if (m_frame->needsReapplyStyles())
m_frame->reapplyStyles();
else if (document->childNeedsStyleRecalc())
document->recalcStyle();
bool subtree = m_layoutRoot;
RenderObject* root = subtree ? m_layoutRoot : document->renderer();
if (!root){ // FIXME: Do we need to set m_size here?
m_layoutSchedulingEnabled = true;
return; }
//因为在布局的过程中,可能进一步获得网页数据,则需要继续布局处理。
if (!m_postLayoutTasksTimer.isActive()){ // Calls resumeScheduledEvents()
performPostLayoutTasks();
if (!m_postLayoutTasksTimer.isActive()&& needsLayout()){ // Post-layout widget updates or an event handler made us need layout again. Lay
out again, but this time defer widget updates and event dispatch until after we
return.
m_postLayoutTasksTimer.startOneShot(0);
pauseScheduledEvents();
layout(); } } else {
resumeScheduledEvents(); } }
void RenderView::layout() {
if (printing())
m_minPrefWidth = m_maxPrefWidth = m_width;
// Use calcWidth/Height to
get the new width/height, since
this will take the full page zoom factor into account.
bool relayoutChildren = !printing()&&(!m_frameView || m_width
!=viewWidth()|| m_height
!= viewHeight());
if (relayoutChildren) {
ASSERT(!m_layoutState);
LayoutState state; // FIXME: May be better to push a clip
and avoid issuing offscreen repaints.
state.m_clipped = false;
m_layoutState =&state;
if (needsLayout())
RenderBlock::layout();//类继承的好处,直接调用父类的layout
// Reset overflow and then replace it with docWidth and docHeight.
m_overflow.clear();
addLayoutOverflow(IntRect(0, 0, docWidth(), docHeight()));
void RenderBlock::layout() { // Update our first letter info now.
updateFirstLetter(); //Table cells
call layoutBlock directly, so don't add any logic here. Put code into layoutBlock(). layoutBlock(false);
// It's safe to check for control clip here, since
controls can never betable cells. If we have a lightweight clip, there can never be any overflow from
children.
if (hasControlClip() && m_overflow)
clearLayoutOverflow(); }
//这就是在布局基本概念中提到的Block-level元素的子节点要么是Block-level元素要么为Inline-level元素。
if (childrenInline()) layoutInlineChildren(relayoutChildren, repaintTop, repaintBottom);
else layoutBlockChildren(relayoutChildren, maxFloatBottom);
// Expand our intrinsic height to
encompass floats.
int toAdd = borderBottom()+ paddingBottom()+horizontalScrollbarHeight();
if (floatBottom()>(m_height
- toAdd)&&(isInlineBlockOrInlineTable()|| isFloatingOrPositioned()|| hasOverflowClip()|| (parent()&& parent()->isFlexibleBox()|| m_hasColumns)))
setHeight(floatBottom()+ toAdd);
// Now lay out our columns within this intrinsic height, since
they can slightly affect the intrinsic height as we
adjust for clean column breaks.
int singleColumnBottom = layoutColumns();
// Calculate our new height.//布局完子节点后确定父节点高度
int oldHeight = height();
calcHeight();
if (previousHeight != height())
relayoutChildren = true;
// Update our scroll information if we're overflow:auto/scroll/hidden now that we know if we overflow or not.
updateScrollInfoAfterLayout();
// Repaint with our new bounds if they are different from our old bounds.
bool didFullRepaint = repainter.repaintAfterLayout();
if (!didFullRepaint && repaintTop != repaintBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
// 设置repaintRect
// Make sure the rect is still non-empty after intersecting for overflow above
if (!repaintRect.isEmpty()) { repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
if (hasReflection()) repaintRectangle(reflectedRect(repaintRect));
}
}
setNeedsLayout(false);
}
四、RenderBlock::layoutBlockChildren方法
void RenderBlock::layoutBlockChildren(bool relayoutChildren, int&maxFloatBottom) {
int top = borderTop()+ paddingTop();
int bottom = borderBottom()+ paddingBottom()+ horizontalScrollbarHeight();
// 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);
//遍历子节点
RenderBox* next = firstChildBox();
while (next) {
RenderBox* child = next;
next = child->nextSiblingBox();
if (legend == child)
continue; // Skip the legend, since it has already been positioned up in the fieldset's border.
// 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.
if (handleSpecialChild(child, marginInfo))
continue;
// Lay out the child. layoutBlockChild(child, marginInfo, previousFloatBottom, maxFloatBottom);
}
// 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);
}