Web Replay: route through UserInputBridge when delivering user inputs to WebCore
authorbburg@apple.com <bburg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 26 Feb 2014 21:41:30 +0000 (21:41 +0000)
committerbburg@apple.com <bburg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 26 Feb 2014 21:41:30 +0000 (21:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=128150

Reviewed by Timothy Hatcher.

Source/WebCore:

Add an UserInputBridge instance to each Page. WebKit2 routes a page's user inputs through
the WebCore page's user input bridge so that the inputs can be selectively captured, filtered,
and replayed using instrumentation inside the UserInputBridge.

For now, the routing methods of UserInputBridge have no replay-specific code paths, and just
put the input delivery code inside WebCore rather than its external clients. Replay-specific
code paths will be added once https://bugs.webkit.org/show_bug.cgi?id=128782 is fixed. However,
once complete the code will work as follows:

- When neither capturing or replaying, behavior is unchanged.

- When capturing user inputs, each external input is saved into a replay log as it crosses
the bridge from outside WebCore.

- When replaying, the bridge closes and user inputs from WebKit2 are not accepted. Instead,
the saved inputs from the replay log are re-dispatched as if they had crossed the bridge.

* CMakeLists.txt:
* GNUmakefile.am:
* GNUmakefile.list.am:
* WebCore.exp.in: Add symbols for input routing methods.
* WebCore.vcxproj/WebCore.vcxproj:
* WebCore.vcxproj/WebCore.vcxproj.filters:
* WebCore.xcodeproj/project.pbxproj:
* page/Page.cpp:
(WebCore::Page::Page): Initialize the owned UserInputBridge in the Page constructor.
* page/Page.h:
(WebCore::Page::inputBridge): Added a by-reference getter.
* replay/UserInputBridge.cpp: Added.
(WebCore::UserInputBridge::UserInputBridge):
(WebCore::UserInputBridge::~UserInputBridge):
(WebCore::UserInputBridge::handleContextMenuEvent):
(WebCore::UserInputBridge::handleMousePressEvent):
(WebCore::UserInputBridge::handleMouseReleaseEvent):
(WebCore::UserInputBridge::handleMouseMoveEvent):
(WebCore::UserInputBridge::handleMouseMoveOnScrollbarEvent):
(WebCore::UserInputBridge::handleKeyEvent):
(WebCore::UserInputBridge::handleAccessKeyEvent):
(WebCore::UserInputBridge::handleWheelEvent):
(WebCore::UserInputBridge::focusSetActive):
(WebCore::UserInputBridge::focusSetFocused):
(WebCore::UserInputBridge::scrollRecursively):
(WebCore::UserInputBridge::logicalScrollRecursively):
(WebCore::UserInputBridge::loadRequest):
(WebCore::UserInputBridge::reloadFrame):
(WebCore::UserInputBridge::stopLoadingFrame):
(WebCore::UserInputBridge::tryClosePage):
* replay/UserInputBridge.h: Added.

Source/WebKit2:

When delivering user inputs to WebCore, route calls through the page's UserInputBridge.
This allows us to capture and replay user inputs from WebKit2 solely within WebCore.

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::tryClose):
(WebKit::WebPage::loadRequest):
(WebKit::WebPage::stopLoadingFrame):
(WebKit::WebPage::stopLoading):
(WebKit::WebPage::reload):
(WebKit::WebPage::contextMenuAtPointInWindow):
(WebKit::handleContextMenuEvent):
(WebKit::handleMouseEvent):
(WebKit::handleWheelEvent):
(WebKit::handleKeyEvent):
(WebKit::WebPage::scroll):
(WebKit::WebPage::logicalScroll):

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

15 files changed:
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.am
Source/WebCore/GNUmakefile.list.am
Source/WebCore/WebCore.exp.in
Source/WebCore/WebCore.order
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/page/Page.cpp
Source/WebCore/page/Page.h
Source/WebCore/replay/UserInputBridge.cpp [new file with mode: 0644]
Source/WebCore/replay/UserInputBridge.h [new file with mode: 0644]
Source/WebKit2/ChangeLog
Source/WebKit2/WebProcess/WebPage/WebPage.cpp

