Title: [294160] trunk/Source
Revision
294160
Author
timothy_hor...@apple.com
Date
2022-05-13 09:31:40 -0700 (Fri, 13 May 2022)

Log Message

Add UI-side layers for optionally indicating interaction regions
https://bugs.webkit.org/show_bug.cgi?id=240372
<rdar://problem/87170289>

Reviewed by Dean Jackson.

Source/WebCore:

* page/DebugPageOverlays.cpp:
(WebCore::pathsForRegion):
Move inline rect inflation into InteractionRegion so that all clients get it.

* page/Page.cpp:
(WebCore::Page::shouldBuildInteractionRegions const):
* page/Page.h:
* page/Frame.cpp:
(WebCore::Frame::invalidateContentEventRegionsIfNeeded):
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::paintObject):
* rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::maintainsEventRegion const):
(WebCore::RenderLayerBacking::updateEventRegion):
If the ENABLE() and setting are both enabled, update event regions
due to possible interaction region changes. We could make this more
conservative later, but chances are high that most layers include
interaction regions.

For now, compute interaction regions only for the root layer.
In a future patch, we will adopt the normal fake paint mechanism
and maintain them on the layer that owns them.

* page/InteractionRegion.cpp:
(WebCore::regionForElement):
Move inline rect inflation into InteractionRegion so that all clients get it.
Limit interaction rects to half of the viewport. Ignore regions that are larger.

* page/InteractionRegion.h:
(WebCore::operator==): Added.
(WebCore::InteractionRegion::encode const):
(WebCore::InteractionRegion::decode):
Remove the isInline bit, since we only used it for rect inflation.

* rendering/EventRegion.cpp:
(WebCore::EventRegion::operator== const):
(WebCore::EventRegion::translate):
(WebCore::EventRegion::uniteInteractionRegions):
(WebCore::EventRegion::computeInteractionRegions):
* rendering/EventRegion.h:
(WebCore::EventRegion::interactionRegions const):
(WebCore::EventRegion::encode const):
(WebCore::EventRegion::decode):
Store interaction regions on EventRegion.

Source/WebKit:

* Shared/RemoteLayerTree/RemoteLayerTreePropertyApplier.mm:
(WebKit::RemoteLayerTreePropertyApplier::applyPropertiesToLayer):
(WebKit::RemoteLayerTreePropertyApplier::applyHierarchyUpdates):
Allow RemoteLayerTreeInteractionRegionLayers to add and maintain layers for interaction regions.

* SourcesCocoa.txt:
* UIProcess/RemoteLayerTree/RemoteLayerTreeInteractionRegionLayers.h: Added.
* UIProcess/RemoteLayerTree/RemoteLayerTreeInteractionRegionLayers.mm: Added.
(configureLayerForInteractionRegion):
(WebKit::interactionRegionForLayer):
(WebKit::isInteractionRegionLayer):
(WebKit::setInteractionRegion):
Box WebCore::InteractionRegion in a Objective-C object and store it on the layer.
Use this as a key to indicate that a given layer is an interaction region.

(WebKit::appendInteractionRegionLayersForLayer):
Make sure that interaction region layers are always at the end of the layer's sublayers array.

(WebKit::updateLayersForInteractionRegions):
Add new layers for interaction regions.
Maintain the same layer for regions that cover the same area.
Add a green wash if the default `WKInteractionRegionDebugFill` is set.

* WebKit.xcodeproj/project.pbxproj:

Source/WTF:

* Scripts/Preferences/WebPreferencesInternal.yaml:
Add a preference to toggle interaction region layers.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WTF/ChangeLog (294159 => 294160)


--- trunk/Source/WTF/ChangeLog	2022-05-13 16:05:06 UTC (rev 294159)
+++ trunk/Source/WTF/ChangeLog	2022-05-13 16:31:40 UTC (rev 294160)
@@ -1,3 +1,14 @@
+2022-05-13  Tim Horton  <timothy_hor...@apple.com>
+
+        Add UI-side layers for optionally indicating interaction regions
+        https://bugs.webkit.org/show_bug.cgi?id=240372
+        <rdar://problem/87170289>
+
+        Reviewed by Dean Jackson.
+
+        * Scripts/Preferences/WebPreferencesInternal.yaml:
+        Add a preference to toggle interaction region layers.
+
 2022-05-13  Commit Queue  <commit-qu...@webkit.org>
 
         Unreviewed, reverting r294113.

