Event region computation should respect transforms
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 14 May 2019 18:28:11 +0000 (18:28 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 14 May 2019 18:28:11 +0000 (18:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=197836
<rdar://problem/50762971>

Reviewed by Darin Adler.

Source/WebCore:

* platform/graphics/transforms/AffineTransform.cpp:
(WebCore::AffineTransform::mapRegion const):

Add support for transforming regions. Non-rectlinear results use enclosing rects.

* platform/graphics/transforms/AffineTransform.h:
* rendering/EventRegion.cpp:
(WebCore::EventRegionContext::EventRegionContext):
(WebCore::EventRegionContext::pushTransform):
(WebCore::EventRegionContext::popTransform):
(WebCore::EventRegionContext::unite):
(WebCore::EventRegionContext::contains const):

Add a context object that holds the current transform.

* rendering/EventRegion.h:
(WebCore::EventRegion::makeContext):
* rendering/InlineTextBox.cpp:
(WebCore::InlineTextBox::paint):
* rendering/PaintInfo.h:

Replace the region object with the context.

* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::paintObject):
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::paintLayerByApplyingTransform):

Apply transforms to regions if needed.

(WebCore::RenderLayer::collectEventRegionForFragments):
* rendering/RenderLayer.h:
* rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::updateEventRegion):
* rendering/SimpleLineLayoutFunctions.cpp:
(WebCore::SimpleLineLayout::paintFlow):

LayoutTests:

* fast/scrolling/ios/event-region-scale-transform-shared-expected.txt:
* fast/scrolling/ios/event-region-translate-transform-shared-expected.txt:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@245293 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/scrolling/ios/event-region-scale-transform-shared-expected.txt
LayoutTests/fast/scrolling/ios/event-region-translate-transform-shared-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/transforms/AffineTransform.cpp
Source/WebCore/platform/graphics/transforms/AffineTransform.h
Source/WebCore/rendering/EventRegion.cpp
Source/WebCore/rendering/EventRegion.h
Source/WebCore/rendering/InlineTextBox.cpp
Source/WebCore/rendering/PaintInfo.h
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderLayer.cpp
Source/WebCore/rendering/RenderLayer.h
Source/WebCore/rendering/RenderLayerBacking.cpp
Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp

index 00a353f..a4d3b90 100644 (file)
@@ -1,3 +1,14 @@
+2019-05-14  Antti Koivisto  <antti@apple.com>
+
+        Event region computation should respect transforms
+        https://bugs.webkit.org/show_bug.cgi?id=197836
+        <rdar://problem/50762971>
+
+        Reviewed by Darin Adler.
+
+        * fast/scrolling/ios/event-region-scale-transform-shared-expected.txt:
+        * fast/scrolling/ios/event-region-translate-transform-shared-expected.txt:
+
 2019-05-14  Said Abou-Hallawa  <sabouhallawa@apple.com>
 
         Unreviewed: fix test failures after r245280.
index a4a7c29..7a3a29f 100644 (file)
@@ -19,8 +19,9 @@
           (bounds 201.00 201.00)
           (drawsContent 1)
           (event region
-            (rect (0,0) width=200 height=200)
-            (rect (200,200) width=100 height=100)
+            (rect (0,0) width=12 height=12)
+            (rect (51,51) width=100 height=100)
+            (rect (151,151) width=50 height=50)
           )
         )
       )
index 128e9ac..06f371b 100644 (file)
@@ -19,8 +19,9 @@
           (bounds 451.00 451.00)
           (drawsContent 1)
           (event region
-            (rect (0,0) width=200 height=200)
-            (rect (200,200) width=100 height=100)
+            (rect (0,0) width=12 height=12)
+            (rect (151,151) width=200 height=200)
+            (rect (351,351) width=100 height=100)
           )
         )
       )