index 7355b54..82271cd 100644 (file)
@@ -86,6 +86,7 @@ set(WebCore_INCLUDE_DIRECTORIES
     "${WEBCORE_DIR}/rendering/shapes"
     "${WEBCORE_DIR}/rendering/style"
     "${WEBCORE_DIR}/rendering/svg"
+    "${WEBCORE_DIR}/replay"
     "${WEBCORE_DIR}/storage"
     "${WEBCORE_DIR}/style"
     "${WEBCORE_DIR}/svg"
@@ -2297,6 +2298,8 @@ set(WebCore_SOURCES
     rendering/svg/SVGTextQuery.cpp
     rendering/svg/SVGTextRunRenderingContext.cpp
 
+    replay/UserInputBridge.cpp
+
     storage/Storage.cpp
     storage/StorageAreaImpl.cpp
     storage/StorageAreaSync.cpp
index 695ff33..3428679 100644 (file)
@@ -1,3 +1,59 @@
+2014-02-26  Brian Burg  <bburg@apple.com>
+
+        Web Replay: route through UserInputBridge when delivering user inputs to WebCore
+        https://bugs.webkit.org/show_bug.cgi?id=128150
+
+        Reviewed by Timothy Hatcher.
+
+        Add an UserInputBridge instance to each Page. WebKit2 routes a page's user inputs through
+        the WebCore page's user input bridge so that the inputs can be selectively captured, filtered,
+        and replayed using instrumentation inside the UserInputBridge.
+
+        For now, the routing methods of UserInputBridge have no replay-specific code paths, and just
+        put the input delivery code inside WebCore rather than its external clients. Replay-specific
+        code paths will be added once https://bugs.webkit.org/show_bug.cgi?id=128782 is fixed. However,
+        once complete the code will work as follows:
+
+        - When neither capturing or replaying, behavior is unchanged.
+
+        - When capturing user inputs, each external input is saved into a replay log as it crosses
+        the bridge from outside WebCore.
+
+        - When replaying, the bridge closes and user inputs from WebKit2 are not accepted. Instead,
+        the saved inputs from the replay log are re-dispatched as if they had crossed the bridge.
+
+        * CMakeLists.txt:
+        * GNUmakefile.am:
+        * GNUmakefile.list.am:
+        * WebCore.exp.in: Add symbols for input routing methods.
+        * WebCore.vcxproj/WebCore.vcxproj:
+        * WebCore.vcxproj/WebCore.vcxproj.filters:
+        * WebCore.xcodeproj/project.pbxproj:
+        * page/Page.cpp:
+        (WebCore::Page::Page): Initialize the owned UserInputBridge in the Page constructor.
+        * page/Page.h:
+        (WebCore::Page::inputBridge): Added a by-reference getter.
+        * replay/UserInputBridge.cpp: Added.
+        (WebCore::UserInputBridge::UserInputBridge):
+        (WebCore::UserInputBridge::~UserInputBridge):
+        (WebCore::UserInputBridge::handleContextMenuEvent):
+        (WebCore::UserInputBridge::handleMousePressEvent):
+        (WebCore::UserInputBridge::handleMouseReleaseEvent):
+        (WebCore::UserInputBridge::handleMouseMoveEvent):
+        (WebCore::UserInputBridge::handleMouseMoveOnScrollbarEvent):
+        (WebCore::UserInputBridge::handleKeyEvent):
+        (WebCore::UserInputBridge::handleAccessKeyEvent):
+        (WebCore::UserInputBridge::handleWheelEvent):
+        (WebCore::UserInputBridge::focusSetActive):
+        (WebCore::UserInputBridge::focusSetFocused):
+        (WebCore::UserInputBridge::scrollRecursively):
+        (WebCore::UserInputBridge::logicalScrollRecursively):
+        (WebCore::UserInputBridge::loadRequest):
+        (WebCore::UserInputBridge::reloadFrame):
+        (WebCore::UserInputBridge::stopLoadingFrame):
+        (WebCore::UserInputBridge::tryClosePage):
+        * replay/UserInputBridge.h: Added.
+
 2014-02-26  Dean Jackson  <dino@apple.com>
 
         [WebGL] Protect more WebGL entry points for pending contexts
index 28cca9b..a978c6c 100644 (file)
@@ -102,6 +102,7 @@ webcore_cppflags += \
        -I$(srcdir)/Source/WebCore/rendering/shapes \
        -I$(srcdir)/Source/WebCore/rendering/style \
        -I$(srcdir)/Source/WebCore/rendering/svg \
+       -I$(srcdir)/Source/WebCore/replay \
        -I$(srcdir)/Source/WebCore/storage \
        -I$(srcdir)/Source/WebCore/style \
        -I$(srcdir)/Source/WebCore/svg \
index ff6b071..28df7b0 100644 (file)
@@ -4618,6 +4618,8 @@ webcore_sources += \
        Source/WebCore/rendering/style/StyleVisualData.h \
        Source/WebCore/rendering/TableLayout.h \
        Source/WebCore/rendering/TrailingFloatsRootInlineBox.h \
+       Source/WebCore/replay/UserInputBridge.cpp \
+       Source/WebCore/replay/UserInputBridge.h \
        Source/WebCore/storage/StorageThread.cpp \
        Source/WebCore/storage/StorageThread.h \
        Source/WebCore/storage/StorageArea.h \
index 62e8b2c..764f439 100644 (file)
@@ -644,6 +644,19 @@ __ZN7WebCore15StorageStrategy30transientLocalStorageNamespaceEPNS_9PageGroupEPNS
 __ZN7WebCore15StringTruncator13rightTruncateERKN3WTF6StringEfRKNS_4FontENS0_24EnableRoundingHacksOrNotE
 __ZN7WebCore15StringTruncator14centerTruncateERKN3WTF6StringEfRKNS_4FontENS0_24EnableRoundingHacksOrNotE
 __ZN7WebCore15StringTruncator5widthERKN3WTF6StringERKNS_4FontENS0_24EnableRoundingHacksOrNotE
+__ZN7WebCore15UserInputBridge20handleAccessKeyEventERKNS_21PlatformKeyboardEventENS_11InputSourceE
+__ZN7WebCore15UserInputBridge14handleKeyEventERKNS_21PlatformKeyboardEventENS_11InputSourceE
+__ZN7WebCore15UserInputBridge16stopLoadingFrameEPNS_5FrameENS_11InputSourceE
+__ZN7WebCore15UserInputBridge16handleWheelEventERKNS_18PlatformWheelEventENS_11InputSourceE
+__ZN7WebCore15UserInputBridge23handleMouseReleaseEventERKNS_18PlatformMouseEventENS_11InputSourceE
+__ZN7WebCore15UserInputBridge31handleMouseMoveOnScrollbarEventERKNS_18PlatformMouseEventENS_11InputSourceE
+__ZN7WebCore15UserInputBridge21handleMousePressEventERKNS_18PlatformMouseEventENS_11InputSourceE
+__ZN7WebCore15UserInputBridge11reloadFrameEPNS_5FrameEbNS_11InputSourceE
+__ZN7WebCore15UserInputBridge20handleMouseMoveEventERKNS_18PlatformMouseEventENS_11InputSourceE
+__ZN7WebCore15UserInputBridge17scrollRecursivelyENS_15ScrollDirectionENS_17ScrollGranularityENS_11InputSourceE
+__ZN7WebCore15UserInputBridge11loadRequestERKNS_16FrameLoadRequestENS_11InputSourceE
+__ZN7WebCore15UserInputBridge22handleContextMenuEventERKNS_18PlatformMouseEventEPKNS_5FrameENS_11InputSourceE
+__ZN7WebCore15UserInputBridge12tryClosePageENS_11InputSourceE
 __ZN7WebCore15VisiblePositionC1ERKNS_8PositionENS_9EAffinityE
 __ZN7WebCore15defaultLanguageEv
 __ZN7WebCore15localizedStringEPKc
index 3893df9..6bad227 100644 (file)
@@ -14993,6 +14993,7 @@ __ZN7WebCore8Document16createTreeWalkerEPNS_4NodeEjN3WTF10PassRefPtrINS_10NodeFi
 __ZN7WebCore10TreeWalker6createEN3WTF10PassRefPtrINS_4NodeEEEjNS2_INS_10NodeFilterEEEb
 __ZN7WebCore10TreeWalkerC1EN3WTF10PassRefPtrINS_4NodeEEEjNS2_INS_10NodeFilterEEEb
 __ZN7WebCore10TreeWalkerC2EN3WTF10PassRefPtrINS_4NodeEEEjNS2_INS_10NodeFilterEEEb
+__ZN7WebCore10InputProxyC1ERNS_4PageE
 __ZN7WebCore9TraversalC2EN3WTF10PassRefPtrINS_4NodeEEEjNS2_INS_10NodeFilterEEEb
 __ZN7WebCore4toJSEPN3JSC9ExecStateEPNS_17JSDOMGlobalObjectEPNS_10TreeWalkerE
 __ZN7WebCore15getDOMStructureINS_12JSTreeWalkerEEEPN3JSC9StructureEPNS2_9ExecStateEPNS_17JSDOMGlobalObjectE
@@ -30878,4 +30879,3 @@ __ZN7WebCoreL19gPropertyWrapperMapE
 __ZN7WebCoreL12gFunctionMapE
 __ZN7WebCoreL12gFunctionMapE
 __ZN7WebCore6Editor26toggleOverwriteModeEnabledEv
-
index 39b4c53..f882c3a 100644 (file)
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="..\replay\UserInputBridge.cpp" />
     <ClCompile Include="..\workers\SharedWorkerRepository.cpp" />
     <ClCompile Include="..\xml\DOMParser.cpp" />
     <ClCompile Include="..\xml\NativeXPathNSResolver.cpp" />
     <ClInclude Include="..\rendering\svg\SVGTextMetricsBuilder.h" />
     <ClInclude Include="..\rendering\svg\SVGTextQuery.h" />
     <ClInclude Include="..\rendering\svg\SVGTextRunRenderingContext.h" />
+    <ClInclude Include="..\replay\UserInputBridge.h" />   
     <ClInclude Include="..\xml\DOMParser.h" />
     <ClInclude Include="..\xml\NativeXPathNSResolver.h" />
     <ClInclude Include="..\xml\XMLErrors.h" />
index 402a8a1..a617409 100644 (file)
     <Filter Include="rendering\svg">
       <UniqueIdentifier>{76d4960a-59c1-42de-bc37-cf4dba01b7a3}</UniqueIdentifier>
     </Filter>
+    <Filter Include="replay">
+      <UniqueIdentifier>{1fac2980-eaa4-4245-8073-90b55475479f}</UniqueIdentifier>
+    </Filter>
     <Filter Include="xml">
       <UniqueIdentifier>{7bf95243-bb51-49a0-8e4f-173242e5fc4e}</UniqueIdentifier>
     </Filter>
     <ClCompile Include="..\rendering\TextPainter.cpp">
       <Filter>rendering</Filter>
     </ClCompile>
+    <ClCompile Include="..\replay\UserInputBridge.cpp">
+      <Filter>replay</Filter>
+    </ClCompile>
     <ClCompile Include="..\xml\DOMParser.cpp">
       <Filter>xml</Filter>
     </ClCompile>
     <ClInclude Include="..\rendering\svg\SVGTextRunRenderingContext.h">
       <Filter>rendering\svg</Filter>
     </ClInclude>
+    <ClInclude Include="..\replay\UserInputBridge.h">
+      <Filter>replay</Filter>
+    </ClInclude>
     <ClInclude Include="..\xml\DOMParser.h">
       <Filter>xml</Filter>
     </ClInclude>
index 0543e06..4b3cb77 100644 (file)
                98EB1F951313FE0500D0E1EA /* NotImplemented.h in Headers */ = {isa = PBXBuildFile; fileRef = 98EB1F941313FE0500D0E1EA /* NotImplemented.h */; settings = {ATTRIBUTES = (Private, ); }; };
                990A1A0418ADA48400183FD1 /* ReplayInputTypes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 990A19F418ADA48400183FD1 /* ReplayInputTypes.cpp */; };
                990A1A0518ADA48400183FD1 /* ReplayInputTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 990A19F518ADA48400183FD1 /* ReplayInputTypes.h */; };
