Implement basic pointer lock behavior for WebKit and WebKit2.
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 21 Oct 2016 18:45:39 +0000 (18:45 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 21 Oct 2016 18:45:39 +0000 (18:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=162745

Patch by Jeremy Jones <jeremyj@apple.com> on 2016-10-21
Reviewed by Simon Fraser.

Source/WebCore:

When ENABLE_POINTER_LOCK is enabled, these tests now pass with DumpRenderTree.
LayoutTests/pointer-lock/lock-already-locked.html
LayoutTests/pointer-lock/lock-element-not-in-dom.html
LayoutTests/pointer-lock/locked-element-iframe-removed-from-dom.html
LayoutTests/pointer-lock/mouse-event-api.html

Export pointer lock symbols and cancel pointer lock on "escape".

* dom/Document.h: Export symbols.
* dom/Element.h: Export symbols.
* page/EventHandler.cpp:
(WebCore::EventHandler::keyEvent): Cancel pointer lock on "escape".
* page/PointerLockController.cpp: Add missing include.
* page/PointerLockController.h: Export symbols.

Source/WebKit/mac:

Add basic pointer lock functionality. User permission is not yet implemented.

* WebCoreSupport/WebChromeClient.h:
* WebCoreSupport/WebChromeClient.mm:
(WebChromeClient::requestPointerLock):
(WebChromeClient::requestPointerUnlock):

Source/WebKit2:

Enable basic pointer lock functionality by plumbing requests through WebPage IPC.
Pass through mouse movement deltas.
Unlock pointer when view is no longer visible.

* Shared/WebEventConversion.cpp:
(WebKit::WebKit2PlatformMouseEvent::WebKit2PlatformMouseEvent): Pass along mouse movement.
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::dispatchViewStateChange): Unlock pointer when page is not visible.
(WebKit::WebPageProxy::requestPointerLock): Hide and disassociate pointer.
(WebKit::WebPageProxy::requestPointerUnlock): Show and associate pointer.
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in: Add methods.
* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::requestPointerLock): Pass along to web page.
(WebKit::WebChromeClient::requestPointerUnlock): Ditto.
* WebProcess/WebCoreSupport/WebChromeClient.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::didAcquirePointerLock): Forward to PointerLockController.
(WebKit::WebPage::didNotAcquirePointerLock): Ditto.
(WebKit::WebPage::didLosePointerLock): Ditto.
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in: Add methods.

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

21 files changed:
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/dom/Document.h
Source/WebCore/dom/Element.h
Source/WebCore/page/ChromeClient.h
Source/WebCore/page/EventHandler.cpp
Source/WebCore/page/PointerLockController.cpp
Source/WebCore/page/PointerLockController.h
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/WebCoreSupport/WebChromeClient.h
Source/WebKit/mac/WebCoreSupport/WebChromeClient.mm
Source/WebKit2/ChangeLog
Source/WebKit2/Shared/WebEventConversion.cpp
Source/WebKit2/UIProcess/WebPageProxy.cpp
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/UIProcess/WebPageProxy.messages.in
Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.cpp
Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.h
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Source/WebKit2/WebProcess/WebPage/WebPage.h
Source/WebKit2/WebProcess/WebPage/WebPage.messages.in

index 53b2eca..04f4b07 100644 (file)
@@ -1,3 +1,25 @@
+2016-10-21  Jeremy Jones  <jeremyj@apple.com>
+
+        Implement basic pointer lock behavior for WebKit and WebKit2.
+        https://bugs.webkit.org/show_bug.cgi?id=162745
+
+        Reviewed by Simon Fraser.
+
+        When ENABLE_POINTER_LOCK is enabled, these tests now pass with DumpRenderTree.
+        LayoutTests/pointer-lock/lock-already-locked.html
+        LayoutTests/pointer-lock/lock-element-not-in-dom.html
+        LayoutTests/pointer-lock/locked-element-iframe-removed-from-dom.html
+        LayoutTests/pointer-lock/mouse-event-api.html
+
+        Export pointer lock symbols and cancel pointer lock on "escape".
+
+        * dom/Document.h: Export symbols.
+        * dom/Element.h: Export symbols.
+        * page/EventHandler.cpp:
+        (WebCore::EventHandler::keyEvent): Cancel pointer lock on "escape".
+        * page/PointerLockController.cpp: Add missing include.
+        * page/PointerLockController.h: Export symbols.
+
 2016-10-21  Jer Noble  <jer.noble@apple.com>
 
         WebCore::PlatformMediaSession::stopSession + 13
