Bug 2064287 - Harden drag handling; r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D321984
This commit is contained in:
Edgar Chen
2026-09-04 14:59:04 +00:00
committed by echen@mozilla.com
parent a48a2abebd
commit 5197db7444
8 changed files with 71 additions and 10 deletions
+11
View File
@@ -510,6 +510,12 @@ void PointerLockManager::SetLockedRemoteTarget(BrowserParent* aBrowserParent,
return; return;
} }
if (nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1")) {
dragService->Suppress();
}
presContext->EventStateManager()->StopTrackingDragGesture(true);
MOZ_POINTERLOCK_LOG("Set locked remote target to 0x%p", aBrowserParent); MOZ_POINTERLOCK_LOG("Set locked remote target to 0x%p", aBrowserParent);
sLockedRemoteTarget = aBrowserParent; sLockedRemoteTarget = aBrowserParent;
PointerEventHandler::ReleaseAllPointerCaptureRemoteTarget(); PointerEventHandler::ReleaseAllPointerCaptureRemoteTarget();
@@ -539,6 +545,11 @@ void PointerLockManager::ReleaseLockedRemoteTarget(
nsCOMPtr<nsIWidget> widget = aBrowserParent->GetTopLevelWidget(); nsCOMPtr<nsIWidget> widget = aBrowserParent->GetTopLevelWidget();
EventStateManager::ReleaseLockedPointer(widget); EventStateManager::ReleaseLockedPointer(widget);
if (nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1")) {
dragService->Unsuppress();
}
} }
} }
+1
View File
@@ -54,6 +54,7 @@ class PointerLockManager final {
// Set/release pointer lock remote target. Should only be called in parent // Set/release pointer lock remote target. Should only be called in parent
// process. // process.
MOZ_CAN_RUN_SCRIPT
static void SetLockedRemoteTarget(dom::BrowserParent* aBrowserParent, static void SetLockedRemoteTarget(dom::BrowserParent* aBrowserParent,
const bool& aUnadjustedMovement, const bool& aUnadjustedMovement,
nsACString& aError); nsACString& aError);
+5
View File
@@ -2636,6 +2636,8 @@ void EventStateManager::BeginTrackingDragGesture(
if (!mGestureDownFrameOwner) { if (!mGestureDownFrameOwner) {
mGestureDownFrameOwner = mGestureDownContent; mGestureDownFrameOwner = mGestureDownContent;
} }
mGestureDownTopLevelRemoteTarget =
BrowserParent::GetFrom(mGestureDownContent);
} }
mGestureModifiers = aMouseDownOrTouchDragEvent.mModifiers; mGestureModifiers = aMouseDownOrTouchDragEvent.mModifiers;
mGestureDownButtons = aMouseDownOrTouchDragEvent.mButtons; mGestureDownButtons = aMouseDownOrTouchDragEvent.mButtons;
@@ -2687,6 +2689,8 @@ void EventStateManager::StopTrackingDragGesture(bool aClearInChildProcesses) {
return; return;
} }
mGestureDownTopLevelRemoteTarget = nullptr;
// Only notify if there is NOT a drag session active in the parent. // Only notify if there is NOT a drag session active in the parent.
RefPtr<nsIDragSession> dragSession = RefPtr<nsIDragSession> dragSession =
nsContentUtils::GetDragSession(mPresContext); nsContentUtils::GetDragSession(mPresContext);
@@ -7990,6 +7994,7 @@ bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY(
void EventStateManager::UpdateGestureContent(nsIContent* aContent) { void EventStateManager::UpdateGestureContent(nsIContent* aContent) {
mGestureDownContent = aContent; mGestureDownContent = aContent;
mGestureDownFrameOwner = aContent; mGestureDownFrameOwner = aContent;
mGestureDownTopLevelRemoteTarget = BrowserParent::GetFrom(aContent);
} }
void EventStateManager::NotifyContentWillBeRemovedForGesture( void EventStateManager::NotifyContentWillBeRemovedForGesture(
+5
View File
@@ -561,6 +561,10 @@ class EventStateManager : public nsSupportsWeakReference, public nsIObserver {
return mGestureDownContent; return mGestureDownContent;
} }
dom::BrowserParent* GetTrackingDragGestureTopLevelRemoteTarget() const {
return mGestureDownTopLevelRemoteTarget;
}
// Update the tracked gesture content to the parent of its frame when it's // Update the tracked gesture content to the parent of its frame when it's
// removed, so that the gesture can be continued. // removed, so that the gesture can be continued.
void NotifyContentWillBeRemovedForGesture(nsIContent& aContent); void NotifyContentWillBeRemovedForGesture(nsIContent& aContent);
@@ -1446,6 +1450,7 @@ class EventStateManager : public nsSupportsWeakReference, public nsIObserver {
// as the target in most cases but not always - for example when dragging // as the target in most cases but not always - for example when dragging
// an <area> of an image map this is the image. (bug 289667) // an <area> of an image map this is the image. (bug 289667)
nsCOMPtr<nsIContent> mGestureDownFrameOwner; nsCOMPtr<nsIContent> mGestureDownFrameOwner;
RefPtr<dom::BrowserParent> mGestureDownTopLevelRemoteTarget;
// Data associated with a drag started in a content process. // Data associated with a drag started in a content process.
RefPtr<dom::RemoteDragStartData> mGestureDownDragStartData; RefPtr<dom::RemoteDragStartData> mGestureDownDragStartData;
// State of keys when the original gesture-down happened // State of keys when the original gesture-down happened
+40 -10
View File
@@ -1060,6 +1060,20 @@ mozilla::ipc::IPCResult BrowserParent::RecvSetDimensions(
nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = do_QueryInterface(treeOwner); nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = do_QueryInterface(treeOwner);
NS_ENSURE_TRUE(treeOwnerAsWin, IPC_OK()); NS_ENSURE_TRUE(treeOwnerAsWin, IPC_OK());
if (nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1")) {
RefPtr<nsIWidget> widget = GetTopLevelWidget();
if (RefPtr<nsIDragSession> session =
dragService->GetCurrentSession(widget)) {
session->EndDragSession(false, 0);
}
}
if (nsPresContext* presContext =
mFrameElement->OwnerDoc()->GetPresContext()) {
presContext->EventStateManager()->StopTrackingDragGesture(true);
}
// `BrowserChild` only sends the values to actually be changed, see more // `BrowserChild` only sends the values to actually be changed, see more
// details in `BrowserChild::SetDimensions()`. // details in `BrowserChild::SetDimensions()`.
// Note that `BrowserChild::SetDimensions()` may be called before receiving // Note that `BrowserChild::SetDimensions()` may be called before receiving
@@ -3883,8 +3897,29 @@ mozilla::ipc::IPCResult BrowserParent::RecvInvokeDragSession(
const CookieJarSettingsArgs& aCookieJarSettingsArgs, const CookieJarSettingsArgs& aCookieJarSettingsArgs,
const MaybeDiscarded<WindowContext>& aSourceWindowContext, const MaybeDiscarded<WindowContext>& aSourceWindowContext,
const MaybeDiscarded<WindowContext>& aSourceTopWindowContext) { const MaybeDiscarded<WindowContext>& aSourceTopWindowContext) {
PresShell* presShell = mFrameElement->OwnerDoc()->GetPresShell(); nsCOMPtr<nsIDragService> dragService =
if (!presShell) { do_GetService("@mozilla.org/widget/dragservice;1");
nsPresContext* presContext = mFrameElement->OwnerDoc()->GetPresContext();
const bool isValidRemoteDrag = [&]() {
if (!dragService || !presContext) {
return false;
}
if (dragService->GetIsSuppressed()) {
return false;
}
BrowserParent* dragTopLevelRemoteTarget =
presContext->EventStateManager()
->GetTrackingDragGestureTopLevelRemoteTarget();
if (NS_WARN_IF(dragTopLevelRemoteTarget != TopLevelBrowserParent())) {
return false;
}
return true;
}();
if (!isValidRemoteDrag) {
(void)SendEndDragSession(true, true, LayoutDeviceIntPoint(), 0, (void)SendEndDragSession(true, true, LayoutDeviceIntPoint(), 0,
nsIDragService::DRAGDROP_ACTION_NONE); nsIDragService::DRAGDROP_ACTION_NONE);
// Continue sending input events with input priority when stopping the dnd // Continue sending input events with input priority when stopping the dnd
@@ -3922,15 +3957,10 @@ mozilla::ipc::IPCResult BrowserParent::RecvInvokeDragSession(
} }
} }
nsCOMPtr<nsIDragService> dragService = dragService->MaybeAddBrowser(this);
do_GetService("@mozilla.org/widget/dragservice;1");
if (dragService) {
dragService->MaybeAddBrowser(this);
}
presShell->GetPresContext() presContext->EventStateManager()->BeginTrackingRemoteDragGesture(
->EventStateManager() mFrameElement, dragStartData);
->BeginTrackingRemoteDragGesture(mFrameElement, dragStartData);
nsCOMPtr<nsIObserverService> os = services::GetObserverService(); nsCOMPtr<nsIObserverService> os = services::GetObserverService();
os->NotifyObservers(nullptr, "content-invoked-drag", nullptr); os->NotifyObservers(nullptr, "content-invoked-drag", nullptr);
+2
View File
@@ -739,6 +739,7 @@ class BrowserParent final : public PBrowserParent,
mozilla::ipc::IPCResult RecvRemoteIsReadyToHandleInputEvents(); mozilla::ipc::IPCResult RecvRemoteIsReadyToHandleInputEvents();
MOZ_CAN_RUN_SCRIPT_BOUNDARY
mozilla::ipc::IPCResult RecvSetDimensions(mozilla::DimensionRequest aRequest, mozilla::ipc::IPCResult RecvSetDimensions(mozilla::DimensionRequest aRequest,
const double& aScale); const double& aScale);
@@ -758,6 +759,7 @@ class BrowserParent final : public PBrowserParent,
mozilla::ipc::IPCResult RecvMaybeFireEmbedderLoadEvents( mozilla::ipc::IPCResult RecvMaybeFireEmbedderLoadEvents(
EmbedderElementEventType aFireEventAtEmbeddingElement); EmbedderElementEventType aFireEventAtEmbeddingElement);
MOZ_CAN_RUN_SCRIPT_BOUNDARY
mozilla::ipc::IPCResult RecvRequestPointerLock( mozilla::ipc::IPCResult RecvRequestPointerLock(
const bool& aUnadjustedMovement, RequestPointerLockResolver&& aResolve); const bool& aUnadjustedMovement, RequestPointerLockResolver&& aResolve);
mozilla::ipc::IPCResult RecvReleasePointerLock(); mozilla::ipc::IPCResult RecvReleasePointerLock();
+2
View File
@@ -1169,6 +1169,8 @@ nsBaseDragService::Unsuppress() {
return NS_OK; return NS_OK;
} }
bool nsBaseDragService::GetIsSuppressed() { return mSuppressLevel > 0; }
NS_IMETHODIMP NS_IMETHODIMP
nsBaseDragSession::UserCancelled() { nsBaseDragSession::UserCancelled() {
mUserCancelled = true; mUserCancelled = true;
+5
View File
@@ -172,6 +172,11 @@ interface nsIDragService : nsISupports
void suppress(); void suppress();
void unsuppress(); void unsuppress();
/**
* True if the dragging is disabled.
*/
[notxpcom, nostdcall] readonly attribute boolean isSuppressed;
[notxpcom, nostdcall] boolean maybeAddBrowser(in BrowserParentPtr aBP); [notxpcom, nostdcall] boolean maybeAddBrowser(in BrowserParentPtr aBP);
[notxpcom, nostdcall] boolean removeAllBrowsers(); [notxpcom, nostdcall] boolean removeAllBrowsers();