Title: [252716] trunk
Revision
252716
Author
[email protected]
Date
2019-11-20 15:52:40 -0800 (Wed, 20 Nov 2019)

Log Message

Flexbox sizing logic triggers full repaint on the flex items.
https://bugs.webkit.org/show_bug.cgi?id=204380
<rdar://problem/57236404>

Reviewed by Simon Fraser.

Source/WebCore:

RenderFlexibleBox::applyStretchAlignmentToChild explicitly sets the child renderer's height to 0 before issuing layout on it.
This confuses the child's repaint logic and could trigger unnecessary repaints on complete subtrees.

Many ::layout functions plant a LayoutRepainter stack object to track and report paint invalidations.
It works as long as the renderer's geometry change happens within the scope of this LayoutRepainter.
When the parent (RenderFlexibleBox) mutates the renderer's geometry, the LayoutRepainter object sees
this already mutated state as the initial state and will happily issue repaints even when the final
geometry remains the same.

This patch addresses the redundant repaint by pushing the height reset from the parent down to the child, inside the LayoutRepainter scope.

* rendering/RenderBlock.h: Restrict it to RenderBlock level for now. It might need to go all the way up to RenderBox.
(WebCore::RenderBlock::shouldResetChildLogicalHeightBeforeLayout const):
* rendering/RenderBlockFlow.cpp:
(WebCore::RenderBlockFlow::layoutBlock):
* rendering/RenderBlockFlow.h:
* rendering/RenderBox.cpp:
(WebCore::RenderBox::resetLogicalHeightBeforeLayoutIfNeeded):
* rendering/RenderBox.h:
(WebCore::RenderBox::shouldResetLogicalHeightBeforeLayout const):
* rendering/RenderDeprecatedFlexibleBox.cpp:
(WebCore::RenderDeprecatedFlexibleBox::layoutBlock):
* rendering/RenderFlexibleBox.cpp:
(WebCore::RenderFlexibleBox::layoutBlock):
(WebCore::RenderFlexibleBox::applyStretchAlignmentToChild):
* rendering/RenderFlexibleBox.h:
* rendering/RenderGrid.cpp:
(WebCore::RenderGrid::layoutBlock):
* rendering/RenderGrid.h:
* rendering/RenderTable.cpp:
(WebCore::RenderTable::layout):
* rendering/RenderTable.h:

LayoutTests:

* fast/repaint/align-items-change-expected.txt: progression.

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (252715 => 252716)


--- trunk/LayoutTests/ChangeLog	2019-11-20 23:31:01 UTC (rev 252715)
+++ trunk/LayoutTests/ChangeLog	2019-11-20 23:52:40 UTC (rev 252716)
@@ -1,3 +1,13 @@
+2019-11-20  Zalan Bujtas  <[email protected]>
+
+        Flexbox sizing logic triggers full repaint on the flex items.
+        https://bugs.webkit.org/show_bug.cgi?id=204380
+        <rdar://problem/57236404>
+
+        Reviewed by Simon Fraser.
+
+        * fast/repaint/align-items-change-expected.txt: progression.
+
 2019-11-20  Justin Fan  <[email protected]>
 
         webgl/1.0.3/conformance/context/context-release-upon-reload.html is flaky

Modified: trunk/LayoutTests/fast/repaint/align-items-change-expected.txt (252715 => 252716)


--- trunk/LayoutTests/fast/repaint/align-items-change-expected.txt	2019-11-20 23:31:01 UTC (rev 252715)
+++ trunk/LayoutTests/fast/repaint/align-items-change-expected.txt	2019-11-20 23:52:40 UTC (rev 252716)
@@ -1,10 +1,10 @@
 Tests invalidation on align-items style change. Passes if there is no red.
 
 (repaint rects
-  (rect 0 52 100 300)
-  (rect 0 51 100 1)
-  (rect 100 52 100 300)
-  (rect 100 51 100 1)
+  (rect 0 154 100 198)
+  (rect 0 153 100 1)
+  (rect 100 204 100 148)
+  (rect 100 203 100 1)
   (rect 0 52 200 300)
 )
 

Modified: trunk/Source/WebCore/ChangeLog (252715 => 252716)


