Title: [279544] trunk
Revision
279544
Author
[email protected]
Date
2021-07-03 10:27:46 -0700 (Sat, 03 Jul 2021)

Log Message

REGRESSION (r278377): incorrect hit-testing with clip-path()
https://bugs.webkit.org/show_bug.cgi?id=227624
<rdar://problem/79845896>

Reviewed by Simon Fraser.

Source/WebCore:

Use the correct coordinate space for clip-path based hittesting.

1. The hittest location is in the coordinate space of the painting root (hittesting is similar to painting in this context).
2. RenderBox::hitTestClipPath's accumulatedOffset (as the name implies) should include the offset from the (paint) hittest root.
3. The clip-path intersecting takes coordinates relative to the containing block.

Test: fast/clip/hit-test-with-clip-path.html

* rendering/RenderBox.cpp:
(WebCore::RenderBox::hitTestVisualOverflow const):
(WebCore::RenderBox::hitTestClipPath const): Make the hittest root coordinates relative to the containing block.
(WebCore::RenderBox::hitTestBorderRadius const):
* rendering/RenderBox.h: Let's not use locationInContainer name as it is way too generic and misleading.
* rendering/RenderLayer.cpp: Compute and pass in proper accumulated offset value.
(WebCore::RenderLayer::hitTestLayer):

LayoutTests:

* fast/clip/hit-test-with-clip-path-expected.txt: Added.
* fast/clip/hit-test-with-clip-path.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (279543 => 279544)


--- trunk/LayoutTests/ChangeLog	2021-07-03 14:17:35 UTC (rev 279543)
+++ trunk/LayoutTests/ChangeLog	2021-07-03 17:27:46 UTC (rev 279544)
@@ -1,5 +1,16 @@
 2021-07-03  Alan Bujtas  <[email protected]>
 
+        REGRESSION (r278377): incorrect hit-testing with clip-path()
+        https://bugs.webkit.org/show_bug.cgi?id=227624
+        <rdar://problem/79845896>
+
+        Reviewed by Simon Fraser.
+
+        * fast/clip/hit-test-with-clip-path-expected.txt: Added.
+        * fast/clip/hit-test-with-clip-path.html: Added.
+
+2021-07-03  Alan Bujtas  <[email protected]>
+
         [LFC][TFC] Add support for priority list of width types when expanding columns
         https://bugs.webkit.org/show_bug.cgi?id=227627
 

Added: trunk/LayoutTests/fast/clip/hit-test-with-clip-path-expected.txt (0 => 279544)


--- trunk/LayoutTests/fast/clip/hit-test-with-clip-path-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/clip/hit-test-with-clip-path-expected.txt	2021-07-03 17:27:46 UTC (rev 279544)
@@ -0,0 +1,5 @@
+hittest result:
+candidate1
+candidate2
+candidate3
+

Added: trunk/LayoutTests/fast/clip/hit-test-with-clip-path.html (0 => 279544)


--- trunk/LayoutTests/fast/clip/hit-test-with-clip-path.html	                        (rev 0)
+++ trunk/LayoutTests/fast/clip/hit-test-with-clip-path.html	2021-07-03 17:27:46 UTC (rev 279544)
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<style>
+.top-container {
+  padding: 20px;
+  margin: 3px;
+}
+
+.intermediate-container {
+    height: 50px;
+    width: 50px;
+    clip-path: inset(0);
+    background: green;
+}
+
+.hittest_candidate {
+    height: 20px;
+    width: 20px;
+    clip-path: inset(0);
+    background: blue;
+}
+
+iframe {
+  width: 200px;
+  height: 200px;
+  border: none;
+}
+</style>
+<script>
+if (window.testRunner)
+  testRunner.dumpAsText();
+</script>
+<pre id=result>hittest result: </pre>
+
+<!-- simple hittest -->
+<div class=top-container>
+  <div class=intermediate-container>
+    <div class=hittest_candidate id=candidate1></div>
+  </div>
+</div>
+<script>
+result.innerText += "\n" + document.elementFromPoint(candidate1.offsetLeft, candidate1.offsetTop).id;
+</script>
+
+<!-- non-top level paint root hittest -->
+<div style="border: 4px solid green; transform: translateZ(0)">
+  <div class=top-container>
+    <div class=intermediate-container>
+      <div class=hittest_candidate id=candidate2></div>
+    </div>
+  </div>
+</div>
+<script>
+result.innerText += "\n" + document.elementFromPoint(candidate2.offsetLeft, candidate2.offsetTop).id;
+</script>
+
+<!-- multi-level non-top level paint root hittest -->
+<div style="margin: 4px; border: 1px solid cyan; transform: translateZ(0)">
+  <div style="height: 11px;"></div>
+  <div style="border: 4px solid green; transform: translateZ(0)">
+    <div class=top-container>
+      <div class=intermediate-container>
+        <div class=hittest_candidate id=candidate3></div>
+      </div>
+    </div>
+  </div>
+</div>
+<script>
+result.innerText += "\n" + document.elementFromPoint(candidate3.offsetLeft, candidate3.offsetTop).id;
+</script>

