Title: [294195] trunk
Revision
294195
Author
za...@apple.com
Date
2022-05-14 08:24:29 -0700 (Sat, 14 May 2022)

Log Message

[Repaint] Border ignores currentColor change when hovering
https://bugs.webkit.org/show_bug.cgi?id=240401

Reviewed by Antti Koivisto.

Source/WebCore:

This patch triggers repaint when currentColor is applied on border.

It most likely got broken at r150259 (9 years ago!) when StyleDifferenceRepaintIfText was introduced.
StyleDifferenceRepaintIfText is a "conditional repaint" diff value which only triggers repaint if the renderer has some text content.

Later, r156619 addressed some of the "content with border/outline is not painting" fallout by extending
StyleDifferenceRepaintIfText to RepaintIfTextOrBorderOrOutline.
RepaintIfTextOrBorderOrOutline turns "conditional repaints" to real repaints if, in addition to text, the content has outline/border.
However the fix was neither complete nor proper (it patched the repaint logic by changing hasImmediateNonWhitespaceTextChildOrBorderOrOutline
instead of computing the correct diff value -unconditional Repaint).

Fast-forward to 2020, r267528 ensured that content with outline is no longer a "conditional repaint".
It also made some of the code introduced in r156619 redundant (see hasImmediateNonWhitespaceTextChildOrBorderOrOutline).

This patch expands on r267528 by introducing isEquivalentForPainting for the border data. It ensures that we
compute (unconditional) Repaint diff value, if the border uses currentColor.

Tests: fast/repaint/repaint-current-color-border-on-hover.html
       fast/repaint/repaint-pseudo-border-on-hover.html

* rendering/RenderElement.cpp:
(WebCore::RenderElement::hasImmediateNonWhitespaceTextChildOrBorderOrOutline const):
* rendering/style/BorderData.h:
(WebCore::BorderData::isEquivalentForPainting const):
* rendering/style/RenderStyle.cpp:
(WebCore::RenderStyle::changeRequiresRepaint const):

LayoutTests:

* fast/repaint/repaint-current-color-border-on-hover-expected.txt: Added.
* fast/repaint/repaint-current-color-border-on-hover.html: Added.
* fast/repaint/repaint-pseudo-border-on-hover-expected.txt: Added.
* fast/repaint/repaint-pseudo-border-on-hover.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (294194 => 294195)


--- trunk/LayoutTests/ChangeLog	2022-05-14 14:40:27 UTC (rev 294194)
+++ trunk/LayoutTests/ChangeLog	2022-05-14 15:24:29 UTC (rev 294195)
@@ -1,3 +1,15 @@
+2022-05-14  Alan Bujtas  <za...@apple.com>
+
+        [Repaint] Border ignores currentColor change when hovering
+        https://bugs.webkit.org/show_bug.cgi?id=240401
+
+        Reviewed by Antti Koivisto.
+
+        * fast/repaint/repaint-current-color-border-on-hover-expected.txt: Added.
+        * fast/repaint/repaint-current-color-border-on-hover.html: Added.
+        * fast/repaint/repaint-pseudo-border-on-hover-expected.txt: Added.
+        * fast/repaint/repaint-pseudo-border-on-hover.html: Added.
+
 2022-05-13  Tim Nguyen  <n...@apple.com>
 
         [css-ui] Unexpose appearance property values already handled by appearance: auto

Added: trunk/LayoutTests/fast/repaint/repaint-current-color-border-on-hover-expected.txt (0 => 294195)


--- trunk/LayoutTests/fast/repaint/repaint-current-color-border-on-hover-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/repaint/repaint-current-color-border-on-hover-expected.txt	2022-05-14 15:24:29 UTC (rev 294195)
@@ -0,0 +1,4 @@
+(repaint rects
+(rect 8 8 120 120)
+)
+

Added: trunk/LayoutTests/fast/repaint/repaint-current-color-border-on-hover.html (0 => 294195)


--- trunk/LayoutTests/fast/repaint/repaint-current-color-border-on-hover.html	                        (rev 0)
+++ trunk/LayoutTests/fast/repaint/repaint-current-color-border-on-hover.html	2022-05-14 15:24:29 UTC (rev 294195)
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<style>
+div {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+  border: solid 10px currentColor;
+}
+div:hover {
+  color: green;
+}
+</style>
+<div id=hitregion></div>
+<script>
+if (window.eventSender) {
+  testRunner.dumpAsText();
+
+  window.internals.startTrackingRepaints();
+
+  eventSender.mouseMoveTo(50, 50);
+  eventSender.mouseDown();
+  eventSender.mouseUp();
+
+  document.body.offsetHeight;
+
+  let repaintRects = window.internals.repaintRectsAsText();
+  window.internals.stopTrackingRepaints();
+
+  hitregion.innerText = repaintRects;
+}
+</script>