+               9920398218B95BC600B39AF9 /* UserInputBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9920398018B95BC600B39AF9 /* UserInputBridge.cpp */; };
+               9920398318B95BC600B39AF9 /* UserInputBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 9920398118B95BC600B39AF9 /* UserInputBridge.h */; settings = {ATTRIBUTES = (Private, ); }; };
                99E45A1718A063BE0026D88F /* EventLoopInput.h in Headers */ = {isa = PBXBuildFile; fileRef = 99E45A1618A063BE0026D88F /* EventLoopInput.h */; };
                9A1142041832D135000BB8AD /* ValueToString.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A1142031832D134000BB8AD /* ValueToString.h */; settings = {ATTRIBUTES = (Private, ); }; };
                9A1B6F97158869C80011A8C4 /* JSDOMStringListCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A1B6F96158869C80011A8C4 /* JSDOMStringListCustom.cpp */; };
                98EB1F941313FE0500D0E1EA /* NotImplemented.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NotImplemented.h; sourceTree = "<group>"; };
                990A19F418ADA48400183FD1 /* ReplayInputTypes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReplayInputTypes.cpp; sourceTree = "<group>"; };
                990A19F518ADA48400183FD1 /* ReplayInputTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReplayInputTypes.h; sourceTree = "<group>"; };
+               9920398018B95BC600B39AF9 /* UserInputBridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserInputBridge.cpp; sourceTree = "<group>"; };
+               9920398118B95BC600B39AF9 /* UserInputBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserInputBridge.h; sourceTree = "<group>"; };
                99E45A1618A063BE0026D88F /* EventLoopInput.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventLoopInput.h; sourceTree = "<group>"; };
                9A1142031832D134000BB8AD /* ValueToString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ValueToString.h; sourceTree = "<group>"; };
                9A1B6F96158869C80011A8C4 /* JSDOMStringListCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDOMStringListCustom.cpp; sourceTree = "<group>"; };
                                99E45A1618A063BE0026D88F /* EventLoopInput.h */,
                                990A19F418ADA48400183FD1 /* ReplayInputTypes.cpp */,
                                990A19F518ADA48400183FD1 /* ReplayInputTypes.h */,
