Skip to content

Commit

Permalink
Refactor mouse and keyboard handling in the web process to be frame s…
Browse files Browse the repository at this point in the history
…pecific

https://bugs.webkit.org/show_bug.cgi?id=260356
rdar://114035729

Reviewed by Wenson Hsieh and Alex Christensen.

To implement mouse and keyboard events for site isolated frames, we need to be able to send
events to frames which are in a different process than the main frame. This patch works
towards this by refactoring how these events are handled in the web process to be able to
specify a frame. There still needs to be changes so that the events queued in the UI process
have support to be to sent to specified frames. For now, these events will all still go to
the main frame.

* Source/WebCore/page/LocalFrame.cpp:
(WebCore::LocalFrame::LocalFrame):
* Source/WebCore/page/LocalFrame.h:
* Source/WebCore/page/Page.cpp:
(WebCore::Page::Page):
* Source/WebCore/page/Page.h:
(WebCore::Page::userInputBridge): Deleted.
* Source/WebCore/replay/UserInputBridge.cpp:
(WebCore::UserInputBridge::UserInputBridge):
(WebCore::UserInputBridge::handleContextMenuEvent):
(WebCore::UserInputBridge::handleMousePressEvent):
(WebCore::UserInputBridge::handleMouseReleaseEvent):
(WebCore::UserInputBridge::handleMouseMoveEvent):
(WebCore::UserInputBridge::handleMouseMoveOnScrollbarEvent):
(WebCore::UserInputBridge::handleMouseForceEvent):
(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):
* Source/WebCore/replay/UserInputBridge.h:
* Source/WebKit/UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::processNextQueuedMouseEvent):
(WebKit::WebPageProxy::sendWheelEvent):
(WebKit::WebPageProxy::handleKeyboardEvent):
(WebKit::WebPageProxy::didReceiveEvent):
* Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePage.cpp:
(WKBundlePageCopyContextMenuAtPointInWindow):
* Source/WebKit/WebProcess/WebPage/EventDispatcher.cpp:
(WebKit::EventDispatcher::dispatchWheelEvent):
* Source/WebKit/WebProcess/WebPage/WebFrame.cpp:
(WebKit::isContextClick):
(WebKit::WebFrame::handleContextMenuEvent):
(WebKit::WebFrame::handleMouseEvent):
(WebKit::WebFrame::handleKeyEvent):
* Source/WebKit/WebProcess/WebPage/WebFrame.h:
* Source/WebKit/WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::tryClose):
(WebKit::WebPage::loadRequest):
(WebKit::WebPage::stopLoading):
(WebKit::WebPage::reload):
(WebKit::WebPage::contextMenuAtPointInWindow):
(WebKit::WebPage::mouseEvent):
(WebKit::WebPage::handleWheelEvent):
(WebKit::WebPage::wheelEvent):
(WebKit::WebPage::keyEvent):
(WebKit::WebPage::scroll):
(WebKit::WebPage::logicalScroll):
(WebKit::WebPage::simulateMouseDown):
(WebKit::WebPage::simulateMouseUp):
(WebKit::WebPage::simulateMouseMotion):
(WebKit::isContextClick): Deleted.
(WebKit::handleContextMenuEvent): Deleted.
(WebKit::handleMouseEvent): Deleted.
(WebKit::handleKeyEvent): Deleted.
* Source/WebKit/WebProcess/WebPage/WebPage.h:
* Source/WebKit/WebProcess/WebPage/WebPage.messages.in:

Canonical link: https://commits.webkit.org/267124@main
  • Loading branch information
