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