+                               9920398018B95BC600B39AF9 /* UserInputBridge.cpp */,
+                               9920398118B95BC600B39AF9 /* UserInputBridge.h */,
                        );
                        path = replay;
                        sourceTree = "<group>";
                                977B3867122883E900B81FF8 /* HTMLDocumentParser.h in Headers */,
                                93309DE8099E64920056E581 /* htmlediting.h in Headers */,
                                93F198E608245E59001E9ABC /* HTMLElement.h in Headers */,
+                               9920398318B95BC600B39AF9 /* UserInputBridge.h in Headers */,
                                A17C81230F2A5CF7005DAAEB /* HTMLElementFactory.h in Headers */,
                                977B37241228721700B81FF8 /* HTMLElementStack.h in Headers */,
                                B562DB6017D3CD630010AF96 /* HTMLElementTypeHelpers.h in Headers */,
                                1ADA14100E1AE5D900023EE5 /* PluginMainThreadScheduler.cpp in Sources */,
                                71E2183B17359FB8006E6E4D /* PlugInsResourcesData.cpp in Sources */,
                                76FF17E311235673001D61B5 /* PluginViewNone.cpp in Sources */,
+                               9920398218B95BC600B39AF9 /* UserInputBridge.cpp in Sources */,
                                B2B1F7160D00CAA8004AEA64 /* PointerEventsHitRules.cpp in Sources */,
                                A1E1154613015C4E0054AC8C /* PointLightSource.cpp in Sources */,
                                97059977107D975200A50A7C /* PolicyCallback.cpp in Sources */,
