| Index: Source/core/frame/FrameView.cpp
|
| diff --git a/Source/core/frame/FrameView.cpp b/Source/core/frame/FrameView.cpp
|
| index a338e756e020c1eb3beb88cabe31f2c009c53052..06ced1cd8d714bdc1730e2be88a5951c95906581 100644
|
| --- a/Source/core/frame/FrameView.cpp
|
| +++ b/Source/core/frame/FrameView.cpp
|
| @@ -108,7 +108,6 @@ FrameView::FrameView(LocalFrame* frame)
|
| , m_canHaveScrollbars(true)
|
| , m_slowRepaintObjectCount(0)
|
| , m_hasPendingLayout(false)
|
| - , m_layoutSubtreeRoot(0)
|
| , m_inSynchronousPostLayout(false)
|
| , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
|
| , m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired)
|
| @@ -227,7 +226,6 @@ DEFINE_TRACE(FrameView)
|
| void FrameView::reset()
|
| {
|
| m_hasPendingLayout = false;
|
| - m_layoutSubtreeRoot = nullptr;
|
| m_doFullPaintInvalidation = false;
|
| m_layoutSchedulingEnabled = true;
|
| m_inPerformLayout = false;
|
| @@ -757,9 +755,31 @@ 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;
|
| + isSubtree = isSubtreeLayout();
|
| + if (isSubtree) {
|
| + for (auto& subtreeRoot : m_layoutSubtreeRoots)
|
| + countObjectsNeedingLayoutInRoot(subtreeRoot, needsLayoutObjects, totalObjects);
|
| + } else {
|
| + countObjectsNeedingLayoutInRoot(layoutView(), needsLayoutObjects, totalObjects);
|
| + }
|
| +}
|
| +
|
| +bool FrameView::isLayoutRoot(const LayoutObject& object) const
|
| +{
|
| + return m_layoutSubtreeRoots.contains(const_cast<LayoutObject*>(&object));
|
| }
|
|
|
| inline void FrameView::forceLayoutParentViewIfNeeded()
|
| @@ -828,8 +848,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 = LayoutRect(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();
|
| @@ -845,12 +900,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 LayoutView
|
| + // 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(*layoutView());
|
| + }
|
|
|
| ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities();
|
|
|
| @@ -926,7 +993,9 @@ void FrameView::layout()
|
|
|
| Document* document = m_frame->document();
|
| bool inSubtreeLayout = isSubtreeLayout();
|
| - LayoutObject* rootForThisLayout = inSubtreeLayout ? m_layoutSubtreeRoot : document->layoutView();
|
| +
|
| + // 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()) : layoutView();
|
| if (!rootForThisLayout) {
|
| // FIXME: Do we need to set m_size here?
|
| ASSERT_NOT_REACHED();
|
| @@ -934,13 +1003,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)) {
|
| @@ -969,7 +1037,7 @@ void FrameView::layout()
|
| m_firstLayout = false;
|
| m_firstLayoutCallbackPending = true;
|
| m_lastViewportSize = layoutSize(IncludeScrollbars);
|
| - m_lastZoomFactor = rootForThisLayout->style()->zoom();
|
| + m_lastZoomFactor = layoutView()->style()->zoom();
|
|
|
| // Set the initial vMode to AlwaysOn if we're auto.
|
| if (vMode == ScrollbarAuto)
|
| @@ -1005,43 +1073,36 @@ void FrameView::layout()
|
| m_doFullPaintInvalidation |= layoutView()->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 LayoutView
|
| - // for paint invalidation. This simplifies our code as we just always
|
| - // do a full tree walk.
|
| - if (LayoutObject* container = rootForThisLayout->container())
|
| - container->setMayNeedPaintInvalidation();
|
| + ASSERT(m_layoutSubtreeRoots.isEmpty());
|
| } // Reset m_layoutSchedulingEnabled to its previous value.
|
|
|
| - if (!inSubtreeLayout && !toLayoutView(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. crbug.com/462719
|
| + layoutView()->enclosingLayer()->updateLayerPositionsAfterLayout();
|
|
|
| layoutView()->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)
|
| @@ -1049,7 +1110,7 @@ void FrameView::layout()
|
|
|
| #if ENABLE(ASSERT)
|
| // Post-layout assert that nobody was re-marked as needing layout during layout.
|
| - document->layoutView()->assertSubtreeIsLaidOut();
|
| + layoutView()->assertSubtreeIsLaidOut();
|
| #endif
|
|
|
| // FIXME: It should be not possible to remove the FrameView from the frame/page during layout
|
| @@ -1103,32 +1164,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 = LayoutRect(quad.enclosingBoundingBox());
|
| - debugInfo.currentLayoutRects().append(rect);
|
| - }
|
| - }
|
| -}
|
| -
|
| LayoutBox* FrameView::embeddedContentBox() const
|
| {
|
| LayoutView* layoutView = this->layoutView();
|
| @@ -1803,14 +1838,22 @@ void FrameView::handleLoadCompleted()
|
| maintainScrollPositionAtAnchor(0);
|
| }
|
|
|
| +void FrameView::clearLayoutSubtreeRoot(const LayoutObject& root)
|
| +{
|
| + m_layoutSubtreeRoots.remove(const_cast<LayoutObject*>(&root));
|
| +}
|
| +
|
| +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;
|
| - }
|
| if (!m_layoutSchedulingEnabled)
|
| return;
|
| if (!needsLayout())
|
| @@ -1819,6 +1862,8 @@ void FrameView::scheduleRelayout()
|
| return;
|
| TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "InvalidateLayout", "data", InspectorInvalidateLayoutEvent::data(m_frame.get()));
|
|
|
| + clearLayoutSubtreeRootsAndMarkContainingBlocks();
|
| +
|
| if (m_hasPendingLayout)
|
| return;
|
| m_hasPendingLayout = true;
|
| @@ -1827,15 +1872,6 @@ void FrameView::scheduleRelayout()
|
| 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);
|
| @@ -1851,28 +1887,11 @@ void FrameView::scheduleRelayoutOfSubtree(LayoutObject* relayoutRoot)
|
| 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 == layoutView)
|
| + clearLayoutSubtreeRootsAndMarkContainingBlocks();
|
| + else
|
| + m_layoutSubtreeRoots.add(relayoutRoot);
|
| + if (m_layoutSchedulingEnabled) {
|
| m_hasPendingLayout = true;
|
|
|
| page()->animator().scheduleVisualUpdate(m_frame.get());
|
|
|