index 2340a0e..c875ad0 100644 (file)
                3F42B31E1881191B00278AAC /* WebVideoFullscreenControllerAVKit.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3F42B31C1881191B00278AAC /* WebVideoFullscreenControllerAVKit.mm */; };
                3FBC4AF3189881560046EE38 /* WebVideoFullscreenInterfaceAVKit.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3FBC4AF1189881560046EE38 /* WebVideoFullscreenInterfaceAVKit.mm */; };
                3FBC4AF4189881560046EE38 /* WebVideoFullscreenInterfaceAVKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FBC4AF2189881560046EE38 /* WebVideoFullscreenInterfaceAVKit.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               3FF813A71DBA8640009BF001 /* PointerLockController.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CFC434F192406A900A0D3B5 /* PointerLockController.h */; settings = {ATTRIBUTES = (Private, ); }; };
                3FFFF9A8159D9A550020BBD5 /* WebKitCSSViewportRule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3FFFF9A6159D9A550020BBD5 /* WebKitCSSViewportRule.cpp */; };
                3FFFF9A9159D9A550020BBD5 /* WebKitCSSViewportRule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FFFF9A7159D9A550020BBD5 /* WebKitCSSViewportRule.h */; };
                3FFFF9AD159D9B060020BBD5 /* ViewportStyleResolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3FFFF9AB159D9B060020BBD5 /* ViewportStyleResolver.cpp */; };
                                BCBB8ABA13F1AFB000734DF0 /* PODIntervalTree.h in Headers */,
                                BCBB8ABB13F1AFB000734DF0 /* PODRedBlackTree.h in Headers */,
                                B2B1F7170D00CAA8004AEA64 /* PointerEventsHitRules.h in Headers */,
+                               3FF813A71DBA8640009BF001 /* PointerLockController.h in Headers */,
                                84730D921248F0B300D3A9C9 /* PointLightSource.h in Headers */,
                                97059978107D975200A50A7C /* PolicyCallback.h in Headers */,
                                9705997A107D975200A50A7C /* PolicyChecker.h in Headers */,
index 2ad23ee..c732298 100644 (file)
@@ -1123,8 +1123,8 @@ public:
 #endif
 
 #if ENABLE(POINTER_LOCK)
-    void exitPointerLock();
-    Element* pointerLockElement() const;
+    WEBCORE_EXPORT void exitPointerLock();
+    WEBCORE_EXPORT Element* pointerLockElement() const;
 #endif
 
     // Used to allow element that loads data without going through a FrameLoader to delay the 'load' event.
index 0b0f1f7..c6e5899 100644 (file)
@@ -477,7 +477,7 @@ public:
 #endif
 
 #if ENABLE(POINTER_LOCK)
-    void requestPointerLock();
+    WEBCORE_EXPORT void requestPointerLock();
 #endif
 
 #if ENABLE(INDIE_UI)
index f4834bb..8590d94 100644 (file)
@@ -405,7 +405,6 @@ public:
 #if ENABLE(POINTER_LOCK)
     virtual bool requestPointerLock() { return false; }
     virtual void requestPointerUnlock() { }
-    virtual bool isPointerLocked() { return false; }
 #endif
 
     virtual FloatSize minimumWindowSize() const { return FloatSize(100, 100); };
index 71c194d..4d39959 100644 (file)
@@ -73,6 +73,7 @@
 #include "PlatformKeyboardEvent.h"
 #include "PlatformWheelEvent.h"
 #include "PluginDocument.h"
+#include "PointerLockController.h"
 #include "RenderFrameSet.h"
 #include "RenderLayer.h"
 #include "RenderListBox.h"
@@ -3062,6 +3063,13 @@ bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
 
     LOG(Editing, "EventHandler %p keyEvent (text %s keyIdentifier %s)", this, initialKeyEvent.text().utf8().data(), initialKeyEvent.keyIdentifier().utf8().data());
 
+#if ENABLE(POINTER_LOCK)
+    if (initialKeyEvent.type() == PlatformEvent::KeyDown && initialKeyEvent.windowsVirtualKeyCode() == VK_ESCAPE && m_frame.page()->pointerLockController().element()) {
+        m_frame.page()->pointerLockController().requestPointerUnlock();
+        return true;
+    }
+#endif
+
 #if ENABLE(FULLSCREEN_API)
     if (m_frame.document()->webkitIsFullScreen() && !isKeyEventAllowedInFullScreen(initialKeyEvent))
         return false;