Modified: trunk/Source/WTF/Scripts/Preferences/WebPreferencesInternal.yaml (294159 => 294160)


--- trunk/Source/WTF/Scripts/Preferences/WebPreferencesInternal.yaml	2022-05-13 16:05:06 UTC (rev 294159)
+++ trunk/Source/WTF/Scripts/Preferences/WebPreferencesInternal.yaml	2022-05-13 16:31:40 UTC (rev 294160)
@@ -496,6 +496,19 @@
     WebCore:
       default: false
 
+InteractionRegionsEnabled:
+  type: bool
+  humanReadableName: "Interaction Regions"
+  humanReadableDescription: "Generate and visualize interaction regions"
+  condition: ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+  defaultValue:
+    WebKit:
+      default: true
+    WebKitLegacy:
+      default: false
+    WebCore:
+      default: false
+
 # FIXME: This is not relevent for WebKitLegacy, so should be excluded from WebKitLegacy entirely.
 IsFirstPartyWebsiteDataRemovalLiveOnTestingEnabled:
   type: bool

Modified: trunk/Source/WebCore/ChangeLog (294159 => 294160)


--- trunk/Source/WebCore/ChangeLog	2022-05-13 16:05:06 UTC (rev 294159)
+++ trunk/Source/WebCore/ChangeLog	2022-05-13 16:31:40 UTC (rev 294160)
@@ -1,3 +1,56 @@
+2022-05-13  Tim Horton  <timothy_hor...@apple.com>
+
+        Add UI-side layers for optionally indicating interaction regions
+        https://bugs.webkit.org/show_bug.cgi?id=240372
+        <rdar://problem/87170289>
+
+        Reviewed by Dean Jackson.
+
+        * page/DebugPageOverlays.cpp:
+        (WebCore::pathsForRegion):
+        Move inline rect inflation into InteractionRegion so that all clients get it.
+
+        * page/Page.cpp:
+        (WebCore::Page::shouldBuildInteractionRegions const):
+        * page/Page.h:
+        * page/Frame.cpp:
+        (WebCore::Frame::invalidateContentEventRegionsIfNeeded):
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::paintObject):
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::RenderLayerBacking::maintainsEventRegion const):
+        (WebCore::RenderLayerBacking::updateEventRegion):
+        If the ENABLE() and setting are both enabled, update event regions
+        due to possible interaction region changes. We could make this more
+        conservative later, but chances are high that most layers include
+        interaction regions.
+
+        For now, compute interaction regions only for the root layer.
+        In a future patch, we will adopt the normal fake paint mechanism
+        and maintain them on the layer that owns them.
+
+        * page/InteractionRegion.cpp:
+        (WebCore::regionForElement):
+        Move inline rect inflation into InteractionRegion so that all clients get it.
+        Limit interaction rects to half of the viewport. Ignore regions that are larger.
+
+        * page/InteractionRegion.h:
+        (WebCore::operator==): Added.
+        (WebCore::InteractionRegion::encode const):
+        (WebCore::InteractionRegion::decode):
+        Remove the isInline bit, since we only used it for rect inflation.
+        
+        * rendering/EventRegion.cpp:
+        (WebCore::EventRegion::operator== const):
+        (WebCore::EventRegion::translate):
+        (WebCore::EventRegion::uniteInteractionRegions):
+        (WebCore::EventRegion::computeInteractionRegions):
+        * rendering/EventRegion.h:
+        (WebCore::EventRegion::interactionRegions const):
+        (WebCore::EventRegion::encode const):
+        (WebCore::EventRegion::decode):
+        Store interaction regions on EventRegion.
+
 2022-05-13  Commit Queue  <commit-qu...@webkit.org>
 
         Unreviewed, reverting r294113.

Modified: trunk/Source/WebCore/page/DebugPageOverlays.cpp (294159 => 294160)


--- trunk/Source/WebCore/page/DebugPageOverlays.cpp	2022-05-13 16:05:06 UTC (rev 294159)
+++ trunk/Source/WebCore/page/DebugPageOverlays.cpp	2022-05-13 16:31:40 UTC (rev 294160)
@@ -293,15 +293,11 @@
 
 static Vector<Path> pathsForRegion(const InteractionRegion& region)
 {
-    static constexpr float padding = 3;
     static constexpr float radius = 4;
 
     Vector<FloatRect> rects;
-    for (auto rect : region.rectsInContentCoordinates) {
-        if (region.isInline)
-            rect.inflate(padding);
+    for (auto rect : region.rectsInContentCoordinates)
         rects.append(rect);
-    }
     return PathUtilities::pathsWithShrinkWrappedRects(rects, std::max(region.borderRadius, radius));
 }
 

Modified: trunk/Source/WebCore/page/Frame.cpp (294159 => 294160)


--- trunk/Source/WebCore/page/Frame.cpp	2022-05-13 16:05:06 UTC (rev 294159)
+++ trunk/Source/WebCore/page/Frame.cpp	2022-05-13 16:31:40 UTC (rev 294160)
@@ -336,6 +336,7 @@
     bool needsUpdateForWheelEventHandlers = false;
     bool needsUpdateForTouchActionElements = false;
     bool needsUpdateForEditableElements = false;
+    bool needsUpdateForInteractionRegions = false;
 #if ENABLE(WHEEL_EVENT_REGIONS)
     needsUpdateForWheelEventHandlers = m_doc->hasWheelEventHandlers() || reason == InvalidateContentEventRegionsReason::EventHandlerChange;
 #else
@@ -349,7 +350,10 @@
     // Document::mayHaveEditableElements never changes from true to false currently.
     needsUpdateForEditableElements = m_doc->mayHaveEditableElements() && m_page->shouldBuildEditableRegion();
 #endif
-    if (!needsUpdateForTouchActionElements && !needsUpdateForEditableElements && !needsUpdateForWheelEventHandlers)
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+    needsUpdateForInteractionRegions = m_page->shouldBuildInteractionRegions();
+#endif
+    if (!needsUpdateForTouchActionElements && !needsUpdateForEditableElements && !needsUpdateForWheelEventHandlers && !needsUpdateForInteractionRegions)
         return;
 
     if (!m_doc->renderView()->compositor().viewNeedsToInvalidateEventRegionOfEnclosingCompositingLayerForRepaint())

Modified: trunk/Source/WebCore/page/InteractionRegion.cpp (294159 => 294160)


--- trunk/Source/WebCore/page/InteractionRegion.cpp	2022-05-13 16:05:06 UTC (rev 294159)
+++ trunk/Source/WebCore/page/InteractionRegion.cpp	2022-05-13 16:31:40 UTC (rev 294160)
@@ -73,10 +73,8 @@
     if (!renderer)
         return std::nullopt;
 
-    Vector<FloatRect> rectsInContentsCoordinates;
-    
+    Vector<FloatRect> rectsInContentCoordinates;
     InteractionRegion region;
-
     auto linkRange = makeRangeSelectingNode(element);
     
     if (linkRange)
