Diff
Modified: trunk/LayoutTests/ChangeLog (240633 => 240634)
--- trunk/LayoutTests/ChangeLog 2019-01-29 02:59:08 UTC (rev 240633)
+++ trunk/LayoutTests/ChangeLog 2019-01-29 03:15:02 UTC (rev 240634)
@@ -1,3 +1,24 @@
+2019-01-28 Antoine Quint <[email protected]>
+
+ Implement capture for Pointer Events on iOS
+ https://bugs.webkit.org/show_bug.cgi?id=193917
+ <rdar://problem/47605689>
+
+ Reviewed by Dean Jackson.
+
+ New tests for implicit pointer capture and the Element APIs related to pointer capture.
+
+ * pointerevents/ios/pointer-events-implicit-capture-expected.txt: Added.
+ * pointerevents/ios/pointer-events-implicit-capture-has-pointer-capture-in-pointer-down-expected.txt: Added.
+ * pointerevents/ios/pointer-events-implicit-capture-has-pointer-capture-in-pointer-down.html: Added.
+ * pointerevents/ios/pointer-events-implicit-capture-release-exception-expected.txt: Added.
+ * pointerevents/ios/pointer-events-implicit-capture-release-exception.html: Added.
+ * pointerevents/ios/pointer-events-implicit-capture-release-expected.txt: Added.
+ * pointerevents/ios/pointer-events-implicit-capture-release.html: Added.
+ * pointerevents/ios/pointer-events-implicit-capture.html: Added.
+ * pointerevents/ios/pointer-events-set-pointer-capture-exceptions-expected.txt: Added.
+ * pointerevents/ios/pointer-events-set-pointer-capture-exceptions.html: Added.
+
2019-01-28 Dean Jackson <[email protected]>
Produce "pen" Pointer Events if using a stylus (e.g. Apple Pencil)
Added: trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-expected.txt (0 => 240634)
--- trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-expected.txt (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-expected.txt 2019-01-29 03:15:02 UTC (rev 240634)
@@ -0,0 +1,3 @@
+
+PASS Pointer events for a direct manipulation device trigger 'gotpointercapture' and 'lostpointercapture' events due to implicit capture.
+
Added: trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-has-pointer-capture-in-pointer-down-expected.txt (0 => 240634)
--- trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-has-pointer-capture-in-pointer-down-expected.txt (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-has-pointer-capture-in-pointer-down-expected.txt 2019-01-29 03:15:02 UTC (rev 240634)
@@ -0,0 +1,3 @@
+
+PASS Calling hasPointerCapture() in the 'pointerdown' event handler returns true for direct manipulation devices.
+
Added: trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-has-pointer-capture-in-pointer-down.html (0 => 240634)
--- trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-has-pointer-capture-in-pointer-down.html (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-has-pointer-capture-in-pointer-down.html 2019-01-29 03:15:02 UTC (rev 240634)
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script>
+
+'use strict';
+
+target_test((target, test) => {
+ target.addEventListener("pointerdown", event => assert_true(target.hasPointerCapture(event.pointerId)));
+ ui.beginTouches({ x: 50, y: 50 }).then(() => test.done());
+}, "Calling hasPointerCapture() in the 'pointerdown' event handler returns true for direct manipulation devices.");
+
+</script>
+</body>
+</html>
\ No newline at end of file
Added: trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-exception-expected.txt (0 => 240634)
--- trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-exception-expected.txt (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-exception-expected.txt 2019-01-29 03:15:02 UTC (rev 240634)
@@ -0,0 +1,3 @@
+
+PASS Calling releasePointerCapture() in the 'pointerdown' event handler with a bogus pointer id raises an exception and does not alter pointer capture.
+
Added: trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-exception.html (0 => 240634)
--- trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-exception.html (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-exception.html 2019-01-29 03:15:02 UTC (rev 240634)
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script>
+
+'use strict';
+
+target_test((target, test) => {
+ target.addEventListener("pointerdown", event => {
+ assert_true(target.hasPointerCapture(event.pointerId));
+ assert_throws("NotFoundError", () => target.releasePointerCapture(event.pointerId + 1));
+ assert_true(target.hasPointerCapture(event.pointerId));
+ });
+ ui.beginTouches({ x: 50, y: 50 }).then(() => test.done());
+}, "Calling releasePointerCapture() in the 'pointerdown' event handler with a bogus pointer id raises an exception and does not alter pointer capture.");
+
+</script>
+</body>
+</html>
\ No newline at end of file
Added: trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-expected.txt (0 => 240634)
--- trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-expected.txt (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-expected.txt 2019-01-29 03:15:02 UTC (rev 240634)
@@ -0,0 +1,3 @@
+
+PASS Calling releasePointerCapture() in the 'pointerdown' event handler makes hasPointerCapture() return false.
+
Added: trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release.html (0 => 240634)
--- trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release.html (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release.html 2019-01-29 03:15:02 UTC (rev 240634)
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script>
+
+'use strict';
+
+target_test((target, test) => {
+ target.addEventListener("pointerdown", event => {
+ assert_true(target.hasPointerCapture(event.pointerId));
+ target.releasePointerCapture(event.pointerId);
+ assert_false(target.hasPointerCapture(event.pointerId));
+ });
+ ui.beginTouches({ x: 50, y: 50 }).then(() => test.done());
+}, "Calling releasePointerCapture() in the 'pointerdown' event handler makes hasPointerCapture() return false.");
+
+</script>
+</body>
+</html>
\ No newline at end of file
Added: trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture.html (0 => 240634)
--- trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture.html (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/pointer-events-implicit-capture.html 2019-01-29 03:15:02 UTC (rev 240634)
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script>
+
+'use strict';
+
+target_test((target, test) => {
+ const eventTracker = new EventTracker(target, ["pointerdown", "gotpointercapture", "pointermove", "pointerup", "lostpointercapture"]);
+
+ const _one_ = ui.finger();
+ const two = ui.finger();
+ ui.sequence([
+ one.begin({ x: 10, y: 10 }),
+ two.begin({ x: 50, y: 50 }),
+ one.move({ x: 30, y: 30 }),
+ two.move({ x: 70, y: 70 }),
+ one.end(),
+ two.end()
+ ]).then(() => {
+ eventTracker.assertMatchesEvents([
+ { id: 1, type: "pointerdown" },
+ { id: 1, type: "gotpointercapture", isPrimary: true },
+ { id: 2, type: "pointerdown" },
+ { id: 2, type: "gotpointercapture", isPrimary: false },
+ { id: 1, type: "pointermove" },
+ { id: 2, type: "pointermove" },
+ { id: 1, type: "pointerup" },
+ { id: 1, type: "lostpointercapture", isPrimary: false },
+ { id: 2, type: "pointerup" },
+ { id: 2, type: "lostpointercapture", isPrimary: false }
+ ]);
+ test.done();
+ });
+}, "Pointer events for a direct manipulation device trigger 'gotpointercapture' and 'lostpointercapture' events due to implicit capture.");
+
+</script>
+</body>
+</html>
\ No newline at end of file
Added: trunk/LayoutTests/pointerevents/ios/pointer-events-set-pointer-capture-exceptions-expected.txt (0 => 240634)
--- trunk/LayoutTests/pointerevents/ios/pointer-events-set-pointer-capture-exceptions-expected.txt (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/pointer-events-set-pointer-capture-exceptions-expected.txt 2019-01-29 03:15:02 UTC (rev 240634)
@@ -0,0 +1,3 @@
+
+PASS The setPointerCapture() method can throw.
+
Added: trunk/LayoutTests/pointerevents/ios/pointer-events-set-pointer-capture-exceptions.html (0 => 240634)
--- trunk/LayoutTests/pointerevents/ios/pointer-events-set-pointer-capture-exceptions.html (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/pointer-events-set-pointer-capture-exceptions.html 2019-01-29 03:15:02 UTC (rev 240634)
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script>
+
+'use strict';
+
+target_test((target, test) => {
+ assert_throws("NotFoundError", () => document.body.setPointerCapture(10), "Calling setPointerCapture() with an invalid pointer id throws a NotFoundError exception.");
+
+ target.addEventListener("pointerdown", event => {
+ assert_true(target.hasPointerCapture(event.pointerId));
+ assert_throws("InvalidStateError", () => document.createElement("div").setPointerCapture(event.pointerId), "Calling setPointerCapture() with a valid pointer id on a disconnected element throws an InvalidStateError exception.");
+ });
+ ui.beginTouches({ x: 50, y: 50 }).then(() => test.done());
+}, "The setPointerCapture() method can throw.");
+
+</script>
+</body>
+</html>
\ No newline at end of file
Modified: trunk/Source/WebCore/ChangeLog (240633 => 240634)
--- trunk/Source/WebCore/ChangeLog 2019-01-29 02:59:08 UTC (rev 240633)
+++ trunk/Source/WebCore/ChangeLog 2019-01-29 03:15:02 UTC (rev 240634)
@@ -1,3 +1,51 @@
+2019-01-28 Antoine Quint <[email protected]>
+
+ Implement capture for Pointer Events on iOS
+ https://bugs.webkit.org/show_bug.cgi?id=193917
+ <rdar://problem/47605689>
+
+ Reviewed by Dean Jackson.
+
+ We add a new PointerCaptureController object which gets notified upon dispatch of pointer events
+ to implement implicit pointer capture, dispatch the gotpointercapture and lostpointercaptiure events,
+ and implement the Element APIs for pointer capture: hasPointerCapture(), setPointerCapture() and
+ releasePointerCapture().
+
+ Tests: pointerevents/ios/pointer-events-implicit-capture-has-pointer-capture-in-pointer-down.html
+ pointerevents/ios/pointer-events-implicit-capture-release-exception.html
+ pointerevents/ios/pointer-events-implicit-capture-release.html
+ pointerevents/ios/pointer-events-implicit-capture.html
+ pointerevents/ios/pointer-events-set-pointer-capture-exceptions.html
+
+ * Sources.txt:
+ * WebCore.xcodeproj/project.pbxproj:
+ * dom/Element.cpp:
+ (WebCore::Element::setPointerCapture):
+ (WebCore::Element::releasePointerCapture):
+ (WebCore::Element::hasPointerCapture):
+ * dom/Element.h:
+ * dom/Element.idl:
+ * dom/EventNames.h:
+ * dom/PointerEvent.h:
+ * page/Page.cpp:
+ (WebCore::Page::Page):
+ * page/Page.h:
+ (WebCore::Page::pointerCaptureController const):
+ * page/PointerCaptureController.cpp: Added.
+ (WebCore::PointerCaptureController::PointerCaptureController):
+ (WebCore::PointerCaptureController::setPointerCapture):
+ (WebCore::PointerCaptureController::releasePointerCapture):
+ (WebCore::PointerCaptureController::hasPointerCapture):
+ (WebCore::PointerCaptureController::pointerLockWasApplied):
+ (WebCore::PointerCaptureController::touchEndedOrWasCancelledForIdentifier):
+ (WebCore::PointerCaptureController::pointerEventWillBeDispatched):
+ (WebCore::PointerCaptureController::pointerEventWasDispatched):
+ (WebCore::PointerCaptureController::processPendingPointerCapture):
+ * page/PointerCaptureController.h: Added.
+ * page/PointerLockController.cpp:
+ (WebCore::PointerLockController::requestPointerLock):
+ * page/PointerLockController.h:
+
2019-01-28 Andy Estes <[email protected]>
[watchOS] Enable Parental Controls content filtering
Modified: trunk/Source/WebCore/Sources.txt (240633 => 240634)
--- trunk/Source/WebCore/Sources.txt 2019-01-29 02:59:08 UTC (rev 240633)
+++ trunk/Source/WebCore/Sources.txt 2019-01-29 03:15:02 UTC (rev 240634)
@@ -1523,6 +1523,7 @@
page/PerformanceServerTiming.cpp
page/PerformanceTiming.cpp
page/PerformanceUserTiming.cpp
+page/PointerCaptureController.cpp
page/PointerLockController.cpp
page/PrintContext.cpp
page/ProcessWarming.cpp
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (240633 => 240634)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2019-01-29 02:59:08 UTC (rev 240633)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2019-01-29 03:15:02 UTC (rev 240634)
@@ -2117,6 +2117,7 @@
71A1B6081DEE5AD70073BCFB /* modern-media-controls-localized-strings.js in Resources */ = {isa = PBXBuildFile; fileRef = 71A1B6061DEE5A820073BCFB /* modern-media-controls-localized-strings.js */; };
71A57DF2154BE25C0009D120 /* SVGPathUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 71A57DF0154BE25C0009D120 /* SVGPathUtilities.h */; };
71B28427203CEC4C0036AA5D /* JSCSSAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 71B28426203CEC0D0036AA5D /* JSCSSAnimation.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 71B5AB2621F1D9F400376E5C /* PointerCaptureController.h in Headers */ = {isa = PBXBuildFile; fileRef = 71B5AB2421F1D9E200376E5C /* PointerCaptureController.h */; };
71B7EE0D21B5C6870031C1EF /* TouchAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 71AEE4EB21B5A49C00DDB036 /* TouchAction.h */; settings = {ATTRIBUTES = (Private, ); }; };
71C29E32203CE781008F36D2 /* CSSAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 71C29E30203CE76B008F36D2 /* CSSAnimation.h */; settings = {ATTRIBUTES = (Private, ); }; };
71C916081D1483A300ACA47D /* UserInterfaceLayoutDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 71C916071D1483A300ACA47D /* UserInterfaceLayoutDirection.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -9410,6 +9411,8 @@
71B0460A1DD3C2EE00EE19CF /* status-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = "status-support.js"; sourceTree = "<group>"; };
71B28424203CEC0B0036AA5D /* JSCSSAnimation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCSSAnimation.cpp; sourceTree = "<group>"; };
71B28426203CEC0D0036AA5D /* JSCSSAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCSSAnimation.h; sourceTree = "<group>"; };
+ 71B5AB2421F1D9E200376E5C /* PointerCaptureController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PointerCaptureController.h; sourceTree = "<group>"; };
+ 71B5AB2521F1D9E300376E5C /* PointerCaptureController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PointerCaptureController.cpp; sourceTree = "<group>"; };
71C29E2E203CE76B008F36D2 /* CSSAnimation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CSSAnimation.cpp; sourceTree = "<group>"; };
71C29E30203CE76B008F36D2 /* CSSAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSAnimation.h; sourceTree = "<group>"; };
71C29E31203CE76C008F36D2 /* CSSAnimation.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CSSAnimation.idl; sourceTree = "<group>"; };
@@ -20413,6 +20416,8 @@
A554B5F01E383936001D4E03 /* PerformanceUserTiming.cpp */,
A554B5F11E383936001D4E03 /* PerformanceUserTiming.h */,
31D591B116697A6C00E6BF02 /* PlugInClient.h */,
+ 71B5AB2521F1D9E300376E5C /* PointerCaptureController.cpp */,
+ 71B5AB2421F1D9E200376E5C /* PointerCaptureController.h */,
5CFC434E192406A900A0D3B5 /* PointerLockController.cpp */,
5CFC434F192406A900A0D3B5 /* PointerLockController.h */,
3772B09516535856000A49CA /* PopupOpeningObserver.h */,
@@ -31956,6 +31961,7 @@
26E944DD1AC4B4EA007B85B5 /* Term.h in Headers */,
6550B6A6099DF0270090D781 /* Text.h in Headers */,
93309E17099E64920056E581 /* TextAffinity.h in Headers */,
+ 71B5AB2621F1D9F400376E5C /* PointerCaptureController.h in Headers */,
CE7B2DB51586ABAD0098B3FA /* TextAlternativeWithRange.h in Headers */,
0F54DCE61881051D003EEDBB /* TextAutoSizing.h in Headers */,
B2C3DA340D006C1D00EF6F26 /* TextBoundaries.h in Headers */,
Modified: trunk/Source/WebCore/dom/Element.cpp (240633 => 240634)
--- trunk/Source/WebCore/dom/Element.cpp 2019-01-29 02:59:08 UTC (rev 240633)
+++ trunk/Source/WebCore/dom/Element.cpp 2019-01-29 03:15:02 UTC (rev 240634)
@@ -78,6 +78,7 @@
#include "MutationRecord.h"
#include "NodeRenderStyle.h"
#include "PlatformWheelEvent.h"
+#include "PointerCaptureController.h"
#include "PointerLockController.h"
#include "RenderFragmentContainer.h"
#include "RenderLayer.h"
@@ -3434,6 +3435,29 @@
}
#endif
+#if ENABLE(POINTER_EVENTS)
+ExceptionOr<void> Element::setPointerCapture(int32_t pointerId)
+{
+ if (document().page())
+ return document().page()->pointerCaptureController().setPointerCapture(this, pointerId);
+ return { };
+}
+
+ExceptionOr<void> Element::releasePointerCapture(int32_t pointerId)
+{
+ if (document().page())
+ return document().page()->pointerCaptureController().releasePointerCapture(this, pointerId);
+ return { };
+}
+
+bool Element::hasPointerCapture(int32_t pointerId)
+{
+ if (document().page())
+ return document().page()->pointerCaptureController().hasPointerCapture(this, pointerId);
+ return false;
+}
+#endif
+
#if ENABLE(POINTER_LOCK)
void Element::requestPointerLock()
{
Modified: trunk/Source/WebCore/dom/Element.h (240633 => 240634)
--- trunk/Source/WebCore/dom/Element.h 2019-01-29 02:59:08 UTC (rev 240633)
+++ trunk/Source/WebCore/dom/Element.h 2019-01-29 03:15:02 UTC (rev 240634)
@@ -497,6 +497,12 @@
WEBCORE_EXPORT virtual void webkitRequestFullscreen();
#endif
+#if ENABLE(POINTER_EVENTS)
+ ExceptionOr<void> setPointerCapture(int32_t);
+ ExceptionOr<void> releasePointerCapture(int32_t);
+ bool hasPointerCapture(int32_t);
+#endif
+
#if ENABLE(POINTER_LOCK)
WEBCORE_EXPORT void requestPointerLock();
#endif
Modified: trunk/Source/WebCore/dom/Element.idl (240633 => 240634)
--- trunk/Source/WebCore/dom/Element.idl 2019-01-29 02:59:08 UTC (rev 240633)
+++ trunk/Source/WebCore/dom/Element.idl 2019-01-29 03:15:02 UTC (rev 240634)
@@ -98,6 +98,11 @@
[Conditional=FULLSCREEN_API, EnabledBySetting=FullScreen, ImplementedAs=webkitRequestFullscreen] void webkitRequestFullScreen(); // Prefixed Mozilla version.
[Conditional=FULLSCREEN_API, EnabledBySetting=FullScreen] void webkitRequestFullscreen(); // Prefixed W3C version.
+ // Extensions from Pointer Events API (https://w3c.github.io/pointerevents/#extensions-to-the-element-interface).
+ [Conditional=POINTER_EVENTS, EnabledAtRuntime=PointerEvents, MayThrowException] void setPointerCapture(long pointerId);
+ [Conditional=POINTER_EVENTS, EnabledAtRuntime=PointerEvents, MayThrowException] void releasePointerCapture(long pointerId);
+ [Conditional=POINTER_EVENTS, EnabledAtRuntime=PointerEvents] boolean hasPointerCapture(long pointerId);
+
// Extensions from Pointer Lock API (https://w3c.github.io/pointerlock/#extensions-to-the-element-interface).
[Conditional=POINTER_LOCK] void requestPointerLock();
Modified: trunk/Source/WebCore/dom/EventNames.h (240633 => 240634)
--- trunk/Source/WebCore/dom/EventNames.h 2019-01-29 02:59:08 UTC (rev 240633)
+++ trunk/Source/WebCore/dom/EventNames.h 2019-01-29 03:15:02 UTC (rev 240634)
@@ -140,6 +140,7 @@
macro(gesturestart) \
macro(gesturetap) \
macro(gesturetapdown) \
+ macro(gotpointercapture) \
macro(hashchange) \
macro(icecandidate) \
macro(iceconnectionstatechange) \
@@ -162,6 +163,7 @@
macro(loadingdone) \
macro(loadingerror) \
macro(loadstart) \
+ macro(lostpointercapture) \
macro(mark) \
macro(merchantvalidation) \
macro(message) \
Modified: trunk/Source/WebCore/dom/PointerEvent.h (240633 => 240634)
--- trunk/Source/WebCore/dom/PointerEvent.h 2019-01-29 02:59:08 UTC (rev 240633)
+++ trunk/Source/WebCore/dom/PointerEvent.h 2019-01-29 03:15:02 UTC (rev 240634)
@@ -39,7 +39,7 @@
class PointerEvent final : public MouseEvent {
public:
struct Init : MouseEventInit {
- long pointerId { 0 };
+ int32_t pointerId { 0 };
double width { 1 };
double height { 1 };
float pressure { 0 };
@@ -56,6 +56,18 @@
return adoptRef(*new PointerEvent(type, WTFMove(initializer)));
}
+#if ENABLE(POINTER_EVENTS)
+ static Ref<PointerEvent> createForPointerCapture(const AtomicString& type, const PointerEvent& pointerEvent)
+ {
+ Init initializer;
+ initializer.bubbles = true;
+ initializer.pointerId = pointerEvent.pointerId();
+ initializer.isPrimary = pointerEvent.isPrimary();
+ initializer.pointerType = pointerEvent.pointerType();
+ return adoptRef(*new PointerEvent(type, WTFMove(initializer)));
+ }
+#endif
+
static Ref<PointerEvent> createForBindings()
{
return adoptRef(*new PointerEvent);
@@ -67,7 +79,7 @@
virtual ~PointerEvent();
- long pointerId() const { return m_pointerId; }
+ int32_t pointerId() const { return m_pointerId; }
double width() const { return m_width; }
double height() const { return m_height; }
float pressure() const { return m_pressure; }
@@ -89,7 +101,7 @@
PointerEvent(const AtomicString& type, const PlatformTouchEvent&, IsCancelable isCancelable, unsigned touchIndex, bool isPrimary, Ref<WindowProxy>&&);
#endif
- long m_pointerId { 0 };
+ int32_t m_pointerId { 0 };
double m_width { 1 };
double m_height { 1 };
float m_pressure { 0 };
Modified: trunk/Source/WebCore/page/Page.cpp (240633 => 240634)
--- trunk/Source/WebCore/page/Page.cpp 2019-01-29 02:59:08 UTC (rev 240633)
+++ trunk/Source/WebCore/page/Page.cpp 2019-01-29 03:15:02 UTC (rev 240634)
@@ -86,6 +86,7 @@
#include "PluginData.h"
#include "PluginInfoProvider.h"
#include "PluginViewBase.h"
+#include "PointerCaptureController.h"
#include "PointerLockController.h"
#include "ProgressTracker.h"
#include "PublicSuffix.h"
@@ -214,6 +215,9 @@
#endif
, m_userInputBridge(std::make_unique<UserInputBridge>(*this))
, m_inspectorController(std::make_unique<InspectorController>(*this, pageConfiguration.inspectorClient))
+#if ENABLE(POINTER_EVENTS)
+ , m_pointerCaptureController(std::make_unique<PointerCaptureController>())
+#endif
#if ENABLE(POINTER_LOCK)
, m_pointerLockController(std::make_unique<PointerLockController>(*this))
#endif
Modified: trunk/Source/WebCore/page/Page.h (240633 => 240634)
--- trunk/Source/WebCore/page/Page.h 2019-01-29 02:59:08 UTC (rev 240633)
+++ trunk/Source/WebCore/page/Page.h 2019-01-29 03:15:02 UTC (rev 240634)
@@ -122,6 +122,7 @@
class PluginData;
class PluginInfoProvider;
class PluginViewBase;
+class PointerCaptureController;
class PointerLockController;
class ProgressTracker;
class ProgressTrackerClient;
@@ -244,6 +245,9 @@
#endif
UserInputBridge& userInputBridge() const { return *m_userInputBridge; }
InspectorController& inspectorController() const { return *m_inspectorController; }
+#if ENABLE(POINTER_EVENTS)
+ PointerCaptureController& pointerCaptureController() const { return *m_pointerCaptureController; }
+#endif
#if ENABLE(POINTER_LOCK)
PointerLockController& pointerLockController() const { return *m_pointerLockController; }
#endif
@@ -747,6 +751,9 @@
#endif
const std::unique_ptr<UserInputBridge> m_userInputBridge;
const std::unique_ptr<InspectorController> m_inspectorController;
+#if ENABLE(POINTER_EVENTS)
+ const std::unique_ptr<PointerCaptureController> m_pointerCaptureController;
+#endif
#if ENABLE(POINTER_LOCK)
const std::unique_ptr<PointerLockController> m_pointerLockController;
#endif
Added: trunk/Source/WebCore/page/PointerCaptureController.cpp (0 => 240634)
--- trunk/Source/WebCore/page/PointerCaptureController.cpp (rev 0)
+++ trunk/Source/WebCore/page/PointerCaptureController.cpp 2019-01-29 03:15:02 UTC (rev 240634)
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "config.h"
+#include "PointerCaptureController.h"
+
+#if ENABLE(POINTER_EVENTS)
+
+#include "Document.h"
+#include "Element.h"
+#include "EventNames.h"
+#include "EventTarget.h"
+#include "Page.h"
+#include "PointerEvent.h"
+
+namespace WebCore {
+
+PointerCaptureController::PointerCaptureController() = default;
+
+ExceptionOr<void> PointerCaptureController::setPointerCapture(Element* capturingTarget, int32_t pointerId)
+{
+ // https://w3c.github.io/pointerevents/#setting-pointer-capture
+
+ // 1. If the pointerId provided as the method's argument does not match any of the active pointers, then throw a DOMException with the name NotFoundError.
+ auto iterator = m_activePointerIdsToCapturingData.find(pointerId);
+ if (iterator == m_activePointerIdsToCapturingData.end())
+ return Exception { NotFoundError };
+
+ // 2. If the Element on which this method is invoked is not connected, throw an exception with the name InvalidStateError.
+ if (!capturingTarget->isConnected())
+ return Exception { InvalidStateError };
+
+#if ENABLE(POINTER_LOCK)
+ // 3. If this method is invoked while the document has a locked element, throw an exception with the name InvalidStateError.
+ if (auto* page = capturingTarget->document().page()) {
+ if (page->pointerLockController().isLocked())
+ return Exception { InvalidStateError };
+ }
+#endif
+
+ // 4. If the pointer is not in the active buttons state, then terminate these steps.
+ // FIXME: implement when we support mouse events.
+
+ // 5. For the specified pointerId, set the pending pointer capture target override to the Element on which this method was invoked.
+ iterator->value.pendingTargetOverride = capturingTarget;
+
+ return { };
+}
+
+ExceptionOr<void> PointerCaptureController::releasePointerCapture(Element* capturingTarget, int32_t pointerId, ImplicitCapture implicit)
+{
+ // https://w3c.github.io/pointerevents/#releasing-pointer-capture
+
+ // Pointer capture is released on an element explicitly by calling the element.releasePointerCapture(pointerId) method.
+ // When this method is called, a user agent MUST run the following steps:
+
+ // 1. If the pointerId provided as the method's argument does not match any of the active pointers and these steps are not
+ // being invoked as a result of the implicit release of pointer capture, then throw a DOMException with the name NotFoundError.
+ auto iterator = m_activePointerIdsToCapturingData.find(pointerId);
+ if (implicit == ImplicitCapture::No && iterator == m_activePointerIdsToCapturingData.end())
+ return Exception { NotFoundError };
+
+ // 2. If hasPointerCapture is false for the Element with the specified pointerId, then terminate these steps.
+ if (!hasPointerCapture(capturingTarget, pointerId))
+ return { };
+
+ // 3. For the specified pointerId, clear the pending pointer capture target override, if set.
+ iterator->value.pendingTargetOverride = nullptr;
+
+ return { };
+}
+
+bool PointerCaptureController::hasPointerCapture(Element* capturingTarget, int32_t pointerId)
+{
+ // https://w3c.github.io/pointerevents/#dom-element-haspointercapture
+
+ // Indicates whether the element on which this method is invoked has pointer capture for the pointer identified by the argument pointerId.
+ // In particular, returns true if the pending pointer capture target override for pointerId is set to the element on which this method is
+ // invoked, and false otherwise.
+
+ auto iterator = m_activePointerIdsToCapturingData.find(pointerId);
+ if (iterator == m_activePointerIdsToCapturingData.end())
+ return false;
+
+ auto& capturingData = iterator->value;
+ return capturingData.pendingTargetOverride == capturingTarget || capturingData.targetOverride == capturingTarget;
+}
+
+void PointerCaptureController::pointerLockWasApplied()
+{
+ // https://w3c.github.io/pointerevents/#implicit-release-of-pointer-capture
+
+ // When a pointer lock is successfully applied on an element, a user agent MUST run the steps as if the releasePointerCapture()
+ // method has been called if any element is set to be captured or pending to be captured.
+ for (auto& capturingData : m_activePointerIdsToCapturingData.values()) {
+ capturingData.pendingTargetOverride = nullptr;
+ capturingData.targetOverride = nullptr;
+ }
+}
+
+void PointerCaptureController::touchEndedOrWasCancelledForIdentifier(int32_t pointerId)
+{
+ m_activePointerIdsToCapturingData.remove(pointerId);
+}
+
+void PointerCaptureController::pointerEventWillBeDispatched(const PointerEvent& event, EventTarget* target)
+{
+ // https://w3c.github.io/pointerevents/#implicit-pointer-capture
+
+ // Some input devices (such as touchscreens) implement a "direct manipulation" metaphor where a pointer is intended to act primarily on the UI
+ // element it became active upon (providing a physical illusion of direct contact, instead of indirect contact via a cursor that conceptually
+ // floats above the UI). Such devices are identified by the InputDeviceCapabilities.pointerMovementScrolls property and should have "implicit
+ // pointer capture" behavior as follows.
+
+ // Direct manipulation devices should behave exactly as if setPointerCapture was called on the target element just before the invocation of any
+ // pointerdown listeners. The hasPointerCapture API may be used (eg. within any pointerdown listener) to determine whether this has occurred. If
+ // releasePointerCapture is not called for the pointer before the next pointer event is fired, then a gotpointercapture event will be dispatched
+ // to the target (as normal) indicating that capture is active.
+
+ if (!is<Element>(target) || event.type() != eventNames().pointerdownEvent)
+ return;
+
+ auto pointerId = event.pointerId();
+ m_activePointerIdsToCapturingData.set(pointerId, CapturingData { });
+ setPointerCapture(downcast<Element>(target), pointerId);
+}
+
+void PointerCaptureController::pointerEventWasDispatched(const PointerEvent& event)
+{
+ // https://w3c.github.io/pointerevents/#implicit-release-of-pointer-capture
+
+ auto iterator = m_activePointerIdsToCapturingData.find(event.pointerId());
+ if (iterator != m_activePointerIdsToCapturingData.end()) {
+ auto& capturingData = iterator->value;
+ // Immediately after firing the pointerup or pointercancel events, a user agent MUST clear the pending pointer capture target
+ // override for the pointerId of the pointerup or pointercancel event that was just dispatched, and then run Process Pending
+ // Pointer Capture steps to fire lostpointercapture if necessary.
+ if (event.type() == eventNames().pointerupEvent)
+ capturingData.pendingTargetOverride = nullptr;
+
+ // When the pointer capture target override is no longer connected, the pending pointer capture target override and pointer
+ // capture target override nodes SHOULD be cleared and also a PointerEvent named lostpointercapture corresponding to the captured
+ // pointer SHOULD be fired at the document.
+ if (capturingData.targetOverride && !capturingData.targetOverride->isConnected()) {
+ capturingData.pendingTargetOverride = nullptr;
+ capturingData.targetOverride = nullptr;
+ }
+ }
+
+ processPendingPointerCapture(event);
+}
+
+void PointerCaptureController::processPendingPointerCapture(const PointerEvent& event)
+{
+ // https://w3c.github.io/pointerevents/#process-pending-pointer-capture
+
+ auto iterator = m_activePointerIdsToCapturingData.find(event.pointerId());
+ if (iterator == m_activePointerIdsToCapturingData.end())
+ return;
+
+ auto& capturingData = iterator->value;
+
+ // 1. If the pointer capture target override for this pointer is set and is not equal to the pending pointer capture target override,
+ // then fire a pointer event named lostpointercapture at the pointer capture target override node.
+ if (capturingData.targetOverride && capturingData.targetOverride != capturingData.pendingTargetOverride)
+ capturingData.targetOverride->dispatchEvent(PointerEvent::createForPointerCapture(eventNames().lostpointercaptureEvent, event));
+
+ // 2. If the pending pointer capture target override for this pointer is set and is not equal to the pointer capture target override,
+ // then fire a pointer event named gotpointercapture at the pending pointer capture target override.
+ if (capturingData.pendingTargetOverride && capturingData.targetOverride != capturingData.pendingTargetOverride)
+ capturingData.pendingTargetOverride->dispatchEvent(PointerEvent::createForPointerCapture(eventNames().gotpointercaptureEvent, event));
+
+ // 3. Set the pointer capture target override to the pending pointer capture target override, if set. Otherwise, clear the pointer
+ // capture target override.
+ capturingData.targetOverride = capturingData.pendingTargetOverride;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(POINTER_EVENTS)
Added: trunk/Source/WebCore/page/PointerCaptureController.h (0 => 240634)
--- trunk/Source/WebCore/page/PointerCaptureController.h (rev 0)
+++ trunk/Source/WebCore/page/PointerCaptureController.h 2019-01-29 03:15:02 UTC (rev 240634)
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 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(POINTER_EVENTS)
+
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+class Element;
+class EventTarget;
+class PointerEvent;
+
+class PointerCaptureController {
+ WTF_MAKE_NONCOPYABLE(PointerCaptureController);
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ explicit PointerCaptureController();
+
+ enum class ImplicitCapture : uint8_t { Yes, No };
+
+ ExceptionOr<void> setPointerCapture(Element*, int32_t);
+ ExceptionOr<void> releasePointerCapture(Element*, int32_t, ImplicitCapture implicit = ImplicitCapture::No);
+ bool hasPointerCapture(Element*, int32_t);
+
+ void pointerLockWasApplied();
+
+ void touchEndedOrWasCancelledForIdentifier(int32_t);
+ void pointerEventWillBeDispatched(const PointerEvent&, EventTarget*);
+ void pointerEventWasDispatched(const PointerEvent&);
+
+private:
+ struct CapturingData {
+ Element* pendingTargetOverride;
+ Element* targetOverride;
+ };
+
+ void processPendingPointerCapture(const PointerEvent&);
+ HashMap<int32_t, CapturingData> m_activePointerIdsToCapturingData;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(POINTER_EVENTS)
Modified: trunk/Source/WebCore/page/PointerLockController.cpp (240633 => 240634)
--- trunk/Source/WebCore/page/PointerLockController.cpp 2019-01-29 02:59:08 UTC (rev 240633)
+++ trunk/Source/WebCore/page/PointerLockController.cpp 2019-01-29 03:15:02 UTC (rev 240634)
@@ -71,6 +71,9 @@
}
m_element = target;
enqueueEvent(eventNames().pointerlockchangeEvent, target);
+#if ENABLE(POINTER_EVENTS)
+ m_page.pointerCaptureController().pointerLockWasApplied();
+#endif
} else {
m_lockPending = true;
m_element = target;
Modified: trunk/Source/WebCore/page/PointerLockController.h (240633 => 240634)
--- trunk/Source/WebCore/page/PointerLockController.h 2019-01-29 02:59:08 UTC (rev 240633)
+++ trunk/Source/WebCore/page/PointerLockController.h 2019-01-29 03:15:02 UTC (rev 240634)
@@ -27,6 +27,7 @@
#if ENABLE(POINTER_LOCK)
#include <wtf/RefPtr.h>
+#include <wtf/WeakPtr.h>
#include <wtf/text/AtomicString.h>
namespace WebCore {