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:
@@ -463,7 +463,7 @@ class DataTransfer final : public nsISupports, public nsWrapperCache {
|
||||
nsresult SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData,
|
||||
uint32_t aIndex, nsIPrincipal* aSubjectPrincipal);
|
||||
|
||||
friend class ContentParent;
|
||||
friend class BrowserParent;
|
||||
friend class Clipboard;
|
||||
|
||||
void FillAllExternalData();
|
||||
|
||||
@@ -2031,8 +2031,7 @@ void EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent,
|
||||
}
|
||||
case eDragEventClass: {
|
||||
RefPtr<BrowserParent> browserParent = remote;
|
||||
browserParent->Manager()->MaybeInvokeDragSession(browserParent,
|
||||
aEvent->mMessage);
|
||||
browserParent->MaybeInvokeDragSession(aEvent->mMessage);
|
||||
|
||||
RefPtr<nsIWidget> widget = browserParent->GetTopLevelWidget();
|
||||
nsCOMPtr<nsIDragSession> dragSession =
|
||||
@@ -2436,7 +2435,7 @@ void EventStateManager::StopTrackingDragGesture(bool aClearInChildProcesses) {
|
||||
dragService->GetCurrentSession(mPresContext->GetRootWidget());
|
||||
if (!dragSession) {
|
||||
// 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.
|
||||
dragSession->SetOnlyChromeDrop(true);
|
||||
}
|
||||
if (ContentChild* child = ContentChild::GetSingleton()) {
|
||||
child->SendUpdateDropEffect(action, dropEffect);
|
||||
if (auto* bc = BrowserChild::GetFrom(presContext->GetDocShell())) {
|
||||
bc->SendUpdateDropEffect(action, dropEffect);
|
||||
}
|
||||
if (aEvent->HasBeenPostedToRemoteProcess()) {
|
||||
dragSession->SetCanDrop(true);
|
||||
@@ -4392,18 +4391,18 @@ nsresult EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
||||
ClearGlobalActiveContent(this);
|
||||
break;
|
||||
}
|
||||
case eDragExit:
|
||||
case eDragExit: {
|
||||
// make sure to fire the enter and exit_synth events after the
|
||||
// eDragExit event, otherwise we'll clean up too early
|
||||
GenerateDragDropEnterExit(presContext, aEvent->AsDragEvent());
|
||||
if (ContentChild* child = ContentChild::GetSingleton()) {
|
||||
if (auto* bc = BrowserChild::GetFrom(presContext->GetDocShell())) {
|
||||
// SendUpdateDropEffect to prevent nsIDragService from waiting for
|
||||
// response of forwarded dragexit event.
|
||||
child->SendUpdateDropEffect(nsIDragService::DRAGDROP_ACTION_NONE,
|
||||
bc->SendUpdateDropEffect(nsIDragService::DRAGDROP_ACTION_NONE,
|
||||
nsIDragService::DRAGDROP_ACTION_NONE);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case eKeyUp:
|
||||
// If space key is released, we need to inactivate the element which was
|
||||
// activated by preceding space key down.
|
||||
|
||||
@@ -112,6 +112,7 @@
|
||||
#include "nsRefreshDriver.h"
|
||||
#include "nsThreadManager.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsVariant.h"
|
||||
#include "nsViewManager.h"
|
||||
#include "nsWebBrowser.h"
|
||||
#include "nsWindowWatcher.h"
|
||||
@@ -1921,6 +1922,103 @@ mozilla::ipc::IPCResult BrowserChild::RecvRealDragEvent(
|
||||
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,
|
||||
const WidgetKeyboardEvent& aEvent,
|
||||
nsTArray<CommandInt>& aCommands) {
|
||||
|
||||
@@ -659,6 +659,22 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
||||
|
||||
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:
|
||||
virtual ~BrowserChild();
|
||||
|
||||
|
||||
@@ -263,8 +263,10 @@ BrowserParent::LayerToBrowserParentTable*
|
||||
BrowserParent::sLayerToBrowserParentTable = nullptr;
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserParent)
|
||||
NS_INTERFACE_MAP_ENTRY_CONCRETE(BrowserParent)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
@@ -3868,7 +3870,7 @@ mozilla::ipc::IPCResult BrowserParent::RecvInvokeDragSession(
|
||||
const MaybeDiscarded<WindowContext>& aSourceTopWindowContext) {
|
||||
PresShell* presShell = mFrameElement->OwnerDoc()->GetPresShell();
|
||||
if (!presShell) {
|
||||
Unused << Manager()->SendEndDragSession(
|
||||
Unused << SendEndDragSession(
|
||||
true, true, LayoutDeviceIntPoint(), 0,
|
||||
nsIDragService::DRAGDROP_ACTION_NONE);
|
||||
// Continue sending input events with input priority when stopping the dnd
|
||||
@@ -3899,7 +3901,7 @@ mozilla::ipc::IPCResult BrowserParent::RecvInvokeDragSession(
|
||||
nsCOMPtr<nsIDragService> dragService =
|
||||
do_GetService("@mozilla.org/widget/dragservice;1");
|
||||
if (dragService) {
|
||||
dragService->MaybeAddChildProcess(Manager());
|
||||
dragService->MaybeAddBrowser(this);
|
||||
}
|
||||
|
||||
presShell->GetPresContext()
|
||||
@@ -3912,6 +3914,95 @@ mozilla::ipc::IPCResult BrowserParent::RecvInvokeDragSession(
|
||||
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 {
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
return widget && widget->AsyncPanZoomEnabled();
|
||||
|
||||
@@ -78,6 +78,14 @@ namespace ipc {
|
||||
class StructuredCloneData;
|
||||
} // 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
|
||||
* PBrowser for more information.
|
||||
@@ -99,6 +107,7 @@ class BrowserParent final : public PBrowserParent,
|
||||
// Helper class for ContentParent::RecvCreateWindow.
|
||||
struct AutoUseNewTab;
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(DOM_BROWSERPARENT_IID)
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_NSIAUTHPROMPTPROVIDER
|
||||
// nsIDOMEventListener interfaces
|
||||
@@ -672,6 +681,9 @@ class BrowserParent final : public PBrowserParent,
|
||||
const MaybeDiscarded<WindowContext>& aSourceWindowContext,
|
||||
const MaybeDiscarded<WindowContext>& aSourceTopWindowContext);
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateDropEffect(const uint32_t& aDragAction,
|
||||
const uint32_t& aDropEffect);
|
||||
|
||||
void AddInitialDnDDataTo(IPCTransferableData* aTransferableData,
|
||||
nsIPrincipal** aPrincipal);
|
||||
|
||||
@@ -709,6 +721,8 @@ class BrowserParent final : public PBrowserParent,
|
||||
// Called when the BrowserParent is being destroyed or entering bfcache.
|
||||
void Deactivated();
|
||||
|
||||
void MaybeInvokeDragSession(EventMessage aMessage);
|
||||
|
||||
protected:
|
||||
friend BrowserBridgeParent;
|
||||
friend BrowserHost;
|
||||
@@ -753,6 +767,9 @@ class BrowserParent final : public PBrowserParent,
|
||||
|
||||
mozilla::ipc::IPCResult RecvShowDynamicToolbar();
|
||||
|
||||
void GetIPCTransferableData(nsIDragSession* aSession,
|
||||
nsTArray<IPCTransferableData>& aIPCTransferables);
|
||||
|
||||
private:
|
||||
void SuppressDisplayport(bool aEnabled);
|
||||
|
||||
@@ -995,6 +1012,8 @@ class BrowserParent final : public PBrowserParent,
|
||||
bool mShowingTooltip : 1;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(BrowserParent, DOM_BROWSERPARENT_IID)
|
||||
|
||||
struct MOZ_STACK_CLASS BrowserParent::AutoUseNewTab final {
|
||||
public:
|
||||
explicit AutoUseNewTab(BrowserParent* aNewTab) : mNewTab(aNewTab) {
|
||||
|
||||
@@ -201,7 +201,6 @@
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsStyleSheetService.h"
|
||||
#include "nsThreadManager.h"
|
||||
#include "nsVariant.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "IHistory.h"
|
||||
#include "ReferrerInfo.h"
|
||||
@@ -3218,111 +3217,6 @@ mozilla::ipc::IPCResult ContentChild::RecvPWebBrowserPersistDocumentConstructor(
|
||||
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,
|
||||
nsIPrincipal* aPrincipal,
|
||||
const nsString& aMessageId) {
|
||||
|
||||
@@ -413,21 +413,6 @@ class ContentChild final : public PContentChild,
|
||||
|
||||
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,
|
||||
nsIPrincipal* aPrincipal,
|
||||
const nsString& aMessageId);
|
||||
|
||||
@@ -5177,95 +5177,6 @@ bool ContentParent::DeallocPWebrtcGlobalParent(PWebrtcGlobalParent* aActor) {
|
||||
}
|
||||
#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*
|
||||
ContentParent::AllocPContentPermissionRequestParent(
|
||||
const nsTArray<PermissionRequest>& aRequests, nsIPrincipal* aPrincipal,
|
||||
|
||||
@@ -518,8 +518,6 @@ class ContentParent final : public PContentParent,
|
||||
|
||||
mozilla::ipc::IPCResult RecvNotifyShutdownSuccess();
|
||||
|
||||
void MaybeInvokeDragSession(BrowserParent* aParent, EventMessage aMessage);
|
||||
|
||||
PContentPermissionRequestParent* AllocPContentPermissionRequestParent(
|
||||
const nsTArray<PermissionRequest>& aRequests, nsIPrincipal* aPrincipal,
|
||||
nsIPrincipal* aTopLevelPrincipal, const bool& aIsHandlingUserInput,
|
||||
@@ -1103,9 +1101,6 @@ class ContentParent final : public PContentParent,
|
||||
bool DeallocPWebrtcGlobalParent(PWebrtcGlobalParent* aActor);
|
||||
#endif
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateDropEffect(const uint32_t& aDragAction,
|
||||
const uint32_t& aDropEffect);
|
||||
|
||||
mozilla::ipc::IPCResult RecvShutdownProfile(const nsACString& aProfile);
|
||||
|
||||
mozilla::ipc::IPCResult RecvShutdownPerfStats(const nsACString& aPerfStats);
|
||||
@@ -1419,9 +1414,6 @@ class ContentParent final : public PContentParent,
|
||||
return mThreadsafeHandle;
|
||||
}
|
||||
|
||||
void GetIPCTransferableData(nsIDragSession* aSession, BrowserParent* aParent,
|
||||
nsTArray<IPCTransferableData>& aIPCTransferables);
|
||||
|
||||
RemoteWorkerServiceParent* GetRemoteWorkerServiceParent() const {
|
||||
return mRemoteWorkerServiceActor;
|
||||
}
|
||||
|
||||
@@ -1003,6 +1003,19 @@ child:
|
||||
|
||||
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:
|
||||
/**
|
||||
* Fetches whether this window supports protected media, which is sent back in response.
|
||||
@@ -1029,6 +1042,8 @@ parent:
|
||||
async NewWindowGlobal(ManagedEndpoint<PWindowGlobalParent> aEndpoint,
|
||||
WindowGlobalInit aInit);
|
||||
|
||||
async UpdateDropEffect(uint32_t aDragAction, uint32_t aDropEffect);
|
||||
|
||||
/*
|
||||
* FIXME: write protocol!
|
||||
|
||||
|
||||
@@ -826,17 +826,6 @@ child:
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
@@ -1306,8 +1295,6 @@ parent:
|
||||
*/
|
||||
async FinishShutdown();
|
||||
|
||||
async UpdateDropEffect(uint32_t aDragAction, uint32_t aDropEffect);
|
||||
|
||||
/**
|
||||
* Initiates an asynchronous request for permission for the
|
||||
* provided principal.
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/ViewportUtils.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/BrowserParent.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/DataTransferItemList.h"
|
||||
#include "mozilla/dom/DataTransfer.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
@@ -44,7 +46,6 @@
|
||||
#include "mozilla/dom/Selection.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "nsFrameLoader.h"
|
||||
#include "BrowserParent.h"
|
||||
#include "nsIMutableArray.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxPlatform.h"
|
||||
@@ -626,14 +627,19 @@ nsBaseDragService::EndDragSession(bool aDoneDrag, uint32_t aKeyModifiers) {
|
||||
dropEffect = mDataTransfer->DropEffectInt();
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mChildProcesses.Length(); ++i) {
|
||||
mozilla::Unused << mChildProcesses[i]->SendEndDragSession(
|
||||
aDoneDrag, mUserCancelled, mEndDragPoint, aKeyModifiers, dropEffect);
|
||||
for (nsWeakPtr& browser : mBrowsers) {
|
||||
nsCOMPtr<BrowserParent> bp = do_QueryReferent(browser);
|
||||
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
|
||||
// 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
|
||||
// explicitly deref the contained data here so that we don't have to wait for
|
||||
@@ -1026,22 +1032,31 @@ nsBaseDragSession::DragEventDispatchedToChildProcess() {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool nsBaseDragService::MaybeAddChildProcess(
|
||||
mozilla::dom::ContentParent* aChild) {
|
||||
if (!mChildProcesses.Contains(aChild)) {
|
||||
mChildProcesses.AppendElement(aChild);
|
||||
bool nsBaseDragService::MaybeAddBrowser(BrowserParent* aBP) {
|
||||
nsWeakPtr browser = do_GetWeakReference(aBP);
|
||||
|
||||
// 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 false;
|
||||
}
|
||||
|
||||
bool nsBaseDragService::RemoveAllChildProcesses() {
|
||||
for (uint32_t c = 0; c < mChildProcesses.Length(); c++) {
|
||||
mozilla::Unused << mChildProcesses[c]->SendEndDragSession(
|
||||
bool nsBaseDragService::RemoveAllBrowsers() {
|
||||
for (auto& weakBrowser : mBrowsers) {
|
||||
nsCOMPtr<BrowserParent> browser = do_QueryReferent(weakBrowser);
|
||||
if (!browser) {
|
||||
continue;
|
||||
}
|
||||
mozilla::Unused << browser->SendEndDragSession(
|
||||
true, false, LayoutDeviceIntPoint(), 0,
|
||||
nsIDragService::DRAGDROP_ACTION_NONE);
|
||||
}
|
||||
mChildProcesses.Clear();
|
||||
|
||||
mBrowsers.Clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "nsPoint.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
#include "mozilla/dom/MouseEventBinding.h"
|
||||
#include "mozilla/dom/RemoteDragStartData.h"
|
||||
@@ -253,7 +252,8 @@ class nsBaseDragService : public nsIDragService, public nsBaseDragSession {
|
||||
|
||||
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.
|
||||
mozilla::Maybe<mozilla::CSSIntRegion> mRegion;
|
||||
|
||||
@@ -22,14 +22,14 @@ interface nsIMockDragServiceController;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class ContentParent;
|
||||
class BrowserParent;
|
||||
class DataTransfer;
|
||||
class RemoteDragStartData;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
%}
|
||||
|
||||
[ptr] native ContentParentPtr(mozilla::dom::ContentParent);
|
||||
[ptr] native BrowserParentPtr(mozilla::dom::BrowserParent);
|
||||
[ptr] native DataTransferPtr(mozilla::dom::DataTransfer);
|
||||
[ptr] native RemoteDragStartDataPtr(mozilla::dom::RemoteDragStartData);
|
||||
native EventMessage(mozilla::EventMessage);
|
||||
@@ -184,8 +184,8 @@ interface nsIDragService : nsISupports
|
||||
void suppress();
|
||||
void unsuppress();
|
||||
|
||||
[notxpcom, nostdcall] boolean maybeAddChildProcess(in ContentParentPtr aChild);
|
||||
[notxpcom, nostdcall] boolean removeAllChildProcesses();
|
||||
[notxpcom, nostdcall] boolean maybeAddBrowser(in BrowserParentPtr aBP);
|
||||
[notxpcom, nostdcall] boolean removeAllBrowsers();
|
||||
|
||||
/**
|
||||
* Retrun true if nsIDragSession's data is updated.
|
||||
|
||||
Reference in New Issue
Block a user