index 39be7a4..9308852 100644 (file)
@@ -83,6 +83,7 @@
 #include "SubframeLoader.h"
 #include "TextResourceDecoder.h"
 #include "UserContentController.h"
+#include "UserInputBridge.h"
 #include "VisitedLinkState.h"
 #include "VisitedLinkStore.h"
 #include "VoidCallback.h"
@@ -127,6 +128,7 @@ Page::Page(PageClients& pageClients)
 #if ENABLE(CONTEXT_MENUS)
     , m_contextMenuController(std::make_unique<ContextMenuController>(*this, *pageClients.contextMenuClient))
 #endif
+    , m_userInputBridge(std::make_unique<UserInputBridge>(*this))
 #if ENABLE(INSPECTOR)
     , m_inspectorController(std::make_unique<InspectorController>(*this, pageClients.inspectorClient))
 #endif
index 9c85ef3..e41d124 100644 (file)
@@ -80,6 +80,7 @@ class FrameLoaderClient;
 class FrameSelection;
 class HaltablePlugin;
 class HistoryItem;
+class UserInputBridge;
 class InspectorClient;
 class InspectorController;
 class MainFrame;
@@ -198,6 +199,7 @@ public:
 #if ENABLE(CONTEXT_MENUS)
     ContextMenuController& contextMenuController() const { return *m_contextMenuController; }
 #endif
+    UserInputBridge& userInputBridge() const { return *m_userInputBridge; }
 #if ENABLE(INSPECTOR)
     InspectorController& inspectorController() const { return *m_inspectorController; }
 #endif
@@ -447,6 +449,7 @@ private:
 #if ENABLE(CONTEXT_MENUS)
     const std::unique_ptr<ContextMenuController> m_contextMenuController;
 #endif
+    const std::unique_ptr<UserInputBridge> m_userInputBridge;
 #if ENABLE(INSPECTOR)
     const std::unique_ptr<InspectorController> m_inspectorController;
 #endif