Modified: trunk/Source/WebCore/ChangeLog (279543 => 279544)


--- trunk/Source/WebCore/ChangeLog	2021-07-03 14:17:35 UTC (rev 279543)
+++ trunk/Source/WebCore/ChangeLog	2021-07-03 17:27:46 UTC (rev 279544)
@@ -1,5 +1,29 @@
 2021-07-03  Alan Bujtas  <[email protected]>
 
+        REGRESSION (r278377): incorrect hit-testing with clip-path()
+        https://bugs.webkit.org/show_bug.cgi?id=227624
+        <rdar://problem/79845896>
+
+        Reviewed by Simon Fraser.
+
+        Use the correct coordinate space for clip-path based hittesting.
+
+        1. The hittest location is in the coordinate space of the painting root (hittesting is similar to painting in this context).
+        2. RenderBox::hitTestClipPath's accumulatedOffset (as the name implies) should include the offset from the (paint) hittest root.
+        3. The clip-path intersecting takes coordinates relative to the containing block.
+
+        Test: fast/clip/hit-test-with-clip-path.html
+
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::hitTestVisualOverflow const):
+        (WebCore::RenderBox::hitTestClipPath const): Make the hittest root coordinates relative to the containing block.
+        (WebCore::RenderBox::hitTestBorderRadius const):
+        * rendering/RenderBox.h: Let's not use locationInContainer name as it is way too generic and misleading.
+        * rendering/RenderLayer.cpp: Compute and pass in proper accumulated offset value.
+        (WebCore::RenderLayer::hitTestLayer):
+
+2021-07-03  Alan Bujtas  <[email protected]>
+
         [LFC][TFC] Add support for priority list of width types when expanding columns
         https://bugs.webkit.org/show_bug.cgi?id=227627
 

Modified: trunk/Source/WebCore/rendering/RenderBox.cpp (279543 => 279544)


--- trunk/Source/WebCore/rendering/RenderBox.cpp	2021-07-03 14:17:35 UTC (rev 279543)
+++ trunk/Source/WebCore/rendering/RenderBox.cpp	2021-07-03 17:27:46 UTC (rev 279544)
@@ -1361,7 +1361,7 @@
 }
 
 // Hit Testing
