event.clientX/clientY should be in layout viewport coordinates
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 13 May 2017 18:24:15 +0000 (18:24 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 13 May 2017 18:24:15 +0000 (18:24 +0000)
https://bugs.webkit.org/show_bug.cgi?id=172018

Reviewed by Zalan Bujtas.
Source/WebCore:

Fix clientX and clientY on mouse events to be relative to the layout viewport, to match
getBoundingClientRect(), getClientRects() and fixed-position objects.

Also minor cleanup of MouseRelatedEvent to use initializers.

Test: fast/visual-viewport/client-coordinates-relative-to-layout-viewport.html

* dom/MouseRelatedEvent.cpp:
(WebCore::MouseRelatedEvent::MouseRelatedEvent):
(WebCore::MouseRelatedEvent::init):
(WebCore::MouseRelatedEvent::initCoordinates):
(WebCore::contentsScrollOffset): Deleted.
* dom/MouseRelatedEvent.h:

LayoutTests:

* fast/events/clientXY-in-zoom-and-scroll.html:
* fast/visual-viewport/client-coordinates-relative-to-layout-viewport-expected.txt: Added.
* fast/visual-viewport/client-coordinates-relative-to-layout-viewport.html: Added.
* platform/ios/TestExpectations:
* platform/mac/fast/events/clientXY-in-zoom-and-scroll-expected.txt:

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

LayoutTests/ChangeLog
LayoutTests/fast/events/clientXY-in-zoom-and-scroll.html
LayoutTests/fast/visual-viewport/client-coordinates-relative-to-layout-viewport-expected.txt [new file with mode: 0644]
LayoutTests/fast/visual-viewport/client-coordinates-relative-to-layout-viewport.html [new file with mode: 0644]
LayoutTests/platform/ios/TestExpectations
LayoutTests/platform/mac/fast/events/clientXY-in-zoom-and-scroll-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/dom/MouseRelatedEvent.cpp
Source/WebCore/dom/MouseRelatedEvent.h

index cc8a621..a22c228 100644 (file)
@@ -1,5 +1,18 @@
 2017-05-12  Simon Fraser  <simon.fraser@apple.com>
 
+        event.clientX/clientY should be in layout viewport coordinates
+        https://bugs.webkit.org/show_bug.cgi?id=172018
+
+        Reviewed by Zalan Bujtas.
+        
+        * fast/events/clientXY-in-zoom-and-scroll.html:
+        * fast/visual-viewport/client-coordinates-relative-to-layout-viewport-expected.txt: Added.
+        * fast/visual-viewport/client-coordinates-relative-to-layout-viewport.html: Added.
+        * platform/ios/TestExpectations:
+        * platform/mac/fast/events/clientXY-in-zoom-and-scroll-expected.txt:
+
+2017-05-12  Simon Fraser  <simon.fraser@apple.com>
+
         The rects returned by Element/Range.getClientRects() should not be rounded
         https://bugs.webkit.org/show_bug.cgi?id=172057
 
index 29d20ad..877a5cd 100644 (file)
     {
         event = e;
         debug("\nZoomed and scrolled");
-        shouldBe("event.clientX", hasSubpixelSupport ? "83" : "84");
-        shouldBe("event.clientY", hasSubpixelSupport ? "83" : "84");
+        shouldBe("event.clientX", hasSubpixelSupport ? "73" : "74");
+        shouldBe("event.clientY", hasSubpixelSupport ? "73" : "74");
         shouldBe("event.pageX", "133");
         shouldBe("event.pageY", "133");
     }
diff --git a/LayoutTests/fast/visual-viewport/client-coordinates-relative-to-layout-viewport-expected.txt b/LayoutTests/fast/visual-viewport/client-coordinates-relative-to-layout-viewport-expected.txt
new file mode 100644 (file)
index 0000000..c1f52d3
--- /dev/null
@@ -0,0 +1,21 @@
+layer at (0,0) size 2008x3024
+  RenderView at (0,0) size 785x585
+layer at (0,0) size 785x3024
+  RenderBlock {HTML} at (0,0) size 785x3024
+    RenderBody {BODY} at (8,16) size 2000x3000
+      RenderBlock {P} at (0,0) size 2000x18
+        RenderText {#text} at (0,0) size 79x18
+          text run at (0,0) width 79: "Got click at "
+        RenderInline {SPAN} at (0,0) size 123x18
+          RenderText {#text} at (78,0) size 123x18
+            text run at (78,0) width 123: "clicked at 292, 240"
+layer at (278,226) size 28x28
+  RenderBlock (positioned) {DIV} at (278,226) size 28x28 [bgcolor=#FF0000]
+layer at (280,228) size 25x25
+  RenderBlock (positioned) {DIV} at (279,227) size 26x26 [bgcolor=#008000]
+layer at (281,229) size 22x22
+  RenderBlock (positioned) {DIV} at (281,229) size 22x22 [bgcolor=#FFA500]
+layer at (284,232) size 16x16
+  RenderBlock (positioned) {DIV} at (284,232) size 16x16 [bgcolor=#0000FF]
+caret: position 12 of child 0 {#text} of child 9 {P} of body
+scrolled to 120,123
diff --git a/LayoutTests/fast/visual-viewport/client-coordinates-relative-to-layout-viewport.html b/LayoutTests/fast/visual-viewport/client-coordinates-relative-to-layout-viewport.html
new file mode 100644 (file)
index 0000000..73ed323
--- /dev/null
@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        body {
+            width: 2000px;
+            height: 3000px;
+        }
+        .box {
+            height: 100px;
+            width: 100px;
+            background-color: blue;
+            pointer-events: none;
+        }
+        #client {
+            position: fixed;
+            background-color: red;
+            width: 28px;
+            height: 28px;
+        }
+        #clientrects {
+            position: absolute;
+            background-color: green;
+            width: 25px;
+            height: 25px;
+        }
+        #clientscroll {
+            position: absolute;
+            background-color: orange;
+            width: 22px;
+            height: 22px;
+        }
+        #page {
+            position: absolute;
+            background-color: blue;
+            width: 16px;
+            height: 16px;
+        }
+    </style>
+    <script src="../../resources/ui-helper.js"></script>
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        if (window.internals)
+            internals.settings.setVisualViewportEnabled(true);
+
+        function getUIScript()
+        {
+            return `(function() {
+                uiController.zoomToScale(2, function() {
+                    uiController.uiScriptComplete();
+                });
+            })();`;
+        }
+        
+        function doAfterZooming()
+        {
+            window.scrollTo(120, 123);
+            eventSender.mouseMoveTo(345, 234);
+            eventSender.mouseDown();
+            eventSender.mouseUp();
+        }
+        
+        function doTest()
+        {
+            document.addEventListener('click', clickHandler);
+
+            if (!window.testRunner)
+                return;
+
+            testRunner.runUIScript(getUIScript(), function(zoomScale) {
+                doAfterZooming();
+            });
+        }
+        
+        function clickHandler(event)
+        {
+            document.getElementById('click-location').textContent = 'clicked at ' + event.clientX + ', ' + event.clientY;
+            var clientBox = document.getElementById('client');
+            var clientRect = clientBox.getBoundingClientRect();
+            clientBox.style.left = (event.clientX - clientRect.width / 2) + 'px';
+            clientBox.style.top = (event.clientY - clientRect.height / 2) + 'px';
+
+            var clientRectsBox = document.getElementById('clientrects');
+            clientRect = clientRectsBox.getBoundingClientRect();
+            var pageViewport = document.documentElement.getClientRects()[0];
+            clientRectsBox.style.left = (event.clientX - clientRect.width / 2) - pageViewport.left + 'px';
+            clientRectsBox.style.top = (event.clientY - clientRect.height / 2) - pageViewport.top + 'px';
+
+            var clientScrollBox = document.getElementById('clientscroll');
+            clientRect = clientScrollBox.getBoundingClientRect();
+            var pageViewport = document.documentElement.getBoundingClientRect();
+            clientRect = clientScrollBox.getBoundingClientRect();
+            clientScrollBox.style.left = (event.clientX - clientRect.width / 2) - pageViewport.left + 'px';
+            clientScrollBox.style.top = (event.clientY - clientRect.height / 2) - pageViewport.top + 'px';
+
+            var pageBox = document.getElementById('page');
+            clientRect = pageBox.getBoundingClientRect();
+            pageBox.style.left = (event.clientX - clientRect.width / 2) + 'px';
+            pageBox.style.top = (event.clientY - clientRect.height / 2) + 'px';
+            
+            if (window.testRunner)
+                testRunner.notifyDone();
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <div id="client" class="box"></div>
+    <div id="clientrects" class="box"></div>
+    <div id="clientscroll" class="box"></div>
+    <div id="page" class="box"></div>
+    <p>Got click at <span id="click-location"></span></p>
+</body>
+</html>
index 15b55f9..22662ee 100644 (file)
@@ -2778,6 +2778,7 @@ fast/zooming/client-rect-in-fixed-zoomed.html [ Skip ]
 fast/visual-viewport/zoomed-scroll-to-anchor-in-position-fixed.html [ Skip ]
 fast/visual-viewport/zoomed-scroll-into-view-fixed.html [ Skip ]
 fast/scrolling/scroll-to-anchor-zoomed-header.html [ Skip ]
+fast/visual-viewport/client-coordinates-relative-to-layout-viewport.html [ Skip ]
 
 # This test relies on Arial being used to draw Arabic. However, on iOS,
 # we explicitly disallow this because this font is too slow.
index 586881e..534a3c3 100644 (file)
@@ -17,8 +17,8 @@ PASS event.pageX is 150
 PASS event.pageY is 150
 
 Zoomed and scrolled
-PASS event.clientX is 83
-PASS event.clientY is 83
+PASS event.clientX is 73
+PASS event.clientY is 73
 PASS event.pageX is 133
 PASS event.pageY is 133
 PASS successfullyParsed is true
index e4b3706..4519990 100644 (file)
@@ -1,3 +1,24 @@
+2017-05-12  Simon Fraser  <simon.fraser@apple.com>
+
+        event.clientX/clientY should be in layout viewport coordinates
+        https://bugs.webkit.org/show_bug.cgi?id=172018
+
+        Reviewed by Zalan Bujtas.
+
+        Fix clientX and clientY on mouse events to be relative to the layout viewport, to match
+        getBoundingClientRect(), getClientRects() and fixed-position objects.
+
+        Also minor cleanup of MouseRelatedEvent to use initializers.
+
+        Test: fast/visual-viewport/client-coordinates-relative-to-layout-viewport.html
+
+        * dom/MouseRelatedEvent.cpp:
+        (WebCore::MouseRelatedEvent::MouseRelatedEvent):
+        (WebCore::MouseRelatedEvent::init):
+        (WebCore::MouseRelatedEvent::initCoordinates):
+        (WebCore::contentsScrollOffset): Deleted.
+        * dom/MouseRelatedEvent.h:
+
 2017-05-12  Sam Weinig  <sam@webkit.org>
 
         [WebIDL] Remove need for custom binding for Worker constructor
index 829126b..7eb8453 100644 (file)
 
 namespace WebCore {
 
-MouseRelatedEvent::MouseRelatedEvent()
-    : m_isSimulated(false)
-    , m_hasCachedRelativePosition(false)
-{
-}
-
-static LayoutSize contentsScrollOffset(DOMWindow* DOMWindow)
-{
-    if (!DOMWindow)
-        return LayoutSize();
-    Frame* frame = DOMWindow->frame();
-    if (!frame)
-        return LayoutSize();
-    FrameView* frameView = frame->view();
-    if (!frameView)
-        return LayoutSize();
-#if !PLATFORM(IOS)
-    float scaleFactor = frame->pageZoomFactor() * frame->frameScaleFactor();
-    return LayoutSize(frameView->scrollX() / scaleFactor, frameView->scrollY() / scaleFactor);
-#else
-    return LayoutSize(frameView->actualScrollX(), frameView->actualScrollY());
-#endif
-}
-
 MouseRelatedEvent::MouseRelatedEvent(const AtomicString& eventType, bool canBubble, bool cancelable, double timestamp, DOMWindow* DOMWindow,
                                      int detail, const IntPoint& screenLocation, const IntPoint& windowLocation,
 #if ENABLE(POINTER_LOCK)
@@ -77,32 +53,22 @@ MouseRelatedEvent::MouseRelatedEvent(const AtomicString& eventType, const MouseR
 #if ENABLE(POINTER_LOCK)
     , m_movementDelta(IntPoint(0, 0))
 #endif
-    , m_isSimulated(false)
 {
     init(false, IntPoint(0, 0));
 }
 
 void MouseRelatedEvent::init(bool isSimulated, const IntPoint& windowLocation)
 {
-    LayoutPoint adjustedPageLocation;
-    LayoutPoint scrollPosition;
-
-    Frame* frame = view() ? view()->frame() : nullptr;
+    auto* frame = view() ? view()->frame() : nullptr;
     if (frame && !isSimulated) {
         if (FrameView* frameView = frame->view()) {
-            scrollPosition = frameView->contentsScrollPosition();
-            adjustedPageLocation = frameView->windowToContents(windowLocation);
-            float scaleFactor = 1 / (frame->pageZoomFactor() * frame->frameScaleFactor());
-            if (scaleFactor != 1.0f) {
-                adjustedPageLocation.scale(scaleFactor);
-                scrollPosition.scale(scaleFactor);
-            }
+            FloatPoint absolutePoint = frameView->windowToContents(windowLocation);
+            FloatPoint documentPoint = frameView->absoluteToDocumentPoint(absolutePoint);
+            m_pageLocation = flooredLayoutPoint(documentPoint);
+            m_clientLocation = flooredLayoutPoint(frameView->documentToClientPoint(documentPoint));
         }
     }
 
-    m_clientLocation = adjustedPageLocation - toLayoutSize(scrollPosition);
-    m_pageLocation = adjustedPageLocation;
-
     initCoordinates();
 }
 
@@ -121,8 +87,15 @@ void MouseRelatedEvent::initCoordinates(const LayoutPoint& clientLocation)
 {
     // Set up initial values for coordinates.
     // Correct values are computed lazily, see computeRelativePosition.
+    FloatSize documentToClientOffset;
+    auto* frame = view() ? view()->frame() : nullptr;
+    if (frame) {
+        if (FrameView* frameView = frame->view())
+            documentToClientOffset = frameView->documentToClientOffset();
+    }
+
     m_clientLocation = clientLocation;
-    m_pageLocation = clientLocation + contentsScrollOffset(view());
+    m_pageLocation = clientLocation - LayoutSize(documentToClientOffset);
 
     m_layerLocation = m_pageLocation;
     m_offsetLocation = m_pageLocation;
index 5f8dc03..e50f7cd 100644 (file)
@@ -65,7 +65,7 @@ public:
     void setAbsoluteLocation(const LayoutPoint& p) { m_absoluteLocation = p; }
 
 protected:
-    MouseRelatedEvent();
+    MouseRelatedEvent() = default;
     MouseRelatedEvent(const AtomicString& type, bool canBubble, bool cancelable, double timestamp, DOMWindow*,
         int detail, const IntPoint& screenLocation, const IntPoint& windowLocation,
 #if ENABLE(POINTER_LOCK)
@@ -95,8 +95,8 @@ private:
     LayoutPoint m_layerLocation;
     LayoutPoint m_offsetLocation;
     LayoutPoint m_absoluteLocation;
-    bool m_isSimulated;
-    bool m_hasCachedRelativePosition;
+    bool m_isSimulated { false };
+    bool m_hasCachedRelativePosition { false };
 };
 
 } // namespace WebCore