diff --git a/Source/WebCore/replay/UserInputBridge.cpp b/Source/WebCore/replay/UserInputBridge.cpp
new file mode 100644 (file)
index 0000000..6949696
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2013 University of Washington. All rights reserved.
+ * Copyright (C) 2014 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * HOLDER OR 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 "UserInputBridge.h"
+
+#include "EventHandler.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameLoadRequest.h"
+#include "MainFrame.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformWheelEvent.h"
+
+namespace WebCore {
+
+UserInputBridge::UserInputBridge(Page& page)
+    : m_page(page)
+{
+}
+
+bool UserInputBridge::handleContextMenuEvent(const PlatformMouseEvent& mouseEvent, const Frame* frame, InputSource)
+{
+    return frame->eventHandler().sendContextMenuEvent(mouseEvent);
+}
+
+bool UserInputBridge::handleMousePressEvent(const PlatformMouseEvent& mouseEvent, InputSource)
+{
+    return m_page.mainFrame().eventHandler().handleMousePressEvent(mouseEvent);
+}
+
+bool UserInputBridge::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent, InputSource)
+{
+    return m_page.mainFrame().eventHandler().handleMouseReleaseEvent(mouseEvent);
+}
+
+bool UserInputBridge::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, InputSource)
+{
+    return m_page.mainFrame().eventHandler().mouseMoved(mouseEvent);
+}
+
+bool UserInputBridge::handleMouseMoveOnScrollbarEvent(const PlatformMouseEvent& mouseEvent, InputSource)
+{
+    return m_page.mainFrame().eventHandler().passMouseMovedEventToScrollbars(mouseEvent);
+}
+
+bool UserInputBridge::handleKeyEvent(const PlatformKeyboardEvent& keyEvent, InputSource)
+{
+    return m_page.focusController().focusedOrMainFrame().eventHandler().keyEvent(keyEvent);
+}
+
+bool UserInputBridge::handleAccessKeyEvent(const PlatformKeyboardEvent& keyEvent, InputSource)
+{
+    return m_page.focusController().focusedOrMainFrame().eventHandler().handleAccessKey(keyEvent);
+}
+
+bool UserInputBridge::handleWheelEvent(const PlatformWheelEvent& wheelEvent, InputSource)
+{
+    return m_page.mainFrame().eventHandler().handleWheelEvent(wheelEvent);
+}
+
+void UserInputBridge::focusSetActive(bool active, InputSource)
+{
+    m_page.focusController().setActive(active);
+}
+
+void UserInputBridge::focusSetFocused(bool focused, InputSource)
+{
+    m_page.focusController().setFocused(focused);
+}
+
+bool UserInputBridge::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity, InputSource)
+{
+    return m_page.focusController().focusedOrMainFrame().eventHandler().scrollRecursively(direction, granularity, nullptr);
+}
+
+bool UserInputBridge::logicalScrollRecursively(ScrollLogicalDirection direction, ScrollGranularity granularity, InputSource)
+{
+    return m_page.focusController().focusedOrMainFrame().eventHandler().logicalScrollRecursively(direction, granularity, nullptr);
+}
+
+void UserInputBridge::loadRequest(const FrameLoadRequest& request, InputSource)
+{
+    m_page.mainFrame().loader().load(request);
+}
+
+void UserInputBridge::reloadFrame(Frame* frame, bool endToEndReload, InputSource)
+{
+    frame->loader().reload(endToEndReload);
+}
+
+void UserInputBridge::stopLoadingFrame(Frame* frame, InputSource)
+{
+    frame->loader().stopForUserCancel();
+}
+
+bool UserInputBridge::tryClosePage(InputSource)
+{
+    return m_page.mainFrame().loader().shouldClose();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/replay/UserInputBridge.h b/Source/WebCore/replay/UserInputBridge.h
new file mode 100644 (file)
index 0000000..da03a12
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2012, 2013 University of Washington. All rights reserved.
+ * Copyright (C) 2014 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * HOLDER OR 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.
+ */
+
+#ifndef UserInputBridge_h
+#define UserInputBridge_h
+
+#include "ScrollTypes.h"
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+struct FrameLoadRequest;
+
+class Frame;
+class Page;
+class PlatformKeyboardEvent;
+class PlatformMouseEvent;
+class PlatformWheelEvent;
+
+// Real user inputs come from WebKit or WebKit2.
+// Synthetic inputs come from within WebCore (i.e., from web replay or fake mouse moves).
+enum class InputSource {
+    User,
+    Synthetic
+};
+
+class UserInputBridge {
+    WTF_MAKE_NONCOPYABLE(UserInputBridge);
+public:
+    UserInputBridge(Page&);
+
+    // User input APIs.
+    bool handleContextMenuEvent(const PlatformMouseEvent&, const Frame*, InputSource source = InputSource::User);
+    bool handleMousePressEvent(const PlatformMouseEvent&, InputSource source = InputSource::User);
+    bool handleMouseReleaseEvent(const PlatformMouseEvent&, InputSource source = InputSource::User);
+    bool handleMouseMoveEvent(const PlatformMouseEvent&, InputSource source = InputSource::User);
+    bool handleMouseMoveOnScrollbarEvent(const PlatformMouseEvent&, InputSource source = InputSource::User);
+    bool handleWheelEvent(const PlatformWheelEvent&, InputSource source = InputSource::User);
+    bool handleKeyEvent(const PlatformKeyboardEvent&, InputSource source = InputSource::User);
+    bool handleAccessKeyEvent(const PlatformKeyboardEvent&, InputSource source = InputSource::User);
+    void focusSetActive(bool active, InputSource source = InputSource::User);
+    void focusSetFocused(bool focused, InputSource source = InputSource::User);
+    bool scrollRecursively(ScrollDirection, ScrollGranularity, InputSource source = InputSource::User);
+    bool logicalScrollRecursively(ScrollLogicalDirection, ScrollGranularity, InputSource source = InputSource::User);
+
+    // Navigation APIs.
+    void loadRequest(const FrameLoadRequest&, InputSource source = InputSource::User);
+    void reloadFrame(Frame*, bool endToEndReload, InputSource source = InputSource::User);
+    void stopLoadingFrame(Frame*, InputSource source = InputSource::User);
+    bool tryClosePage(InputSource source = InputSource::User);
+
+private:
+    Page& m_page;
+};
+
+} // namespace WebCore
+
+#endif // UserInputBridge_h
index a89347a..3eff634 100644 (file)
@@ -1,3 +1,27 @@
+2014-02-26  Brian Burg  <bburg@apple.com>
+
+        Web Replay: route through UserInputBridge when delivering user inputs to WebCore
+        https://bugs.webkit.org/show_bug.cgi?id=128150
+
+        Reviewed by Timothy Hatcher.
+
+        When delivering user inputs to WebCore, route calls through the page's UserInputBridge.
+        This allows us to capture and replay user inputs from WebKit2 solely within WebCore.
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::tryClose):
+        (WebKit::WebPage::loadRequest):
+        (WebKit::WebPage::stopLoadingFrame):
+        (WebKit::WebPage::stopLoading):
+        (WebKit::WebPage::reload):
+        (WebKit::WebPage::contextMenuAtPointInWindow):
+        (WebKit::handleContextMenuEvent):
+        (WebKit::handleMouseEvent):
+        (WebKit::handleWheelEvent):
+        (WebKit::handleKeyEvent):
+        (WebKit::WebPage::scroll):
+        (WebKit::WebPage::logicalScroll):
+
 2014-02-26  Pratik Solanki  <psolanki@apple.com>
 
         [iOS][WebKit2] Adopt SPI for managing tabs