-bool RenderBox::hitTestVisualOverflow(const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const
+bool RenderBox::hitTestVisualOverflow(const HitTestLocation& hitTestLocation, const LayoutPoint& accumulatedOffset) const
 {
     if (isRenderView())
         return true;
@@ -1370,22 +1370,21 @@
     LayoutRect overflowBox = visualOverflowRect();
     flipForWritingMode(overflowBox);
     overflowBox.moveBy(adjustedLocation);
-    return locationInContainer.intersects(overflowBox);
+    return hitTestLocation.intersects(overflowBox);
 }
 
-bool RenderBox::hitTestClipPath(const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const
+bool RenderBox::hitTestClipPath(const HitTestLocation& hitTestLocation, const LayoutPoint& accumulatedOffset) const
 {
     if (!style().clipPath())
         return true;
 
-    LayoutPoint adjustedLocation = accumulatedOffset + location();
-    const LayoutSize localOffset = toLayoutSize(adjustedLocation);
-
+    auto offsetFromHitTestRoot = toLayoutSize(accumulatedOffset + location());
+    auto hitTestLocationInLocalCoordinates = hitTestLocation.point() - offsetFromHitTestRoot;
     switch (style().clipPath()->type()) {
     case ClipPathOperation::Shape: {
         auto& clipPath = downcast<ShapeClipPathOperation>(*style().clipPath());
         auto referenceBoxRect = referenceBox(clipPath.referenceBox());
-        if (!clipPath.pathForReferenceRect(referenceBoxRect).contains(locationInContainer.point() - localOffset, clipPath.windRule()))
+        if (!clipPath.pathForReferenceRect(referenceBoxRect).contains(hitTestLocationInLocalCoordinates, clipPath.windRule()))
             return false;
         break;
     }
@@ -1397,7 +1396,7 @@
         if (!is<SVGClipPathElement>(*element))
             break;
         auto& clipper = downcast<RenderSVGResourceClipper>(*element->renderer());
-        if (!clipper.hitTestClipContent(FloatRect(borderBoxRect()), FloatPoint(locationInContainer.point() - localOffset)))
+        if (!clipper.hitTestClipContent(FloatRect(borderBoxRect()), FloatPoint { hitTestLocationInLocalCoordinates }))
             return false;
         break;
     }
@@ -1408,7 +1407,7 @@
     return true;
 }
 
-bool RenderBox::hitTestBorderRadius(const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const
+bool RenderBox::hitTestBorderRadius(const HitTestLocation& hitTestLocation, const LayoutPoint& accumulatedOffset) const
 {
     if (isRenderView() || !style().hasBorderRadius())
         return true;
@@ -1417,7 +1416,7 @@
     LayoutRect borderRect = borderBoxRect();
     borderRect.moveBy(adjustedLocation);
     RoundedRect border = style().getRoundedBorderFor(borderRect);
-    return locationInContainer.intersects(border);
+    return hitTestLocation.intersects(border);
 }
 
 bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)

Modified: trunk/Source/WebCore/rendering/RenderBox.h (279543 => 279544)


--- trunk/Source/WebCore/rendering/RenderBox.h	2021-07-03 14:17:35 UTC (rev 279543)
+++ trunk/Source/WebCore/rendering/RenderBox.h	2021-07-03 17:27:46 UTC (rev 279544)
@@ -305,10 +305,10 @@
     LayoutRect reflectedRect(const LayoutRect&) const;
 
     void layout() override;
-    bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override;
-    bool hitTestVisualOverflow(const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const;
-    bool hitTestClipPath(const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const;
-    bool hitTestBorderRadius(const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const;
+    bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint& accumulatedOffset, HitTestAction) override;
+    bool hitTestVisualOverflow(const HitTestLocation&, const LayoutPoint& accumulatedOffset) const;
+    bool hitTestClipPath(const HitTestLocation&, const LayoutPoint& accumulatedOffset) const;
+    bool hitTestBorderRadius(const HitTestLocation&, const LayoutPoint& accumulatedOffset) const;
 
     LayoutUnit minPreferredLogicalWidth() const override;
     LayoutUnit maxPreferredLogicalWidth() const override;

Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (279543 => 279544)


--- trunk/Source/WebCore/rendering/RenderLayer.cpp	2021-07-03 14:17:35 UTC (rev 279543)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp	2021-07-03 17:27:46 UTC (rev 279544)
@@ -4111,8 +4111,9 @@
     LayerListMutationDetector mutationChecker(*this);
 #endif
 
+    auto offsetFromRoot = offsetFromAncestor(rootLayer);
     // FIXME: We need to correctly hit test the clip-path when we have a RenderInline too.
-    if (renderer().hasClipPath() && is<RenderBox>(renderer()) && !downcast<RenderBox>(renderer()).hitTestClipPath(hitTestLocation, toLayoutPoint(location() - renderBoxLocation())))
+    if (auto* rendererBox = this->renderBox(); rendererBox && !rendererBox->hitTestClipPath(hitTestLocation, toLayoutPoint(offsetFromRoot - toLayoutSize(renderBoxLocation()))))
         return nullptr;
 
     // Begin by walking our list of positive layers from highest z-index down to the lowest z-index.
@@ -4135,8 +4136,7 @@
 
     // Collect the fragments. This will compute the clip rectangles for each layer fragment.
     LayerFragments layerFragments;
-    collectFragments(layerFragments, rootLayer, hitTestRect, IncludeCompositedPaginatedLayers, RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip,
-        offsetFromAncestor(rootLayer));
+    collectFragments(layerFragments, rootLayer, hitTestRect, IncludeCompositedPaginatedLayers, RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip, offsetFromRoot);
 
     LayoutPoint localPoint;
     if (canResize() && m_scrollableArea && m_scrollableArea->hitTestResizerInFragments(layerFragments, hitTestLocation, localPoint)) {
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to