Chromium Code Reviews| Index: Source/core/frame/FrameView.cpp |
| diff --git a/Source/core/frame/FrameView.cpp b/Source/core/frame/FrameView.cpp |
| index 3a253cf77eb84bfba5e5efca34ffcbdcb5dd0c18..3c02ad246f7d5e0641e6c0744028aaee29d0c566 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,33 @@ 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; |
| + auto end = m_layoutSubtreeRoots.end(); |
| + for (auto subtreeRoot = m_layoutSubtreeRoots.begin(); subtreeRoot != end; ++subtreeRoot) |
| + 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() |
| @@ -837,7 +861,40 @@ void FrameView::lineLayoutTime(double ms) |
| m_lineLayoutMs += ms; |
| } |
| -void FrameView::performLayout(LayoutObject* rootForThisLayout, bool inSubtreeLayout) |
| +static void gatherDebugLayoutRects(LayoutObject& layoutRoot) |
|
leviw_travelin_and_unemployed
2015/02/20 22:42:24
This is just being moved up in the file.
|
| +{ |
| + 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) |
| { |
| m_lineLayoutMs = 0; |
| TRACE_EVENT0("blink,benchmark", "FrameView::performLayout"); |
| @@ -854,12 +911,18 @@ 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); |
| + } |
| + } else { |
| + layoutFromRootObject(*m_frame->document()->renderView()); |
| + } |
| ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities(); |
| @@ -935,7 +998,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(); |
| @@ -943,13 +1008,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)) { |
| @@ -978,7 +1042,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) |
| @@ -1014,43 +1078,49 @@ 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(); |
| + if (inSubtreeLayout) { |
| + auto end = m_layoutSubtreeRoots.end(); |
| + for (auto root = m_layoutSubtreeRoots.begin(); root != end; ++root) { |
| + if (LayoutObject* container = (*root)->container()) |
| + container->setMayNeedPaintInvalidation(); |
| + } |
| + } |
| + |
| + m_layoutSubtreeRoot = nullptr; |
| + 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) |
| @@ -1058,7 +1128,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 |
| @@ -1111,32 +1181,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(); |
| @@ -1813,14 +1857,26 @@ 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() |
| +{ |
| + auto end = m_layoutSubtreeRoots.end(); |
| + for (auto iter = m_layoutSubtreeRoots.begin(); iter != end; ++iter) |
| + (*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()) |
| @@ -1831,21 +1887,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); |
| @@ -1856,33 +1904,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()); |