index e25e063..672a831 100644 (file)
 #include <WebCore/SubframeLoader.h>
 #include <WebCore/SubstituteData.h>
 #include <WebCore/TextIterator.h>
+#include <WebCore/UserInputBridge.h>
 #include <WebCore/VisiblePosition.h>
 #include <WebCore/VisibleUnits.h>
 #include <WebCore/markup.h>
@@ -892,7 +893,7 @@ void WebPage::tryClose()
 {
     SendStopResponsivenessTimer stopper(this);
 
-    if (!m_mainFrame->coreFrame()->loader().shouldClose()) {
+    if (!corePage()->userInputBridge().tryClosePage()) {
         send(Messages::WebPageProxy::StopResponsivenessTimer());
         return;
     }
@@ -933,7 +934,7 @@ void WebPage::loadRequest(uint64_t navigationID, const ResourceRequest& request,
     m_loaderClient.willLoadURLRequest(this, request, userData.get());
 
     // Initate the load in WebCore.
-    m_mainFrame->coreFrame()->loader().load(FrameLoadRequest(m_mainFrame->coreFrame(), request));
+    corePage()->userInputBridge().loadRequest(FrameLoadRequest(m_mainFrame->coreFrame(), request));
 
     ASSERT(!m_pendingNavigationID);
 }
@@ -1006,14 +1007,14 @@ void WebPage::stopLoadingFrame(uint64_t frameID)
     if (!frame)
         return;
 
-    frame->coreFrame()->loader().stopForUserCancel();
+    corePage()->userInputBridge().stopLoadingFrame(frame->coreFrame());
 }
 
 void WebPage::stopLoading()
 {
     SendStopResponsivenessTimer stopper(this);
 
-    m_mainFrame->coreFrame()->loader().stopForUserCancel();
+    corePage()->userInputBridge().stopLoadingFrame(m_mainFrame->coreFrame());
 }
 
 void WebPage::setDefersLoading(bool defersLoading)
@@ -1029,7 +1030,7 @@ void WebPage::reload(uint64_t navigationID, bool reloadFromOrigin, const Sandbox
     m_pendingNavigationID = navigationID;
 
     m_sandboxExtensionTracker.beginLoad(m_mainFrame.get(), sandboxExtensionHandle);
-    m_mainFrame->coreFrame()->loader().reload(reloadFromOrigin);
+    corePage()->userInputBridge().reloadFrame(m_mainFrame->coreFrame(), reloadFromOrigin);
 }
 
 void WebPage::goForward(uint64_t backForwardItemID)
@@ -1583,7 +1584,7 @@ WebContextMenu* WebPage::contextMenuAtPointInWindow(const IntPoint& point)
     
     // Simulate a mouse click to generate the correct menu.
     PlatformMouseEvent mouseEvent(point, point, RightButton, PlatformEvent::MousePressed, 1, false, false, false, false, currentTime());
-    bool handled = corePage()->mainFrame().eventHandler().sendContextMenuEvent(mouseEvent);
+    bool handled = corePage()->userInputBridge().handleContextMenuEvent(mouseEvent, &corePage()->mainFrame());
     if (!handled)
         return 0;
 
@@ -1643,8 +1644,8 @@ static bool handleContextMenuEvent(const PlatformMouseEvent& platformMouseEvent,
     Frame* frame = &page->corePage()->mainFrame();
     if (result.innerNonSharedNode())
         frame = result.innerNonSharedNode()->document().frame();
-    
-    bool handled = frame->eventHandler().sendContextMenuEvent(platformMouseEvent);
+
+    bool handled = page->corePage()->userInputBridge().handleContextMenuEvent(platformMouseEvent, frame);
     if (handled)
         page->contextMenu()->show();
 
@@ -1667,7 +1668,7 @@ static bool handleMouseEvent(const WebMouseEvent& mouseEvent, WebPage* page, boo
                 page->corePage()->contextMenuController().clearContextMenu();
 #endif
 
-            bool handled = frame.eventHandler().handleMousePressEvent(platformMouseEvent);
+            bool handled = page->corePage()->userInputBridge().handleMousePressEvent(platformMouseEvent);
 #if ENABLE(CONTEXT_MENUS)
             if (isContextClick(platformMouseEvent))
                 handled = handleContextMenuEvent(platformMouseEvent, page);
@@ -1675,12 +1676,12 @@ static bool handleMouseEvent(const WebMouseEvent& mouseEvent, WebPage* page, boo
             return handled;
         }
         case PlatformEvent::MouseReleased:
-            return frame.eventHandler().handleMouseReleaseEvent(platformMouseEvent);
+            return page->corePage()->userInputBridge().handleMouseReleaseEvent(platformMouseEvent);
 
         case PlatformEvent::MouseMoved:
             if (onlyUpdateScrollbars)
-                return frame.eventHandler().passMouseMovedEventToScrollbars(platformMouseEvent);
-            return frame.eventHandler().mouseMoved(platformMouseEvent);
+                return page->corePage()->userInputBridge().handleMouseMoveOnScrollbarEvent(platformMouseEvent);
+            return page->corePage()->userInputBridge().handleMouseMoveEvent(platformMouseEvent);
         default:
             ASSERT_NOT_REACHED();
             return false;
@@ -1766,7 +1767,7 @@ static bool handleWheelEvent(const WebWheelEvent& wheelEvent, Page* page)
         return false;
 
     PlatformWheelEvent platformWheelEvent = platform(wheelEvent);
-    return frame.eventHandler().handleWheelEvent(platformWheelEvent);
+    return page->userInputBridge().handleWheelEvent(platformWheelEvent);
 }
 
 void WebPage::wheelEvent(const WebWheelEvent& wheelEvent)
@@ -1796,8 +1797,8 @@ static bool handleKeyEvent(const WebKeyboardEvent& keyboardEvent, Page* page)
         return false;
 
     if (keyboardEvent.type() == WebEvent::Char && keyboardEvent.isSystemKey())
-        return page->focusController().focusedOrMainFrame().eventHandler().handleAccessKey(platform(keyboardEvent));
-    return page->focusController().focusedOrMainFrame().eventHandler().keyEvent(platform(keyboardEvent));
+        return page->userInputBridge().handleAccessKeyEvent(platform(keyboardEvent));
+    return page->userInputBridge().handleKeyEvent(platform(keyboardEvent));
 }
 
 void WebPage::keyEvent(const WebKeyboardEvent& keyboardEvent)
@@ -1936,12 +1937,12 @@ void WebPage::touchEventSyncForTesting(const WebTouchEvent& touchEvent, bool& ha
 
 bool WebPage::scroll(Page* page, ScrollDirection direction, ScrollGranularity granularity)
 {
-    return page->focusController().focusedOrMainFrame().eventHandler().scrollRecursively(direction, granularity);
+    return page->userInputBridge().scrollRecursively(direction, granularity);
 }
 
 bool WebPage::logicalScroll(Page* page, ScrollLogicalDirection direction, ScrollGranularity granularity)
 {
-    return page->focusController().focusedOrMainFrame().eventHandler().logicalScrollRecursively(direction, granularity);
+    return page->userInputBridge().logicalScrollRecursively(direction, granularity);
 }
 
 bool WebPage::scrollBy(uint32_t scrollDirection, uint32_t scrollGranularity)