Bug 1893119: Part 16 - Make nsBaseDragService weakly remember PBrowsers instead of PContents r=nika,win-reviewers,rkraesig

nsBaseDragService keeps track of the processes that might need to cancel a drag with EndDragSession and this is technically correct since the drag session is a singleton in the child process, but this series of patches changes those sessions to be per-PuppetWidget/BrowserChild.  This allows content processes to distinguish which of its browsers is engaged in a drag.

Differential Revision: https://phabricator.services.mozilla.com/D211062
This commit is contained in:
David P
2024-07-04 07:48:09 +00:00
parent 808c72fba0
commit c32e8a504a
15 changed files with 286 additions and 264 deletions

View File

@@ -463,7 +463,7 @@ class DataTransfer final : public nsISupports, public nsWrapperCache {
nsresult SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData, nsresult SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData,
uint32_t aIndex, nsIPrincipal* aSubjectPrincipal); uint32_t aIndex, nsIPrincipal* aSubjectPrincipal);
friend class ContentParent; friend class BrowserParent;
friend class Clipboard; friend class Clipboard;
void FillAllExternalData(); void FillAllExternalData();

View File

@@ -2031,8 +2031,7 @@ void EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent,
} }
case eDragEventClass: { case eDragEventClass: {
RefPtr<BrowserParent> browserParent = remote; RefPtr<BrowserParent> browserParent = remote;
browserParent->Manager()->MaybeInvokeDragSession(browserParent, browserParent->MaybeInvokeDragSession(aEvent->mMessage);
aEvent->mMessage);
RefPtr<nsIWidget> widget = browserParent->GetTopLevelWidget(); RefPtr<nsIWidget> widget = browserParent->GetTopLevelWidget();
nsCOMPtr<nsIDragSession> dragSession = nsCOMPtr<nsIDragSession> dragSession =
@@ -2436,7 +2435,7 @@ void EventStateManager::StopTrackingDragGesture(bool aClearInChildProcesses) {
dragService->GetCurrentSession(mPresContext->GetRootWidget()); dragService->GetCurrentSession(mPresContext->GetRootWidget());
if (!dragSession) { if (!dragSession) {
// Only notify if there isn't a drag session active. // Only notify if there isn't a drag session active.
dragService->RemoveAllChildProcesses(); dragService->RemoveAllBrowsers();
} }
} }
} }
@@ -4345,8 +4344,8 @@ nsresult EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
// No one called preventDefault(), so handle drop only in chrome. // No one called preventDefault(), so handle drop only in chrome.
dragSession->SetOnlyChromeDrop(true); dragSession->SetOnlyChromeDrop(true);
} }
if (ContentChild* child = ContentChild::GetSingleton()) { if (auto* bc = BrowserChild::GetFrom(presContext->GetDocShell())) {
child->SendUpdateDropEffect(action, dropEffect); bc->SendUpdateDropEffect(action, dropEffect);
} }
if (aEvent->HasBeenPostedToRemoteProcess()) { if (aEvent->HasBeenPostedToRemoteProcess()) {
dragSession->SetCanDrop(true); dragSession->SetCanDrop(true);
@@ -4392,18 +4391,18 @@ nsresult EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
ClearGlobalActiveContent(this); ClearGlobalActiveContent(this);
break; break;
} }
case eDragExit: case eDragExit: {
// make sure to fire the enter and exit_synth events after the // make sure to fire the enter and exit_synth events after the
// eDragExit event, otherwise we'll clean up too early // eDragExit event, otherwise we'll clean up too early
GenerateDragDropEnterExit(presContext, aEvent->AsDragEvent()); GenerateDragDropEnterExit(presContext, aEvent->AsDragEvent());
if (ContentChild* child = ContentChild::GetSingleton()) { if (auto* bc = BrowserChild::GetFrom(presContext->GetDocShell())) {
// SendUpdateDropEffect to prevent nsIDragService from waiting for // SendUpdateDropEffect to prevent nsIDragService from waiting for
// response of forwarded dragexit event. // response of forwarded dragexit event.
child->SendUpdateDropEffect(nsIDragService::DRAGDROP_ACTION_NONE, bc->SendUpdateDropEffect(nsIDragService::DRAGDROP_ACTION_NONE,
nsIDragService::DRAGDROP_ACTION_NONE); nsIDragService::DRAGDROP_ACTION_NONE);
} }
break; break;
}
case eKeyUp: case eKeyUp:
// If space key is released, we need to inactivate the element which was // If space key is released, we need to inactivate the element which was
// activated by preceding space key down. // activated by preceding space key down.

View File

@@ -112,6 +112,7 @@
#include "nsRefreshDriver.h" #include "nsRefreshDriver.h"
#include "nsThreadManager.h" #include "nsThreadManager.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "nsVariant.h"
#include "nsViewManager.h" #include "nsViewManager.h"
#include "nsWebBrowser.h" #include "nsWebBrowser.h"
#include "nsWindowWatcher.h" #include "nsWindowWatcher.h"
@@ -1921,6 +1922,103 @@ mozilla::ipc::IPCResult BrowserChild::RecvRealDragEvent(
return IPC_OK(); return IPC_OK();
} }
static already_AddRefed<DataTransfer> ConvertToDataTransfer(
nsTArray<IPCTransferableData>&& aTransferables, EventMessage aMessage) {
// Check if we are receiving any file objects. If we are we will want
// to hide any of the other objects coming in from content.
bool hasFiles = false;
for (uint32_t i = 0; i < aTransferables.Length() && !hasFiles; ++i) {
auto& items = aTransferables[i].items();
for (uint32_t j = 0; j < items.Length() && !hasFiles; ++j) {
if (items[j].data().type() ==
IPCTransferableDataType::TIPCTransferableDataBlob) {
hasFiles = true;
}
}
}
// Add the entries from the IPC to the new DataTransfer
RefPtr<DataTransfer> dataTransfer =
new DataTransfer(nullptr, aMessage, false, -1);
for (uint32_t i = 0; i < aTransferables.Length(); ++i) {
auto& items = aTransferables[i].items();
for (uint32_t j = 0; j < items.Length(); ++j) {
const IPCTransferableDataItem& item = items[j];
RefPtr<nsVariantCC> variant = new nsVariantCC();
nsresult rv =
nsContentUtils::IPCTransferableDataItemToVariant(item, variant);
if (NS_FAILED(rv)) {
continue;
}
// We should hide this data from content if we have a file, and we
// aren't a file.
bool hidden =
hasFiles && item.data().type() !=
IPCTransferableDataType::TIPCTransferableDataBlob;
dataTransfer->SetDataWithPrincipalFromOtherProcess(
NS_ConvertUTF8toUTF16(item.flavor()), variant, i,
nsContentUtils::GetSystemPrincipal(), hidden);
}
}
return dataTransfer.forget();
}
mozilla::ipc::IPCResult BrowserChild::RecvInvokeChildDragSession(
const MaybeDiscarded<WindowContext>& aSourceWindowContext,
const MaybeDiscarded<WindowContext>& aSourceTopWindowContext,
nsTArray<IPCTransferableData>&& aTransferables, const uint32_t& aAction) {
if (nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1")) {
dragService->StartDragSession();
if (RefPtr<nsIDragSession> session = GetDragSession()) {
session->SetSourceWindowContext(aSourceWindowContext.GetMaybeDiscarded());
session->SetSourceTopWindowContext(
aSourceTopWindowContext.GetMaybeDiscarded());
session->SetDragAction(aAction);
RefPtr<DataTransfer> dataTransfer =
ConvertToDataTransfer(std::move(aTransferables), eDragStart);
session->SetDataTransfer(dataTransfer);
}
}
return IPC_OK();
}
mozilla::ipc::IPCResult BrowserChild::RecvUpdateDragSession(
nsTArray<IPCTransferableData>&& aTransferables,
EventMessage aEventMessage) {
if (RefPtr<nsIDragSession> session = GetDragSession()) {
nsCOMPtr<DataTransfer> dataTransfer =
ConvertToDataTransfer(std::move(aTransferables), aEventMessage);
session->SetDataTransfer(dataTransfer);
}
return IPC_OK();
}
mozilla::ipc::IPCResult BrowserChild::RecvEndDragSession(
const bool& aDoneDrag, const bool& aUserCancelled,
const LayoutDeviceIntPoint& aDragEndPoint, const uint32_t& aKeyModifiers,
const uint32_t& aDropEffect) {
nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1");
if (dragService) {
RefPtr<nsIDragSession> dragSession = GetDragSession();
if (dragSession) {
if (aUserCancelled) {
dragSession->UserCancelled();
}
RefPtr<DataTransfer> dataTransfer = dragSession->GetDataTransfer();
if (dataTransfer) {
dataTransfer->SetDropEffectInt(aDropEffect);
}
dragSession->SetDragEndPoint(aDragEndPoint.x, aDragEndPoint.y);
}
dragService->EndDragSession(aDoneDrag, aKeyModifiers);
}
return IPC_OK();
}
void BrowserChild::RequestEditCommands(NativeKeyBindingsType aType, void BrowserChild::RequestEditCommands(NativeKeyBindingsType aType,
const WidgetKeyboardEvent& aEvent, const WidgetKeyboardEvent& aEvent,
nsTArray<CommandInt>& aCommands) { nsTArray<CommandInt>& aCommands) {

View File

@@ -659,6 +659,22 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
already_AddRefed<nsIDragSession> GetDragSession(); already_AddRefed<nsIDragSession> GetDragSession();
mozilla::ipc::IPCResult RecvInvokeChildDragSession(
const MaybeDiscarded<WindowContext>& aSourceWindowContext,
const MaybeDiscarded<WindowContext>& aSourceTopWindowContext,
nsTArray<IPCTransferableData>&& aTransferables, const uint32_t& aAction);
mozilla::ipc::IPCResult RecvUpdateDragSession(
nsTArray<IPCTransferableData>&& aTransferables,
EventMessage aEventMessage);
MOZ_CAN_RUN_SCRIPT_BOUNDARY
mozilla::ipc::IPCResult RecvEndDragSession(
const bool& aDoneDrag,
const bool& aUserCancelled,
const mozilla::LayoutDeviceIntPoint& aEndDragPoint,
const uint32_t& aKeyModifiers, const uint32_t& aDropEffect);
protected: protected:
virtual ~BrowserChild(); virtual ~BrowserChild();

View File

@@ -263,8 +263,10 @@ BrowserParent::LayerToBrowserParentTable*
BrowserParent::sLayerToBrowserParentTable = nullptr; BrowserParent::sLayerToBrowserParentTable = nullptr;
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserParent) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserParent)
NS_INTERFACE_MAP_ENTRY_CONCRETE(BrowserParent)
NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider) NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener)
NS_INTERFACE_MAP_END NS_INTERFACE_MAP_END
@@ -3868,7 +3870,7 @@ mozilla::ipc::IPCResult BrowserParent::RecvInvokeDragSession(
const MaybeDiscarded<WindowContext>& aSourceTopWindowContext) { const MaybeDiscarded<WindowContext>& aSourceTopWindowContext) {
PresShell* presShell = mFrameElement->OwnerDoc()->GetPresShell(); PresShell* presShell = mFrameElement->OwnerDoc()->GetPresShell();
if (!presShell) { if (!presShell) {
Unused << Manager()->SendEndDragSession( Unused << SendEndDragSession(
true, true, LayoutDeviceIntPoint(), 0, true, true, LayoutDeviceIntPoint(), 0,
nsIDragService::DRAGDROP_ACTION_NONE); nsIDragService::DRAGDROP_ACTION_NONE);
// Continue sending input events with input priority when stopping the dnd // Continue sending input events with input priority when stopping the dnd
@@ -3899,7 +3901,7 @@ mozilla::ipc::IPCResult BrowserParent::RecvInvokeDragSession(
nsCOMPtr<nsIDragService> dragService = nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1"); do_GetService("@mozilla.org/widget/dragservice;1");
if (dragService) { if (dragService) {
dragService->MaybeAddChildProcess(Manager()); dragService->MaybeAddBrowser(this);
} }
presShell->GetPresContext() presShell->GetPresContext()
@@ -3912,6 +3914,95 @@ mozilla::ipc::IPCResult BrowserParent::RecvInvokeDragSession(
return IPC_OK(); return IPC_OK();
} }
void BrowserParent::GetIPCTransferableData(
nsIDragSession* aSession,
nsTArray<IPCTransferableData>& aIPCTransferables) {
MOZ_ASSERT(aSession);
RefPtr<DataTransfer> transfer = aSession->GetDataTransfer();
if (!transfer) {
// Pass eDrop to get DataTransfer with external
// drag formats cached.
transfer = new DataTransfer(nullptr, eDrop, true, -1);
aSession->SetDataTransfer(transfer);
}
// Note, even though this fills the DataTransfer object with
// external data, the data is usually transfered over IPC lazily when
// needed.
transfer->FillAllExternalData();
nsCOMPtr<nsILoadContext> lc = GetLoadContext();
nsCOMPtr<nsIArray> transferables = transfer->GetTransferables(lc);
nsContentUtils::TransferablesToIPCTransferableDatas(
transferables, aIPCTransferables, false, Manager());
}
void BrowserParent::MaybeInvokeDragSession(EventMessage aMessage) {
// dnd uses IPCBlob to transfer data to the content process and the IPC
// message is sent as normal priority. When sending input events with input
// priority, the message may be preempted by the later dnd events. To make
// sure the input events and the blob message are processed in time order
// on the content process, we temporarily send the input events with normal
// priority when there is an active dnd session.
Manager()->SetInputPriorityEventEnabled(false);
nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1");
RefPtr<nsIWidget> widget = GetTopLevelWidget();
if (!dragService || !widget || !GetBrowsingContext()) {
return;
}
if (dragService->MaybeAddBrowser(this)) {
RefPtr<nsIDragSession> session = dragService->GetCurrentSession(widget);
if (session) {
// We need to send transferable data to child process.
nsTArray<IPCTransferableData> ipcTransferables;
GetIPCTransferableData(session, ipcTransferables);
uint32_t action;
session->GetDragAction(&action);
RefPtr<WindowContext> sourceWC;
session->GetSourceWindowContext(getter_AddRefs(sourceWC));
RefPtr<WindowContext> sourceTopWC;
session->GetSourceTopWindowContext(getter_AddRefs(sourceTopWC));
mozilla::Unused << SendInvokeChildDragSession(
sourceWC, sourceTopWC, std::move(ipcTransferables), action);
}
return;
}
if (dragService->MustUpdateDataTransfer(aMessage)) {
RefPtr<nsIDragSession> session = dragService->GetCurrentSession(widget);
if (session) {
// We need to send transferable data to child process.
nsTArray<IPCTransferableData> ipcTransferables;
GetIPCTransferableData(session, ipcTransferables);
mozilla::Unused << SendUpdateDragSession(
std::move(ipcTransferables), aMessage);
}
}
}
mozilla::ipc::IPCResult BrowserParent::RecvUpdateDropEffect(
const uint32_t& aDragAction, const uint32_t& aDropEffect) {
nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1");
if (!dragService) {
return IPC_OK();
}
RefPtr<nsIWidget> widget = GetTopLevelWidget();
NS_ENSURE_TRUE(widget, IPC_OK());
RefPtr<nsIDragSession> dragSession = dragService->GetCurrentSession(widget);
NS_ENSURE_TRUE(dragSession, IPC_OK());
dragSession->SetDragAction(aDragAction);
RefPtr<DataTransfer> dt = dragSession->GetDataTransfer();
if (dt) {
dt->SetDropEffectInt(aDropEffect);
}
dragSession->UpdateDragEffect();
return IPC_OK();
}
bool BrowserParent::AsyncPanZoomEnabled() const { bool BrowserParent::AsyncPanZoomEnabled() const {
nsCOMPtr<nsIWidget> widget = GetWidget(); nsCOMPtr<nsIWidget> widget = GetWidget();
return widget && widget->AsyncPanZoomEnabled(); return widget && widget->AsyncPanZoomEnabled();

View File

@@ -78,6 +78,14 @@ namespace ipc {
class StructuredCloneData; class StructuredCloneData;
} // namespace ipc } // namespace ipc
#define DOM_BROWSERPARENT_IID \
{ \
0x58b47b52, 0x77dc, 0x44cf, { \
0x8b, 0xe5, 0x8e, 0x78, 0x24, 0xd9, 0xae, 0xc5 \
} \
}
/** /**
* BrowserParent implements the parent actor part of the PBrowser protocol. See * BrowserParent implements the parent actor part of the PBrowser protocol. See
* PBrowser for more information. * PBrowser for more information.
@@ -99,6 +107,7 @@ class BrowserParent final : public PBrowserParent,
// Helper class for ContentParent::RecvCreateWindow. // Helper class for ContentParent::RecvCreateWindow.
struct AutoUseNewTab; struct AutoUseNewTab;
NS_DECLARE_STATIC_IID_ACCESSOR(DOM_BROWSERPARENT_IID)
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSIAUTHPROMPTPROVIDER NS_DECL_NSIAUTHPROMPTPROVIDER
// nsIDOMEventListener interfaces // nsIDOMEventListener interfaces
@@ -672,6 +681,9 @@ class BrowserParent final : public PBrowserParent,
const MaybeDiscarded<WindowContext>& aSourceWindowContext, const MaybeDiscarded<WindowContext>& aSourceWindowContext,
const MaybeDiscarded<WindowContext>& aSourceTopWindowContext); const MaybeDiscarded<WindowContext>& aSourceTopWindowContext);
mozilla::ipc::IPCResult RecvUpdateDropEffect(const uint32_t& aDragAction,
const uint32_t& aDropEffect);
void AddInitialDnDDataTo(IPCTransferableData* aTransferableData, void AddInitialDnDDataTo(IPCTransferableData* aTransferableData,
nsIPrincipal** aPrincipal); nsIPrincipal** aPrincipal);
@@ -709,6 +721,8 @@ class BrowserParent final : public PBrowserParent,
// Called when the BrowserParent is being destroyed or entering bfcache. // Called when the BrowserParent is being destroyed or entering bfcache.
void Deactivated(); void Deactivated();
void MaybeInvokeDragSession(EventMessage aMessage);
protected: protected:
friend BrowserBridgeParent; friend BrowserBridgeParent;
friend BrowserHost; friend BrowserHost;
@@ -753,6 +767,9 @@ class BrowserParent final : public PBrowserParent,
mozilla::ipc::IPCResult RecvShowDynamicToolbar(); mozilla::ipc::IPCResult RecvShowDynamicToolbar();
void GetIPCTransferableData(nsIDragSession* aSession,
nsTArray<IPCTransferableData>& aIPCTransferables);
private: private:
void SuppressDisplayport(bool aEnabled); void SuppressDisplayport(bool aEnabled);
@@ -995,6 +1012,8 @@ class BrowserParent final : public PBrowserParent,
bool mShowingTooltip : 1; bool mShowingTooltip : 1;
}; };
NS_DEFINE_STATIC_IID_ACCESSOR(BrowserParent, DOM_BROWSERPARENT_IID)
struct MOZ_STACK_CLASS BrowserParent::AutoUseNewTab final { struct MOZ_STACK_CLASS BrowserParent::AutoUseNewTab final {
public: public:
explicit AutoUseNewTab(BrowserParent* aNewTab) : mNewTab(aNewTab) { explicit AutoUseNewTab(BrowserParent* aNewTab) : mNewTab(aNewTab) {

View File

@@ -201,7 +201,6 @@
#include "nsServiceManagerUtils.h" #include "nsServiceManagerUtils.h"
#include "nsStyleSheetService.h" #include "nsStyleSheetService.h"
#include "nsThreadManager.h" #include "nsThreadManager.h"
#include "nsVariant.h"
#include "nsXULAppAPI.h" #include "nsXULAppAPI.h"
#include "IHistory.h" #include "IHistory.h"
#include "ReferrerInfo.h" #include "ReferrerInfo.h"
@@ -3218,111 +3217,6 @@ mozilla::ipc::IPCResult ContentChild::RecvPWebBrowserPersistDocumentConstructor(
return IPC_OK(); return IPC_OK();
} }
static already_AddRefed<DataTransfer> ConvertToDataTransfer(
nsTArray<IPCTransferableData>&& aTransferables, EventMessage aMessage) {
// Check if we are receiving any file objects. If we are we will want
// to hide any of the other objects coming in from content.
bool hasFiles = false;
for (uint32_t i = 0; i < aTransferables.Length() && !hasFiles; ++i) {
auto& items = aTransferables[i].items();
for (uint32_t j = 0; j < items.Length() && !hasFiles; ++j) {
if (items[j].data().type() ==
IPCTransferableDataType::TIPCTransferableDataBlob) {
hasFiles = true;
}
}
}
// Add the entries from the IPC to the new DataTransfer
RefPtr<DataTransfer> dataTransfer =
new DataTransfer(nullptr, aMessage, false, -1);
for (uint32_t i = 0; i < aTransferables.Length(); ++i) {
auto& items = aTransferables[i].items();
for (uint32_t j = 0; j < items.Length(); ++j) {
const IPCTransferableDataItem& item = items[j];
RefPtr<nsVariantCC> variant = new nsVariantCC();
nsresult rv =
nsContentUtils::IPCTransferableDataItemToVariant(item, variant);
if (NS_FAILED(rv)) {
continue;
}
// We should hide this data from content if we have a file, and we
// aren't a file.
bool hidden =
hasFiles && item.data().type() !=
IPCTransferableDataType::TIPCTransferableDataBlob;
dataTransfer->SetDataWithPrincipalFromOtherProcess(
NS_ConvertUTF8toUTF16(item.flavor()), variant, i,
nsContentUtils::GetSystemPrincipal(), hidden);
}
}
return dataTransfer.forget();
}
mozilla::ipc::IPCResult ContentChild::RecvInvokeDragSession(
const MaybeDiscarded<WindowContext>& aSourceWindowContext,
const MaybeDiscarded<WindowContext>& aSourceTopWindowContext,
nsTArray<IPCTransferableData>&& aTransferables, const uint32_t& aAction) {
if (nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1")) {
dragService->StartDragSession();
nsCOMPtr<nsIDragSession> session;
dragService->GetCurrentSession(getter_AddRefs(session));
if (session) {
session->SetSourceWindowContext(aSourceWindowContext.GetMaybeDiscarded());
session->SetSourceTopWindowContext(
aSourceTopWindowContext.GetMaybeDiscarded());
session->SetDragAction(aAction);
RefPtr<DataTransfer> dataTransfer =
ConvertToDataTransfer(std::move(aTransferables), eDragStart);
session->SetDataTransfer(dataTransfer);
}
}
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvUpdateDragSession(
nsTArray<IPCTransferableData>&& aTransferables,
EventMessage aEventMessage) {
if (nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1")) {
nsCOMPtr<nsIDragSession> session;
dragService->GetCurrentSession(getter_AddRefs(session));
if (session) {
nsCOMPtr<DataTransfer> dataTransfer =
ConvertToDataTransfer(std::move(aTransferables), aEventMessage);
session->SetDataTransfer(dataTransfer);
}
}
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvEndDragSession(
const bool& aDoneDrag, const bool& aUserCancelled,
const LayoutDeviceIntPoint& aDragEndPoint, const uint32_t& aKeyModifiers,
const uint32_t& aDropEffect) {
nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1");
if (dragService) {
nsCOMPtr<nsIDragSession> dragSession;
dragService->GetCurrentSession(getter_AddRefs(dragSession));
if (dragSession) {
if (aUserCancelled) {
dragSession->UserCancelled();
}
RefPtr<DataTransfer> dataTransfer = dragSession->GetDataTransfer();
if (dataTransfer) {
dataTransfer->SetDropEffectInt(aDropEffect);
}
dragSession->SetDragEndPoint(aDragEndPoint.x, aDragEndPoint.y);
}
dragService->EndDragSession(aDoneDrag, aKeyModifiers);
}
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvPush(const nsCString& aScope, mozilla::ipc::IPCResult ContentChild::RecvPush(const nsCString& aScope,
nsIPrincipal* aPrincipal, nsIPrincipal* aPrincipal,
const nsString& aMessageId) { const nsString& aMessageId) {

View File

@@ -413,21 +413,6 @@ class ContentChild final : public PContentChild,
mozilla::ipc::IPCResult RecvShutdown(); mozilla::ipc::IPCResult RecvShutdown();
mozilla::ipc::IPCResult RecvInvokeDragSession(
const MaybeDiscarded<WindowContext>& aSourceWindowContext,
const MaybeDiscarded<WindowContext>& aSourceTopWindowContext,
nsTArray<IPCTransferableData>&& aTransferables, const uint32_t& aAction);
mozilla::ipc::IPCResult RecvUpdateDragSession(
nsTArray<IPCTransferableData>&& aTransferables,
EventMessage aEventMessage);
MOZ_CAN_RUN_SCRIPT_BOUNDARY
mozilla::ipc::IPCResult RecvEndDragSession(
const bool& aDoneDrag, const bool& aUserCancelled,
const mozilla::LayoutDeviceIntPoint& aEndDragPoint,
const uint32_t& aKeyModifiers, const uint32_t& aDropEffect);
mozilla::ipc::IPCResult RecvPush(const nsCString& aScope, mozilla::ipc::IPCResult RecvPush(const nsCString& aScope,
nsIPrincipal* aPrincipal, nsIPrincipal* aPrincipal,
const nsString& aMessageId); const nsString& aMessageId);

View File

@@ -5177,95 +5177,6 @@ bool ContentParent::DeallocPWebrtcGlobalParent(PWebrtcGlobalParent* aActor) {
} }
#endif #endif
void ContentParent::GetIPCTransferableData(
nsIDragSession* aSession, BrowserParent* aParent,
nsTArray<IPCTransferableData>& aIPCTransferables) {
RefPtr<DataTransfer> transfer = aSession->GetDataTransfer();
if (!transfer) {
// Pass eDrop to get DataTransfer with external
// drag formats cached.
transfer = new DataTransfer(nullptr, eDrop, true, -1);
aSession->SetDataTransfer(transfer);
}
// Note, even though this fills the DataTransfer object with
// external data, the data is usually transfered over IPC lazily when
// needed.
transfer->FillAllExternalData();
nsCOMPtr<nsILoadContext> lc = aParent ? aParent->GetLoadContext() : nullptr;
nsCOMPtr<nsIArray> transferables = transfer->GetTransferables(lc);
nsContentUtils::TransferablesToIPCTransferableDatas(
transferables, aIPCTransferables, false, this);
}
void ContentParent::MaybeInvokeDragSession(BrowserParent* aParent,
EventMessage aMessage) {
// dnd uses IPCBlob to transfer data to the content process and the IPC
// message is sent as normal priority. When sending input events with input
// priority, the message may be preempted by the later dnd events. To make
// sure the input events and the blob message are processed in time order
// on the content process, we temporarily send the input events with normal
// priority when there is an active dnd session.
SetInputPriorityEventEnabled(false);
nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1");
if (!dragService) {
return;
}
if (dragService->MaybeAddChildProcess(this)) {
nsCOMPtr<nsIDragSession> session;
dragService->GetCurrentSession(getter_AddRefs(session));
if (session) {
// We need to send transferable data to child process.
nsTArray<IPCTransferableData> ipcTransferables;
GetIPCTransferableData(session, aParent, ipcTransferables);
uint32_t action;
session->GetDragAction(&action);
RefPtr<WindowContext> sourceWC;
session->GetSourceWindowContext(getter_AddRefs(sourceWC));
RefPtr<WindowContext> sourceTopWC;
session->GetSourceTopWindowContext(getter_AddRefs(sourceTopWC));
mozilla::Unused << SendInvokeDragSession(
sourceWC, sourceTopWC, std::move(ipcTransferables), action);
}
return;
}
if (dragService->MustUpdateDataTransfer(aMessage)) {
nsCOMPtr<nsIDragSession> session;
dragService->GetCurrentSession(getter_AddRefs(session));
if (session) {
// We need to send transferable data to child process.
nsTArray<IPCTransferableData> ipcTransferables;
GetIPCTransferableData(session, aParent, ipcTransferables);
mozilla::Unused << SendUpdateDragSession(std::move(ipcTransferables),
aMessage);
}
}
}
mozilla::ipc::IPCResult ContentParent::RecvUpdateDropEffect(
const uint32_t& aDragAction, const uint32_t& aDropEffect) {
nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1");
if (!dragService) {
return IPC_OK();
}
nsCOMPtr<nsIDragSession> dragSession;
dragService->GetCurrentSession(getter_AddRefs(dragSession));
if (dragSession) {
dragSession->SetDragAction(aDragAction);
RefPtr<DataTransfer> dt = dragSession->GetDataTransfer();
if (dt) {
dt->SetDropEffectInt(aDropEffect);
}
dragSession->UpdateDragEffect();
}
return IPC_OK();
}
PContentPermissionRequestParent* PContentPermissionRequestParent*
ContentParent::AllocPContentPermissionRequestParent( ContentParent::AllocPContentPermissionRequestParent(
const nsTArray<PermissionRequest>& aRequests, nsIPrincipal* aPrincipal, const nsTArray<PermissionRequest>& aRequests, nsIPrincipal* aPrincipal,

View File

@@ -518,8 +518,6 @@ class ContentParent final : public PContentParent,
mozilla::ipc::IPCResult RecvNotifyShutdownSuccess(); mozilla::ipc::IPCResult RecvNotifyShutdownSuccess();
void MaybeInvokeDragSession(BrowserParent* aParent, EventMessage aMessage);
PContentPermissionRequestParent* AllocPContentPermissionRequestParent( PContentPermissionRequestParent* AllocPContentPermissionRequestParent(
const nsTArray<PermissionRequest>& aRequests, nsIPrincipal* aPrincipal, const nsTArray<PermissionRequest>& aRequests, nsIPrincipal* aPrincipal,
nsIPrincipal* aTopLevelPrincipal, const bool& aIsHandlingUserInput, nsIPrincipal* aTopLevelPrincipal, const bool& aIsHandlingUserInput,
@@ -1103,9 +1101,6 @@ class ContentParent final : public PContentParent,
bool DeallocPWebrtcGlobalParent(PWebrtcGlobalParent* aActor); bool DeallocPWebrtcGlobalParent(PWebrtcGlobalParent* aActor);
#endif #endif
mozilla::ipc::IPCResult RecvUpdateDropEffect(const uint32_t& aDragAction,
const uint32_t& aDropEffect);
mozilla::ipc::IPCResult RecvShutdownProfile(const nsACString& aProfile); mozilla::ipc::IPCResult RecvShutdownProfile(const nsACString& aProfile);
mozilla::ipc::IPCResult RecvShutdownPerfStats(const nsACString& aPerfStats); mozilla::ipc::IPCResult RecvShutdownPerfStats(const nsACString& aPerfStats);
@@ -1419,9 +1414,6 @@ class ContentParent final : public PContentParent,
return mThreadsafeHandle; return mThreadsafeHandle;
} }
void GetIPCTransferableData(nsIDragSession* aSession, BrowserParent* aParent,
nsTArray<IPCTransferableData>& aIPCTransferables);
RemoteWorkerServiceParent* GetRemoteWorkerServiceParent() const { RemoteWorkerServiceParent* GetRemoteWorkerServiceParent() const {
return mRemoteWorkerServiceActor; return mRemoteWorkerServiceActor;
} }

View File

@@ -1003,6 +1003,19 @@ child:
async WillChangeProcess(); async WillChangeProcess();
async InvokeChildDragSession(
MaybeDiscardedWindowContext aSourceWindowContext,
MaybeDiscardedWindowContext aSourceTopWindowContext,
IPCTransferableData[] transfers, uint32_t action);
async UpdateDragSession(IPCTransferableData[] transfers,
EventMessage message);
async EndDragSession(bool aDoneDrag, bool aUserCancelled,
LayoutDeviceIntPoint aDragEndPoint,
uint32_t aKeyModifiers,
uint32_t aDropEffect);
parent: parent:
/** /**
* Fetches whether this window supports protected media, which is sent back in response. * Fetches whether this window supports protected media, which is sent back in response.
@@ -1029,6 +1042,8 @@ parent:
async NewWindowGlobal(ManagedEndpoint<PWindowGlobalParent> aEndpoint, async NewWindowGlobal(ManagedEndpoint<PWindowGlobalParent> aEndpoint,
WindowGlobalInit aInit); WindowGlobalInit aInit);
async UpdateDropEffect(uint32_t aDragAction, uint32_t aDropEffect);
/* /*
* FIXME: write protocol! * FIXME: write protocol!

View File

@@ -826,17 +826,6 @@ child:
*/ */
async NotifyIdleObserver(uint64_t observerId, nsCString topic, nsString str); async NotifyIdleObserver(uint64_t observerId, nsCString topic, nsString str);
async InvokeDragSession(MaybeDiscardedWindowContext aSourceWindowContext,
MaybeDiscardedWindowContext aSourceTopWindowContext,
IPCTransferableData[] transfers, uint32_t action);
async UpdateDragSession(IPCTransferableData[] transfers, EventMessage message);
async EndDragSession(bool aDoneDrag, bool aUserCancelled,
LayoutDeviceIntPoint aDragEndPoint,
uint32_t aKeyModifiers,
uint32_t aDropEffect);
async DomainSetChanged(uint32_t aSetType, uint32_t aChangeType, nullable nsIURI aDomain); async DomainSetChanged(uint32_t aSetType, uint32_t aChangeType, nullable nsIURI aDomain);
/** /**
@@ -1306,8 +1295,6 @@ parent:
*/ */
async FinishShutdown(); async FinishShutdown();
async UpdateDropEffect(uint32_t aDragAction, uint32_t aDropEffect);
/** /**
* Initiates an asynchronous request for permission for the * Initiates an asynchronous request for permission for the
* provided principal. * provided principal.

View File

@@ -36,6 +36,8 @@
#include "mozilla/Unused.h" #include "mozilla/Unused.h"
#include "mozilla/ViewportUtils.h" #include "mozilla/ViewportUtils.h"
#include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/DataTransferItemList.h" #include "mozilla/dom/DataTransferItemList.h"
#include "mozilla/dom/DataTransfer.h" #include "mozilla/dom/DataTransfer.h"
#include "mozilla/dom/Document.h" #include "mozilla/dom/Document.h"
@@ -44,7 +46,6 @@
#include "mozilla/dom/Selection.h" #include "mozilla/dom/Selection.h"
#include "mozilla/gfx/2D.h" #include "mozilla/gfx/2D.h"
#include "nsFrameLoader.h" #include "nsFrameLoader.h"
#include "BrowserParent.h"
#include "nsIMutableArray.h" #include "nsIMutableArray.h"
#include "gfxContext.h" #include "gfxContext.h"
#include "gfxPlatform.h" #include "gfxPlatform.h"
@@ -626,14 +627,19 @@ nsBaseDragService::EndDragSession(bool aDoneDrag, uint32_t aKeyModifiers) {
dropEffect = mDataTransfer->DropEffectInt(); dropEffect = mDataTransfer->DropEffectInt();
} }
for (uint32_t i = 0; i < mChildProcesses.Length(); ++i) { for (nsWeakPtr& browser : mBrowsers) {
mozilla::Unused << mChildProcesses[i]->SendEndDragSession( nsCOMPtr<BrowserParent> bp = do_QueryReferent(browser);
aDoneDrag, mUserCancelled, mEndDragPoint, aKeyModifiers, dropEffect); if (NS_WARN_IF(!bp)) {
continue;
}
mozilla::Unused << bp->SendEndDragSession(aDoneDrag, mUserCancelled,
mEndDragPoint, aKeyModifiers,
dropEffect);
// Continue sending input events with input priority when stopping the dnd // Continue sending input events with input priority when stopping the dnd
// session. // session.
mChildProcesses[i]->SetInputPriorityEventEnabled(true); bp->Manager()->SetInputPriorityEventEnabled(true);
} }
mChildProcesses.Clear(); mBrowsers.Clear();
// mDataTransfer and the items it owns are going to die anyway, but we // mDataTransfer and the items it owns are going to die anyway, but we
// explicitly deref the contained data here so that we don't have to wait for // explicitly deref the contained data here so that we don't have to wait for
@@ -1026,22 +1032,31 @@ nsBaseDragSession::DragEventDispatchedToChildProcess() {
return NS_OK; return NS_OK;
} }
bool nsBaseDragService::MaybeAddChildProcess( bool nsBaseDragService::MaybeAddBrowser(BrowserParent* aBP) {
mozilla::dom::ContentParent* aChild) { nsWeakPtr browser = do_GetWeakReference(aBP);
if (!mChildProcesses.Contains(aChild)) {
mChildProcesses.AppendElement(aChild); // Equivalent to `InsertElementSorted`, avoiding inserting a duplicate
// element. See bug 1896166.
size_t index = mBrowsers.IndexOfFirstElementGt(browser);
if (index == 0 || mBrowsers[index - 1] != browser) {
mBrowsers.InsertElementAt(index, browser);
return true; return true;
} }
return false; return false;
} }
bool nsBaseDragService::RemoveAllChildProcesses() { bool nsBaseDragService::RemoveAllBrowsers() {
for (uint32_t c = 0; c < mChildProcesses.Length(); c++) { for (auto& weakBrowser : mBrowsers) {
mozilla::Unused << mChildProcesses[c]->SendEndDragSession( nsCOMPtr<BrowserParent> browser = do_QueryReferent(weakBrowser);
if (!browser) {
continue;
}
mozilla::Unused << browser->SendEndDragSession(
true, false, LayoutDeviceIntPoint(), 0, true, false, LayoutDeviceIntPoint(), 0,
nsIDragService::DRAGDROP_ACTION_NONE); nsIDragService::DRAGDROP_ACTION_NONE);
} }
mChildProcesses.Clear();
mBrowsers.Clear();
return true; return true;
} }

View File

@@ -13,7 +13,6 @@
#include "nsPoint.h" #include "nsPoint.h"
#include "nsString.h" #include "nsString.h"
#include "mozilla/RefPtr.h" #include "mozilla/RefPtr.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/HTMLCanvasElement.h" #include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/dom/MouseEventBinding.h" #include "mozilla/dom/MouseEventBinding.h"
#include "mozilla/dom/RemoteDragStartData.h" #include "mozilla/dom/RemoteDragStartData.h"
@@ -253,7 +252,8 @@ class nsBaseDragService : public nsIDragService, public nsBaseDragSession {
uint32_t mSuppressLevel; uint32_t mSuppressLevel;
nsTArray<RefPtr<mozilla::dom::ContentParent>> mChildProcesses; // Weak references to PBrowsers that are currently engaged in drags
nsTArray<nsWeakPtr> mBrowsers;
// Sub-region for tree-selections. // Sub-region for tree-selections.
mozilla::Maybe<mozilla::CSSIntRegion> mRegion; mozilla::Maybe<mozilla::CSSIntRegion> mRegion;

View File

@@ -22,14 +22,14 @@ interface nsIMockDragServiceController;
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
class ContentParent; class BrowserParent;
class DataTransfer; class DataTransfer;
class RemoteDragStartData; class RemoteDragStartData;
} // namespace dom } // namespace dom
} // namespace mozilla } // namespace mozilla
%} %}
[ptr] native ContentParentPtr(mozilla::dom::ContentParent); [ptr] native BrowserParentPtr(mozilla::dom::BrowserParent);
[ptr] native DataTransferPtr(mozilla::dom::DataTransfer); [ptr] native DataTransferPtr(mozilla::dom::DataTransfer);
[ptr] native RemoteDragStartDataPtr(mozilla::dom::RemoteDragStartData); [ptr] native RemoteDragStartDataPtr(mozilla::dom::RemoteDragStartData);
native EventMessage(mozilla::EventMessage); native EventMessage(mozilla::EventMessage);
@@ -184,8 +184,8 @@ interface nsIDragService : nsISupports
void suppress(); void suppress();
void unsuppress(); void unsuppress();
[notxpcom, nostdcall] boolean maybeAddChildProcess(in ContentParentPtr aChild); [notxpcom, nostdcall] boolean maybeAddBrowser(in BrowserParentPtr aBP);
[notxpcom, nostdcall] boolean removeAllChildProcesses(); [notxpcom, nostdcall] boolean removeAllBrowsers();
/** /**
* Retrun true if nsIDragSession's data is updated. * Retrun true if nsIDragSession's data is updated.