widget/cocoa/nsDragService.mm

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #ifdef MOZ_LOGGING
michael@0 7 #define FORCE_PR_LOG
michael@0 8 #endif
michael@0 9 #include "prlog.h"
michael@0 10
michael@0 11 #include "nsDragService.h"
michael@0 12 #include "nsObjCExceptions.h"
michael@0 13 #include "nsITransferable.h"
michael@0 14 #include "nsString.h"
michael@0 15 #include "nsClipboard.h"
michael@0 16 #include "nsXPCOM.h"
michael@0 17 #include "nsISupportsPrimitives.h"
michael@0 18 #include "nsCOMPtr.h"
michael@0 19 #include "nsPrimitiveHelpers.h"
michael@0 20 #include "nsLinebreakConverter.h"
michael@0 21 #include "nsIMacUtils.h"
michael@0 22 #include "nsIDOMNode.h"
michael@0 23 #include "nsRect.h"
michael@0 24 #include "nsPoint.h"
michael@0 25 #include "nsIIOService.h"
michael@0 26 #include "nsNetUtil.h"
michael@0 27 #include "nsIDocument.h"
michael@0 28 #include "nsIContent.h"
michael@0 29 #include "nsView.h"
michael@0 30 #include "gfxContext.h"
michael@0 31 #include "nsCocoaUtils.h"
michael@0 32 #include "mozilla/gfx/2D.h"
michael@0 33 #include "gfxPlatform.h"
michael@0 34
michael@0 35 using namespace mozilla;
michael@0 36 using namespace mozilla::gfx;
michael@0 37
michael@0 38 #ifdef PR_LOGGING
michael@0 39 extern PRLogModuleInfo* sCocoaLog;
michael@0 40 #endif
michael@0 41
michael@0 42 extern void EnsureLogInitialized();
michael@0 43
michael@0 44 extern NSPasteboard* globalDragPboard;
michael@0 45 extern NSView* gLastDragView;
michael@0 46 extern NSEvent* gLastDragMouseDownEvent;
michael@0 47 extern bool gUserCancelledDrag;
michael@0 48
michael@0 49 // This global makes the transferable array available to Cocoa's promised
michael@0 50 // file destination callback.
michael@0 51 nsISupportsArray *gDraggedTransferables = nullptr;
michael@0 52
michael@0 53 NSString* const kWildcardPboardType = @"MozillaWildcard";
michael@0 54 NSString* const kCorePboardType_url = @"CorePasteboardFlavorType 0x75726C20"; // 'url ' url
michael@0 55 NSString* const kCorePboardType_urld = @"CorePasteboardFlavorType 0x75726C64"; // 'urld' desc
michael@0 56 NSString* const kCorePboardType_urln = @"CorePasteboardFlavorType 0x75726C6E"; // 'urln' title
michael@0 57
michael@0 58 nsDragService::nsDragService()
michael@0 59 {
michael@0 60 mNativeDragView = nil;
michael@0 61 mNativeDragEvent = nil;
michael@0 62
michael@0 63 EnsureLogInitialized();
michael@0 64 }
michael@0 65
michael@0 66 nsDragService::~nsDragService()
michael@0 67 {
michael@0 68 }
michael@0 69
michael@0 70 static nsresult SetUpDragClipboard(nsISupportsArray* aTransferableArray)
michael@0 71 {
michael@0 72 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
michael@0 73
michael@0 74 if (!aTransferableArray)
michael@0 75 return NS_ERROR_FAILURE;
michael@0 76
michael@0 77 uint32_t count = 0;
michael@0 78 aTransferableArray->Count(&count);
michael@0 79
michael@0 80 NSPasteboard* dragPBoard = [NSPasteboard pasteboardWithName:NSDragPboard];
michael@0 81
michael@0 82 for (uint32_t i = 0; i < count; i++) {
michael@0 83 nsCOMPtr<nsISupports> currentTransferableSupports;
michael@0 84 aTransferableArray->GetElementAt(i, getter_AddRefs(currentTransferableSupports));
michael@0 85 if (!currentTransferableSupports)
michael@0 86 return NS_ERROR_FAILURE;
michael@0 87
michael@0 88 nsCOMPtr<nsITransferable> currentTransferable(do_QueryInterface(currentTransferableSupports));
michael@0 89 if (!currentTransferable)
michael@0 90 return NS_ERROR_FAILURE;
michael@0 91
michael@0 92 // Transform the transferable to an NSDictionary
michael@0 93 NSDictionary* pasteboardOutputDict = nsClipboard::PasteboardDictFromTransferable(currentTransferable);
michael@0 94 if (!pasteboardOutputDict)
michael@0 95 return NS_ERROR_FAILURE;
michael@0 96
michael@0 97 // write everything out to the general pasteboard
michael@0 98 unsigned int typeCount = [pasteboardOutputDict count];
michael@0 99 NSMutableArray* types = [NSMutableArray arrayWithCapacity:typeCount + 1];
michael@0 100 [types addObjectsFromArray:[pasteboardOutputDict allKeys]];
michael@0 101 // Gecko is initiating this drag so we always want its own views to consider
michael@0 102 // it. Add our wildcard type to the pasteboard to accomplish this.
michael@0 103 [types addObject:kWildcardPboardType]; // we don't increase the count for the loop below on purpose
michael@0 104 [dragPBoard declareTypes:types owner:nil];
michael@0 105 for (unsigned int i = 0; i < typeCount; i++) {
michael@0 106 NSString* currentKey = [types objectAtIndex:i];
michael@0 107 id currentValue = [pasteboardOutputDict valueForKey:currentKey];
michael@0 108 if (currentKey == NSStringPboardType ||
michael@0 109 currentKey == kCorePboardType_url ||
michael@0 110 currentKey == kCorePboardType_urld ||
michael@0 111 currentKey == kCorePboardType_urln) {
michael@0 112 [dragPBoard setString:currentValue forType:currentKey];
michael@0 113 }
michael@0 114 else if (currentKey == NSHTMLPboardType) {
michael@0 115 [dragPBoard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue))
michael@0 116 forType:currentKey];
michael@0 117 }
michael@0 118 else if (currentKey == NSTIFFPboardType) {
michael@0 119 [dragPBoard setData:currentValue forType:currentKey];
michael@0 120 }
michael@0 121 else if (currentKey == NSFilesPromisePboardType ||
michael@0 122 currentKey == NSFilenamesPboardType) {
michael@0 123 [dragPBoard setPropertyList:currentValue forType:currentKey];
michael@0 124 }
michael@0 125 }
michael@0 126 }
michael@0 127
michael@0 128 return NS_OK;
michael@0 129
michael@0 130 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
michael@0 131 }
michael@0 132
michael@0 133 NSImage*
michael@0 134 nsDragService::ConstructDragImage(nsIDOMNode* aDOMNode,
michael@0 135 nsIntRect* aDragRect,
michael@0 136 nsIScriptableRegion* aRegion)
michael@0 137 {
michael@0 138 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
michael@0 139
michael@0 140 NSPoint screenPoint =
michael@0 141 [[gLastDragView window] convertBaseToScreen:
michael@0 142 [gLastDragMouseDownEvent locationInWindow]];
michael@0 143 // Y coordinates are bottom to top, so reverse this
michael@0 144 screenPoint.y = nsCocoaUtils::FlippedScreenY(screenPoint.y);
michael@0 145
michael@0 146 CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(gLastDragView);
michael@0 147
michael@0 148 RefPtr<SourceSurface> surface;
michael@0 149 nsPresContext* pc;
michael@0 150 nsresult rv = DrawDrag(aDOMNode, aRegion,
michael@0 151 NSToIntRound(screenPoint.x),
michael@0 152 NSToIntRound(screenPoint.y),
michael@0 153 aDragRect, &surface, &pc);
michael@0 154 if (!aDragRect->width || !aDragRect->height) {
michael@0 155 // just use some suitable defaults
michael@0 156 int32_t size = nsCocoaUtils::CocoaPointsToDevPixels(20, scaleFactor);
michael@0 157 aDragRect->SetRect(nsCocoaUtils::CocoaPointsToDevPixels(screenPoint.x, scaleFactor),
michael@0 158 nsCocoaUtils::CocoaPointsToDevPixels(screenPoint.y, scaleFactor),
michael@0 159 size, size);
michael@0 160 }
michael@0 161
michael@0 162 if (NS_FAILED(rv) || !surface)
michael@0 163 return nil;
michael@0 164
michael@0 165 uint32_t width = aDragRect->width;
michael@0 166 uint32_t height = aDragRect->height;
michael@0 167
michael@0 168 nsRefPtr<gfxImageSurface> imgSurface = new gfxImageSurface(
michael@0 169 gfxIntSize(width, height), gfxImageFormat::ARGB32);
michael@0 170 if (!imgSurface)
michael@0 171 return nil;
michael@0 172
michael@0 173 RefPtr<DrawTarget> dt =
michael@0 174 gfxPlatform::GetPlatform()->
michael@0 175 CreateDrawTargetForSurface(imgSurface, IntSize(width, height));
michael@0 176 if (!dt)
michael@0 177 return nil;
michael@0 178
michael@0 179 dt->FillRect(gfx::Rect(0, 0, width, height),
michael@0 180 SurfacePattern(surface, ExtendMode::CLAMP),
michael@0 181 DrawOptions(1.0f, CompositionOp::OP_SOURCE));
michael@0 182
michael@0 183 uint32_t* imageData = (uint32_t*)imgSurface->Data();
michael@0 184 int32_t stride = imgSurface->Stride();
michael@0 185
michael@0 186 NSBitmapImageRep* imageRep =
michael@0 187 [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
michael@0 188 pixelsWide:width
michael@0 189 pixelsHigh:height
michael@0 190 bitsPerSample:8
michael@0 191 samplesPerPixel:4
michael@0 192 hasAlpha:YES
michael@0 193 isPlanar:NO
michael@0 194 colorSpaceName:NSDeviceRGBColorSpace
michael@0 195 bytesPerRow:width * 4
michael@0 196 bitsPerPixel:32];
michael@0 197
michael@0 198 uint8_t* dest = [imageRep bitmapData];
michael@0 199 for (uint32_t i = 0; i < height; ++i) {
michael@0 200 uint8_t* src = (uint8_t *)imageData + i * stride;
michael@0 201 for (uint32_t j = 0; j < width; ++j) {
michael@0 202 // Reduce transparency overall by multipying by a factor. Remember, Alpha
michael@0 203 // is premultipled here. Also, Quartz likes RGBA, so do that translation as well.
michael@0 204 #ifdef IS_BIG_ENDIAN
michael@0 205 dest[0] = uint8_t(src[1] * DRAG_TRANSLUCENCY);
michael@0 206 dest[1] = uint8_t(src[2] * DRAG_TRANSLUCENCY);
michael@0 207 dest[2] = uint8_t(src[3] * DRAG_TRANSLUCENCY);
michael@0 208 dest[3] = uint8_t(src[0] * DRAG_TRANSLUCENCY);
michael@0 209 #else
michael@0 210 dest[0] = uint8_t(src[2] * DRAG_TRANSLUCENCY);
michael@0 211 dest[1] = uint8_t(src[1] * DRAG_TRANSLUCENCY);
michael@0 212 dest[2] = uint8_t(src[0] * DRAG_TRANSLUCENCY);
michael@0 213 dest[3] = uint8_t(src[3] * DRAG_TRANSLUCENCY);
michael@0 214 #endif
michael@0 215 src += 4;
michael@0 216 dest += 4;
michael@0 217 }
michael@0 218 }
michael@0 219
michael@0 220 NSImage* image =
michael@0 221 [[NSImage alloc] initWithSize:NSMakeSize(width / scaleFactor,
michael@0 222 height / scaleFactor)];
michael@0 223 [image addRepresentation:imageRep];
michael@0 224 [imageRep release];
michael@0 225
michael@0 226 return [image autorelease];
michael@0 227
michael@0 228 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
michael@0 229 }
michael@0 230
michael@0 231 // We can only invoke NSView's 'dragImage:at:offset:event:pasteboard:source:slideBack:' from
michael@0 232 // within NSView's 'mouseDown:' or 'mouseDragged:'. Luckily 'mouseDragged' is always on the
michael@0 233 // stack when InvokeDragSession gets called.
michael@0 234 NS_IMETHODIMP
michael@0 235 nsDragService::InvokeDragSession(nsIDOMNode* aDOMNode, nsISupportsArray* aTransferableArray,
michael@0 236 nsIScriptableRegion* aDragRgn, uint32_t aActionType)
michael@0 237 {
michael@0 238 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
michael@0 239
michael@0 240 nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode,
michael@0 241 aTransferableArray,
michael@0 242 aDragRgn, aActionType);
michael@0 243 NS_ENSURE_SUCCESS(rv, rv);
michael@0 244
michael@0 245 mDataItems = aTransferableArray;
michael@0 246
michael@0 247 // put data on the clipboard
michael@0 248 if (NS_FAILED(SetUpDragClipboard(aTransferableArray)))
michael@0 249 return NS_ERROR_FAILURE;
michael@0 250
michael@0 251 nsIntRect dragRect(0, 0, 20, 20);
michael@0 252 NSImage* image = ConstructDragImage(aDOMNode, &dragRect, aDragRgn);
michael@0 253 if (!image) {
michael@0 254 // if no image was returned, just draw a rectangle
michael@0 255 NSSize size;
michael@0 256 size.width = dragRect.width;
michael@0 257 size.height = dragRect.height;
michael@0 258 image = [[NSImage alloc] initWithSize:size];
michael@0 259 [image lockFocus];
michael@0 260 [[NSColor grayColor] set];
michael@0 261 NSBezierPath* path = [NSBezierPath bezierPath];
michael@0 262 [path setLineWidth:2.0];
michael@0 263 [path moveToPoint:NSMakePoint(0, 0)];
michael@0 264 [path lineToPoint:NSMakePoint(0, size.height)];
michael@0 265 [path lineToPoint:NSMakePoint(size.width, size.height)];
michael@0 266 [path lineToPoint:NSMakePoint(size.width, 0)];
michael@0 267 [path lineToPoint:NSMakePoint(0, 0)];
michael@0 268 [path stroke];
michael@0 269 [image unlockFocus];
michael@0 270 }
michael@0 271
michael@0 272 nsIntPoint pt(dragRect.x, dragRect.YMost());
michael@0 273 CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(gLastDragView);
michael@0 274 NSPoint point = nsCocoaUtils::DevPixelsToCocoaPoints(pt, scaleFactor);
michael@0 275 point.y = nsCocoaUtils::FlippedScreenY(point.y);
michael@0 276
michael@0 277 point = [[gLastDragView window] convertScreenToBase: point];
michael@0 278 NSPoint localPoint = [gLastDragView convertPoint:point fromView:nil];
michael@0 279
michael@0 280 // Save the transferables away in case a promised file callback is invoked.
michael@0 281 gDraggedTransferables = aTransferableArray;
michael@0 282
michael@0 283 nsBaseDragService::StartDragSession();
michael@0 284 nsBaseDragService::OpenDragPopup();
michael@0 285
michael@0 286 // We need to retain the view and the event during the drag in case either gets destroyed.
michael@0 287 mNativeDragView = [gLastDragView retain];
michael@0 288 mNativeDragEvent = [gLastDragMouseDownEvent retain];
michael@0 289
michael@0 290 gUserCancelledDrag = false;
michael@0 291 [mNativeDragView dragImage:image
michael@0 292 at:localPoint
michael@0 293 offset:NSZeroSize
michael@0 294 event:mNativeDragEvent
michael@0 295 pasteboard:[NSPasteboard pasteboardWithName:NSDragPboard]
michael@0 296 source:mNativeDragView
michael@0 297 slideBack:YES];
michael@0 298 gUserCancelledDrag = false;
michael@0 299
michael@0 300 if (mDoingDrag)
michael@0 301 nsBaseDragService::EndDragSession(false);
michael@0 302
michael@0 303 return NS_OK;
michael@0 304
michael@0 305 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
michael@0 306 }
michael@0 307
michael@0 308 NS_IMETHODIMP
michael@0 309 nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex)
michael@0 310 {
michael@0 311 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
michael@0 312
michael@0 313 if (!aTransferable)
michael@0 314 return NS_ERROR_FAILURE;
michael@0 315
michael@0 316 // get flavor list that includes all acceptable flavors (including ones obtained through conversion)
michael@0 317 nsCOMPtr<nsISupportsArray> flavorList;
michael@0 318 nsresult rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList));
michael@0 319 if (NS_FAILED(rv))
michael@0 320 return NS_ERROR_FAILURE;
michael@0 321
michael@0 322 uint32_t acceptableFlavorCount;
michael@0 323 flavorList->Count(&acceptableFlavorCount);
michael@0 324
michael@0 325 // if this drag originated within Mozilla we should just use the cached data from
michael@0 326 // when the drag started if possible
michael@0 327 if (mDataItems) {
michael@0 328 nsCOMPtr<nsISupports> currentTransferableSupports;
michael@0 329 mDataItems->GetElementAt(aItemIndex, getter_AddRefs(currentTransferableSupports));
michael@0 330 if (currentTransferableSupports) {
michael@0 331 nsCOMPtr<nsITransferable> currentTransferable(do_QueryInterface(currentTransferableSupports));
michael@0 332 if (currentTransferable) {
michael@0 333 for (uint32_t i = 0; i < acceptableFlavorCount; i++) {
michael@0 334 nsCOMPtr<nsISupports> genericFlavor;
michael@0 335 flavorList->GetElementAt(i, getter_AddRefs(genericFlavor));
michael@0 336 nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
michael@0 337 if (!currentFlavor)
michael@0 338 continue;
michael@0 339 nsXPIDLCString flavorStr;
michael@0 340 currentFlavor->ToString(getter_Copies(flavorStr));
michael@0 341
michael@0 342 nsCOMPtr<nsISupports> dataSupports;
michael@0 343 uint32_t dataSize = 0;
michael@0 344 rv = currentTransferable->GetTransferData(flavorStr, getter_AddRefs(dataSupports), &dataSize);
michael@0 345 if (NS_SUCCEEDED(rv)) {
michael@0 346 aTransferable->SetTransferData(flavorStr, dataSupports, dataSize);
michael@0 347 return NS_OK; // maybe try to fill in more types? Is there a point?
michael@0 348 }
michael@0 349 }
michael@0 350 }
michael@0 351 }
michael@0 352 }
michael@0 353
michael@0 354 // now check the actual clipboard for data
michael@0 355 for (uint32_t i = 0; i < acceptableFlavorCount; i++) {
michael@0 356 nsCOMPtr<nsISupports> genericFlavor;
michael@0 357 flavorList->GetElementAt(i, getter_AddRefs(genericFlavor));
michael@0 358 nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
michael@0 359
michael@0 360 if (!currentFlavor)
michael@0 361 continue;
michael@0 362
michael@0 363 nsXPIDLCString flavorStr;
michael@0 364 currentFlavor->ToString(getter_Copies(flavorStr));
michael@0 365
michael@0 366 PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("nsDragService::GetData: looking for clipboard data of type %s\n", flavorStr.get()));
michael@0 367
michael@0 368 if (flavorStr.EqualsLiteral(kFileMime)) {
michael@0 369 NSArray* pFiles = [globalDragPboard propertyListForType:NSFilenamesPboardType];
michael@0 370 if (!pFiles || [pFiles count] < (aItemIndex + 1))
michael@0 371 continue;
michael@0 372
michael@0 373 NSString* filePath = [pFiles objectAtIndex:aItemIndex];
michael@0 374 if (!filePath)
michael@0 375 continue;
michael@0 376
michael@0 377 unsigned int stringLength = [filePath length];
michael@0 378 unsigned int dataLength = (stringLength + 1) * sizeof(char16_t); // in bytes
michael@0 379 char16_t* clipboardDataPtr = (char16_t*)malloc(dataLength);
michael@0 380 if (!clipboardDataPtr)
michael@0 381 return NS_ERROR_OUT_OF_MEMORY;
michael@0 382 [filePath getCharacters:reinterpret_cast<unichar*>(clipboardDataPtr)];
michael@0 383 clipboardDataPtr[stringLength] = 0; // null terminate
michael@0 384
michael@0 385 nsCOMPtr<nsIFile> file;
michael@0 386 nsresult rv = NS_NewLocalFile(nsDependentString(clipboardDataPtr), true, getter_AddRefs(file));
michael@0 387 free(clipboardDataPtr);
michael@0 388 if (NS_FAILED(rv))
michael@0 389 continue;
michael@0 390
michael@0 391 aTransferable->SetTransferData(flavorStr, file, dataLength);
michael@0 392
michael@0 393 break;
michael@0 394 }
michael@0 395
michael@0 396 NSString *pboardType = NSStringPboardType;
michael@0 397
michael@0 398 if (nsClipboard::IsStringType(flavorStr, &pboardType) ||
michael@0 399 flavorStr.EqualsLiteral(kURLMime) ||
michael@0 400 flavorStr.EqualsLiteral(kURLDataMime) ||
michael@0 401 flavorStr.EqualsLiteral(kURLDescriptionMime)) {
michael@0 402 NSString* pString = [globalDragPboard stringForType:pboardType];
michael@0 403 if (!pString)
michael@0 404 continue;
michael@0 405
michael@0 406 NSData* stringData = [pString dataUsingEncoding:NSUnicodeStringEncoding];
michael@0 407 unsigned int dataLength = [stringData length];
michael@0 408 void* clipboardDataPtr = malloc(dataLength);
michael@0 409 if (!clipboardDataPtr)
michael@0 410 return NS_ERROR_OUT_OF_MEMORY;
michael@0 411 [stringData getBytes:clipboardDataPtr];
michael@0 412
michael@0 413 // The DOM only wants LF, so convert from MacOS line endings to DOM line endings.
michael@0 414 int32_t signedDataLength = dataLength;
michael@0 415 nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(flavorStr, &clipboardDataPtr, &signedDataLength);
michael@0 416 dataLength = signedDataLength;
michael@0 417
michael@0 418 // skip BOM (Byte Order Mark to distinguish little or big endian)
michael@0 419 char16_t* clipboardDataPtrNoBOM = (char16_t*)clipboardDataPtr;
michael@0 420 if ((dataLength > 2) &&
michael@0 421 ((clipboardDataPtrNoBOM[0] == 0xFEFF) ||
michael@0 422 (clipboardDataPtrNoBOM[0] == 0xFFFE))) {
michael@0 423 dataLength -= sizeof(char16_t);
michael@0 424 clipboardDataPtrNoBOM += 1;
michael@0 425 }
michael@0 426
michael@0 427 nsCOMPtr<nsISupports> genericDataWrapper;
michael@0 428 nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtrNoBOM, dataLength,
michael@0 429 getter_AddRefs(genericDataWrapper));
michael@0 430 aTransferable->SetTransferData(flavorStr, genericDataWrapper, dataLength);
michael@0 431 free(clipboardDataPtr);
michael@0 432 break;
michael@0 433 }
michael@0 434
michael@0 435 // We have never supported this on Mac OS X, we should someday. Normally dragging images
michael@0 436 // in is accomplished with a file path drag instead of the image data itself.
michael@0 437 /*
michael@0 438 if (flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kJPEGImageMime) ||
michael@0 439 flavorStr.EqualsLiteral(kJPGImageMime) || flavorStr.EqualsLiteral(kGIFImageMime)) {
michael@0 440
michael@0 441 }
michael@0 442 */
michael@0 443 }
michael@0 444 return NS_OK;
michael@0 445
michael@0 446 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
michael@0 447 }
michael@0 448
michael@0 449 NS_IMETHODIMP
michael@0 450 nsDragService::IsDataFlavorSupported(const char *aDataFlavor, bool *_retval)
michael@0 451 {
michael@0 452 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
michael@0 453
michael@0 454 *_retval = false;
michael@0 455
michael@0 456 if (!globalDragPboard)
michael@0 457 return NS_ERROR_FAILURE;
michael@0 458
michael@0 459 nsDependentCString dataFlavor(aDataFlavor);
michael@0 460
michael@0 461 // first see if we have data for this in our cached transferable
michael@0 462 if (mDataItems) {
michael@0 463 uint32_t dataItemsCount;
michael@0 464 mDataItems->Count(&dataItemsCount);
michael@0 465 for (unsigned int i = 0; i < dataItemsCount; i++) {
michael@0 466 nsCOMPtr<nsISupports> currentTransferableSupports;
michael@0 467 mDataItems->GetElementAt(i, getter_AddRefs(currentTransferableSupports));
michael@0 468 if (!currentTransferableSupports)
michael@0 469 continue;
michael@0 470
michael@0 471 nsCOMPtr<nsITransferable> currentTransferable(do_QueryInterface(currentTransferableSupports));
michael@0 472 if (!currentTransferable)
michael@0 473 continue;
michael@0 474
michael@0 475 nsCOMPtr<nsISupportsArray> flavorList;
michael@0 476 nsresult rv = currentTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList));
michael@0 477 if (NS_FAILED(rv))
michael@0 478 continue;
michael@0 479
michael@0 480 uint32_t flavorCount;
michael@0 481 flavorList->Count(&flavorCount);
michael@0 482 for (uint32_t j = 0; j < flavorCount; j++) {
michael@0 483 nsCOMPtr<nsISupports> genericFlavor;
michael@0 484 flavorList->GetElementAt(j, getter_AddRefs(genericFlavor));
michael@0 485 nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
michael@0 486 if (!currentFlavor)
michael@0 487 continue;
michael@0 488 nsXPIDLCString flavorStr;
michael@0 489 currentFlavor->ToString(getter_Copies(flavorStr));
michael@0 490 if (dataFlavor.Equals(flavorStr)) {
michael@0 491 *_retval = true;
michael@0 492 return NS_OK;
michael@0 493 }
michael@0 494 }
michael@0 495 }
michael@0 496 }
michael@0 497
michael@0 498 NSString *pboardType = nil;
michael@0 499
michael@0 500 if (dataFlavor.EqualsLiteral(kFileMime)) {
michael@0 501 NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObject:NSFilenamesPboardType]];
michael@0 502 if (availableType && [availableType isEqualToString:NSFilenamesPboardType])
michael@0 503 *_retval = true;
michael@0 504 }
michael@0 505 else if (dataFlavor.EqualsLiteral(kURLMime)) {
michael@0 506 NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObject:kCorePboardType_url]];
michael@0 507 if (availableType && [availableType isEqualToString:kCorePboardType_url])
michael@0 508 *_retval = true;
michael@0 509 }
michael@0 510 else if (nsClipboard::IsStringType(dataFlavor, &pboardType)) {
michael@0 511 NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObject:pboardType]];
michael@0 512 if (availableType && [availableType isEqualToString:pboardType])
michael@0 513 *_retval = true;
michael@0 514 }
michael@0 515
michael@0 516 return NS_OK;
michael@0 517
michael@0 518 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
michael@0 519 }
michael@0 520
michael@0 521 NS_IMETHODIMP
michael@0 522 nsDragService::GetNumDropItems(uint32_t* aNumItems)
michael@0 523 {
michael@0 524 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
michael@0 525
michael@0 526 *aNumItems = 0;
michael@0 527
michael@0 528 // first check to see if we have a number of items cached
michael@0 529 if (mDataItems) {
michael@0 530 mDataItems->Count(aNumItems);
michael@0 531 return NS_OK;
michael@0 532 }
michael@0 533
michael@0 534 // if there is a clipboard and there is something on it, then there is at least 1 item
michael@0 535 NSArray* clipboardTypes = [globalDragPboard types];
michael@0 536 if (globalDragPboard && [clipboardTypes count] > 0)
michael@0 537 *aNumItems = 1;
michael@0 538 else
michael@0 539 return NS_OK;
michael@0 540
michael@0 541 // if there is a list of files, send the number of files in that list
michael@0 542 NSArray* fileNames = [globalDragPboard propertyListForType:NSFilenamesPboardType];
michael@0 543 if (fileNames)
michael@0 544 *aNumItems = [fileNames count];
michael@0 545
michael@0 546 return NS_OK;
michael@0 547
michael@0 548 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
michael@0 549 }
michael@0 550
michael@0 551 NS_IMETHODIMP
michael@0 552 nsDragService::EndDragSession(bool aDoneDrag)
michael@0 553 {
michael@0 554 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
michael@0 555
michael@0 556 if (mNativeDragView) {
michael@0 557 [mNativeDragView release];
michael@0 558 mNativeDragView = nil;
michael@0 559 }
michael@0 560 if (mNativeDragEvent) {
michael@0 561 [mNativeDragEvent release];
michael@0 562 mNativeDragEvent = nil;
michael@0 563 }
michael@0 564
michael@0 565 mUserCancelled = gUserCancelledDrag;
michael@0 566
michael@0 567 nsresult rv = nsBaseDragService::EndDragSession(aDoneDrag);
michael@0 568 mDataItems = nullptr;
michael@0 569 return rv;
michael@0 570
michael@0 571 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
michael@0 572 }

mercurial