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:
David Parks 2024-09-11 23:02:22 +00:00
Родитель 4c7853342b
Коммит 8b722be621
14 изменённых файлов: 451 добавлений и 8 удалений

Просмотреть файл

@ -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.
*/