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 "nsIServiceManager.h"
11 #include "nsITransferable.h"
14 #include "nsISupportsPrimitives.h"
16 #include "nsIInterfaceRequestorUtils.h"
18 #include "nsFrameLoaderOwner.h"
19 #include "mozilla/dom/Document.h"
20 #include "nsIContent.h"
21 #include "nsIPresShell.h"
22 #include "nsViewManager.h"
24 #include "nsPresContext.h"
25 #include "nsIImageLoadingContent.h"
26 #include "imgIContainer.h"
27 #include "imgIRequest.h"
28 #include "ImageRegion.h"
29 #include "nsQueryObject.h"
31 #include "nsXULPopupManager.h"
32 #include "nsMenuPopupFrame.h"
33 #include "SVGImageContext.h"
35 # include "nsTreeBodyFrame.h"
37 #include "mozilla/MouseEvents.h"
38 #include "mozilla/Preferences.h"
39 #include "mozilla/dom/BindingDeclarations.h"
40 #include "mozilla/dom/DataTransferItemList.h"
41 #include "mozilla/dom/DataTransfer.h"
42 #include "mozilla/dom/DragEvent.h"
43 #include "mozilla/dom/MouseEventBinding.h"
44 #include "mozilla/dom/Selection.h"
45 #include "mozilla/gfx/2D.h"
46 #include "mozilla/Unused.h"
47 #include "nsFrameLoader.h"
48 #include "TabParent.h"
50 #include "gfxContext.h"
51 #include "gfxPlatform.h"
54 using namespace mozilla
;
55 using namespace mozilla::dom
;
56 using namespace mozilla::gfx
;
57 using namespace mozilla::image
;
59 #define DRAGIMAGES_PREF "nglayout.enable_drag_images"
61 nsBaseDragService::nsBaseDragService()
63 mOnlyChromeDrop(false),
66 mUserCancelled(false),
67 mDragEventDispatchedToChildProcess(false),
68 mDragAction(DRAGDROP_ACTION_NONE
),
69 mDragActionFromChildProcess(DRAGDROP_ACTION_UNINITIALIZED
),
70 mContentPolicyType(nsIContentPolicy::TYPE_OTHER
),
72 mInputSource(MouseEvent_Binding::MOZ_SOURCE_MOUSE
) {}
74 nsBaseDragService::~nsBaseDragService() = default;
76 NS_IMPL_ISUPPORTS(nsBaseDragService
, nsIDragService
, nsIDragSession
)
78 //---------------------------------------------------------
80 nsBaseDragService::SetCanDrop(bool aCanDrop
) {
85 //---------------------------------------------------------
87 nsBaseDragService::GetCanDrop(bool* aCanDrop
) {
91 //---------------------------------------------------------
93 nsBaseDragService::SetOnlyChromeDrop(bool aOnlyChrome
) {
94 mOnlyChromeDrop
= aOnlyChrome
;
98 //---------------------------------------------------------
100 nsBaseDragService::GetOnlyChromeDrop(bool* aOnlyChrome
) {
101 *aOnlyChrome
= mOnlyChromeDrop
;
105 //---------------------------------------------------------
107 nsBaseDragService::SetDragAction(uint32_t anAction
) {
108 mDragAction
= anAction
;
112 //---------------------------------------------------------
114 nsBaseDragService::GetDragAction(uint32_t* anAction
) {
115 *anAction
= mDragAction
;
119 //-------------------------------------------------------------------------
122 nsBaseDragService::GetNumDropItems(uint32_t* aNumItems
) {
124 return NS_ERROR_FAILURE
;
130 // Returns the DOM document where the drag was initiated. This will be
131 // nullptr if the drag began outside of our application.
134 nsBaseDragService::GetSourceDocument(Document
** aSourceDocument
) {
135 *aSourceDocument
= mSourceDocument
.get();
136 NS_IF_ADDREF(*aSourceDocument
);
144 // Returns the DOM node where the drag was initiated. This will be
145 // nullptr if the drag began outside of our application.
148 nsBaseDragService::GetSourceNode(nsINode
** aSourceNode
) {
149 *aSourceNode
= do_AddRef(mSourceNode
).take();
154 nsBaseDragService::GetTriggeringPrincipal(nsIPrincipal
** aPrincipal
) {
155 NS_IF_ADDREF(*aPrincipal
= mTriggeringPrincipal
);
160 nsBaseDragService::SetTriggeringPrincipal(nsIPrincipal
* aPrincipal
) {
161 mTriggeringPrincipal
= aPrincipal
;
165 //-------------------------------------------------------------------------
168 nsBaseDragService::GetData(nsITransferable
* aTransferable
,
169 uint32_t aItemIndex
) {
170 return NS_ERROR_FAILURE
;
173 //-------------------------------------------------------------------------
175 nsBaseDragService::IsDataFlavorSupported(const char* aDataFlavor
,
177 return NS_ERROR_FAILURE
;
181 nsBaseDragService::GetDataTransferXPCOM(DataTransfer
** aDataTransfer
) {
182 *aDataTransfer
= mDataTransfer
;
183 NS_IF_ADDREF(*aDataTransfer
);
188 nsBaseDragService::SetDataTransferXPCOM(DataTransfer
* aDataTransfer
) {
189 NS_ENSURE_STATE(aDataTransfer
);
190 mDataTransfer
= aDataTransfer
;
194 DataTransfer
* nsBaseDragService::GetDataTransfer() { return mDataTransfer
; }
196 void nsBaseDragService::SetDataTransfer(DataTransfer
* aDataTransfer
) {
197 mDataTransfer
= aDataTransfer
;
200 //-------------------------------------------------------------------------
202 nsBaseDragService::InvokeDragSession(
203 nsINode
* aDOMNode
, nsIPrincipal
* aPrincipal
, nsIArray
* aTransferableArray
,
204 uint32_t aActionType
,
205 nsContentPolicyType aContentPolicyType
= nsIContentPolicy::TYPE_OTHER
) {
206 AUTO_PROFILER_LABEL("nsBaseDragService::InvokeDragSession", OTHER
);
208 NS_ENSURE_TRUE(aDOMNode
, NS_ERROR_INVALID_ARG
);
209 NS_ENSURE_TRUE(mSuppressLevel
== 0, NS_ERROR_FAILURE
);
211 // stash the document of the dom node
212 mSourceDocument
= aDOMNode
->OwnerDoc();
213 mTriggeringPrincipal
= aPrincipal
;
214 mSourceNode
= aDOMNode
;
215 mContentPolicyType
= aContentPolicyType
;
216 mEndDragPoint
= LayoutDeviceIntPoint(0, 0);
218 // When the mouse goes down, the selection code starts a mouse
219 // capture. However, this gets in the way of determining drag
220 // feedback for things like trees because the event coordinates
221 // are in the wrong coord system, so turn off mouse capture.
222 nsIPresShell::ClearMouseCapture(nullptr);
225 mozilla::Unused
<< aTransferableArray
->GetLength(&length
);
226 for (uint32_t i
= 0; i
< length
; ++i
) {
227 nsCOMPtr
<nsITransferable
> trans
= do_QueryElementAt(aTransferableArray
, i
);
229 // Set the requestingPrincipal on the transferable.
230 trans
->SetRequestingPrincipal(mSourceNode
->NodePrincipal());
231 trans
->SetContentPolicyType(mContentPolicyType
);
235 nsresult rv
= InvokeDragSessionImpl(aTransferableArray
, mRegion
, aActionType
);
238 // Set mDoingDrag so that EndDragSession cleans up and sends the dragend
239 // event after the aborted drag.
241 EndDragSession(true, 0);
248 nsBaseDragService::InvokeDragSessionWithImage(
249 nsINode
* aDOMNode
, nsIPrincipal
* aPrincipal
, nsIArray
* aTransferableArray
,
250 uint32_t aActionType
, nsINode
* aImage
, int32_t aImageX
, int32_t aImageY
,
251 DragEvent
* aDragEvent
, DataTransfer
* aDataTransfer
) {
252 NS_ENSURE_TRUE(aDragEvent
, NS_ERROR_NULL_POINTER
);
253 NS_ENSURE_TRUE(aDataTransfer
, NS_ERROR_NULL_POINTER
);
254 NS_ENSURE_TRUE(mSuppressLevel
== 0, NS_ERROR_FAILURE
);
256 mDataTransfer
= aDataTransfer
;
257 mSelection
= nullptr;
259 mDragPopup
= nullptr;
261 mImageOffset
= CSSIntPoint(aImageX
, aImageY
);
263 mScreenPosition
.x
= aDragEvent
->ScreenX(CallerType::System
);
264 mScreenPosition
.y
= aDragEvent
->ScreenY(CallerType::System
);
265 mInputSource
= aDragEvent
->MozInputSource();
267 // If dragging within a XUL tree and no custom drag image was
268 // set, the region argument to InvokeDragSessionWithImage needs
269 // to be set to the area encompassing the selected rows of the
270 // tree to ensure that the drag feedback gets clipped to those
271 // rows. For other content, region should be null.
274 if (aDOMNode
&& aDOMNode
->IsContent() && !aImage
) {
275 if (aDOMNode
->NodeInfo()->Equals(nsGkAtoms::treechildren
,
277 nsTreeBodyFrame
* treeBody
=
278 do_QueryFrame(aDOMNode
->AsContent()->GetPrimaryFrame());
280 mRegion
= treeBody
->GetSelectionRegion();
287 InvokeDragSession(aDOMNode
, aPrincipal
, aTransferableArray
, aActionType
,
288 nsIContentPolicy::TYPE_INTERNAL_IMAGE
);
294 nsBaseDragService::InvokeDragSessionWithSelection(Selection
* aSelection
,
295 nsIPrincipal
* aPrincipal
,
296 nsIArray
* aTransferableArray
,
297 uint32_t aActionType
,
298 DragEvent
* aDragEvent
,
299 DataTransfer
* aDataTransfer
) {
300 NS_ENSURE_TRUE(aSelection
, NS_ERROR_NULL_POINTER
);
301 NS_ENSURE_TRUE(aDragEvent
, NS_ERROR_NULL_POINTER
);
302 NS_ENSURE_TRUE(mSuppressLevel
== 0, NS_ERROR_FAILURE
);
304 mDataTransfer
= aDataTransfer
;
305 mSelection
= aSelection
;
307 mDragPopup
= nullptr;
309 mImageOffset
= CSSIntPoint();
312 mScreenPosition
.x
= aDragEvent
->ScreenX(CallerType::System
);
313 mScreenPosition
.y
= aDragEvent
->ScreenY(CallerType::System
);
314 mInputSource
= aDragEvent
->MozInputSource();
316 // just get the focused node from the selection
317 // XXXndeakin this should actually be the deepest node that contains both
318 // endpoints of the selection
319 nsCOMPtr
<nsINode
> node
= aSelection
->GetFocusNode();
321 return InvokeDragSession(node
, aPrincipal
, aTransferableArray
, aActionType
,
322 nsIContentPolicy::TYPE_OTHER
);
325 //-------------------------------------------------------------------------
327 nsBaseDragService::GetCurrentSession(nsIDragSession
** aSession
) {
328 if (!aSession
) return NS_ERROR_INVALID_ARG
;
330 // "this" also implements a drag session, so say we are one but only
331 // if there is currently a drag going on.
332 if (!mSuppressLevel
&& mDoingDrag
) {
334 NS_ADDREF(*aSession
); // addRef because we're a "getter"
341 //-------------------------------------------------------------------------
343 nsBaseDragService::StartDragSession() {
345 return NS_ERROR_FAILURE
;
348 // By default dispatch drop also to content.
349 mOnlyChromeDrop
= false;
354 void nsBaseDragService::OpenDragPopup() {
356 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
358 pm
->ShowPopupAtScreen(mDragPopup
, mScreenPosition
.x
- mImageOffset
.x
,
359 mScreenPosition
.y
- mImageOffset
.y
, false, nullptr);
364 int32_t nsBaseDragService::TakeChildProcessDragAction() {
365 // If the last event was dispatched to the child process, use the drag action
366 // assigned from it instead and return it. DRAGDROP_ACTION_UNINITIALIZED is
367 // returned otherwise.
368 int32_t retval
= DRAGDROP_ACTION_UNINITIALIZED
;
369 if (TakeDragEventDispatchedToChildProcess() &&
370 mDragActionFromChildProcess
!= DRAGDROP_ACTION_UNINITIALIZED
) {
371 retval
= mDragActionFromChildProcess
;
377 //-------------------------------------------------------------------------
379 nsBaseDragService::EndDragSession(bool aDoneDrag
, uint32_t aKeyModifiers
) {
381 return NS_ERROR_FAILURE
;
384 if (aDoneDrag
&& !mSuppressLevel
) {
385 FireDragEventAtSource(eDragEnd
, aKeyModifiers
);
389 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
391 pm
->HidePopup(mDragPopup
, false, true, false, false);
395 for (uint32_t i
= 0; i
< mChildProcesses
.Length(); ++i
) {
396 mozilla::Unused
<< mChildProcesses
[i
]->SendEndDragSession(
397 aDoneDrag
, mUserCancelled
, mEndDragPoint
, aKeyModifiers
);
398 // Continue sending input events with input priority when stopping the dnd
400 mChildProcesses
[i
]->SetInputPriorityEventEnabled(true);
402 mChildProcesses
.Clear();
404 // mDataTransfer and the items it owns are going to die anyway, but we
405 // explicitly deref the contained data here so that we don't have to wait for
406 // CC to reclaim the memory.
407 if (XRE_IsParentProcess()) {
408 DiscardInternalTransferData();
414 // release the source we've been holding on to.
415 mSourceDocument
= nullptr;
416 mSourceNode
= nullptr;
417 mTriggeringPrincipal
= nullptr;
418 mSelection
= nullptr;
419 mDataTransfer
= nullptr;
421 mUserCancelled
= false;
422 mDragPopup
= nullptr;
424 mImageOffset
= CSSIntPoint();
425 mScreenPosition
= CSSIntPoint();
426 mEndDragPoint
= LayoutDeviceIntPoint(0, 0);
427 mInputSource
= MouseEvent_Binding::MOZ_SOURCE_MOUSE
;
433 void nsBaseDragService::DiscardInternalTransferData() {
434 if (mDataTransfer
&& mSourceNode
) {
435 MOZ_ASSERT(mDataTransfer
);
437 DataTransferItemList
* items
= mDataTransfer
->Items();
438 for (size_t i
= 0; i
< items
->Length(); i
++) {
440 DataTransferItem
* item
= items
->IndexedGetter(i
, found
);
442 // Non-OTHER items may still be needed by JS. Skip them.
443 if (!found
|| item
->Kind() != DataTransferItem::KIND_OTHER
) {
447 nsCOMPtr
<nsIVariant
> variant
= item
->DataNoSecurityCheck();
448 nsCOMPtr
<nsIWritableVariant
> writable
= do_QueryInterface(variant
);
451 writable
->SetAsEmpty();
458 nsBaseDragService::FireDragEventAtSource(EventMessage aEventMessage
,
459 uint32_t aKeyModifiers
) {
460 if (mSourceNode
&& mSourceDocument
&& !mSuppressLevel
) {
461 nsCOMPtr
<nsIPresShell
> presShell
= mSourceDocument
->GetShell();
463 nsEventStatus status
= nsEventStatus_eIgnore
;
464 WidgetDragEvent
event(true, aEventMessage
, nullptr);
465 event
.inputSource
= mInputSource
;
466 if (aEventMessage
== eDragEnd
) {
467 event
.mRefPoint
= mEndDragPoint
;
468 event
.mUserCancelled
= mUserCancelled
;
470 event
.mModifiers
= aKeyModifiers
;
471 // Send the drag event to APZ, which needs to know about them to be
472 // able to accurately detect the end of a drag gesture.
473 if (nsPresContext
* presContext
= presShell
->GetPresContext()) {
474 if (nsCOMPtr
<nsIWidget
> widget
= presContext
->GetRootWidget()) {
475 widget
->DispatchEventToAPZOnly(&event
);
479 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(mSourceNode
);
480 return presShell
->HandleDOMEventWithTarget(content
, &event
, &status
);
487 /* This is used by Windows and Mac to update the position of a popup being
488 * used as a drag image during the drag. This isn't used on GTK as it manages
489 * the drag popup itself.
492 nsBaseDragService::DragMoved(int32_t aX
, int32_t aY
) {
494 nsIFrame
* frame
= mDragPopup
->GetPrimaryFrame();
495 if (frame
&& frame
->IsMenuPopupFrame()) {
497 RoundedToInt(LayoutDeviceIntPoint(aX
, aY
) /
498 frame
->PresContext()->CSSToDevPixelScale()) -
500 (static_cast<nsMenuPopupFrame
*>(frame
))->MoveTo(cssPos
, true);
507 static nsIPresShell
* GetPresShellForContent(nsINode
* aDOMNode
) {
508 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(aDOMNode
);
509 if (!content
) return nullptr;
511 RefPtr
<Document
> document
= content
->GetComposedDoc();
513 document
->FlushPendingNotifications(FlushType::Display
);
514 return document
->GetShell();
520 nsresult
nsBaseDragService::DrawDrag(nsINode
* aDOMNode
,
521 const Maybe
<CSSIntRegion
>& aRegion
,
522 CSSIntPoint aScreenPosition
,
523 LayoutDeviceIntRect
* aScreenDragRect
,
524 RefPtr
<SourceSurface
>* aSurface
,
525 nsPresContext
** aPresContext
) {
527 *aPresContext
= nullptr;
529 // use a default size, in case of an error.
530 aScreenDragRect
->SetRect(aScreenPosition
.x
- mImageOffset
.x
,
531 aScreenPosition
.y
- mImageOffset
.y
, 1, 1);
533 // if a drag image was specified, use that, otherwise, use the source node
534 nsCOMPtr
<nsINode
> dragNode
= mImage
? mImage
.get() : aDOMNode
;
536 // get the presshell for the node being dragged. If the drag image is not in
537 // a document or has no frame, get the presshell from the source drag node
538 nsIPresShell
* presShell
= GetPresShellForContent(dragNode
);
539 if (!presShell
&& mImage
) presShell
= GetPresShellForContent(aDOMNode
);
540 if (!presShell
) return NS_ERROR_FAILURE
;
542 *aPresContext
= presShell
->GetPresContext();
544 RefPtr
<nsFrameLoaderOwner
> flo
= do_QueryObject(dragNode
);
546 RefPtr
<nsFrameLoader
> fl
= flo
->GetFrameLoader();
548 auto* tp
= static_cast<mozilla::dom::TabParent
*>(fl
->GetRemoteBrowser());
549 if (tp
&& tp
->TakeDragVisualization(*aSurface
, aScreenDragRect
)) {
551 // Just clear the surface if chrome has overridden it with an image.
560 // convert mouse position to dev pixels of the prescontext
561 CSSIntPoint
screenPosition(aScreenPosition
);
562 screenPosition
.x
-= mImageOffset
.x
;
563 screenPosition
.y
-= mImageOffset
.y
;
564 LayoutDeviceIntPoint screenPoint
=
565 ConvertToUnscaledDevPixels(*aPresContext
, screenPosition
);
566 aScreenDragRect
->MoveTo(screenPoint
.x
, screenPoint
.y
);
568 // check if drag images are disabled
569 bool enableDragImages
= Preferences::GetBool(DRAGIMAGES_PREF
, true);
571 // didn't want an image, so just set the screen rectangle to the frame size
572 if (!enableDragImages
|| !mHasImage
) {
573 // if a region was specified, set the screen rectangle to the area that
574 // the region occupies
577 // the region's coordinates are relative to the root frame
578 dragRect
= aRegion
->GetBounds();
580 nsIFrame
* rootFrame
= presShell
->GetRootFrame();
581 CSSIntRect screenRect
= rootFrame
->GetScreenRect();
582 dragRect
.MoveBy(screenRect
.TopLeft());
584 // otherwise, there was no region so just set the rectangle to
585 // the size of the primary frame of the content.
586 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(dragNode
);
587 nsIFrame
* frame
= content
->GetPrimaryFrame();
589 dragRect
= frame
->GetScreenRect();
593 nsIntRect dragRectDev
=
594 ToAppUnits(dragRect
, AppUnitsPerCSSPixel())
595 .ToOutsidePixels((*aPresContext
)->AppUnitsPerDevPixel());
596 aScreenDragRect
->SizeTo(dragRectDev
.Width(), dragRectDev
.Height());
600 // draw the image for selections
602 LayoutDeviceIntPoint
pnt(aScreenDragRect
->TopLeft());
603 *aSurface
= presShell
->RenderSelection(
604 mSelection
, pnt
, aScreenDragRect
,
605 mImage
? 0 : nsIPresShell::RENDER_AUTO_SCALE
);
609 // if a custom image was specified, check if it is an image node and draw
610 // using the source rather than the displayed image. But if mImage isn't
611 // an image or canvas, fall through to RenderNode below.
613 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(dragNode
);
614 HTMLCanvasElement
* canvas
= HTMLCanvasElement::FromNodeOrNull(content
);
616 return DrawDragForImage(*aPresContext
, nullptr, canvas
, aScreenDragRect
,
620 nsCOMPtr
<nsIImageLoadingContent
> imageLoader
= do_QueryInterface(dragNode
);
621 // for image nodes, create the drag image from the actual image data
623 return DrawDragForImage(*aPresContext
, imageLoader
, nullptr,
624 aScreenDragRect
, aSurface
);
627 // If the image is a popup, use that as the image. This allows custom drag
628 // images that can change during the drag, but means that any platform
629 // default image handling won't occur.
630 // XXXndeakin this should be chrome-only
632 nsIFrame
* frame
= content
->GetPrimaryFrame();
633 if (frame
&& frame
->IsMenuPopupFrame()) {
634 mDragPopup
= content
;
639 // otherwise, just draw the node
640 uint32_t renderFlags
= mImage
? 0 : nsIPresShell::RENDER_AUTO_SCALE
;
642 // check if the dragged node itself is an img element
643 if (dragNode
->NodeName().LowerCaseEqualsLiteral("img")) {
644 renderFlags
= renderFlags
| nsIPresShell::RENDER_IS_IMAGE
;
646 nsINodeList
* childList
= dragNode
->ChildNodes();
647 uint32_t length
= childList
->Length();
648 // check every childnode for being an img element
649 // XXXbz why don't we need to check descendants recursively?
650 for (uint32_t count
= 0; count
< length
; ++count
) {
651 if (childList
->Item(count
)->NodeName().LowerCaseEqualsLiteral(
653 // if the dragnode contains an image, set RENDER_IS_IMAGE flag
654 renderFlags
= renderFlags
| nsIPresShell::RENDER_IS_IMAGE
;
660 LayoutDeviceIntPoint
pnt(aScreenDragRect
->TopLeft());
661 *aSurface
= presShell
->RenderNode(dragNode
, aRegion
, pnt
, aScreenDragRect
,
665 // If an image was specified, reset the position from the offset that was
668 aScreenDragRect
->MoveTo(screenPoint
.x
, screenPoint
.y
);
674 nsresult
nsBaseDragService::DrawDragForImage(
675 nsPresContext
* aPresContext
, nsIImageLoadingContent
* aImageLoader
,
676 HTMLCanvasElement
* aCanvas
, LayoutDeviceIntRect
* aScreenDragRect
,
677 RefPtr
<SourceSurface
>* aSurface
) {
678 nsCOMPtr
<imgIContainer
> imgContainer
;
680 nsCOMPtr
<imgIRequest
> imgRequest
;
681 nsresult rv
= aImageLoader
->GetRequest(
682 nsIImageLoadingContent::CURRENT_REQUEST
, getter_AddRefs(imgRequest
));
683 NS_ENSURE_SUCCESS(rv
, rv
);
684 if (!imgRequest
) return NS_ERROR_NOT_AVAILABLE
;
686 rv
= imgRequest
->GetImage(getter_AddRefs(imgContainer
));
687 NS_ENSURE_SUCCESS(rv
, rv
);
688 if (!imgContainer
) return NS_ERROR_NOT_AVAILABLE
;
690 // use the size of the image as the size of the drag image
691 int32_t imageWidth
, imageHeight
;
692 rv
= imgContainer
->GetWidth(&imageWidth
);
693 NS_ENSURE_SUCCESS(rv
, rv
);
695 rv
= imgContainer
->GetHeight(&imageHeight
);
696 NS_ENSURE_SUCCESS(rv
, rv
);
698 aScreenDragRect
->SizeTo(aPresContext
->CSSPixelsToDevPixels(imageWidth
),
699 aPresContext
->CSSPixelsToDevPixels(imageHeight
));
701 // XXX The canvas size should be converted to dev pixels.
702 NS_ASSERTION(aCanvas
, "both image and canvas are null");
703 nsIntSize sz
= aCanvas
->GetSize();
704 aScreenDragRect
->SizeTo(sz
.width
, sz
.height
);
708 destSize
.width
= aScreenDragRect
->Width();
709 destSize
.height
= aScreenDragRect
->Height();
710 if (destSize
.width
== 0 || destSize
.height
== 0) return NS_ERROR_FAILURE
;
712 nsresult result
= NS_OK
;
714 RefPtr
<DrawTarget
> dt
=
715 gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
716 destSize
, SurfaceFormat::B8G8R8A8
);
717 if (!dt
|| !dt
->IsValid()) return NS_ERROR_FAILURE
;
719 RefPtr
<gfxContext
> ctx
= gfxContext::CreateOrNull(dt
);
720 if (!ctx
) return NS_ERROR_FAILURE
;
723 imgContainer
->Draw(ctx
, destSize
, ImageRegion::Create(destSize
),
724 imgIContainer::FRAME_CURRENT
, SamplingFilter::GOOD
,
725 /* no SVGImageContext */ Nothing(),
726 imgIContainer::FLAG_SYNC_DECODE
, 1.0);
727 if (res
== ImgDrawResult::BAD_IMAGE
|| res
== ImgDrawResult::BAD_ARGS
||
728 res
== ImgDrawResult::NOT_SUPPORTED
) {
729 return NS_ERROR_FAILURE
;
731 *aSurface
= dt
->Snapshot();
733 *aSurface
= aCanvas
->GetSurfaceSnapshot();
739 LayoutDeviceIntPoint
nsBaseDragService::ConvertToUnscaledDevPixels(
740 nsPresContext
* aPresContext
, CSSIntPoint aScreenPosition
) {
742 aPresContext
->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
743 return LayoutDeviceIntPoint(
744 nsPresContext::CSSPixelsToAppUnits(aScreenPosition
.x
) / adj
,
745 nsPresContext::CSSPixelsToAppUnits(aScreenPosition
.y
) / adj
);
749 nsBaseDragService::Suppress() {
750 EndDragSession(false, 0);
756 nsBaseDragService::Unsuppress() {
762 nsBaseDragService::UserCancelled() {
763 mUserCancelled
= true;
768 nsBaseDragService::UpdateDragEffect() {
769 mDragActionFromChildProcess
= mDragAction
;
774 nsBaseDragService::UpdateDragImage(nsINode
* aImage
, int32_t aImageX
,
776 // Don't change the image if this is a drag from another source or if there
778 if (!mSourceNode
|| mDragPopup
) return NS_OK
;
781 mImageOffset
= CSSIntPoint(aImageX
, aImageY
);
786 nsBaseDragService::DragEventDispatchedToChildProcess() {
787 mDragEventDispatchedToChildProcess
= true;
791 bool nsBaseDragService::MaybeAddChildProcess(
792 mozilla::dom::ContentParent
* aChild
) {
793 if (!mChildProcesses
.Contains(aChild
)) {
794 mChildProcesses
.AppendElement(aChild
);