Title: [295630] trunk
Revision
295630
Author
[email protected]
Date
2022-06-16 23:58:01 -0700 (Thu, 16 Jun 2022)

Log Message

Record InteractionRegions per RenderLayer, instead of all on the root
https://bugs.webkit.org/show_bug.cgi?id=241503
<rdar://problem/93855866>

Reviewed by Simon Fraser.

* Source/WebCore/page/DebugPageOverlays.cpp:
(WebCore::pathsForRegion):
(WebCore::InteractionRegionOverlay::activeLayer const):
(WebCore::InteractionRegionOverlay::activeRegion const):
(WebCore::InteractionRegionOverlay::drawRect):
Hit test to the correct layer and retrieve regions from that layer for the debug overlay.
Also, fix some coordinate conversion now that we actually see non-root layers.

* Source/WebCore/page/InteractionRegion.cpp:
(WebCore::cursorTypeForElement):
(WebCore::interactionRegionForRenderedRegion):
(WebCore::absoluteBoundingRectForRange): Deleted.
(WebCore::regionForElement): Deleted.
(WebCore::interactionRegions): Deleted.
* Source/WebCore/page/InteractionRegion.h:
Refactor InteractionRegion to take the same arguments as EventRegion::unite(),
so we can call it from there. Use the painting-originated rects in the Region,
instead of computing them ourselves.

* Source/WebCore/rendering/EventRegion.cpp:
(WebCore::EventRegionContext::unite):
(WebCore::EventRegionContext::uniteInteractionRegions):
(WebCore::EventRegionContext::copyInteractionRegionsToEventRegion):
(WebCore::EventRegion::computeInteractionRegions): Deleted.
* Source/WebCore/rendering/EventRegion.h:
Collect InteractionRegions in a HashMap by element identifier, in order to
unite the rects for a given element -- but not *across* elements, like other EventRegions.
We need to keep them separate so that we can add an indicator for the united region.
Also, unusually, we maintain this map on the EventRegionContext as we paint, and copy them
to the serialized type at the end, to avoid having two different members on
EventRegion that are only valid on opposite sides of the process boundary.

* Source/WebCore/rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::updateEventRegion):
Stop computing interaction regions for the root layer.

* Source/WebCore/rendering/RenderBlock.cpp:
(WebCore::RenderBlock::paintObject):
* Source/WebCore/rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::updateScrollLayerClipping):
* Source/WebCore/rendering/RenderReplaced.cpp:
(WebCore::RenderReplaced::paint):
* Source/WebCore/rendering/TextBoxPainter.cpp:
(WebCore::TextBoxPainter<TextBoxPath>::paint):
Plumb the renderer through to EventRegionContext so that we can use it in
InteractionRegion::interactionRegionForRenderedRegion.

* LayoutTests/interaction-region/click-handler-in-shadowed-layer-expected.txt: Added.
* LayoutTests/interaction-region/click-handler-in-shadowed-layer.html: Added.
* LayoutTests/interaction-region/inline-link-in-layer-expected.txt: Added.
* LayoutTests/interaction-region/inline-link-in-layer.html: Added.
* LayoutTests/interaction-region/inline-link-in-composited-iframe-expected.txt: Added.
* LayoutTests/interaction-region/inline-link-in-composited-iframe.html: Added.
* LayoutTests/interaction-region/inline-link-in-non-composited-iframe-expected.txt: Added.
* LayoutTests/interaction-region/inline-link-in-non-composited-iframe.html: Added.
Add some tests.

Canonical link: https://commits.webkit.org/251635@main

Modified Paths

Added Paths

Diff

Added: trunk/LayoutTests/interaction-region/click-handler-in-shadowed-layer-expected.txt (0 => 295630)


--- trunk/LayoutTests/interaction-region/click-handler-in-shadowed-layer-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/interaction-region/click-handler-in-shadowed-layer-expected.txt	2022-06-17 06:58:01 UTC (rev 295630)
@@ -0,0 +1,34 @@
+ (GraphicsLayer
+  (anchor 0.00 0.00)
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (contentsOpaque 1)
+      (drawsContent 1)
+      (backgroundColor #FFFFFF)
+      (event region
+        (rect (0,0) width=800 height=600)
+      )
+      (children 1
+        (GraphicsLayer
+          (offsetFromRenderer width=-28 height=-28)
+          (position 72.00 72.00)
+          (bounds 256.00 256.00)
+          (drawsContent 1)
+          (event region
+            (rect (28,28) width=200 height=200)
+
+          (interaction regions [
+            (region
+                (rect (28,28) width=100 height=100)
+)
+            (hasLightBackground 1)
+            (borderRadius 10.00)])
+          )
+        )
+      )
+    )
+  )
+)
+

Added: trunk/LayoutTests/interaction-region/click-handler-in-shadowed-layer.html (0 => 295630)