index 53df7a7..7e2f5e6 100644 (file)
@@ -1,3 +1,48 @@
+2019-05-14  Antti Koivisto  <antti@apple.com>
+
+        Event region computation should respect transforms
+        https://bugs.webkit.org/show_bug.cgi?id=197836
+        <rdar://problem/50762971>
+
+        Reviewed by Darin Adler.
+
+        * platform/graphics/transforms/AffineTransform.cpp:
+        (WebCore::AffineTransform::mapRegion const):
+
+        Add support for transforming regions. Non-rectlinear results use enclosing rects.
+
+        * platform/graphics/transforms/AffineTransform.h:
+        * rendering/EventRegion.cpp:
+        (WebCore::EventRegionContext::EventRegionContext):
+        (WebCore::EventRegionContext::pushTransform):
+        (WebCore::EventRegionContext::popTransform):
+        (WebCore::EventRegionContext::unite):
+        (WebCore::EventRegionContext::contains const):
+
+        Add a context object that holds the current transform.
+
+        * rendering/EventRegion.h:
+        (WebCore::EventRegion::makeContext):
+        * rendering/InlineTextBox.cpp:
+        (WebCore::InlineTextBox::paint):
+        * rendering/PaintInfo.h:
+
+        Replace the region object with the context.
+
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::paintObject):
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::paintLayerByApplyingTransform):
+
+        Apply transforms to regions if needed.
+
+        (WebCore::RenderLayer::collectEventRegionForFragments):
+        * rendering/RenderLayer.h:
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::RenderLayerBacking::updateEventRegion):
+        * rendering/SimpleLineLayoutFunctions.cpp:
+        (WebCore::SimpleLineLayout::paintFlow):
+
 2019-05-14  Youenn Fablet  <youenn@apple.com>
 
         Video frame resizing should be using Trim
index 42c51f2..34398a3 100644 (file)
@@ -31,6 +31,7 @@
 #include "FloatQuad.h"
 #include "FloatRect.h"
 #include "IntRect.h"
+#include "Region.h"
 #include "TransformationMatrix.h"
 #include <wtf/MathExtras.h>
 #include <wtf/Optional.h>
@@ -334,6 +335,21 @@ FloatQuad AffineTransform::mapQuad(const FloatQuad& q) const
     return result;
 }
 
