1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsBaseDragService.h"
7 #include "nsITransferable.h"
9 #include "nsArrayUtils.h"
10 #include "nsITransferable.h"
14 #include "nsIInterfaceRequestorUtils.h"
16 #include "nsFrameLoaderOwner.h"
17 #include "nsIContent.h"
18 #include "nsViewManager.h"
20 #include "nsPresContext.h"
21 #include "nsIImageLoadingContent.h"
22 #include "imgIContainer.h"
23 #include "imgIRequest.h"
24 #include "ImageRegion.h"
25 #include "nsQueryObject.h"
27 #include "nsXULPopupManager.h"
28 #include "nsMenuPopupFrame.h"
29 #include "nsTreeBodyFrame.h"
30 #include "mozilla/MouseEvents.h"
31 #include "mozilla/Preferences.h"
32 #include "mozilla/PresShell.h"
33 #include "mozilla/ProfilerLabels.h"
34 #include "mozilla/SVGImageContext.h"
35 #include "mozilla/TextControlElement.h"
36 #include "mozilla/Unused.h"
37 #include "mozilla/ViewportUtils.h"
38 #include "mozilla/dom/BindingDeclarations.h"
39 #include "mozilla/dom/BrowserParent.h"
40 #include "mozilla/dom/CanonicalBrowsingContext.h"
41 #include "mozilla/dom/ContentParent.h"
42 #include "mozilla/dom/DataTransferItemList.h"
43 #include "mozilla/dom/DataTransfer.h"
44 #include "mozilla/dom/Document.h"
45 #include "mozilla/dom/DocumentInlines.h"
46 #include "mozilla/dom/DragEvent.h"
47 #include "mozilla/dom/Selection.h"
48 #include "mozilla/gfx/2D.h"
49 #include "nsFrameLoader.h"
50 #include "nsIMutableArray.h"
51 #include "gfxContext.h"
52 #include "gfxPlatform.h"
54 #include "MockDragServiceController.h"
58 using namespace mozilla
;
59 using namespace mozilla::dom
;
60 using namespace mozilla::gfx
;
61 using namespace mozilla::image
;
63 LazyLogModule
sWidgetDragServiceLog("WidgetDragService");
65 #define DRAGIMAGES_PREF "nglayout.enable_drag_images"
67 // TODO: Temporary hack to share drag session suppression level.
68 // Removed later in this patch series.
69 uint32_t GetSuppressLevel() {
70 nsCOMPtr
<nsIDragService
> svc
=
71 do_GetService("@mozilla.org/widget/dragservice;1");
72 NS_ENSURE_TRUE(svc
, 0);
73 return static_cast<nsBaseDragService
*>(svc
.get())->GetSuppressLevel();
76 nsBaseDragService::nsBaseDragService() = default;
77 nsBaseDragService::~nsBaseDragService() = default;
79 nsBaseDragSession::nsBaseDragSession() { TakeSessionBrowserListFromService(); }
80 nsBaseDragSession::~nsBaseDragSession() = default;
82 NS_IMPL_ISUPPORTS(nsBaseDragService
, nsIDragService
)
83 NS_IMPL_ISUPPORTS(nsBaseDragSession
, nsIDragSession
)
85 NS_IMETHODIMP
nsBaseDragService::GetIsMockService(bool* aRet
) {
90 //---------------------------------------------------------
92 nsBaseDragSession::SetCanDrop(bool aCanDrop
) {
97 //---------------------------------------------------------
99 nsBaseDragSession::GetCanDrop(bool* aCanDrop
) {
100 *aCanDrop
= mCanDrop
;
103 //---------------------------------------------------------
105 nsBaseDragSession::SetOnlyChromeDrop(bool aOnlyChrome
) {
106 mOnlyChromeDrop
= aOnlyChrome
;
110 //---------------------------------------------------------
112 nsBaseDragSession::GetOnlyChromeDrop(bool* aOnlyChrome
) {
113 *aOnlyChrome
= mOnlyChromeDrop
;
117 //---------------------------------------------------------
119 nsBaseDragSession::SetDragAction(uint32_t anAction
) {
120 mDragAction
= anAction
;
124 //---------------------------------------------------------
126 nsBaseDragSession::GetDragAction(uint32_t* anAction
) {
127 *anAction
= mDragAction
;
131 //-------------------------------------------------------------------------
134 nsBaseDragSession::GetNumDropItems(uint32_t* aNumItems
) {
136 return NS_ERROR_FAILURE
;
140 // GetSourceWindowContext
142 // Returns the window context where the drag was initiated. This will be
143 // nullptr if the drag began outside of our application.
146 nsBaseDragSession::GetSourceWindowContext(
147 WindowContext
** aSourceWindowContext
) {
148 *aSourceWindowContext
= mSourceWindowContext
.get();
149 NS_IF_ADDREF(*aSourceWindowContext
);
154 nsBaseDragSession::SetSourceWindowContext(WindowContext
* aSourceWindowContext
) {
155 // This should only be called in a child process.
156 MOZ_ASSERT(!XRE_IsParentProcess());
157 mSourceWindowContext
= aSourceWindowContext
;
162 // GetSourceTopWindowContext
164 // Returns the top-level window context where the drag was initiated. This will
165 // be nullptr if the drag began outside of our application.
168 nsBaseDragSession::GetSourceTopWindowContext(
169 WindowContext
** aSourceTopWindowContext
) {
170 *aSourceTopWindowContext
= mSourceTopWindowContext
.get();
171 NS_IF_ADDREF(*aSourceTopWindowContext
);
176 nsBaseDragSession::SetSourceTopWindowContext(
177 WindowContext
* aSourceTopWindowContext
) {
178 // This should only be called in a child process.
179 MOZ_ASSERT(!XRE_IsParentProcess());
180 mSourceTopWindowContext
= aSourceTopWindowContext
;
187 // Returns the DOM node where the drag was initiated. This will be
188 // nullptr if the drag began outside of our application.
191 nsBaseDragSession::GetSourceNode(nsINode
** aSourceNode
) {
192 *aSourceNode
= do_AddRef(mSourceNode
).take();
196 void nsBaseDragSession::UpdateSource(nsINode
* aNewSourceNode
,
197 Selection
* aNewSelection
) {
198 MOZ_ASSERT(mSourceNode
);
199 MOZ_ASSERT(aNewSourceNode
);
200 MOZ_ASSERT(mSourceNode
->IsInNativeAnonymousSubtree() ||
201 aNewSourceNode
->IsInNativeAnonymousSubtree());
202 MOZ_ASSERT(mSourceDocument
== aNewSourceNode
->OwnerDoc());
203 mSourceNode
= aNewSourceNode
;
204 // Don't set mSelection if the session was invoked without selection or
205 // making it becomes nullptr. The latter occurs when the old frame is
207 if (mSelection
&& aNewSelection
) {
208 // XXX If the dragging image is created once (e.g., at drag start), the
209 // image won't be updated unless we notify `DrawDrag` callers.
210 // However, it must be okay for now to keep using older image of
212 mSelection
= aNewSelection
;
217 nsBaseDragSession::GetTriggeringPrincipal(nsIPrincipal
** aPrincipal
) {
218 NS_IF_ADDREF(*aPrincipal
= mTriggeringPrincipal
);
223 nsBaseDragSession::SetTriggeringPrincipal(nsIPrincipal
* aPrincipal
) {
224 mTriggeringPrincipal
= aPrincipal
;
229 nsBaseDragSession::GetCsp(nsIContentSecurityPolicy
** aCsp
) {
230 NS_IF_ADDREF(*aCsp
= mCsp
);
235 nsBaseDragSession::SetCsp(nsIContentSecurityPolicy
* aCsp
) {
240 //-------------------------------------------------------------------------
243 nsBaseDragSession::GetData(nsITransferable
* aTransferable
,
244 uint32_t aItemIndex
) {
245 return NS_ERROR_FAILURE
;
248 //-------------------------------------------------------------------------
250 nsBaseDragSession::IsDataFlavorSupported(const char* aDataFlavor
,
252 return NS_ERROR_FAILURE
;
256 nsBaseDragSession::GetDataTransferXPCOM(DataTransfer
** aDataTransfer
) {
257 *aDataTransfer
= mDataTransfer
;
258 NS_IF_ADDREF(*aDataTransfer
);
263 nsBaseDragSession::SetDataTransferXPCOM(DataTransfer
* aDataTransfer
) {
264 NS_ENSURE_STATE(aDataTransfer
);
265 mDataTransfer
= aDataTransfer
;
269 DataTransfer
* nsBaseDragSession::GetDataTransfer() { return mDataTransfer
; }
271 void nsBaseDragSession::SetDataTransfer(DataTransfer
* aDataTransfer
) {
272 mDataTransfer
= aDataTransfer
;
275 bool nsBaseDragSession::IsSynthesizedForTests() {
276 return mSessionIsSynthesizedForTests
;
279 bool nsBaseDragSession::IsDraggingTextInTextControl() {
280 return mIsDraggingTextInTextControl
;
283 uint32_t nsBaseDragSession::GetEffectAllowedForTests() {
284 MOZ_ASSERT(mSessionIsSynthesizedForTests
);
285 return mEffectAllowedForTests
;
288 NS_IMETHODIMP
nsBaseDragSession::SetDragEndPointForTests(int32_t aScreenX
,
290 MOZ_ASSERT(mDoingDrag
);
291 MOZ_ASSERT(mSourceDocument
);
292 MOZ_ASSERT(mSessionIsSynthesizedForTests
);
294 if (!mDoingDrag
|| !mSourceDocument
|| !mSessionIsSynthesizedForTests
) {
295 return NS_ERROR_FAILURE
;
297 nsPresContext
* pc
= mSourceDocument
->GetPresContext();
298 if (NS_WARN_IF(!pc
)) {
299 return NS_ERROR_FAILURE
;
301 auto p
= LayoutDeviceIntPoint::Round(CSSIntPoint(aScreenX
, aScreenY
) *
302 pc
->CSSToDevPixelScale());
303 // p is screen-relative, and we want them to be top-level-widget-relative.
304 if (nsCOMPtr
<nsIWidget
> widget
= pc
->GetRootWidget()) {
305 p
-= widget
->WidgetToScreenOffset();
306 p
+= widget
->WidgetToTopLevelWidgetOffset();
312 //-------------------------------------------------------------------------
313 nsresult
nsBaseDragSession::InvokeDragSession(
314 nsIWidget
* aWidget
, nsINode
* aDOMNode
, nsIPrincipal
* aPrincipal
,
315 nsIContentSecurityPolicy
* aCsp
, nsICookieJarSettings
* aCookieJarSettings
,
316 nsIArray
* aTransferableArray
, uint32_t aActionType
,
317 nsContentPolicyType aContentPolicyType
) {
318 AUTO_PROFILER_LABEL("nsBaseDragService::InvokeDragSession", OTHER
);
320 NS_ENSURE_TRUE(aDOMNode
, NS_ERROR_INVALID_ARG
);
322 // stash the document of the dom node
323 mSourceDocument
= aDOMNode
->OwnerDoc();
324 mTriggeringPrincipal
= aPrincipal
;
326 mSourceNode
= aDOMNode
;
327 mIsDraggingTextInTextControl
=
328 mSourceNode
->IsInNativeAnonymousSubtree() &&
329 TextControlElement::FromNodeOrNull(
330 mSourceNode
->GetClosestNativeAnonymousSubtreeRootParentOrHost());
331 mContentPolicyType
= aContentPolicyType
;
332 mEndDragPoint
= LayoutDeviceIntPoint(0, 0);
334 // When the mouse goes down, the selection code starts a mouse
335 // capture. However, this gets in the way of determining drag
336 // feedback for things like trees because the event coordinates
337 // are in the wrong coord system, so turn off mouse capture.
338 PresShell::ClearMouseCapture();
340 if (mSessionIsSynthesizedForTests
) {
342 mDragAction
= aActionType
;
343 mEffectAllowedForTests
= aActionType
;
347 if (XRE_IsParentProcess()) {
348 // If you're hitting this, a test is causing the browser to attempt to enter
349 // the drag-drop native nested event loop, which will put the browser in a
350 // state that won't run tests properly until there's manual intervention
351 // to exit the drag-drop loop (either by moving the mouse or hitting
352 // escape), which can't be done from script since we're in the nested loop.
354 // The best way to avoid this is to use the mock service in tests. See
355 // synthesizeMockDragAndDrop.
356 nsCOMPtr
<nsIDragService
> dragService
=
357 do_GetService("@mozilla.org/widget/dragservice;1");
358 MOZ_ASSERT(dragService
);
360 !xpc::IsInAutomation() || dragService
->IsMockService(),
361 "About to start drag-drop native loop on which will prevent later "
362 "tests from running properly.");
366 mozilla::Unused
<< aTransferableArray
->GetLength(&length
);
368 nsCOMPtr
<nsIMutableArray
> mutableArray
=
369 do_QueryInterface(aTransferableArray
);
371 // In order to be able trigger dnd, we need to have some transferable
373 nsCOMPtr
<nsITransferable
> trans
=
374 do_CreateInstance("@mozilla.org/widget/transferable;1");
375 trans
->Init(nullptr);
376 trans
->SetDataPrincipal(mSourceNode
->NodePrincipal());
377 trans
->SetContentPolicyType(mContentPolicyType
);
378 trans
->SetCookieJarSettings(aCookieJarSettings
);
379 mutableArray
->AppendElement(trans
);
382 for (uint32_t i
= 0; i
< length
; ++i
) {
383 nsCOMPtr
<nsITransferable
> trans
=
384 do_QueryElementAt(aTransferableArray
, i
);
386 // Set the dataPrincipal on the transferable.
387 trans
->SetDataPrincipal(mSourceNode
->NodePrincipal());
388 trans
->SetContentPolicyType(mContentPolicyType
);
389 trans
->SetCookieJarSettings(aCookieJarSettings
);
395 InvokeDragSessionImpl(aWidget
, aTransferableArray
, mRegion
, aActionType
);
398 // Set mDoingDrag so that EndDragSession cleans up and sends the dragend
399 // event after the aborted drag.
401 EndDragSession(true, 0);
408 nsBaseDragService::InvokeDragSessionWithImage(
409 nsINode
* aDOMNode
, nsIPrincipal
* aPrincipal
, nsIContentSecurityPolicy
* aCsp
,
410 nsICookieJarSettings
* aCookieJarSettings
, nsIArray
* aTransferableArray
,
411 uint32_t aActionType
, nsINode
* aImage
, int32_t aImageX
, int32_t aImageY
,
412 DragEvent
* aDragEvent
, DataTransfer
* aDataTransfer
) {
413 nsCOMPtr
<nsIWidget
> widget
=
414 aDragEvent
->WidgetEventPtr()->AsDragEvent()->mWidget
;
417 NS_ENSURE_TRUE(aDragEvent
, NS_ERROR_NULL_POINTER
);
418 NS_ENSURE_TRUE(aDataTransfer
, NS_ERROR_NULL_POINTER
);
419 NS_ENSURE_TRUE(mSuppressLevel
== 0, NS_ERROR_FAILURE
);
421 RefPtr
<nsBaseDragSession
> session
=
422 CreateDragSession().downcast
<nsBaseDragSession
>();
423 if (XRE_IsParentProcess()) {
424 mCurrentParentDragSession
= session
;
427 aDragEvent
->WidgetEventPtr()->mFlags
.mIsSynthesizedForTests
&&
428 !GetNeverAllowSessionIsSynthesizedForTests();
429 return session
->InitWithImage(widget
, aDOMNode
, aPrincipal
, aCsp
,
430 aCookieJarSettings
, aTransferableArray
,
431 aActionType
, aImage
, aImageX
, aImageY
,
432 aDragEvent
, aDataTransfer
, isSynthesized
);
435 nsresult
nsBaseDragSession::InitWithImage(
436 nsIWidget
* aWidget
, nsINode
* aDOMNode
, nsIPrincipal
* aPrincipal
,
437 nsIContentSecurityPolicy
* aCsp
, nsICookieJarSettings
* aCookieJarSettings
,
438 nsIArray
* aTransferableArray
, uint32_t aActionType
, nsINode
* aImage
,
439 int32_t aImageX
, int32_t aImageY
, DragEvent
* aDragEvent
,
440 DataTransfer
* aDataTransfer
, bool aIsSynthesizedForTests
) {
441 mSessionIsSynthesizedForTests
= aIsSynthesizedForTests
;
442 mDataTransfer
= aDataTransfer
;
443 mSelection
= nullptr;
445 mDragPopup
= nullptr;
447 mImageOffset
= CSSIntPoint(aImageX
, aImageY
);
448 mDragStartData
= nullptr;
449 mSourceWindowContext
=
450 aDOMNode
? aDOMNode
->OwnerDoc()->GetWindowContext() : nullptr;
451 mSourceTopWindowContext
=
452 mSourceWindowContext
? mSourceWindowContext
->TopWindowContext() : nullptr;
454 mScreenPosition
= RoundedToInt(aDragEvent
->ScreenPoint(CallerType::System
));
455 mInputSource
= aDragEvent
->InputSource(CallerType::System
);
457 // If dragging within a XUL tree and no custom drag image was
458 // set, the region argument to InvokeDragSessionWithImage needs
459 // to be set to the area encompassing the selected rows of the
460 // tree to ensure that the drag feedback gets clipped to those
461 // rows. For other content, region should be null.
463 if (aDOMNode
&& aDOMNode
->IsContent() && !aImage
) {
464 if (aDOMNode
->NodeInfo()->Equals(nsGkAtoms::treechildren
,
466 nsTreeBodyFrame
* treeBody
=
467 do_QueryFrame(aDOMNode
->AsContent()->GetPrimaryFrame());
469 mRegion
= treeBody
->GetSelectionRegion();
474 nsresult rv
= InvokeDragSession(
475 aWidget
, aDOMNode
, aPrincipal
, aCsp
, aCookieJarSettings
,
476 aTransferableArray
, aActionType
, nsIContentPolicy::TYPE_INTERNAL_IMAGE
);
482 nsBaseDragService::InvokeDragSessionWithRemoteImage(
483 nsINode
* aDOMNode
, nsIPrincipal
* aPrincipal
, nsIContentSecurityPolicy
* aCsp
,
484 nsICookieJarSettings
* aCookieJarSettings
, nsIArray
* aTransferableArray
,
485 uint32_t aActionType
, RemoteDragStartData
* aDragStartData
,
486 DragEvent
* aDragEvent
, DataTransfer
* aDataTransfer
) {
487 nsCOMPtr
<nsIWidget
> widget
=
488 aDragEvent
->WidgetEventPtr()->AsDragEvent()->mWidget
;
491 NS_ENSURE_TRUE(aDragEvent
, NS_ERROR_NULL_POINTER
);
492 NS_ENSURE_TRUE(aDataTransfer
, NS_ERROR_NULL_POINTER
);
493 NS_ENSURE_TRUE(mSuppressLevel
== 0, NS_ERROR_FAILURE
);
495 RefPtr
<nsBaseDragSession
> session
=
496 CreateDragSession().downcast
<nsBaseDragSession
>();
497 if (XRE_IsParentProcess()) {
498 mCurrentParentDragSession
= session
;
501 aDragEvent
->WidgetEventPtr()->mFlags
.mIsSynthesizedForTests
&&
502 !GetNeverAllowSessionIsSynthesizedForTests();
503 return session
->InitWithRemoteImage(widget
, aDOMNode
, aPrincipal
, aCsp
,
504 aCookieJarSettings
, aTransferableArray
,
505 aActionType
, aDragStartData
, aDragEvent
,
506 aDataTransfer
, isSynthesized
);
509 nsresult
nsBaseDragSession::InitWithRemoteImage(
510 nsIWidget
* aWidget
, nsINode
* aDOMNode
, nsIPrincipal
* aPrincipal
,
511 nsIContentSecurityPolicy
* aCsp
, nsICookieJarSettings
* aCookieJarSettings
,
512 nsIArray
* aTransferableArray
, uint32_t aActionType
,
513 RemoteDragStartData
* aDragStartData
, DragEvent
* aDragEvent
,
514 DataTransfer
* aDataTransfer
, bool aIsSynthesizedForTests
) {
515 mSessionIsSynthesizedForTests
= aIsSynthesizedForTests
;
516 mDataTransfer
= aDataTransfer
;
517 mSelection
= nullptr;
519 mDragPopup
= nullptr;
521 mDragStartData
= aDragStartData
;
522 mImageOffset
= CSSIntPoint(0, 0);
523 mSourceWindowContext
= mDragStartData
->GetSourceWindowContext();
524 mSourceTopWindowContext
= mDragStartData
->GetSourceTopWindowContext();
526 mScreenPosition
= RoundedToInt(aDragEvent
->ScreenPoint(CallerType::System
));
527 mInputSource
= aDragEvent
->InputSource(CallerType::System
);
529 nsresult rv
= InvokeDragSession(
530 aWidget
, aDOMNode
, aPrincipal
, aCsp
, aCookieJarSettings
,
531 aTransferableArray
, aActionType
, nsIContentPolicy::TYPE_INTERNAL_IMAGE
);
537 nsBaseDragService::InvokeDragSessionWithSelection(
538 Selection
* aSelection
, nsIPrincipal
* aPrincipal
,
539 nsIContentSecurityPolicy
* aCsp
, nsICookieJarSettings
* aCookieJarSettings
,
540 nsIArray
* aTransferableArray
, uint32_t aActionType
, DragEvent
* aDragEvent
,
541 DataTransfer
* aDataTransfer
, nsINode
* aTargetContent
) {
542 nsCOMPtr
<nsIWidget
> widget
=
543 aDragEvent
->WidgetEventPtr()->AsDragEvent()->mWidget
;
546 NS_ENSURE_TRUE(aSelection
, NS_ERROR_NULL_POINTER
);
547 NS_ENSURE_TRUE(aDragEvent
, NS_ERROR_NULL_POINTER
);
548 NS_ENSURE_TRUE(aTargetContent
, NS_ERROR_NULL_POINTER
);
549 NS_ENSURE_TRUE(mSuppressLevel
== 0, NS_ERROR_FAILURE
);
551 RefPtr
<nsBaseDragSession
> session
=
552 CreateDragSession().downcast
<nsBaseDragSession
>();
553 if (XRE_IsParentProcess()) {
554 mCurrentParentDragSession
= session
;
557 aDragEvent
->WidgetEventPtr()->mFlags
.mIsSynthesizedForTests
&&
558 !GetNeverAllowSessionIsSynthesizedForTests();
559 return session
->InitWithSelection(widget
, aSelection
, aPrincipal
, aCsp
,
560 aCookieJarSettings
, aTransferableArray
,
561 aActionType
, aDragEvent
, aDataTransfer
,
562 aTargetContent
, isSynthesized
);
565 nsresult
nsBaseDragSession::InitWithSelection(
566 nsIWidget
* aWidget
, Selection
* aSelection
, nsIPrincipal
* aPrincipal
,
567 nsIContentSecurityPolicy
* aCsp
, nsICookieJarSettings
* aCookieJarSettings
,
568 nsIArray
* aTransferableArray
, uint32_t aActionType
, DragEvent
* aDragEvent
,
569 DataTransfer
* aDataTransfer
, nsINode
* aTargetContent
,
570 bool aIsSynthesizedForTests
) {
571 mSessionIsSynthesizedForTests
= aIsSynthesizedForTests
;
572 mDataTransfer
= aDataTransfer
;
573 mSelection
= aSelection
;
575 mDragPopup
= nullptr;
577 mImageOffset
= CSSIntPoint();
578 mDragStartData
= nullptr;
581 mScreenPosition
= RoundedToInt(aDragEvent
->ScreenPoint(CallerType::System
));
582 mInputSource
= aDragEvent
->InputSource(CallerType::System
);
584 // XXXndeakin this should actually be the deepest node that contains both
585 // endpoints of the selection
586 nsCOMPtr
<nsINode
> node
= aTargetContent
;
587 mSourceWindowContext
= node
->OwnerDoc()->GetWindowContext();
588 mSourceTopWindowContext
=
589 mSourceWindowContext
? mSourceWindowContext
->TopWindowContext() : nullptr;
591 return InvokeDragSession(aWidget
, node
, aPrincipal
, aCsp
, aCookieJarSettings
,
592 aTransferableArray
, aActionType
,
593 nsIContentPolicy::TYPE_OTHER
);
596 //-------------------------------------------------------------------------
598 nsBaseDragService::GetCurrentSession(nsISupports
* aWidgetProvider
,
599 nsIDragSession
** aSession
) {
600 MOZ_ASSERT(XRE_IsParentProcess());
602 return NS_ERROR_INVALID_ARG
;
605 if (!mSuppressLevel
&& mCurrentParentDragSession
) {
606 RefPtr
<nsIDragSession
> session
= mCurrentParentDragSession
;
607 session
.forget(aSession
);
615 //-------------------------------------------------------------------------
616 nsIDragSession
* nsBaseDragService::StartDragSession(
617 nsISupports
* aWidgetProvider
) {
618 MOZ_ASSERT(XRE_IsParentProcess());
619 if (!aWidgetProvider
) {
622 if (mCurrentParentDragSession
) {
623 return mCurrentParentDragSession
;
626 RefPtr
<nsIDragSession
> session
= CreateDragSession();
627 mCurrentParentDragSession
= session
;
632 nsBaseDragSession::InitForTests(uint32_t aAllowedEffect
) {
633 mDragAction
= aAllowedEffect
;
634 mEffectAllowedForTests
= aAllowedEffect
;
635 mSessionIsSynthesizedForTests
= true;
639 NS_IMETHODIMP
nsBaseDragService::StartDragSessionForTests(
640 nsISupports
* aWidgetProvider
, uint32_t aAllowedEffect
) {
641 // This method must set mSessionIsSynthesizedForTests
642 MOZ_ASSERT(!mNeverAllowSessionIsSynthesizedForTests
);
644 RefPtr
<nsIDragSession
> session
= StartDragSession(aWidgetProvider
);
646 session
->InitForTests(aAllowedEffect
);
650 void nsBaseDragSession::OpenDragPopup() {
652 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
654 pm
->ShowPopupAtScreen(mDragPopup
, mScreenPosition
.x
- mImageOffset
.x
,
655 mScreenPosition
.y
- mImageOffset
.y
, false, nullptr);
660 int32_t nsBaseDragSession::TakeChildProcessDragAction() {
661 // If the last event was dispatched to the child process, use the drag action
662 // assigned from it instead and return it. DRAGDROP_ACTION_UNINITIALIZED is
663 // returned otherwise.
664 int32_t retval
= nsIDragService::DRAGDROP_ACTION_UNINITIALIZED
;
665 if (TakeDragEventDispatchedToChildProcess() &&
666 mDragActionFromChildProcess
!=
667 nsIDragService::DRAGDROP_ACTION_UNINITIALIZED
) {
668 retval
= mDragActionFromChildProcess
;
674 //-------------------------------------------------------------------------
676 nsBaseDragSession::EndDragSession(bool aDoneDrag
, uint32_t aKeyModifiers
) {
677 if (mDelayedDropTarget
) {
678 if (!mEndDragSessionData
) {
679 EndDragSessionData edsData
= {aDoneDrag
, aKeyModifiers
};
680 mEndDragSessionData
= Some(edsData
);
684 return EndDragSessionImpl(aDoneDrag
, aKeyModifiers
);
687 nsresult
nsBaseDragSession::EndDragSessionImpl(bool aDoneDrag
,
688 uint32_t aKeyModifiers
) {
689 MOZ_DRAGSERVICE_LOG("[%p] EndDragSession | mDoingDrag %s", this,
690 mDoingDrag
? "true" : "false");
691 if (!mDoingDrag
|| mEndingSession
) {
692 return NS_ERROR_FAILURE
;
695 mEndingSession
= true;
697 if (aDoneDrag
&& !GetSuppressLevel()) {
698 FireDragEventAtSource(eDragEnd
, aKeyModifiers
);
702 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
704 pm
->HidePopup(mDragPopup
, {HidePopupOption::DeselectMenu
});
708 uint32_t dropEffect
= nsIDragService::DRAGDROP_ACTION_NONE
;
710 dropEffect
= mDataTransfer
->DropEffectInt();
713 for (nsWeakPtr
& browser
: mBrowsers
) {
714 nsCOMPtr
<BrowserParent
> bp
= do_QueryReferent(browser
);
715 if (NS_WARN_IF(!bp
)) {
718 mozilla::Unused
<< bp
->SendEndDragSession(
719 aDoneDrag
, mUserCancelled
, mEndDragPoint
, aKeyModifiers
, dropEffect
);
720 // Continue sending input events with input priority when stopping the dnd
722 bp
->Manager()->SetInputPriorityEventEnabled(true);
726 // mDataTransfer and the items it owns are going to die anyway, but we
727 // explicitly deref the contained data here so that we don't have to wait for
728 // CC to reclaim the memory.
729 if (XRE_IsParentProcess()) {
730 DiscardInternalTransferData();
731 nsCOMPtr
<nsIDragService
> svc
=
732 do_GetService("@mozilla.org/widget/dragservice;1");
734 static_cast<nsBaseDragService
*>(svc
.get())
735 ->ClearCurrentParentDragSession();
740 mSessionIsSynthesizedForTests
= false;
741 mIsDraggingTextInTextControl
= false;
742 mEffectAllowedForTests
= nsIDragService::DRAGDROP_ACTION_UNINITIALIZED
;
743 mEndingSession
= false;
746 // release the source we've been holding on to.
747 mSourceDocument
= nullptr;
748 mSourceNode
= nullptr;
749 mSourceWindowContext
= nullptr;
750 mSourceTopWindowContext
= nullptr;
751 mTriggeringPrincipal
= nullptr;
753 mSelection
= nullptr;
754 mDataTransfer
= nullptr;
756 mUserCancelled
= false;
757 mDragPopup
= nullptr;
758 mDragStartData
= nullptr;
760 mImageOffset
= CSSIntPoint();
761 mScreenPosition
= CSSIntPoint();
762 mEndDragPoint
= LayoutDeviceIntPoint(0, 0);
763 mInputSource
= MouseEvent_Binding::MOZ_SOURCE_MOUSE
;
769 void nsBaseDragSession::DiscardInternalTransferData() {
770 if (mDataTransfer
&& mSourceNode
) {
771 MOZ_ASSERT(mDataTransfer
);
773 DataTransferItemList
* items
= mDataTransfer
->Items();
774 for (size_t i
= 0; i
< items
->Length(); i
++) {
776 DataTransferItem
* item
= items
->IndexedGetter(i
, found
);
778 // Non-OTHER items may still be needed by JS. Skip them.
779 if (!found
|| item
->Kind() != DataTransferItem::KIND_OTHER
) {
783 nsCOMPtr
<nsIVariant
> variant
= item
->DataNoSecurityCheck();
784 nsCOMPtr
<nsIWritableVariant
> writable
= do_QueryInterface(variant
);
787 writable
->SetAsEmpty();
794 nsBaseDragSession::FireDragEventAtSource(EventMessage aEventMessage
,
795 uint32_t aKeyModifiers
) {
796 if (!mSourceNode
|| !mSourceDocument
|| GetSuppressLevel()) {
799 RefPtr
<PresShell
> presShell
= mSourceDocument
->GetPresShell();
804 RefPtr
<nsPresContext
> pc
= presShell
->GetPresContext();
805 nsCOMPtr
<nsIWidget
> widget
= pc
? pc
->GetRootWidget() : nullptr;
807 nsEventStatus status
= nsEventStatus_eIgnore
;
808 WidgetDragEvent
event(true, aEventMessage
, widget
);
809 event
.mFlags
.mIsSynthesizedForTests
= mSessionIsSynthesizedForTests
;
810 event
.mInputSource
= mInputSource
;
811 if (aEventMessage
== eDragEnd
) {
812 event
.mRefPoint
= mEndDragPoint
;
814 event
.mRefPoint
-= widget
->WidgetToTopLevelWidgetOffset();
816 event
.mUserCancelled
= mUserCancelled
;
818 event
.mModifiers
= aKeyModifiers
;
820 // Most drag events aren't able to converted to MouseEvent except to
821 // eDragStart and eDragEnd.
822 if (widget
&& event
.CanConvertToInputData()) {
823 // Send the drag event to APZ, which needs to know about them to be
824 // able to accurately detect the end of a drag gesture.
825 widget
->DispatchEventToAPZOnly(&event
);
828 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(mSourceNode
);
829 return presShell
->HandleDOMEventWithTarget(content
, &event
, &status
);
832 /* This is used by Windows and Mac to update the position of a popup being
833 * used as a drag image during the drag. This isn't used on GTK as it manages
834 * the drag popup itself.
837 nsBaseDragSession::DragMoved(int32_t aX
, int32_t aY
) {
839 nsIFrame
* frame
= mDragPopup
->GetPrimaryFrame();
840 if (frame
&& frame
->IsMenuPopupFrame()) {
842 RoundedToInt(LayoutDeviceIntPoint(aX
, aY
) /
843 frame
->PresContext()->CSSToDevPixelScale()) -
845 static_cast<nsMenuPopupFrame
*>(frame
)->MoveTo(cssPos
, true);
852 static PresShell
* GetPresShellForContent(nsINode
* aDOMNode
) {
853 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(aDOMNode
);
854 if (!content
) return nullptr;
856 RefPtr
<Document
> document
= content
->GetComposedDoc();
858 document
->FlushPendingNotifications(FlushType::Layout
);
859 return document
->GetPresShell();
865 nsresult
nsBaseDragSession::DrawDrag(nsINode
* aDOMNode
,
866 const Maybe
<CSSIntRegion
>& aRegion
,
867 CSSIntPoint aScreenPosition
,
868 LayoutDeviceIntRect
* aScreenDragRect
,
869 RefPtr
<SourceSurface
>* aSurface
,
870 nsPresContext
** aPresContext
) {
872 *aPresContext
= nullptr;
874 // use a default size, in case of an error.
875 aScreenDragRect
->SetRect(aScreenPosition
.x
- mImageOffset
.x
,
876 aScreenPosition
.y
- mImageOffset
.y
, 1, 1);
878 // if a drag image was specified, use that, otherwise, use the source node
879 nsCOMPtr
<nsINode
> dragNode
= mImage
? mImage
.get() : aDOMNode
;
881 // get the presshell for the node being dragged. If the drag image is not in
882 // a document or has no frame, get the presshell from the source drag node
883 PresShell
* presShell
= GetPresShellForContent(dragNode
);
884 if (!presShell
&& mImage
) {
885 presShell
= GetPresShellForContent(aDOMNode
);
888 return NS_ERROR_FAILURE
;
891 *aPresContext
= presShell
->GetPresContext();
893 if (mDragStartData
) {
895 // Just clear the surface if chrome has overridden it with an image.
898 *aSurface
= mDragStartData
->TakeVisualization(aScreenDragRect
);
901 mDragStartData
= nullptr;
905 // convert mouse position to dev pixels of the prescontext
906 const CSSIntPoint screenPosition
= aScreenPosition
- mImageOffset
;
907 const auto screenPoint
= LayoutDeviceIntPoint::Round(
908 screenPosition
* (*aPresContext
)->CSSToDevPixelScale());
909 aScreenDragRect
->MoveTo(screenPoint
.x
, screenPoint
.y
);
911 // check if drag images are disabled
912 bool enableDragImages
= Preferences::GetBool(DRAGIMAGES_PREF
, true);
914 // didn't want an image, so just set the screen rectangle to the frame size
915 if (!enableDragImages
|| !mHasImage
) {
916 // This holds a quantity in RelativeTo{presShell->GetRootFrame(),
917 // ViewportType::Layout} space.
918 nsRect presLayoutRect
;
920 // if a region was specified, set the screen rectangle to the area that
921 // the region occupies
922 presLayoutRect
= ToAppUnits(aRegion
->GetBounds(), AppUnitsPerCSSPixel());
924 // otherwise, there was no region so just set the rectangle to
925 // the size of the primary frame of the content.
926 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(dragNode
);
927 if (nsIFrame
* frame
= content
->GetPrimaryFrame()) {
928 presLayoutRect
= frame
->GetBoundingClientRect();
932 LayoutDeviceRect screenVisualRect
= ViewportUtils::ToScreenRelativeVisual(
933 LayoutDeviceRect::FromAppUnits(presLayoutRect
,
934 (*aPresContext
)->AppUnitsPerDevPixel()),
936 aScreenDragRect
->SizeTo(screenVisualRect
.Width(),
937 screenVisualRect
.Height());
941 // draw the image for selections
943 LayoutDeviceIntPoint
pnt(aScreenDragRect
->TopLeft());
944 *aSurface
= presShell
->RenderSelection(
945 mSelection
, pnt
, aScreenDragRect
,
946 mImage
? RenderImageFlags::None
: RenderImageFlags::AutoScale
);
950 // if a custom image was specified, check if it is an image node and draw
951 // using the source rather than the displayed image. But if mImage isn't
952 // an image or canvas, fall through to RenderNode below.
954 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(dragNode
);
955 HTMLCanvasElement
* canvas
= HTMLCanvasElement::FromNodeOrNull(content
);
957 return DrawDragForImage(*aPresContext
, nullptr, canvas
, aScreenDragRect
,
961 nsCOMPtr
<nsIImageLoadingContent
> imageLoader
= do_QueryInterface(dragNode
);
962 // for image nodes, create the drag image from the actual image data
964 return DrawDragForImage(*aPresContext
, imageLoader
, nullptr,
965 aScreenDragRect
, aSurface
);
968 // If the image is a popup, use that as the image. This allows custom drag
969 // images that can change during the drag, but means that any platform
970 // default image handling won't occur.
971 // XXXndeakin this should be chrome-only
973 nsIFrame
* frame
= content
->GetPrimaryFrame();
974 if (frame
&& frame
->IsMenuPopupFrame()) {
975 mDragPopup
= content
->AsElement();
980 // otherwise, just draw the node
981 RenderImageFlags renderFlags
=
982 mImage
? RenderImageFlags::None
: RenderImageFlags::AutoScale
;
983 if (renderFlags
!= RenderImageFlags::None
) {
984 // check if the dragged node itself is an img element
985 if (dragNode
->NodeName().LowerCaseEqualsLiteral("img")) {
986 renderFlags
= renderFlags
| RenderImageFlags::IsImage
;
988 nsINodeList
* childList
= dragNode
->ChildNodes();
989 uint32_t length
= childList
->Length();
990 // check every childnode for being an img element
991 // XXXbz why don't we need to check descendants recursively?
992 for (uint32_t count
= 0; count
< length
; ++count
) {
993 if (childList
->Item(count
)->NodeName().LowerCaseEqualsLiteral(
995 // if the dragnode contains an image, set RenderImageFlags::IsImage
997 renderFlags
= renderFlags
| RenderImageFlags::IsImage
;
1003 LayoutDeviceIntPoint
pnt(aScreenDragRect
->TopLeft());
1004 *aSurface
= presShell
->RenderNode(dragNode
, aRegion
, pnt
, aScreenDragRect
,
1008 // If an image was specified, reset the position from the offset that was
1011 aScreenDragRect
->MoveTo(screenPoint
.x
, screenPoint
.y
);
1017 nsresult
nsBaseDragSession::DrawDragForImage(
1018 nsPresContext
* aPresContext
, nsIImageLoadingContent
* aImageLoader
,
1019 HTMLCanvasElement
* aCanvas
, LayoutDeviceIntRect
* aScreenDragRect
,
1020 RefPtr
<SourceSurface
>* aSurface
) {
1021 nsCOMPtr
<imgIContainer
> imgContainer
;
1023 nsCOMPtr
<imgIRequest
> imgRequest
;
1024 nsresult rv
= aImageLoader
->GetRequest(
1025 nsIImageLoadingContent::CURRENT_REQUEST
, getter_AddRefs(imgRequest
));
1026 NS_ENSURE_SUCCESS(rv
, rv
);
1027 if (!imgRequest
) return NS_ERROR_NOT_AVAILABLE
;
1029 rv
= imgRequest
->GetImage(getter_AddRefs(imgContainer
));
1030 NS_ENSURE_SUCCESS(rv
, rv
);
1031 if (!imgContainer
) return NS_ERROR_NOT_AVAILABLE
;
1033 // use the size of the image as the size of the drag image
1034 int32_t imageWidth
, imageHeight
;
1035 rv
= imgContainer
->GetWidth(&imageWidth
);
1036 NS_ENSURE_SUCCESS(rv
, rv
);
1038 rv
= imgContainer
->GetHeight(&imageHeight
);
1039 NS_ENSURE_SUCCESS(rv
, rv
);
1041 aScreenDragRect
->SizeTo(aPresContext
->CSSPixelsToDevPixels(imageWidth
),
1042 aPresContext
->CSSPixelsToDevPixels(imageHeight
));
1044 // Bug 1907668: The canvas size should be converted to dev pixels.
1045 NS_ASSERTION(aCanvas
, "both image and canvas are null");
1046 CSSIntSize sz
= aCanvas
->GetSize();
1047 aScreenDragRect
->SizeTo(sz
.width
, sz
.height
);
1051 destSize
.width
= aScreenDragRect
->Width();
1052 destSize
.height
= aScreenDragRect
->Height();
1053 if (destSize
.width
== 0 || destSize
.height
== 0) return NS_ERROR_FAILURE
;
1055 nsresult result
= NS_OK
;
1057 RefPtr
<DrawTarget
> dt
=
1058 gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
1059 destSize
, SurfaceFormat::B8G8R8A8
);
1060 if (!dt
|| !dt
->IsValid()) return NS_ERROR_FAILURE
;
1064 ImgDrawResult res
= imgContainer
->Draw(
1065 &ctx
, destSize
, ImageRegion::Create(destSize
),
1066 imgIContainer::FRAME_CURRENT
, SamplingFilter::GOOD
, SVGImageContext(),
1067 imgIContainer::FLAG_SYNC_DECODE
, 1.0);
1068 if (res
== ImgDrawResult::BAD_IMAGE
|| res
== ImgDrawResult::BAD_ARGS
||
1069 res
== ImgDrawResult::NOT_SUPPORTED
) {
1070 return NS_ERROR_FAILURE
;
1072 *aSurface
= dt
->Snapshot();
1074 *aSurface
= aCanvas
->GetSurfaceSnapshot();
1081 nsBaseDragService::Suppress() {
1082 RefPtr
<nsIDragSession
> session
= mCurrentParentDragSession
;
1084 session
->EndDragSession(false, 0);
1091 nsBaseDragService::Unsuppress() {
1097 nsBaseDragSession::UserCancelled() {
1098 mUserCancelled
= true;
1103 nsBaseDragSession::UpdateDragEffect() {
1104 mDragActionFromChildProcess
= mDragAction
;
1109 nsBaseDragSession::UpdateDragImage(nsINode
* aImage
, int32_t aImageX
,
1111 // Don't change the image if this is a drag from another source or if there
1113 if (!mSourceNode
|| mDragPopup
) return NS_OK
;
1116 mImageOffset
= CSSIntPoint(aImageX
, aImageY
);
1121 nsBaseDragSession::DragEventDispatchedToChildProcess() {
1122 mDragEventDispatchedToChildProcess
= true;
1126 static bool MaybeAddBrowser(nsTArray
<nsWeakPtr
>& aBrowsers
,
1127 BrowserParent
* aBP
) {
1128 nsWeakPtr browser
= do_GetWeakReference(aBP
);
1130 // Equivalent to `InsertElementSorted`, avoiding inserting a duplicate
1131 // element. See bug 1896166.
1132 size_t index
= aBrowsers
.IndexOfFirstElementGt(browser
);
1133 if (index
== 0 || aBrowsers
[index
- 1] != browser
) {
1134 aBrowsers
.InsertElementAt(index
, browser
);
1140 static bool RemoveAllBrowsers(nsTArray
<nsWeakPtr
>& aBrowsers
) {
1141 for (auto& weakBrowser
: aBrowsers
) {
1142 nsCOMPtr
<BrowserParent
> browser
= do_QueryReferent(weakBrowser
);
1143 if (NS_WARN_IF(!browser
)) {
1146 mozilla::Unused
<< browser
->SendEndDragSession(
1147 true, false, LayoutDeviceIntPoint(), 0,
1148 nsIDragService::DRAGDROP_ACTION_NONE
);
1155 bool nsBaseDragService::MaybeAddBrowser(BrowserParent
* aBP
) {
1156 nsCOMPtr
<nsIDragSession
> session
;
1157 GetCurrentSession(nullptr, getter_AddRefs(session
));
1159 return session
->MaybeAddBrowser(aBP
);
1161 return ::MaybeAddBrowser(mBrowsers
, aBP
);
1164 bool nsBaseDragService::RemoveAllBrowsers() {
1165 nsCOMPtr
<nsIDragSession
> session
;
1166 GetCurrentSession(nullptr, getter_AddRefs(session
));
1168 return session
->RemoveAllBrowsers();
1170 return ::RemoveAllBrowsers(mBrowsers
);
1173 bool nsBaseDragSession::MaybeAddBrowser(BrowserParent
* aBP
) {
1174 return ::MaybeAddBrowser(mBrowsers
, aBP
);
1177 bool nsBaseDragSession::RemoveAllBrowsers() {
1178 return ::RemoveAllBrowsers(mBrowsers
);
1181 bool nsBaseDragSession::MustUpdateDataTransfer(EventMessage aMessage
) {
1186 nsBaseDragSession::MaybeEditorDeletedSourceNode(Element
* aEditingHost
) {
1187 // If builtin editor of Blink and WebKit deletes the source node,they retarget
1188 // the source node to the editing host.
1189 // https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/page/drag_controller.cc;l=724;drc=d9ba13b8cd8ac0faed7afc3d1f7e4b67ebac2a0b
1190 // That allows editor apps listens to "dragend" event in editing host or its
1191 // ancestors. Therefore, we should follow them for compatibility.
1192 if (mSourceNode
&& !mSourceNode
->IsInComposedDoc()) {
1193 mSourceNode
= aEditingHost
;
1199 nsBaseDragService::GetMockDragController(
1200 nsIMockDragServiceController
** aController
) {
1202 if (XRE_IsContentProcess()) {
1203 // The mock drag controller is only available in the parent process.
1204 MOZ_ASSERT(!XRE_IsContentProcess());
1205 return NS_ERROR_NOT_AVAILABLE
;
1207 if (!mMockController
) {
1208 mMockController
= new mozilla::test::MockDragServiceController();
1210 auto controller
= mMockController
;
1211 controller
.forget(aController
);
1214 *aController
= nullptr;
1215 MOZ_ASSERT(false, "CreateMockDragController may only be called for testing");
1216 return NS_ERROR_NOT_AVAILABLE
;
1221 nsBaseDragService::GetNeverAllowSessionIsSynthesizedForTests(
1222 bool* aNeverAllow
) {
1223 *aNeverAllow
= mNeverAllowSessionIsSynthesizedForTests
;
1228 nsBaseDragService::SetNeverAllowSessionIsSynthesizedForTests(bool aNeverAllow
) {
1229 mNeverAllowSessionIsSynthesizedForTests
= aNeverAllow
;
1234 nsBaseDragSession::SetDragEndPoint(int32_t aScreenX
, int32_t aScreenY
) {
1235 SetDragEndPoint(LayoutDeviceIntPoint(aScreenX
, aScreenY
));
1239 void nsBaseDragSession::TakeSessionBrowserListFromService() {
1240 nsCOMPtr
<nsIDragService
> svc
=
1241 do_GetService("@mozilla.org/widget/dragservice;1");
1242 NS_ENSURE_TRUE_VOID(svc
);
1244 static_cast<nsBaseDragService
*>(svc
.get())->TakeSessionBrowserList();
1248 nsIWidget
* nsBaseDragService::GetWidgetFromWidgetProvider(
1249 nsISupports
* aWidgetProvider
) {
1250 nsCOMPtr
<nsIWidget
> widget
= do_QueryObject(aWidgetProvider
);
1255 nsPIDOMWindowOuter
* outer
;
1256 if (aWidgetProvider
) {
1257 nsCOMPtr
<mozIDOMWindow
> window
= do_GetInterface(aWidgetProvider
);
1258 NS_ENSURE_TRUE(window
, nullptr);
1259 RefPtr
<nsPIDOMWindowInner
> innerWin
= nsGlobalWindowInner::Cast(window
);
1260 NS_ENSURE_TRUE(innerWin
, nullptr);
1261 outer
= innerWin
->GetOuterWindow();
1263 nsCOMPtr
<nsPIDOMWindowInner
> winInner
;
1264 winInner
= do_QueryInterface(GetEntryGlobal());
1265 NS_ENSURE_TRUE(winInner
, nullptr);
1266 outer
= winInner
->GetOuterWindow();
1268 NS_ENSURE_TRUE(outer
, nullptr);
1269 nsIDocShell
* docShell
= outer
->GetDocShell();
1270 NS_ENSURE_TRUE(docShell
, nullptr);
1271 PresShell
* presShell
= docShell
->GetPresShell();
1272 NS_ENSURE_TRUE(presShell
, nullptr);
1273 nsViewManager
* vm
= presShell
->GetViewManager();
1274 NS_ENSURE_TRUE(vm
, nullptr);
1275 return vm
->GetRootWidget();
1279 nsBaseDragSession::SendStoreDropTargetAndDelayEndDragSession(
1280 DragEvent
* aEvent
) {
1281 mDelayedDropBrowserParent
= dom::BrowserParent::GetBrowserParentFromLayersId(
1282 aEvent
->WidgetEventPtr()->mLayersId
);
1283 NS_ENSURE_TRUE(mDelayedDropBrowserParent
, NS_ERROR_FAILURE
);
1284 uint32_t dropEffect
= nsIDragService::DRAGDROP_ACTION_NONE
;
1285 if (mDataTransfer
) {
1286 dropEffect
= mDataTransfer
->DropEffectInt();
1289 << mDelayedDropBrowserParent
->SendStoreDropTargetAndDelayEndDragSession(
1290 aEvent
->WidgetEventPtr()->mRefPoint
, dropEffect
, mDragAction
,
1291 mTriggeringPrincipal
, mCsp
);
1296 nsBaseDragSession::SendDispatchToDropTargetAndResumeEndDragSession(
1298 MOZ_ASSERT(mDelayedDropBrowserParent
);
1299 Unused
<< mDelayedDropBrowserParent
1300 ->SendDispatchToDropTargetAndResumeEndDragSession(aShouldDrop
);
1301 mDelayedDropBrowserParent
= nullptr;
1306 nsBaseDragSession::StoreDropTargetAndDelayEndDragSession(
1307 mozilla::dom::Element
* aElement
, nsIFrame
* aFrame
) {
1308 MOZ_ASSERT(XRE_IsContentProcess());
1309 MOZ_DRAGSERVICE_LOG(
1310 "[%p] StoreDropTargetAndDelayEndDragSession | aElement: %p | aFrame: %p",
1311 this, aElement
, aFrame
);
1312 mDelayedDropTarget
= do_GetWeakReference(aElement
);
1313 mDelayedDropFrame
= aFrame
;
1318 nsBaseDragSession::DispatchToDropTargetAndResumeEndDragSession(
1319 nsIWidget
* aWidget
, const LayoutDeviceIntPoint
& aPt
, bool aShouldDrop
) {
1320 MOZ_ASSERT(XRE_IsContentProcess());
1321 MOZ_DRAGSERVICE_LOG(
1322 "[%p] DispatchToDropTargetAndResumeEndDragSession | pt=(%d, %d) | "
1324 this, static_cast<int32_t>(aPt
.x
), static_cast<int32_t>(aPt
.y
),
1325 aShouldDrop
? "true" : "false");
1327 RefPtr
<Element
> delayedDropTarget
= do_QueryReferent(mDelayedDropTarget
);
1328 mDelayedDropTarget
= nullptr;
1329 nsIFrame
* delayedDropFrame
= mDelayedDropFrame
;
1330 mDelayedDropFrame
= nullptr;
1331 auto edsData
= std::move(mEndDragSessionData
);
1333 if (!delayedDropTarget
) {
1334 MOZ_ASSERT(!edsData
&& !delayedDropFrame
);
1337 if (!delayedDropFrame
) {
1338 // Weak frame was deleted
1342 nsEventStatus status
= nsEventStatus_eIgnore
;
1343 RefPtr
<PresShell
> ps
= delayedDropFrame
->PresContext()->GetPresShell();
1344 auto event
= MakeUnique
<WidgetDragEvent
>(
1345 true, aShouldDrop
? eDrop
: eDragExit
, aWidget
);
1346 event
->mRefPoint
= aPt
;
1347 ps
->HandleEventWithTarget(event
.get(), delayedDropFrame
, delayedDropTarget
,
1350 // If EndDragSession was delayed, issue it now.
1352 EndDragSession(edsData
->mDoneDrag
, edsData
->mKeyModifiers
);