charliewolfe committed Aug 22, 2023
1 parent 22cfa17 commit b1c1773
Show file tree
Hide file tree
Showing 14 changed files with 242 additions and 200 deletions.
2 changes: 2 additions & 0 deletions Source/WebCore/page/LocalFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
#include "UserContentController.h"
#include "UserContentURLPattern.h"
#include "UserGestureIndicator.h"
#include "UserInputBridge.h"
#include "UserScript.h"
#include "UserTypingGestureIndicator.h"
#include "VisibleUnits.h"
Expand Down Expand Up @@ -155,6 +156,7 @@ LocalFrame::LocalFrame(Page& page, UniqueRef<LocalFrameLoaderClient>&& frameLoad
, m_pageZoomFactor(parentPageZoomFactor(this))
, m_textZoomFactor(parentTextZoomFactor(this))
, m_eventHandler(makeUniqueRef<EventHandler>(*this))
, m_userInputBridge(makeUniqueRef<UserInputBridge>(*this))
{
ProcessWarming::initializeNames();
StaticCSSValuePool::init();
Expand Down
4 changes: 4 additions & 0 deletions Source/WebCore/page/LocalFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class RenderView;
class RenderWidget;
class ScriptController;
class SecurityOrigin;
class UserInputBridge;
class VisiblePosition;
class Widget;

Expand Down Expand Up @@ -285,6 +286,8 @@ class LocalFrame final : public Frame {

WEBCORE_EXPORT bool arePluginsEnabled();

UserInputBridge& userInputBridge() { return m_userInputBridge.get(); }

private:
friend class NavigationDisabler;

Expand Down Expand Up @@ -342,6 +345,7 @@ class LocalFrame final : public Frame {
FloatSize m_overrideScreenSize;

UniqueRef<EventHandler> m_eventHandler;
UniqueRef<UserInputBridge> m_userInputBridge;
};

inline LocalFrameView* LocalFrame::view() const
Expand Down
2 changes: 0 additions & 2 deletions Source/WebCore/page/Page.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@
#include "TextResourceDecoder.h"
#include "UserContentProvider.h"
#include "UserContentURLPattern.h"
#include "UserInputBridge.h"
#include "UserScript.h"
#include "UserStyleSheet.h"
#include "ValidationMessageClient.h"
Expand Down Expand Up @@ -294,7 +293,6 @@ Page::Page(PageConfiguration&& pageConfiguration)
#if ENABLE(CONTEXT_MENUS)
, m_contextMenuController(makeUniqueRef<ContextMenuController>(*this, WTFMove(pageConfiguration.contextMenuClient)))
#endif
, m_userInputBridge(makeUniqueRef<UserInputBridge>(*this))
, m_inspectorController(makeUniqueRef<InspectorController>(*this, WTFMove(pageConfiguration.inspectorClient)))
, m_pointerCaptureController(makeUniqueRef<PointerCaptureController>(*this))
#if ENABLE(POINTER_LOCK)
Expand Down
3 changes: 0 additions & 3 deletions Source/WebCore/page/Page.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ class StorageNamespaceProvider;
class StorageProvider;
class UserContentProvider;
class UserContentURLPattern;
class UserInputBridge;
class UserScript;
class UserStyleSheet;
class ValidationMessageClient;
Expand Down Expand Up @@ -376,7 +375,6 @@ class Page : public Supplementable<Page>, public CanMakeWeakPtr<Page> {
ContextMenuController& contextMenuController() { return m_contextMenuController.get(); }
const ContextMenuController& contextMenuController() const { return m_contextMenuController.get(); }
#endif
UserInputBridge& userInputBridge() { return m_userInputBridge.get(); }
InspectorController& inspectorController() { return m_inspectorController.get(); }
PointerCaptureController& pointerCaptureController() { return m_pointerCaptureController.get(); }
#if ENABLE(POINTER_LOCK)
Expand Down Expand Up @@ -1119,7 +1117,6 @@ class Page : public Supplementable<Page>, public CanMakeWeakPtr<Page> {
#if ENABLE(CONTEXT_MENUS)
UniqueRef<ContextMenuController> m_contextMenuController;
#endif
UniqueRef<UserInputBridge> m_userInputBridge;
UniqueRef<InspectorController> m_inspectorController;
UniqueRef<PointerCaptureController> m_pointerCaptureController;
#if ENABLE(POINTER_LOCK)
Expand Down
78 changes: 36 additions & 42 deletions Source/WebCore/replay/UserInputBridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,123 +41,117 @@

namespace WebCore {

UserInputBridge::UserInputBridge(Page& page)
: m_page(page)
UserInputBridge::UserInputBridge(LocalFrame& frame)
: m_frame(frame)
{
}

#if ENABLE(CONTEXT_MENU_EVENT)
bool UserInputBridge::handleContextMenuEvent(const PlatformMouseEvent& mouseEvent, LocalFrame& frame, InputSource)
bool UserInputBridge::handleContextMenuEvent(const PlatformMouseEvent& mouseEvent, InputSource)
{
return frame.eventHandler().sendContextMenuEvent(mouseEvent);
return m_frame.eventHandler().sendContextMenuEvent(mouseEvent);
}
#endif

bool UserInputBridge::handleMousePressEvent(const PlatformMouseEvent& mouseEvent, InputSource)
{
auto* localMainFrame = dynamicDowncast<LocalFrame>(m_page.mainFrame());
if (!localMainFrame)
return false;
return Ref(*localMainFrame)->eventHandler().handleMousePressEvent(mouseEvent);
return m_frame.eventHandler().handleMousePressEvent(mouseEvent);
}

bool UserInputBridge::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent, InputSource)
{
auto* localMainFrame = dynamicDowncast<LocalFrame>(m_page.mainFrame());
if (!localMainFrame)
return false;
return Ref(*localMainFrame)->eventHandler().handleMouseReleaseEvent(mouseEvent);
return m_frame.eventHandler().handleMouseReleaseEvent(mouseEvent);
}

bool UserInputBridge::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, InputSource)
{
auto* localMainFrame = dynamicDowncast<LocalFrame>(m_page.mainFrame());
if (!localMainFrame)
return false;
return Ref(*localMainFrame)->eventHandler().mouseMoved(mouseEvent);
return m_frame.eventHandler().mouseMoved(mouseEvent);
}

bool UserInputBridge::handleMouseMoveOnScrollbarEvent(const PlatformMouseEvent& mouseEvent, InputSource)
{
auto* localMainFrame = dynamicDowncast<LocalFrame>(m_page.mainFrame());
if (!localMainFrame)
return false;
return Ref(*localMainFrame)->eventHandler().passMouseMovedEventToScrollbars(mouseEvent);
return m_frame.eventHandler().passMouseMovedEventToScrollbars(mouseEvent);
}

bool UserInputBridge::handleMouseForceEvent(const PlatformMouseEvent& mouseEvent, InputSource)
{
auto* localMainFrame = dynamicDowncast<LocalFrame>(m_page.mainFrame());
if (!localMainFrame)
return false;
return Ref(*localMainFrame)->eventHandler().handleMouseForceEvent(mouseEvent);
return m_frame.eventHandler().handleMouseForceEvent(mouseEvent);
}

bool UserInputBridge::handleKeyEvent(const PlatformKeyboardEvent& keyEvent, InputSource)
{
return Ref(m_page.focusController().focusedOrMainFrame())->eventHandler().keyEvent(keyEvent);
return m_frame.eventHandler().keyEvent(keyEvent);
}

bool UserInputBridge::handleAccessKeyEvent(const PlatformKeyboardEvent& keyEvent, InputSource)
{
return Ref(m_page.focusController().focusedOrMainFrame())->eventHandler().handleAccessKey(keyEvent);
return m_frame.eventHandler().handleAccessKey(keyEvent);
}

bool UserInputBridge::handleWheelEvent(const PlatformWheelEvent& wheelEvent, OptionSet<WheelEventProcessingSteps> processingSteps, InputSource)
{
auto* localMainFrame = dynamicDowncast<LocalFrame>(m_page.mainFrame());
if (!localMainFrame)
return false;
return Ref(*localMainFrame)->eventHandler().handleWheelEvent(wheelEvent, processingSteps);
return m_frame.eventHandler().handleWheelEvent(wheelEvent, processingSteps);
}

void UserInputBridge::focusSetActive(bool active, InputSource)
{
m_page.focusController().setActive(active);
auto* page = m_frame.page();
if (!page)
return;
page->focusController().setActive(active);
}

void UserInputBridge::focusSetFocused(bool focused, InputSource)
{
m_page.focusController().setFocused(focused);
auto* page = m_frame.page();
if (!page)
return;
page->focusController().setFocused(focused);
}

bool UserInputBridge::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity, InputSource)
{
return Ref(m_page.focusController().focusedOrMainFrame())->eventHandler().scrollRecursively(direction, granularity, nullptr);
return Ref(m_frame)->eventHandler().scrollRecursively(direction, granularity, nullptr);
}

bool UserInputBridge::logicalScrollRecursively(ScrollLogicalDirection direction, ScrollGranularity granularity, InputSource)
{
return Ref(m_page.focusController().focusedOrMainFrame())->eventHandler().logicalScrollRecursively(direction, granularity, nullptr);
return Ref(m_frame)->eventHandler().logicalScrollRecursively(direction, granularity, nullptr);
}

void UserInputBridge::loadRequest(FrameLoadRequest&& request, InputSource)
{
auto* page = m_frame.page();
if (!page)
return;
#if ENABLE(WEB_AUTHN)
m_page.authenticatorCoordinator().resetUserGestureRequirement();
page->authenticatorCoordinator().resetUserGestureRequirement();
#endif
auto* localMainFrame = dynamicDowncast<LocalFrame>(m_page.mainFrame());
auto* localMainFrame = dynamicDowncast<LocalFrame>(m_frame.mainFrame());
if (!localMainFrame)
return;
Ref(*localMainFrame)->loader().load(WTFMove(request));
}

void UserInputBridge::reloadFrame(LocalFrame& frame, OptionSet<ReloadOption> options, InputSource)
void UserInputBridge::reloadFrame(OptionSet<ReloadOption> options, InputSource)
{
#if ENABLE(WEB_AUTHN)
m_page.authenticatorCoordinator().resetUserGestureRequirement();
auto page = m_frame.page();
if (!page)
return;
page->authenticatorCoordinator().resetUserGestureRequirement();
#endif
frame.loader().reload(options);
m_frame.loader().reload(options);
}

void UserInputBridge::stopLoadingFrame(LocalFrame& frame, InputSource)
void UserInputBridge::stopLoadingFrame(InputSource)
{
frame.loader().stopForUserCancel();
m_frame.loader().stopForUserCancel();
}

bool UserInputBridge::tryClosePage(InputSource)
{
auto* localMainFrame = dynamicDowncast<LocalFrame>(m_page.mainFrame());
auto* localMainFrame = dynamicDowncast<LocalFrame>(m_frame.mainFrame());
if (!localMainFrame)
return false;
return Ref(*localMainFrame)->loader().shouldClose();
Expand Down
11 changes: 5 additions & 6 deletions Source/WebCore/replay/UserInputBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ namespace WebCore {

class FrameLoadRequest;
class LocalFrame;
class Page;
class PlatformKeyboardEvent;
class PlatformMouseEvent;
class PlatformWheelEvent;
Expand All @@ -55,11 +54,11 @@ class UserInputBridge {
WTF_MAKE_FAST_ALLOCATED;
WTF_MAKE_NONCOPYABLE(UserInputBridge);
public:
UserInputBridge(Page&);
UserInputBridge(LocalFrame&);

// User input APIs.
#if ENABLE(CONTEXT_MENU_EVENT)
WEBCORE_EXPORT bool handleContextMenuEvent(const PlatformMouseEvent&, LocalFrame&, InputSource = InputSource::User);
WEBCORE_EXPORT bool handleContextMenuEvent(const PlatformMouseEvent&, InputSource = InputSource::User);
#endif
WEBCORE_EXPORT bool handleMousePressEvent(const PlatformMouseEvent&, InputSource = InputSource::User);
WEBCORE_EXPORT bool handleMouseReleaseEvent(const PlatformMouseEvent&, InputSource = InputSource::User);
Expand All @@ -76,12 +75,12 @@ class UserInputBridge {

// Navigation APIs.
WEBCORE_EXPORT void loadRequest(FrameLoadRequest&&, InputSource = InputSource::User);
WEBCORE_EXPORT void reloadFrame(LocalFrame&, OptionSet<ReloadOption>, InputSource = InputSource::User);
WEBCORE_EXPORT void stopLoadingFrame(LocalFrame&, InputSource = InputSource::User);
WEBCORE_EXPORT void reloadFrame(OptionSet<ReloadOption>, InputSource = InputSource::User);
WEBCORE_EXPORT void stopLoadingFrame(InputSource = InputSource::User);
WEBCORE_EXPORT bool tryClosePage(InputSource = InputSource::User);

private:
Page& m_page;
LocalFrame& m_frame;
};

} // namespace WebCore
29 changes: 22 additions & 7 deletions Source/WebKit/UIProcess/WebPageProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3248,6 +3248,9 @@ void WebPageProxy::processNextQueuedMouseEvent()
if (!hasRunningProcess())
return;

if (!m_mainFrame)
return;

ASSERT(!internals().mouseEventQueue.isEmpty());

const NativeWebMouseEvent& event = internals().mouseEventQueue.first();
Expand All @@ -3273,7 +3276,7 @@ void WebPageProxy::processNextQueuedMouseEvent()

LOG_WITH_STREAM(MouseHandling, stream << "UIProcess: sent mouse event " << eventType << " (queue size " << internals().mouseEventQueue.size() << ")");
m_process->recordUserGestureAuthorizationToken(event.authorizationToken());
send(Messages::WebPage::MouseEvent(event, sandboxExtensions));
send(Messages::WebPage::MouseEvent(m_mainFrame->frameID(), event, sandboxExtensions));
}

void WebPageProxy::doAfterProcessingAllPendingMouseEvents(WTF::Function<void ()>&& action)
Expand Down Expand Up @@ -3302,7 +3305,11 @@ void WebPageProxy::flushPendingMouseEventCallbacks()
#if PLATFORM(IOS_FAMILY)
void WebPageProxy::dispatchWheelEventWithoutScrolling(const WebWheelEvent& event, CompletionHandler<void(bool)>&& completionHandler)
{
sendWithAsyncReply(Messages::WebPage::DispatchWheelEventWithoutScrolling(event), WTFMove(completionHandler));
if (!m_mainFrame) {
completionHandler(false);
return;
}
sendWithAsyncReply(Messages::WebPage::DispatchWheelEventWithoutScrolling(m_mainFrame->frameID(), event), WTFMove(completionHandler));
}
#endif

Expand Down Expand Up @@ -3364,11 +3371,14 @@ void WebPageProxy::sendWheelEvent(const WebWheelEvent& event, OptionSet<WheelEve
if (!connection)
return;

if (!m_mainFrame)
return;

if (drawingArea()->shouldSendWheelEventsToEventDispatcher()) {
sendWheelEventScrollingAccelerationCurveIfNecessary(event);
connection->send(Messages::EventDispatcher::WheelEvent(webPageID(), event, rubberBandableEdges), 0, { }, Thread::QOS::UserInteractive);
} else {
sendWithAsyncReply(Messages::WebPage::HandleWheelEvent(event, processingSteps, willStartSwipe), [weakThis = WeakPtr { *this }, wheelEvent = event, wasHandledForScrolling](ScrollingNodeID nodeID, std::optional<WheelScrollGestureState> gestureState, bool handled) {
sendWithAsyncReply(Messages::WebPage::HandleWheelEvent(m_mainFrame->frameID(), event, processingSteps, willStartSwipe), [weakThis = WeakPtr { *this }, wheelEvent = event, wasHandledForScrolling](ScrollingNodeID nodeID, std::optional<WheelScrollGestureState> gestureState, bool handled) {
RefPtr protectedThis = weakThis.get();
if (!protectedThis)
return;
Expand Down Expand Up @@ -3516,7 +3526,12 @@ bool WebPageProxy::handleKeyboardEvent(const NativeWebKeyboardEvent& event)
{
if (!hasRunningProcess())
return false;


if (!m_mainFrame) {
m_uiClient->didNotHandleKeyEvent(this, event);
return false;
}

LOG_WITH_STREAM(KeyHandling, stream << "WebPageProxy::handleKeyboardEvent: " << event.type());

internals().keyEventQueue.append(event);
Expand All @@ -3527,7 +3542,7 @@ bool WebPageProxy::handleKeyboardEvent(const NativeWebKeyboardEvent& event)
if (internals().keyEventQueue.size() == 1) {
LOG(KeyHandling, " UI process: sent keyEvent from handleKeyboardEvent");
m_process->recordUserGestureAuthorizationToken(event.authorizationToken());
send(Messages::WebPage::KeyEvent(event));
send(Messages::WebPage::KeyEvent(m_mainFrame->frameID(), event));
}

return true;
Expand Down Expand Up @@ -8544,11 +8559,11 @@ void WebPageProxy::didReceiveEvent(WebEventType eventType, bool handled)
#endif

bool canProcessMoreKeyEvents = !internals().keyEventQueue.isEmpty();
if (canProcessMoreKeyEvents) {
if (canProcessMoreKeyEvents && m_mainFrame) {
auto nextEvent = internals().keyEventQueue.first();
LOG(KeyHandling, " UI process: sent keyEvent from didReceiveEvent");
m_process->recordUserGestureAuthorizationToken(nextEvent.authorizationToken());
send(Messages::WebPage::KeyEvent(internals().keyEventQueue.first()));
send(Messages::WebPage::KeyEvent(m_mainFrame->frameID(), internals().keyEventQueue.first()));
}

// The call to doneWithKeyEvent may close this WebPage.
Expand Down
10 changes: 9 additions & 1 deletion Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,15 @@ WKArrayRef WKBundlePageCopyContextMenuItems(WKBundlePageRef pageRef)
WKArrayRef WKBundlePageCopyContextMenuAtPointInWindow(WKBundlePageRef pageRef, WKPoint point)
{
#if ENABLE(CONTEXT_MENUS)
WebKit::WebContextMenu* contextMenu = WebKit::toImpl(pageRef)->contextMenuAtPointInWindow(WebKit::toIntPoint(point));
WebCore::Page* page = WebKit::toImpl(pageRef)->corePage();
if (!page)
return nullptr;

auto* localMainFrame = dynamicDowncast<WebCore::LocalFrame>(page->mainFrame());
if (!localMainFrame)
return nullptr;

WebKit::WebContextMenu* contextMenu = WebKit::toImpl(pageRef)->contextMenuAtPointInWindow(localMainFrame->frameID(), WebKit::toIntPoint(point));
if (!contextMenu)
return nullptr;

Expand Down
4 changes: 3 additions & 1 deletion Source/WebKit/WebProcess/WebPage/EventDispatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,9 @@ void EventDispatcher::dispatchWheelEvent(PageIdentifier pageID, const WebWheelEv
if (!webPage)
return;

bool handled = webPage->wheelEvent(wheelEvent, processingSteps, wheelEventOrigin);
bool handled = false;
if (webPage->mainFrame())
handled = webPage->wheelEvent(webPage->mainFrame()->frameID(), wheelEvent, processingSteps, wheelEventOrigin);

if (processingSteps.contains(WheelEventProcessingSteps::SynchronousScrolling) && wheelEventOrigin == EventDispatcher::WheelEventOrigin::UIProcess)
sendDidReceiveEvent(pageID, wheelEvent.type(), handled);
Expand Down
Loading

0 comments on commit b1c1773

Please sign in to comment.