diff --git a/dom/events/ContentEventHandler.cpp b/dom/events/ContentEventHandler.cpp index 2ec230a4da1e..be32fac4bd04 100644 --- a/dom/events/ContentEventHandler.cpp +++ b/dom/events/ContentEventHandler.cpp @@ -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 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 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 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, diff --git a/dom/events/ContentEventHandler.h b/dom/events/ContentEventHandler.h index 7c802097fadd..4216063c61d2 100644 --- a/dom/events/ContentEventHandler.h +++ b/dom/events/ContentEventHandler.h @@ -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 diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index a4b4adf17754..632b161254a3 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -1519,6 +1519,7 @@ void EventStateManager::HandleQueryContentEvent( case eQueryCharacterAtPoint: case eQueryDOMWidgetHittest: case eQueryTextRectArray: + case eQueryDropTargetHittest: break; default: return; diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp index 8035302359a8..bd5e55b5de7f 100644 --- a/dom/ipc/BrowserChild.cpp +++ b/dom/ipc/BrowserChild.cpp @@ -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 dragSession = GetDragSession(); + MOZ_ASSERT(dragSession); + dragSession->SetDragAction(aDragAction); + dragSession->SetTriggeringPrincipal(aPrincipal); + dragSession->SetCsp(aCsp); + RefPtr 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 dragSession = GetDragSession(); + MOZ_ASSERT(dragSession); + RefPtr widget = mPuppetWidget; + dragSession->DispatchToDropTargetAndResumeEndDragSession( + widget, mDelayedDropPoint, aShouldDrop); + mDelayedDropPoint = {}; + return IPC_OK(); +} + void BrowserChild::RequestEditCommands(NativeKeyBindingsType aType, const WidgetKeyboardEvent& aEvent, nsTArray& aCommands) { diff --git a/dom/ipc/BrowserChild.h b/dom/ipc/BrowserChild.h index 4a6eb77f5db5..143bc14c7364 100644 --- a/dom/ipc/BrowserChild.h +++ b/dom/ipc/BrowserChild.h @@ -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; diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index 9877447af876..d8deff3ad6c7 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -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. diff --git a/toolkit/content/widgets/browser-custom-element.js b/toolkit/content/widgets/browser-custom-element.js index 71ab79052e67..08d173ef2092 100644 --- a/toolkit/content/widgets/browser-custom-element.js +++ b/toolkit/content/widgets/browser-custom-element.js @@ -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 ( diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index b6707d30286a..7d7402f89300 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -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) diff --git a/widget/TextEvents.h b/widget/TextEvents.h index 3f42561c7509..a775dd84c41a 100644 --- a/widget/TextEvents.h +++ b/widget/TextEvents.h @@ -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) {} diff --git a/widget/WidgetEventImpl.cpp b/widget/WidgetEventImpl.cpp index 33456df2e274..0e761d371614 100644 --- a/widget/WidgetEventImpl.cpp +++ b/widget/WidgetEventImpl.cpp @@ -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 { diff --git a/widget/nsBaseDragService.cpp b/widget/nsBaseDragService.cpp index ffe4e4ceff9a..ce33bc9dd566 100644 --- a/widget/nsBaseDragService.cpp +++ b/widget/nsBaseDragService.cpp @@ -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 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(aPt.x), static_cast(aPt.y), + aShouldDrop ? "true" : "false"); + + RefPtr 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 ps = delayedDropFrame->PresContext()->GetPresShell(); + auto event = MakeUnique( + 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; +} diff --git a/widget/nsBaseDragService.h b/widget/nsBaseDragService.h index 20160fc2013f..a735c64430f8 100644 --- a/widget/nsBaseDragService.h +++ b/widget/nsBaseDragService.h @@ -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 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 mDelayedDropBrowserParent; + RefPtr mSourceWindowContext; RefPtr mSourceTopWindowContext; nsCOMPtr mSourceNode; diff --git a/widget/nsIDragService.idl b/widget/nsIDragService.idl index 6ac5253f5be5..b731e1e14689 100644 --- a/widget/nsIDragService.idl +++ b/widget/nsIDragService.idl @@ -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 diff --git a/widget/nsIDragSession.idl b/widget/nsIDragSession.idl index f4e3d0eb47c8..697eceecbadd 100644 --- a/widget/nsIDragSession.idl +++ b/widget/nsIDragSession.idl @@ -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. */