зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1910452: Part 1 - Intercept drop events for content analysis r=smaug,dlp-reviewers,gstoll,reusable-components-reviewers,mstriemer
Sends OOP drop events to content analysis for approval before sending them to the DOM. It intercepts drop events at the browser level and sends them to CA before calling stopPropagation and preventDefault on them. (CA also presents a modal dialog over the tab.) The drag session then ends as usual in the parent process but remains open on the related browser in the process where it would be sent to the DOM while the drop is being analyzed. While CA runs, the browser dispatches an eQueryDropTargetHittest event to locate the drop target while the event screen coordinates are still valid. When CA is complete, a drop or dragexit event is sent to the drop target (drop if it was approved by CA). Calls to EndDragSession are delayed during this. Differential Revision: https://phabricator.services.mozilla.com/D219201
This commit is contained in:
Родитель
4c7853342b
Коммит
8b722be621
|
@ -1485,6 +1485,9 @@ nsresult ContentEventHandler::HandleQueryContentEvent(
|
|||
case eQueryDOMWidgetHittest:
|
||||
rv = OnQueryDOMWidgetHittest(aEvent);
|
||||
break;
|
||||
case eQueryDropTargetHittest:
|
||||
rv = OnQueryDropTargetHittest(aEvent);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -3065,8 +3068,9 @@ nsresult ContentEventHandler::OnQueryCharacterAtPoint(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult ContentEventHandler::OnQueryDOMWidgetHittest(
|
||||
WidgetQueryContentEvent* aEvent) {
|
||||
nsresult ContentEventHandler::QueryHittestImpl(WidgetQueryContentEvent* aEvent,
|
||||
bool aFlushLayout,
|
||||
Element** aContentUnderMouse) {
|
||||
NS_ASSERTION(aEvent, "aEvent must not be null");
|
||||
|
||||
nsresult rv = InitBasic();
|
||||
|
@ -3074,8 +3078,6 @@ nsresult ContentEventHandler::OnQueryDOMWidgetHittest(
|
|||
return rv;
|
||||
}
|
||||
|
||||
aEvent->mReply->mWidgetIsHit = false;
|
||||
|
||||
NS_ENSURE_TRUE(aEvent->mWidget, NS_ERROR_FAILURE);
|
||||
|
||||
PresShell* presShell = mDocument->GetPresShell();
|
||||
|
@ -3091,9 +3093,21 @@ nsresult ContentEventHandler::OnQueryDOMWidgetHittest(
|
|||
docFrameRect.x,
|
||||
docFrame->PresContext()->DevPixelsToIntCSSPixels(eventLoc.y) -
|
||||
docFrameRect.y);
|
||||
RefPtr<Element> contentUnderMouse = mDocument->ElementFromPointHelper(
|
||||
eventLocCSS.x, eventLocCSS.y, false, false, ViewportType::Visual);
|
||||
|
||||
if (Element* contentUnderMouse = mDocument->ElementFromPointHelper(
|
||||
eventLocCSS.x, eventLocCSS.y, false, false, ViewportType::Visual)) {
|
||||
contentUnderMouse.forget(aContentUnderMouse);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult ContentEventHandler::OnQueryDOMWidgetHittest(
|
||||
WidgetQueryContentEvent* aEvent) {
|
||||
aEvent->mReply->mWidgetIsHit = false;
|
||||
RefPtr<Element> contentUnderMouse;
|
||||
nsresult rv =
|
||||
QueryHittestImpl(aEvent, true, getter_AddRefs(contentUnderMouse));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (contentUnderMouse) {
|
||||
if (nsIFrame* targetFrame = contentUnderMouse->GetPrimaryFrame()) {
|
||||
if (aEvent->mWidget == targetFrame->GetNearestWidget()) {
|
||||
aEvent->mReply->mWidgetIsHit = true;
|
||||
|
@ -3105,6 +3119,19 @@ nsresult ContentEventHandler::OnQueryDOMWidgetHittest(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult ContentEventHandler::OnQueryDropTargetHittest(
|
||||
WidgetQueryContentEvent* aEvent) {
|
||||
RefPtr<Element> contentUnderMouse;
|
||||
nsresult rv =
|
||||
QueryHittestImpl(aEvent, true, getter_AddRefs(contentUnderMouse));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
aEvent->EmplaceReply();
|
||||
aEvent->mReply->mDropElement = contentUnderMouse;
|
||||
aEvent->mReply->mDropFrame =
|
||||
mDocument->GetPresShell()->GetCurrentEventFrame();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult ContentEventHandler::GetFlatTextLengthInRange(
|
||||
const RawNodePosition& aStartPosition, const RawNodePosition& aEndPosition,
|
||||
|
|
|
@ -164,6 +164,9 @@ class MOZ_STACK_CLASS ContentEventHandler {
|
|||
// eQueryDOMWidgetHittest event handler
|
||||
MOZ_CAN_RUN_SCRIPT nsresult
|
||||
OnQueryDOMWidgetHittest(WidgetQueryContentEvent* aEvent);
|
||||
// eQueryDropTargetHittest event handler
|
||||
MOZ_CAN_RUN_SCRIPT nsresult
|
||||
OnQueryDropTargetHittest(WidgetQueryContentEvent* aEvent);
|
||||
|
||||
// NS_SELECTION_* event
|
||||
MOZ_CAN_RUN_SCRIPT nsresult OnSelectionEvent(WidgetSelectionEvent* aEvent);
|
||||
|
@ -611,6 +614,9 @@ class MOZ_STACK_CLASS ContentEventHandler {
|
|||
static nsRect GetCaretRectAfter(nsPresContext& aPresContext,
|
||||
const nsRect& aCharRect,
|
||||
const WritingMode& aWritingMode);
|
||||
|
||||
nsresult QueryHittestImpl(WidgetQueryContentEvent* aEvent, bool aFlushLayout,
|
||||
Element** aContentUnderMouse);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -1519,6 +1519,7 @@ void EventStateManager::HandleQueryContentEvent(
|
|||
case eQueryCharacterAtPoint:
|
||||
case eQueryDOMWidgetHittest:
|
||||
case eQueryTextRectArray:
|
||||
case eQueryDropTargetHittest:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
|
|
|
@ -2053,6 +2053,55 @@ mozilla::ipc::IPCResult BrowserChild::RecvEndDragSession(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserChild::RecvStoreDropTargetAndDelayEndDragSession(
|
||||
const LayoutDeviceIntPoint& aPt, uint32_t aDropEffect, uint32_t aDragAction,
|
||||
nsIPrincipal* aPrincipal, nsIContentSecurityPolicy* aCsp) {
|
||||
// cf. RecvRealDragEvent
|
||||
nsCOMPtr<nsIDragSession> dragSession = GetDragSession();
|
||||
MOZ_ASSERT(dragSession);
|
||||
dragSession->SetDragAction(aDragAction);
|
||||
dragSession->SetTriggeringPrincipal(aPrincipal);
|
||||
dragSession->SetCsp(aCsp);
|
||||
RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
|
||||
if (initialDataTransfer) {
|
||||
initialDataTransfer->SetDropEffectInt(aDropEffect);
|
||||
}
|
||||
|
||||
bool canDrop = true;
|
||||
if (!dragSession || NS_FAILED(dragSession->GetCanDrop(&canDrop)) ||
|
||||
!canDrop) {
|
||||
// Don't record the target or delay EDS calls.
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
auto parentToChildTf = GetChildToParentConversionMatrix().MaybeInverse();
|
||||
NS_ENSURE_TRUE(parentToChildTf, IPC_OK());
|
||||
LayoutDevicePoint floatPt(aPt);
|
||||
LayoutDevicePoint floatTf = parentToChildTf->TransformPoint(floatPt);
|
||||
WidgetQueryContentEvent queryEvent(true, eQueryDropTargetHittest,
|
||||
mPuppetWidget);
|
||||
queryEvent.mRefPoint = RoundedToInt(floatTf);
|
||||
DispatchWidgetEventViaAPZ(queryEvent);
|
||||
if (queryEvent.mReply && queryEvent.mReply->mDropElement) {
|
||||
mDelayedDropPoint = queryEvent.mRefPoint;
|
||||
dragSession->StoreDropTargetAndDelayEndDragSession(
|
||||
queryEvent.mReply->mDropElement, queryEvent.mReply->mDropFrame);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BrowserChild::RecvDispatchToDropTargetAndResumeEndDragSession(
|
||||
bool aShouldDrop) {
|
||||
nsCOMPtr<nsIDragSession> dragSession = GetDragSession();
|
||||
MOZ_ASSERT(dragSession);
|
||||
RefPtr<nsIWidget> widget = mPuppetWidget;
|
||||
dragSession->DispatchToDropTargetAndResumeEndDragSession(
|
||||
widget, mDelayedDropPoint, aShouldDrop);
|
||||
mDelayedDropPoint = {};
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void BrowserChild::RequestEditCommands(NativeKeyBindingsType aType,
|
||||
const WidgetKeyboardEvent& aEvent,
|
||||
nsTArray<CommandInt>& aCommands) {
|
||||
|
|
|
@ -697,6 +697,15 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
|||
const mozilla::LayoutDeviceIntPoint& aEndDragPoint,
|
||||
const uint32_t& aKeyModifiers, const uint32_t& aDropEffect);
|
||||
|
||||
mozilla::ipc::IPCResult RecvStoreDropTargetAndDelayEndDragSession(
|
||||
const LayoutDeviceIntPoint& aPt, uint32_t aDropEffect,
|
||||
uint32_t aDragAction, nsIPrincipal* aPrincipal,
|
||||
nsIContentSecurityPolicy* aCsp);
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
mozilla::ipc::IPCResult RecvDispatchToDropTargetAndResumeEndDragSession(
|
||||
bool aShouldDrop);
|
||||
|
||||
protected:
|
||||
virtual ~BrowserChild();
|
||||
|
||||
|
@ -826,6 +835,9 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
|||
ScreenIntCoord mKeyboardHeight;
|
||||
TabId mUniqueId;
|
||||
|
||||
// Position of a delayed drop event.
|
||||
LayoutDeviceIntPoint mDelayedDropPoint;
|
||||
|
||||
bool mDidFakeShow : 1;
|
||||
bool mTriedBrowserInit : 1;
|
||||
bool mHasValidInnerSize : 1;
|
||||
|
|
|
@ -1033,6 +1033,24 @@ child:
|
|||
uint32_t aKeyModifiers,
|
||||
uint32_t aDropEffect);
|
||||
|
||||
/**
|
||||
* Use a eQueryDropTargetHittest event to obtain the element under aPt.
|
||||
* Store that in the current drag session for later event targetting.
|
||||
* Also tell the drag session to hold off on running EndDragSession
|
||||
* until it is told to resume.
|
||||
*/
|
||||
async StoreDropTargetAndDelayEndDragSession(
|
||||
LayoutDeviceIntPoint aPt, uint32_t aDropEffect, uint32_t aDragAction,
|
||||
nullable nsIPrincipal aPrincipal,
|
||||
nullable nsIContentSecurityPolicy aCsp);
|
||||
|
||||
/**
|
||||
* Send a drop (if aShouldDrop) or dragexit (otherwise) event to the
|
||||
* recorded drop target and issue any EndDragSession call that was stopped
|
||||
* by StoreDropTargetAndDelayEndDragSession (if any).
|
||||
*/
|
||||
async DispatchToDropTargetAndResumeEndDragSession(bool aShouldDrop);
|
||||
|
||||
parent:
|
||||
/**
|
||||
* Fetches whether this window supports protected media, which is sent back in response.
|
||||
|
|
|
@ -30,6 +30,13 @@
|
|||
Services.io.newURI("about:blank")
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
lazy,
|
||||
"contentAnalysis",
|
||||
"@mozilla.org/contentanalysis;1",
|
||||
Ci.nsIContentAnalysis
|
||||
);
|
||||
|
||||
let lazyPrefs = {};
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
lazyPrefs,
|
||||
|
@ -159,6 +166,128 @@
|
|||
this.addEventListener(
|
||||
"drop",
|
||||
event => {
|
||||
if (lazy.contentAnalysis.isActive) {
|
||||
let dragService = Cc[
|
||||
"@mozilla.org/widget/dragservice;1"
|
||||
].getService(Ci.nsIDragService);
|
||||
let dragSession = dragService.getCurrentSession(window);
|
||||
if (!dragSession) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't check items from drags that take place inside of a single
|
||||
// frame, or in a same-origin iframe hierarchy. Drag sessions with an
|
||||
// external source have no sourceWindowContext and must be checked.
|
||||
let sourceWC = dragSession.sourceWindowContext;
|
||||
let targetWC = this.browsingContext?.currentWindowContext;
|
||||
if (!targetWC) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
sourceWC &&
|
||||
sourceWC.browsingContext.top == targetWC.browsingContext.top &&
|
||||
targetWC.documentPrincipal?.subsumes(sourceWC.documentPrincipal)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a request for each text and file item in the DataTransfer
|
||||
try {
|
||||
// Submit a content analysis request for each checkable entry in the
|
||||
// DataTransfer and stop dispatching this drop event. Reissue the
|
||||
// drop if all requests are permitted.
|
||||
let caPromises = [];
|
||||
let items = event.dataTransfer.items;
|
||||
for (let elt of items) {
|
||||
const kTextMimeTypes = [
|
||||
"text/plain",
|
||||
"text/html",
|
||||
"application/x-moz-nativehtml",
|
||||
];
|
||||
|
||||
let requestFields;
|
||||
if (
|
||||
elt.kind === "string" &&
|
||||
kTextMimeTypes.includes(elt.type)
|
||||
) {
|
||||
let str = event.dataTransfer.getData(elt.type);
|
||||
if (!str) {
|
||||
continue;
|
||||
}
|
||||
requestFields = {
|
||||
analysisType: Ci.nsIContentAnalysisRequest.eBulkDataEntry,
|
||||
operationTypeForDisplay:
|
||||
Ci.nsIContentAnalysisRequest.eDroppedText,
|
||||
textContent: str,
|
||||
};
|
||||
} else if (elt.kind === "file") {
|
||||
let file = elt.getAsFile();
|
||||
requestFields = {
|
||||
analysisType: Ci.nsIContentAnalysisRequest.eFileAttached,
|
||||
operationTypeForDisplay:
|
||||
Ci.nsIContentAnalysisRequest.eCustomDisplayString,
|
||||
operationDisplayString: file.name,
|
||||
filePath: file.mozFullPath,
|
||||
};
|
||||
} else {
|
||||
// Unrecognized data type -- don't send to content analysis
|
||||
continue;
|
||||
}
|
||||
|
||||
caPromises.push(
|
||||
lazy.contentAnalysis.analyzeContentRequest(
|
||||
{
|
||||
requestToken: Services.uuid.generateUUID().toString(),
|
||||
resources: [],
|
||||
url: dragSession.uriForEvent(event),
|
||||
windowGlobalParent:
|
||||
this.browsingContext.currentWindowContext,
|
||||
...requestFields,
|
||||
},
|
||||
true /* autoAcknowledge */
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (!caPromises.length) {
|
||||
// Nothing was analyzable.
|
||||
return;
|
||||
}
|
||||
|
||||
// Tell browser to record the event target and to delay EndDragSession
|
||||
// until the results are given.
|
||||
dragSession.sendStoreDropTargetAndDelayEndDragSession(event);
|
||||
|
||||
// Only permit the drop if all requests were approved. Issue dragexit
|
||||
// instead of drop if CA rejected the content or there was an error.
|
||||
Promise.all(caPromises).then(
|
||||
caResults => {
|
||||
let allApproved = caResults.reduce((prev, current) => {
|
||||
return prev && current.shouldAllowContent;
|
||||
}, true);
|
||||
dragSession.sendDispatchToDropTargetAndResumeEndDragSession(
|
||||
allApproved
|
||||
);
|
||||
},
|
||||
() => {
|
||||
dragSession.sendDispatchToDropTargetAndResumeEndDragSession(
|
||||
false
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// Do not allow this drop to continue dispatch.
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
} catch {
|
||||
// On internal error, deny any drop. CA has its own behavior to
|
||||
// handle internal errors, like a lost connection to the agent, but
|
||||
// we are more strict when facing errors here.
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
// No need to handle "drop" in e10s, since nsDocShellTreeOwner.cpp in the child process
|
||||
// handles that case using "@mozilla.org/content/dropped-link-handler;1" service.
|
||||
if (
|
||||
|
|
|
@ -287,6 +287,9 @@ NS_EVENT_MESSAGE(eQueryCharacterAtPoint)
|
|||
// Query if the DOM element under Event::mRefPoint belongs to our widget
|
||||
// or not.
|
||||
NS_EVENT_MESSAGE(eQueryDOMWidgetHittest)
|
||||
// Query for the DOM element under Event::mRefPoint that is the target of a
|
||||
// delayed drop event.
|
||||
NS_EVENT_MESSAGE(eQueryDropTargetHittest)
|
||||
|
||||
// Video events
|
||||
NS_EVENT_MESSAGE(eLoadStart)
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "mozilla/ipc/IPCForwards.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsHashtablesFwd.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsISelectionListener.h"
|
||||
#include "nsITransferable.h"
|
||||
#include "nsRect.h"
|
||||
|
@ -1248,6 +1249,10 @@ class WidgetQueryContentEvent : public WidgetGUIEvent {
|
|||
bool mWidgetIsHit = false;
|
||||
// true if mContentRoot is focused editable content
|
||||
bool mIsEditableContent = false;
|
||||
// Set to the element that a drop at the given coordinates would target
|
||||
mozilla::dom::Element* mDropElement;
|
||||
// Set to the frame that a drop at the given coordinates would target
|
||||
nsIFrame* mDropFrame;
|
||||
|
||||
Reply() = delete;
|
||||
explicit Reply(EventMessage aEventMessage) : mEventMessage(aEventMessage) {}
|
||||
|
|
|
@ -132,6 +132,7 @@ bool IsForbiddenDispatchingToNonElementContent(EventMessage aMessage) {
|
|||
case eDragStart:
|
||||
case eDrop:
|
||||
case eDragLeave:
|
||||
case eQueryDropTargetHittest:
|
||||
// case mouse wheel related message target should be an Element node
|
||||
case eLegacyMouseLineOrPageScroll:
|
||||
case eLegacyMousePixelScroll:
|
||||
|
@ -551,7 +552,9 @@ bool WidgetEvent::WillBeSentToRemoteProcess() const {
|
|||
}
|
||||
|
||||
bool WidgetEvent::IsIMERelatedEvent() const {
|
||||
return HasIMEEventMessage() || IsQueryContentEvent() || IsSelectionEvent();
|
||||
return HasIMEEventMessage() ||
|
||||
(IsQueryContentEvent() && mMessage != eQueryDropTargetHittest) ||
|
||||
IsSelectionEvent();
|
||||
}
|
||||
|
||||
bool WidgetEvent::IsUsingCoordinates() const {
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "mozilla/ViewportUtils.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/BrowserParent.h"
|
||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/DataTransferItemList.h"
|
||||
#include "mozilla/dom/DataTransfer.h"
|
||||
|
@ -674,11 +675,20 @@ int32_t nsBaseDragSession::TakeChildProcessDragAction() {
|
|||
//-------------------------------------------------------------------------
|
||||
NS_IMETHODIMP
|
||||
nsBaseDragSession::EndDragSession(bool aDoneDrag, uint32_t aKeyModifiers) {
|
||||
if (mDelayedDropTarget) {
|
||||
if (!mEndDragSessionData) {
|
||||
EndDragSessionData edsData = {aDoneDrag, aKeyModifiers};
|
||||
mEndDragSessionData = Some(edsData);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
return EndDragSessionImpl(aDoneDrag, aKeyModifiers);
|
||||
}
|
||||
|
||||
nsresult nsBaseDragSession::EndDragSessionImpl(bool aDoneDrag,
|
||||
uint32_t aKeyModifiers) {
|
||||
MOZ_DRAGSERVICE_LOG("[%p] EndDragSession | mDoingDrag %s", this,
|
||||
mDoingDrag ? "true" : "false");
|
||||
if (!mDoingDrag || mEndingSession) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -1265,3 +1275,98 @@ nsIWidget* nsBaseDragService::GetWidgetFromWidgetProvider(
|
|||
NS_ENSURE_TRUE(vm, nullptr);
|
||||
return vm->GetRootWidget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseDragSession::UriForEvent(DragEvent* aEvent, nsIURI** aUri) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
*aUri = nullptr;
|
||||
auto* widgetEvent = aEvent->WidgetEventPtr();
|
||||
MOZ_ASSERT(widgetEvent);
|
||||
auto* bp =
|
||||
dom::BrowserParent::GetBrowserParentFromLayersId(widgetEvent->mLayersId);
|
||||
NS_ENSURE_TRUE(bp, NS_ERROR_FAILURE);
|
||||
auto* bc = bp->GetBrowsingContext();
|
||||
NS_ENSURE_TRUE(bc, NS_ERROR_FAILURE);
|
||||
RefPtr<nsIURI> ret = bc->GetCurrentURI();
|
||||
ret.forget(aUri);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseDragSession::SendStoreDropTargetAndDelayEndDragSession(
|
||||
DragEvent* aEvent) {
|
||||
mDelayedDropBrowserParent = dom::BrowserParent::GetBrowserParentFromLayersId(
|
||||
aEvent->WidgetEventPtr()->mLayersId);
|
||||
NS_ENSURE_TRUE(mDelayedDropBrowserParent, NS_ERROR_FAILURE);
|
||||
uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
|
||||
if (mDataTransfer) {
|
||||
dropEffect = mDataTransfer->DropEffectInt();
|
||||
}
|
||||
Unused
|
||||
<< mDelayedDropBrowserParent->SendStoreDropTargetAndDelayEndDragSession(
|
||||
aEvent->WidgetEventPtr()->mRefPoint, dropEffect, mDragAction,
|
||||
mTriggeringPrincipal, mCsp);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseDragSession::SendDispatchToDropTargetAndResumeEndDragSession(
|
||||
bool aShouldDrop) {
|
||||
MOZ_ASSERT(mDelayedDropBrowserParent);
|
||||
Unused << mDelayedDropBrowserParent
|
||||
->SendDispatchToDropTargetAndResumeEndDragSession(aShouldDrop);
|
||||
mDelayedDropBrowserParent = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseDragSession::StoreDropTargetAndDelayEndDragSession(
|
||||
mozilla::dom::Element* aElement, nsIFrame* aFrame) {
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
MOZ_DRAGSERVICE_LOG(
|
||||
"[%p] StoreDropTargetAndDelayEndDragSession | aElement: %p | aFrame: %p",
|
||||
this, aElement, aFrame);
|
||||
mDelayedDropTarget = do_GetWeakReference(aElement);
|
||||
mDelayedDropFrame = aFrame;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseDragSession::DispatchToDropTargetAndResumeEndDragSession(
|
||||
nsIWidget* aWidget, const LayoutDeviceIntPoint& aPt, bool aShouldDrop) {
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
MOZ_DRAGSERVICE_LOG(
|
||||
"[%p] DispatchToDropTargetAndResumeEndDragSession | pt=(%d, %d) | "
|
||||
"shouldDrop: %s",
|
||||
this, static_cast<int32_t>(aPt.x), static_cast<int32_t>(aPt.y),
|
||||
aShouldDrop ? "true" : "false");
|
||||
|
||||
RefPtr<Element> delayedDropTarget = do_QueryReferent(mDelayedDropTarget);
|
||||
mDelayedDropTarget = nullptr;
|
||||
nsIFrame* delayedDropFrame = mDelayedDropFrame;
|
||||
mDelayedDropFrame = nullptr;
|
||||
auto edsData = std::move(mEndDragSessionData);
|
||||
|
||||
if (!delayedDropTarget) {
|
||||
MOZ_ASSERT(!edsData && !delayedDropFrame);
|
||||
return NS_OK;
|
||||
}
|
||||
if (!delayedDropFrame) {
|
||||
// Weak frame was deleted
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
RefPtr<PresShell> ps = delayedDropFrame->PresContext()->GetPresShell();
|
||||
auto event = MakeUnique<WidgetDragEvent>(
|
||||
true, aShouldDrop ? eDrop : eDragExit, aWidget);
|
||||
event->mRefPoint = aPt;
|
||||
ps->HandleEventWithTarget(event.get(), delayedDropFrame, delayedDropTarget,
|
||||
&status);
|
||||
|
||||
// If EndDragSession was delayed, issue it now.
|
||||
if (edsData) {
|
||||
EndDragSession(edsData->mDoneDrag, edsData->mKeyModifiers);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "nsIDragService.h"
|
||||
#include "nsIDragSession.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsRect.h"
|
||||
#include "nsPoint.h"
|
||||
#include "nsString.h"
|
||||
|
@ -42,6 +43,7 @@ class SourceSurface;
|
|||
} // namespace gfx
|
||||
|
||||
namespace dom {
|
||||
class BrowserParent;
|
||||
class DataTransfer;
|
||||
class Selection;
|
||||
} // namespace dom
|
||||
|
@ -196,6 +198,27 @@ class nsBaseDragSession : public nsIDragSession {
|
|||
*/
|
||||
void OpenDragPopup();
|
||||
|
||||
// Data from a prior call to EndDragSession.
|
||||
struct EndDragSessionData {
|
||||
bool mDoneDrag = false;
|
||||
uint32_t mKeyModifiers = 0;
|
||||
};
|
||||
|
||||
// When we delay a drop event in a content process, if we subsequently need to
|
||||
// also delay an EndDragSession call, this records the parameters to that
|
||||
// call.
|
||||
mozilla::Maybe<EndDragSessionData> mEndDragSessionData;
|
||||
// When we delay a drop event in a content process, this is the dom::Element
|
||||
// that the drop was targetted to.
|
||||
nsWeakPtr mDelayedDropTarget;
|
||||
// When we delay a drop event in a content process, this is the nsIFrame that
|
||||
// would handle the drop.
|
||||
WeakFrame mDelayedDropFrame;
|
||||
|
||||
// Parent process PBrowser with a the remote drag session that corresponds to
|
||||
// this one and is currently delayed.
|
||||
RefPtr<mozilla::dom::BrowserParent> mDelayedDropBrowserParent;
|
||||
|
||||
RefPtr<mozilla::dom::WindowContext> mSourceWindowContext;
|
||||
RefPtr<mozilla::dom::WindowContext> mSourceTopWindowContext;
|
||||
nsCOMPtr<nsINode> mSourceNode;
|
||||
|
|
|
@ -35,7 +35,6 @@ class RemoteDragStartData;
|
|||
[ptr] native DataTransferPtr(mozilla::dom::DataTransfer);
|
||||
[ptr] native RemoteDragStartDataPtr(mozilla::dom::RemoteDragStartData);
|
||||
native EventMessage(mozilla::EventMessage);
|
||||
[ptr] native nsIWidgetPtr(nsIWidget);
|
||||
|
||||
[scriptable, uuid(ebd6b3a2-af16-43af-a698-3091a087dd62), builtinclass]
|
||||
interface nsIDragService : nsISupports
|
||||
|
|
|
@ -11,7 +11,12 @@
|
|||
|
||||
%{ C++
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsSize.h"
|
||||
#include "Units.h"
|
||||
|
||||
class nsIFrame;
|
||||
class nsIWidget;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -19,13 +24,18 @@ class BrowserParent;
|
|||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
%}
|
||||
|
||||
interface nsIContentSecurityPolicy;
|
||||
|
||||
[ptr] native BrowserParentPtr(mozilla::dom::BrowserParent);
|
||||
native EventMessage(mozilla::EventMessage);
|
||||
[ref] native LayoutDeviceIntPoint(mozilla::LayoutDeviceIntPoint);
|
||||
[ptr] native nsIFramePtr(nsIFrame);
|
||||
[ptr] native nsIWidgetPtr(nsIWidget);
|
||||
native nsSize(nsSize);
|
||||
|
||||
webidl DataTransfer;
|
||||
webidl DragEvent;
|
||||
webidl Element;
|
||||
webidl WindowContext;
|
||||
webidl Node;
|
||||
|
@ -205,6 +215,59 @@ interface nsIDragSession : nsISupports
|
|||
void endDragSession(in boolean aDoneDrag,
|
||||
[optional] in unsigned long aKeyModifiers);
|
||||
|
||||
/**
|
||||
* Returns the URI that should be used in a content analysis request for
|
||||
* the given drag event.
|
||||
*/
|
||||
nsIURI uriForEvent(in DragEvent event);
|
||||
|
||||
/**
|
||||
* Tell the drag session for the given browser that it
|
||||
* should store the would-be target of the aEvent (a drop event) and delay
|
||||
* calls to EndDragSession. This is used in the main process.
|
||||
*
|
||||
* @param aEvent The drag event
|
||||
*/
|
||||
void sendStoreDropTargetAndDelayEndDragSession(
|
||||
in DragEvent aEvent);
|
||||
|
||||
/**
|
||||
* After sendStoreDropTargetAndDelayEndDragSession, send a drop (if
|
||||
* aShouldDrop is true) or dragexit event to the recorded drop target and
|
||||
* then reissue any stored EndDragSession call. This is used in the main
|
||||
* process.
|
||||
*
|
||||
* @param aShouldDrop True to send drop event, false to send dragexit event
|
||||
*/
|
||||
void sendDispatchToDropTargetAndResumeEndDragSession(
|
||||
in boolean aShouldDrop);
|
||||
|
||||
/**
|
||||
* Store aElement and aDocFrame as the future drop/dragexit context, and
|
||||
* delay calls to EndDragSession. This is used in content processes.
|
||||
*
|
||||
* @param aElement The element to drop onto
|
||||
* @param aDocFrame The frame to dispatch to
|
||||
*/
|
||||
[noscript] void storeDropTargetAndDelayEndDragSession(
|
||||
in Element aElement,
|
||||
in nsIFramePtr aDocFrame
|
||||
);
|
||||
|
||||
/**
|
||||
* Issue drop or dragexit to the stored drop target (if any) and issue
|
||||
* any delayed call to EndDragSession. This is used in content processes.
|
||||
*
|
||||
* @param aWidget The widget on which the drop will happen
|
||||
* @param aPt Screen coords of drop
|
||||
* @param aShouldDrop If true, send a drop event. Otherwise send dragexit.
|
||||
*/
|
||||
[noscript, can_run_script]
|
||||
void dispatchToDropTargetAndResumeEndDragSession(
|
||||
in nsIWidgetPtr aWidget,
|
||||
[const] in LayoutDeviceIntPoint aPt,
|
||||
in boolean aShouldDrop);
|
||||
|
||||
/**
|
||||
* Retrun true if nsIDragSession's data is updated.
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче