From e844cdeed5d471f4908385373365a1cb1591f585 Mon Sep 17 00:00:00 2001 From: David P Date: Thu, 4 Jul 2024 07:48:11 +0000 Subject: [PATCH] Bug 1893119: Part 21 - Separate nsIDragService and nsIDragSession implementations r=gstoll,geckoview-reviewers,rkraesig,win-reviewers,m_kato Split the class inheritance trees for nsIDragService and nsIDragSession. Remember that, before the start of this patch series, the inheritance diagram was: nsDragService -> nsBaseDragService -> nsIDragService + nsIDragSession and the only instance was a singleton. We switched it to: nsDragService -> nsDragSession -> nsBaseDragService -> nsIDragService + nsBaseDragSession -> nsIDragSession and maintained the singleton. This allowed us to allow us to move things to the new classes without breaking behavior. We are done with that, so we can now change the inheritance to its final form: nsDragService -> nsBaseDragService -> nsIDragService nsDragSession -> nsBaseDragSession -> nsIDragSession Of course, we also need to properly construct and release the nsIDragSessions (formerly part of the singleton), so that is done here as well. That happens in nsBaseDrag[Service|Session] for parent process drags and in nsDrag[Service|Session]Proxy for content. This is all fairly straightforward, except in the case of gtk, where we need to change some callback behavior. Differential Revision: https://phabricator.services.mozilla.com/D211084 --- dom/ipc/BrowserChild.cpp | 21 ++- dom/ipc/BrowserChild.h | 13 ++ widget/MockDragServiceController.cpp | 22 ++- widget/android/nsDragService.cpp | 27 ++-- widget/android/nsDragService.h | 41 +++-- widget/android/nsWindow.cpp | 18 ++- widget/cocoa/nsDragService.h | 33 ++-- widget/cocoa/nsDragService.mm | 10 +- widget/gtk/nsDragService.cpp | 212 ++++++++++++-------------- widget/gtk/nsDragService.h | 55 +++---- widget/gtk/nsWindow.cpp | 56 +++++-- widget/moz.build | 1 + widget/nsBaseDragService.cpp | 195 +++++++++++++++++------ widget/nsBaseDragService.h | 207 +++++++++++++++---------- widget/nsDragServiceProxy.cpp | 116 +++++++++++++- widget/nsDragServiceProxy.h | 48 ++++-- widget/nsIDragService.idl | 22 ++- widget/nsIDragSession.idl | 6 + widget/windows/nsDragService.cpp | 40 +++-- widget/windows/nsDragService.h | 51 +++---- widget/windows/nsNativeDragTarget.cpp | 18 ++- 21 files changed, 765 insertions(+), 447 deletions(-) diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp index ad06dff04cad..0775837ed776 100644 --- a/dom/ipc/BrowserChild.cpp +++ b/dom/ipc/BrowserChild.cpp @@ -84,6 +84,7 @@ #include "nsDeviceContext.h" #include "nsDocShell.h" #include "nsDocShellLoadState.h" +#include "nsDragServiceProxy.h" #include "nsExceptionHandler.h" #include "nsFilePickerProxy.h" #include "nsFocusManager.h" @@ -502,6 +503,7 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(BrowserChild) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserChild) + NS_INTERFACE_MAP_ENTRY_CONCRETE(BrowserChild) NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome) NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) NS_INTERFACE_MAP_ENTRY(nsIWindowProvider) @@ -1919,6 +1921,15 @@ mozilla::ipc::IPCResult BrowserChild::RecvRealDragEvent( } DispatchWidgetEventViaAPZ(localEvent); + + if (aEvent.mMessage == eDragLeave || + aEvent.mMessage == eDragExit) { + // If session is still active, remove its target. + dragSession = GetDragSession(); + if (dragSession) { + static_cast(dragSession.get())->SetDragTarget(nullptr); + } + } return IPC_OK(); } @@ -1971,7 +1982,7 @@ mozilla::ipc::IPCResult BrowserChild::RecvInvokeChildDragSession( do_GetService("@mozilla.org/widget/dragservice;1")) { nsIWidget* widget = WebWidget(); dragService->StartDragSession(widget); - if (RefPtr session = nsContentUtils::GetDragSession(widget)) { + if (RefPtr session = GetDragSession()) { session->SetSourceWindowContext(aSourceWindowContext.GetMaybeDiscarded()); session->SetSourceTopWindowContext( aSourceTopWindowContext.GetMaybeDiscarded()); @@ -3889,9 +3900,11 @@ BrowserChild::ContentTransformsReceived(JSContext* aCx, } already_AddRefed BrowserChild::GetDragSession() { - RefPtr session = - nsContentUtils::GetDragSession(mPuppetWidget); - return session.forget(); + return RefPtr(mDragSession).forget(); +} + +void BrowserChild::SetDragSession(nsIDragSession* aSession) { + mDragSession = aSession; } BrowserChildMessageManager::BrowserChildMessageManager( diff --git a/dom/ipc/BrowserChild.h b/dom/ipc/BrowserChild.h index c987cee6c58b..238df55ebd23 100644 --- a/dom/ipc/BrowserChild.h +++ b/dom/ipc/BrowserChild.h @@ -85,6 +85,13 @@ class SessionStoreChild; class RequestData; class WebProgressData; +#define DOM_BROWSERCHILD_IID \ + { \ + 0x58a5775d, 0xba05, 0x45bf, { \ + 0xbd, 0xb8, 0xd7, 0x61, 0xf9, 0x01, 0x01, 0x31 \ + } \ + } + class BrowserChildMessageManager : public ContentFrameMessageManager, public nsIMessageSender, public nsSupportsWeakReference { @@ -181,6 +188,7 @@ class BrowserChild final : public nsMessageManagerScriptExecutor, return mUniqueId; } + NS_DECLARE_STATIC_IID_ACCESSOR(DOM_BROWSERCHILD_IID) NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_NSIWEBBROWSERCHROME NS_DECL_NSIINTERFACEREQUESTOR @@ -658,6 +666,7 @@ class BrowserChild final : public nsMessageManagerScriptExecutor, const Maybe aCanvasFingerprinterKnownText); already_AddRefed GetDragSession(); + void SetDragSession(nsIDragSession* aSession); mozilla::ipc::IPCResult RecvInvokeChildDragSession( const MaybeDiscarded& aSourceWindowContext, @@ -777,6 +786,8 @@ class BrowserChild final : public nsMessageManagerScriptExecutor, RefPtr mManager; RefPtr mBrowsingContext; RefPtr mStatusFilter; + RefPtr mDragSession; + Maybe mPreviousConsumedKeyDownCode; uint32_t mChromeFlags; uint32_t mMaxTouchPoints; @@ -879,6 +890,8 @@ class BrowserChild final : public nsMessageManagerScriptExecutor, DISALLOW_EVIL_CONSTRUCTORS(BrowserChild); }; +NS_DEFINE_STATIC_IID_ACCESSOR(BrowserChild, DOM_BROWSERCHILD_IID) + } // namespace dom } // namespace mozilla diff --git a/widget/MockDragServiceController.cpp b/widget/MockDragServiceController.cpp index 6b0c5dcd8fba..2be7effb650e 100644 --- a/widget/MockDragServiceController.cpp +++ b/widget/MockDragServiceController.cpp @@ -17,8 +17,8 @@ namespace mozilla::test { NS_IMPL_ISUPPORTS(MockDragServiceController, nsIMockDragServiceController) -class MockDragService : public nsBaseDragService { - public: +class MockDragSession : public nsBaseDragSession { + protected: MOZ_CAN_RUN_SCRIPT nsresult InvokeDragSessionImpl(nsIWidget* aWidget, nsIArray* aTransferableArray, const mozilla::Maybe& aRegion, @@ -50,12 +50,24 @@ class MockDragService : public nsBaseDragService { // Note that, like in non-mocked DND, we do this regardless of whether // the source and target were the same widget -- in that case, // EndDragSession is just called twice. - mDragAction = DRAGDROP_ACTION_MOVE; - StartDragSession(aWidget); + mDragAction = nsIDragService::DRAGDROP_ACTION_MOVE; return NS_OK; } +}; - bool IsMockService() override { return true; } +class MockDragService : public nsBaseDragService { + public: + NS_IMETHOD GetIsMockService(bool* aRet) override { + *aRet = true; + return NS_OK; + } + uint32_t mLastModifierKeyState = 0; + + protected: + already_AddRefed CreateDragSession() override { + RefPtr session = new MockDragSession(); + return session.forget(); + } }; static void SetDragEndPointFromScreenPoint( diff --git a/widget/android/nsDragService.cpp b/widget/android/nsDragService.cpp index 0e547bf75a33..65274c205a21 100644 --- a/widget/android/nsDragService.cpp +++ b/widget/android/nsDragService.cpp @@ -20,9 +20,6 @@ #include "nsViewManager.h" #include "nsWindow.h" -NS_IMPL_ISUPPORTS_INHERITED0(nsDragSession, nsBaseDragService) -NS_IMPL_ISUPPORTS_INHERITED0(nsDragService, nsDragSession) - using namespace mozilla; using namespace mozilla::widget; @@ -39,6 +36,11 @@ already_AddRefed nsDragService::GetInstance() { return service.forget(); } +already_AddRefed nsDragService::CreateDragSession() { + RefPtr session = new nsDragSession(); + return session.forget(); +} + static nsWindow* GetWindow(dom::Document* aDocument) { if (!aDocument) { return nullptr; @@ -63,7 +65,7 @@ static nsWindow* GetWindow(dom::Document* aDocument) { return window.get(); } -nsresult nsDragService::InvokeDragSessionImpl( +nsresult nsDragSession::InvokeDragSessionImpl( nsIWidget* aWidget, nsIArray* aTransferableArray, const Maybe& aRegion, uint32_t aActionType) { if (jni::GetAPIVersion() < 24) { @@ -90,7 +92,6 @@ nsresult nsDragService::InvokeDragSessionImpl( if (nsWindow* window = GetWindow(mSourceDocument)) { mTransferable = transferable; - nsBaseDragService::StartDragSession(aWidget); OpenDragPopup(); auto bitmap = CreateDragImage(mSourceNode, aRegion); @@ -230,18 +231,12 @@ void nsDragSession::SetData(nsITransferable* aTransferable) { mDataTransfer = nullptr; } -// static -void nsDragService::SetDropData( +void nsDragSession::SetDropData( mozilla::java::GeckoDragAndDrop::DropData::Param aDropData) { MOZ_ASSERT(NS_IsMainThread()); - RefPtr dragService = nsDragService::GetInstance(); - if (!dragService) { - return; - } - if (!aDropData) { - dragService->SetData(nullptr); + SetData(nullptr); return; } @@ -254,7 +249,7 @@ void nsDragService::SetDropData( if (!mime.EqualsLiteral("text/plain") && !mime.EqualsLiteral("text/html")) { // Not supported data. - dragService->SetData(nullptr); + SetData(nullptr); return; } @@ -263,12 +258,12 @@ void nsDragService::SetDropData( nsPrimitiveHelpers::CreatePrimitiveForData( mime, buffer.get(), buffer.Length() * 2, getter_AddRefs(wrapper)); if (!wrapper) { - dragService->SetData(nullptr); + SetData(nullptr); return; } nsCOMPtr transferable = do_CreateInstance("@mozilla.org/widget/transferable;1"); transferable->Init(nullptr); transferable->SetTransferData(mime.get(), wrapper); - dragService->SetData(transferable); + SetData(transferable); } diff --git a/widget/android/nsDragService.h b/widget/android/nsDragService.h index a3cda0c9f061..0fc2757123e6 100644 --- a/widget/android/nsDragService.h +++ b/widget/android/nsDragService.h @@ -13,15 +13,11 @@ class nsITransferable; -// Temporary inheritance from nsBaseDragService instead of nsBaseDragSession -// (which nsBaseDragService temporarily inherits). -// This will be undone at the end of this patch series. -class nsDragSession : public nsBaseDragService { +/** + * Android native nsIDragSession implementation + */ +class nsDragSession : public nsBaseDragSession { public: - nsDragSession() = default; - - NS_DECL_ISUPPORTS_INHERITED - // nsIDragSession NS_IMETHOD GetData(nsITransferable* aTransferable, uint32_t anItem) override; NS_IMETHOD GetNumDropItems(uint32_t* aNumItems) override; @@ -32,6 +28,8 @@ class nsDragSession : public nsBaseDragService { void SetData(nsITransferable* aTransferable); + void SetDropData(mozilla::java::GeckoDragAndDrop::DropData::Param aDropData); + virtual bool MustUpdateDataTransfer(mozilla::EventMessage aMessage) override; MOZ_CAN_RUN_SCRIPT nsresult EndDragSessionImpl( @@ -40,6 +38,12 @@ class nsDragSession : public nsBaseDragService { protected: virtual ~nsDragSession() = default; + // nsBaseDragSession + MOZ_CAN_RUN_SCRIPT nsresult + InvokeDragSessionImpl(nsIWidget* aWidget, nsIArray* anArrayTransferables, + const mozilla::Maybe& aRegion, + uint32_t aActionType) override; + mozilla::java::sdk::Bitmap::LocalRef CreateDragImage( nsINode* aNode, const mozilla::Maybe& aRegion); @@ -47,26 +51,15 @@ class nsDragSession : public nsBaseDragService { nsCOMPtr mTransferable; }; -// Temporary inheritance from nsDragSession instead of nsBaseDragService -// (which nsDragSession temporarily inherits). -// This will be undone at the end of this patch series. -class nsDragService final : public nsDragSession { +/** + * Android native nsIDragService implementation + */ +class nsDragService final : public nsBaseDragService { public: static already_AddRefed GetInstance(); - NS_DECL_ISUPPORTS_INHERITED - - static void SetDropData( - mozilla::java::GeckoDragAndDrop::DropData::Param aDropData); - protected: - virtual ~nsDragService() = default; - - // nsBaseDragService - MOZ_CAN_RUN_SCRIPT nsresult - InvokeDragSessionImpl(nsIWidget* aWidget, nsIArray* anArrayTransferables, - const mozilla::Maybe& aRegion, - uint32_t aActionType) override; + already_AddRefed CreateDragSession() override; }; #endif // nsDragService_h__ diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index cf8aae548468..9e59a4000ee1 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -2677,15 +2677,16 @@ void nsWindow::OnDragEvent(int32_t aAction, int64_t aTime, float aX, float aY, jni::Object::Param aDropData) { MOZ_ASSERT(NS_IsMainThread()); + LayoutDeviceIntPoint point = + LayoutDeviceIntPoint(int32_t(floorf(aX)), int32_t(floorf(aY))); + RefPtr dragService = nsDragService::GetInstance(); if (!dragService) { return; } - LayoutDeviceIntPoint point = - LayoutDeviceIntPoint(int32_t(floorf(aX)), int32_t(floorf(aY))); - - nsCOMPtr dragSession = dragService->GetCurrentSession(this); + RefPtr dragSession = + static_cast(dragService->GetCurrentSession(this)); if (dragSession && aAction == java::sdk::DragEvent::ACTION_DRAG_STARTED) { dragSession->SetDragEndPoint(point.x, point.y); return; @@ -2702,10 +2703,13 @@ void nsWindow::OnDragEvent(int32_t aAction, int64_t aTime, float aX, float aY, nsIWidget* widget = this; dragService->StartDragSession(widget); // For compatibility, we have to set temporary data. + dragSession = + static_cast(dragService->GetCurrentSession(this)); + MOZ_ASSERT(dragSession); + auto dropData = mozilla::java::GeckoDragAndDrop::DropData::Ref::From(aDropData); - nsDragService::SetDropData(dropData); - dragSession = dragService->GetCurrentSession(this); + dragSession->SetDropData(dropData); } if (dragSession) { @@ -2727,7 +2731,7 @@ void nsWindow::OnDragEvent(int32_t aAction, int64_t aTime, float aX, float aY, } auto dropData = mozilla::java::GeckoDragAndDrop::DropData::Ref::From(aDropData); - nsDragService::SetDropData(dropData); + dragSession->SetDropData(dropData); dragSession->SetDragEndPoint(point.x, point.y); break; } diff --git a/widget/cocoa/nsDragService.h b/widget/cocoa/nsDragService.h index 9307cc7da4f1..0eefe91e55a3 100644 --- a/widget/cocoa/nsDragService.h +++ b/widget/cocoa/nsDragService.h @@ -11,10 +11,10 @@ #include -// Temporary inheritance from nsBaseDragService instead of nsBaseDragSession -// (which nsBaseDragService temporarily inherits). -// This will be undone at the end of this patch series. -class nsDragSession : public nsBaseDragService { +/** + * Cocoa native nsIDragSession implementation + */ +class nsDragSession : public nsBaseDragSession { public: // nsIDragSession NS_IMETHOD GetData(nsITransferable* aTransferable, @@ -34,6 +34,12 @@ class nsDragSession : public nsBaseDragService { bool aDoneDrag, uint32_t aKeyModifiers) override; protected: + // nsBaseDragSession + MOZ_CAN_RUN_SCRIPT virtual nsresult InvokeDragSessionImpl( + nsIWidget* aWidget, nsIArray* anArrayTransferables, + const mozilla::Maybe& aRegion, + uint32_t aActionType) override; + // Creates and returns the drag image for a drag. aImagePoint will be set to // the origin of the drag relative to mNativeDragView. NSImage* ConstructDragImage( @@ -59,21 +65,12 @@ class nsDragSession : public nsBaseDragService { bool mDragImageChanged = false; }; -// Temporary inheritance from nsDragSession instead of nsBaseDragService -// (which nsDragSession temporarily inherits). -// This will be undone at the end of this patch series. -class nsDragService final : public nsDragSession { +/** + * Cocoa native nsIDragService implementation + */ +class nsDragService final : public nsBaseDragService { public: - nsDragService(); - - // nsBaseDragService - MOZ_CAN_RUN_SCRIPT virtual nsresult InvokeDragSessionImpl( - nsIWidget* aWidget, nsIArray* anArrayTransferables, - const mozilla::Maybe& aRegion, - uint32_t aActionType) override; - - protected: - virtual ~nsDragService(); + already_AddRefed CreateDragSession() override; }; #endif // nsDragService_h_ diff --git a/widget/cocoa/nsDragService.mm b/widget/cocoa/nsDragService.mm index 6aaf842ab846..0f6ea216a0fe 100644 --- a/widget/cocoa/nsDragService.mm +++ b/widget/cocoa/nsDragService.mm @@ -44,9 +44,10 @@ extern bool gUserCancelledDrag; // file destination callback. mozilla::StaticRefPtr gDraggedTransferables; -nsDragService::nsDragService() {} - -nsDragService::~nsDragService() {} +already_AddRefed nsDragService::CreateDragSession() { + RefPtr sess = new nsDragSession(); + return sess.forget(); +} NSImage* nsDragSession::ConstructDragImage(nsINode* aDOMNode, const Maybe& aRegion, @@ -177,7 +178,7 @@ NSImage* nsDragSession::ConstructDragImage(nsINode* aDOMNode, NS_OBJC_END_TRY_BLOCK_RETURN(nil); } -nsresult nsDragService::InvokeDragSessionImpl( +nsresult nsDragSession::InvokeDragSessionImpl( nsIWidget* aWidget, nsIArray* aTransferableArray, const Maybe& aRegion, uint32_t aActionType) { NS_OBJC_BEGIN_TRY_BLOCK_RETURN; @@ -250,7 +251,6 @@ nsresult nsDragService::InvokeDragSessionImpl( [pbItem release]; [dragItem setDraggingFrame:localDragRect contents:image]; - nsBaseDragService::StartDragSession(aWidget); OpenDragPopup(); mNSDraggingSession = [mNativeDragView diff --git a/widget/gtk/nsDragService.cpp b/widget/gtk/nsDragService.cpp index 4582d40385b5..6723c24d5dd5 100644 --- a/widget/gtk/nsDragService.cpp +++ b/widget/gtk/nsDragService.cpp @@ -31,6 +31,7 @@ #include "mozilla/PresShell.h" #include "mozilla/ScopeExit.h" #include "mozilla/AutoRestore.h" +#include "mozilla/WidgetUtils.h" #include "mozilla/WidgetUtilsGtk.h" #include "GRefPtr.h" #include "nsAppShell.h" @@ -519,7 +520,7 @@ void DragData::Print() const { /* static */ int nsDragSession::sEventLoopDepth = 0; -nsDragService::nsDragService() { +nsDragSession::nsDragSession() { // We have to destroy the hidden widget before the event loop stops // running. nsCOMPtr obsServ = @@ -580,8 +581,8 @@ nsDragService::nsDragService() { LOGDRAGSERVICE("nsDragService::nsDragService"); } -nsDragService::~nsDragService() { - LOGDRAGSERVICE("nsDragService::~nsDragService"); +nsDragSession::~nsDragSession() { + LOGDRAGSERVICE("nsDragSession::~nsDragSession"); if (mTaskSource) g_source_remove(mTaskSource); if (mTempFileTimerID) { g_source_remove(mTempFileTimerID); @@ -589,7 +590,7 @@ nsDragService::~nsDragService() { } } -NS_IMPL_ISUPPORTS_INHERITED(nsDragService, nsBaseDragService, nsIObserver) +NS_IMPL_ISUPPORTS_INHERITED(nsDragSession, nsBaseDragSession, nsIObserver) mozilla::StaticRefPtr sDragServiceInstance; /* static */ @@ -606,13 +607,18 @@ already_AddRefed nsDragService::GetInstance() { return service.forget(); } +already_AddRefed nsDragService::CreateDragSession() { + RefPtr session = new nsDragSession(); + return session.forget(); +} + // nsIObserver NS_IMETHODIMP -nsDragService::Observe(nsISupports* aSubject, const char* aTopic, +nsDragSession::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) { if (!nsCRT::strcmp(aTopic, "quit-application")) { - LOGDRAGSERVICE("nsDragService::Observe(\"quit-application\")"); + LOGDRAGSERVICE("nsDragSession::Observe(\"quit-application\")"); if (mHiddenWidget) { gtk_widget_destroy(mHiddenWidget); mHiddenWidget = 0; @@ -725,15 +731,13 @@ static GtkWindow* GetGtkWindow(dom::Document* aDocument) { return GTK_WINDOW(toplevel); } -// nsIDragService - NS_IMETHODIMP -nsDragService::InvokeDragSession( +nsDragSession::InvokeDragSession( nsIWidget* aWidget, nsINode* aDOMNode, nsIPrincipal* aPrincipal, nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings, nsIArray* aArrayTransferables, uint32_t aActionType, nsContentPolicyType aContentPolicyType = nsIContentPolicy::TYPE_OTHER) { - LOGDRAGSERVICE("nsDragService::InvokeDragSession"); + LOGDRAGSERVICE("nsDragSession::InvokeDragSession"); // If the previous source drag has not yet completed, signal handlers need // to be removed from sGrabWidget and dragend needs to be dispatched to @@ -741,13 +745,13 @@ nsDragService::InvokeDragSession( // know whether or not the drag succeeded. if (mSourceNode) return NS_ERROR_NOT_AVAILABLE; - return nsBaseDragService::InvokeDragSession( + return nsBaseDragSession::InvokeDragSession( aWidget, aDOMNode, aPrincipal, aCsp, aCookieJarSettings, aArrayTransferables, aActionType, aContentPolicyType); } -// nsBaseDragService -nsresult nsDragService::InvokeDragSessionImpl( +// nsBaseDragSession +nsresult nsDragSession::InvokeDragSessionImpl( nsIWidget* aWidget, nsIArray* aArrayTransferables, const Maybe& aRegion, uint32_t aActionType) { // make sure that we have an array of transferables to use @@ -757,7 +761,7 @@ nsresult nsDragService::InvokeDragSessionImpl( // length of this call mSourceDataItems = aArrayTransferables; - LOGDRAGSERVICE("nsDragService::InvokeDragSessionImpl"); + LOGDRAGSERVICE("nsDragSession::InvokeDragSessionImpl"); GdkDevice* device = widget::GdkGetPointer(); GdkWindow* originGdkWindow = nullptr; @@ -768,7 +772,7 @@ nsresult nsDragService::InvokeDragSessionImpl( // Check we have GdkWindow drag source. if (!originGdkWindow) { NS_WARNING( - "nsDragService::InvokeDragSessionImpl(): Missing origin GdkWindow!"); + "nsDragSession::InvokeDragSessionImpl(): Missing origin GdkWindow!"); return NS_ERROR_FAILURE; } } @@ -781,11 +785,11 @@ nsresult nsDragService::InvokeDragSessionImpl( // save our action type GdkDragAction action = GDK_ACTION_DEFAULT; - if (aActionType & DRAGDROP_ACTION_COPY) + if (aActionType & nsIDragService::DRAGDROP_ACTION_COPY) action = (GdkDragAction)(action | GDK_ACTION_COPY); - if (aActionType & DRAGDROP_ACTION_MOVE) + if (aActionType & nsIDragService::DRAGDROP_ACTION_MOVE) action = (GdkDragAction)(action | GDK_ACTION_MOVE); - if (aActionType & DRAGDROP_ACTION_LINK) + if (aActionType & nsIDragService::DRAGDROP_ACTION_LINK) action = (GdkDragAction)(action | GDK_ACTION_LINK); GdkEvent* existingEvent = widget::GetLastMousePressEvent(); @@ -826,8 +830,6 @@ nsresult nsDragService::InvokeDragSessionImpl( nsresult rv; if (context) { - StartDragSession(aWidget); - // GTK uses another hidden window for receiving mouse events. sGrabWidget = gtk_window_group_get_current_grab(window_group); if (sGrabWidget) { @@ -849,7 +851,7 @@ nsresult nsDragService::InvokeDragSessionImpl( return rv; } -bool nsDragService::SetAlphaPixmap(SourceSurface* aSurface, +bool nsDragSession::SetAlphaPixmap(SourceSurface* aSurface, GdkDragContext* aContext, int32_t aXOffset, int32_t aYOffset, const LayoutDeviceIntRect& dragRect) { @@ -902,7 +904,6 @@ bool nsDragService::SetAlphaPixmap(SourceSurface* aSurface, NS_IMETHODIMP nsDragService::StartDragSession(nsISupports* aWidgetProvider) { LOGDRAGSERVICE("nsDragService::StartDragSession"); - mTempFileUrls.Clear(); return nsBaseDragService::StartDragSession(aWidgetProvider); } @@ -943,7 +944,6 @@ gboolean nsDragSession::TaskRemoveTempFiles(gpointer data) { // We manually deref it here. RefPtr session = static_cast(data); session.get()->Release(); - RefPtr dragService = static_cast(data); return session->RemoveTempFiles(); } @@ -968,7 +968,7 @@ nsresult nsDragSession::EndDragSessionImpl(bool aDoneDrag, } // unset our drag action - SetDragAction(DRAGDROP_ACTION_NONE); + SetDragAction(nsIDragService::DRAGDROP_ACTION_NONE); // start timer to remove temporary files if (mTemporaryFiles.Count() > 0 && !mTempFileTimerID) { @@ -1297,15 +1297,15 @@ void nsDragSession::ReplyToDragMotion(GdkDragContext* aDragContext, if (mCanDrop) { // notify the dragger if we can drop switch (mDragAction) { - case DRAGDROP_ACTION_COPY: + case nsIDragService::DRAGDROP_ACTION_COPY: LOGDRAGSERVICE(" set explicit action copy"); action = GDK_ACTION_COPY; break; - case DRAGDROP_ACTION_LINK: + case nsIDragService::DRAGDROP_ACTION_LINK: LOGDRAGSERVICE(" set explicit action link"); action = GDK_ACTION_LINK; break; - case DRAGDROP_ACTION_NONE: + case nsIDragService::DRAGDROP_ACTION_NONE: LOGDRAGSERVICE(" set explicit action none"); action = (GdkDragAction)0; break; @@ -1345,7 +1345,7 @@ void nsDragSession::ReplyToDragMotion(GdkDragContext* aDragContext, gdk_drag_status(aDragContext, action, aTime); } -void nsDragService::SetCachedDragContext(GdkDragContext* aDragContext) { +void nsDragSession::SetCachedDragContext(GdkDragContext* aDragContext) { LOGDRAGSERVICE("nsDragService::SetCachedDragContext(): [drag %p / cached %p]", aDragContext, (void*)mCachedDragContext); // Clear cache data if we're going to D&D with different drag context. @@ -1371,7 +1371,7 @@ bool nsDragSession::IsTargetContextList(void) { return IsDragFlavorAvailable(sMimeListTypeAtom); } -bool nsDragService::IsDragFlavorAvailable(GdkAtom aRequestedFlavor) { +bool nsDragSession::IsDragFlavorAvailable(GdkAtom aRequestedFlavor) { if (mCachedDragFlavors.IsEmpty()) { for (GList* tmp = gdk_drag_context_list_targets(mTargetDragContext); tmp; tmp = tmp->next) { @@ -1388,7 +1388,7 @@ bool nsDragService::IsDragFlavorAvailable(GdkAtom aRequestedFlavor) { // Spins event loop, called from eDragTaskMotion handler by // DispatchMotionEvents(). // Can lead to another round of drag_motion events. -RefPtr nsDragService::GetDragData(GdkAtom aRequestedFlavor) { +RefPtr nsDragSession::GetDragData(GdkAtom aRequestedFlavor) { LOGDRAGSERVICE("nsDragService::GetDragData(%p) requested '%s'\n", mTargetDragContext.get(), GUniquePtr(gdk_atom_name(aRequestedFlavor)).get()); @@ -1455,7 +1455,7 @@ RefPtr nsDragService::GetDragData(GdkAtom aRequestedFlavor) { return nullptr; } -void nsDragService::TargetDataReceived(GtkWidget* aWidget, +void nsDragSession::TargetDataReceived(GtkWidget* aWidget, GdkDragContext* aContext, gint aX, gint aY, GtkSelectionData* aSelectionData, @@ -1558,7 +1558,7 @@ static bool CanExportAsURLTarget(const char16_t* aURLData, uint32_t aURLLen) { return true; } -GtkTargetList* nsDragService::GetSourceList(void) { +GtkTargetList* nsDragSession::GetSourceList(void) { if (!mSourceDataItems) { return nullptr; } @@ -1691,7 +1691,7 @@ GtkTargetList* nsDragService::GetSourceList(void) { return targetList; } -void nsDragService::SourceEndDragSession(GdkDragContext* aContext, +void nsDragSession::SourceEndDragSession(GdkDragContext* aContext, gint aResult) { LOGDRAGSERVICE("SourceEndDragSession(%p) result %s\n", aContext, kGtkDragResults[aResult]); @@ -1722,10 +1722,7 @@ void nsDragService::SourceEndDragSession(GdkDragContext* aContext, gdk_window_get_device_position( gdkWindow, gdk_drag_context_get_device(aContext), &x, &y, nullptr); gint scale = gdk_window_get_scale_factor(gdkWindow); - nsCOMPtr session = GetCurrentSession(mSourceWindow); - if (session) { - session->SetDragEndPoint(x * scale, y * scale); - } + SetDragEndPoint(x * scale, y * scale); LOGDRAGSERVICE(" guess drag end point %d %d\n", x * scale, y * scale); } @@ -1750,23 +1747,23 @@ void nsDragService::SourceEndDragSession(GdkDragContext* aContext, // unusual action combinations as NONE. if (!action) { LOGDRAGSERVICE(" drop action is none"); - dropEffect = DRAGDROP_ACTION_NONE; + dropEffect = nsIDragService::DRAGDROP_ACTION_NONE; } else if (action & GDK_ACTION_COPY) { LOGDRAGSERVICE(" drop action is copy"); - dropEffect = DRAGDROP_ACTION_COPY; + dropEffect = nsIDragService::DRAGDROP_ACTION_COPY; } else if (action & GDK_ACTION_LINK) { LOGDRAGSERVICE(" drop action is link"); - dropEffect = DRAGDROP_ACTION_LINK; + dropEffect = nsIDragService::DRAGDROP_ACTION_LINK; } else if (action & GDK_ACTION_MOVE) { LOGDRAGSERVICE(" drop action is move"); - dropEffect = DRAGDROP_ACTION_MOVE; + dropEffect = nsIDragService::DRAGDROP_ACTION_MOVE; } else { LOGDRAGSERVICE(" drop action is copy"); - dropEffect = DRAGDROP_ACTION_COPY; + dropEffect = nsIDragService::DRAGDROP_ACTION_COPY; } } else { LOGDRAGSERVICE(" drop action is none"); - dropEffect = DRAGDROP_ACTION_NONE; + dropEffect = nsIDragService::DRAGDROP_ACTION_NONE; if (aResult != GTK_DRAG_RESULT_NO_TARGET) { LOGDRAGSERVICE(" drop is user chancelled\n"); mUserCancelled = true; @@ -1778,7 +1775,8 @@ void nsDragService::SourceEndDragSession(GdkDragContext* aContext, } // Schedule the appropriate drag end dom events. - Schedule(eDragTaskSourceEnd, nullptr, nullptr, LayoutDeviceIntPoint(), 0); + Schedule(eDragTaskSourceEnd, mTargetWindow, nullptr, LayoutDeviceIntPoint(), + 0); } static nsresult GetDownloadDetails(nsITransferable* aTransferable, @@ -1837,9 +1835,9 @@ static nsresult GetDownloadDetails(nsITransferable* aTransferable, } // See nsContentAreaDragDropDataProvider::GetFlavorData() for reference. -nsresult nsDragService::CreateTempFile(nsITransferable* aItem, +nsresult nsDragSession::CreateTempFile(nsITransferable* aItem, nsACString& aURI) { - LOGDRAGSERVICE("nsDragService::CreateTempFile()"); + LOGDRAGSERVICE("nsDragSession::CreateTempFile()"); nsCOMPtr tmpDir; nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpDir)); @@ -1973,7 +1971,7 @@ nsresult nsDragService::CreateTempFile(nsITransferable* aItem, return NS_OK; } -bool nsDragService::SourceDataAppendURLFileItem(nsACString& aURI, +bool nsDragSession::SourceDataAppendURLFileItem(nsACString& aURI, nsITransferable* aItem) { // If there is a file available, create a URI from the file. nsCOMPtr data; @@ -1990,7 +1988,7 @@ bool nsDragService::SourceDataAppendURLFileItem(nsACString& aURI, return false; } -bool nsDragService::SourceDataAppendURLItem(nsITransferable* aItem, +bool nsDragSession::SourceDataAppendURLItem(nsITransferable* aItem, bool aExternalDrop, nsACString& aURI) { nsCOMPtr data; @@ -2035,7 +2033,7 @@ bool nsDragService::SourceDataAppendURLItem(nsITransferable* aItem, return NS_SUCCEEDED(CreateTempFile(aItem, aURI)); } -void nsDragService::SourceDataGetUriList(GdkDragContext* aContext, +void nsDragSession::SourceDataGetUriList(GdkDragContext* aContext, GtkSelectionData* aSelectionData, uint32_t aDragItems) { // Check if we're transfering data to another application. @@ -2047,7 +2045,7 @@ void nsDragService::SourceDataGetUriList(GdkDragContext* aContext, ? !nsWindow::GetWindow(gdk_drag_context_get_dest_window(aContext)) : !gdk_drag_context_get_dest_window(aContext); - LOGDRAGSERVICE("nsDragService::SourceDataGetUriLists() len %d external %d", + LOGDRAGSERVICE("nsDragSession::SourceDataGetUriLists() len %d external %d", aDragItems, isExternalDrop); // Disable processing of native events until we store all files to /tmp. @@ -2081,9 +2079,9 @@ void nsDragService::SourceDataGetUriList(GdkDragContext* aContext, uriList.Length()); } -void nsDragService::SourceDataGetImage(nsITransferable* aItem, +void nsDragSession::SourceDataGetImage(nsITransferable* aItem, GtkSelectionData* aSelectionData) { - LOGDRAGSERVICE("nsDragService::SourceDataGetImage()"); + LOGDRAGSERVICE("nsDragSession::SourceDataGetImage()"); nsresult rv; nsCOMPtr data; @@ -2106,10 +2104,10 @@ void nsDragService::SourceDataGetImage(nsITransferable* aItem, return; } -void nsDragService::SourceDataGetXDND(nsITransferable* aItem, +void nsDragSession::SourceDataGetXDND(nsITransferable* aItem, GdkDragContext* aContext, GtkSelectionData* aSelectionData) { - LOGDRAGSERVICE("nsDragService::SourceDataGetXDND"); + LOGDRAGSERVICE("nsDragSession::SourceDataGetXDND"); // Indicate failure by default. GdkAtom target = gtk_selection_data_get_target(aSelectionData); @@ -2200,11 +2198,11 @@ void nsDragService::SourceDataGetXDND(nsITransferable* aItem, return; } -bool nsDragService::SourceDataGetText(nsITransferable* aItem, +bool nsDragSession::SourceDataGetText(nsITransferable* aItem, const nsACString& aMIMEType, bool aNeedToDoConversionToPlainText, GtkSelectionData* aSelectionData) { - LOGDRAGSERVICE("nsDragService::SourceDataGetPlain()"); + LOGDRAGSERVICE("nsDragSession::SourceDataGetPlain()"); nsresult rv; nsCOMPtr data; @@ -2248,11 +2246,11 @@ bool nsDragService::SourceDataGetText(nsITransferable* aItem, // GtkSelectionData (Gtk D&D interface). // We need to check mSourceDataItems data type and try to convert it // to data type accepted by Gtk. -void nsDragService::SourceDataGet(GtkWidget* aWidget, GdkDragContext* aContext, +void nsDragSession::SourceDataGet(GtkWidget* aWidget, GdkDragContext* aContext, GtkSelectionData* aSelectionData, guint32 aTime) { GdkAtom requestedFlavor = gtk_selection_data_get_target(aSelectionData); - LOGDRAGSERVICE("nsDragService::SourceDataGet(%p) MIME %s", aContext, + LOGDRAGSERVICE("nsDragSession::SourceDataGet(%p) MIME %s", aContext, GUniquePtr(gdk_atom_name(requestedFlavor)).get()); // check to make sure that we have data items to return. @@ -2321,8 +2319,8 @@ void nsDragService::SourceDataGet(GtkWidget* aWidget, GdkDragContext* aContext, /* aNeedToDoConversionToPlainText */ false, aSelectionData); } -void nsDragService::SourceBeginDrag(GdkDragContext* aContext) { - LOGDRAGSERVICE("nsDragService::SourceBeginDrag(%p)\n", aContext); +void nsDragSession::SourceBeginDrag(GdkDragContext* aContext) { + LOGDRAGSERVICE("nsDragSession::SourceBeginDrag(%p)\n", aContext); nsCOMPtr transferable = do_QueryElementAt(mSourceDataItems, 0); @@ -2364,10 +2362,10 @@ void nsDragService::SourceBeginDrag(GdkDragContext* aContext) { } } -void nsDragService::SetDragIcon(GdkDragContext* aContext) { +void nsDragSession::SetDragIcon(GdkDragContext* aContext) { if (!mHasImage && !mSelection) return; - LOGDRAGSERVICE("nsDragService::SetDragIcon(%p)", aContext); + LOGDRAGSERVICE("nsDragSession::SetDragIcon(%p)", aContext); LayoutDeviceIntRect dragRect; nsPresContext* pc; @@ -2445,10 +2443,10 @@ void nsDragService::SetDragIcon(GdkDragContext* aContext) { static void invisibleSourceDragBegin(GtkWidget* aWidget, GdkDragContext* aContext, gpointer aData) { LOGDRAGSERVICESTATIC("invisibleSourceDragBegin (%p)", aContext); - nsDragService* dragService = (nsDragService*)aData; + nsDragSession* dragSession = (nsDragSession*)aData; - dragService->SourceBeginDrag(aContext); - dragService->SetDragIcon(aContext); + dragSession->SourceBeginDrag(aContext); + dragSession->SetDragIcon(aContext); } static void invisibleSourceDragDataGet(GtkWidget* aWidget, @@ -2457,15 +2455,13 @@ static void invisibleSourceDragDataGet(GtkWidget* aWidget, guint aInfo, guint32 aTime, gpointer aData) { LOGDRAGSERVICESTATIC("invisibleSourceDragDataGet (%p)", aContext); - nsDragService* dragService = (nsDragService*)aData; - dragService->SourceDataGet(aWidget, aContext, aSelectionData, aTime); + nsDragSession* dragSession = (nsDragSession*)aData; + dragSession->SourceDataGet(aWidget, aContext, aSelectionData, aTime); } static gboolean invisibleSourceDragFailed(GtkWidget* aWidget, GdkDragContext* aContext, gint aResult, gpointer aData) { - nsDragService* dragService = (nsDragService*)aData; - // Wayland and X11 uses different drag results here. When drag target is // missing X11 passes GDK_DRAG_CANCEL_NO_TARGET // (from gdk_dnd_handle_button_event()/gdkdnd-x11.c) @@ -2482,10 +2478,11 @@ static gboolean invisibleSourceDragFailed(GtkWidget* aWidget, LOGDRAGSERVICESTATIC("invisibleSourceDragFailed(%p) %s", aContext, kGtkDragResults[aResult]); + nsDragSession* dragSession = (nsDragSession*)aData; // End the drag session now (rather than waiting for the drag-end signal) // so that operations performed on dropEffect == none can start immediately // rather than waiting for the drag-failed animation to finish. - dragService->SourceEndDragSession(aContext, aResult); + dragSession->SourceEndDragSession(aContext, aResult); // We should return TRUE to disable the drag-failed animation iff the // source performed an operation when dropEffect was none, but the handler @@ -2496,10 +2493,10 @@ static gboolean invisibleSourceDragFailed(GtkWidget* aWidget, static void invisibleSourceDragEnd(GtkWidget* aWidget, GdkDragContext* aContext, gpointer aData) { LOGDRAGSERVICESTATIC("invisibleSourceDragEnd(%p)", aContext); - nsDragService* dragService = (nsDragService*)aData; + nsDragSession* dragSession = (nsDragSession*)aData; // The drag has ended. Release the hostages! - dragService->SourceEndDragSession(aContext, GTK_DRAG_RESULT_SUCCESS); + dragSession->SourceEndDragSession(aContext, GTK_DRAG_RESULT_SUCCESS); } // The following methods handle responding to GTK drag signals and @@ -2543,7 +2540,7 @@ static void invisibleSourceDragEnd(GtkWidget* aWidget, GdkDragContext* aContext, // Gecko drag events are in flight. This helps event handlers that may not // expect nested events, while accessing an event's dataTransfer for example. -gboolean nsDragService::ScheduleMotionEvent(nsWindow* aWindow, +gboolean nsDragSession::ScheduleMotionEvent(nsWindow* aWindow, GdkDragContext* aDragContext, LayoutDeviceIntPoint aWindowPoint, guint aTime) { @@ -2561,7 +2558,7 @@ gboolean nsDragService::ScheduleMotionEvent(nsWindow* aWindow, return Schedule(eDragTaskMotion, aWindow, aDragContext, aWindowPoint, aTime); } -void nsDragService::ScheduleLeaveEvent() { +void nsDragSession::ScheduleLeaveEvent() { // We don't know at this stage whether a drop signal will immediately // follow. If the drop signal gets sent it will happen before we return // to the main loop and the scheduled leave task will be replaced. @@ -2570,7 +2567,7 @@ void nsDragService::ScheduleLeaveEvent() { } } -gboolean nsDragService::ScheduleDropEvent(nsWindow* aWindow, +gboolean nsDragSession::ScheduleDropEvent(nsWindow* aWindow, GdkDragContext* aDragContext, LayoutDeviceIntPoint aWindowPoint, guint aTime) { @@ -2579,17 +2576,14 @@ gboolean nsDragService::ScheduleDropEvent(nsWindow* aWindow, return FALSE; } - nsCOMPtr session = GetCurrentSession(aWindow); - if (session) { - session->SetDragEndPoint(aWindowPoint.x, aWindowPoint.y); - } + SetDragEndPoint(aWindowPoint.x, aWindowPoint.y); // We'll reply with gtk_drag_finish(). return TRUE; } #ifdef MOZ_LOGGING -const char* nsDragService::GetDragServiceTaskName(DragTask aTask) { +const char* nsDragSession::GetDragServiceTaskName(DragTask aTask) { static const char* taskNames[] = {"eDragTaskNone", "eDragTaskMotion", "eDragTaskLeave", "eDragTaskDrop", "eDragTaskSourceEnd"}; @@ -2598,7 +2592,7 @@ const char* nsDragService::GetDragServiceTaskName(DragTask aTask) { } #endif -gboolean nsDragService::Schedule(DragTask aTask, nsWindow* aWindow, +gboolean nsDragSession::Schedule(DragTask aTask, nsWindow* aWindow, GdkDragContext* aDragContext, LayoutDeviceIntPoint aWindowPoint, guint aTime) { @@ -2611,7 +2605,7 @@ gboolean nsDragService::Schedule(DragTask aTask, nsWindow* aWindow, // within the allowed time). Otherwise, if we haven't yet run a scheduled // drop or end task, just say that we are not ready to receive another // drop. - LOGDRAGSERVICE("nsDragService::Schedule(%p) task %s window %p\n", + LOGDRAGSERVICE("nsDragSession::Schedule(%p) task %s window %p\n", aDragContext, GetDragServiceTaskName(aTask), aWindow); if (mScheduledTask == eDragTaskSourceEnd || @@ -2632,7 +2626,7 @@ gboolean nsDragService::Schedule(DragTask aTask, nsWindow* aWindow, // right after drag_motion event handler which is called by Gtk. // An ideal scenario is to call TaskDispatchCallback() directly here // but we can't do that. TaskDispatchCallback() spins gtk event loop - // while nsDragService::Schedule() is already called from event loop + // while nsDragSession::Schedule() is already called from event loop // (by drag_motion* gtk_widget events) so that direct call will cause // nested recursion. mTaskSource = g_timeout_add_full(G_PRIORITY_HIGH, 0, TaskDispatchCallback, @@ -2649,15 +2643,17 @@ gboolean nsDragService::Schedule(DragTask aTask, nsWindow* aWindow, return TRUE; } -gboolean nsDragService::TaskDispatchCallback(gpointer data) { - RefPtr dragService = static_cast(data); - AutoEventLoop loop(dragService); - return dragService->RunScheduledTask(); +gboolean nsDragSession::TaskDispatchCallback(gpointer data) { + // Make sure we hold a strong reference to the session while we process + // the task. + RefPtr dragSession = static_cast(data); + AutoEventLoop loop(dragSession); + return dragSession->RunScheduledTask(); } -gboolean nsDragService::RunScheduledTask() { +gboolean nsDragSession::RunScheduledTask() { LOGDRAGSERVICE( - "nsDragService::RunScheduledTask() task %s mTargetWindow %p " + "nsDragSession::RunScheduledTask() task %s mTargetWindow %p " "mPendingWindow %p\n", GetDragServiceTaskName(mScheduledTask), mTargetWindow.get(), mPendingWindow.get()); @@ -2679,10 +2675,7 @@ gboolean nsDragService::RunScheduledTask() { // The drag that was initiated in a different app. End the drag // session, since we're done with it for now (until the user drags // back into this app). - RefPtr session = GetCurrentSession(mTargetWindow); - if (session) { - session->EndDragSession(false, GetCurrentModifiers()); - } + EndDragSession(false, GetCurrentModifiers()); } } @@ -2704,10 +2697,7 @@ gboolean nsDragService::RunScheduledTask() { LOGDRAGSERVICE(" quit, selected task %s\n", GetDragServiceTaskName(task)); if (task == eDragTaskSourceEnd) { // Dispatch drag end events. - RefPtr session = GetCurrentSession(mTargetWindow); - if (session) { - session->EndDragSession(true, GetCurrentModifiers()); - } + EndDragSession(true, GetCurrentModifiers()); } // Nothing more to do @@ -2716,10 +2706,6 @@ gboolean nsDragService::RunScheduledTask() { return FALSE; } - // This may be the start of a destination drag session. - nsIWidget* targetWidget = mTargetWindow; - StartDragSession(targetWidget); - // mTargetWidget may be nullptr if the window has been destroyed. // (The leave event is not scheduled if a drop task is still scheduled.) // We still reply appropriately to indicate that the drop will or didn't @@ -2786,10 +2772,7 @@ gboolean nsDragService::RunScheduledTask() { } // Make sure to end the drag session. If this drag started in a // different app, we won't get a drag_end signal to end it from. - RefPtr session = GetCurrentSession(mTargetWindow); - if (session) { - session->EndDragSession(true, GetCurrentModifiers()); - } + EndDragSession(true, GetCurrentModifiers()); } // We're done with the drag context. @@ -2813,14 +2796,14 @@ gboolean nsDragService::RunScheduledTask() { // drag context. Gtk gets this from a combination of the key settings // and what the source is offering. -void nsDragService::UpdateDragAction(GdkDragContext* aDragContext) { +void nsDragSession::UpdateDragAction(GdkDragContext* aDragContext) { // This doesn't look right. dragSession.dragAction is used by // nsContentUtils::SetDataTransferInEvent() to set the initial // dataTransfer.dropEffect, so GdkDragContext::suggested_action would be // more appropriate. GdkDragContext::actions should be used to set // dataTransfer.effectAllowed, which doesn't currently happen with // external sources. - LOGDRAGSERVICE("nsDragService::UpdateDragAction(%p)", aDragContext); + LOGDRAGSERVICE("nsDragSession::UpdateDragAction(%p)", aDragContext); // default is to do nothing int action = nsIDragService::DRAGDROP_ACTION_NONE; @@ -2836,7 +2819,7 @@ void nsDragService::UpdateDragAction(GdkDragContext* aDragContext) { // So we need to call gdk_drag_context_get_selected_action() on Wayland // to get potential D&D modifier. // gdk_drag_context_get_selected_action() is also affected by - // gdk_drag_status(), see nsDragService::ReplyToDragMotion(). + // gdk_drag_status(), see nsDragSession::ReplyToDragMotion(). if (widget::GdkIsWaylandDisplay()) { GdkDragAction gdkActionSelected = gdk_drag_context_get_selected_action(aDragContext); @@ -2871,7 +2854,7 @@ void nsDragService::UpdateDragAction(GdkDragContext* aDragContext) { SetDragAction(action); } -void nsDragService::UpdateDragAction() { UpdateDragAction(mTargetDragContext); } +void nsDragSession::UpdateDragAction() { UpdateDragAction(mTargetDragContext); } NS_IMETHODIMP nsDragSession::UpdateDragEffect() { @@ -2889,12 +2872,9 @@ void nsDragSession::ReplyToDragMotion() { } } -void nsDragService::DispatchMotionEvents() { +void nsDragSession::DispatchMotionEvents() { if (mSourceWindow) { - RefPtr session = GetCurrentSession(mSourceWindow); - if (session) { - session->FireDragEventAtSource(eDrag, GetCurrentModifiers()); - } + FireDragEventAtSource(eDrag, GetCurrentModifiers()); } if (mTargetWindow) { mTargetWindow->DispatchDragEvent(eDragOver, mTargetWindowPoint, @@ -2903,7 +2883,7 @@ void nsDragService::DispatchMotionEvents() { } // Returns true if the drop was successful -gboolean nsDragService::DispatchDropEvent() { +gboolean nsDragSession::DispatchDropEvent() { // We need to check IsDestroyed here because the nsRefPtr // only protects this from being deleted, it does NOT protect // against nsView::~nsView() calling Destroy() on it, bug 378273. @@ -2919,7 +2899,7 @@ gboolean nsDragService::DispatchDropEvent() { } /* static */ -uint32_t nsDragService::GetCurrentModifiers() { +uint32_t nsDragSession::GetCurrentModifiers() { return mozilla::widget::KeymapWrapper::ComputeCurrentKeyModifiers(); } diff --git a/widget/gtk/nsDragService.h b/widget/gtk/nsDragService.h index f3383ea8ce28..37937ae8c931 100644 --- a/widget/gtk/nsDragService.h +++ b/widget/gtk/nsDragService.h @@ -87,11 +87,14 @@ class DragData final { nsTArray mUris; }; -// Temporary inheritance from nsBaseDragService instead of nsBaseDragSession -// (which nsBaseDragService temporarily inherits). -// This will be undone at the end of this patch series. -class nsDragSession : public nsBaseDragService { +/** + * GTK native nsIDragSession implementation + */ +class nsDragSession : public nsBaseDragSession, public nsIObserver { public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIOBSERVER + // nsIDragSession NS_IMETHOD SetCanDrop(bool aCanDrop) override; NS_IMETHOD GetCanDrop(bool* aCanDrop) override; @@ -109,6 +112,7 @@ class nsDragSession : public nsBaseDragService { MOZ_CAN_RUN_SCRIPT nsresult EndDragSessionImpl( bool aDoneDrag, uint32_t aKeyModifiers) override; + class AutoEventLoop { RefPtr mSession; @@ -123,8 +127,6 @@ class nsDragSession : public nsBaseDragService { static int GetLoopDepth() { return sEventLoopDepth; }; protected: - virtual ~nsDragSession() = default; - // mScheduledTask indicates what signal has been received from GTK and // so what needs to be dispatched when the scheduled task is run. It is // eDragTaskNone when there is no task scheduled (but the @@ -259,37 +261,25 @@ class nsDragSession : public nsBaseDragService { static GdkAtom sFilePromiseURLMimeAtom; static GdkAtom sFilePromiseMimeAtom; static GdkAtom sNativeImageMimeAtom; -}; -// Temporary inheritance from nsDragSession instead of nsBaseDragService -// (which nsDragSession temporarily inherits). -// This will be undone at the end of this patch series. -class nsDragService final : public nsDragSession, public nsIObserver { - public: - nsDragService(); + nsDragSession(); - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_NSIOBSERVER - - // nsBaseDragService + // nsBaseDragSession MOZ_CAN_RUN_SCRIPT virtual nsresult InvokeDragSessionImpl( nsIWidget* aWidget, nsIArray* anArrayTransferables, const mozilla::Maybe& aRegion, uint32_t aActionType) override; - // nsIDragService + + // nsIDragSession MOZ_CAN_RUN_SCRIPT NS_IMETHOD InvokeDragSession( nsIWidget* aWidget, nsINode* aDOMNode, nsIPrincipal* aPrincipal, nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings, nsIArray* anArrayTransferables, uint32_t aActionType, nsContentPolicyType aContentPolicyType) override; - NS_IMETHOD StartDragSession(nsISupports* aWidgetProvider) override; - // Methods called from nsWindow to handle responding to GTK drag // destination signals - static already_AddRefed GetInstance(); - void TargetDataReceived(GtkWidget* aWidget, GdkDragContext* aContext, gint aX, gint aY, GtkSelectionData* aSelection_data, guint aInfo, guint32 aTime); @@ -334,7 +324,7 @@ class nsDragService final : public nsDragSession, public nsIObserver { void SetDragIcon(GdkDragContext* aContext); protected: - virtual ~nsDragService(); + virtual ~nsDragSession(); private: // target/destination side vars @@ -370,8 +360,9 @@ class nsDragService final : public nsDragSession, public nsIObserver { // attempts to create a semi-transparent drag image. Returns TRUE if // successful, FALSE if not - bool SetAlphaPixmap(SourceSurface* aPixbuf, GdkDragContext* aContext, - int32_t aXOffset, int32_t aYOffset, + bool SetAlphaPixmap(mozilla::gfx::SourceSurface* aPixbuf, + GdkDragContext* aContext, int32_t aXOffset, + int32_t aYOffset, const mozilla::LayoutDeviceIntRect& dragRect); gboolean Schedule(DragTask aTask, nsWindow* aWindow, @@ -386,7 +377,7 @@ class nsDragService final : public nsDragSession, public nsIObserver { void UpdateDragAction(); #ifdef MOZ_LOGGING - const char* GetDragServiceTaskName(nsDragService::DragTask aTask); + const char* GetDragServiceTaskName(DragTask aTask); #endif gboolean DispatchDropEvent(); static uint32_t GetCurrentModifiers(); @@ -394,4 +385,16 @@ class nsDragService final : public nsDragSession, public nsIObserver { nsresult CreateTempFile(nsITransferable* aItem, nsACString& aURI); }; +/** + * Native GTK nsIDragService implementation + */ +class nsDragService : public nsBaseDragService { + public: + static already_AddRefed GetInstance(); + NS_IMETHOD StartDragSession(nsISupports* aWidgetProvider) override; + + protected: + already_AddRefed CreateDragSession() override; +}; + #endif // nsDragService_h__ diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index dde22ba3ac41..e5ab81f7f779 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -591,10 +591,14 @@ void nsWindow::Destroy() { UnlockNativePointer(); #endif - // dragService will be null after shutdown of the service manager. + // Cancel (dragleave) the current drag session, if any. RefPtr dragService = nsDragService::GetInstance(); - if (dragService && this == dragService->GetMostRecentDestWindow()) { - dragService->ScheduleLeaveEvent(); + if (dragService) { + nsDragSession* dragSession = + static_cast(dragService->GetCurrentSession(this)); + if (dragSession && this == dragSession->GetMostRecentDestWindow()) { + dragSession->ScheduleLeaveEvent(); + } } nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener(); @@ -5465,9 +5469,13 @@ void nsWindow::OnDragDataReceivedEvent(GtkWidget* aWidget, LOGDRAG("nsWindow::OnDragDataReceived"); RefPtr dragService = nsDragService::GetInstance(); - nsDragService::AutoEventLoop loop(dragService); - dragService->TargetDataReceived(aWidget, aDragContext, aX, aY, aSelectionData, - aInfo, aTime); + nsDragSession* dragSession = + static_cast(dragService->GetCurrentSession(this)); + if (dragSession) { + nsDragSession::AutoEventLoop loop(dragSession); + dragSession->TargetDataReceived(aWidget, aDragContext, aX, aY, aSelectionData, + aInfo, aTime); + } } nsWindow* nsWindow::GetTransientForWindowIfPopup() { @@ -8704,8 +8712,20 @@ gboolean WindowDragMotionHandler(GtkWidget* aWidget, LOGDRAG("WindowDragMotionHandler target nsWindow [%p]", window.get()); RefPtr dragService = nsDragService::GetInstance(); - nsDragService::AutoEventLoop loop(dragService); - if (!dragService->ScheduleMotionEvent( + NS_ENSURE_TRUE(dragService, FALSE); + nsDragSession* dragSession = + static_cast(dragService->GetCurrentSession(window)); + if (!dragSession) { + // This may be the start of an external drag session. + nsIWidget* widget = window; + static_cast(dragService->StartDragSession(widget)); + dragSession = + static_cast(dragService->GetCurrentSession(window)); + } + NS_ENSURE_TRUE(dragSession, FALSE); + + nsDragSession::AutoEventLoop loop(dragSession); + if (!dragSession->ScheduleMotionEvent( window, aDragContext, GetWindowDropPosition(window, aX, aY), aTime)) { return FALSE; } @@ -8728,9 +8748,17 @@ void WindowDragLeaveHandler(GtkWidget* aWidget) { } RefPtr dragService = nsDragService::GetInstance(); - nsDragService::AutoEventLoop loop(dragService); + nsIWidget* widget = window; + nsDragSession* dragSession = + static_cast(dragService->GetCurrentSession(widget)); + if (!dragSession) { + LOGDRAG(" Received dragleave after drag had ended.\n"); + return; + } - nsWindow* mostRecentDragWindow = dragService->GetMostRecentDestWindow(); + nsDragSession::AutoEventLoop loop(dragSession); + + nsWindow* mostRecentDragWindow = dragSession->GetMostRecentDestWindow(); if (!mostRecentDragWindow) { // This can happen when the target will not accept a drop. A GTK drag // source sends the leave message to the destination before the @@ -8750,7 +8778,7 @@ void WindowDragLeaveHandler(GtkWidget* aWidget) { } LOGDRAG("WindowDragLeaveHandler nsWindow %p\n", (void*)mostRecentDragWindow); - dragService->ScheduleLeaveEvent(); + dragSession->ScheduleLeaveEvent(); } static void drag_leave_event_cb(GtkWidget* aWidget, @@ -8778,8 +8806,10 @@ gboolean WindowDragDropHandler(GtkWidget* aWidget, GdkDragContext* aDragContext, LOGDRAG("WindowDragDropHandler nsWindow [%p]", window.get()); RefPtr dragService = nsDragService::GetInstance(); - nsDragService::AutoEventLoop loop(dragService); - return dragService->ScheduleDropEvent( + nsDragSession* dragSession = + static_cast(dragService->GetCurrentSession(window)); + nsDragSession::AutoEventLoop loop(dragSession); + return dragSession->ScheduleDropEvent( window, aDragContext, GetWindowDropPosition(window, aX, aY), aTime); } diff --git a/widget/moz.build b/widget/moz.build index 0d83e79a3d97..6e11dba4060a 100644 --- a/widget/moz.build +++ b/widget/moz.build @@ -153,6 +153,7 @@ EXPORTS += [ "nsBaseDragService.h", "nsBaseFilePicker.h", "nsBaseWidget.h", + "nsDragServiceProxy.h", "nsIDeviceContextSpec.h", "nsIRollupListener.h", "nsIWidget.h", diff --git a/widget/nsBaseDragService.cpp b/widget/nsBaseDragService.cpp index 543d41b4d710..a8b40817a77c 100644 --- a/widget/nsBaseDragService.cpp +++ b/widget/nsBaseDragService.cpp @@ -72,20 +72,22 @@ uint32_t GetSuppressLevel() { return static_cast(svc.get())->GetSuppressLevel(); } -nsBaseDragService::nsBaseDragService() - : mContentPolicyType(nsIContentPolicy::TYPE_OTHER), - mSuppressLevel(0) {} - +nsBaseDragService::nsBaseDragService() = default; nsBaseDragService::~nsBaseDragService() = default; -NS_IMPL_ISUPPORTS(nsBaseDragService, nsIDragService, nsIDragSession) - nsBaseDragSession::nsBaseDragSession() { TakeSessionBrowserListFromService(); } - nsBaseDragSession::~nsBaseDragSession() = default; +NS_IMPL_ISUPPORTS(nsBaseDragService, nsIDragService) +NS_IMPL_ISUPPORTS(nsBaseDragSession, nsIDragSession) + +NS_IMETHODIMP nsBaseDragService::GetIsMockService(bool* aRet) { + *aRet = false; + return NS_OK; +} + //--------------------------------------------------------- NS_IMETHODIMP nsBaseDragSession::SetCanDrop(bool aCanDrop) { @@ -309,7 +311,7 @@ NS_IMETHODIMP nsBaseDragSession::SetDragEndPointForTests(int32_t aScreenX, } //------------------------------------------------------------------------- -nsresult nsBaseDragService::InvokeDragSession( +nsresult nsBaseDragSession::InvokeDragSession( nsIWidget* aWidget, nsINode* aDOMNode, nsIPrincipal* aPrincipal, nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings, nsIArray* aTransferableArray, uint32_t aActionType, @@ -317,7 +319,6 @@ nsresult nsBaseDragService::InvokeDragSession( AUTO_PROFILER_LABEL("nsBaseDragService::InvokeDragSession", OTHER); NS_ENSURE_TRUE(aDOMNode, NS_ERROR_INVALID_ARG); - NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE); // stash the document of the dom node mSourceDocument = aDOMNode->OwnerDoc(); @@ -353,8 +354,11 @@ nsresult nsBaseDragService::InvokeDragSession( // // The best way to avoid this is to use the mock service in tests. See // synthesizeMockDragAndDrop. + nsCOMPtr dragService = + do_GetService("@mozilla.org/widget/dragservice;1"); + MOZ_ASSERT(dragService); MOZ_ASSERT( - !xpc::IsInAutomation() || IsMockService(), + !xpc::IsInAutomation() || dragService->IsMockService(), "About to start drag-drop native loop on which will prevent later " "tests from running properly."); } @@ -395,10 +399,7 @@ nsresult nsBaseDragService::InvokeDragSession( // Set mDoingDrag so that EndDragSession cleans up and sends the dragend // event after the aborted drag. mDoingDrag = true; - RefPtr session = GetCurrentSession(aWidget); - if (session) { - session->EndDragSession(true, 0); - } + EndDragSession(true, 0); } return rv; @@ -418,9 +419,27 @@ nsBaseDragService::InvokeDragSessionWithImage( NS_ENSURE_TRUE(aDataTransfer, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE); - mSessionIsSynthesizedForTests = + RefPtr session = + CreateDragSession().downcast(); + if (XRE_IsParentProcess()) { + mCurrentParentDragSession = session; + } + bool isSynthesized = aDragEvent->WidgetEventPtr()->mFlags.mIsSynthesizedForTests && !GetNeverAllowSessionIsSynthesizedForTests(); + return session->InitWithImage(widget, aDOMNode, aPrincipal, aCsp, + aCookieJarSettings, aTransferableArray, + aActionType, aImage, aImageX, aImageY, + aDragEvent, aDataTransfer, isSynthesized); +} + +nsresult nsBaseDragSession::InitWithImage( + nsIWidget* aWidget, nsINode* aDOMNode, nsIPrincipal* aPrincipal, + nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings, + nsIArray* aTransferableArray, uint32_t aActionType, nsINode* aImage, + int32_t aImageX, int32_t aImageY, DragEvent* aDragEvent, + DataTransfer* aDataTransfer, bool aIsSynthesizedForTests) { + mSessionIsSynthesizedForTests = aIsSynthesizedForTests; mDataTransfer = aDataTransfer; mSelection = nullptr; mHasImage = true; @@ -454,7 +473,7 @@ nsBaseDragService::InvokeDragSessionWithImage( } nsresult rv = InvokeDragSession( - widget, aDOMNode, aPrincipal, aCsp, aCookieJarSettings, + aWidget, aDOMNode, aPrincipal, aCsp, aCookieJarSettings, aTransferableArray, aActionType, nsIContentPolicy::TYPE_INTERNAL_IMAGE); mRegion = Nothing(); return rv; @@ -474,9 +493,27 @@ nsBaseDragService::InvokeDragSessionWithRemoteImage( NS_ENSURE_TRUE(aDataTransfer, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE); - mSessionIsSynthesizedForTests = + RefPtr session = + CreateDragSession().downcast(); + if (XRE_IsParentProcess()) { + mCurrentParentDragSession = session; + } + bool isSynthesized = aDragEvent->WidgetEventPtr()->mFlags.mIsSynthesizedForTests && !GetNeverAllowSessionIsSynthesizedForTests(); + return session->InitWithRemoteImage(widget, aDOMNode, aPrincipal, aCsp, + aCookieJarSettings, aTransferableArray, + aActionType, aDragStartData, aDragEvent, + aDataTransfer, isSynthesized); +} + +nsresult nsBaseDragSession::InitWithRemoteImage( + nsIWidget* aWidget, nsINode* aDOMNode, nsIPrincipal* aPrincipal, + nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings, + nsIArray* aTransferableArray, uint32_t aActionType, + RemoteDragStartData* aDragStartData, DragEvent* aDragEvent, + DataTransfer* aDataTransfer, bool aIsSynthesizedForTests) { + mSessionIsSynthesizedForTests = aIsSynthesizedForTests; mDataTransfer = aDataTransfer; mSelection = nullptr; mHasImage = true; @@ -491,7 +528,7 @@ nsBaseDragService::InvokeDragSessionWithRemoteImage( mInputSource = aDragEvent->InputSource(CallerType::System); nsresult rv = InvokeDragSession( - widget, aDOMNode, aPrincipal, aCsp, aCookieJarSettings, + aWidget, aDOMNode, aPrincipal, aCsp, aCookieJarSettings, aTransferableArray, aActionType, nsIContentPolicy::TYPE_INTERNAL_IMAGE); mRegion = Nothing(); return rv; @@ -511,9 +548,26 @@ nsBaseDragService::InvokeDragSessionWithSelection( NS_ENSURE_TRUE(aDragEvent, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE); - mSessionIsSynthesizedForTests = + RefPtr session = + CreateDragSession().downcast(); + if (XRE_IsParentProcess()) { + mCurrentParentDragSession = session; + } + bool isSynthesized = aDragEvent->WidgetEventPtr()->mFlags.mIsSynthesizedForTests && !GetNeverAllowSessionIsSynthesizedForTests(); + return session->InitWithSelection(widget, aSelection, aPrincipal, aCsp, + aCookieJarSettings, aTransferableArray, + aActionType, aDragEvent, aDataTransfer, + isSynthesized); +} + +nsresult nsBaseDragSession::InitWithSelection( + nsIWidget* aWidget, Selection* aSelection, nsIPrincipal* aPrincipal, + nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings, + nsIArray* aTransferableArray, uint32_t aActionType, DragEvent* aDragEvent, + DataTransfer* aDataTransfer, bool aIsSynthesizedForTests) { + mSessionIsSynthesizedForTests = aIsSynthesizedForTests; mDataTransfer = aDataTransfer; mSelection = aSelection; mHasImage = true; @@ -535,7 +589,7 @@ nsBaseDragService::InvokeDragSessionWithSelection( mSourceTopWindowContext = mSourceWindowContext ? mSourceWindowContext->TopWindowContext() : nullptr; - return InvokeDragSession(widget, node, aPrincipal, aCsp, aCookieJarSettings, + return InvokeDragSession(aWidget, node, aPrincipal, aCsp, aCookieJarSettings, aTransferableArray, aActionType, nsIContentPolicy::TYPE_OTHER); } @@ -544,15 +598,17 @@ nsBaseDragService::InvokeDragSessionWithSelection( NS_IMETHODIMP nsBaseDragService::GetCurrentSession(nsISupports* aWidgetProvider, nsIDragSession** aSession) { - if (!aSession) return NS_ERROR_INVALID_ARG; + MOZ_ASSERT(XRE_IsParentProcess()); + if (!aSession) { + return NS_ERROR_INVALID_ARG; + } - // "this" also implements a drag session, so say we are one but only - // if there is currently a drag going on. - if (!mSuppressLevel && mDoingDrag) { - *aSession = this; - NS_ADDREF(*aSession); // addRef because we're a "getter" - } else + if (!mSuppressLevel && mCurrentParentDragSession) { + RefPtr session = mCurrentParentDragSession; + session.forget(aSession); + } else { *aSession = nullptr; + } return NS_OK; } @@ -560,16 +616,26 @@ nsBaseDragService::GetCurrentSession(nsISupports* aWidgetProvider, //------------------------------------------------------------------------- NS_IMETHODIMP nsBaseDragService::StartDragSession(nsISupports* aWidgetProvider) { + MOZ_ASSERT(XRE_IsParentProcess()); if (!aWidgetProvider) { return NS_ERROR_NULL_POINTER; } - if (mDoingDrag) { - return NS_ERROR_FAILURE; + if (mCurrentParentDragSession) { + return NS_ERROR_ALREADY_INITIALIZED; } - mDoingDrag = true; - // By default dispatch drop also to content. - mOnlyChromeDrop = false; + RefPtr session = CreateDragSession(); + if (XRE_IsParentProcess()) { + mCurrentParentDragSession = session; + } + return NS_OK; +} + +NS_IMETHODIMP +nsBaseDragSession::InitForTests(uint32_t aAllowedEffect) { + mDragAction = aAllowedEffect; + mEffectAllowedForTests = aAllowedEffect; + mSessionIsSynthesizedForTests = true; return NS_OK; } @@ -578,12 +644,13 @@ NS_IMETHODIMP nsBaseDragService::StartDragSessionForTests( // This method must set mSessionIsSynthesizedForTests MOZ_ASSERT(!mNeverAllowSessionIsSynthesizedForTests); - if (NS_WARN_IF(NS_FAILED(StartDragSession(aWidgetProvider)))) { - return NS_ERROR_FAILURE; - } - mDragAction = aAllowedEffect; - mEffectAllowedForTests = aAllowedEffect; - mSessionIsSynthesizedForTests = true; + nsresult rv = StartDragSession(aWidgetProvider); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr session; + GetCurrentSession(aWidgetProvider, getter_AddRefs(session)); + MOZ_ASSERT(session); + session->InitForTests(aAllowedEffect); return NS_OK; } @@ -660,6 +727,11 @@ nsresult nsBaseDragSession::EndDragSessionImpl(bool aDoneDrag, // CC to reclaim the memory. if (XRE_IsParentProcess()) { DiscardInternalTransferData(); + nsCOMPtr svc = + do_GetService("@mozilla.org/widget/dragservice;1"); + if (svc) { + static_cast(svc.get())->ClearCurrentParentDragSession(); + } } mDoingDrag = false; @@ -788,7 +860,7 @@ static PresShell* GetPresShellForContent(nsINode* aDOMNode) { return nullptr; } -nsresult nsBaseDragService::DrawDrag(nsINode* aDOMNode, +nsresult nsBaseDragSession::DrawDrag(nsINode* aDOMNode, const Maybe& aRegion, CSSIntPoint aScreenPosition, LayoutDeviceIntRect* aScreenDragRect, @@ -940,7 +1012,7 @@ nsresult nsBaseDragService::DrawDrag(nsINode* aDOMNode, return NS_OK; } -nsresult nsBaseDragService::DrawDragForImage( +nsresult nsBaseDragSession::DrawDragForImage( nsPresContext* aPresContext, nsIImageLoadingContent* aImageLoader, HTMLCanvasElement* aCanvas, LayoutDeviceIntRect* aScreenDragRect, RefPtr* aSurface) { @@ -1005,7 +1077,10 @@ nsresult nsBaseDragService::DrawDragForImage( NS_IMETHODIMP nsBaseDragService::Suppress() { - EndDragSession(false, 0); + RefPtr session = mCurrentParentDragSession; + if (session) { + session->EndDragSession(false, 0); + } ++mSuppressLevel; return NS_OK; } @@ -1075,28 +1150,20 @@ static bool RemoveAllBrowsers(nsTArray& aBrowsers) { } bool nsBaseDragService::MaybeAddBrowser(BrowserParent* aBP) { -/* - // TODO: until nsBaseDragService and nsBaseDragSession separate - // (part 21), they automatically share mBrowsers, so skip this. nsCOMPtr session; GetCurrentSession(nullptr, getter_AddRefs(session)); if (session) { return session->MaybeAddBrowser(aBP); } -*/ return ::MaybeAddBrowser(mBrowsers, aBP); } bool nsBaseDragService::RemoveAllBrowsers() { -/* - // TODO: until nsBaseDragService and nsBaseDragSession separate - // (part 21), they automatically share mBrowsers, so skip this. nsCOMPtr session; GetCurrentSession(nullptr, getter_AddRefs(session)); if (session) { return session->RemoveAllBrowsers(); } -*/ return ::RemoveAllBrowsers(mBrowsers); } @@ -1172,3 +1239,33 @@ void nsBaseDragSession::TakeSessionBrowserListFromService() { NS_ENSURE_TRUE_VOID(svc); mBrowsers = static_cast(svc.get())->TakeSessionBrowserList(); } + +/* static */ +nsIWidget* nsBaseDragService::GetWidgetFromWidgetProvider(nsISupports* aWidgetProvider) { + nsCOMPtr widget = do_QueryObject(aWidgetProvider); + if (widget) { + return widget; + } + + nsPIDOMWindowOuter* outer; + if (aWidgetProvider) { + nsCOMPtr window = do_GetInterface(aWidgetProvider); + NS_ENSURE_TRUE(window, nullptr); + RefPtr innerWin = nsGlobalWindowInner::Cast(window); + NS_ENSURE_TRUE(innerWin, nullptr); + outer = innerWin->GetOuterWindow(); + } else { + nsCOMPtr winInner; + winInner = do_QueryInterface(GetEntryGlobal()); + NS_ENSURE_TRUE(winInner, nullptr); + outer = winInner->GetOuterWindow(); + } + NS_ENSURE_TRUE(outer, nullptr); + nsIDocShell* docShell = outer->GetDocShell(); + NS_ENSURE_TRUE(docShell, nullptr); + PresShell* presShell = docShell->GetPresShell(); + NS_ENSURE_TRUE(presShell, nullptr); + nsViewManager* vm = presShell->GetViewManager(); + NS_ENSURE_TRUE(vm, nullptr); + return vm->GetRootWidget(); +} diff --git a/widget/nsBaseDragService.h b/widget/nsBaseDragService.h index ca29642d3e29..a11ec959b8ec 100644 --- a/widget/nsBaseDragService.h +++ b/widget/nsBaseDragService.h @@ -56,6 +56,7 @@ class MockDragServiceController; */ class nsBaseDragSession : public nsIDragSession { public: + NS_DECL_ISUPPORTS NS_DECL_NSIDRAGSESSION int32_t TakeChildProcessDragAction(); @@ -68,9 +69,106 @@ class nsBaseDragSession : public nsIDragSession { mEndDragPoint = aEndDragPoint; } + uint16_t GetInputSource() { return mInputSource; } + + // The nsIDragService uses this to create nsIDragSessions when dragging + // from a child process. + MOZ_CAN_RUN_SCRIPT nsresult InitWithRemoteImage( + nsIWidget* aWidget, nsINode* aDOMNode, nsIPrincipal* aPrincipal, + nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings, + nsIArray* aTransferableArray, uint32_t aActionType, + mozilla::dom::RemoteDragStartData* aDragStartData, + mozilla::dom::DragEvent* aDragEvent, + mozilla::dom::DataTransfer* aDataTransfer, bool aIsSynthesizedForTests); + + // The nsIDragService uses this to create nsIDragSessions for dragging + // a selected region from a Gecko window. + MOZ_CAN_RUN_SCRIPT nsresult InitWithSelection( + nsIWidget* aWidget, mozilla::dom::Selection* aSelection, + nsIPrincipal* aPrincipal, nsIContentSecurityPolicy* aCsp, + nsICookieJarSettings* aCookieJarSettings, nsIArray* aTransferableArray, + uint32_t aActionType, mozilla::dom::DragEvent* aDragEvent, + mozilla::dom::DataTransfer* aDataTransfer, bool aIsSynthesizedForTests); + + // The nsIDragService uses this to create nsIDragSessions when dragging + // from anywhere else. + MOZ_CAN_RUN_SCRIPT nsresult InitWithImage( + nsIWidget* aWidget, nsINode* aDOMNode, nsIPrincipal* aPrincipal, + nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings, + nsIArray* aTransferableArray, uint32_t aActionType, nsINode* aImage, + int32_t aImageX, int32_t aImageY, mozilla::dom::DragEvent* aDragEvent, + mozilla::dom::DataTransfer* aDataTransfer, bool aIsSynthesizedForTests); + protected: nsBaseDragSession(); - ~nsBaseDragSession(); + virtual ~nsBaseDragSession(); + + /** + * Starts a modal drag session with an array of transaferables. + * + * @param aPrincipal - the triggering principal of the drag, or null if + * it's from browser chrome or OS + * @param aCsp - The csp of the triggering Document + * @param aTransferables - an array of transferables to be dragged + * @param aActionType - specified which of copy/move/link are allowed + * @param aContentPolicyType - the contentPolicyType that will be + * passed to the loadInfo when creating a new channel + * (defaults to TYPE_OTHER) + */ + MOZ_CAN_RUN_SCRIPT virtual nsresult InvokeDragSession( + nsIWidget* aWidget, nsINode* aDOMNode, nsIPrincipal* aPrincipal, + nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings, + nsIArray* aTransferableArray, uint32_t aActionType, + nsContentPolicyType aContentPolicyType = nsIContentPolicy::TYPE_OTHER); + + /** + * Called to create a drag session with a Gecko source. Like all drag + * sessions, the resulting session needs to be eventually ended with a call + * to nsIDragSession::EndDragSession. + */ + MOZ_CAN_RUN_SCRIPT virtual nsresult InvokeDragSessionImpl( + nsIWidget* aWidget, nsIArray* aTransferableArray, + const mozilla::Maybe& aRegion, + uint32_t aActionType) = 0; + + /** + * Draw the drag image, if any, to a surface and return it. The drag image + * is constructed from mImage if specified, or aDOMNode if mImage is null. + * + * aRegion may be used to draw only a subset of the element. This region + * should be supplied using x and y coordinates measured in css pixels + * that are relative to the upper-left corner of the window. + * + * aScreenPosition should be the screen coordinates of the mouse click + * for the drag. These are in CSS pixels. + * + * On return, aScreenDragRect will contain the screen coordinates of the + * area being dragged. This is used by the platform-specific part of the + * drag service to determine the drag feedback. This rect will be in the + * device pixels of the presContext. + * + * If there is no drag image, the returned surface will be null, but + * aScreenDragRect will still be set to the drag area. + * + * aPresContext will be set to the nsPresContext used determined from + * whichever of mImage or aDOMNode is used. + */ + nsresult DrawDrag(nsINode* aDOMNode, + const mozilla::Maybe& aRegion, + mozilla::CSSIntPoint aScreenPosition, + mozilla::LayoutDeviceIntRect* aScreenDragRect, + RefPtr* aSurface, + nsPresContext** aPresContext); + + /** + * Draw a drag image for an image node specified by aImageLoader or aCanvas. + * This is called by DrawDrag. + */ + nsresult DrawDragForImage(nsPresContext* aPresContext, + nsIImageLoadingContent* aImageLoader, + mozilla::dom::HTMLCanvasElement* aCanvas, + mozilla::LayoutDeviceIntRect* aScreenDragRect, + RefPtr* aSurface); MOZ_CAN_RUN_SCRIPT virtual nsresult EndDragSessionImpl( bool aDoneDrag, uint32_t aKeyModifiers); @@ -133,6 +231,10 @@ class nsBaseDragSession : public nsIDragSession { // The position relative to the top level widget where the drag ended. mozilla::LayoutDeviceIntPoint mEndDragPoint; + // the contentpolicy type passed to the channel when initiating the drag + // session + nsContentPolicyType mContentPolicyType = nsIContentPolicy::TYPE_OTHER; + uint32_t mDragAction = nsIDragService::DRAGDROP_ACTION_NONE; uint32_t mDragActionFromChildProcess = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED; @@ -145,7 +247,8 @@ class nsBaseDragSession : public nsIDragSession { // The input source of the drag event. Possible values are from MouseEvent. uint16_t mInputSource = mozilla::dom::MouseEvent_Binding::MOZ_SOURCE_MOUSE; - bool mDoingDrag = false; + // false after EndDragSession has run + bool mDoingDrag = true; bool mCanDrop = false; bool mOnlyChromeDrop = false; @@ -166,14 +269,9 @@ class nsBaseDragSession : public nsIDragSession { /** * Platform-agnostic base for nsIDragService. - * NB: This class temporarily subclasses nsBaseDragSession while we move - * methods from it to nsBaseDragSession. The inheritance relationship - * will be severed by the end of this patch series. */ -class nsBaseDragService : public nsIDragService, public nsBaseDragSession { +class nsBaseDragService : public nsIDragService { public: - typedef mozilla::gfx::SourceSurface SourceSurface; - nsBaseDragService(); // nsISupports @@ -181,8 +279,6 @@ class nsBaseDragService : public nsIDragService, public nsBaseDragSession { NS_DECL_NSIDRAGSERVICE - uint16_t GetInputSource() { return mInputSource; } - using nsIDragService::GetCurrentSession; uint32_t GetSuppressLevel() { return mSuppressLevel; }; @@ -191,89 +287,34 @@ class nsBaseDragService : public nsIDragService, public nsBaseDragSession { return std::move(mBrowsers); } + void ClearCurrentParentDragSession() { + mCurrentParentDragSession = nullptr; + } + + static nsIWidget* GetWidgetFromWidgetProvider(nsISupports* aWidgetProvider); + protected: virtual ~nsBaseDragService(); - /** - * Starts a modal drag session with an array of transaferables. - * - * @param aPrincipal - the triggering principal of the drag, or null if - * it's from browser chrome or OS - * @param aCsp - The csp of the triggering Document - * @param aTransferables - an array of transferables to be dragged - * @param aActionType - specified which of copy/move/link are allowed - * @param aContentPolicyType - the contentPolicyType that will be - * passed to the loadInfo when creating a new channel - * (defaults to TYPE_OTHER) - */ - MOZ_CAN_RUN_SCRIPT virtual nsresult InvokeDragSession( - nsIWidget* aWidget, nsINode* aDOMNode, nsIPrincipal* aPrincipal, - nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings, - nsIArray* aTransferableArray, uint32_t aActionType, - nsContentPolicyType aContentPolicyType = nsIContentPolicy::TYPE_OTHER); + virtual already_AddRefed CreateDragSession() = 0; - /** - * Called from nsBaseDragService to initiate a platform drag from a source - * in this process. This is expected to ensure that StartDragSession() and - * EndDragSession() get called if the platform drag is successfully invoked. - */ - MOZ_CAN_RUN_SCRIPT virtual nsresult InvokeDragSessionImpl( - nsIWidget* aWidget, nsIArray* aTransferableArray, - const mozilla::Maybe& aRegion, - uint32_t aActionType) = 0; - - /** - * Draw the drag image, if any, to a surface and return it. The drag image - * is constructed from mImage if specified, or aDOMNode if mImage is null. - * - * aRegion may be used to draw only a subset of the element. This region - * should be supplied using x and y coordinates measured in css pixels - * that are relative to the upper-left corner of the window. - * - * aScreenPosition should be the screen coordinates of the mouse click - * for the drag. These are in CSS pixels. - * - * On return, aScreenDragRect will contain the screen coordinates of the - * area being dragged. This is used by the platform-specific part of the - * drag service to determine the drag feedback. This rect will be in the - * device pixels of the presContext. - * - * If there is no drag image, the returned surface will be null, but - * aScreenDragRect will still be set to the drag area. - * - * aPresContext will be set to the nsPresContext used determined from - * whichever of mImage or aDOMNode is used. - */ - nsresult DrawDrag(nsINode* aDOMNode, - const mozilla::Maybe& aRegion, - mozilla::CSSIntPoint aScreenPosition, - mozilla::LayoutDeviceIntRect* aScreenDragRect, - RefPtr* aSurface, - nsPresContext** aPresContext); - - /** - * Draw a drag image for an image node specified by aImageLoader or aCanvas. - * This is called by DrawDrag. - */ - nsresult DrawDragForImage(nsPresContext* aPresContext, - nsIImageLoadingContent* aImageLoader, - mozilla::dom::HTMLCanvasElement* aCanvas, - mozilla::LayoutDeviceIntRect* aScreenDragRect, - RefPtr* aSurface); - - virtual bool IsMockService() { return false; } - - // the contentpolicy type passed to the channel when initiating the drag - // session - nsContentPolicyType mContentPolicyType; - - uint32_t mSuppressLevel; + // The drag session representing the user's current actions, if any. + // This value is only valid in the parent process. For child + // process drag sessions, see BrowserChild and PuppetWidget. + RefPtr mCurrentParentDragSession; // Sub-region for tree-selections. mozilla::Maybe mRegion; RefPtr mMockController; + // Weak references to PBrowsers that are currently engaged in drags. + // Once an nsIDragSession is created for the remote drag, these browsers + // will be moved to that object. + nsTArray mBrowsers; + + uint32_t mSuppressLevel = 0; + // If this is set, mSessionIsSynthesizedForTests should not become true. // This hack is used to bypass the "old" drag-drop test behavior. // See nsIDragService.idl for details. diff --git a/widget/nsDragServiceProxy.cpp b/widget/nsDragServiceProxy.cpp index 2f3fb8a241a2..f21574410bbb 100644 --- a/widget/nsDragServiceProxy.cpp +++ b/widget/nsDragServiceProxy.cpp @@ -24,11 +24,36 @@ using mozilla::gfx::SourceSurface; using mozilla::gfx::SurfaceFormat; using mozilla::ipc::Shmem; -nsDragServiceProxy::nsDragServiceProxy() = default; - nsDragServiceProxy::~nsDragServiceProxy() = default; -nsresult nsDragServiceProxy::InvokeDragSessionImpl( +nsDragSessionProxy::~nsDragSessionProxy() = default; + +already_AddRefed nsDragServiceProxy::CreateDragSession() { + RefPtr session = new nsDragSessionProxy(); + return session.forget(); +} + +nsresult nsDragSessionProxy::InvokeDragSession( + nsIWidget* aWidget, nsINode* aDOMNode, nsIPrincipal* aPrincipal, + nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings, + nsIArray* aTransferableArray, uint32_t aActionType, + nsContentPolicyType aContentPolicyType) { + BrowserChild* sourceBrowser = aWidget->GetOwningBrowserChild(); + NS_ENSURE_TRUE(sourceBrowser, NS_ERROR_INVALID_ARG); + [[maybe_unused]] RefPtr sourceSession = + sourceBrowser->GetDragSession(); + MOZ_ASSERT(!sourceSession); + nsresult rv = nsBaseDragSession::InvokeDragSession(aWidget, aDOMNode, + aPrincipal, aCsp, aCookieJarSettings, aTransferableArray, aActionType, + aContentPolicyType); + if (NS_SUCCEEDED(rv)) { + MOZ_ALWAYS_SUCCEEDS(sourceBrowser->GetWeakReference(getter_AddRefs(mSourceBrowser))); + sourceBrowser->SetDragSession(this); + } + return rv; +} + +nsresult nsDragSessionProxy::InvokeDragSessionImpl( nsIWidget* aWidget, nsIArray* aArrayTransferables, const Maybe& aRegion, uint32_t aActionType) { NS_ENSURE_STATE(mSourceDocument->GetDocShell()); @@ -81,7 +106,6 @@ nsresult nsDragServiceProxy::InvokeDragSessionImpl( std::move(transferables), aActionType, std::move(surfaceData), stride, dataSurface->GetFormat(), dragRect, principal, csp, csArgs, mSourceWindowContext, mSourceTopWindowContext); - StartDragSession(aWidget); return NS_OK; } } @@ -91,6 +115,88 @@ nsresult nsDragServiceProxy::InvokeDragSessionImpl( std::move(transferables), aActionType, Nothing(), 0, static_cast(0), dragRect, principal, csp, csArgs, mSourceWindowContext, mSourceTopWindowContext); - StartDragSession(aWidget); return NS_OK; } + +NS_IMETHODIMP +nsDragServiceProxy::StartDragSession(nsISupports* aWidgetProvider) { + nsIWidget* widget = GetWidgetFromWidgetProvider(aWidgetProvider); + NS_ENSURE_TRUE(widget, NS_ERROR_INVALID_ARG); + BrowserChild* targetBrowser = widget->GetOwningBrowserChild(); + NS_ENSURE_TRUE(targetBrowser, NS_ERROR_INVALID_ARG); + RefPtr session = targetBrowser->GetDragSession(); + if (session) { + // session already exists on the browser + return NS_OK; + } + + session = CreateDragSession(); + MOZ_ASSERT(session); + static_cast(session.get())->SetDragTarget(targetBrowser); + targetBrowser->SetDragSession(session); + return NS_OK; +} + +NS_IMETHODIMP +nsDragServiceProxy::GetCurrentSession(nsISupports* aWidgetProvider, + nsIDragSession** aSession) { + if (!aSession) { + return NS_ERROR_INVALID_ARG; + } + *aSession = nullptr; + + nsIWidget* widget = GetWidgetFromWidgetProvider(aWidgetProvider); + NS_ENSURE_TRUE(widget, NS_ERROR_INVALID_ARG); + BrowserChild* browser = widget->GetOwningBrowserChild(); + NS_ENSURE_TRUE(browser, NS_ERROR_INVALID_ARG); + RefPtr session = browser->GetDragSession(); + + if (!mSuppressLevel && session) { + session.forget(aSession); + } + + return NS_OK; +} + +void nsDragSessionProxy::SetDragTarget(BrowserChild* aTarget) { + if (!aTarget) { + if (mTargetBrowser) { + nsCOMPtr targetBC = do_QueryReferent(mTargetBrowser); + MOZ_ASSERT(targetBC); + if (targetBC) { + targetBC->SetDragSession(nullptr); + } + mTargetBrowser = nullptr; + } + return; + } + [[maybe_unused]] RefPtr session = + aTarget->GetDragSession(); + MOZ_ASSERT(!session); + MOZ_ALWAYS_SUCCEEDS(aTarget->GetWeakReference(getter_AddRefs(mTargetBrowser))); +} + +nsresult nsDragSessionProxy::EndDragSessionImpl(bool aDoneDrag, + uint32_t aKeyModifiers) { + if (mSourceBrowser) { + nsCOMPtr sourceBC = do_QueryReferent(mSourceBrowser); + MOZ_ASSERT(sourceBC); + [[maybe_unused]] RefPtr session = + sourceBC->GetDragSession(); + MOZ_ASSERT(session == this); + sourceBC->SetDragSession(nullptr); + mSourceBrowser = nullptr; + } + + if (mTargetBrowser) { + nsCOMPtr targetBC = do_QueryReferent(mTargetBrowser); + MOZ_ASSERT(targetBC); + [[maybe_unused]] RefPtr session = + targetBC->GetDragSession(); + MOZ_ASSERT(session == this); + targetBC->SetDragSession(nullptr); + mTargetBrowser = nullptr; + } + + return nsBaseDragSession::EndDragSessionImpl(aDoneDrag, aKeyModifiers); +} diff --git a/widget/nsDragServiceProxy.h b/widget/nsDragServiceProxy.h index 6e8769c5c8ee..5cda4de6ffb4 100644 --- a/widget/nsDragServiceProxy.h +++ b/widget/nsDragServiceProxy.h @@ -8,26 +8,48 @@ #include "nsBaseDragService.h" -// Temporary inheritance from nsBaseDragService instead of nsBaseDragSession -// (which nsBaseDragService temporarily inherits). -// This will be undone at the end of this patch series. -class nsDragSessionProxy : public nsBaseDragService {}; - -// Temporary inheritance from nsDragSessionProxy instead of nsBaseDragService -// (which nsDragSession temporarily inherits). -// This will be undone at the end of this patch series. -class nsDragServiceProxy final : public nsDragSessionProxy { +class nsDragSessionProxy : public nsBaseDragSession { public: - nsDragServiceProxy(); + NS_INLINE_DECL_REFCOUNTING_INHERITED(nsDragSessionProxy, nsBaseDragSession) - NS_INLINE_DECL_REFCOUNTING_INHERITED(nsDragServiceProxy, nsDragSessionProxy) + MOZ_CAN_RUN_SCRIPT virtual nsresult InvokeDragSession( + nsIWidget* aWidget, nsINode* aDOMNode, nsIPrincipal* aPrincipal, + nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings, + nsIArray* aTransferableArray, uint32_t aActionType, + nsContentPolicyType aContentPolicyType) override; - // nsBaseDragService - virtual nsresult InvokeDragSessionImpl( + nsresult InvokeDragSessionImpl( nsIWidget* aWidget, nsIArray* anArrayTransferables, const mozilla::Maybe& aRegion, uint32_t aActionType) override; + void SetDragTarget(mozilla::dom::BrowserChild* aTarget); + + MOZ_CAN_RUN_SCRIPT + nsresult EndDragSessionImpl(bool aDoneDrag, uint32_t aKeyModifiers) override; + + private: + ~nsDragSessionProxy(); + + // The source for this drag. This is null if the source is a different + // application or drag session. + nsWeakPtr mSourceBrowser; + // The target for this drag. This is null if the target is a different + // application or drag session. + nsWeakPtr mTargetBrowser; +}; + +class nsDragServiceProxy : public nsBaseDragService { + public: + NS_INLINE_DECL_REFCOUNTING_INHERITED(nsDragServiceProxy, nsBaseDragService) + + already_AddRefed CreateDragSession() override; + + NS_IMETHOD StartDragSession(nsISupports* aWidgetProvider) override; + + NS_IMETHOD GetCurrentSession(nsISupports* aWidgetProvider, + nsIDragSession** aSession) override; + private: virtual ~nsDragServiceProxy(); }; diff --git a/widget/nsIDragService.idl b/widget/nsIDragService.idl index b2ac40e908d0..096591037cbe 100644 --- a/widget/nsIDragService.idl +++ b/widget/nsIDragService.idl @@ -128,15 +128,7 @@ interface nsIDragService : nsISupports */ nsIDragSession getCurrentSession([optional] in nsISupports aWidgetProvider); - /** - * TODO: Temporary proxy for old C++ callers, for whom [optional] is - * insufficient. This method is removed at the end of this patch series. - */ %{ C++ - nsresult GetCurrentSession(nsIDragSession** aSession) { - return GetCurrentSession(nullptr, aSession); - } - nsIDragSession* GetCurrentSession(nsIWidget* aWidget) { nsCOMPtr session; GetCurrentSession(aWidget, getter_AddRefs(session)); @@ -195,6 +187,20 @@ interface nsIDragService : nsISupports */ nsIMockDragServiceController getMockDragController(); + /** + * True if this is a mock nsIDragService, created with + * createMockDragController(). + */ + readonly attribute boolean isMockService; + +%{ C++ + bool IsMockService() { + bool ret = false; + MOZ_ALWAYS_SUCCEEDS(GetIsMockService(&ret)); + return ret; + } +%} + /** * If this is true, mSessionIsSynthesizedForTests should not become true. * This hack is used to bypass the "old" drag-drop test behavior, which needed diff --git a/widget/nsIDragSession.idl b/widget/nsIDragSession.idl index 5c5036216b5d..f4e3d0eb47c8 100644 --- a/widget/nsIDragSession.idl +++ b/widget/nsIDragSession.idl @@ -137,6 +137,12 @@ interface nsIDragSession : nsISupports // nsIDragService::InvokeDragSessionWithImage. void updateDragImage(in Node aImage, in long aImageX, in long aImageY); + /** + * Tell Gecko that this session is generated for automated testing. + * This should be called immediately after StartDragSession when testing. + */ + [noscript] void InitForTests(in uint32_t aAllowedEffect); + /** * Returns effects allowed at starting the session for tests. */ diff --git a/widget/windows/nsDragService.cpp b/widget/windows/nsDragService.cpp index ebb6106a06e6..4fb5ea7d67a1 100644 --- a/widget/windows/nsDragService.cpp +++ b/widget/windows/nsDragService.cpp @@ -46,13 +46,13 @@ using namespace mozilla; using namespace mozilla::gfx; using namespace mozilla::widget; -//------------------------------------------------------------------------- -// -// DragService destructor -// -//------------------------------------------------------------------------- nsDragSession::~nsDragSession() { NS_IF_RELEASE(mDataObject); } +already_AddRefed nsDragService::CreateDragSession() { + RefPtr session = new nsDragSession(); + return session.forget(); +} + bool nsDragSession::CreateDragImage(nsINode* aDOMNode, const Maybe& aRegion, SHDRAGIMAGE* psdi) { @@ -140,7 +140,7 @@ bool nsDragSession::CreateDragImage(nsINode* aDOMNode, } //------------------------------------------------------------------------- -nsresult nsDragService::InvokeDragSessionImpl( +nsresult nsDragSession::InvokeDragSessionImpl( nsIWidget* aWidget, nsIArray* anArrayTransferables, const Maybe& aRegion, uint32_t aActionType) { // Try and get source URI of the items that are being dragged @@ -229,7 +229,7 @@ static HWND GetSourceWindow(dom::Document* aSourceDocument) { } //------------------------------------------------------------------------- -nsresult nsDragService::StartInvokingDragSession(nsIWidget* aWidget, +nsresult nsDragSession::StartInvokingDragSession(nsIWidget* aWidget, IDataObject* aDataObj, uint32_t aActionType) { // To do the drag we need to create an object that @@ -240,13 +240,13 @@ nsresult nsDragService::StartInvokingDragSession(nsIWidget* aWidget, // Now figure out what the native drag effect should be DWORD winDropRes; DWORD effects = DROPEFFECT_SCROLL; - if (aActionType & DRAGDROP_ACTION_COPY) { + if (aActionType & nsIDragService::DRAGDROP_ACTION_COPY) { effects |= DROPEFFECT_COPY; } - if (aActionType & DRAGDROP_ACTION_MOVE) { + if (aActionType & nsIDragService::DRAGDROP_ACTION_MOVE) { effects |= DROPEFFECT_MOVE; } - if (aActionType & DRAGDROP_ACTION_LINK) { + if (aActionType & nsIDragService::DRAGDROP_ACTION_LINK) { effects |= DROPEFFECT_LINK; } @@ -256,7 +256,6 @@ nsresult nsDragService::StartInvokingDragSession(nsIWidget* aWidget, mSentLocalDropEvent = false; // Start dragging - StartDragSession(aWidget); OpenDragPopup(); RefPtr pAsyncOp; @@ -277,19 +276,19 @@ nsresult nsDragService::StartInvokingDragSession(nsIWidget* aWidget, uint32_t dropResult; // Order is important, since multiple flags can be returned. if (winDropRes & DROPEFFECT_COPY) - dropResult = DRAGDROP_ACTION_COPY; + dropResult = nsIDragService::DRAGDROP_ACTION_COPY; else if (winDropRes & DROPEFFECT_LINK) - dropResult = DRAGDROP_ACTION_LINK; + dropResult = nsIDragService::DRAGDROP_ACTION_LINK; else if (winDropRes & DROPEFFECT_MOVE) - dropResult = DRAGDROP_ACTION_MOVE; + dropResult = nsIDragService::DRAGDROP_ACTION_MOVE; else - dropResult = DRAGDROP_ACTION_NONE; + dropResult = nsIDragService::DRAGDROP_ACTION_NONE; if (mDataTransfer) { if (res == DRAGDROP_S_DROP) // Success mDataTransfer->SetDropEffectInt(dropResult); else - mDataTransfer->SetDropEffectInt(DRAGDROP_ACTION_NONE); + mDataTransfer->SetDropEffectInt(nsIDragService::DRAGDROP_ACTION_NONE); } } @@ -310,11 +309,8 @@ nsresult nsDragService::StartInvokingDragSession(nsIWidget* aWidget, } SetDragEndPoint(LayoutDeviceIntPoint(cpos.x, cpos.y)); - RefPtr session = GetCurrentSession(aWidget); - if (session) { - ModifierKeyState modifierKeyState; - session->EndDragSession(true, modifierKeyState.GetModifiers()); - } + ModifierKeyState modifierKeyState; + EndDragSession(true, modifierKeyState.GetModifiers()); mDoingDrag = false; @@ -471,7 +467,7 @@ void nsDragSession::SetIDataObject(IDataObject* aDataObj) { } //--------------------------------------------------------- -void nsDragService::SetDroppedLocal() { +void nsDragSession::SetDroppedLocal() { // Sent from the native drag handler, letting us know // a drop occurred within the application vs. outside of it. mSentLocalDropEvent = true; diff --git a/widget/windows/nsDragService.h b/widget/windows/nsDragService.h index 629fa5051281..8f564d8bcdaf 100644 --- a/widget/windows/nsDragService.h +++ b/widget/windows/nsDragService.h @@ -13,10 +13,10 @@ struct IDataObject; class nsDataObjCollection; -// Temporary inheritance from nsBaseDragService instead of nsBaseDragSession -// (which nsBaseDragService temporarily inherits). -// This will be undone at the end of this patch series. -class nsDragSession : public nsBaseDragService { +/** + * Windows native nsIDragSession implementation + */ +class nsDragSession : public nsBaseDragSession { public: virtual ~nsDragSession(); @@ -30,9 +30,21 @@ class nsDragSession : public nsBaseDragService { void SetIDataObject(IDataObject* aDataObj); IDataObject* GetDataObject() { return mDataObject; } + MOZ_CAN_RUN_SCRIPT virtual nsresult InvokeDragSessionImpl( + nsIWidget* aWidget, nsIArray* anArrayTransferables, + const mozilla::Maybe& aRegion, + uint32_t aActionType); + MOZ_CAN_RUN_SCRIPT nsresult EndDragSessionImpl( bool aDoneDrag, uint32_t aKeyModifiers) override; + MOZ_CAN_RUN_SCRIPT nsresult StartInvokingDragSession(nsIWidget* aWidget, + IDataObject* aDataObj, + uint32_t aActionType); + + // A drop occurred within the application vs. outside of it. + void SetDroppedLocal(); + protected: // determine if we have a single data object or one of our private // collections @@ -45,29 +57,16 @@ class nsDragSession : public nsBaseDragService { SHDRAGIMAGE* psdi); IDataObject* mDataObject = nullptr; -}; - -// Temporary inheritance from nsDragSession instead of nsBaseDragService -// (which nsDragSession temporarily inherits). -// This will be undone at the end of this patch series. -class nsDragService final : public nsDragSession { - public: - // nsBaseDragService - MOZ_CAN_RUN_SCRIPT virtual nsresult InvokeDragSessionImpl( - nsIWidget* aWidget, nsIArray* anArrayTransferables, - const mozilla::Maybe& aRegion, - uint32_t aActionType); - - // native impl. - MOZ_CAN_RUN_SCRIPT nsresult StartInvokingDragSession(nsIWidget* aWidget, - IDataObject* aDataObj, - uint32_t aActionType); - - // A drop occurred within the application vs. outside of it. - void SetDroppedLocal(); - - protected: bool mSentLocalDropEvent = false; }; +/** + * Windows native nsIDragService implementation + */ +class nsDragService final : public nsBaseDragService { + public: + already_AddRefed CreateDragSession() override; + +}; + #endif // nsDragService_h__ diff --git a/widget/windows/nsNativeDragTarget.cpp b/widget/windows/nsNativeDragTarget.cpp index f1a064584ba9..6f487cd196dd 100644 --- a/widget/windows/nsNativeDragTarget.cpp +++ b/widget/windows/nsNativeDragTarget.cpp @@ -16,6 +16,7 @@ #include "nsClipboard.h" #include "KeyboardLayout.h" +#include "mozilla/dom/MouseEventBinding.h" #include "mozilla/MouseEvents.h" using namespace mozilla; @@ -152,8 +153,13 @@ void nsNativeDragTarget::DispatchDragDropEvent(EventMessage aEventMessage, ModifierKeyState modifierKeyState; modifierKeyState.InitInputEvent(event); - event.mInputSource = - static_cast(mDragService.get())->GetInputSource(); + nsDragSession* currSession = + static_cast(mDragService->GetCurrentSession(mWidget)); + if (currSession) { + event.mInputSource = currSession->GetInputSource(); + } else { + event.mInputSource = dom::MouseEvent_Binding::MOZ_SOURCE_MOUSE; + } mWidget->DispatchInputEvent(&event); } @@ -426,14 +432,12 @@ nsNativeDragTarget::Drop(LPDATAOBJECT pData, DWORD grfKeyState, POINTL aPT, return S_OK; // DragCancel() was called. } - // Let the win drag service know whether this session experienced + // Let the win drag session know whether it experienced // a drop event within the application. Drop will not oocur if the // drop landed outside the app. (used in tab tear off, bug 455884) - RefPtr winDragService = - static_cast(mDragService.get()); - winDragService->SetDroppedLocal(); + currentDragSession->SetDroppedLocal(); - // tell the drag service we're done with the session + // Tell the drag session we're done with it. // Use GetMessagePos to get the position of the mouse at the last message // seen by the event loop. (Bug 489729) DWORD pos = ::GetMessagePos();