--- trunk/Source/WebCore/ChangeLog	2019-11-20 23:31:01 UTC (rev 252715)
+++ trunk/Source/WebCore/ChangeLog	2019-11-20 23:52:40 UTC (rev 252716)
@@ -1,3 +1,44 @@
+2019-11-20  Zalan Bujtas  <[email protected]>
+
+        Flexbox sizing logic triggers full repaint on the flex items.
+        https://bugs.webkit.org/show_bug.cgi?id=204380
+        <rdar://problem/57236404>
+
+        Reviewed by Simon Fraser.
+
+        RenderFlexibleBox::applyStretchAlignmentToChild explicitly sets the child renderer's height to 0 before issuing layout on it.
+        This confuses the child's repaint logic and could trigger unnecessary repaints on complete subtrees.
+
+        Many ::layout functions plant a LayoutRepainter stack object to track and report paint invalidations.
+        It works as long as the renderer's geometry change happens within the scope of this LayoutRepainter.
+        When the parent (RenderFlexibleBox) mutates the renderer's geometry, the LayoutRepainter object sees
+        this already mutated state as the initial state and will happily issue repaints even when the final
+        geometry remains the same.
+
+        This patch addresses the redundant repaint by pushing the height reset from the parent down to the child, inside the LayoutRepainter scope.
+
+        * rendering/RenderBlock.h: Restrict it to RenderBlock level for now. It might need to go all the way up to RenderBox.
+        (WebCore::RenderBlock::shouldResetChildLogicalHeightBeforeLayout const):
+        * rendering/RenderBlockFlow.cpp:
+        (WebCore::RenderBlockFlow::layoutBlock):
+        * rendering/RenderBlockFlow.h:
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::resetLogicalHeightBeforeLayoutIfNeeded):
+        * rendering/RenderBox.h:
+        (WebCore::RenderBox::shouldResetLogicalHeightBeforeLayout const):
+        * rendering/RenderDeprecatedFlexibleBox.cpp:
+        (WebCore::RenderDeprecatedFlexibleBox::layoutBlock):
+        * rendering/RenderFlexibleBox.cpp:
+        (WebCore::RenderFlexibleBox::layoutBlock):
+        (WebCore::RenderFlexibleBox::applyStretchAlignmentToChild):
+        * rendering/RenderFlexibleBox.h:
+        * rendering/RenderGrid.cpp:
+        (WebCore::RenderGrid::layoutBlock):
+        * rendering/RenderGrid.h:
+        * rendering/RenderTable.cpp:
+        (WebCore::RenderTable::layout):
+        * rendering/RenderTable.h:
+
 2019-11-20  Myles C. Maxfield  <[email protected]>
 
         [Cocoa] Add ui-sans-serif as a sibling to ui-serif, ui-monospace, and ui-rounded

Modified: trunk/Source/WebCore/rendering/RenderBlock.h (252715 => 252716)


--- trunk/Source/WebCore/rendering/RenderBlock.h	2019-11-20 23:31:01 UTC (rev 252715)
+++ trunk/Source/WebCore/rendering/RenderBlock.h	2019-11-20 23:52:40 UTC (rev 252716)
@@ -315,7 +315,9 @@
 
     Optional<LayoutUnit> availableLogicalHeightForPercentageComputation() const;
     bool hasDefiniteLogicalHeight() const;
-    
+
+    virtual bool shouldResetChildLogicalHeightBeforeLayout(const RenderBox&) const { return false; }
+
 protected:
     RenderFragmentedFlow* locateEnclosingFragmentedFlow() const override;
     void willBeDestroyed() override;

Modified: trunk/Source/WebCore/rendering/RenderBlockFlow.cpp (252715 => 252716)


--- trunk/Source/WebCore/rendering/RenderBlockFlow.cpp	2019-11-20 23:31:01 UTC (rev 252715)
+++ trunk/Source/WebCore/rendering/RenderBlockFlow.cpp	2019-11-20 23:52:40 UTC (rev 252716)
@@ -472,7 +472,7 @@
     LayoutUnit previousHeight = logicalHeight();
     // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(),
     // for consistency with other render classes?
-    setLogicalHeight(0);
+    resetLogicalHeightBeforeLayoutIfNeeded();
 
     bool pageLogicalHeightChanged = false;
     checkForPaginationLogicalHeightChange(relayoutChildren, pageLogicalHeight, pageLogicalHeightChanged);