Added: trunk/LayoutTests/fast/repaint/repaint-pseudo-border-on-hover-expected.txt (0 => 294195)


--- trunk/LayoutTests/fast/repaint/repaint-pseudo-border-on-hover-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/repaint/repaint-pseudo-border-on-hover-expected.txt	2022-05-14 15:24:29 UTC (rev 294195)
@@ -0,0 +1,4 @@
+(repaint rects
+(rect 148 8 100 100)
+)
+

Added: trunk/LayoutTests/fast/repaint/repaint-pseudo-border-on-hover.html (0 => 294195)


--- trunk/LayoutTests/fast/repaint/repaint-pseudo-border-on-hover.html	                        (rev 0)
+++ trunk/LayoutTests/fast/repaint/repaint-pseudo-border-on-hover.html	2022-05-14 15:24:29 UTC (rev 294195)
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<style>
+#hitregion {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+#hitregion:after {
+  content: "";
+  border: 50px solid;
+  position: absolute;
+  width: 0;
+  height: 0;
+  margin-left: 140px;
+}
+
+#hitregion:hover:after {
+  color: green;
+}
+</style>
+<div id="hitregion"></div>
+<script>
+if (window.eventSender) {
+  testRunner.dumpAsText();
+
+  window.internals.startTrackingRepaints();
+
+  eventSender.mouseMoveTo(50, 50);
+  eventSender.mouseDown();
+  eventSender.mouseUp();
+
+  document.body.offsetHeight;
+
+  let repaintRects = window.internals.repaintRectsAsText();
+  window.internals.stopTrackingRepaints();
+
+  hitregion.innerText = repaintRects;
+}
+</script>

Modified: trunk/Source/WebCore/ChangeLog (294194 => 294195)


--- trunk/Source/WebCore/ChangeLog	2022-05-14 14:40:27 UTC (rev 294194)
+++ trunk/Source/WebCore/ChangeLog	2022-05-14 15:24:29 UTC (rev 294195)
@@ -1,5 +1,39 @@
 2022-05-14  Alan Bujtas  <za...@apple.com>
 
+        [Repaint] Border ignores currentColor change when hovering
+        https://bugs.webkit.org/show_bug.cgi?id=240401
+
+        Reviewed by Antti Koivisto.
+
+        This patch triggers repaint when currentColor is applied on border.
+
+        It most likely got broken at r150259 (9 years ago!) when StyleDifferenceRepaintIfText was introduced.
+        StyleDifferenceRepaintIfText is a "conditional repaint" diff value which only triggers repaint if the renderer has some text content.
+
+        Later, r156619 addressed some of the "content with border/outline is not painting" fallout by extending
+        StyleDifferenceRepaintIfText to RepaintIfTextOrBorderOrOutline.
+        RepaintIfTextOrBorderOrOutline turns "conditional repaints" to real repaints if, in addition to text, the content has outline/border.
+        However the fix was neither complete nor proper (it patched the repaint logic by changing hasImmediateNonWhitespaceTextChildOrBorderOrOutline 
+        instead of computing the correct diff value -unconditional Repaint).
+
+        Fast-forward to 2020, r267528 ensured that content with outline is no longer a "conditional repaint".
+        It also made some of the code introduced in r156619 redundant (see hasImmediateNonWhitespaceTextChildOrBorderOrOutline).
+
+        This patch expands on r267528 by introducing isEquivalentForPainting for the border data. It ensures that we
+        compute (unconditional) Repaint diff value, if the border uses currentColor.
+
+        Tests: fast/repaint/repaint-current-color-border-on-hover.html
+               fast/repaint/repaint-pseudo-border-on-hover.html
+
+        * rendering/RenderElement.cpp:
+        (WebCore::RenderElement::hasImmediateNonWhitespaceTextChildOrBorderOrOutline const):
+        * rendering/style/BorderData.h:
+        (WebCore::BorderData::isEquivalentForPainting const):
+        * rendering/style/RenderStyle.cpp:
+        (WebCore::RenderStyle::changeRequiresRepaint const):
+
+2022-05-14  Alan Bujtas  <za...@apple.com>
+
         [FFC][Integration] Add updateFormattingRootGeometryAndInvalidate/updateRenderers
         https://bugs.webkit.org/show_bug.cgi?id=240413
 

Modified: trunk/Source/WebCore/layout/integration/LayoutIntegrationCoverage.cpp (294194 => 294195)