+Region AffineTransform::mapRegion(const Region& region) const
+{
+    if (isIdentityOrTranslation()) {
+        Region mappedRegion(region);
+        mappedRegion.translate(roundedIntSize(FloatSize(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]))));
+        return mappedRegion;
+    }
+
+    Region mappedRegion;
+    for (auto& rect : region.rects())
+        mappedRegion.unite(mapRect(rect));
+
+    return mappedRegion;
+}
+
 void AffineTransform::blend(const AffineTransform& from, double progress)
 {
     DecomposedType srA, srB;
index dc2c497..f4d64ad 100644 (file)
@@ -53,6 +53,7 @@ class FloatSize;
 class IntPoint;
 class IntSize;
 class IntRect;
+class Region;
 class TransformationMatrix;
 
 class AffineTransform {
@@ -89,6 +90,8 @@ public:
     WEBCORE_EXPORT FloatRect mapRect(const FloatRect&) const;
     WEBCORE_EXPORT FloatQuad mapQuad(const FloatQuad&) const;
 
+    WEBCORE_EXPORT Region mapRegion(const Region&) const;
+
     WEBCORE_EXPORT bool isIdentity() const;
 
     double a() const { return m_transform[0]; }
index 878a4e1..244ae5b 100644 (file)
 
 namespace WebCore {
 
+EventRegionContext::EventRegionContext(EventRegion& eventRegion)
+    : m_eventRegion(eventRegion)
+{
+}
+
+void EventRegionContext::pushTransform(const AffineTransform& transform)
+{
+    if (m_transformStack.isEmpty())
+        m_transformStack.append(transform);
+    else
+        m_transformStack.append(m_transformStack.last() * transform);
+}
+
+void EventRegionContext::popTransform()
+{
+    m_transformStack.removeLast();
+}
+
+void EventRegionContext::unite(const Region& region, const RenderStyle& style)
+{
+    if (m_transformStack.isEmpty())
+        m_eventRegion.unite(region, style);
+    else
+        m_eventRegion.unite(m_transformStack.last().mapRegion(region), style);
+}
+
+bool EventRegionContext::contains(const IntRect& rect) const
+{
+    if (m_transformStack.isEmpty())
+        return m_eventRegion.contains(rect);
+
+    return m_eventRegion.contains(m_transformStack.last().mapRect(rect));
+}
+
 EventRegion::EventRegion() = default;
 
 bool EventRegion::operator==(const EventRegion& other) const
index 2039328..c2bac4e 100644 (file)
@@ -25,6 +25,7 @@
 
 #pragma once
 
+#include "AffineTransform.h"
 #include "Region.h"
 #include "TouchAction.h"
 #include <wtf/OptionSet.h>
 
 namespace WebCore {
 
+class EventRegion;
 class RenderStyle;
 
+class EventRegionContext {
+public:
+    explicit EventRegionContext(EventRegion&);
+
+    void pushTransform(const AffineTransform&);
+    void popTransform();
+
+    void unite(const Region&, const RenderStyle&);
+    bool contains(const IntRect&) const;
+
+private:
+    EventRegion& m_eventRegion;
+    Vector<AffineTransform> m_transformStack;
+};
+
 class EventRegion {
 public:
     WEBCORE_EXPORT EventRegion();
 
+    EventRegionContext makeContext() { return EventRegionContext(*this); }
+
     bool isEmpty() const { return m_region.isEmpty(); }
 
     WEBCORE_EXPORT bool operator==(const EventRegion&) const;
index c734dbc..0f23329 100644 (file)
@@ -505,7 +505,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset,
 
     if (paintInfo.phase == PaintPhase::EventRegion) {
         if (visibleToHitTesting())
-            paintInfo.eventRegion->unite(enclosingIntRect(boxRect), renderer().style());
+            paintInfo.eventRegionContext->unite(enclosingIntRect(boxRect), renderer().style());
         return;
     }
 
index 02bf93c..f3afd55 100644 (file)
@@ -37,7 +37,7 @@
 
 namespace WebCore {
 
-class EventRegion;
+class EventRegionContext;
 class OverlapTestRequestClient;
 class RenderInline;
 class RenderLayer;
@@ -130,7 +130,8 @@ struct PaintInfo {
     const RenderLayerModelObject* paintContainer; // the layer object that originates the current painting
     bool requireSecurityOriginAccessForWidgets { false };
     const RenderLayer* m_enclosingSelfPaintingLayer { nullptr };
-    EventRegion* eventRegion { nullptr }; // For PaintPhase::EventRegion.
+    EventRegionContext* eventRegionContext { nullptr }; // For PaintPhase::EventRegion.
+
 private:
     GraphicsContext* m_context;
 };
index 4496296..9c9983e 100644 (file)
@@ -1246,11 +1246,11 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffs
 
         if (visibleToHitTesting()) {
             auto borderRegion = approximateAsRegion(style().getRoundedBorderFor(borderRect));
-            paintInfo.eventRegion->unite(borderRegion, style());
+            paintInfo.eventRegionContext->unite(borderRegion, style());
         }
 
         // No need to check descendants if we don't have overflow and the area is already covered.
-        bool needsTraverseDescendants = hasVisualOverflow() || !paintInfo.eventRegion->contains(enclosingIntRect(borderRect));
+        bool needsTraverseDescendants = hasVisualOverflow() || !paintInfo.eventRegionContext->contains(enclosingIntRect(borderRect));
 #if PLATFORM(IOS_FAMILY) && ENABLE(POINTER_EVENTS)
         needsTraverseDescendants = needsTraverseDescendants || document().touchActionElements();
 #endif
index 7a1dc38..7a9700e 100644 (file)
@@ -4600,8 +4600,12 @@ void RenderLayer::paintLayerByApplyingTransform(GraphicsContext& context, const
     // Translate the graphics context to the snapping position to avoid off-device-pixel positing.
     transform.translateRight(devicePixelSnappedOffsetForThisLayer.width(), devicePixelSnappedOffsetForThisLayer.height());
     // Apply the transform.
-    AffineTransform oldTransfrom = context.getCTM();
-    context.concatCTM(transform.toAffineTransform());
+    auto oldTransform = context.getCTM();
+    auto affineTransform = transform.toAffineTransform();
+    context.concatCTM(affineTransform);
+
+    if (paintingInfo.eventRegionContext)
+        paintingInfo.eventRegionContext->pushTransform(affineTransform);
 
     // Now do a paint with the root layer shifted to be us.
     LayoutSize adjustedSubpixelOffset = offsetForThisLayer - LayoutSize(devicePixelSnappedOffsetForThisLayer);
@@ -4610,7 +4614,11 @@ void RenderLayer::paintLayerByApplyingTransform(GraphicsContext& context, const
     transformedPaintingInfo.paintDirtyRect = LayoutRect(encloseRectToDevicePixels(transform.inverse().valueOr(AffineTransform()).mapRect(paintingInfo.paintDirtyRect), deviceScaleFactor));
     transformedPaintingInfo.subpixelOffset = adjustedSubpixelOffset;
     paintLayerContentsAndReflection(context, transformedPaintingInfo, paintFlags);
-    context.setCTM(oldTransfrom);
+
+    if (paintingInfo.eventRegionContext)
+        paintingInfo.eventRegionContext->popTransform();
+
+    context.setCTM(oldTransform);
 }
 
 void RenderLayer::paintList(LayerList layerIterator, GraphicsContext& context, const LayerPaintingInfo& paintingInfo, OptionSet<PaintLayerFlag> paintFlags)
@@ -4998,11 +5006,11 @@ void RenderLayer::paintOverflowControlsForFragments(const LayerFragments& layerF
 
 void RenderLayer::collectEventRegionForFragments(const LayerFragments& layerFragments, GraphicsContext& context, const LayerPaintingInfo& localPaintingInfo)
 {
-    ASSERT(localPaintingInfo.eventRegion);
+    ASSERT(localPaintingInfo.eventRegionContext);
 
     for (const auto& fragment : layerFragments) {
         PaintInfo paintInfo(context, fragment.foregroundRect.rect(), PaintPhase::EventRegion, { });
-        paintInfo.eventRegion = localPaintingInfo.eventRegion;
+        paintInfo.eventRegionContext = localPaintingInfo.eventRegionContext;
         renderer().paint(paintInfo, toLayoutPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subpixelOffset));
     }
 }
index e519f4f..aa96306 100644 (file)
@@ -63,7 +63,7 @@ namespace WebCore {
 class CSSFilter;
 class ClipRects;
 class ClipRectsCache;
-class EventRegion;
+class EventRegionContext;
 class HitTestRequest;
 class HitTestResult;
 class HitTestingTransformState;
@@ -941,7 +941,7 @@ private:
         OptionSet<PaintBehavior> paintBehavior;
         bool requireSecurityOriginAccessForWidgets;
         bool clipToDirtyRect { true };
-        EventRegion* eventRegion { nullptr };
+        EventRegionContext* eventRegionContext { nullptr };
     };
 
     // Compute, cache and return clip rects computed with the given layer as the root.
index 261b90f..389aa1e 100644 (file)
@@ -1484,7 +1484,8 @@ void RenderLayerBacking::updateEventRegion()
     RenderLayer::LayerPaintingInfo paintingInfo(&m_owningLayer, compositedBounds(), { }, LayoutSize());
 
     EventRegion eventRegion;
-    paintingInfo.eventRegion = &eventRegion;
+    auto eventRegionContext = eventRegion.makeContext();
+    paintingInfo.eventRegionContext = &eventRegionContext;
 
     auto paintFlags = RenderLayer::paintLayerPaintingCompositingAllPhasesFlags() | RenderLayer::PaintLayerCollectingEventRegion;
     m_owningLayer.paintLayerContents(nullContext, paintingInfo, paintFlags);
index 8b7082a..94f1ad2 100644 (file)
@@ -84,7 +84,7 @@ void paintFlow(const RenderBlockFlow& flow, const Layout& layout, PaintInfo& pai
         paintRect.moveBy(-paintOffset);
         for (auto run : layout.runResolver().rangeForRect(paintRect)) {
             FloatRect visualOverflowRect = computeOverflow(flow, run.rect());
-            paintInfo.eventRegion->unite(enclosingIntRect(visualOverflowRect), flow.style());
+            paintInfo.eventRegionContext->unite(enclosingIntRect(visualOverflowRect), flow.style());
         }
         return;
     }