@@ -83,29 +81,41 @@
         region.hasLightBackground = estimatedBackgroundColorForRange(*linkRange, *element.document().frame()).luminance() > 0.5;
     
     if (linkRange && renderer->isInline() && !renderer->isReplacedOrInlineBlock()) {
-        region.isInline = true;
-
+        static constexpr float inlinePadding = 3;
         OptionSet<RenderObject::BoundingRectBehavior> behavior { RenderObject::BoundingRectBehavior::RespectClipping };
-        rectsInContentsCoordinates = RenderObject::absoluteTextRects(*linkRange, behavior).map([&](auto rect) -> FloatRect {
+        rectsInContentCoordinates = RenderObject::absoluteTextRects(*linkRange, behavior).map([&](auto rect) -> FloatRect {
+            rect.inflate(inlinePadding);
             return rect;
         });
 
-        if (rectsInContentsCoordinates.isEmpty()) {
+        if (rectsInContentCoordinates.isEmpty()) {
             auto boundingRectForRange = absoluteBoundingRectForRange(*linkRange);
-            if (!boundingRectForRange.isEmpty())
-                rectsInContentsCoordinates = { boundingRectForRange };
+            if (!boundingRectForRange.isEmpty()) {
+                boundingRectForRange.inflate(inlinePadding);
+                rectsInContentCoordinates = { boundingRectForRange };
+            }
         }
     }
 
-    if (rectsInContentsCoordinates.isEmpty())
-        rectsInContentsCoordinates = { renderer->absoluteBoundingBoxRect() };
+    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 (rectsInContentCoordinates.isEmpty())
+        return std::nullopt;
+
     if (is<RenderBox>(*renderer)) {
         RoundedRect::Radii borderRadii = downcast<RenderBox>(*renderer).borderRadii();
         region.borderRadius = borderRadii.minimumRadius();
     }
 
-    region.rectsInContentCoordinates = rectsInContentsCoordinates.map([&](auto rect) {
+    region.rectsInContentCoordinates = rectsInContentCoordinates.map([&](auto rect) {
         auto contentsRect = rect;
 
         if (&frameView != &mainFrameView)

Modified: trunk/Source/WebCore/page/InteractionRegion.h (294159 => 294160)


--- trunk/Source/WebCore/page/InteractionRegion.h	2022-05-13 16:05:06 UTC (rev 294159)
+++ trunk/Source/WebCore/page/InteractionRegion.h	2022-05-13 16:31:40 UTC (rev 294160)
@@ -38,7 +38,6 @@
 
 struct InteractionRegion {
     Vector<FloatRect> rectsInContentCoordinates;
-    bool isInline { false };
     bool hasLightBackground { false };
     float borderRadius { 0 };
     
@@ -48,6 +47,13 @@
     template<class Decoder> static std::optional<InteractionRegion> decode(Decoder&);
 };
 
+inline bool operator==(const InteractionRegion& a, const InteractionRegion& b)
+{
+    return a.rectsInContentCoordinates == b.rectsInContentCoordinates
+        && a.hasLightBackground == b.hasLightBackground
+        && a.borderRadius == b.borderRadius;
+}
+
 WEBCORE_EXPORT Vector<InteractionRegion> interactionRegions(Page&, FloatRect rectInContentCoordinates);
 
 template<class Encoder>
@@ -54,7 +60,6 @@
 void InteractionRegion::encode(Encoder& encoder) const
 {
     encoder << rectsInContentCoordinates;
-    encoder << isInline;
     encoder << hasLightBackground;
     encoder << borderRadius;
 }
@@ -67,11 +72,6 @@
     if (!rectsInContentCoordinates)
         return std::nullopt;
     
-    std::optional<bool> isInline;
-    decoder >> isInline;
-    if (!isInline)
-        return std::nullopt;
-    
     std::optional<bool> hasLightBackground;
     decoder >> hasLightBackground;
     if (!hasLightBackground)
@@ -84,7 +84,6 @@
 
     return { {
         WTFMove(*rectsInContentCoordinates),
-        WTFMove(*isInline),
         WTFMove(*hasLightBackground),
         WTFMove(*borderRadius)
     } };

Modified: trunk/Source/WebCore/page/Page.cpp (294159 => 294160)


--- trunk/Source/WebCore/page/Page.cpp	2022-05-13 16:05:06 UTC (rev 294159)
+++ trunk/Source/WebCore/page/Page.cpp	2022-05-13 16:31:40 UTC (rev 294160)
@@ -1092,6 +1092,13 @@
     return WTF::map(rootEditableElements, [](const auto& element) { return element.copyRef(); });
 }
 
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+bool Page::shouldBuildInteractionRegions() const
+{
+    return m_settings->interactionRegionsEnabled();
+}
+#endif
+
 const VisibleSelection& Page::selection() const
 {
     return CheckedRef(focusController())->focusedOrMainFrame().selection().selection();

Modified: trunk/Source/WebCore/page/Page.h (294159 => 294160)


--- trunk/Source/WebCore/page/Page.h	2022-05-13 16:05:06 UTC (rev 294159)
+++ trunk/Source/WebCore/page/Page.h	2022-05-13 16:31:40 UTC (rev 294160)
@@ -900,6 +900,10 @@
 
     WEBCORE_EXPORT Vector<Ref<Element>> editableElementsInRect(const FloatRect&) const;
 
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+    bool shouldBuildInteractionRegions() const;
+#endif
+
 #if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY)
     DeviceOrientationUpdateProvider* deviceOrientationUpdateProvider() const { return m_deviceOrientationUpdateProvider.get(); }
 #endif

Modified: trunk/Source/WebCore/rendering/EventRegion.cpp (294159 => 294160)


--- trunk/Source/WebCore/rendering/EventRegion.cpp	2022-05-13 16:05:06 UTC (rev 294159)
+++ trunk/Source/WebCore/rendering/EventRegion.cpp	2022-05-13 16:31:40 UTC (rev 294160)
@@ -116,6 +116,12 @@
     if (m_editableRegion != other.m_editableRegion)
         return false;
 #endif
+
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+    if (m_interactionRegions != other.m_interactionRegions)
+        return false;
+#endif
+
     return m_region == other.m_region;
 }
 
@@ -163,6 +169,13 @@
     if (m_editableRegion)
         m_editableRegion->translate(offset);
 #endif
+
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+    for (auto& region : m_interactionRegions) {
+        for (auto& rect : region.rectsInContentCoordinates)
+            rect.move(offset);
+    }
+#endif
 }
 
 static inline unsigned toIndex(TouchAction touchAction)
@@ -303,6 +316,21 @@
 
 #endif
 
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+
+void EventRegion::uniteInteractionRegions(const Vector<InteractionRegion>& interactionRegions)
+{
+    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
 {
     ts << m_region;

Modified: trunk/Source/WebCore/rendering/EventRegion.h (294159 => 294160)


--- trunk/Source/WebCore/rendering/EventRegion.h	2022-05-13 16:05:06 UTC (rev 294159)
+++ trunk/Source/WebCore/rendering/EventRegion.h	2022-05-13 16:31:40 UTC (rev 294160)
@@ -26,6 +26,8 @@
 #pragma once
 
 #include "AffineTransform.h"
+#include "InteractionRegion.h"
+#include "Node.h"
 #include "Region.h"
 #include "RenderStyleConstants.h"
 #include "TouchAction.h"
@@ -131,6 +133,12 @@
 
     void dump(TextStream&) const;
 
+#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:
 #if ENABLE(TOUCH_ACTION_REGIONS)
     void uniteTouchActions(const Region&, OptionSet<TouchAction>);
@@ -148,6 +156,9 @@
 #if ENABLE(EDITABLE_REGION)
     std::optional<Region> m_editableRegion;
 #endif
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+    Vector<InteractionRegion> m_interactionRegions;
+#endif
 };
 
 WEBCORE_EXPORT TextStream& operator<<(TextStream&, const EventRegion&);
@@ -166,6 +177,9 @@
 #if ENABLE(EDITABLE_REGION)
     encoder << m_editableRegion;
 #endif
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+    encoder << m_interactionRegions;
+#endif
 }
 
 template<class Decoder>
@@ -212,6 +226,14 @@
     eventRegion.m_editableRegion = WTFMove(*editableRegion);
 #endif
 
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+    std::optional<Vector<InteractionRegion>> interactionRegions;
+    decoder >> interactionRegions;
+    if (!interactionRegions)
+        return std::nullopt;
+    eventRegion.m_interactionRegions = WTFMove(*interactionRegions);
+#endif
+
     return eventRegion;
 }
 

Modified: trunk/Source/WebCore/rendering/RenderBlock.cpp (294159 => 294160)


--- trunk/Source/WebCore/rendering/RenderBlock.cpp	2022-05-13 16:05:06 UTC (rev 294159)
+++ trunk/Source/WebCore/rendering/RenderBlock.cpp	2022-05-13 16:31:40 UTC (rev 294160)
@@ -1313,6 +1313,11 @@
             LOG_WITH_STREAM(EventRegions, stream << "  needs editable event region: " << (document().mayHaveEditableElements() && page().shouldBuildEditableRegion()));
         }
 #endif
+
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+        needsTraverseDescendants |= page().shouldBuildInteractionRegions();
+#endif
+
         if (!needsTraverseDescendants)
             return;
     }

Modified: trunk/Source/WebCore/rendering/RenderLayerBacking.cpp (294159 => 294160)


--- trunk/Source/WebCore/rendering/RenderLayerBacking.cpp	2022-05-13 16:05:06 UTC (rev 294159)
+++ trunk/Source/WebCore/rendering/RenderLayerBacking.cpp	2022-05-13 16:31:40 UTC (rev 294160)
@@ -1789,6 +1789,11 @@
     if (renderer().document().hasWheelEventHandlers())
         return true;
 #endif
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+    if (renderer().page().shouldBuildInteractionRegions())
+        return true;
+#endif
+
     if (m_owningLayer.isRenderViewLayer())
         return false;
 
@@ -1837,20 +1842,27 @@
 #endif
         auto eventRegionContext = eventRegion.makeContext();
         auto layerOffset = graphicsLayer.scrollOffset() - roundedIntSize(graphicsLayer.offsetFromRenderer());
+        auto layerBounds = enclosingIntRect(FloatRect(-layerOffset, graphicsLayer.size()));
 
         if (visibleToHitTesting) {
             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(enclosingIntRect(FloatRect(-layerOffset, graphicsLayer.size())), renderer().style());
+                eventRegionContext.unite(layerBounds, renderer().style());
             }
         }
 
         if (m_owningLayer.isRenderViewLayer() && (&graphicsLayer == m_graphicsLayer || &graphicsLayer == m_foregroundLayer)) {
             // Event handlers on the root cover the entire layer.
-            eventRegionContext.unite(enclosingIntRect(FloatRect(-layerOffset, graphicsLayer.size())), renderer().style());
+            eventRegionContext.unite(layerBounds, 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);
 

Modified: trunk/Source/WebKit/ChangeLog (294159 => 294160)


--- trunk/Source/WebKit/ChangeLog	2022-05-13 16:05:06 UTC (rev 294159)
+++ trunk/Source/WebKit/ChangeLog	2022-05-13 16:31:40 UTC (rev 294160)
@@ -1,3 +1,36 @@
+2022-05-13  Tim Horton  <timothy_hor...@apple.com>
+
+        Add UI-side layers for optionally indicating interaction regions
+        https://bugs.webkit.org/show_bug.cgi?id=240372
+        <rdar://problem/87170289>
+
+        Reviewed by Dean Jackson.
+
+        * Shared/RemoteLayerTree/RemoteLayerTreePropertyApplier.mm:
+        (WebKit::RemoteLayerTreePropertyApplier::applyPropertiesToLayer):
+        (WebKit::RemoteLayerTreePropertyApplier::applyHierarchyUpdates):
+        Allow RemoteLayerTreeInteractionRegionLayers to add and maintain layers for interaction regions.
+
+        * SourcesCocoa.txt:
+        * UIProcess/RemoteLayerTree/RemoteLayerTreeInteractionRegionLayers.h: Added.
+        * UIProcess/RemoteLayerTree/RemoteLayerTreeInteractionRegionLayers.mm: Added.
+        (configureLayerForInteractionRegion):
+        (WebKit::interactionRegionForLayer):
+        (WebKit::isInteractionRegionLayer):
+        (WebKit::setInteractionRegion):
+        Box WebCore::InteractionRegion in a Objective-C object and store it on the layer.
+        Use this as a key to indicate that a given layer is an interaction region.
+
+        (WebKit::appendInteractionRegionLayersForLayer):
+        Make sure that interaction region layers are always at the end of the layer's sublayers array.
+
+        (WebKit::updateLayersForInteractionRegions):
+        Add new layers for interaction regions.
+        Maintain the same layer for regions that cover the same area.
+        Add a green wash if the default `WKInteractionRegionDebugFill` is set.
+
+        * WebKit.xcodeproj/project.pbxproj:
+
 2022-05-13  Simon Fraser  <simon.fra...@apple.com>
 
         Simplify the usage of DrawGlyphsRecorder

Modified: trunk/Source/WebKit/Shared/RemoteLayerTree/RemoteLayerTreePropertyApplier.mm (294159 => 294160)


--- trunk/Source/WebKit/Shared/RemoteLayerTree/RemoteLayerTreePropertyApplier.mm	2022-05-13 16:05:06 UTC (rev 294159)
+++ trunk/Source/WebKit/Shared/RemoteLayerTree/RemoteLayerTreePropertyApplier.mm	2022-05-13 16:31:40 UTC (rev 294160)
@@ -29,6 +29,7 @@
 #import "PlatformCAAnimationRemote.h"
 #import "PlatformCALayerRemote.h"
 #import "RemoteLayerTreeHost.h"
+#import "RemoteLayerTreeInteractionRegionLayers.h"
 #import <QuartzCore/QuartzCore.h>
 #import <WebCore/PlatformCAFilters.h>
 #import <WebCore/ScrollbarThemeMac.h>
@@ -291,6 +292,11 @@
     }
 #endif
 #endif
+
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+    if (properties.changedProperties & RemoteLayerTreeTransaction::EventRegionChanged)
+        updateLayersForInteractionRegions(layer, properties);
+#endif // ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
 }
 
 void RemoteLayerTreePropertyApplier::applyProperties(RemoteLayerTreeNode& node, RemoteLayerTreeHost* layerTreeHost, const RemoteLayerTreeTransaction::LayerProperties& properties, const RelatedLayerMap& relatedLayers, RemoteLayerBackingStore::LayerContentsType layerContentsType)