--- trunk/Source/WebCore/layout/integration/LayoutIntegrationCoverage.cpp	2022-05-14 14:40:27 UTC (rev 294194)
+++ trunk/Source/WebCore/layout/integration/LayoutIntegrationCoverage.cpp	2022-05-14 15:24:29 UTC (rev 294195)
@@ -652,7 +652,7 @@
     case StyleDifference::RecompositeLayer:
         return true;
     case StyleDifference::Repaint:
-    case StyleDifference::RepaintIfTextOrBorderOrOutline:
+    case StyleDifference::RepaintIfText:
     case StyleDifference::RepaintLayer:
         // FIXME: We could do a more focused style check by matching RendererStyle::changeRequiresRepaint&co.
         return canUseForStyle(blockContainer, IncludeReasons::First).isEmpty();

Modified: trunk/Source/WebCore/rendering/RenderElement.cpp (294194 => 294195)


--- trunk/Source/WebCore/rendering/RenderElement.cpp	2022-05-14 14:40:27 UTC (rev 294194)
+++ trunk/Source/WebCore/rendering/RenderElement.cpp	2022-05-14 15:24:29 UTC (rev 294195)
@@ -301,20 +301,17 @@
     return diff;
 }
 
-inline bool RenderElement::hasImmediateNonWhitespaceTextChildOrBorderOrOutline() const
-{
-    for (auto& child : childrenOfType<RenderObject>(*this)) {
-        if (is<RenderText>(child) && !downcast<RenderText>(child).isAllCollapsibleWhitespace())
-            return true;
-        if (child.style().hasOutline() || child.style().hasBorder())
-            return true;
-    }
-    return false;
-}
 
 inline bool RenderElement::shouldRepaintForStyleDifference(StyleDifference diff) const
 {
-    return diff == StyleDifference::Repaint || (diff == StyleDifference::RepaintIfTextOrBorderOrOutline && hasImmediateNonWhitespaceTextChildOrBorderOrOutline());
+    auto hasImmediateNonWhitespaceTextChild = [&] {
+        for (auto& child : childrenOfType<RenderText>(*this)) {
+            if (!child.isAllCollapsibleWhitespace())
+                return true;
+        }
+        return false;
+    };
+    return diff == StyleDifference::Repaint || (diff == StyleDifference::RepaintIfText && hasImmediateNonWhitespaceTextChild());
 }
 
 void RenderElement::updateFillImages(const FillLayer* oldLayers, const FillLayer& newLayers)

Modified: trunk/Source/WebCore/rendering/RenderElement.h (294194 => 294195)


--- trunk/Source/WebCore/rendering/RenderElement.h	2022-05-14 14:40:27 UTC (rev 294194)
+++ trunk/Source/WebCore/rendering/RenderElement.h	2022-05-14 15:24:29 UTC (rev 294195)
@@ -368,7 +368,6 @@
     void handleDynamicFloatPositionChange();
 
     bool shouldRepaintForStyleDifference(StyleDifference) const;
-    bool hasImmediateNonWhitespaceTextChildOrBorderOrOutline() const;
 
     void updateFillImages(const FillLayer*, const FillLayer&);
     void updateImage(StyleImage*, StyleImage*);

Modified: trunk/Source/WebCore/rendering/RenderTextControl.cpp (294194 => 294195)


--- trunk/Source/WebCore/rendering/RenderTextControl.cpp	2022-05-14 14:40:27 UTC (rev 294194)
+++ trunk/Source/WebCore/rendering/RenderTextControl.cpp	2022-05-14 15:24:29 UTC (rev 294195)
@@ -71,7 +71,7 @@
         auto oldInnerTextStyle = textFormControlElement().createInnerTextStyle(*oldStyle);
         if (newInnerTextStyle != oldInnerTextStyle)
             innerTextRenderer->setStyle(WTFMove(newInnerTextStyle));
