Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(968)

Unified Diff: Source/core/frame/FrameView.cpp

Issue 927773002: Keep track of multiple layout roots (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Address concerns. Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/core/frame/FrameView.cpp
diff --git a/Source/core/frame/FrameView.cpp b/Source/core/frame/FrameView.cpp
index 8a39570e8b213508269616b772b35f1171af8afe..223155c17d9fa5fb0bc4cbcfc98a12eef69eda58 100644
--- a/Source/core/frame/FrameView.cpp
+++ b/Source/core/frame/FrameView.cpp
@@ -108,7 +108,7 @@ FrameView::FrameView(LocalFrame* frame)
, m_canHaveScrollbars(true)
, m_slowRepaintObjectCount(0)
, m_hasPendingLayout(false)
- , m_layoutSubtreeRoot(0)
+ , m_isSubtreeLayout(false)
, m_inSynchronousPostLayout(false)
, m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
, m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired)
@@ -227,7 +227,7 @@ void FrameView::trace(Visitor* visitor)
void FrameView::reset()
{
m_hasPendingLayout = false;
- m_layoutSubtreeRoot = nullptr;
+ m_isSubtreeLayout = false;
m_doFullPaintInvalidation = false;
m_layoutSchedulingEnabled = true;
m_inPerformLayout = false;
@@ -764,9 +764,32 @@ bool FrameView::isEnclosedInCompositingLayer() const
return frameOwnerRenderer && frameOwnerRenderer->enclosingLayer()->enclosingLayerForPaintInvalidationCrossingFrameBoundaries();
}
-LayoutObject* FrameView::layoutRoot(bool onlyDuringLayout) const
+static inline void countObjectsNeedingLayoutInRoot(const LayoutObject* root, unsigned& needsLayoutObjects, unsigned& totalObjects)
{
- return onlyDuringLayout && layoutPending() ? nullptr : m_layoutSubtreeRoot;
+ for (const LayoutObject* o = root; o; o = o->nextInPreOrder(root)) {
+ ++totalObjects;
+ if (o->needsLayout())
+ ++needsLayoutObjects;
+ }
+}
+
+void FrameView::countObjectsNeedingLayout(unsigned& needsLayoutObjects, unsigned& totalObjects, bool& isSubtree)
+{
+ needsLayoutObjects = 0;
+ totalObjects = 0;
+ if (isSubtreeLayout()) {
+ isSubtree = true;
+ for (auto& subtreeRoot : m_layoutSubtreeRoots)
+ countObjectsNeedingLayoutInRoot(subtreeRoot, needsLayoutObjects, totalObjects);
+ } else {
+ isSubtree = false;
+ countObjectsNeedingLayoutInRoot(m_frame->document()->renderView(), needsLayoutObjects, totalObjects);
+ }
+}
+
+bool FrameView::isLayoutRoot(const LayoutObject* object) const
+{
+ return m_layoutSubtreeRoots.contains(const_cast<LayoutObject*>(object));
}
inline void FrameView::forceLayoutParentViewIfNeeded()
@@ -835,8 +858,43 @@ void FrameView::lineLayoutTime(double ms)
m_lineLayoutMs += ms;
}
-void FrameView::performLayout(LayoutObject* rootForThisLayout, bool inSubtreeLayout)
+static void gatherDebugLayoutRects(LayoutObject& layoutRoot)
+{
+ bool isTracing;
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("blink.debug.layout"), &isTracing);
+ if (!isTracing)
+ return;
+ if (!layoutRoot.enclosingLayer()->hasCompositedLayerMapping())
+ return;
+ // For access to compositedLayerMapping().
+ DisableCompositingQueryAsserts disabler;
+ GraphicsLayer* graphicsLayer = layoutRoot.enclosingLayer()->compositedLayerMapping()->mainGraphicsLayer();
+ if (!graphicsLayer)
+ return;
+
+ GraphicsLayerDebugInfo& debugInfo = graphicsLayer->debugInfo();
+
+ debugInfo.currentLayoutRects().clear();
+ for (LayoutObject* renderer = &layoutRoot; renderer; renderer = renderer->nextInPreOrder()) {
+ if (renderer->layoutDidGetCalledSinceLastFrame()) {
+ FloatQuad quad = renderer->localToAbsoluteQuad(FloatQuad(renderer->previousPaintInvalidationRect()));
+ LayoutRect rect = quad.enclosingBoundingBox();
+ debugInfo.currentLayoutRects().append(rect);
+ }
+ }
+}
+
+static inline void layoutFromRootObject(LayoutObject& root)
{
+ LayoutState layoutState(root);
+ root.layout();
+ gatherDebugLayoutRects(root);
+}
+
+void FrameView::performLayout(bool inSubtreeLayout)
+{
+ ASSERT(inSubtreeLayout || m_layoutSubtreeRoots.isEmpty());
+
m_lineLayoutMs = 0;
TRACE_EVENT0("blink,benchmark", "FrameView::performLayout");
double start = WTF::currentTimeMS();
@@ -852,12 +910,24 @@ void FrameView::performLayout(LayoutObject* rootForThisLayout, bool inSubtreeLay
// FIXME: The 300 other lines in layout() probably belong in other helper functions
// so that a single human could understand what layout() is actually doing.
- LayoutState layoutState(*rootForThisLayout);
-
forceLayoutParentViewIfNeeded();
- rootForThisLayout->layout();
- gatherDebugLayoutRects(rootForThisLayout);
+ if (inSubtreeLayout) {
+ while (m_layoutSubtreeRoots.size()) {
+ LayoutObject& root = *m_layoutSubtreeRoots.takeAny();
+ if (!root.needsLayout())
+ continue;
+ layoutFromRootObject(root);
+
+ // We need to ensure that we mark up all renderers up to the RenderView
+ // for paint invalidation. This simplifies our code as we just always
+ // do a full tree walk.
+ if (LayoutObject* container = root.container())
+ container->setMayNeedPaintInvalidation();
+ }
+ } else {
+ layoutFromRootObject(*m_frame->document()->renderView());
+ }
ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities();
@@ -933,7 +1003,9 @@ void FrameView::layout()
Document* document = m_frame->document();
bool inSubtreeLayout = isSubtreeLayout();
- LayoutObject* rootForThisLayout = inSubtreeLayout ? m_layoutSubtreeRoot : document->renderView();
+
+ // FIXME: The notion of a single root for layout is no longer applicable. Remove or update this code. crbug.com/460596
+ LayoutObject* rootForThisLayout = inSubtreeLayout ? *(m_layoutSubtreeRoots.begin()) : renderView();
if (!rootForThisLayout) {
// FIXME: Do we need to set m_size here?
ASSERT_NOT_REACHED();
@@ -941,13 +1013,12 @@ void FrameView::layout()
}
FontCachePurgePreventer fontCachePurgePreventer;
- Layer* layer;
{
TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
m_nestedLayoutCount++;
if (!inSubtreeLayout) {
- Document* document = m_frame->document();
+ clearLayoutSubtreeRootsAndMarkContainingBlocks();
Node* body = document->body();
if (body && body->renderer()) {
if (isHTMLFrameSetElement(*body)) {
@@ -976,7 +1047,7 @@ void FrameView::layout()
m_firstLayout = false;
m_firstLayoutCallbackPending = true;
m_lastViewportSize = layoutSize(IncludeScrollbars);
- m_lastZoomFactor = rootForThisLayout->style()->zoom();
+ m_lastZoomFactor = renderView()->style()->zoom();
// Set the initial vMode to AlwaysOn if we're auto.
if (vMode == ScrollbarAuto)
@@ -1012,43 +1083,37 @@ void FrameView::layout()
m_doFullPaintInvalidation |= renderView()->shouldDoFullPaintInvalidationForNextLayout();
}
- layer = rootForThisLayout->enclosingLayer();
-
- performLayout(rootForThisLayout, inSubtreeLayout);
+ performLayout(inSubtreeLayout);
- m_layoutSubtreeRoot = nullptr;
- // We need to ensure that we mark up all renderers up to the RenderView
- // for paint invalidation. This simplifies our code as we just always
- // do a full tree walk.
- if (LayoutObject* container = rootForThisLayout->container())
- container->setMayNeedPaintInvalidation();
+ m_layoutSubtreeRoots.clear();
+ m_isSubtreeLayout = false;
} // Reset m_layoutSchedulingEnabled to its previous value.
- if (!inSubtreeLayout && !toRenderView(rootForThisLayout)->document().printing())
+ if (!inSubtreeLayout && !document->printing())
adjustViewSize();
- layer->updateLayerPositionsAfterLayout();
+ // FIXME: Could find the common ancestor layer of all dirty subtrees and mark from there.
+ renderView()->enclosingLayer()->updateLayerPositionsAfterLayout();
renderView()->compositor()->didLayout();
m_layoutCount++;
- if (AXObjectCache* cache = rootForThisLayout->document().axObjectCache()) {
- const KURL& url = rootForThisLayout->document().url();
+ if (AXObjectCache* cache = document->axObjectCache()) {
+ const KURL& url = document->url();
if (url.isValid() && !url.isAboutBlankURL())
- cache->handleLayoutComplete(rootForThisLayout);
+ cache->handleLayoutComplete(document);
}
updateAnnotatedRegions();
- ASSERT(!rootForThisLayout->needsLayout());
-
if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
updateOverflowStatus(layoutSize().width() < contentsWidth(), layoutSize().height() < contentsHeight());
scheduleOrPerformPostLayoutTasks();
+ // FIXME: The notion of a single root for layout is no longer applicable. Remove or update this code. crbug.com/460596
TRACE_EVENT_END1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Layout", "endData", InspectorLayoutEvent::endData(rootForThisLayout));
- InspectorInstrumentation::didLayout(m_frame.get(), rootForThisLayout);
+ InspectorInstrumentation::didLayout(m_frame.get());
m_nestedLayoutCount--;
if (m_nestedLayoutCount)
@@ -1056,7 +1121,7 @@ void FrameView::layout()
#if ENABLE(ASSERT)
// Post-layout assert that nobody was re-marked as needing layout during layout.
- document->renderView()->assertSubtreeIsLaidOut();
+ renderView()->assertSubtreeIsLaidOut();
#endif
// FIXME: It should be not possible to remove the FrameView from the frame/page during layout
@@ -1109,32 +1174,6 @@ DocumentLifecycle& FrameView::lifecycle() const
return m_frame->document()->lifecycle();
}
-void FrameView::gatherDebugLayoutRects(LayoutObject* layoutRoot)
-{
- bool isTracing;
- TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("blink.debug.layout"), &isTracing);
- if (!isTracing)
- return;
- if (!layoutRoot->enclosingLayer()->hasCompositedLayerMapping())
- return;
- // For access to compositedLayerMapping().
- DisableCompositingQueryAsserts disabler;
- GraphicsLayer* graphicsLayer = layoutRoot->enclosingLayer()->compositedLayerMapping()->mainGraphicsLayer();
- if (!graphicsLayer)
- return;
-
- GraphicsLayerDebugInfo& debugInfo = graphicsLayer->debugInfo();
-
- debugInfo.currentLayoutRects().clear();
- for (LayoutObject* renderer = layoutRoot; renderer; renderer = renderer->nextInPreOrder()) {
- if (renderer->layoutDidGetCalledSinceLastFrame()) {
- FloatQuad quad = renderer->localToAbsoluteQuad(FloatQuad(renderer->previousPaintInvalidationRect()));
- LayoutRect rect = quad.enclosingBoundingBox();
- debugInfo.currentLayoutRects().append(rect);
- }
- }
-}
-
RenderBox* FrameView::embeddedContentBox() const
{
RenderView* renderView = this->renderView();
@@ -1811,14 +1850,25 @@ void FrameView::handleLoadCompleted()
maintainScrollPositionAtAnchor(0);
}
+void FrameView::clearLayoutSubtreeRoot(const LayoutObject* root)
+{
+ m_layoutSubtreeRoots.remove(const_cast<LayoutObject*>(root));
+ if (m_layoutSubtreeRoots.isEmpty())
+ m_isSubtreeLayout = false;
+}
+
+void FrameView::clearLayoutSubtreeRootsAndMarkContainingBlocks()
+{
+ for (auto& iter : m_layoutSubtreeRoots)
+ iter->markContainingBlocksForLayout(false);
+ m_layoutSubtreeRoots.clear();
+}
+
void FrameView::scheduleRelayout()
{
ASSERT(m_frame->view() == this);
- if (isSubtreeLayout()) {
- m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
- m_layoutSubtreeRoot = nullptr;
- }
+ m_isSubtreeLayout = false;
if (!m_layoutSchedulingEnabled)
return;
if (!needsLayout())
@@ -1829,21 +1879,13 @@ void FrameView::scheduleRelayout()
if (m_hasPendingLayout)
return;
+ clearLayoutSubtreeRootsAndMarkContainingBlocks();
m_hasPendingLayout = true;
page()->animator().scheduleVisualUpdate(m_frame.get());
lifecycle().ensureStateAtMost(DocumentLifecycle::StyleClean);
}
-static bool isObjectAncestorContainerOf(LayoutObject* ancestor, LayoutObject* descendant)
-{
- for (LayoutObject* r = descendant; r; r = r->container()) {
- if (r == ancestor)
- return true;
- }
- return false;
-}
-
void FrameView::scheduleRelayoutOfSubtree(LayoutObject* relayoutRoot)
{
ASSERT(m_frame->view() == this);
@@ -1854,33 +1896,20 @@ void FrameView::scheduleRelayoutOfSubtree(LayoutObject* relayoutRoot)
RenderView* renderView = this->renderView();
if (renderView && renderView->needsLayout()) {
+ ASSERT(!m_isSubtreeLayout);
if (relayoutRoot)
relayoutRoot->markContainingBlocksForLayout(false);
return;
}
- if (layoutPending() || !m_layoutSchedulingEnabled) {
- if (m_layoutSubtreeRoot != relayoutRoot) {
- if (isObjectAncestorContainerOf(m_layoutSubtreeRoot, relayoutRoot)) {
- // Keep the current root
- relayoutRoot->markContainingBlocksForLayout(false, m_layoutSubtreeRoot);
- ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
- } else if (isSubtreeLayout() && isObjectAncestorContainerOf(relayoutRoot, m_layoutSubtreeRoot)) {
- // Re-root at relayoutRoot
- m_layoutSubtreeRoot->markContainingBlocksForLayout(false, relayoutRoot);
- m_layoutSubtreeRoot = relayoutRoot;
- ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
- } else {
- // Just do a full relayout
- if (isSubtreeLayout())
- m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
- m_layoutSubtreeRoot = nullptr;
- relayoutRoot->markContainingBlocksForLayout(false);
- }
- }
- } else if (m_layoutSchedulingEnabled) {
- m_layoutSubtreeRoot = relayoutRoot;
- ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
+ if (relayoutRoot == renderView) {
+ m_isSubtreeLayout = false;
+ clearLayoutSubtreeRootsAndMarkContainingBlocks();
+ } else {
+ m_isSubtreeLayout = true;
+ m_layoutSubtreeRoots.add(relayoutRoot);
+ }
+ if (m_layoutSchedulingEnabled) {
m_hasPendingLayout = true;
page()->animator().scheduleVisualUpdate(m_frame.get());

Powered by Google App Engine
This is Rietveld 408576698