[LayoutState cleanup] LayoutContext should own the stack of LayoutState objects
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Nov 2017 01:32:17 +0000 (01:32 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Nov 2017 01:32:17 +0000 (01:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=179408
<rdar://problem/35423075>

Reviewed by Antti Koivisto.

No change in functionality.

* page/LayoutContext.cpp:
(WebCore::LayoutContext::layoutDelta const):
(WebCore::LayoutContext::addLayoutDelta):
(WebCore::LayoutContext::layoutDeltaMatches):
(WebCore::LayoutContext::layoutState const):
(WebCore::LayoutContext::pushLayoutState):
(WebCore::LayoutContext::pushLayoutStateForPaginationIfNeeded):
(WebCore::LayoutContext::popLayoutState):
* page/LayoutContext.h:
(WebCore::LayoutContext::isPaintOffsetCacheEnabled const):
(WebCore::LayoutContext::layoutState const): Deleted.
* rendering/LayoutState.cpp:
(WebCore::LayoutState::LayoutState):
(WebCore::LayoutState::computeOffsets):
(WebCore::LayoutState::computeClipRect):
(WebCore::LayoutState::computePaginationInformation):
(WebCore::LayoutState::propagateLineGridInfo):
(WebCore::LayoutState::establishLineGrid):
(WebCore::LayoutState::clearPaginationInformation): Deleted.
* rendering/LayoutState.h:
(WebCore::LayoutState::setIsPaginated):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@224612 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/page/LayoutContext.cpp
Source/WebCore/page/LayoutContext.h
Source/WebCore/rendering/LayoutState.cpp
Source/WebCore/rendering/LayoutState.h

index 594bb2b..332058c 100644 (file)
@@ -1,3 +1,35 @@
+2017-11-08  Zalan Bujtas  <zalan@apple.com>
+
+        [LayoutState cleanup] LayoutContext should own the stack of LayoutState objects
+        https://bugs.webkit.org/show_bug.cgi?id=179408
+        <rdar://problem/35423075>
+
+        Reviewed by Antti Koivisto.
+
+        No change in functionality.
+
+        * page/LayoutContext.cpp:
+        (WebCore::LayoutContext::layoutDelta const):
+        (WebCore::LayoutContext::addLayoutDelta):
+        (WebCore::LayoutContext::layoutDeltaMatches):
+        (WebCore::LayoutContext::layoutState const):
+        (WebCore::LayoutContext::pushLayoutState):
+        (WebCore::LayoutContext::pushLayoutStateForPaginationIfNeeded):
+        (WebCore::LayoutContext::popLayoutState):
+        * page/LayoutContext.h:
+        (WebCore::LayoutContext::isPaintOffsetCacheEnabled const):
+        (WebCore::LayoutContext::layoutState const): Deleted.
+        * rendering/LayoutState.cpp:
+        (WebCore::LayoutState::LayoutState):
+        (WebCore::LayoutState::computeOffsets):
+        (WebCore::LayoutState::computeClipRect):
+        (WebCore::LayoutState::computePaginationInformation):
+        (WebCore::LayoutState::propagateLineGridInfo):
+        (WebCore::LayoutState::establishLineGrid):
+        (WebCore::LayoutState::clearPaginationInformation): Deleted.
+        * rendering/LayoutState.h:
+        (WebCore::LayoutState::setIsPaginated):
+
 2017-11-08  Brady Eidson  <beidson@apple.com>
 
         ServiceWorkerRegistration::updateStateFromServer fix! (Don't always create a new ServiceWorker every time).
index 4fe0e1f..7d5832c 100644 (file)
@@ -530,43 +530,49 @@ void LayoutContext::startLayoutAtMainFrameViewIfNeeded()
 
 LayoutSize LayoutContext::layoutDelta() const
 {
-    if (!m_layoutState)
-        return { };
-    return m_layoutState->layoutDelta();
+    if (auto* layoutState = this->layoutState())
+        return layoutState->layoutDelta();
+    return { };
 }
     
 void LayoutContext::addLayoutDelta(const LayoutSize& delta)
 {
-    if (!m_layoutState)
-        return;
-    m_layoutState->addLayoutDelta(delta);
+    if (auto* layoutState = this->layoutState())
+        layoutState->addLayoutDelta(delta);
 }
     
 #if !ASSERT_DISABLED
 bool LayoutContext::layoutDeltaMatches(const LayoutSize& delta)
 {
-    if (!m_layoutState)
-        return false;
-    return m_layoutState->layoutDeltaMatches(delta);
+    if (auto* layoutState = this->layoutState())
+        return layoutState->layoutDeltaMatches(delta);
+    return false;
 }
 #endif
-    
+
+LayoutState* LayoutContext::layoutState() const
+{
+    if (m_layoutStateStack.isEmpty())
+        return nullptr;
+    return m_layoutStateStack.last().get();
+}
+
 void LayoutContext::pushLayoutState(RenderElement& root)
 {
     ASSERT(!m_paintOffsetCacheDisableCount);
-    ASSERT(!m_layoutState);
+    ASSERT(!layoutState());
 
-    m_layoutState = std::make_unique<LayoutState>(root);
+    m_layoutStateStack.append(std::make_unique<LayoutState>(root));
 }
 
 bool LayoutContext::pushLayoutStateForPaginationIfNeeded(RenderBlockFlow& layoutRoot)
 {
-    if (m_layoutState)
+    if (layoutState())
         return false;
-    m_layoutState = std::make_unique<LayoutState>(layoutRoot);
-    m_layoutState->setIsPaginated();
+    m_layoutStateStack.append(std::make_unique<LayoutState>(layoutRoot));
+    layoutState()->setIsPaginated();
     // This is just a flag for known page height (see RenderBlockFlow::checkForPaginationLogicalHeightChange).
-    m_layoutState->setPageLogicalHeight(1);
+    layoutState()->setPageLogicalHeight(1);
     return true;
 }
     
@@ -578,9 +584,10 @@ void LayoutContext::popLayoutState(RenderObject&)
 bool LayoutContext::pushLayoutState(RenderBox& renderer, const LayoutSize& offset, LayoutUnit pageHeight, bool pageHeightChanged)
 {
     // We push LayoutState even if layoutState is disabled because it stores layoutDelta too.
-    if (!m_layoutState || !needsFullRepaint() || m_layoutState->isPaginated() || renderer.enclosingFragmentedFlow()
-        || m_layoutState->lineGrid() || (renderer.style().lineGrid() != RenderStyle::initialLineGrid() && renderer.isRenderBlockFlow())) {
-        m_layoutState = std::make_unique<LayoutState>(WTFMove(m_layoutState), renderer, offset, pageHeight, pageHeightChanged);
+    auto* layoutState = this->layoutState();
+    if (!layoutState || !needsFullRepaint() || layoutState->isPaginated() || renderer.enclosingFragmentedFlow()
+        || layoutState->lineGrid() || (renderer.style().lineGrid() != RenderStyle::initialLineGrid() && renderer.isRenderBlockFlow())) {
+        m_layoutStateStack.append(std::make_unique<LayoutState>(m_layoutStateStack, renderer, offset, pageHeight, pageHeightChanged));
         return true;
     }
     return false;
@@ -588,7 +595,7 @@ bool LayoutContext::pushLayoutState(RenderBox& renderer, const LayoutSize& offse
     
 void LayoutContext::popLayoutState()
 {
-    m_layoutState = WTFMove(m_layoutState->m_ancestor);
+    m_layoutStateStack.removeLast();
 }
     
 #ifndef NDEBUG
index 61a36e3..78ccd0d 100644 (file)
@@ -25,6 +25,7 @@
 
 #pragma once
 
+#include "LayoutUnit.h"
 #include "Timer.h"
 
 #include <wtf/WeakPtr.h>
@@ -35,8 +36,11 @@ class Document;
 class Frame;
 class FrameView;
 class LayoutScope;
+class LayoutSize;
 class LayoutState;
 class RenderBlockFlow;
+class RenderBox;
+class RenderObject;
 class RenderElement;
 class RenderView;
     
@@ -92,9 +96,9 @@ public:
     void pushLayoutState(RenderElement&);
     bool pushLayoutStateForPaginationIfNeeded(RenderBlockFlow&);
     void popLayoutState(RenderObject&);
-    LayoutState* layoutState() const { return m_layoutState.get(); }
+    LayoutState* layoutState() const;
     // Returns true if layoutState should be used for its cached offset and clip.
-    bool isPaintOffsetCacheEnabled() const { return !m_paintOffsetCacheDisableCount && m_layoutState; }
+    bool isPaintOffsetCacheEnabled() const { return !m_paintOffsetCacheDisableCount && layoutState(); }
 #ifndef NDEBUG
     void checkLayoutState();
 #endif
@@ -106,6 +110,7 @@ public:
 #if !ASSERT_DISABLED
     bool layoutDeltaMatches(const LayoutSize& delta);
 #endif
+    using LayoutStateStack = Vector<std::unique_ptr<LayoutState>>;
 
 private:
     friend class LayoutScope;
@@ -166,7 +171,7 @@ private:
     unsigned m_disableSetNeedsLayoutCount { 0 };
     int m_layoutDisallowedCount { 0 };
     WeakPtr<RenderElement> m_subtreeLayoutRoot;
-    std::unique_ptr<LayoutState> m_layoutState;
+    LayoutStateStack m_layoutStateStack;
     unsigned m_paintOffsetCacheDisableCount { 0 };
 };
 
index 5e8b995..c745d47 100644 (file)
@@ -26,7 +26,6 @@
 #include "config.h"
 #include "LayoutState.h"
 
-#include "LayoutContext.h"
 #include "RenderFragmentedFlow.h"
 #include "RenderInline.h"
 #include "RenderLayer.h"
@@ -60,9 +59,8 @@ LayoutState::LayoutState(RenderElement& renderer)
     }
 }
 
-LayoutState::LayoutState(std::unique_ptr<LayoutState> ancestor, RenderBox& renderer, const LayoutSize& offset, LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged)
-    : m_ancestor(WTFMove(ancestor))
-    , m_clipped(false)
+LayoutState::LayoutState(const LayoutContext::LayoutStateStack& layoutStateStack, RenderBox& renderer, const LayoutSize& offset, LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged)
+    : m_clipped(false)
     , m_isPaginated(false)
     , m_pageLogicalHeightChanged(false)
 #if !ASSERT_DISABLED
@@ -73,23 +71,22 @@ LayoutState::LayoutState(std::unique_ptr<LayoutState> ancestor, RenderBox& rende
     , m_renderer(&renderer)
 #endif
 {
-    if (m_ancestor) {
-        computeOffsets(renderer, offset);
-        computeClipRect(renderer);
+    if (!layoutStateStack.isEmpty()) {
+        auto& ancestor = *layoutStateStack.last().get();
+        computeOffsets(ancestor, renderer, offset);
+        computeClipRect(ancestor, renderer);
     }
-    computePaginationInformation(renderer, pageLogicalHeight, pageLogicalHeightChanged);
+    computePaginationInformation(layoutStateStack, renderer, pageLogicalHeight, pageLogicalHeightChanged);
 }
 
-void LayoutState::computeOffsets(RenderBox& renderer, LayoutSize offset)
+void LayoutState::computeOffsets(const LayoutState& ancestor, RenderBox& renderer, LayoutSize offset)
 {
-    ASSERT(m_ancestor);
-
     bool fixed = renderer.isFixedPositioned();
     if (fixed) {
         FloatPoint fixedOffset = renderer.view().localToAbsolute(FloatPoint(), IsFixed);
         m_paintOffset = LayoutSize(fixedOffset.x(), fixedOffset.y()) + offset;
     } else
-        m_paintOffset = m_ancestor->m_paintOffset + offset;
+        m_paintOffset = ancestor.paintOffset() + offset;
 
     if (renderer.isOutOfFlowPositioned() && !fixed) {
         if (auto* container = renderer.container()) {
@@ -106,20 +103,18 @@ void LayoutState::computeOffsets(RenderBox& renderer, LayoutSize offset)
     if (renderer.hasOverflowClip())
         m_paintOffset -= toLayoutSize(renderer.scrollPosition());
 
-    m_layoutDelta = m_ancestor->m_layoutDelta;
+    m_layoutDelta = ancestor.layoutDelta();
 #if !ASSERT_DISABLED
-    m_layoutDeltaXSaturated = m_ancestor->m_layoutDeltaXSaturated;
-    m_layoutDeltaYSaturated = m_ancestor->m_layoutDeltaYSaturated;
+    m_layoutDeltaXSaturated = ancestor.m_layoutDeltaXSaturated;
+    m_layoutDeltaYSaturated = ancestor.m_layoutDeltaYSaturated;
 #endif
 }
 
-void LayoutState::computeClipRect(RenderBox& renderer)
+void LayoutState::computeClipRect(const LayoutState& ancestor, RenderBox& renderer)
 {
-    ASSERT(m_ancestor);
-
-    m_clipped = !renderer.isFixedPositioned() && m_ancestor->m_clipped;
+    m_clipped = !renderer.isFixedPositioned() && ancestor.isClipped();
     if (m_clipped)
-        m_clipRect = m_ancestor->m_clipRect;
+        m_clipRect = ancestor.clipRect();
     if (!renderer.hasOverflowClip())
         return;
 
@@ -132,21 +127,22 @@ void LayoutState::computeClipRect(RenderBox& renderer)
     // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if present.
 }
 
-void LayoutState::computePaginationInformation(RenderBox& renderer, LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged)
+void LayoutState::computePaginationInformation(const LayoutContext::LayoutStateStack& layoutStateStack, RenderBox& renderer, LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged)
 {
+    auto* ancestor = layoutStateStack.isEmpty() ? nullptr : layoutStateStack.last().get();
     // If we establish a new page height, then cache the offset to the top of the first page.
-    // We can compare this later on to figure out what part of the page we're actually on,
+    // We can compare this later on to figure out what part of the page we're actually on.
     if (pageLogicalHeight || renderer.isRenderFragmentedFlow()) {
         m_pageLogicalHeight = pageLogicalHeight;
         bool isFlipped = renderer.style().isFlippedBlocksWritingMode();
         m_pageOffset = LayoutSize(m_layoutOffset.width() + (!isFlipped ? renderer.borderLeft() + renderer.paddingLeft() : renderer.borderRight() + renderer.paddingRight()), m_layoutOffset.height() + (!isFlipped ? renderer.borderTop() + renderer.paddingTop() : renderer.borderBottom() + renderer.paddingBottom()));
         m_pageLogicalHeightChanged = pageLogicalHeightChanged;
         m_isPaginated = true;
-    } else if (m_ancestor) {
+    } else if (ancestor) {
         // If we don't establish a new page height, then propagate the old page height and offset down.
-        m_pageLogicalHeight = m_ancestor->m_pageLogicalHeight;
-        m_pageLogicalHeightChanged = m_ancestor->m_pageLogicalHeightChanged;
-        m_pageOffset = m_ancestor->m_pageOffset;
+        m_pageLogicalHeight = ancestor->pageLogicalHeight();
+        m_pageLogicalHeightChanged = ancestor->pageLogicalHeightChanged();
+        m_pageOffset = ancestor->pageOffset();
 
         // Disable pagination for objects we don't support. For now this includes overflow:scroll/auto, inline blocks and writing mode roots.
         if (renderer.isUnsplittableForPagination()) {
@@ -157,20 +153,15 @@ void LayoutState::computePaginationInformation(RenderBox& renderer, LayoutUnit p
     }
 
     // Propagate line grid information.
-    propagateLineGridInfo(renderer);
+    if (ancestor)
+        propagateLineGridInfo(*ancestor, renderer);
 
     if (lineGrid() && (lineGrid()->style().writingMode() == renderer.style().writingMode()) && is<RenderMultiColumnFlow>(renderer))
         downcast<RenderMultiColumnFlow>(renderer).computeLineGridPaginationOrigin(*this);
 
     // If we have a new grid to track, then add it to our set.
     if (renderer.style().lineGrid() != RenderStyle::initialLineGrid() && is<RenderBlockFlow>(renderer))
-        establishLineGrid(downcast<RenderBlockFlow>(renderer));
-}
-
-void LayoutState::clearPaginationInformation()
-{
-    m_pageLogicalHeight = m_ancestor->m_pageLogicalHeight;
-    m_pageOffset = m_ancestor->m_pageOffset;
+        establishLineGrid(layoutStateStack, downcast<RenderBlockFlow>(renderer));
 }
 
 LayoutUnit LayoutState::pageLogicalOffset(RenderBox* child, LayoutUnit childLogicalOffset) const
@@ -180,34 +171,36 @@ LayoutUnit LayoutState::pageLogicalOffset(RenderBox* child, LayoutUnit childLogi
     return m_layoutOffset.width() + childLogicalOffset - m_pageOffset.width();
 }
 
-void LayoutState::propagateLineGridInfo(RenderBox& renderer)
+void LayoutState::propagateLineGridInfo(const LayoutState& ancestor, RenderBox& renderer)
 {
     // Disable line grids for objects we don't support. For now this includes overflow:scroll/auto, inline blocks and
     // writing mode roots.
-    if (!m_ancestor || renderer.isUnsplittableForPagination())
+    if (renderer.isUnsplittableForPagination())
         return;
 
-    m_lineGrid = m_ancestor->m_lineGrid;
-    m_lineGridOffset = m_ancestor->m_lineGridOffset;
-    m_lineGridPaginationOrigin = m_ancestor->m_lineGridPaginationOrigin;
+    m_lineGrid = ancestor.lineGrid();
+    m_lineGridOffset = ancestor.lineGridOffset();
+    m_lineGridPaginationOrigin = ancestor.lineGridPaginationOrigin();
 }
 
-void LayoutState::establishLineGrid(RenderBlockFlow& renderer)
+void LayoutState::establishLineGrid(const LayoutContext::LayoutStateStack& layoutStateStack, RenderBlockFlow& renderer)
 {
+    // FIXME: webkit.org/b/179440 This logic should be part of the LayoutContext.
     // First check to see if this grid has been established already.
     if (m_lineGrid) {
         if (m_lineGrid->style().lineGrid() == renderer.style().lineGrid())
             return;
         RenderBlockFlow* currentGrid = m_lineGrid;
-        for (LayoutState* currentState = m_ancestor.get(); currentState; currentState = currentState->m_ancestor.get()) {
-            if (currentState->m_lineGrid == currentGrid)
+        for (int i = layoutStateStack.size() - 1; i <= 0; --i) {
+            auto& currentState = *layoutStateStack[i].get();
+            if (currentState.m_lineGrid == currentGrid)
                 continue;
-            currentGrid = currentState->m_lineGrid;
+            currentGrid = currentState.m_lineGrid;
             if (!currentGrid)
                 break;
             if (currentGrid->style().lineGrid() == renderer.style().lineGrid()) {
                 m_lineGrid = currentGrid;
-                m_lineGridOffset = currentState->m_lineGridOffset;
+                m_lineGridOffset = currentState.m_lineGridOffset;
                 return;
             }
         }
index d1f1029..a4da9fb 100644 (file)
@@ -25,6 +25,7 @@
 
 #pragma once
 
+#include "LayoutContext.h"
 #include "LayoutRect.h"
 #include <wtf/Noncopyable.h>
 
@@ -51,13 +52,11 @@ public:
 #endif
     {
     }
-
-    LayoutState(std::unique_ptr<LayoutState> ancestor, RenderBox&, const LayoutSize& offset, LayoutUnit pageHeight, bool pageHeightChanged);
+    LayoutState(const LayoutContext::LayoutStateStack&, RenderBox&, const LayoutSize& offset, LayoutUnit pageHeight, bool pageHeightChanged);
     explicit LayoutState(RenderElement&);
 
     bool isPaginated() const { return m_isPaginated; }
     void setIsPaginated() { m_isPaginated = true; }
-    void clearPaginationInformation();
 
     // The page logical offset is the object's offset from the top of the page in the page progression
     // direction (so an x-offset in vertical text and a y-offset for horizontal text).
@@ -93,15 +92,12 @@ public:
     bool layoutDeltaMatches(LayoutSize);
 #endif
 
-    // FIXME: webkit.org/b/179408 LayoutContext should own the stack of LayoutState objects
-    std::unique_ptr<LayoutState> m_ancestor;
-
 private:
-    void computeOffsets(RenderBox&, LayoutSize offset);
-    void computeClipRect(RenderBox&);
-    void computePaginationInformation(RenderBox&, LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged);
-    void propagateLineGridInfo(RenderBox&);
-    void establishLineGrid(RenderBlockFlow&);
+    void computeOffsets(const LayoutState& ancestor, RenderBox&, LayoutSize offset);
+    void computeClipRect(const LayoutState& ancestor, RenderBox&);
+    void computePaginationInformation(const LayoutContext::LayoutStateStack&, RenderBox&, LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged);
+    void propagateLineGridInfo(const LayoutState& ancestor, RenderBox&);
+    void establishLineGrid(const LayoutContext::LayoutStateStack&, RenderBlockFlow&);
 
     // Do not add anything apart from bitfields. See https://bugs.webkit.org/show_bug.cgi?id=100173
     bool m_clipped : 1;
@@ -112,7 +108,6 @@ private:
     bool m_layoutDeltaXSaturated : 1;
     bool m_layoutDeltaYSaturated : 1;
 #endif
-
     // The current line grid that we're snapping to and the offset of the start of the grid.
     RenderBlockFlow* m_lineGrid { nullptr };