index 897a415..98655e6 100644 (file)
@@ -31,6 +31,7 @@
 #include "ChromeClient.h"
 #include "Element.h"
 #include "Event.h"
+#include "EventNames.h"
 #include "Page.h"
 #include "PlatformMouseEvent.h"
 #include "VoidCallback.h"
@@ -63,13 +64,17 @@ void PointerLockController::requestPointerLock(Element* target)
             enqueueEvent(eventNames().pointerlockerrorEvent, target);
             return;
         }
-        enqueueEvent(eventNames().pointerlockchangeEvent, target);
         m_element = target;
-    } else if (m_page.chrome().client().requestPointerLock()) {
+        enqueueEvent(eventNames().pointerlockchangeEvent, target);
+    } else {
         m_lockPending = true;
         m_element = target;
-    } else
-        enqueueEvent(eventNames().pointerlockerrorEvent, target);
+        if (!m_page.chrome().client().requestPointerLock()) {
+            m_element = nullptr;
+            m_lockPending = false;
+            enqueueEvent(eventNames().pointerlockerrorEvent, target);
+        }
+    }
 }
 
 void PointerLockController::requestPointerUnlock()
index 762851b..5d0fe1c 100644 (file)
@@ -50,9 +50,9 @@ public:
     bool lockPending() const;
     Element* element() const;
 
-    void didAcquirePointerLock();
-    void didNotAcquirePointerLock();
-    void didLosePointerLock();
+    WEBCORE_EXPORT void didAcquirePointerLock();
+    WEBCORE_EXPORT void didNotAcquirePointerLock();
+    WEBCORE_EXPORT void didLosePointerLock();
     void dispatchLockedMouseEvent(const PlatformMouseEvent&, const AtomicString& eventType);
 
 private:
index f60b630..6a6ee4c 100644 (file)
@@ -1,3 +1,17 @@
+2016-10-21  Jeremy Jones  <jeremyj@apple.com>
+
+        Implement basic pointer lock behavior for WebKit and WebKit2.
+        https://bugs.webkit.org/show_bug.cgi?id=162745
+
+        Reviewed by Simon Fraser.
+
+        Add basic pointer lock functionality. User permission is not yet implemented.
+
+        * WebCoreSupport/WebChromeClient.h:
+        * WebCoreSupport/WebChromeClient.mm:
+        (WebChromeClient::requestPointerLock):
+        (WebChromeClient::requestPointerUnlock):
+
 2016-10-19  Myles C. Maxfield  <mmaxfield@apple.com>
 
         [macOS] [iOS] Disable variation fonts on macOS El Capitan and iOS 9
index 9f0f881..c101924 100644 (file)
@@ -135,6 +135,11 @@ public:
 #if ENABLE(INPUT_TYPE_COLOR)
     std::unique_ptr<WebCore::ColorChooser> createColorChooser(WebCore::ColorChooserClient*, const WebCore::Color&) override;
 #endif
+    
+#if ENABLE(POINTER_LOCK)
+    bool requestPointerLock() override;
+    void requestPointerUnlock() override;
+#endif
 
     WebCore::KeyboardUIMode keyboardUIMode() override;
 
index 8c30ccd..bf9af55 100644 (file)
@@ -77,6 +77,7 @@
 #import <WebCore/NotImplemented.h>
 #import <WebCore/Page.h>
 #import <WebCore/PlatformScreen.h>
+#import <WebCore/PointerLockController.h>
 #import <WebCore/ResourceRequest.h>
 #import <WebCore/SerializedCryptoKeyWrap.h>
 #import <WebCore/Widget.h>
@@ -709,6 +710,34 @@ std::unique_ptr<ColorChooser> WebChromeClient::createColorChooser(ColorChooserCl
 }
 #endif
 