--- trunk/LayoutTests/interaction-region/click-handler-in-shadowed-layer.html	                        (rev 0)
+++ trunk/LayoutTests/interaction-region/click-handler-in-shadowed-layer.html	2022-06-17 06:58:01 UTC (rev 295630)
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<style>
+    body { margin: 0; }
+
+    #layer {
+        position: absolute;
+        top: 100px;
+        left: 100px;
+        width: 200px;
+        height: 200px;
+
+        will-change: opacity;
+
+        box-shadow: 0 0 20px black;
+    }
+
+    #button {
+        display: inline-block;
+        width: 100px;
+        height: 100px;
+        background-color: green;
+        cursor: pointer;
+        border-radius: 10px;
+    }
+</style>
+<body>
+<div id="layer">
+    <div id="button" _onclick_="click()"></div>
+</div>
+
+<pre id="results"></pre>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+
+window._onload_ = function () {
+    if (window.internals)
+       results.textContent = internals.layerTreeAsText(document, internals.LAYER_TREE_INCLUDES_EVENT_REGION | internals.LAYER_TREE_INCLUDES_ROOT_LAYER_PROPERTIES);
+};
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/interaction-region/inline-link-in-composited-iframe-expected.txt (0 => 295630)


--- trunk/LayoutTests/interaction-region/inline-link-in-composited-iframe-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/interaction-region/inline-link-in-composited-iframe-expected.txt	2022-06-17 06:58:01 UTC (rev 295630)
@@ -0,0 +1,42 @@
+This is a link, outside the frame.
+
+(GraphicsLayer
+  (anchor 0.00 0.00)
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (contentsOpaque 1)
+      (drawsContent 1)
+      (backgroundColor #FFFFFF)
+      (event region
+        (rect (0,0) width=800 height=600)
+
+      (interaction regions [
+        (region
+            (rect (-3,-3) width=35 height=24)
+)
+        (hasLightBackground 1)
+        (borderRadius 0.00)])
+      )
+      (children 1
+        (GraphicsLayer
+          (position 0.00 18.00)
+          (bounds 204.00 204.00)
+          (drawsContent 1)
+          (event region
+            (rect (2,2) width=200 height=200)
+
+          (interaction regions [
+            (region
+                (rect (7,7) width=35 height=24)
+)
+            (hasLightBackground 1)
+            (borderRadius 0.00)])
+          )
+        )
+      )
+    )
+  )
+)
+

Added: trunk/LayoutTests/interaction-region/inline-link-in-composited-iframe.html (0 => 295630)


--- trunk/LayoutTests/interaction-region/inline-link-in-composited-iframe.html	                        (rev 0)
+++ trunk/LayoutTests/interaction-region/inline-link-in-composited-iframe.html	2022-06-17 06:58:01 UTC (rev 295630)
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<style>
+    body { margin: 0; }
+
+    #frame {
+        width: 200px;
+        height: 200px;
+        will-change: opacity;
+    }
+</style>
+<body>
+<a href="" is a link, outside the frame.<br/>
+<iframe id="frame" srcdoc="<a href=''>This</a> is a link, inside the frame."></iframe>
+
+<pre id="results"></pre>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+
+window._onload_ = function () {
+    if (window.internals)
+       results.textContent = internals.layerTreeAsText(document, internals.LAYER_TREE_INCLUDES_EVENT_REGION | internals.LAYER_TREE_INCLUDES_ROOT_LAYER_PROPERTIES);
+};
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/interaction-region/inline-link-in-layer-expected.txt (0 => 295630)


--- trunk/LayoutTests/interaction-region/inline-link-in-layer-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/interaction-region/inline-link-in-layer-expected.txt	2022-06-17 06:58:01 UTC (rev 295630)
@@ -0,0 +1,42 @@
+This is a link, outside the layer.
+This is a link, inside the layer.
+(GraphicsLayer
+  (anchor 0.00 0.00)
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (contentsOpaque 1)
+      (drawsContent 1)
+      (backgroundColor #FFFFFF)
+      (event region
+        (rect (0,0) width=800 height=600)
+
+      (interaction regions [
+        (region
+            (rect (-3,-3) width=35 height=24)
+)
+        (hasLightBackground 1)
+        (borderRadius 0.00)])
+      )
+      (children 1
+        (GraphicsLayer
+          (position 0.00 18.00)
+          (bounds 200.00 200.00)
+          (drawsContent 1)
+          (event region
+            (rect (0,0) width=200 height=200)
+
+          (interaction regions [
+            (region
+                (rect (-3,-3) width=35 height=24)
+)
+            (hasLightBackground 1)
+            (borderRadius 0.00)])
+          )
+        )
+      )
+    )
+  )
+)
+

Added: trunk/LayoutTests/interaction-region/inline-link-in-layer.html (0 => 295630)


