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 "mozilla/Logging.h"
8 #include "gfxContext.h"
9 #include "nsArrayUtils.h"
10 #include "nsDragService.h"
11 #include "nsArrayUtils.h"
12 #include "nsObjCExceptions.h"
13 #include "nsITransferable.h"
15 #include "nsClipboard.h"
18 #include "nsPrimitiveHelpers.h"
19 #include "nsLinebreakConverter.h"
23 #include "mozilla/PresShell.h"
24 #include "mozilla/dom/Document.h"
25 #include "mozilla/dom/DocumentInlines.h"
26 #include "nsIContent.h"
28 #include "nsCocoaUtils.h"
29 #include "mozilla/gfx/2D.h"
30 #include "gfxPlatform.h"
31 #include "nsDeviceContext.h"
33 using namespace mozilla;
34 using namespace mozilla::gfx;
36 extern mozilla::LazyLogModule sCocoaLog;
38 extern NSPasteboard* globalDragPboard;
39 extern ChildView* gLastDragView;
40 extern NSEvent* gLastDragMouseDownEvent;
41 extern bool gUserCancelledDrag;
43 // This global makes the transferable array available to Cocoa's promised
44 // file destination callback.
45 mozilla::StaticRefPtr<nsIArray> gDraggedTransferables;
47 NSString* const kPublicUrlPboardType = @"public.url";
48 NSString* const kPublicUrlNamePboardType = @"public.url-name";
49 NSString* const kUrlsWithTitlesPboardType = @"WebURLsWithTitlesPboardType";
50 NSString* const kMozWildcardPboardType = @"org.mozilla.MozillaWildcard";
51 NSString* const kMozCustomTypesPboardType = @"org.mozilla.custom-clipdata";
52 NSString* const kMozFileUrlsPboardType = @"org.mozilla.file-urls";
54 nsDragService::nsDragService()
55 : mNativeDragView(nil), mNativeDragEvent(nil), mDragImageChanged(false) {}
57 nsDragService::~nsDragService() {}
59 NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSIntRegion>& aRegion,
60 NSPoint* aDragPoint) {
61 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
63 CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView);
65 LayoutDeviceIntRect dragRect(0, 0, 20, 20);
66 NSImage* image = ConstructDragImage(mSourceNode, aRegion, mScreenPosition, &dragRect);
68 // if no image was returned, just draw a rectangle
70 size.width = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.width, scaleFactor);
71 size.height = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.height, scaleFactor);
72 image = [NSImage imageWithSize:size
74 drawingHandler:^BOOL(NSRect dstRect) {
75 [[NSColor grayColor] set];
76 NSBezierPath* path = [NSBezierPath bezierPathWithRect:dstRect];
77 [path setLineWidth:2.0];
83 LayoutDeviceIntPoint pt(dragRect.x, dragRect.YMost());
84 NSPoint point = nsCocoaUtils::DevPixelsToCocoaPoints(pt, scaleFactor);
85 point.y = nsCocoaUtils::FlippedScreenY(point.y);
87 point = nsCocoaUtils::ConvertPointFromScreen([mNativeDragView window], point);
88 *aDragPoint = [mNativeDragView convertPoint:point fromView:nil];
92 NS_OBJC_END_TRY_BLOCK_RETURN(nil);
95 NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSIntRegion>& aRegion,
96 CSSIntPoint aPoint, LayoutDeviceIntRect* aDragRect) {
97 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
99 CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView);
101 RefPtr<SourceSurface> surface;
103 nsresult rv = DrawDrag(aDOMNode, aRegion, aPoint, aDragRect, &surface, &pc);
104 if (pc && (!aDragRect->width || !aDragRect->height)) {
105 // just use some suitable defaults
106 int32_t size = nsCocoaUtils::CocoaPointsToDevPixels(20, scaleFactor);
107 aDragRect->SetRect(pc->CSSPixelsToDevPixels(aPoint.x), pc->CSSPixelsToDevPixels(aPoint.y), size,
111 if (NS_FAILED(rv) || !surface) return nil;
113 uint32_t width = aDragRect->width;
114 uint32_t height = aDragRect->height;
116 RefPtr<DataSourceSurface> dataSurface =
117 Factory::CreateDataSourceSurface(IntSize(width, height), SurfaceFormat::B8G8R8A8);
118 DataSourceSurface::MappedSurface map;
119 if (!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) {
123 RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(
124 BackendType::CAIRO, map.mData, dataSurface->GetSize(), map.mStride, dataSurface->GetFormat());
126 dataSurface->Unmap();
130 dt->FillRect(gfx::Rect(0, 0, width, height), SurfacePattern(surface, ExtendMode::CLAMP),
131 DrawOptions(1.0f, CompositionOp::OP_SOURCE));
133 NSBitmapImageRep* imageRep =
134 [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
141 colorSpaceName:NSDeviceRGBColorSpace
142 bytesPerRow:width * 4
145 uint8_t* dest = [imageRep bitmapData];
146 for (uint32_t i = 0; i < height; ++i) {
147 uint8_t* src = map.mData + i * map.mStride;
148 for (uint32_t j = 0; j < width; ++j) {
149 // Reduce transparency overall by multipying by a factor. Remember, Alpha
150 // is premultipled here. Also, Quartz likes RGBA, so do that translation as well.
152 dest[0] = uint8_t(src[1] * DRAG_TRANSLUCENCY);
153 dest[1] = uint8_t(src[2] * DRAG_TRANSLUCENCY);
154 dest[2] = uint8_t(src[3] * DRAG_TRANSLUCENCY);
155 dest[3] = uint8_t(src[0] * DRAG_TRANSLUCENCY);
157 dest[0] = uint8_t(src[2] * DRAG_TRANSLUCENCY);
158 dest[1] = uint8_t(src[1] * DRAG_TRANSLUCENCY);
159 dest[2] = uint8_t(src[0] * DRAG_TRANSLUCENCY);
160 dest[3] = uint8_t(src[3] * DRAG_TRANSLUCENCY);
166 dataSurface->Unmap();
169 [[NSImage alloc] initWithSize:NSMakeSize(width / scaleFactor, height / scaleFactor)];
170 [image addRepresentation:imageRep];
173 return [image autorelease];
175 NS_OBJC_END_TRY_BLOCK_RETURN(nil);
178 bool nsDragService::IsValidType(NSString* availableType, bool allowFileURL) {
179 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
181 // Prevent exposing fileURL for non-fileURL type.
182 // We need URL provided by dropped webloc file, but don't need file's URL.
183 // kUTTypeFileURL is returned by [NSPasteboard availableTypeFromArray:] for
184 // kPublicUrlPboardType, since it conforms to kPublicUrlPboardType.
187 [availableType isEqualToString:[UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL]]) {
193 NS_OBJC_END_TRY_BLOCK_RETURN(false);
196 NSString* nsDragService::GetStringForType(NSPasteboardItem* item, const NSString* type,
198 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
200 NSString* availableType = [item availableTypeFromArray:[NSArray arrayWithObjects:(id)type, nil]];
201 if (availableType && IsValidType(availableType, allowFileURL)) {
202 return [item stringForType:(id)availableType];
207 NS_OBJC_END_TRY_BLOCK_RETURN(nil);
210 NSString* nsDragService::GetTitleForURL(NSPasteboardItem* item) {
211 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
214 GetStringForType(item, [UTIHelper stringFromPboardType:kPublicUrlNamePboardType]);
219 NSString* filePath = GetFilePath(item);
221 return [filePath lastPathComponent];
226 NS_OBJC_END_TRY_BLOCK_RETURN(nil);
229 NSString* nsDragService::GetFilePath(NSPasteboardItem* item) {
230 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
232 NSString* urlString =
233 GetStringForType(item, [UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL], true);
235 NSURL* url = [NSURL URLWithString:urlString];
243 NS_OBJC_END_TRY_BLOCK_RETURN(nil);
246 nsresult nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
247 const Maybe<CSSIntRegion>& aRegion,
248 uint32_t aActionType) {
249 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
252 MOZ_RELEASE_ASSERT(NS_IsMainThread());
255 if (!gLastDragView) {
256 // gLastDragView is non-null between -[ChildView mouseDown:] and -[ChildView mouseUp:].
257 // If we get here with gLastDragView being null, that means that the mouse button has already
258 // been released. In that case we need to abort the drag because the OS won't know where to drop
259 // whatever's being dragged, and we might end up with a stuck drag & drop session.
260 return NS_ERROR_FAILURE;
263 mDataItems = aTransferableArray;
265 // Save the transferables away in case a promised file callback is invoked.
266 gDraggedTransferables = aTransferableArray;
268 // We need to retain the view and the event during the drag in case either
270 mNativeDragView = [gLastDragView retain];
271 mNativeDragEvent = [gLastDragMouseDownEvent retain];
273 gUserCancelledDrag = false;
275 NSPasteboardItem* pbItem = [NSPasteboardItem new];
276 NSMutableArray* types = [NSMutableArray arrayWithCapacity:5];
278 if (gDraggedTransferables) {
280 gDraggedTransferables->GetLength(&count);
282 for (uint32_t j = 0; j < count; j++) {
283 nsCOMPtr<nsITransferable> currentTransferable = do_QueryElementAt(aTransferableArray, j);
284 if (!currentTransferable) {
285 return NS_ERROR_FAILURE;
288 // Transform the transferable to an NSDictionary
289 NSDictionary* pasteboardOutputDict =
290 nsClipboard::PasteboardDictFromTransferable(currentTransferable);
291 if (!pasteboardOutputDict) {
292 return NS_ERROR_FAILURE;
295 // write everything out to the general pasteboard
296 [types addObjectsFromArray:[pasteboardOutputDict allKeys]];
297 // Gecko is initiating this drag so we always want its own views to
298 // consider it. Add our wildcard type to the pasteboard to accomplish
300 [types addObject:[UTIHelper stringFromPboardType:kMozWildcardPboardType]];
303 [pbItem setDataProvider:mNativeDragView forTypes:types];
305 NSPoint draggingPoint;
306 NSImage* image = ConstructDragImage(mSourceNode, aRegion, &draggingPoint);
308 NSRect localDragRect = image.alignmentRect;
309 localDragRect.origin.x = draggingPoint.x;
310 localDragRect.origin.y = draggingPoint.y - localDragRect.size.height;
312 NSDraggingItem* dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter:pbItem];
314 [dragItem setDraggingFrame:localDragRect contents:image];
316 nsBaseDragService::StartDragSession();
317 nsBaseDragService::OpenDragPopup();
319 NSDraggingSession* draggingSession = [mNativeDragView
320 beginDraggingSessionWithItems:[NSArray arrayWithObject:[dragItem autorelease]]
321 event:mNativeDragEvent
322 source:mNativeDragView];
323 draggingSession.animatesToStartingPositionsOnCancelOrFail = YES;
327 NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
331 nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex) {
332 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
334 if (!aTransferable) return NS_ERROR_FAILURE;
336 // get flavor list that includes all acceptable flavors (including ones obtained through
338 nsTArray<nsCString> flavors;
339 nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
340 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
342 // if this drag originated within Mozilla we should just use the cached data from
343 // when the drag started if possible
345 nsCOMPtr<nsITransferable> currentTransferable = do_QueryElementAt(mDataItems, aItemIndex);
346 if (currentTransferable) {
347 for (uint32_t i = 0; i < flavors.Length(); i++) {
348 nsCString& flavorStr = flavors[i];
350 nsCOMPtr<nsISupports> dataSupports;
351 rv = currentTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(dataSupports));
352 if (NS_SUCCEEDED(rv)) {
353 aTransferable->SetTransferData(flavorStr.get(), dataSupports);
354 return NS_OK; // maybe try to fill in more types? Is there a point?
360 // now check the actual clipboard for data
361 for (uint32_t i = 0; i < flavors.Length(); i++) {
362 nsCString& flavorStr = flavors[i];
364 MOZ_LOG(sCocoaLog, LogLevel::Info,
365 ("nsDragService::GetData: looking for clipboard data of type %s\n", flavorStr.get()));
367 NSArray* droppedItems = [globalDragPboard pasteboardItems];
372 uint32_t itemCount = [droppedItems count];
373 if (aItemIndex >= itemCount) {
377 NSPasteboardItem* item = [droppedItems objectAtIndex:aItemIndex];
382 if (flavorStr.EqualsLiteral(kFileMime)) {
383 NSString* filePath = GetFilePath(item);
384 if (!filePath) continue;
386 unsigned int stringLength = [filePath length];
387 unsigned int dataLength = (stringLength + 1) * sizeof(char16_t); // in bytes
388 char16_t* clipboardDataPtr = (char16_t*)malloc(dataLength);
389 if (!clipboardDataPtr) return NS_ERROR_OUT_OF_MEMORY;
390 [filePath getCharacters:reinterpret_cast<unichar*>(clipboardDataPtr)];
391 clipboardDataPtr[stringLength] = 0; // null terminate
393 nsCOMPtr<nsIFile> file;
394 rv = NS_NewLocalFile(nsDependentString(clipboardDataPtr), true, getter_AddRefs(file));
395 free(clipboardDataPtr);
396 if (NS_FAILED(rv)) continue;
398 aTransferable->SetTransferData(flavorStr.get(), file);
401 } else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
402 NSString* availableType =
403 [item availableTypeFromArray:[NSArray arrayWithObject:kMozCustomTypesPboardType]];
404 if (!availableType || !IsValidType(availableType, false)) {
407 NSData* pasteboardData = [item dataForType:availableType];
408 if (!pasteboardData) {
412 unsigned int dataLength = [pasteboardData length];
413 void* clipboardDataPtr = malloc(dataLength);
414 if (!clipboardDataPtr) {
415 return NS_ERROR_OUT_OF_MEMORY;
417 [pasteboardData getBytes:clipboardDataPtr length:dataLength];
419 nsCOMPtr<nsISupports> genericDataWrapper;
420 nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtr, dataLength,
421 getter_AddRefs(genericDataWrapper));
423 aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper);
424 free(clipboardDataPtr);
428 NSString* pString = nil;
429 if (flavorStr.EqualsLiteral(kUnicodeMime)) {
430 pString = GetStringForType(item, [UTIHelper stringFromPboardType:NSPasteboardTypeString]);
431 } else if (flavorStr.EqualsLiteral(kHTMLMime)) {
432 pString = GetStringForType(item, [UTIHelper stringFromPboardType:NSPasteboardTypeHTML]);
433 } else if (flavorStr.EqualsLiteral(kURLMime)) {
434 pString = GetStringForType(item, [UTIHelper stringFromPboardType:kPublicUrlPboardType]);
436 NSString* title = GetTitleForURL(item);
440 pString = [NSString stringWithFormat:@"%@\n%@", pString, title];
442 } else if (flavorStr.EqualsLiteral(kURLDataMime)) {
443 pString = GetStringForType(item, [UTIHelper stringFromPboardType:kPublicUrlPboardType]);
444 } else if (flavorStr.EqualsLiteral(kURLDescriptionMime)) {
445 pString = GetTitleForURL(item);
446 } else if (flavorStr.EqualsLiteral(kRTFMime)) {
447 pString = GetStringForType(item, [UTIHelper stringFromPboardType:NSPasteboardTypeRTF]);
451 if (flavorStr.EqualsLiteral(kRTFMime)) {
452 stringData = [pString dataUsingEncoding:NSASCIIStringEncoding];
454 stringData = [pString dataUsingEncoding:NSUnicodeStringEncoding];
456 unsigned int dataLength = [stringData length];
457 void* clipboardDataPtr = malloc(dataLength);
458 if (!clipboardDataPtr) return NS_ERROR_OUT_OF_MEMORY;
459 [stringData getBytes:clipboardDataPtr length:dataLength];
461 // The DOM only wants LF, so convert from MacOS line endings to DOM line endings.
462 int32_t signedDataLength = dataLength;
463 nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(flavorStr, &clipboardDataPtr,
465 dataLength = signedDataLength;
467 // skip BOM (Byte Order Mark to distinguish little or big endian)
468 char16_t* clipboardDataPtrNoBOM = (char16_t*)clipboardDataPtr;
469 if ((dataLength > 2) &&
470 ((clipboardDataPtrNoBOM[0] == 0xFEFF) || (clipboardDataPtrNoBOM[0] == 0xFFFE))) {
471 dataLength -= sizeof(char16_t);
472 clipboardDataPtrNoBOM += 1;
475 nsCOMPtr<nsISupports> genericDataWrapper;
476 nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtrNoBOM, dataLength,
477 getter_AddRefs(genericDataWrapper));
478 aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper);
479 free(clipboardDataPtr);
483 // We have never supported this on Mac OS X, we should someday. Normally dragging images
484 // in is accomplished with a file path drag instead of the image data itself.
486 if (flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kJPEGImageMime) ||
487 flavorStr.EqualsLiteral(kJPGImageMime) || flavorStr.EqualsLiteral(kGIFImageMime)) {
494 NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
498 nsDragService::IsDataFlavorSupported(const char* aDataFlavor, bool* _retval) {
499 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
503 if (!globalDragPboard) return NS_ERROR_FAILURE;
505 nsDependentCString dataFlavor(aDataFlavor);
507 // first see if we have data for this in our cached transferable
509 uint32_t dataItemsCount;
510 mDataItems->GetLength(&dataItemsCount);
511 for (unsigned int i = 0; i < dataItemsCount; i++) {
512 nsCOMPtr<nsITransferable> currentTransferable = do_QueryElementAt(mDataItems, i);
513 if (!currentTransferable) continue;
515 nsTArray<nsCString> flavors;
516 nsresult rv = currentTransferable->FlavorsTransferableCanImport(flavors);
517 if (NS_FAILED(rv)) continue;
519 for (uint32_t j = 0; j < flavors.Length(); j++) {
520 if (dataFlavor.Equals(flavors[j])) {
528 const NSString* type = nil;
529 bool allowFileURL = false;
530 if (dataFlavor.EqualsLiteral(kFileMime)) {
531 type = [UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL];
533 } else if (dataFlavor.EqualsLiteral(kUnicodeMime)) {
534 type = [UTIHelper stringFromPboardType:NSPasteboardTypeString];
535 } else if (dataFlavor.EqualsLiteral(kHTMLMime)) {
536 type = [UTIHelper stringFromPboardType:NSPasteboardTypeHTML];
537 } else if (dataFlavor.EqualsLiteral(kURLMime) || dataFlavor.EqualsLiteral(kURLDataMime)) {
538 type = [UTIHelper stringFromPboardType:kPublicUrlPboardType];
539 } else if (dataFlavor.EqualsLiteral(kURLDescriptionMime)) {
540 type = [UTIHelper stringFromPboardType:kPublicUrlNamePboardType];
541 } else if (dataFlavor.EqualsLiteral(kRTFMime)) {
542 type = [UTIHelper stringFromPboardType:NSPasteboardTypeRTF];
543 } else if (dataFlavor.EqualsLiteral(kCustomTypesMime)) {
544 type = [UTIHelper stringFromPboardType:kMozCustomTypesPboardType];
547 NSString* availableType =
548 [globalDragPboard availableTypeFromArray:[NSArray arrayWithObjects:(id)type, nil]];
549 if (availableType && IsValidType(availableType, allowFileURL)) {
555 NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
559 nsDragService::GetNumDropItems(uint32_t* aNumItems) {
560 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
564 // first check to see if we have a number of items cached
566 mDataItems->GetLength(aNumItems);
570 NSArray* droppedItems = [globalDragPboard pasteboardItems];
572 *aNumItems = [droppedItems count];
577 NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
581 nsDragService::UpdateDragImage(nsINode* aImage, int32_t aImageX, int32_t aImageY) {
582 nsBaseDragService::UpdateDragImage(aImage, aImageX, aImageY);
583 mDragImageChanged = true;
587 void nsDragService::DragMovedWithView(NSDraggingSession* aSession, NSPoint aPoint) {
588 aPoint.y = nsCocoaUtils::FlippedScreenY(aPoint.y);
590 // XXX It feels like we should be using the backing scale factor at aPoint
591 // rather than the initial drag view, but I've seen no ill effects of this.
592 CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView);
593 LayoutDeviceIntPoint devPoint = nsCocoaUtils::CocoaPointsToDevPixels(aPoint, scaleFactor);
595 // If the image has changed, call enumerateDraggingItemsWithOptions to get
596 // the item being dragged and update its image.
597 if (mDragImageChanged && mNativeDragView) {
598 mDragImageChanged = false;
600 nsPresContext* pc = nullptr;
601 nsCOMPtr<nsIContent> content = do_QueryInterface(mImage);
603 pc = content->OwnerDoc()->GetPresContext();
607 void (^changeImageBlock)(NSDraggingItem*, NSInteger, BOOL*) =
608 ^(NSDraggingItem* draggingItem, NSInteger idx, BOOL* stop) {
609 // We never add more than one item right now, but check just in case.
615 LayoutDevicePixel::ToAppUnits(devPoint, pc->DeviceContext()->AppUnitsPerDevPixel());
616 CSSIntPoint screenPoint = CSSIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
617 nsPresContext::AppUnitsToIntCSSPixels(pt.y));
619 // Create a new image; if one isn't returned don't change the current one.
620 LayoutDeviceIntRect newRect;
621 NSImage* image = ConstructDragImage(mSourceNode, Nothing(), screenPoint, &newRect);
623 NSRect draggingRect = nsCocoaUtils::GeckoRectToCocoaRectDevPix(newRect, scaleFactor);
624 [draggingItem setDraggingFrame:draggingRect contents:image];
628 [aSession enumerateDraggingItemsWithOptions:NSDraggingItemEnumerationConcurrent
630 classes:[NSArray arrayWithObject:[NSPasteboardItem class]]
632 usingBlock:changeImageBlock];
636 DragMoved(devPoint.x, devPoint.y);
640 nsDragService::EndDragSession(bool aDoneDrag, uint32_t aKeyModifiers) {
641 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
643 if (mNativeDragView) {
644 [mNativeDragView release];
645 mNativeDragView = nil;
647 if (mNativeDragEvent) {
648 [mNativeDragEvent release];
649 mNativeDragEvent = nil;
652 mUserCancelled = gUserCancelledDrag;
654 nsresult rv = nsBaseDragService::EndDragSession(aDoneDrag, aKeyModifiers);
655 mDataItems = nullptr;
658 NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);