+#if ENABLE(POINTER_LOCK)
+bool WebChromeClient::requestPointerLock()
+{
+#if PLATFORM(MAC)
+    if (![m_webView page])
+        return false;
+
+    CGDisplayHideCursor(CGMainDisplayID());
+    CGAssociateMouseAndMouseCursorPosition(false);
+    [m_webView page]->pointerLockController().didAcquirePointerLock();
+    
+    return true;
+#else
+    return false;
+#endif
+}
+
+void WebChromeClient::requestPointerUnlock()
+{
+#if PLATFORM(MAC)
+    CGDisplayShowCursor(CGMainDisplayID());
+    CGAssociateMouseAndMouseCursorPosition(true);
+    if ([m_webView page])
+        [m_webView page]->pointerLockController().didLosePointerLock();
+#endif
+}
+#endif
+
 void WebChromeClient::runOpenPanel(Frame*, PassRefPtr<FileChooser> chooser)
 {
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
index eadb0fc..277c980 100644 (file)
@@ -1,3 +1,33 @@
+2016-10-21  Jeremy Jones  <jeremyj@apple.com>
+
+        Implement basic pointer lock behavior for WebKit and WebKit2.
+        https://bugs.webkit.org/show_bug.cgi?id=162745
+
+        Reviewed by Simon Fraser.
+
+        Enable basic pointer lock functionality by plumbing requests through WebPage IPC.
+        Pass through mouse movement deltas.
+        Unlock pointer when view is no longer visible.
+
+        * Shared/WebEventConversion.cpp:
+        (WebKit::WebKit2PlatformMouseEvent::WebKit2PlatformMouseEvent): Pass along mouse movement.
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::dispatchViewStateChange): Unlock pointer when page is not visible.
+        (WebKit::WebPageProxy::requestPointerLock): Hide and disassociate pointer.
+        (WebKit::WebPageProxy::requestPointerUnlock): Show and associate pointer.
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in: Add methods.
+        * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+        (WebKit::WebChromeClient::requestPointerLock): Pass along to web page.
+        (WebKit::WebChromeClient::requestPointerUnlock): Ditto.
+        * WebProcess/WebCoreSupport/WebChromeClient.h:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::didAcquirePointerLock): Forward to PointerLockController.
+        (WebKit::WebPage::didNotAcquirePointerLock): Ditto.
+        (WebKit::WebPage::didLosePointerLock): Ditto.
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in: Add methods.
+
 2016-10-21  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         Implement InputEvent.getTargetRanges() for the input events spec
index 06bf37a..289dac6 100644 (file)
@@ -100,6 +100,9 @@ public:
         }
 
         m_position = webEvent.position();
+#if ENABLE(POINTER_LOCK)
+        m_movementDelta = WebCore::IntPoint(webEvent.deltaX(), webEvent.deltaY());
+#endif
         m_globalPosition = webEvent.globalPosition();
         m_clickCount = webEvent.clickCount();
 #if PLATFORM(MAC)
index f9c374c..36f6014 100644 (file)
@@ -1549,6 +1549,11 @@ void WebPageProxy::dispatchViewStateChange()
     if ((changed & ViewState::IsVisible) && !isViewVisible())
         m_process->responsivenessTimer().stop();
 
+#if ENABLE(POINTER_LOCK)
+    if ((changed & ViewState::IsVisible) && !isViewVisible())
+        requestPointerUnlock();
+#endif
+
     if (changed & ViewState::IsInWindow) {
         if (isInWindow())
             viewDidEnterWindow();
@@ -6620,5 +6625,37 @@ void WebPageProxy::setUserInterfaceLayoutDirection(WebCore::UserInterfaceLayoutD
 
     m_process->send(Messages::WebPage::SetUserInterfaceLayoutDirection(static_cast<uint32_t>(userInterfaceLayoutDirection)), m_pageID);
 }
+    
+#if ENABLE(POINTER_LOCK)
+void WebPageProxy::requestPointerLock()
+{
+    if (!isViewVisible()) {
+        m_process->send(Messages::WebPage::DidNotAcquirePointerLock(), m_pageID);
+        return;
+    }
+
+    didAllowPointerLock();
+}
+    
+void WebPageProxy::didAllowPointerLock()
+{
+    CGDisplayHideCursor(CGMainDisplayID());
+    CGAssociateMouseAndMouseCursorPosition(false);
+    m_process->send(Messages::WebPage::DidAcquirePointerLock(), m_pageID);
+}
+    
+void WebPageProxy::didDenyPointerLock()
+{
+    m_process->send(Messages::WebPage::DidNotAcquirePointerLock(), m_pageID);
+}
+
+void WebPageProxy::requestPointerUnlock()
+{
+    CGDisplayShowCursor(CGMainDisplayID());
+    CGAssociateMouseAndMouseCursorPosition(true);
+    m_process->send(Messages::WebPage::DidLosePointerLock(), m_pageID);
+}
+#endif
+
 
 } // namespace WebKit
index 176b9e0..07ae419 100644 (file)
@@ -946,6 +946,11 @@ public:
     void handleMediaEvent(WebCore::MediaEventType);
     void setVolumeOfMediaElement(double, uint64_t);
 #endif
