1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/cocoa/nsDragService.mm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,572 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifdef MOZ_LOGGING 1.10 +#define FORCE_PR_LOG 1.11 +#endif 1.12 +#include "prlog.h" 1.13 + 1.14 +#include "nsDragService.h" 1.15 +#include "nsObjCExceptions.h" 1.16 +#include "nsITransferable.h" 1.17 +#include "nsString.h" 1.18 +#include "nsClipboard.h" 1.19 +#include "nsXPCOM.h" 1.20 +#include "nsISupportsPrimitives.h" 1.21 +#include "nsCOMPtr.h" 1.22 +#include "nsPrimitiveHelpers.h" 1.23 +#include "nsLinebreakConverter.h" 1.24 +#include "nsIMacUtils.h" 1.25 +#include "nsIDOMNode.h" 1.26 +#include "nsRect.h" 1.27 +#include "nsPoint.h" 1.28 +#include "nsIIOService.h" 1.29 +#include "nsNetUtil.h" 1.30 +#include "nsIDocument.h" 1.31 +#include "nsIContent.h" 1.32 +#include "nsView.h" 1.33 +#include "gfxContext.h" 1.34 +#include "nsCocoaUtils.h" 1.35 +#include "mozilla/gfx/2D.h" 1.36 +#include "gfxPlatform.h" 1.37 + 1.38 +using namespace mozilla; 1.39 +using namespace mozilla::gfx; 1.40 + 1.41 +#ifdef PR_LOGGING 1.42 +extern PRLogModuleInfo* sCocoaLog; 1.43 +#endif 1.44 + 1.45 +extern void EnsureLogInitialized(); 1.46 + 1.47 +extern NSPasteboard* globalDragPboard; 1.48 +extern NSView* gLastDragView; 1.49 +extern NSEvent* gLastDragMouseDownEvent; 1.50 +extern bool gUserCancelledDrag; 1.51 + 1.52 +// This global makes the transferable array available to Cocoa's promised 1.53 +// file destination callback. 1.54 +nsISupportsArray *gDraggedTransferables = nullptr; 1.55 + 1.56 +NSString* const kWildcardPboardType = @"MozillaWildcard"; 1.57 +NSString* const kCorePboardType_url = @"CorePasteboardFlavorType 0x75726C20"; // 'url ' url 1.58 +NSString* const kCorePboardType_urld = @"CorePasteboardFlavorType 0x75726C64"; // 'urld' desc 1.59 +NSString* const kCorePboardType_urln = @"CorePasteboardFlavorType 0x75726C6E"; // 'urln' title 1.60 + 1.61 +nsDragService::nsDragService() 1.62 +{ 1.63 + mNativeDragView = nil; 1.64 + mNativeDragEvent = nil; 1.65 + 1.66 + EnsureLogInitialized(); 1.67 +} 1.68 + 1.69 +nsDragService::~nsDragService() 1.70 +{ 1.71 +} 1.72 + 1.73 +static nsresult SetUpDragClipboard(nsISupportsArray* aTransferableArray) 1.74 +{ 1.75 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.76 + 1.77 + if (!aTransferableArray) 1.78 + return NS_ERROR_FAILURE; 1.79 + 1.80 + uint32_t count = 0; 1.81 + aTransferableArray->Count(&count); 1.82 + 1.83 + NSPasteboard* dragPBoard = [NSPasteboard pasteboardWithName:NSDragPboard]; 1.84 + 1.85 + for (uint32_t i = 0; i < count; i++) { 1.86 + nsCOMPtr<nsISupports> currentTransferableSupports; 1.87 + aTransferableArray->GetElementAt(i, getter_AddRefs(currentTransferableSupports)); 1.88 + if (!currentTransferableSupports) 1.89 + return NS_ERROR_FAILURE; 1.90 + 1.91 + nsCOMPtr<nsITransferable> currentTransferable(do_QueryInterface(currentTransferableSupports)); 1.92 + if (!currentTransferable) 1.93 + return NS_ERROR_FAILURE; 1.94 + 1.95 + // Transform the transferable to an NSDictionary 1.96 + NSDictionary* pasteboardOutputDict = nsClipboard::PasteboardDictFromTransferable(currentTransferable); 1.97 + if (!pasteboardOutputDict) 1.98 + return NS_ERROR_FAILURE; 1.99 + 1.100 + // write everything out to the general pasteboard 1.101 + unsigned int typeCount = [pasteboardOutputDict count]; 1.102 + NSMutableArray* types = [NSMutableArray arrayWithCapacity:typeCount + 1]; 1.103 + [types addObjectsFromArray:[pasteboardOutputDict allKeys]]; 1.104 + // Gecko is initiating this drag so we always want its own views to consider 1.105 + // it. Add our wildcard type to the pasteboard to accomplish this. 1.106 + [types addObject:kWildcardPboardType]; // we don't increase the count for the loop below on purpose 1.107 + [dragPBoard declareTypes:types owner:nil]; 1.108 + for (unsigned int i = 0; i < typeCount; i++) { 1.109 + NSString* currentKey = [types objectAtIndex:i]; 1.110 + id currentValue = [pasteboardOutputDict valueForKey:currentKey]; 1.111 + if (currentKey == NSStringPboardType || 1.112 + currentKey == kCorePboardType_url || 1.113 + currentKey == kCorePboardType_urld || 1.114 + currentKey == kCorePboardType_urln) { 1.115 + [dragPBoard setString:currentValue forType:currentKey]; 1.116 + } 1.117 + else if (currentKey == NSHTMLPboardType) { 1.118 + [dragPBoard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue)) 1.119 + forType:currentKey]; 1.120 + } 1.121 + else if (currentKey == NSTIFFPboardType) { 1.122 + [dragPBoard setData:currentValue forType:currentKey]; 1.123 + } 1.124 + else if (currentKey == NSFilesPromisePboardType || 1.125 + currentKey == NSFilenamesPboardType) { 1.126 + [dragPBoard setPropertyList:currentValue forType:currentKey]; 1.127 + } 1.128 + } 1.129 + } 1.130 + 1.131 + return NS_OK; 1.132 + 1.133 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.134 +} 1.135 + 1.136 +NSImage* 1.137 +nsDragService::ConstructDragImage(nsIDOMNode* aDOMNode, 1.138 + nsIntRect* aDragRect, 1.139 + nsIScriptableRegion* aRegion) 1.140 +{ 1.141 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; 1.142 + 1.143 + NSPoint screenPoint = 1.144 + [[gLastDragView window] convertBaseToScreen: 1.145 + [gLastDragMouseDownEvent locationInWindow]]; 1.146 + // Y coordinates are bottom to top, so reverse this 1.147 + screenPoint.y = nsCocoaUtils::FlippedScreenY(screenPoint.y); 1.148 + 1.149 + CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(gLastDragView); 1.150 + 1.151 + RefPtr<SourceSurface> surface; 1.152 + nsPresContext* pc; 1.153 + nsresult rv = DrawDrag(aDOMNode, aRegion, 1.154 + NSToIntRound(screenPoint.x), 1.155 + NSToIntRound(screenPoint.y), 1.156 + aDragRect, &surface, &pc); 1.157 + if (!aDragRect->width || !aDragRect->height) { 1.158 + // just use some suitable defaults 1.159 + int32_t size = nsCocoaUtils::CocoaPointsToDevPixels(20, scaleFactor); 1.160 + aDragRect->SetRect(nsCocoaUtils::CocoaPointsToDevPixels(screenPoint.x, scaleFactor), 1.161 + nsCocoaUtils::CocoaPointsToDevPixels(screenPoint.y, scaleFactor), 1.162 + size, size); 1.163 + } 1.164 + 1.165 + if (NS_FAILED(rv) || !surface) 1.166 + return nil; 1.167 + 1.168 + uint32_t width = aDragRect->width; 1.169 + uint32_t height = aDragRect->height; 1.170 + 1.171 + nsRefPtr<gfxImageSurface> imgSurface = new gfxImageSurface( 1.172 + gfxIntSize(width, height), gfxImageFormat::ARGB32); 1.173 + if (!imgSurface) 1.174 + return nil; 1.175 + 1.176 + RefPtr<DrawTarget> dt = 1.177 + gfxPlatform::GetPlatform()-> 1.178 + CreateDrawTargetForSurface(imgSurface, IntSize(width, height)); 1.179 + if (!dt) 1.180 + return nil; 1.181 + 1.182 + dt->FillRect(gfx::Rect(0, 0, width, height), 1.183 + SurfacePattern(surface, ExtendMode::CLAMP), 1.184 + DrawOptions(1.0f, CompositionOp::OP_SOURCE)); 1.185 + 1.186 + uint32_t* imageData = (uint32_t*)imgSurface->Data(); 1.187 + int32_t stride = imgSurface->Stride(); 1.188 + 1.189 + NSBitmapImageRep* imageRep = 1.190 + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL 1.191 + pixelsWide:width 1.192 + pixelsHigh:height 1.193 + bitsPerSample:8 1.194 + samplesPerPixel:4 1.195 + hasAlpha:YES 1.196 + isPlanar:NO 1.197 + colorSpaceName:NSDeviceRGBColorSpace 1.198 + bytesPerRow:width * 4 1.199 + bitsPerPixel:32]; 1.200 + 1.201 + uint8_t* dest = [imageRep bitmapData]; 1.202 + for (uint32_t i = 0; i < height; ++i) { 1.203 + uint8_t* src = (uint8_t *)imageData + i * stride; 1.204 + for (uint32_t j = 0; j < width; ++j) { 1.205 + // Reduce transparency overall by multipying by a factor. Remember, Alpha 1.206 + // is premultipled here. Also, Quartz likes RGBA, so do that translation as well. 1.207 +#ifdef IS_BIG_ENDIAN 1.208 + dest[0] = uint8_t(src[1] * DRAG_TRANSLUCENCY); 1.209 + dest[1] = uint8_t(src[2] * DRAG_TRANSLUCENCY); 1.210 + dest[2] = uint8_t(src[3] * DRAG_TRANSLUCENCY); 1.211 + dest[3] = uint8_t(src[0] * DRAG_TRANSLUCENCY); 1.212 +#else 1.213 + dest[0] = uint8_t(src[2] * DRAG_TRANSLUCENCY); 1.214 + dest[1] = uint8_t(src[1] * DRAG_TRANSLUCENCY); 1.215 + dest[2] = uint8_t(src[0] * DRAG_TRANSLUCENCY); 1.216 + dest[3] = uint8_t(src[3] * DRAG_TRANSLUCENCY); 1.217 +#endif 1.218 + src += 4; 1.219 + dest += 4; 1.220 + } 1.221 + } 1.222 + 1.223 + NSImage* image = 1.224 + [[NSImage alloc] initWithSize:NSMakeSize(width / scaleFactor, 1.225 + height / scaleFactor)]; 1.226 + [image addRepresentation:imageRep]; 1.227 + [imageRep release]; 1.228 + 1.229 + return [image autorelease]; 1.230 + 1.231 + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; 1.232 +} 1.233 + 1.234 +// We can only invoke NSView's 'dragImage:at:offset:event:pasteboard:source:slideBack:' from 1.235 +// within NSView's 'mouseDown:' or 'mouseDragged:'. Luckily 'mouseDragged' is always on the 1.236 +// stack when InvokeDragSession gets called. 1.237 +NS_IMETHODIMP 1.238 +nsDragService::InvokeDragSession(nsIDOMNode* aDOMNode, nsISupportsArray* aTransferableArray, 1.239 + nsIScriptableRegion* aDragRgn, uint32_t aActionType) 1.240 +{ 1.241 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.242 + 1.243 + nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode, 1.244 + aTransferableArray, 1.245 + aDragRgn, aActionType); 1.246 + NS_ENSURE_SUCCESS(rv, rv); 1.247 + 1.248 + mDataItems = aTransferableArray; 1.249 + 1.250 + // put data on the clipboard 1.251 + if (NS_FAILED(SetUpDragClipboard(aTransferableArray))) 1.252 + return NS_ERROR_FAILURE; 1.253 + 1.254 + nsIntRect dragRect(0, 0, 20, 20); 1.255 + NSImage* image = ConstructDragImage(aDOMNode, &dragRect, aDragRgn); 1.256 + if (!image) { 1.257 + // if no image was returned, just draw a rectangle 1.258 + NSSize size; 1.259 + size.width = dragRect.width; 1.260 + size.height = dragRect.height; 1.261 + image = [[NSImage alloc] initWithSize:size]; 1.262 + [image lockFocus]; 1.263 + [[NSColor grayColor] set]; 1.264 + NSBezierPath* path = [NSBezierPath bezierPath]; 1.265 + [path setLineWidth:2.0]; 1.266 + [path moveToPoint:NSMakePoint(0, 0)]; 1.267 + [path lineToPoint:NSMakePoint(0, size.height)]; 1.268 + [path lineToPoint:NSMakePoint(size.width, size.height)]; 1.269 + [path lineToPoint:NSMakePoint(size.width, 0)]; 1.270 + [path lineToPoint:NSMakePoint(0, 0)]; 1.271 + [path stroke]; 1.272 + [image unlockFocus]; 1.273 + } 1.274 + 1.275 + nsIntPoint pt(dragRect.x, dragRect.YMost()); 1.276 + CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(gLastDragView); 1.277 + NSPoint point = nsCocoaUtils::DevPixelsToCocoaPoints(pt, scaleFactor); 1.278 + point.y = nsCocoaUtils::FlippedScreenY(point.y); 1.279 + 1.280 + point = [[gLastDragView window] convertScreenToBase: point]; 1.281 + NSPoint localPoint = [gLastDragView convertPoint:point fromView:nil]; 1.282 + 1.283 + // Save the transferables away in case a promised file callback is invoked. 1.284 + gDraggedTransferables = aTransferableArray; 1.285 + 1.286 + nsBaseDragService::StartDragSession(); 1.287 + nsBaseDragService::OpenDragPopup(); 1.288 + 1.289 + // We need to retain the view and the event during the drag in case either gets destroyed. 1.290 + mNativeDragView = [gLastDragView retain]; 1.291 + mNativeDragEvent = [gLastDragMouseDownEvent retain]; 1.292 + 1.293 + gUserCancelledDrag = false; 1.294 + [mNativeDragView dragImage:image 1.295 + at:localPoint 1.296 + offset:NSZeroSize 1.297 + event:mNativeDragEvent 1.298 + pasteboard:[NSPasteboard pasteboardWithName:NSDragPboard] 1.299 + source:mNativeDragView 1.300 + slideBack:YES]; 1.301 + gUserCancelledDrag = false; 1.302 + 1.303 + if (mDoingDrag) 1.304 + nsBaseDragService::EndDragSession(false); 1.305 + 1.306 + return NS_OK; 1.307 + 1.308 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.309 +} 1.310 + 1.311 +NS_IMETHODIMP 1.312 +nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex) 1.313 +{ 1.314 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.315 + 1.316 + if (!aTransferable) 1.317 + return NS_ERROR_FAILURE; 1.318 + 1.319 + // get flavor list that includes all acceptable flavors (including ones obtained through conversion) 1.320 + nsCOMPtr<nsISupportsArray> flavorList; 1.321 + nsresult rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList)); 1.322 + if (NS_FAILED(rv)) 1.323 + return NS_ERROR_FAILURE; 1.324 + 1.325 + uint32_t acceptableFlavorCount; 1.326 + flavorList->Count(&acceptableFlavorCount); 1.327 + 1.328 + // if this drag originated within Mozilla we should just use the cached data from 1.329 + // when the drag started if possible 1.330 + if (mDataItems) { 1.331 + nsCOMPtr<nsISupports> currentTransferableSupports; 1.332 + mDataItems->GetElementAt(aItemIndex, getter_AddRefs(currentTransferableSupports)); 1.333 + if (currentTransferableSupports) { 1.334 + nsCOMPtr<nsITransferable> currentTransferable(do_QueryInterface(currentTransferableSupports)); 1.335 + if (currentTransferable) { 1.336 + for (uint32_t i = 0; i < acceptableFlavorCount; i++) { 1.337 + nsCOMPtr<nsISupports> genericFlavor; 1.338 + flavorList->GetElementAt(i, getter_AddRefs(genericFlavor)); 1.339 + nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor)); 1.340 + if (!currentFlavor) 1.341 + continue; 1.342 + nsXPIDLCString flavorStr; 1.343 + currentFlavor->ToString(getter_Copies(flavorStr)); 1.344 + 1.345 + nsCOMPtr<nsISupports> dataSupports; 1.346 + uint32_t dataSize = 0; 1.347 + rv = currentTransferable->GetTransferData(flavorStr, getter_AddRefs(dataSupports), &dataSize); 1.348 + if (NS_SUCCEEDED(rv)) { 1.349 + aTransferable->SetTransferData(flavorStr, dataSupports, dataSize); 1.350 + return NS_OK; // maybe try to fill in more types? Is there a point? 1.351 + } 1.352 + } 1.353 + } 1.354 + } 1.355 + } 1.356 + 1.357 + // now check the actual clipboard for data 1.358 + for (uint32_t i = 0; i < acceptableFlavorCount; i++) { 1.359 + nsCOMPtr<nsISupports> genericFlavor; 1.360 + flavorList->GetElementAt(i, getter_AddRefs(genericFlavor)); 1.361 + nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor)); 1.362 + 1.363 + if (!currentFlavor) 1.364 + continue; 1.365 + 1.366 + nsXPIDLCString flavorStr; 1.367 + currentFlavor->ToString(getter_Copies(flavorStr)); 1.368 + 1.369 + PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("nsDragService::GetData: looking for clipboard data of type %s\n", flavorStr.get())); 1.370 + 1.371 + if (flavorStr.EqualsLiteral(kFileMime)) { 1.372 + NSArray* pFiles = [globalDragPboard propertyListForType:NSFilenamesPboardType]; 1.373 + if (!pFiles || [pFiles count] < (aItemIndex + 1)) 1.374 + continue; 1.375 + 1.376 + NSString* filePath = [pFiles objectAtIndex:aItemIndex]; 1.377 + if (!filePath) 1.378 + continue; 1.379 + 1.380 + unsigned int stringLength = [filePath length]; 1.381 + unsigned int dataLength = (stringLength + 1) * sizeof(char16_t); // in bytes 1.382 + char16_t* clipboardDataPtr = (char16_t*)malloc(dataLength); 1.383 + if (!clipboardDataPtr) 1.384 + return NS_ERROR_OUT_OF_MEMORY; 1.385 + [filePath getCharacters:reinterpret_cast<unichar*>(clipboardDataPtr)]; 1.386 + clipboardDataPtr[stringLength] = 0; // null terminate 1.387 + 1.388 + nsCOMPtr<nsIFile> file; 1.389 + nsresult rv = NS_NewLocalFile(nsDependentString(clipboardDataPtr), true, getter_AddRefs(file)); 1.390 + free(clipboardDataPtr); 1.391 + if (NS_FAILED(rv)) 1.392 + continue; 1.393 + 1.394 + aTransferable->SetTransferData(flavorStr, file, dataLength); 1.395 + 1.396 + break; 1.397 + } 1.398 + 1.399 + NSString *pboardType = NSStringPboardType; 1.400 + 1.401 + if (nsClipboard::IsStringType(flavorStr, &pboardType) || 1.402 + flavorStr.EqualsLiteral(kURLMime) || 1.403 + flavorStr.EqualsLiteral(kURLDataMime) || 1.404 + flavorStr.EqualsLiteral(kURLDescriptionMime)) { 1.405 + NSString* pString = [globalDragPboard stringForType:pboardType]; 1.406 + if (!pString) 1.407 + continue; 1.408 + 1.409 + NSData* stringData = [pString dataUsingEncoding:NSUnicodeStringEncoding]; 1.410 + unsigned int dataLength = [stringData length]; 1.411 + void* clipboardDataPtr = malloc(dataLength); 1.412 + if (!clipboardDataPtr) 1.413 + return NS_ERROR_OUT_OF_MEMORY; 1.414 + [stringData getBytes:clipboardDataPtr]; 1.415 + 1.416 + // The DOM only wants LF, so convert from MacOS line endings to DOM line endings. 1.417 + int32_t signedDataLength = dataLength; 1.418 + nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(flavorStr, &clipboardDataPtr, &signedDataLength); 1.419 + dataLength = signedDataLength; 1.420 + 1.421 + // skip BOM (Byte Order Mark to distinguish little or big endian) 1.422 + char16_t* clipboardDataPtrNoBOM = (char16_t*)clipboardDataPtr; 1.423 + if ((dataLength > 2) && 1.424 + ((clipboardDataPtrNoBOM[0] == 0xFEFF) || 1.425 + (clipboardDataPtrNoBOM[0] == 0xFFFE))) { 1.426 + dataLength -= sizeof(char16_t); 1.427 + clipboardDataPtrNoBOM += 1; 1.428 + } 1.429 + 1.430 + nsCOMPtr<nsISupports> genericDataWrapper; 1.431 + nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtrNoBOM, dataLength, 1.432 + getter_AddRefs(genericDataWrapper)); 1.433 + aTransferable->SetTransferData(flavorStr, genericDataWrapper, dataLength); 1.434 + free(clipboardDataPtr); 1.435 + break; 1.436 + } 1.437 + 1.438 + // We have never supported this on Mac OS X, we should someday. Normally dragging images 1.439 + // in is accomplished with a file path drag instead of the image data itself. 1.440 + /* 1.441 + if (flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kJPEGImageMime) || 1.442 + flavorStr.EqualsLiteral(kJPGImageMime) || flavorStr.EqualsLiteral(kGIFImageMime)) { 1.443 + 1.444 + } 1.445 + */ 1.446 + } 1.447 + return NS_OK; 1.448 + 1.449 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.450 +} 1.451 + 1.452 +NS_IMETHODIMP 1.453 +nsDragService::IsDataFlavorSupported(const char *aDataFlavor, bool *_retval) 1.454 +{ 1.455 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.456 + 1.457 + *_retval = false; 1.458 + 1.459 + if (!globalDragPboard) 1.460 + return NS_ERROR_FAILURE; 1.461 + 1.462 + nsDependentCString dataFlavor(aDataFlavor); 1.463 + 1.464 + // first see if we have data for this in our cached transferable 1.465 + if (mDataItems) { 1.466 + uint32_t dataItemsCount; 1.467 + mDataItems->Count(&dataItemsCount); 1.468 + for (unsigned int i = 0; i < dataItemsCount; i++) { 1.469 + nsCOMPtr<nsISupports> currentTransferableSupports; 1.470 + mDataItems->GetElementAt(i, getter_AddRefs(currentTransferableSupports)); 1.471 + if (!currentTransferableSupports) 1.472 + continue; 1.473 + 1.474 + nsCOMPtr<nsITransferable> currentTransferable(do_QueryInterface(currentTransferableSupports)); 1.475 + if (!currentTransferable) 1.476 + continue; 1.477 + 1.478 + nsCOMPtr<nsISupportsArray> flavorList; 1.479 + nsresult rv = currentTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList)); 1.480 + if (NS_FAILED(rv)) 1.481 + continue; 1.482 + 1.483 + uint32_t flavorCount; 1.484 + flavorList->Count(&flavorCount); 1.485 + for (uint32_t j = 0; j < flavorCount; j++) { 1.486 + nsCOMPtr<nsISupports> genericFlavor; 1.487 + flavorList->GetElementAt(j, getter_AddRefs(genericFlavor)); 1.488 + nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor)); 1.489 + if (!currentFlavor) 1.490 + continue; 1.491 + nsXPIDLCString flavorStr; 1.492 + currentFlavor->ToString(getter_Copies(flavorStr)); 1.493 + if (dataFlavor.Equals(flavorStr)) { 1.494 + *_retval = true; 1.495 + return NS_OK; 1.496 + } 1.497 + } 1.498 + } 1.499 + } 1.500 + 1.501 + NSString *pboardType = nil; 1.502 + 1.503 + if (dataFlavor.EqualsLiteral(kFileMime)) { 1.504 + NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObject:NSFilenamesPboardType]]; 1.505 + if (availableType && [availableType isEqualToString:NSFilenamesPboardType]) 1.506 + *_retval = true; 1.507 + } 1.508 + else if (dataFlavor.EqualsLiteral(kURLMime)) { 1.509 + NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObject:kCorePboardType_url]]; 1.510 + if (availableType && [availableType isEqualToString:kCorePboardType_url]) 1.511 + *_retval = true; 1.512 + } 1.513 + else if (nsClipboard::IsStringType(dataFlavor, &pboardType)) { 1.514 + NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObject:pboardType]]; 1.515 + if (availableType && [availableType isEqualToString:pboardType]) 1.516 + *_retval = true; 1.517 + } 1.518 + 1.519 + return NS_OK; 1.520 + 1.521 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.522 +} 1.523 + 1.524 +NS_IMETHODIMP 1.525 +nsDragService::GetNumDropItems(uint32_t* aNumItems) 1.526 +{ 1.527 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.528 + 1.529 + *aNumItems = 0; 1.530 + 1.531 + // first check to see if we have a number of items cached 1.532 + if (mDataItems) { 1.533 + mDataItems->Count(aNumItems); 1.534 + return NS_OK; 1.535 + } 1.536 + 1.537 + // if there is a clipboard and there is something on it, then there is at least 1 item 1.538 + NSArray* clipboardTypes = [globalDragPboard types]; 1.539 + if (globalDragPboard && [clipboardTypes count] > 0) 1.540 + *aNumItems = 1; 1.541 + else 1.542 + return NS_OK; 1.543 + 1.544 + // if there is a list of files, send the number of files in that list 1.545 + NSArray* fileNames = [globalDragPboard propertyListForType:NSFilenamesPboardType]; 1.546 + if (fileNames) 1.547 + *aNumItems = [fileNames count]; 1.548 + 1.549 + return NS_OK; 1.550 + 1.551 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.552 +} 1.553 + 1.554 +NS_IMETHODIMP 1.555 +nsDragService::EndDragSession(bool aDoneDrag) 1.556 +{ 1.557 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.558 + 1.559 + if (mNativeDragView) { 1.560 + [mNativeDragView release]; 1.561 + mNativeDragView = nil; 1.562 + } 1.563 + if (mNativeDragEvent) { 1.564 + [mNativeDragEvent release]; 1.565 + mNativeDragEvent = nil; 1.566 + } 1.567 + 1.568 + mUserCancelled = gUserCancelledDrag; 1.569 + 1.570 + nsresult rv = nsBaseDragService::EndDragSession(aDoneDrag); 1.571 + mDataItems = nullptr; 1.572 + return rv; 1.573 + 1.574 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.575 +}