--- trunk/LayoutTests/interaction-region/inline-link-in-layer.html	                        (rev 0)
+++ trunk/LayoutTests/interaction-region/inline-link-in-layer.html	2022-06-17 06:58:01 UTC (rev 295630)
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<style>
+    body { margin: 0; }
+
+    #layer {
+        width: 200px;
+        height: 200px;
+        will-change: opacity;
+    }
+</style>
+<body>
+<a href="" is a link, outside the layer.
+<div id="layer">
+    <a href="" is a link, inside the layer.
+</div>
+
+<pre id="results"></pre>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+
+window._onload_ = function () {
+    if (window.internals)
+       results.textContent = internals.layerTreeAsText(document, internals.LAYER_TREE_INCLUDES_EVENT_REGION | internals.LAYER_TREE_INCLUDES_ROOT_LAYER_PROPERTIES);
+};
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/interaction-region/inline-link-in-non-composited-iframe-expected.txt (0 => 295630)


--- trunk/LayoutTests/interaction-region/inline-link-in-non-composited-iframe-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/interaction-region/inline-link-in-non-composited-iframe-expected.txt	2022-06-17 06:58:01 UTC (rev 295630)
@@ -0,0 +1,30 @@
+This is a link, outside the frame.
+
+(GraphicsLayer
+  (anchor 0.00 0.00)
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (contentsOpaque 1)
+      (drawsContent 1)
+      (backgroundColor #FFFFFF)
+      (event region
+        (rect (0,0) width=800 height=600)
+
+      (interaction regions [
+        (region
+            (rect (7,25) width=35 height=24)
+)
+        (hasLightBackground 1)
+        (borderRadius 0.00),
+        (region
+            (rect (-3,-3) width=35 height=24)
+)
+        (hasLightBackground 1)
+        (borderRadius 0.00)])
+      )
+    )
+  )
+)
+

Added: trunk/LayoutTests/interaction-region/inline-link-in-non-composited-iframe.html (0 => 295630)


--- trunk/LayoutTests/interaction-region/inline-link-in-non-composited-iframe.html	                        (rev 0)
+++ trunk/LayoutTests/interaction-region/inline-link-in-non-composited-iframe.html	2022-06-17 06:58:01 UTC (rev 295630)
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<style>
+    body { margin: 0; }
+
+    #frame {
+        width: 200px;
+        height: 200px;
+    }
+</style>
+<body>
+<a href="" is a link, outside the frame.<br/>
+<iframe id="frame" srcdoc="<a href=''>This</a> is a link, inside the frame."></iframe>
+
+<pre id="results"></pre>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+
+window._onload_ = function () {
+    if (window.internals)
+       results.textContent = internals.layerTreeAsText(document, internals.LAYER_TREE_INCLUDES_EVENT_REGION | internals.LAYER_TREE_INCLUDES_ROOT_LAYER_PROPERTIES);
+};
+</script>
+</body>
+</html>

Modified: trunk/Source/WebCore/page/DebugPageOverlays.cpp (295629 => 295630)


--- trunk/Source/WebCore/page/DebugPageOverlays.cpp	2022-06-17 06:23:42 UTC (rev 295629)
+++ trunk/Source/WebCore/page/DebugPageOverlays.cpp	2022-06-17 06:58:01 UTC (rev 295630)
@@ -33,6 +33,7 @@
 #include "FrameView.h"
 #include "Gradient.h"
 #include "GraphicsContext.h"
+#include "HitTestResult.h"
 #include "InteractionRegion.h"
 #include "Page.h"
 #include "PageOverlay.h"
@@ -296,29 +297,43 @@
     return true;
 }
 
-static Vector<Path> pathsForRegion(const InteractionRegion& region)
+static Vector<Path> pathsForRegion(const Region& region, float borderRadius)
 {
     static constexpr float radius = 4;
 
-    Vector<FloatRect> rects = region.regionInLayerCoordinates.rects().map([] (auto rect) -> FloatRect {
+    Vector<FloatRect> rects = region.rects().map([] (auto rect) -> FloatRect {
         return rect;
     });
-    return PathUtilities::pathsWithShrinkWrappedRects(rects, std::max(region.borderRadius, radius));
+    return PathUtilities::pathsWithShrinkWrappedRects(rects, std::max(borderRadius, radius));
 }
 
 std::optional<std::pair<RenderLayer&, GraphicsLayer&>> InteractionRegionOverlay::activeLayer() const
 {
-    // FIXME: This should hit-test to find the correct layer, once we store InteractionRegions
-    // on each layer instead of keeping them all on the root.
-    auto* frameView = m_page.mainFrame().view();
-    if (!frameView || !frameView->renderView())
+    constexpr OptionSet<HitTestRequest::Type> hitType {
+        HitTestRequest::Type::ReadOnly,
+        HitTestRequest::Type::Active,
+        HitTestRequest::Type::AllowChildFrameContent
+    };
+    HitTestResult result(m_mouseLocationInContentCoordinates);
+    m_page.mainFrame().document()->hitTest(hitType, result);
+
+    auto* hitNode = result.innerNode();
+    if (!hitNode || !hitNode->renderer())
         return std::nullopt;
 
-    auto* layer = frameView->renderView()->enclosingLayer();
-    if (!layer || !layer->backing())
+    auto* rendererLayer = hitNode->renderer()->enclosingLayer();
+    if (!rendererLayer)
         return std::nullopt;
 
-    auto* graphicsLayer = layer->backing()->graphicsLayer();
+    auto* layer = rendererLayer->enclosingCompositingLayerForRepaint().layer;
+    if (!layer)
+        return std::nullopt;
+
+    auto* backing = layer->backing();
+    if (!backing)
+        return std::nullopt;
+
+    auto* graphicsLayer = backing->graphicsLayer();
     if (!graphicsLayer)
         return std::nullopt;
 
@@ -334,30 +349,33 @@
     auto& [layer, graphicsLayer] = *layerPair;
 
     std::optional<InteractionRegion> hitRegion;
+    Region hitRegionInOverlayCoordinates;
     float hitRegionArea = 0;
-    
-    FloatSize offset(layer.offsetFromAncestor(&layer.compositor().rootRenderLayer()));
-    FloatPoint mouseLocationInLayerCoordinates = m_mouseLocationInContentCoordinates - offset;
 
     auto regions = graphicsLayer.eventRegion().interactionRegions();
     for (const auto& region : regions) {
         float area = 0;
         FloatRect boundingRect;
-        for (const auto& rect : region.regionInLayerCoordinates.rects()) {
+        Region regionInOverlayCoordinates;
+
+        for (auto rect : region.regionInLayerCoordinates.rects()) {
+            rect.move(roundedIntSize(graphicsLayer.offsetFromRenderer()));
+            IntRect rectInOverlayCoordinates = layer.renderer().localToAbsoluteQuad(FloatRect { rect }).enclosingBoundingBox();
             if (boundingRect.isEmpty())
-                boundingRect = rect;
+                boundingRect = rectInOverlayCoordinates;
             else
-                boundingRect.unite(rect);
-            area += rect.area();
+                boundingRect.unite(rectInOverlayCoordinates);
+            area += rectInOverlayCoordinates.area();
+            regionInOverlayCoordinates.unite(rectInOverlayCoordinates);
         }
 
-        if (!boundingRect.contains(mouseLocationInLayerCoordinates))
+        if (!boundingRect.contains(m_mouseLocationInContentCoordinates))
             continue;
 
-        auto paths = pathsForRegion(region);
+        auto paths = pathsForRegion(regionInOverlayCoordinates, region.borderRadius);
         bool didHitRegion = false;
         for (const auto& path : paths) {
-            if (path.contains(mouseLocationInLayerCoordinates)) {
+            if (path.contains(m_mouseLocationInContentCoordinates)) {
                 didHitRegion = true;
                 break;
             }
@@ -372,11 +390,12 @@
         if (didHitRegion && (!hitRegion || area < hitRegionArea)) {
             hitRegion = region;
             hitRegionArea = area;
+            hitRegionInOverlayCoordinates = regionInOverlayCoordinates;
         }
     }
     
     if (hitRegion)
-        hitRegion->regionInLayerCoordinates.translate(roundedIntSize(offset));
+        hitRegion->regionInLayerCoordinates = hitRegionInOverlayCoordinates;
 
     return hitRegion;
 #else
@@ -502,7 +521,7 @@
         Vector<Path> clipPaths;
 
         if (shouldClip)
-            clipPaths = pathsForRegion(*region);
+            clipPaths = pathsForRegion(region->regionInLayerCoordinates, region->borderRadius);
 
         bool shouldUseBackdropGradient = !shouldClip || !region || (!valueForSetting("wash"_s) && valueForSetting("clip"_s));
 

Modified: trunk/Source/WebCore/page/InteractionRegion.cpp (295629 => 295630)


--- trunk/Source/WebCore/page/InteractionRegion.cpp	2022-06-17 06:23:42 UTC (rev 295629)
+++ trunk/Source/WebCore/page/InteractionRegion.cpp	2022-06-17 06:58:01 UTC (rev 295630)
@@ -38,6 +38,8 @@
 #include "PathUtilities.h"
 #include "PlatformMouseEvent.h"
 #include "RenderBox.h"
+#include "RenderLayer.h"
+#include "RenderLayerBacking.h"
 #include "SimpleRange.h"
 #include <wtf/NeverDestroyed.h>
 
@@ -45,94 +47,6 @@
 
 InteractionRegion::~InteractionRegion() = default;
 
-static FloatRect absoluteBoundingRectForRange(const SimpleRange& range)
-{
-    return unionRectIgnoringZeroRects(RenderObject::absoluteBorderAndTextRects(range, {
-        RenderObject::BoundingRectBehavior::RespectClipping,
-        RenderObject::BoundingRectBehavior::UseVisibleBounds,
-        RenderObject::BoundingRectBehavior::IgnoreTinyRects,
-    }));
-}
-
-static std::optional<InteractionRegion> regionForElement(Element& element)
-{
-    Ref document = element.document();
-    Ref frameView = *document->frame()->view();
-    Ref mainFrameView = *document->frame()->mainFrame().view();
-    
-    IntRect frameClipRect;
-#if PLATFORM(IOS_FAMILY)
-    frameClipRect = enclosingIntRect(frameView->exposedContentRect());
-#else
-    if (auto viewExposedRect = frameView->viewExposedRect())
-        frameClipRect = enclosingIntRect(*viewExposedRect);
-    else
-        frameClipRect = frameView->visibleContentRect();
-#endif
-
-    auto* renderer = element.renderer();
-    if (!renderer)
-        return std::nullopt;
-
-    Vector<FloatRect> rectsInContentCoordinates;
-    InteractionRegion region;
-
-    region.elementIdentifier = element.identifier();
-
-    auto linkRange = makeRangeSelectingNode(element);
-    if (linkRange)
-        region.hasLightBackground = estimatedBackgroundColorForRange(*linkRange, *element.document().frame()).luminance() > 0.5;
-    
-    if (linkRange && renderer->isInline() && !renderer->isReplacedOrInlineBlock()) {
-        static constexpr float inlinePadding = 3;
-        OptionSet<RenderObject::BoundingRectBehavior> behavior { RenderObject::BoundingRectBehavior::RespectClipping };
-        rectsInContentCoordinates = RenderObject::absoluteTextRects(*linkRange, behavior).map([&](auto rect) -> FloatRect {
-            rect.inflate(inlinePadding);
-            return rect;
-        });
-
-        if (rectsInContentCoordinates.isEmpty()) {
-            auto boundingRectForRange = absoluteBoundingRectForRange(*linkRange);
-            if (!boundingRectForRange.isEmpty()) {
-                boundingRectForRange.inflate(inlinePadding);
-                rectsInContentCoordinates = { boundingRectForRange };
-            }
-        }
-    }
-
-    if (rectsInContentCoordinates.isEmpty())
-        rectsInContentCoordinates = { renderer->absoluteBoundingBoxRect() };
-    
-    auto layoutArea = mainFrameView->layoutSize().area();
-    rectsInContentCoordinates = compactMap(rectsInContentCoordinates, [&] (auto rect) -> std::optional<FloatRect> {
-        if (rect.area() > layoutArea / 2)
-            return std::nullopt;
-        return rect;
-    });
-    
-    if (is<RenderBox>(*renderer)) {
-        RoundedRect::Radii borderRadii = downcast<RenderBox>(*renderer).borderRadii();
-        region.borderRadius = borderRadii.minimumRadius();
-    }
-    
-    for (auto rect : rectsInContentCoordinates) {
-        auto contentsRect = rect;
-
-        if (frameView.ptr() != mainFrameView.ptr())
-            contentsRect.intersect(frameClipRect);
-
-        if (contentsRect.isEmpty())
-            continue;
-
-        region.regionInLayerCoordinates.unite(enclosingIntRect(contentsRect));
-    }
-
-    if (region.regionInLayerCoordinates.isEmpty())
-        return std::nullopt;
-
-    return region;
-}
-
 static CursorType cursorTypeForElement(Element& element)
 {
     auto* renderer = element.renderer();
@@ -139,58 +53,70 @@
     auto* style = renderer ? &renderer->style() : nullptr;
     auto cursorType = style ? style->cursor() : CursorType::Auto;
 
-    if (cursorType == CursorType::Auto && element.enclosingLinkEventParentOrSelf() && element.isLink())
+    if (cursorType == CursorType::Auto && element.enclosingLinkEventParentOrSelf())
         cursorType = CursorType::Pointer;
 
     return cursorType;
 }
 
-Vector<InteractionRegion> interactionRegions(Page& page, FloatRect rect)
+std::optional<InteractionRegion> interactionRegionForRenderedRegion(RenderObject& regionRenderer, const Region& region)
 {
-    Ref frame(page.mainFrame());
-    RefPtr frameView = frame->view();
-    
-    if (!frameView)
-        return { };
+    if (!regionRenderer.node())
+        return std::nullopt;
 
-    frameView->updateLayoutAndStyleIfNeededRecursive();
-    
-    RefPtr document = frame->document();
-    if (!document)
-        return { };
+    auto bounds = region.bounds();
 
-    auto result = HitTestResult { LayoutRect(rect) };
-    HitTestRequest request({
-        HitTestRequest::Type::ReadOnly,
-        HitTestRequest::Type::Active,
-        HitTestRequest::Type::AllowVisibleChildFrameContentOnly,
-        HitTestRequest::Type::CollectMultipleElements
-    });
-    document->hitTest(request, result);
+    if (bounds.isEmpty())
+        return std::nullopt;
 
-    Vector<InteractionRegion> regions;
+    auto& mainFrameView = *regionRenderer.document().frame()->mainFrame().view();
+    auto layoutArea = mainFrameView.layoutSize().area();
 
-    for (const auto& node : result.listBasedTestResult()) {
-        if (!is<Element>(node.get()))
-            continue;
-        auto& element = downcast<Element>(node.get());
-        if (!element.renderer())
-            continue;
+    if (bounds.area() > layoutArea / 2)
+        return std::nullopt;
 
-        auto& renderer = *element.renderer();
-        // FIXME: Consider also allowing elements that only receive touch events.
-        if (!renderer.style().eventListenerRegionTypes().contains(EventListenerRegionType::MouseClick))
-            continue;
+    auto element = dynamicDowncast<Element>(regionRenderer.node());
+    if (!element) 
+        element = regionRenderer.node()->parentElement();
+    if (auto* linkElement = element->enclosingLinkEventParentOrSelf())
+        element = linkElement;
 
-        if (cursorTypeForElement(element) != CursorType::Pointer && !is<HTMLFormControlElement>(element))
-            continue;
+    if (!element || !element->renderer())
+        return std::nullopt;
+    auto& renderer = *element->renderer();
 
-        auto region = regionForElement(element);
-        if (region)
-            regions.append(*region);
+    // FIXME: Consider also allowing elements that only receive touch events.
+    if (!renderer.style().eventListenerRegionTypes().contains(EventListenerRegionType::MouseClick))
+        return std::nullopt;
+
+    auto cursor = cursorTypeForElement(*element);
+    if (cursor != CursorType::Pointer && !is<HTMLFormControlElement>(element))
+        return std::nullopt;
+
+    bool isInlineNonBlock = renderer.isInline() && !renderer.isReplacedOrInlineBlock();
+
+    if (isInlineNonBlock) {
+        static constexpr float inlinePadding = 3;
+        bounds.inflate(inlinePadding);
     }
 
-    return regions;
+    bool hasLightBackground = true;
+    if (auto linkRange = makeRangeSelectingNode(*element))
+        hasLightBackground = estimatedBackgroundColorForRange(*linkRange, *element->document().frame()).luminance() > 0.5;
+
+    float borderRadius = 0;
+    if (const auto& renderBox = dynamicDowncast<RenderBox>(renderer))
+        borderRadius = renderBox->borderRadii().minimumRadius();
+
+    Region boundsRegion;
+    boundsRegion.unite(bounds);
+
+    return { {
+        element->identifier(),
+        boundsRegion,
+        hasLightBackground,
+        borderRadius
+    } };
 }
 
 TextStream& operator<<(TextStream& ts, const InteractionRegion& interactionRegion)

Modified: trunk/Source/WebCore/page/InteractionRegion.h (295629 => 295630)


--- trunk/Source/WebCore/page/InteractionRegion.h	2022-06-17 06:23:42 UTC (rev 295629)
+++ trunk/Source/WebCore/page/InteractionRegion.h	2022-06-17 06:58:01 UTC (rev 295630)
@@ -40,7 +40,9 @@
 
 namespace WebCore {
 
+class Element;
 class Page;
+class RenderObject;
 
 struct InteractionRegion {
     ElementIdentifier elementIdentifier;
@@ -62,7 +64,7 @@
         && a.borderRadius == b.borderRadius;
 }
 
-WEBCORE_EXPORT Vector<InteractionRegion> interactionRegions(Page&, FloatRect rectInContentCoordinates);
+WEBCORE_EXPORT std::optional<InteractionRegion> interactionRegionForRenderedRegion(RenderObject&, const Region&);
 
 WTF::TextStream& operator<<(WTF::TextStream&, const InteractionRegion&);
 

Modified: trunk/Source/WebCore/rendering/EventRegion.cpp (295629 => 295630)


--- trunk/Source/WebCore/rendering/EventRegion.cpp	2022-06-17 06:23:42 UTC (rev 295629)
+++ trunk/Source/WebCore/rendering/EventRegion.cpp	2022-06-17 06:58:01 UTC (rev 295630)
@@ -26,8 +26,12 @@
 #include "config.h"
 #include "EventRegion.h"
 
+#include "ElementAncestorIterator.h"
+#include "HTMLFormControlElement.h"
 #include "Logging.h"
+#include "RenderBox.h"
 #include "RenderStyle.h"
+#include "SimpleRange.h"
 #include <wtf/text/TextStream.h>
 
 namespace WebCore {
@@ -73,10 +77,13 @@
     m_clipStack.removeLast();
 }
 
-void EventRegionContext::unite(const Region& region, const RenderStyle& style, bool overrideUserModifyIsEditable)
+void EventRegionContext::unite(const Region& region, RenderObject& renderer, const RenderStyle& style, bool overrideUserModifyIsEditable)
 {
     if (m_transformStack.isEmpty() && m_clipStack.isEmpty()) {
         m_eventRegion.unite(region, style, overrideUserModifyIsEditable);
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+        uniteInteractionRegions(region, renderer);
+#endif
         return;
     }
 
@@ -86,6 +93,11 @@
         transformedAndClippedRegion.intersect(m_clipStack.last());
 
     m_eventRegion.unite(transformedAndClippedRegion, style, overrideUserModifyIsEditable);
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+    uniteInteractionRegions(transformedAndClippedRegion, renderer);
+#else
+    UNUSED_PARAM(renderer);
+#endif
 }
 
 bool EventRegionContext::contains(const IntRect& rect) const
@@ -96,6 +108,26 @@
     return m_eventRegion.contains(m_transformStack.last().mapRect(rect));
 }
 
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+
+void EventRegionContext::uniteInteractionRegions(const Region& region, RenderObject& renderer)
+{
+    if (renderer.page().shouldBuildInteractionRegions()) {
+        if (auto interactionRegion = interactionRegionForRenderedRegion(renderer, region)) {
+            auto addResult = m_interactionRegionsByElement.add(interactionRegion->elementIdentifier, *interactionRegion);
+            if (!addResult.isNewEntry)
+                addResult.iterator->value.regionInLayerCoordinates.unite(interactionRegion->regionInLayerCoordinates);
+        }
+    }
+}
+
+void EventRegionContext::copyInteractionRegionsToEventRegion()
+{
+    m_eventRegion.uniteInteractionRegions(copyToVector(m_interactionRegionsByElement.values()));
+}
+
+#endif
+
 EventRegion::EventRegion() = default;
 
 bool EventRegion::operator==(const EventRegion& other) const
@@ -323,12 +355,6 @@
     m_interactionRegions.appendVector(interactionRegions);
 }
 
-void EventRegion::computeInteractionRegions(Page& page, IntRect rect)
-{
-    // FIXME: Collect regions from `EventRegion::unite` instead of hit-testing, so that they are per-layer.
-    uniteInteractionRegions(WebCore::interactionRegions(page, rect));
-}
-
 #endif
 
 void EventRegion::dump(TextStream& ts) const

Modified: trunk/Source/WebCore/rendering/EventRegion.h (295629 => 295630)


--- trunk/Source/WebCore/rendering/EventRegion.h	2022-06-17 06:23:42 UTC (rev 295629)
+++ trunk/Source/WebCore/rendering/EventRegion.h	2022-06-17 06:58:01 UTC (rev 295630)
@@ -32,11 +32,13 @@
 #include "RenderStyleConstants.h"
 #include "TouchAction.h"
 #include <wtf/OptionSet.h>
+#include <wtf/Ref.h>
 #include <wtf/Vector.h>
 
 namespace WebCore {
 
 class EventRegion;
+class RenderObject;
 class RenderStyle;
 
 class EventRegionContext {
@@ -49,13 +51,22 @@
     void pushClip(const IntRect&);
     void popClip();
 
-    void unite(const Region&, const RenderStyle&, bool overrideUserModifyIsEditable = false);
+    void unite(const Region&, RenderObject&, const RenderStyle&, bool overrideUserModifyIsEditable = false);
     bool contains(const IntRect&) const;
 
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+    void uniteInteractionRegions(const Region&, RenderObject&);
+    void copyInteractionRegionsToEventRegion();
+#endif
+
 private:
     EventRegion& m_eventRegion;
     Vector<AffineTransform> m_transformStack;
     Vector<IntRect> m_clipStack;
+
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+    HashMap<ElementIdentifier, InteractionRegion> m_interactionRegionsByElement;
+#endif
 };
 
 class EventRegionContextStateSaver {
@@ -136,7 +147,6 @@
 #if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
     const Vector<InteractionRegion>& interactionRegions() const { return m_interactionRegions; }
     void uniteInteractionRegions(const Vector<InteractionRegion>&);
-    void computeInteractionRegions(Page&, IntRect);
 #endif
 
 private:

Modified: trunk/Source/WebCore/rendering/RenderBlock.cpp (295629 => 295630)


--- trunk/Source/WebCore/rendering/RenderBlock.cpp	2022-06-17 06:23:42 UTC (rev 295629)
+++ trunk/Source/WebCore/rendering/RenderBlock.cpp	2022-06-17 06:58:01 UTC (rev 295630)
@@ -1287,7 +1287,7 @@
         if (paintInfo.paintBehavior.contains(PaintBehavior::EventRegionIncludeBackground) && visibleToHitTesting()) {
             auto borderRegion = approximateAsRegion(style().getRoundedBorderFor(borderRect));
             LOG_WITH_STREAM(EventRegions, stream << "RenderBlock " << *this << " uniting region " << borderRegion);
-            paintInfo.eventRegionContext->unite(borderRegion, style(), isTextControl() && downcast<RenderTextControl>(*this).textFormControlElement().isInnerTextElementEditable());
+            paintInfo.eventRegionContext->unite(borderRegion, *this, style(), isTextControl() && downcast<RenderTextControl>(*this).textFormControlElement().isInnerTextElementEditable());
         }
 
         if (!paintInfo.paintBehavior.contains(PaintBehavior::EventRegionIncludeForeground))

Modified: trunk/Source/WebCore/rendering/RenderLayerBacking.cpp (295629 => 295630)


--- trunk/Source/WebCore/rendering/RenderLayerBacking.cpp	2022-06-17 06:23:42 UTC (rev 295629)
+++ trunk/Source/WebCore/rendering/RenderLayerBacking.cpp	2022-06-17 06:58:01 UTC (rev 295630)
@@ -1825,8 +1825,11 @@
         EventRegion eventRegion;
         auto eventRegionContext = eventRegion.makeContext();
         if (visibleToHitTesting)
-            eventRegionContext.unite(enclosingIntRect(FloatRect({ }, graphicsLayer->size())), renderer().style());
+            eventRegionContext.unite(enclosingIntRect(FloatRect({ }, graphicsLayer->size())), renderer(), renderer().style());
 
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+        eventRegionContext.copyInteractionRegionsToEventRegion();
+#endif
         graphicsLayer->setEventRegion(WTFMove(eventRegion));
     };
 
@@ -1845,26 +1848,22 @@
             if (&graphicsLayer == m_scrolledContentsLayer) {
                 // Initialize scrolled contents layer with layer-sized event region as it can all used for scrolling.
                 // This avoids generating unnecessarily complex event regions. We still need to to do the paint to capture touch-action regions.
-                eventRegionContext.unite(layerBounds, renderer().style());
+                eventRegionContext.unite(layerBounds, renderer(), renderer().style());
             }
         }
 
         if (m_owningLayer.isRenderViewLayer() && (&graphicsLayer == m_graphicsLayer || &graphicsLayer == m_foregroundLayer)) {
             // Event handlers on the root cover the entire layer.
-            eventRegionContext.unite(layerBounds, renderer().style());
+            eventRegionContext.unite(layerBounds, renderer(), renderer().style());
         }
 
-#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
-        // FIXME: We should collect editable regions per-layer instead of keeping them all on the root.
-        if (renderer().page().shouldBuildInteractionRegions() && m_owningLayer.isRenderViewLayer() && (&graphicsLayer == m_graphicsLayer))
-            eventRegion.computeInteractionRegions(renderer().page(), layerBounds);
-#endif
-
         auto dirtyRect = enclosingIntRect(FloatRect(FloatPoint(graphicsLayer.offsetFromRenderer()), graphicsLayer.size()));
         paintIntoLayer(&graphicsLayer, nullContext, dirtyRect, { }, &eventRegionContext);
 
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+        eventRegionContext.copyInteractionRegionsToEventRegion();
+#endif
         eventRegion.translate(toIntSize(layerOffset));
-
         graphicsLayer.setEventRegion(WTFMove(eventRegion));
     };
 

Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp (295629 => 295630)


--- trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2022-06-17 06:23:42 UTC (rev 295629)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2022-06-17 06:58:01 UTC (rev 295630)
@@ -2275,7 +2275,10 @@
     if (layerForClipping == m_clipLayer) {
         EventRegion eventRegion;
         auto eventRegionContext = eventRegion.makeContext();
-        eventRegionContext.unite(IntRect({ }, layerSize), RenderStyle::defaultStyle());
+        eventRegionContext.unite(IntRect({ }, layerSize), m_renderView, RenderStyle::defaultStyle());
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+        eventRegionContext.copyInteractionRegionsToEventRegion();
+#endif
         m_clipLayer->setEventRegion(WTFMove(eventRegion));
     }
 #endif

Modified: trunk/Source/WebCore/rendering/RenderReplaced.cpp (295629 => 295630)


--- trunk/Source/WebCore/rendering/RenderReplaced.cpp	2022-06-17 06:23:42 UTC (rev 295629)
+++ trunk/Source/WebCore/rendering/RenderReplaced.cpp	2022-06-17 06:58:01 UTC (rev 295630)
@@ -215,7 +215,7 @@
         if (visibleToHitTesting()) {
             auto borderRect = LayoutRect(adjustedPaintOffset, size());
             auto borderRegion = approximateAsRegion(style().getRoundedBorderFor(borderRect));
-            paintInfo.eventRegionContext->unite(borderRegion, style());
+            paintInfo.eventRegionContext->unite(borderRegion, *this, style());
         }
         return;
     }

Modified: trunk/Source/WebCore/rendering/TextBoxPainter.cpp (295629 => 295630)


--- trunk/Source/WebCore/rendering/TextBoxPainter.cpp	2022-06-17 06:23:42 UTC (rev 295629)
+++ trunk/Source/WebCore/rendering/TextBoxPainter.cpp	2022-06-17 06:58:01 UTC (rev 295630)
@@ -101,7 +101,7 @@
 
     if (m_paintInfo.phase == PaintPhase::EventRegion) {
         if (m_renderer.parent()->visibleToHitTesting())
-            m_paintInfo.eventRegionContext->unite(enclosingIntRect(m_paintRect), m_style);
+            m_paintInfo.eventRegionContext->unite(enclosingIntRect(m_paintRect), const_cast<RenderText&>(m_renderer), m_style);
         return;
     }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to