зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1586471 - Part 3. Allow to drop data from external application on GeckoView. r=dom-core,geckoview-reviewers,amejiamarmol,edgar
The dropped item is set on drop event handler in Android. Current Gecko's implementation caches dropped item as `DataTransfer` when any drag events are fired. It will works on desktop platform, but doesn't on GeckoView. Even if drop item is set by handling drop event, `DataTransfer`'s cache isn't refreshed. So if drop event is received, we re-fill DataTransfer on GeckoView. Differential Revision: https://phabricator.services.mozilla.com/D197331
This commit is contained in:
Родитель
d88b0348e7
Коммит
30d76ab208
|
@ -1720,7 +1720,8 @@ void EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent,
|
|||
}
|
||||
case eDragEventClass: {
|
||||
RefPtr<BrowserParent> browserParent = remote;
|
||||
browserParent->Manager()->MaybeInvokeDragSession(browserParent);
|
||||
browserParent->Manager()->MaybeInvokeDragSession(browserParent,
|
||||
aEvent->mMessage);
|
||||
|
||||
nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
|
||||
uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
|
||||
|
|
|
@ -3152,13 +3152,53 @@ 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) {
|
||||
nsCOMPtr<nsIDragService> dragService =
|
||||
do_GetService("@mozilla.org/widget/dragservice;1");
|
||||
if (dragService) {
|
||||
if (nsCOMPtr<nsIDragService> dragService =
|
||||
do_GetService("@mozilla.org/widget/dragservice;1")) {
|
||||
dragService->StartDragSession();
|
||||
nsCOMPtr<nsIDragSession> session;
|
||||
dragService->GetCurrentSession(getter_AddRefs(session));
|
||||
|
@ -3167,43 +3207,25 @@ mozilla::ipc::IPCResult ContentChild::RecvInvokeDragSession(
|
|||
session->SetSourceTopWindowContext(
|
||||
aSourceTopWindowContext.GetMaybeDiscarded());
|
||||
session->SetDragAction(aAction);
|
||||
// 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 =
|
||||
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 =
|
||||
new DataTransfer(nullptr, eDragStart, 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);
|
||||
}
|
||||
}
|
||||
ConvertToDataTransfer(std::move(aTransferables), aEventMessage);
|
||||
session->SetDataTransfer(dataTransfer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -415,6 +415,10 @@ class ContentChild final : public PContentChild,
|
|||
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,
|
||||
|
|
|
@ -5358,7 +5358,28 @@ bool ContentParent::DeallocPWebrtcGlobalParent(PWebrtcGlobalParent* aActor) {
|
|||
}
|
||||
#endif
|
||||
|
||||
void ContentParent::MaybeInvokeDragSession(BrowserParent* aParent) {
|
||||
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
|
||||
|
@ -5369,28 +5390,17 @@ void ContentParent::MaybeInvokeDragSession(BrowserParent* aParent) {
|
|||
|
||||
nsCOMPtr<nsIDragService> dragService =
|
||||
do_GetService("@mozilla.org/widget/dragservice;1");
|
||||
if (dragService && dragService->MaybeAddChildProcess(this)) {
|
||||
// We need to send transferable data to child process.
|
||||
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;
|
||||
RefPtr<DataTransfer> transfer = session->GetDataTransfer();
|
||||
if (!transfer) {
|
||||
// Pass eDrop to get DataTransfer with external
|
||||
// drag formats cached.
|
||||
transfer = new DataTransfer(nullptr, eDrop, true, -1);
|
||||
session->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, ipcTransferables, false, this);
|
||||
GetIPCTransferableData(session, aParent, ipcTransferables);
|
||||
uint32_t action;
|
||||
session->GetDragAction(&action);
|
||||
|
||||
|
@ -5401,6 +5411,19 @@ void ContentParent::MaybeInvokeDragSession(BrowserParent* aParent) {
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -463,7 +463,7 @@ class ContentParent final : public PContentParent,
|
|||
|
||||
mozilla::ipc::IPCResult RecvNotifyShutdownSuccess();
|
||||
|
||||
void MaybeInvokeDragSession(BrowserParent* aParent);
|
||||
void MaybeInvokeDragSession(BrowserParent* aParent, EventMessage aMessage);
|
||||
|
||||
PContentPermissionRequestParent* AllocPContentPermissionRequestParent(
|
||||
const nsTArray<PermissionRequest>& aRequests, nsIPrincipal* aPrincipal,
|
||||
|
@ -1417,6 +1417,9 @@ class ContentParent final : public PContentParent,
|
|||
return mThreadsafeHandle;
|
||||
}
|
||||
|
||||
void GetIPCTransferableData(nsIDragSession* aSession, BrowserParent* aParent,
|
||||
nsTArray<IPCTransferableData>& aIPCTransferables);
|
||||
|
||||
private:
|
||||
// Return an existing ContentParent if possible. Otherwise, `nullptr`.
|
||||
static already_AddRefed<ContentParent> GetUsedBrowserProcess(
|
||||
|
|
|
@ -98,6 +98,7 @@ using mozilla::gfx::IntSize from "mozilla/gfx/2D.h";
|
|||
using mozilla::gfx::SurfaceFormat from "mozilla/gfx/Types.h";
|
||||
using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
|
||||
using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
|
||||
using mozilla::EventMessage from "mozilla/EventForwards.h";
|
||||
using mozilla::LayoutDeviceIntPoint from "Units.h";
|
||||
using mozilla::ImagePoint from "Units.h";
|
||||
using mozilla::ImageIntSize from "Units.h";
|
||||
|
@ -824,6 +825,8 @@ child:
|
|||
MaybeDiscardedWindowContext aSourceTopWindowContext,
|
||||
IPCTransferableData[] transfers, uint32_t action);
|
||||
|
||||
async UpdateDragSession(IPCTransferableData[] transfers, EventMessage message);
|
||||
|
||||
async EndDragSession(bool aDoneDrag, bool aUserCancelled,
|
||||
LayoutDeviceIntPoint aDragEndPoint,
|
||||
uint32_t aKeyModifiers,
|
||||
|
|
|
@ -186,6 +186,12 @@ nsDragService::UpdateDragImage(nsINode* aImage, int32_t aImageX,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
bool nsDragService::MustUpdateDataTransfer(EventMessage aMessage) {
|
||||
// Android's drag and drop API sets drop item in drop event.
|
||||
// So we have to invalidate data transfer cache on drop event.
|
||||
return aMessage == eDrop;
|
||||
}
|
||||
|
||||
java::sdk::Bitmap::LocalRef nsDragService::CreateDragImage(
|
||||
nsINode* aNode, const Maybe<CSSIntRegion>& aRegion) {
|
||||
LayoutDeviceIntRect dragRect;
|
||||
|
@ -218,6 +224,8 @@ java::sdk::Bitmap::LocalRef nsDragService::CreateDragImage(
|
|||
|
||||
void nsDragService::SetData(nsITransferable* aTransferable) {
|
||||
mTransferable = aTransferable;
|
||||
// Reset DataTransfer
|
||||
mDataTransfer = nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
@ -30,6 +30,7 @@ class nsDragService final : public nsBaseDragService {
|
|||
uint32_t aKeyModifiers) override;
|
||||
NS_IMETHOD
|
||||
UpdateDragImage(nsINode* aImage, int32_t aImageX, int32_t aImageY) override;
|
||||
virtual bool MustUpdateDataTransfer(mozilla::EventMessage aMessage) override;
|
||||
|
||||
void SetData(nsITransferable* aTransferable);
|
||||
|
||||
|
|
|
@ -1025,6 +1025,10 @@ bool nsBaseDragService::RemoveAllChildProcesses() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool nsBaseDragService::MustUpdateDataTransfer(EventMessage aMessage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseDragService::MaybeEditorDeletedSourceNode(Element* aEditingHost) {
|
||||
// If builtin editor of Blink and WebKit deletes the source node,they retarget
|
||||
|
|
|
@ -194,6 +194,11 @@ interface nsIDragService : nsISupports
|
|||
[notxpcom, nostdcall] boolean maybeAddChildProcess(in ContentParentPtr aChild);
|
||||
[notxpcom, nostdcall] boolean removeAllChildProcesses();
|
||||
|
||||
/**
|
||||
* Retrun true if nsIDragSession's data is updated.
|
||||
*/
|
||||
[notxpcom, nostdcall] boolean mustUpdateDataTransfer(in EventMessage aMessage);
|
||||
|
||||
/**
|
||||
* Called when HTMLEditor maybe deleted the source node from the document.
|
||||
*
|
||||
|
|
Загрузка…
Ссылка в новой задаче