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/. */
11 // shellapi.h is needed to build with WIN32_LEAN_AND_MEAN
14 #include "mozilla/RefPtr.h"
15 #include "nsDragService.h"
16 #include "nsITransferable.h"
17 #include "nsDataObj.h"
19 #include "nsWidgetsCID.h"
20 #include "nsNativeDragTarget.h"
21 #include "nsNativeDragSource.h"
22 #include "nsClipboard.h"
23 #include "mozilla/dom/Document.h"
24 #include "mozilla/dom/DocumentInlines.h"
25 #include "nsDataObjCollection.h"
27 #include "nsArrayUtils.h"
30 #include "nsIScreenManager.h"
31 #include "nsToolkit.h"
33 #include "nsDirectoryServiceDefs.h"
34 #include "nsUnicharUtils.h"
36 #include "nsMathUtils.h"
38 #include "KeyboardLayout.h"
39 #include "gfxContext.h"
40 #include "mozilla/gfx/2D.h"
41 #include "mozilla/gfx/DataSurfaceHelpers.h"
42 #include "mozilla/gfx/Tools.h"
43 #include "mozilla/ScopeExit.h"
45 using namespace mozilla
;
46 using namespace mozilla::gfx
;
47 using namespace mozilla::widget
;
49 //-------------------------------------------------------------------------
51 // DragService constructor
53 //-------------------------------------------------------------------------
54 nsDragService::nsDragService()
55 : mDataObject(nullptr), mSentLocalDropEvent(false) {}
57 //-------------------------------------------------------------------------
59 // DragService destructor
61 //-------------------------------------------------------------------------
62 nsDragService::~nsDragService() { NS_IF_RELEASE(mDataObject
); }
64 bool nsDragService::CreateDragImage(nsINode
* aDOMNode
,
65 const Maybe
<CSSIntRegion
>& aRegion
,
67 if (!psdi
) return false;
69 memset(psdi
, 0, sizeof(SHDRAGIMAGE
));
70 if (!aDOMNode
) return false;
72 // Prepare the drag image
73 LayoutDeviceIntRect dragRect
;
74 RefPtr
<SourceSurface
> surface
;
76 DrawDrag(aDOMNode
, aRegion
, mScreenPosition
, &dragRect
, &surface
, &pc
);
77 if (!surface
) return false;
79 uint32_t bmWidth
= dragRect
.Width(), bmHeight
= dragRect
.Height();
81 if (bmWidth
== 0 || bmHeight
== 0) return false;
83 psdi
->crColorKey
= CLR_NONE
;
85 RefPtr
<DataSourceSurface
> dataSurface
= Factory::CreateDataSourceSurface(
86 IntSize(bmWidth
, bmHeight
), SurfaceFormat::B8G8R8A8
);
87 NS_ENSURE_TRUE(dataSurface
, false);
89 DataSourceSurface::MappedSurface map
;
90 if (!dataSurface
->Map(DataSourceSurface::MapType::READ_WRITE
, &map
)) {
94 RefPtr
<DrawTarget
> dt
= Factory::CreateDrawTargetForData(
95 BackendType::CAIRO
, map
.mData
, dataSurface
->GetSize(), map
.mStride
,
96 dataSurface
->GetFormat());
104 Rect(0, 0, dataSurface
->GetSize().width
, dataSurface
->GetSize().height
),
105 Rect(0, 0, surface
->GetSize().width
, surface
->GetSize().height
),
106 DrawSurfaceOptions(), DrawOptions(1.0f
, CompositionOp::OP_SOURCE
));
110 memset((void*)&bmih
, 0, sizeof(BITMAPV5HEADER
));
111 bmih
.bV5Size
= sizeof(BITMAPV5HEADER
);
112 bmih
.bV5Width
= bmWidth
;
113 bmih
.bV5Height
= -(int32_t)bmHeight
; // flip vertical
115 bmih
.bV5BitCount
= 32;
116 bmih
.bV5Compression
= BI_BITFIELDS
;
117 bmih
.bV5RedMask
= 0x00FF0000;
118 bmih
.bV5GreenMask
= 0x0000FF00;
119 bmih
.bV5BlueMask
= 0x000000FF;
120 bmih
.bV5AlphaMask
= 0xFF000000;
122 HDC hdcSrc
= CreateCompatibleDC(nullptr);
123 void* lpBits
= nullptr;
125 psdi
->hbmpDragImage
=
126 ::CreateDIBSection(hdcSrc
, (BITMAPINFO
*)&bmih
, DIB_RGB_COLORS
,
127 (void**)&lpBits
, nullptr, 0);
128 if (psdi
->hbmpDragImage
&& lpBits
) {
129 CopySurfaceDataToPackedArray(map
.mData
, static_cast<uint8_t*>(lpBits
),
130 dataSurface
->GetSize(), map
.mStride
,
131 BytesPerPixel(dataSurface
->GetFormat()));
134 psdi
->sizeDragImage
.cx
= bmWidth
;
135 psdi
->sizeDragImage
.cy
= bmHeight
;
137 const auto screenPoint
=
138 LayoutDeviceIntPoint::Round(mScreenPosition
* pc
->CSSToDevPixelScale());
139 psdi
->ptOffset
.x
= screenPoint
.x
- dragRect
.X();
140 psdi
->ptOffset
.y
= screenPoint
.y
- dragRect
.Y();
145 dataSurface
->Unmap();
147 return psdi
->hbmpDragImage
!= nullptr;
150 //-------------------------------------------------------------------------
151 nsresult
nsDragService::InvokeDragSessionImpl(
152 nsIArray
* anArrayTransferables
, const Maybe
<CSSIntRegion
>& aRegion
,
153 uint32_t aActionType
) {
154 // Try and get source URI of the items that are being dragged
155 nsIURI
* uri
= nullptr;
157 RefPtr
<dom::Document
> doc(mSourceDocument
);
159 uri
= doc
->GetDocumentURI();
162 uint32_t numItemsToDrag
= 0;
163 nsresult rv
= anArrayTransferables
->GetLength(&numItemsToDrag
);
164 if (!numItemsToDrag
) return NS_ERROR_FAILURE
;
166 // The clipboard class contains some static utility methods that we
167 // can use to create an IDataObject from the transferable
169 // if we're dragging more than one item, we need to create a
170 // "collection" object to fake out the OS. This collection contains
171 // one |IDataObject| for each transferable. If there is just the one
172 // (most cases), only pass around the native |IDataObject|.
173 RefPtr
<IDataObject
> itemToDrag
;
174 if (numItemsToDrag
> 1) {
175 nsDataObjCollection
* dataObjCollection
= new nsDataObjCollection();
176 if (!dataObjCollection
) return NS_ERROR_OUT_OF_MEMORY
;
177 itemToDrag
= dataObjCollection
;
178 for (uint32_t i
= 0; i
< numItemsToDrag
; ++i
) {
179 nsCOMPtr
<nsITransferable
> trans
=
180 do_QueryElementAt(anArrayTransferables
, i
);
182 RefPtr
<IDataObject
> dataObj
;
183 rv
= nsClipboard::CreateNativeDataObject(trans
, getter_AddRefs(dataObj
),
185 NS_ENSURE_SUCCESS(rv
, rv
);
186 // Add the flavors to the collection object too
187 rv
= nsClipboard::SetupNativeDataObject(trans
, dataObjCollection
);
188 NS_ENSURE_SUCCESS(rv
, rv
);
190 dataObjCollection
->AddDataObject(dataObj
);
193 } // if dragging multiple items
195 nsCOMPtr
<nsITransferable
> trans
=
196 do_QueryElementAt(anArrayTransferables
, 0);
198 rv
= nsClipboard::CreateNativeDataObject(trans
,
199 getter_AddRefs(itemToDrag
), uri
);
200 NS_ENSURE_SUCCESS(rv
, rv
);
202 } // else dragging a single object
204 // Create a drag image if support is available
205 IDragSourceHelper
* pdsh
;
206 if (SUCCEEDED(CoCreateInstance(CLSID_DragDropHelper
, nullptr,
207 CLSCTX_INPROC_SERVER
, IID_IDragSourceHelper
,
210 if (CreateDragImage(mSourceNode
, aRegion
, &sdi
)) {
211 if (FAILED(pdsh
->InitializeFromBitmap(&sdi
, itemToDrag
)))
212 DeleteObject(sdi
.hbmpDragImage
);
217 // Kick off the native drag session
218 return StartInvokingDragSession(itemToDrag
, aActionType
);
221 static HWND
GetSourceWindow(dom::Document
* aSourceDocument
) {
222 if (!aSourceDocument
) {
226 auto* pc
= aSourceDocument
->GetPresContext();
231 nsCOMPtr
<nsIWidget
> widget
= pc
->GetRootWidget();
236 return (HWND
)widget
->GetNativeData(NS_NATIVE_WINDOW
);
239 //-------------------------------------------------------------------------
240 nsresult
nsDragService::StartInvokingDragSession(IDataObject
* aDataObj
,
241 uint32_t aActionType
) {
242 // To do the drag we need to create an object that
243 // implements the IDataObject interface (for OLE)
244 RefPtr
<nsNativeDragSource
> nativeDragSrc
=
245 new nsNativeDragSource(mDataTransfer
);
247 // Now figure out what the native drag effect should be
249 DWORD effects
= DROPEFFECT_SCROLL
;
250 if (aActionType
& DRAGDROP_ACTION_COPY
) {
251 effects
|= DROPEFFECT_COPY
;
253 if (aActionType
& DRAGDROP_ACTION_MOVE
) {
254 effects
|= DROPEFFECT_MOVE
;
256 if (aActionType
& DRAGDROP_ACTION_LINK
) {
257 effects
|= DROPEFFECT_LINK
;
260 // XXX not sure why we bother to cache this, it can change during
262 mDragAction
= aActionType
;
263 mSentLocalDropEvent
= false;
269 RefPtr
<IDataObjectAsyncCapability
> pAsyncOp
;
270 // Offer to do an async drag
271 if (SUCCEEDED(aDataObj
->QueryInterface(IID_IDataObjectAsyncCapability
,
272 getter_AddRefs(pAsyncOp
)))) {
273 pAsyncOp
->SetAsyncMode(VARIANT_TRUE
);
275 MOZ_ASSERT_UNREACHABLE("When did our data object stop being async");
278 // Call the native D&D method
279 HRESULT res
= ::DoDragDrop(aDataObj
, nativeDragSrc
, effects
, &winDropRes
);
281 // In cases where the drop operation completed outside the application,
282 // update the source node's DataTransfer dropEffect value so it is up to date.
283 if (!mSentLocalDropEvent
) {
285 // Order is important, since multiple flags can be returned.
286 if (winDropRes
& DROPEFFECT_COPY
)
287 dropResult
= DRAGDROP_ACTION_COPY
;
288 else if (winDropRes
& DROPEFFECT_LINK
)
289 dropResult
= DRAGDROP_ACTION_LINK
;
290 else if (winDropRes
& DROPEFFECT_MOVE
)
291 dropResult
= DRAGDROP_ACTION_MOVE
;
293 dropResult
= DRAGDROP_ACTION_NONE
;
296 if (res
== DRAGDROP_S_DROP
) // Success
297 mDataTransfer
->SetDropEffectInt(dropResult
);
299 mDataTransfer
->SetDropEffectInt(DRAGDROP_ACTION_NONE
);
303 mUserCancelled
= nativeDragSrc
->UserCancelled();
305 // We're done dragging, get the cursor position and end the drag
306 // Use GetMessagePos to get the position of the mouse at the last message
307 // seen by the event loop. (Bug 489729)
308 // Note that we must convert this from device pixels back to Windows logical
309 // pixels (bug 818927).
310 DWORD pos
= ::GetMessagePos();
312 cpos
.x
= GET_X_LPARAM(pos
);
313 cpos
.y
= GET_Y_LPARAM(pos
);
314 if (auto wnd
= GetSourceWindow(mSourceDocument
)) {
315 // Convert from screen to client coordinates like nsWindow::InitEvent does.
316 ::ScreenToClient(wnd
, &cpos
);
318 SetDragEndPoint(LayoutDeviceIntPoint(cpos
.x
, cpos
.y
));
320 ModifierKeyState modifierKeyState
;
321 EndDragSession(true, modifierKeyState
.GetModifiers());
325 return DRAGDROP_S_DROP
== res
? NS_OK
: NS_ERROR_FAILURE
;
328 //-------------------------------------------------------------------------
329 // Make Sure we have the right kind of object
330 nsDataObjCollection
* nsDragService::GetDataObjCollection(
331 IDataObject
* aDataObj
) {
332 nsDataObjCollection
* dataObjCol
= nullptr;
334 nsIDataObjCollection
* dataObj
;
335 if (aDataObj
->QueryInterface(IID_IDataObjCollection
, (void**)&dataObj
) ==
337 dataObjCol
= static_cast<nsDataObjCollection
*>(aDataObj
);
345 //-------------------------------------------------------------------------
347 nsDragService::GetNumDropItems(uint32_t* aNumItems
) {
353 if (IsCollectionObject(mDataObject
)) {
354 nsDataObjCollection
* dataObjCol
= GetDataObjCollection(mDataObject
);
355 // If the count cannot be determined just return 0.
356 // This can happen if we have collection data of type
357 // MULTI_MIME ("Mozilla/IDataObjectCollectionFormat") on the clipboard
358 // from another process but we can't obtain an IID_IDataObjCollection
359 // from this process.
360 *aNumItems
= dataObjCol
? dataObjCol
->GetNumDataObjects() : 0;
363 // Next check if we have a file drop. Return the number of files in
364 // the file drop as the number of items we have, pretending like we
365 // actually have > 1 drag item.
367 SET_FORMATETC(fe2
, CF_HDROP
, 0, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
);
368 if (SUCCEEDED(mDataObject
->QueryGetData(&fe2
))) {
370 if (FAILED(mDataObject
->GetData(&fe2
, &stm
))) {
374 HDROP hdrop
= static_cast<HDROP
>(GlobalLock(stm
.hGlobal
));
375 MOZ_ASSERT(hdrop
!= NULL
);
376 *aNumItems
= ::DragQueryFileW(hdrop
, 0xFFFFFFFF, nullptr, 0);
377 ::GlobalUnlock(stm
.hGlobal
);
378 ::ReleaseStgMedium(&stm
);
379 // Data may be provided later, so assume we have 1 item
380 if (*aNumItems
== 0) {
385 // Next check if we have a virtual file drop.
386 SET_FORMATETC(fe2
, nsClipboard::GetClipboardFileDescriptorFormatW(), 0,
387 DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
);
390 if (SUCCEEDED(mDataObject
->GetData(&fe2
, &stm
))) {
391 LPFILEGROUPDESCRIPTOR pDesc
=
392 static_cast<LPFILEGROUPDESCRIPTOR
>(GlobalLock(stm
.hGlobal
));
394 *aNumItems
= pDesc
->cItems
;
396 GlobalUnlock(stm
.hGlobal
);
397 ReleaseStgMedium(&stm
);
404 //-------------------------------------------------------------------------
406 nsDragService::GetData(nsITransferable
* aTransferable
, uint32_t anItem
) {
407 // This typcially happens on a drop, the target would be asking
408 // for it's transferable to be filled in
409 // Use a static clipboard utility method for this
410 if (!mDataObject
) return NS_ERROR_FAILURE
;
412 nsresult dataFound
= NS_ERROR_FAILURE
;
414 if (IsCollectionObject(mDataObject
)) {
415 // multiple items, use |anItem| as an index into our collection
416 nsDataObjCollection
* dataObjCol
= GetDataObjCollection(mDataObject
);
417 uint32_t cnt
= dataObjCol
->GetNumDataObjects();
419 IDataObject
* dataObj
= dataObjCol
->GetDataObjectAt(anItem
);
420 dataFound
= nsClipboard::GetDataFromDataObject(dataObj
, 0, nullptr,
423 NS_WARNING("Index out of range!");
425 // If they are asking for item "0", we can just get it...
427 dataFound
= nsClipboard::GetDataFromDataObject(mDataObject
, anItem
,
428 nullptr, aTransferable
);
430 // It better be a file drop, or else non-zero indexes are invalid!
433 SET_FORMATETC(fe2
, CF_HDROP
, 0, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
);
434 SET_FORMATETC(fe3
, nsClipboard::GetClipboardFileDescriptorFormatW(), 0,
435 DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
);
436 if (SUCCEEDED(mDataObject
->QueryGetData(&fe2
)) ||
437 SUCCEEDED(mDataObject
->QueryGetData(&fe3
)))
438 dataFound
= nsClipboard::GetDataFromDataObject(mDataObject
, anItem
,
439 nullptr, aTransferable
);
442 "Reqesting non-zero index, but clipboard data is not a "
449 //---------------------------------------------------------
451 nsDragService::SetIDataObject(IDataObject
* aDataObj
) {
452 // When the native drag starts the DragService gets
453 // the IDataObject that is being dragged
454 NS_IF_RELEASE(mDataObject
);
455 mDataObject
= aDataObj
;
456 NS_IF_ADDREF(mDataObject
);
458 if (MOZ_DRAGSERVICE_LOG_ENABLED()) {
459 MOZ_DRAGSERVICE_LOG("nsDragService::SetIDataObject (%p)", mDataObject
);
460 IEnumFORMATETC
* pEnum
= nullptr;
462 S_OK
== mDataObject
->EnumFormatEtc(DATADIR_GET
, &pEnum
)) {
463 MOZ_DRAGSERVICE_LOG(" formats in DataObject:");
466 while (S_OK
== pEnum
->Next(1, &fEtc
, nullptr)) {
468 WinUtils::GetClipboardFormatAsString(fEtc
.cfFormat
, format
);
469 MOZ_DRAGSERVICE_LOG(" FORMAT %s",
470 NS_ConvertUTF16toUTF8(format
).get());
479 //---------------------------------------------------------
480 void nsDragService::SetDroppedLocal() {
481 // Sent from the native drag handler, letting us know
482 // a drop occurred within the application vs. outside of it.
483 mSentLocalDropEvent
= true;
487 //-------------------------------------------------------------------------
489 nsDragService::IsDataFlavorSupported(const char* aDataFlavor
, bool* _retval
) {
490 if (!aDataFlavor
|| !mDataObject
|| !_retval
) {
491 MOZ_DRAGSERVICE_LOG("%s: error", __PRETTY_FUNCTION__
);
492 return NS_ERROR_FAILURE
;
496 auto logging
= MakeScopeExit([&] {
497 MOZ_DRAGSERVICE_LOG("IsDataFlavorSupported: %s is%s found", aDataFlavor
,
498 *_retval
? "" : " not");
504 if (IsCollectionObject(mDataObject
)) {
505 // We know we have one of our special collection objects.
506 format
= nsClipboard::GetFormat(aDataFlavor
);
507 SET_FORMATETC(fe
, format
, 0, DVASPECT_CONTENT
, -1,
508 TYMED_HGLOBAL
| TYMED_FILE
| TYMED_GDI
);
510 // See if any one of the IDataObjects in the collection supports
512 nsDataObjCollection
* dataObjCol
= GetDataObjCollection(mDataObject
);
514 uint32_t cnt
= dataObjCol
->GetNumDataObjects();
515 for (uint32_t i
= 0; i
< cnt
; ++i
) {
516 IDataObject
* dataObj
= dataObjCol
->GetDataObjectAt(i
);
517 if (S_OK
== dataObj
->QueryGetData(&fe
)) {
518 *_retval
= true; // found it!
525 // Ok, so we have a single object. Check to see if has the correct
526 // data type. Since this can come from an outside app, we also
527 // need to see if we need to perform text->unicode conversion if
528 // the client asked for unicode and it wasn't available.
529 format
= nsClipboard::GetFormat(aDataFlavor
);
530 SET_FORMATETC(fe
, format
, 0, DVASPECT_CONTENT
, -1,
531 TYMED_HGLOBAL
| TYMED_FILE
| TYMED_GDI
);
532 if (mDataObject
->QueryGetData(&fe
) == S_OK
) {
533 *_retval
= true; // found it!
537 // We haven't found the exact flavor the client asked for, but
538 // maybe we can still find it from something else that's in the
540 if (strcmp(aDataFlavor
, kTextMime
) == 0) {
541 // If unicode wasn't there, it might exist as CF_TEXT, client asked
542 // for unicode and it wasn't present, check if we
543 // have CF_TEXT. We'll handle the actual data substitution in
545 SET_FORMATETC(fe
, CF_TEXT
, 0, DVASPECT_CONTENT
, -1,
546 TYMED_HGLOBAL
| TYMED_FILE
| TYMED_GDI
);
547 if (mDataObject
->QueryGetData(&fe
) == S_OK
) {
548 *_retval
= true; // found it!
553 if (strcmp(aDataFlavor
, kURLMime
) == 0) {
554 // client asked for a url and it wasn't present, but if we
555 // have a file, then we have a URL to give them (the path, or
556 // the internal URL if an InternetShortcut).
557 format
= nsClipboard::GetFormat(kFileMime
);
558 SET_FORMATETC(fe
, format
, 0, DVASPECT_CONTENT
, -1,
559 TYMED_HGLOBAL
| TYMED_FILE
| TYMED_GDI
);
560 if (mDataObject
->QueryGetData(&fe
) == S_OK
) {
561 *_retval
= true; // found it!
566 if (format
== CF_HDROP
) {
567 // Dragging a link from browsers creates both a URL and a FILE which is a
568 // *.url shortcut in the data object. The file is useful when dropping in
569 // Windows Explorer to create a internet shortcut. But when dropping in the
570 // browser, users do not expect to have this file. So do not try to look up
571 // virtal file if there is a URL in the data object.
572 format
= nsClipboard::GetFormat(kURLMime
);
573 SET_FORMATETC(fe
, format
, 0, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
);
574 if (mDataObject
->QueryGetData(&fe
) == S_OK
) {
578 // If the client wants a file, maybe we find a virtual file.
579 format
= nsClipboard::GetClipboardFileDescriptorFormatW();
580 SET_FORMATETC(fe
, format
, 0, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
);
581 if (mDataObject
->QueryGetData(&fe
) == S_OK
) {
582 *_retval
= true; // found it!
585 // XXX should we fall back to CFSTR_FILEDESCRIPTORA?
593 // IsCollectionObject
595 // Determine if this is a single |IDataObject| or one of our private
596 // collection objects. We know the difference because our collection
597 // object will respond to supporting the private |MULTI_MIME| format.
599 bool nsDragService::IsCollectionObject(IDataObject
* inDataObj
) {
600 bool isCollection
= false;
602 // setup the format object to ask for the MULTI_MIME format. We only
603 // need to do this once
604 static UINT sFormat
= 0;
605 static FORMATETC sFE
;
607 sFormat
= nsClipboard::GetFormat(MULTI_MIME
);
608 SET_FORMATETC(sFE
, sFormat
, 0, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
);
611 // ask the object if it supports it. If yes, we have a collection
613 if (inDataObj
->QueryGetData(&sFE
) == S_OK
) isCollection
= true;
617 } // IsCollectionObject
622 // Override the default to make sure that we release the data object
623 // when the drag ends. It seems that OLE doesn't like to let apps quit
624 // w/out crashing when we're still holding onto their data
627 nsDragService::EndDragSession(bool aDoneDrag
, uint32_t aKeyModifiers
) {
628 // Bug 100180: If we've got mouse events captured, make sure we release it -
629 // that way, if we happen to call EndDragSession before diving into a nested
630 // event loop, we can still respond to mouse events.
631 if (::GetCapture()) {
635 nsBaseDragService::EndDragSession(aDoneDrag
, aKeyModifiers
);
636 NS_IF_RELEASE(mDataObject
);
642 nsDragService::UpdateDragImage(nsINode
* aImage
, int32_t aImageX
,
648 nsBaseDragService::UpdateDragImage(aImage
, aImageX
, aImageY
);
650 IDragSourceHelper
* pdsh
;
651 if (SUCCEEDED(CoCreateInstance(CLSID_DragDropHelper
, nullptr,
652 CLSCTX_INPROC_SERVER
, IID_IDragSourceHelper
,
655 if (CreateDragImage(mSourceNode
, Nothing(), &sdi
)) {
656 nsNativeDragTarget::DragImageChanged();
657 if (FAILED(pdsh
->InitializeFromBitmap(&sdi
, mDataObject
)))
658 DeleteObject(sdi
.hbmpDragImage
);