@@ -351,7 +357,7 @@
     }
 #endif
 
-    node.layer().sublayers = createNSArray(properties.children, [&] (auto& child) -> CALayer * {
+    auto sublayers = createNSArray(properties.children, [&] (auto& child) -> CALayer * {
         auto* childNode = relatedLayers.get(child);
         ASSERT(childNode);
         if (!childNode)
@@ -360,8 +366,14 @@
         ASSERT(!childNode->uiView());
 #endif
         return childNode->layer();
-    }).get();
+    });
 
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+    appendInteractionRegionLayersForLayer(sublayers.get(), node.layer());
+#endif
+
+    node.layer().sublayers = sublayers.get();
+
     END_BLOCK_OBJC_EXCEPTIONS
 }
 

Modified: trunk/Source/WebKit/SourcesCocoa.txt (294159 => 294160)


--- trunk/Source/WebKit/SourcesCocoa.txt	2022-05-13 16:05:06 UTC (rev 294159)
+++ trunk/Source/WebKit/SourcesCocoa.txt	2022-05-13 16:31:40 UTC (rev 294160)
@@ -579,6 +579,7 @@
 
 UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.mm
 UIProcess/RemoteLayerTree/RemoteLayerTreeHost.mm
+UIProcess/RemoteLayerTree/RemoteLayerTreeInteractionRegionLayers.mm
 UIProcess/RemoteLayerTree/RemoteLayerTreeNode.mm
 UIProcess/RemoteLayerTree/RemoteLayerTreeScrollingPerformanceData.mm
 UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp

Added: trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeInteractionRegionLayers.h (0 => 294160)


--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeInteractionRegionLayers.h	                        (rev 0)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeInteractionRegionLayers.h	2022-05-13 16:31:40 UTC (rev 294160)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+
+#include "RemoteLayerTreeNode.h"
+#include "RemoteLayerTreeTransaction.h"
+#include <wtf/HashMap.h>
+
+OBJC_CLASS NSMutableArray;
+
+namespace WebKit {
+
+void updateLayersForInteractionRegions(CALayer *, const RemoteLayerTreeTransaction::LayerProperties&);
+void appendInteractionRegionLayersForLayer(NSMutableArray *, CALayer *);
+
+} // namespace WebKit
+
+#endif

Added: trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeInteractionRegionLayers.mm (0 => 294160)


--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeInteractionRegionLayers.mm	                        (rev 0)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeInteractionRegionLayers.mm	2022-05-13 16:31:40 UTC (rev 294160)
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "RemoteLayerTreeInteractionRegionLayers.h"
+
+#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
+
+#import "PlatformCALayerRemote.h"
+#import "RemoteLayerTreeHost.h"
+#import <QuartzCore/QuartzCore.h>
+#import <WebCore/IntRectHash.h>
+#import <pal/spi/cocoa/QuartzCoreSPI.h>
+
+#if USE(APPLE_INTERNAL_SDK)
+#import <WebKitAdditions/RemoteLayerTreePropertyApplierInteractionRegionAdditions.mm>
+#else
+static void configureLayerForInteractionRegion(CALayer *, NSString *) { }
+#endif
+
+@interface WKInteractionRegion : NSObject
+@property (nonatomic, assign) WebCore::InteractionRegion interactionRegion;
+@end
+
+@implementation WKInteractionRegion
+@end
+
+namespace WebKit {
+using namespace WebCore;
+
+NSString *interactionRegionKey = @"WKInteractionRegion";
+
+static std::optional<WebCore::InteractionRegion> interactionRegionForLayer(CALayer *layer)
+{
+    id value = [layer valueForKey:interactionRegionKey];
+    if (![value isKindOfClass:[WKInteractionRegion class]])
+        return std::nullopt;
+    WKInteractionRegion *region = (WKInteractionRegion *)value;
+    return region.interactionRegion;
+}
+
+static bool isInteractionRegionLayer(CALayer *layer)
+{
+    return !!interactionRegionForLayer(layer);
+}
+
+static void setInteractionRegion(CALayer *layer, const WebCore::InteractionRegion& interactionRegion)
+{
+    WKInteractionRegion *region = [[[WKInteractionRegion alloc] init] autorelease];
+    region.interactionRegion = interactionRegion;
+    [layer setValue:region forKey:interactionRegionKey];
+}
+
+void appendInteractionRegionLayersForLayer(NSMutableArray *sublayers, CALayer *layer)
+{
+    for (CALayer *sublayer in layer.sublayers) {
+        if (isInteractionRegionLayer(sublayer))
+            [sublayers addObject:sublayer];
+    }
+}
+
+void updateLayersForInteractionRegions(CALayer *layer, const RemoteLayerTreeTransaction::LayerProperties& properties)
+{
+    ASSERT(properties.changedProperties & RemoteLayerTreeTransaction::EventRegionChanged);
+
+    HashMap<IntRect, CALayer *> interactionRegionLayers;
+    for (CALayer *sublayer in layer.sublayers) {
+        if (isInteractionRegionLayer(sublayer))
+            interactionRegionLayers.set(enclosingIntRect(sublayer.frame), sublayer);
+    }
+
+    bool applyBackgroundColorForDebugging = [[NSUserDefaults standardUserDefaults] boolForKey:@"WKInteractionRegionDebugFill"];
+
+    for (const WebCore::InteractionRegion& region : properties.eventRegion.interactionRegions()) {
+        for (FloatRect rect : region.rectsInContentCoordinates) {
+            auto layerIterator = interactionRegionLayers.find(enclosingIntRect(rect));
+
+            RetainPtr<CALayer> interactionRegionLayer;
+            if (layerIterator != interactionRegionLayers.end()) {
+                interactionRegionLayer = layerIterator->value;
+                interactionRegionLayers.remove(layerIterator);
+            } else {
+                interactionRegionLayer = adoptNS([[CALayer alloc] init]);
+                [interactionRegionLayer setFrame:rect];
+                [interactionRegionLayer setHitTestsAsOpaque:YES];
+
+                if (applyBackgroundColorForDebugging)
+                    [interactionRegionLayer setBackgroundColor:cachedCGColor({ WebCore::SRGBA<float>(0, 1, 0, .3) }).get()];
+
+                setInteractionRegion(interactionRegionLayer.get(), region);
+                configureLayerForInteractionRegion(interactionRegionLayer.get(), @"WKInteractionRegion");
+
+                [layer addSublayer:interactionRegionLayer.get()];
+            }
+
+            static constexpr float minimumBorderRadius = 4;
+            [interactionRegionLayer setCornerRadius:std::max(region.borderRadius, minimumBorderRadius)];
+        }
+    }
+
+    for (CALayer *sublayer : interactionRegionLayers.values())
+        [sublayer removeFromSuperlayer];
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)

Modified: trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj (294159 => 294160)


--- trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2022-05-13 16:05:06 UTC (rev 294159)
+++ trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2022-05-13 16:31:40 UTC (rev 294160)
@@ -3890,6 +3890,8 @@
 		2D3A65E51A7C3AA700CAC637 /* WKFrameInfoRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKFrameInfoRef.h; sourceTree = "<group>"; };
 		2D3EF4401917646300034184 /* WebMemoryPressureHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebMemoryPressureHandler.cpp; sourceTree = "<group>"; };
 		2D3EF4411917646300034184 /* WebMemoryPressureHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebMemoryPressureHandler.h; sourceTree = "<group>"; };
+		2D40C2BB282E286E0052102D /* RemoteLayerTreeInteractionRegionLayers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RemoteLayerTreeInteractionRegionLayers.h; sourceTree = "<group>"; };
+		2D40C2BC282E286E0052102D /* RemoteLayerTreeInteractionRegionLayers.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = RemoteLayerTreeInteractionRegionLayers.mm; sourceTree = "<group>"; };
 		2D429BFA1721E2BA00EC681F /* PDFPluginPasswordField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PDFPluginPasswordField.h; path = PDF/PDFPluginPasswordField.h; sourceTree = "<group>"; };
 		2D429BFB1721E2BA00EC681F /* PDFPluginPasswordField.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PDFPluginPasswordField.mm; path = PDF/PDFPluginPasswordField.mm; sourceTree = "<group>"; };
 		2D440B8225EF235E00A98D87 /* PDFKitSoftLink.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PDFKitSoftLink.mm; sourceTree = "<group>"; };
@@ -8794,6 +8796,8 @@
 				1AB16ADF1648656D00290D62 /* RemoteLayerTreeDrawingAreaProxy.mm */,
 				1AA3D75A1651B44F008713D0 /* RemoteLayerTreeHost.h */,
 				1AA3D7591651B44F008713D0 /* RemoteLayerTreeHost.mm */,
+				2D40C2BB282E286E0052102D /* RemoteLayerTreeInteractionRegionLayers.h */,
+				2D40C2BC282E286E0052102D /* RemoteLayerTreeInteractionRegionLayers.mm */,
 				E4E57F6A21A83B1100345F3C /* RemoteLayerTreeNode.h */,
 				E4E57F6821A83B0300345F3C /* RemoteLayerTreeNode.mm */,
 				0F707C791A1FEEA300DA7A45 /* RemoteLayerTreeScrollingPerformanceData.h */,
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to