Modified: trunk/Source/WebCore/rendering/RenderBlockFlow.h (252715 => 252716)


--- trunk/Source/WebCore/rendering/RenderBlockFlow.h	2019-11-20 23:31:01 UTC (rev 252715)
+++ trunk/Source/WebCore/rendering/RenderBlockFlow.h	2019-11-20 23:52:40 UTC (rev 252716)
@@ -391,6 +391,8 @@
     void addFloatsToNewParent(RenderBlockFlow& toBlockFlow) const;
 
 protected:
+    bool shouldResetLogicalHeightBeforeLayout() const override { return true; }
+
     void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const override;
     
     bool pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const;

Modified: trunk/Source/WebCore/rendering/RenderBox.cpp (252715 => 252716)


--- trunk/Source/WebCore/rendering/RenderBox.cpp	2019-11-20 23:31:01 UTC (rev 252715)
+++ trunk/Source/WebCore/rendering/RenderBox.cpp	2019-11-20 23:52:40 UTC (rev 252716)
@@ -567,6 +567,12 @@
     return hasOverflowClip() && layer() ? layer()->scrollPosition().y() : 0;
 }
 
+void RenderBox::resetLogicalHeightBeforeLayoutIfNeeded()
+{
+    if (shouldResetLogicalHeightBeforeLayout() || (is<RenderBlock>(parent()) && downcast<RenderBlock>(*parent()).shouldResetChildLogicalHeightBeforeLayout(*this)))
+        setLogicalHeight(0_lu);
+}
+
 static void setupWheelEventMonitor(RenderLayer& layer)
 {
     Page& page = layer.renderer().page();

Modified: trunk/Source/WebCore/rendering/RenderBox.h (252715 => 252716)


--- trunk/Source/WebCore/rendering/RenderBox.h	2019-11-20 23:31:01 UTC (rev 252715)
+++ trunk/Source/WebCore/rendering/RenderBox.h	2019-11-20 23:52:40 UTC (rev 252716)
@@ -654,6 +654,9 @@
 
     bool createsNewFormattingContext() const;
 
+    virtual bool shouldResetLogicalHeightBeforeLayout() const { return false; }
+    void resetLogicalHeightBeforeLayoutIfNeeded();
+
     virtual ItemPosition selfAlignmentNormalBehavior(const RenderBox* = nullptr) const { return ItemPosition::Stretch; }
 
     // Returns false if it could not cheaply compute the extent (e.g. fixed background), in which case the returned rect may be incorrect.

Modified: trunk/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp (252715 => 252716)


--- trunk/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp	2019-11-20 23:31:01 UTC (rev 252715)
+++ trunk/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp	2019-11-20 23:52:40 UTC (rev 252716)
@@ -285,6 +285,7 @@
     {
         LayoutStateMaintainer statePusher(*this, locationOffset(), hasTransform() || hasReflection() || style().isFlippedBlocksWritingMode());
 
+        resetLogicalHeightBeforeLayoutIfNeeded();
         preparePaginationBeforeBlockLayout(relayoutChildren);
 
         LayoutSize previousSize = size();

Modified: trunk/Source/WebCore/rendering/RenderFlexibleBox.cpp (252715 => 252716)


--- trunk/Source/WebCore/rendering/RenderFlexibleBox.cpp	2019-11-20 23:31:01 UTC (rev 252715)
+++ trunk/Source/WebCore/rendering/RenderFlexibleBox.cpp	2019-11-20 23:52:40 UTC (rev 252716)
@@ -262,6 +262,7 @@
 
     LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
 
+    resetLogicalHeightBeforeLayoutIfNeeded();
     m_relaidOutChildren.clear();
     
     bool oldInLayout = m_inLayout;
@@ -1839,10 +1840,10 @@
         if (childNeedsRelayout || !child.hasOverrideContentLogicalHeight())
             child.setOverrideContentLogicalHeight(desiredLogicalHeight - child.borderAndPaddingLogicalHeight());
         if (childNeedsRelayout) {
-            child.setLogicalHeight(0_lu);
+            SetForScope<bool> resetChildLogicalHeight(m_shouldResetChildLogicalHeightBeforeLayout, true);
             // We cache the child's intrinsic content logical height to avoid it being
             // reset to the stretched height.
-            // FIXME: This is fragile. RendertBoxes should be smart enough to
+            // FIXME: This is fragile. RenderBoxes should be smart enough to
             // determine their intrinsic content logical height correctly even when
             // there's an overrideHeight.
             LayoutUnit childIntrinsicContentLogicalHeight = cachedChildIntrinsicContentLogicalHeight(child);

Modified: trunk/Source/WebCore/rendering/RenderFlexibleBox.h (252715 => 252716)


--- trunk/Source/WebCore/rendering/RenderFlexibleBox.h	2019-11-20 23:31:01 UTC (rev 252715)
+++ trunk/Source/WebCore/rendering/RenderFlexibleBox.h	2019-11-20 23:52:40 UTC (rev 252716)
@@ -92,6 +92,8 @@
     void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const override;
     void computePreferredLogicalWidths() override;
 
+    bool shouldResetChildLogicalHeightBeforeLayout(const RenderBox&) const override { return m_shouldResetChildLogicalHeightBeforeLayout; }
+
 private:
     enum FlexSign {
         PositiveFlexibility,
@@ -211,6 +213,7 @@
     // This is SizeIsUnknown outside of layoutBlock()
     mutable SizeDefiniteness m_hasDefiniteHeight { SizeDefiniteness::Unknown };
     bool m_inLayout { false };
+    bool m_shouldResetChildLogicalHeightBeforeLayout { false };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/rendering/RenderGrid.cpp (252715 => 252716)


--- trunk/Source/WebCore/rendering/RenderGrid.cpp	2019-11-20 23:31:01 UTC (rev 252715)
+++ trunk/Source/WebCore/rendering/RenderGrid.cpp	2019-11-20 23:52:40 UTC (rev 252716)
@@ -219,7 +219,7 @@
                 m_trackSizingAlgorithm.cacheBaselineAlignedItem(*child, GridRowAxis);
         }
         m_baselineItemsCached = true;
-        setLogicalHeight(0);
+        resetLogicalHeightBeforeLayoutIfNeeded();
         updateLogicalWidth();
 
         // Fieldsets need to find their legend and position it inside the border of the object.

Modified: trunk/Source/WebCore/rendering/RenderGrid.h (252715 => 252716)


--- trunk/Source/WebCore/rendering/RenderGrid.h	2019-11-20 23:31:01 UTC (rev 252715)
+++ trunk/Source/WebCore/rendering/RenderGrid.h	2019-11-20 23:52:40 UTC (rev 252716)
@@ -186,6 +186,8 @@
     LayoutUnit translateOutOfFlowRTLCoordinate(const RenderBox&, LayoutUnit) const;
     LayoutUnit translateRTLCoordinate(LayoutUnit) const;
 
+    bool shouldResetLogicalHeightBeforeLayout() const override { return true; }
+
     Grid m_grid;
 
     GridTrackSizingAlgorithm m_trackSizingAlgorithm;

Modified: trunk/Source/WebCore/rendering/RenderTable.cpp (252715 => 252716)


--- trunk/Source/WebCore/rendering/RenderTable.cpp	2019-11-20 23:31:01 UTC (rev 252715)
+++ trunk/Source/WebCore/rendering/RenderTable.cpp	2019-11-20 23:52:40 UTC (rev 252716)
@@ -433,7 +433,7 @@
 
         LayoutUnit oldLogicalWidth = logicalWidth();
         LayoutUnit oldLogicalHeight = logicalHeight();
-        setLogicalHeight(0);
+        resetLogicalHeightBeforeLayoutIfNeeded();
         updateLogicalWidth();
 
         if (logicalWidth() != oldLogicalWidth) {

Modified: trunk/Source/WebCore/rendering/RenderTable.h (252715 => 252716)


--- trunk/Source/WebCore/rendering/RenderTable.h	2019-11-20 23:31:01 UTC (rev 252715)
+++ trunk/Source/WebCore/rendering/RenderTable.h	2019-11-20 23:52:40 UTC (rev 252716)
@@ -361,6 +361,8 @@
         return false;
     }
 
+    bool shouldResetLogicalHeightBeforeLayout() const override { return true; }
+
     LayoutUnit m_hSpacing;
     LayoutUnit m_vSpacing;
     LayoutUnit m_borderStart;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to