+        
+#if ENABLE(POINTER_LOCK)
+    void didAllowPointerLock();
+    void didDenyPointerLock();
+#endif
 
     // WebPopupMenuProxy::Client
     NativeWebMouseEvent* currentlyProcessedMouseDownEvent() override;
@@ -1168,6 +1173,11 @@ private:
     void failedToShowPopupMenu() override;
 #endif
 
+#if ENABLE(POINTER_LOCK)
+    void requestPointerLock();
+    void requestPointerUnlock();
+#endif
+
     void didCreateMainFrame(uint64_t frameID);
     void didCreateSubframe(uint64_t frameID);
 
index cef42e6..0e3b6e4 100644 (file)
@@ -458,6 +458,11 @@ messages -> WebPageProxy {
     SetMockMediaPlaybackTargetPickerState(String name, unsigned pickerState)
 #endif
 
+#if ENABLE(POINTER_LOCK)
+    RequestPointerLock()
+    RequestPointerUnlock()
+#endif
+
     ImageOrMediaDocumentSizeChanged(WebCore::IntSize newSize)
 
     UseFixedLayoutDidChange(bool useFixedLayout)
index bdaf90a..8c78d4f 100644 (file)
@@ -455,6 +455,19 @@ KeyboardUIMode WebChromeClient::keyboardUIMode()
     return m_page->keyboardUIMode();
 }
 
+#if ENABLE(POINTER_LOCK)
+bool WebChromeClient::requestPointerLock()
+{
+    m_page->send(Messages::WebPageProxy::RequestPointerLock());
+    return true;
+}
+
+void WebChromeClient::requestPointerUnlock()
+{
+    m_page->send(Messages::WebPageProxy::RequestPointerUnlock());
+}
+#endif
+
 void WebChromeClient::invalidateRootView(const IntRect&)
 {
     // Do nothing here, there's no concept of invalidating the window in the web process.
index 3ac9fd3..47e0866 100644 (file)
@@ -191,6 +191,11 @@ private:
 #if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER)
     void scheduleAnimation() override;
 #endif
+    
+#if ENABLE(POINTER_LOCK)
+    bool requestPointerLock() override;
+    void requestPointerUnlock() override;
+#endif
 
     void didAssociateFormControls(const Vector<RefPtr<WebCore::Element>>&) override;
     bool shouldNotifyOnFormChanges() override;
index 88634e0..212f14a 100644 (file)
 #include <WebCore/PageThrottler.h>
 #include <WebCore/PlatformKeyboardEvent.h>
 #include <WebCore/PluginDocument.h>
+#include <WebCore/PointerLockController.h>
 #include <WebCore/PrintContext.h>
 #include <WebCore/Range.h>
 #include <WebCore/RenderLayer.h>
@@ -5613,4 +5614,21 @@ void WebPage::gamepadActivity(const Vector<GamepadData>& gamepadDatas)
 
 #endif
 
+#if ENABLE(POINTER_LOCK)
+void WebPage::didAcquirePointerLock()
+{
+    corePage()->pointerLockController().didAcquirePointerLock();
+}
+
+void WebPage::didNotAcquirePointerLock()
+{
+    corePage()->pointerLockController().didNotAcquirePointerLock();
+}
+
+void WebPage::didLosePointerLock()
+{
+    corePage()->pointerLockController().didLosePointerLock();
+}
+#endif
+
 } // namespace WebKit
index 2d56dca..dcd59de 100644 (file)
@@ -961,6 +961,12 @@ public:
 #if ENABLE(GAMEPAD)
     void gamepadActivity(const Vector<GamepadData>&);
 #endif
+    
+#if ENABLE(POINTER_LOCK)
+    void didAcquirePointerLock();
+    void didNotAcquirePointerLock();
+    void didLosePointerLock();
+#endif
 
 private:
     WebPage(uint64_t pageID, const WebPageCreationParameters&);
index 71239e6..727eb79 100644 (file)
@@ -428,6 +428,12 @@ messages -> WebPage LegacyReceiver {
     SetShouldPlayToPlaybackTarget(uint64_t contextId, bool shouldPlay)
 #endif
 
+#if ENABLE(POINTER_LOCK)
+    DidAcquirePointerLock()
+    DidNotAcquirePointerLock()
+    DidLosePointerLock()
+#endif
+
     ClearWheelEventTestTrigger()
     SetShouldScaleViewToFitDocument(bool shouldScaleViewToFitDocument)