-        else if (diff == StyleDifference::RepaintIfTextOrBorderOrOutline || diff == StyleDifference::Repaint) {
+        else if (diff == StyleDifference::RepaintIfText || diff == StyleDifference::Repaint) {
             // Repaint is expected to be propagated down to the shadow tree when non-inherited style property changes
             // (e.g. text-decoration-color) since that's where the value actually takes effect.
             innerTextRenderer->repaint();

Modified: trunk/Source/WebCore/rendering/style/BorderData.cpp (294194 => 294195)


--- trunk/Source/WebCore/rendering/style/BorderData.cpp	2022-05-14 14:40:27 UTC (rev 294194)
+++ trunk/Source/WebCore/rendering/style/BorderData.cpp	2022-05-14 15:24:29 UTC (rev 294195)
@@ -27,10 +27,23 @@
 #include "BorderData.h"
 
 #include "OutlineValue.h"
+#include "RenderStyle.h"
 #include <wtf/text/TextStream.h>
 
 namespace WebCore {
 
+bool BorderData::isEquivalentForPainting(const BorderData& other, bool currentColorDiffers) const
+{
+    if (*this != other)
+        return false;
+
+    if (!currentColorDiffers)
+        return true;
+
+    auto borderHasCurrentColor = RenderStyle::isCurrentColor(m_top.color()) || RenderStyle::isCurrentColor(m_right.color()) || RenderStyle::isCurrentColor(m_bottom.color()) || RenderStyle::isCurrentColor(m_left.color());
+    return !borderHasCurrentColor;
+}
+
 TextStream& operator<<(TextStream& ts, const BorderValue& borderValue)
 {
     ts << borderValue.width() << " " << borderValue.style() << " " << borderValue.color();

Modified: trunk/Source/WebCore/rendering/style/BorderData.h (294194 => 294195)


--- trunk/Source/WebCore/rendering/style/BorderData.h	2022-05-14 14:40:27 UTC (rev 294194)
+++ trunk/Source/WebCore/rendering/style/BorderData.h	2022-05-14 15:24:29 UTC (rev 294195)
@@ -107,6 +107,8 @@
         return FloatBoxExtent(borderTopWidth(), borderRightWidth(), borderBottomWidth(), borderLeftWidth());
     }
 
+    bool isEquivalentForPainting(const BorderData& other, bool currentColorDiffers) const;
+
     bool operator==(const BorderData& o) const
     {
         return m_left == o.m_left && m_right == o.m_right && m_top == o.m_top && m_bottom == o.m_bottom && m_image == o.m_image

Modified: trunk/Source/WebCore/rendering/style/RenderStyle.cpp (294194 => 294195)


--- trunk/Source/WebCore/rendering/style/RenderStyle.cpp	2022-05-14 14:40:27 UTC (rev 294194)
+++ trunk/Source/WebCore/rendering/style/RenderStyle.cpp	2022-05-14 15:24:29 UTC (rev 294195)
@@ -1214,14 +1214,14 @@
         return true;
 
 
+    bool currentColorDiffers = m_inheritedData->color != other.m_inheritedData->color;
     if (m_backgroundData.ptr() != other.m_backgroundData.ptr()) {
-        bool currentColorDiffers = m_inheritedData->color != other.m_inheritedData->color;
         if (!m_backgroundData->isEquivalentForPainting(*other.m_backgroundData, currentColorDiffers))
             return true;
     }
 
     if (m_surroundData.ptr() != other.m_surroundData.ptr()) {
-        if (m_surroundData->border != other.m_surroundData->border)
+        if (!m_surroundData->border.isEquivalentForPainting(other.m_surroundData->border, currentColorDiffers))
             return true;
     }
 
@@ -1241,7 +1241,7 @@
     return false;
 }
 
-bool RenderStyle::changeRequiresRepaintIfTextOrBorderOrOutline(const RenderStyle& other, OptionSet<StyleDifferenceContextSensitiveProperty>&) const
+bool RenderStyle::changeRequiresRepaintIfText(const RenderStyle& other, OptionSet<StyleDifferenceContextSensitiveProperty>&) const
 {
     if (m_inheritedData->color != other.m_inheritedData->color
         || m_inheritedFlags.textDecorationLines != other.m_inheritedFlags.textDecorationLines
@@ -1309,8 +1309,8 @@
     if (changeRequiresRepaint(other, changedContextSensitiveProperties))
         return StyleDifference::Repaint;
 
-    if (changeRequiresRepaintIfTextOrBorderOrOutline(other, changedContextSensitiveProperties))
-        return StyleDifference::RepaintIfTextOrBorderOrOutline;
+    if (changeRequiresRepaintIfText(other, changedContextSensitiveProperties))
+        return StyleDifference::RepaintIfText;
 
     // FIXME: RecompositeLayer should also behave as a priority bit (e.g when the style change requires layout, we know that
     // the content also needs repaint and it will eventually get repainted,

Modified: trunk/Source/WebCore/rendering/style/RenderStyle.h (294194 => 294195)


--- trunk/Source/WebCore/rendering/style/RenderStyle.h	2022-05-14 14:40:27 UTC (rev 294194)
+++ trunk/Source/WebCore/rendering/style/RenderStyle.h	2022-05-14 15:24:29 UTC (rev 294195)
@@ -2076,7 +2076,7 @@
     bool changeRequiresPositionedLayoutOnly(const RenderStyle&, OptionSet<StyleDifferenceContextSensitiveProperty>& changedContextSensitiveProperties) const;
     bool changeRequiresLayerRepaint(const RenderStyle&, OptionSet<StyleDifferenceContextSensitiveProperty>& changedContextSensitiveProperties) const;
     bool changeRequiresRepaint(const RenderStyle&, OptionSet<StyleDifferenceContextSensitiveProperty>& changedContextSensitiveProperties) const;
-    bool changeRequiresRepaintIfTextOrBorderOrOutline(const RenderStyle&, OptionSet<StyleDifferenceContextSensitiveProperty>& changedContextSensitiveProperties) const;
+    bool changeRequiresRepaintIfText(const RenderStyle&, OptionSet<StyleDifferenceContextSensitiveProperty>& changedContextSensitiveProperties) const;
     bool changeRequiresRecompositeLayer(const RenderStyle&, OptionSet<StyleDifferenceContextSensitiveProperty>& changedContextSensitiveProperties) const;
 
     // non-inherited attributes

Modified: trunk/Source/WebCore/rendering/style/RenderStyleConstants.cpp (294194 => 294195)


--- trunk/Source/WebCore/rendering/style/RenderStyleConstants.cpp	2022-05-14 14:40:27 UTC (rev 294194)
+++ trunk/Source/WebCore/rendering/style/RenderStyleConstants.cpp	2022-05-14 15:24:29 UTC (rev 294195)
@@ -958,7 +958,7 @@
     case StyleDifference::Equal: ts << "equal"; break;
     case StyleDifference::RecompositeLayer: ts << "recomposite layer"; break;
     case StyleDifference::Repaint: ts << "repaint"; break;
-    case StyleDifference::RepaintIfTextOrBorderOrOutline: ts << "repaint if text or border or outline"; break;
+    case StyleDifference::RepaintIfText: ts << "repaint if text"; break;
     case StyleDifference::RepaintLayer: ts << "repaint layer"; break;
     case StyleDifference::LayoutPositionedMovementOnly: ts << "layout positioned movement only"; break;
     case StyleDifference::SimplifiedLayout: ts << "simplified layout"; break;

Modified: trunk/Source/WebCore/rendering/style/RenderStyleConstants.h (294194 => 294195)


--- trunk/Source/WebCore/rendering/style/RenderStyleConstants.h	2022-05-14 14:40:27 UTC (rev 294194)
+++ trunk/Source/WebCore/rendering/style/RenderStyleConstants.h	2022-05-14 15:24:29 UTC (rev 294195)
@@ -49,7 +49,7 @@
 // - StyleDifference::Equal - The two styles are identical
 // - StyleDifference::RecompositeLayer - The layer needs its position and transform updated, but no repaint
 // - StyleDifference::Repaint - The object just needs to be repainted.
-// - StyleDifference::RepaintIfTextOrBorderOrOutline - The object needs to be repainted if it contains text or a border or outline.
+// - StyleDifference::RepaintIfText - The object needs to be repainted if it contains text.
 // - StyleDifference::RepaintLayer - The layer and its descendant layers needs to be repainted.
 // - StyleDifference::LayoutPositionedMovementOnly - Only the position of this positioned object has been updated
 // - StyleDifference::SimplifiedLayout - Only overflow needs to be recomputed
@@ -59,7 +59,7 @@
     Equal,
     RecompositeLayer,
     Repaint,
-    RepaintIfTextOrBorderOrOutline,
+    RepaintIfText,
     RepaintLayer,
     LayoutPositionedMovementOnly,
     SimplifiedLayout,

Modified: trunk/Source/WebCore/rendering/svg/SVGResourcesCache.cpp (294194 => 294195)


--- trunk/Source/WebCore/rendering/svg/SVGResourcesCache.cpp	2022-05-14 14:40:27 UTC (rev 294194)
+++ trunk/Source/WebCore/rendering/svg/SVGResourcesCache.cpp	2022-05-14 15:24:29 UTC (rev 294195)
@@ -102,7 +102,7 @@
         return;
 
     // In this case the proper SVGFE*Element will decide whether the modified CSS properties require a relayout or repaint.
-    if (renderer.isSVGResourceFilterPrimitive() && (diff == StyleDifference::Repaint || diff == StyleDifference::RepaintIfTextOrBorderOrOutline))
+    if (renderer.isSVGResourceFilterPrimitive() && (diff == StyleDifference::Repaint || diff == StyleDifference::RepaintIfText))
         return;
 
     // Dynamic changes of CSS properties like 'clip-path' may require us to recompute the associated resources for a renderer.
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to