WebKit Bugzilla
Attachment 360413 Details for
Bug 193917
: Implement capture for Pointer Events on iOS
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-193917-20190129033401.patch (text/plain), 44.62 KB, created by
Antoine Quint
on 2019-01-28 18:34:03 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Antoine Quint
Created:
2019-01-28 18:34:03 PST
Size:
44.62 KB
patch
obsolete
>Subversion Revision: 240632 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 510cb093cb7ee0896810eb4e85c2ce16ed3b223c..0d1cc42fcf432a41ca3f0c875b6c739dd2875b91 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,51 @@ >+2019-01-28 Antoine Quint <graouts@apple.com> >+ >+ Implement capture for Pointer Events on iOS >+ https://bugs.webkit.org/show_bug.cgi?id=193917 >+ <rdar://problem/47605689> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ 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::touchEndedOrWasCanceledForIdentifier): >+ (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 Dean Jackson <dino@apple.com> > > Produce "pen" Pointer Events if using a stylus (e.g. Apple Pencil) >diff --git a/Source/WebCore/Sources.txt b/Source/WebCore/Sources.txt >index de5421f8f8fc32c46e7ac9a7f9bda7dd4d13ebdb..cb5143d25023bf9fed5b75940257fa3f5d599441 100644 >--- a/Source/WebCore/Sources.txt >+++ b/Source/WebCore/Sources.txt >@@ -1523,6 +1523,7 @@ page/PerformanceResourceTiming.cpp > page/PerformanceServerTiming.cpp > page/PerformanceTiming.cpp > page/PerformanceUserTiming.cpp >+page/PointerCaptureController.cpp > page/PointerLockController.cpp > page/PrintContext.cpp > page/ProcessWarming.cpp >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index 9cc3bae41a26100463ac92e39211b5543591ec4b..bcce83d33cdae1322e94ed3ba81e90f5c9f7f06d 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -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>"; }; >@@ -17276,8 +17279,8 @@ > 29A812040FBB9B4100510293 /* accessibility */ = { > isa = PBXGroup; > children = ( >- 29AE212921AB9ECB00869283 /* isolatedtree */, > AAA728EF16D1D8BC00D3BBC6 /* ios */, >+ 29AE212921AB9ECB00869283 /* isolatedtree */, > 29A812050FBB9B5200510293 /* mac */, > 2981CA9D131822EC00D12F2A /* AccessibilityARIAGrid.cpp */, > 29A812160FBB9C1D00510293 /* AccessibilityARIAGrid.h */, >@@ -17374,10 +17377,10 @@ > 29AE212921AB9ECB00869283 /* isolatedtree */ = { > isa = PBXGroup; > children = ( >- 29AE212B21AB9EEB00869283 /* AXIsolatedTree.h */, > 29AE212C21AB9EEB00869283 /* AXIsolatedTree.cpp */, >- 29AE213321ABA48A00869283 /* AXIsolatedTreeNode.h */, >+ 29AE212B21AB9EEB00869283 /* AXIsolatedTree.h */, > 29AE213421ABA48A00869283 /* AXIsolatedTreeNode.cpp */, >+ 29AE213321ABA48A00869283 /* AXIsolatedTreeNode.h */, > ); > path = isolatedtree; > 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 */, >@@ -28265,6 +28270,7 @@ > 76CDD2F51103DA6600680521 /* AccessibilityMenuListPopup.h in Headers */, > 29ACB212143E7128006BCA5F /* AccessibilityMockObject.h in Headers */, > 29A812360FBB9C1D00510293 /* AccessibilityObject.h in Headers */, >+ 2936BF5C21D69E4B004A8FC9 /* AccessibilityObjectInterface.h in Headers */, > A409C985116D0DDD007197BD /* AccessibilityProgressIndicator.h in Headers */, > 29A812390FBB9C1D00510293 /* AccessibilityRenderObject.h in Headers */, > 93C4F6EB1108F9A50099D0DB /* AccessibilityScrollbar.h in Headers */, >@@ -28434,6 +28440,8 @@ > 07F4E93320B3587F002E3803 /* AVFoundationMIMETypeCache.h in Headers */, > CD336F6217F9F64700DDDCD0 /* AVTrackPrivateAVFObjCImpl.h in Headers */, > 070363E6181A1CDC00C074A5 /* AVVideoCaptureSource.h in Headers */, >+ 29AE212D21AB9EEB00869283 /* AXIsolatedTree.h in Headers */, >+ 29AE213521ABA48A00869283 /* AXIsolatedTreeNode.h in Headers */, > F45C231E1995B73B00A6E2E3 /* AxisScrollSnapOffsets.h in Headers */, > 29A812380FBB9C1D00510293 /* AXObjectCache.h in Headers */, > 91C9F2F91AE3BEB00095B61C /* AXTextStateChangeIntent.h in Headers */, >@@ -30007,7 +30015,6 @@ > 1AE2AA980A1CDD2D00B42B25 /* JSHTMLImageElement.h in Headers */, > A80E7E970A1A83E3007FB8C5 /* JSHTMLInputElement.h in Headers */, > 836B09561F5F34D9003C3702 /* JSHTMLInputElementEntriesAPI.h in Headers */, >- 2936BF5C21D69E4B004A8FC9 /* AccessibilityObjectInterface.h in Headers */, > A6148A7912E41E3B0044A784 /* JSHTMLKeygenElement.h in Headers */, > 1AE2AB220A1CE63B00B42B25 /* JSHTMLLabelElement.h in Headers */, > 1AE2AB240A1CE63B00B42B25 /* JSHTMLLegendElement.h in Headers */, >@@ -31034,6 +31041,7 @@ > BCBB8AB913F1AFB000734DF0 /* PODInterval.h in Headers */, > BCBB8ABA13F1AFB000734DF0 /* PODIntervalTree.h in Headers */, > BCBB8ABB13F1AFB000734DF0 /* PODRedBlackTree.h in Headers */, >+ 71B5AB2621F1D9F400376E5C /* PointerCaptureController.h in Headers */, > 317D3FF3215599F40034E3B9 /* PointerEvent.h in Headers */, > B2B1F7170D00CAA8004AEA64 /* PointerEventsHitRules.h in Headers */, > 3FF813A71DBA8640009BF001 /* PointerLockController.h in Headers */, >@@ -31464,7 +31472,6 @@ > 51405C89190B014400754F94 /* SelectionRectGatherer.h in Headers */, > E44B4BB4141650D7002B1D8B /* SelectorChecker.h in Headers */, > 432D3FE818A8658400D7DC03 /* SelectorCheckerTestFunctions.h in Headers */, >- 29AE213521ABA48A00869283 /* AXIsolatedTreeNode.h in Headers */, > 26B999971804D54200D01121 /* SelectorCompiler.h in Headers */, > 415071581685067300C3C7B3 /* SelectorFilter.h in Headers */, > 43107BE218CC19DE00CC18E8 /* SelectorPseudoTypeMap.h in Headers */, >@@ -32400,7 +32407,6 @@ > 977E2E0F12F0FC9C00C13380 /* XSSAuditorDelegate.h in Headers */, > A5416FE618810EF80009FC5F /* YouTubeEmbedShadowElement.h in Headers */, > 7A5515F5191830A3009687D2 /* YouTubePluginReplacement.h in Headers */, >- 29AE212D21AB9EEB00869283 /* AXIsolatedTree.h in Headers */, > FD537353137B651800008DCE /* ZeroPole.h in Headers */, > ); > runOnlyForDeploymentPostprocessing = 0; >diff --git a/Source/WebCore/dom/Element.cpp b/Source/WebCore/dom/Element.cpp >index 16645850d7cbfd8da3caba2e041a2172379c0c56..c3c23b1cdf715d3d5496ef48d59d73064fe5bd42 100644 >--- a/Source/WebCore/dom/Element.cpp >+++ b/Source/WebCore/dom/Element.cpp >@@ -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 @@ void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(boo > } > #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() > { >diff --git a/Source/WebCore/dom/Element.h b/Source/WebCore/dom/Element.h >index 6ae16185e9ac471854a9349d741dd464a11f4e53..a2599ada87d216034d75925cd31cc5fc50ee6aeb 100644 >--- a/Source/WebCore/dom/Element.h >+++ b/Source/WebCore/dom/Element.h >@@ -497,6 +497,12 @@ public: > 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 >diff --git a/Source/WebCore/dom/Element.idl b/Source/WebCore/dom/Element.idl >index 77894f7c976c4b35c597707e07ab80642143bcc3..3ea4c7d80519a031cda9a50ad69701c7991e0ce4 100644 >--- a/Source/WebCore/dom/Element.idl >+++ b/Source/WebCore/dom/Element.idl >@@ -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(); > >diff --git a/Source/WebCore/dom/EventNames.h b/Source/WebCore/dom/EventNames.h >index 3f88b750effb049985b4d1750ae7dbf6e4803066..463ed4364c6887635f3c373fbbdfa55de0f36841 100644 >--- a/Source/WebCore/dom/EventNames.h >+++ b/Source/WebCore/dom/EventNames.h >@@ -140,6 +140,7 @@ namespace WebCore { > macro(gesturestart) \ > macro(gesturetap) \ > macro(gesturetapdown) \ >+ macro(gotpointercapture) \ > macro(hashchange) \ > macro(icecandidate) \ > macro(iceconnectionstatechange) \ >@@ -162,6 +163,7 @@ namespace WebCore { > macro(loadingdone) \ > macro(loadingerror) \ > macro(loadstart) \ >+ macro(lostpointercapture) \ > macro(mark) \ > macro(merchantvalidation) \ > macro(message) \ >diff --git a/Source/WebCore/dom/PointerEvent.h b/Source/WebCore/dom/PointerEvent.h >index bdaee5eaebf2e84d77d529587659bb9c00ce066b..25059af033335200318b200e8c097e4d7e4e3c29 100644 >--- a/Source/WebCore/dom/PointerEvent.h >+++ b/Source/WebCore/dom/PointerEvent.h >@@ -39,7 +39,7 @@ namespace WebCore { > 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 @@ public: > 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 @@ public: > > 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 @@ private: > 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 }; >diff --git a/Source/WebCore/page/Page.cpp b/Source/WebCore/page/Page.cpp >index 26a25819c1a7741d12cd964629ad15979986d0d0..fd66607dcddc40edb928d3063e8d29909c04904c 100644 >--- a/Source/WebCore/page/Page.cpp >+++ b/Source/WebCore/page/Page.cpp >@@ -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 @@ Page::Page(PageConfiguration&& pageConfiguration) > #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 >diff --git a/Source/WebCore/page/Page.h b/Source/WebCore/page/Page.h >index 7f7b370bcae98ab957db4c50176dec29b7b4f926..335d6a05fcbc14dc26ad70ef6493bd4b77aa32e2 100644 >--- a/Source/WebCore/page/Page.h >+++ b/Source/WebCore/page/Page.h >@@ -122,6 +122,7 @@ class PlugInClient; > class PluginData; > class PluginInfoProvider; > class PluginViewBase; >+class PointerCaptureController; > class PointerLockController; > class ProgressTracker; > class ProgressTrackerClient; >@@ -244,6 +245,9 @@ public: > #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 @@ private: > #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 >diff --git a/Source/WebCore/page/PointerCaptureController.cpp b/Source/WebCore/page/PointerCaptureController.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..eb97dd2b57826126e27949806a135f2a251aa68c >--- /dev/null >+++ b/Source/WebCore/page/PointerCaptureController.cpp >@@ -0,0 +1,206 @@ >+/* >+ * 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() >+{ >+} >+ >+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 ([DOM4]), 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 ([PointerLock]), 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::touchEndedOrWasCanceledForIdentifier(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 ([DOM4]), 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. >+ if (capturingData.pendingTargetOverride) >+ capturingData.targetOverride = capturingData.pendingTargetOverride; >+ else >+ capturingData.targetOverride = nullptr; >+} >+ >+} // namespace WebCore >+ >+#endif // ENABLE(POINTER_EVENTS) >diff --git a/Source/WebCore/page/PointerCaptureController.h b/Source/WebCore/page/PointerCaptureController.h >new file mode 100644 >index 0000000000000000000000000000000000000000..58fdce2d64092c15b99cf6c2def6c97d4dacd80f >--- /dev/null >+++ b/Source/WebCore/page/PointerCaptureController.h >@@ -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 = ImplicitCapture::No); >+ bool hasPointerCapture(Element*, int32_t); >+ >+ void pointerLockWasApplied(); >+ >+ void touchEndedOrWasCanceledForIdentifier(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) >diff --git a/Source/WebCore/page/PointerLockController.cpp b/Source/WebCore/page/PointerLockController.cpp >index cfae41b51afe54d4daa56853b75d02c55e05a21d..6580f23b7d9bbe6ebf6eac3962d3f65c7f8a7987 100644 >--- a/Source/WebCore/page/PointerLockController.cpp >+++ b/Source/WebCore/page/PointerLockController.cpp >@@ -71,6 +71,9 @@ void PointerLockController::requestPointerLock(Element* target) > } > m_element = target; > enqueueEvent(eventNames().pointerlockchangeEvent, target); >+#if ENABLE(POINTER_EVENTS) >+ m_page.pointerCaptureController().pointerLockWasApplied(); >+#endif > } else { > m_lockPending = true; > m_element = target; >diff --git a/Source/WebCore/page/PointerLockController.h b/Source/WebCore/page/PointerLockController.h >index 49097ae59dfac2109cd25a57330f968579789976..5077465fb5456dfbf286a00313429e891a87febb 100644 >--- a/Source/WebCore/page/PointerLockController.h >+++ b/Source/WebCore/page/PointerLockController.h >@@ -27,6 +27,7 @@ > #if ENABLE(POINTER_LOCK) > > #include <wtf/RefPtr.h> >+#include <wtf/WeakPtr.h> > #include <wtf/text/AtomicString.h> > > namespace WebCore { >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index c38cf4171388bb0ac41ab7420bd324ae874be9b7..2f11219030cb0ad9b791e5ad8fc0d752fcbf8327 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,24 @@ >+2019-01-28 Antoine Quint <graouts@apple.com> >+ >+ Implement capture for Pointer Events on iOS >+ https://bugs.webkit.org/show_bug.cgi?id=193917 >+ <rdar://problem/47605689> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ 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 <dino@apple.com> > > Produce "pen" Pointer Events if using a stylus (e.g. Apple Pencil) >diff --git a/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-expected.txt b/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..8922b28e876ce3d7bbd26b748ab25956353fe472 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-expected.txt >@@ -0,0 +1,3 @@ >+ >+PASS Pointer events for a direct manipulation device trigger 'gotpointercapture' and 'lostpointercapture' events due to implicit capture. >+ >diff --git a/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-has-pointer-capture-in-pointer-down-expected.txt b/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-has-pointer-capture-in-pointer-down-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..b42ff7337bfbdf3ccf5b44e61e37010f77614bfd >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-has-pointer-capture-in-pointer-down-expected.txt >@@ -0,0 +1,3 @@ >+ >+PASS Calling hasPointerCapture() in the 'pointerdown' event handler returns true for direct manipulation devices. >+ >diff --git a/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-has-pointer-capture-in-pointer-down.html b/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-has-pointer-capture-in-pointer-down.html >new file mode 100644 >index 0000000000000000000000000000000000000000..3587115d7eecbee09a4944d4fd7bc9247b98c743 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-has-pointer-capture-in-pointer-down.html >@@ -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="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+<script src="../utils.js"></script> >+<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 >diff --git a/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-exception-expected.txt b/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-exception-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..a4ccb78823d7c330da31a299e25071d500ddd342 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-exception-expected.txt >@@ -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. >+ >diff --git a/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-exception.html b/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-exception.html >new file mode 100644 >index 0000000000000000000000000000000000000000..8c9d1ec9870a16a65f9f52d2b27affdeb4e5c521 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-exception.html >@@ -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="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+<script src="../utils.js"></script> >+<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 >diff --git a/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-expected.txt b/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..46414472482999f5dd516333b593df4621d969ce >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release-expected.txt >@@ -0,0 +1,3 @@ >+ >+PASS Calling releasePointerCapture() in the 'pointerdown' event handler makes hasPointerCapture() return false. >+ >diff --git a/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release.html b/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release.html >new file mode 100644 >index 0000000000000000000000000000000000000000..0f3b673cf21f9c06b289bd9ac8d6dcf0ae0d1dec >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/pointer-events-implicit-capture-release.html >@@ -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="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+<script src="../utils.js"></script> >+<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 >diff --git a/LayoutTests/pointerevents/ios/pointer-events-implicit-capture.html b/LayoutTests/pointerevents/ios/pointer-events-implicit-capture.html >new file mode 100644 >index 0000000000000000000000000000000000000000..c1d08dc29463dc311cc3fee6d2e9016b0988305f >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/pointer-events-implicit-capture.html >@@ -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="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+<script src="../utils.js"></script> >+<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 >diff --git a/LayoutTests/pointerevents/ios/pointer-events-set-pointer-capture-exceptions-expected.txt b/LayoutTests/pointerevents/ios/pointer-events-set-pointer-capture-exceptions-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..a53ec750d44d6d6ab275b3a834dd1da3a08e1371 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/pointer-events-set-pointer-capture-exceptions-expected.txt >@@ -0,0 +1,3 @@ >+ >+PASS The setPointerCapture() method can throw. >+ >diff --git a/LayoutTests/pointerevents/ios/pointer-events-set-pointer-capture-exceptions.html b/LayoutTests/pointerevents/ios/pointer-events-set-pointer-capture-exceptions.html >new file mode 100644 >index 0000000000000000000000000000000000000000..e39749152662d27256500209e88560b56b9e05e1 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/pointer-events-set-pointer-capture-exceptions.html >@@ -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="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+<script src="../utils.js"></script> >+<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
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 193917
:
360413
|
360414