summaryrefslogtreecommitdiffstats
path: root/Source/WebKit2/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit2/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm')
-rw-r--r--Source/WebKit2/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm327
1 files changed, 233 insertions, 94 deletions
diff --git a/Source/WebKit2/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm b/Source/WebKit2/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm
index ae9cec3..75d92e2 100644
--- a/Source/WebKit2/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm
+++ b/Source/WebKit2/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm
@@ -32,134 +32,273 @@
#import "WebPage.h"
#import "WebPageProxyMessages.h"
#import <WebCore/CachedImage.h>
-#import <WebCore/DOMPrivate.h>
#import <WebCore/DOMElementInternal.h>
+#import <WebCore/DOMPrivate.h>
+#import <WebCore/DragController.h>
#import <WebCore/FrameView.h>
#import <WebCore/GraphicsContext.h>
#import <WebCore/LegacyWebArchive.h>
#import <WebCore/RenderImage.h>
+#import <WebCore/ResourceHandle.h>
#import <WebCore/StringTruncator.h>
-#import <wtf/StdLibExtras.h>
+#import <WebKit/WebArchive.h>
#import <WebKit/WebKitNSStringExtras.h>
+#import <WebKit/WebNSFileManagerExtras.h>
+#import <WebKit/WebNSPasteboardExtras.h>
#import <WebKit/WebNSURLExtras.h>
+#import <WebKitSystemInterface.h>
+#import <wtf/StdLibExtras.h>
using namespace WebCore;
+using namespace WebKit;
+
+// Internal AppKit class. If the pasteboard handling was in the same process
+// that called the dragImage method, this would be created automatically.
+// Create it explicitly because dragImage is called in the UI process.
+@interface NSFilePromiseDragSource : NSObject
+{
+ char _unknownFields[256];
+}
+- (id)initWithSource:(id)dragSource;
+- (void)setTypes:(NSArray *)types onPasteboard:(NSPasteboard *)pasteboard;
+@end
+
+@interface WKPasteboardFilePromiseOwner : NSFilePromiseDragSource
+@end
+
+@interface WKPasteboardOwner : NSObject
+{
+ CachedResourceHandle<CachedImage> _image;
+}
+- (id)initWithImage:(CachedImage*)image;
+@end
namespace WebKit {
-using namespace WebCore;
-
-void WebDragClient::startDrag(DragImageRef dragImage, const IntPoint& at, const IntPoint& eventPos, Clipboard* clipboard, Frame* frame, bool linkDrag)
+static PassRefPtr<ShareableBitmap> convertImageToBitmap(NSImage *image)
{
- if (!frame)
- return;
- ASSERT(clipboard);
-
- NSImage *dragNSImage = dragImage.get();
- RefPtr<ShareableBitmap> dragShareableImage = ShareableBitmap::createShareable(IntSize([dragNSImage size]));
- OwnPtr<GraphicsContext> graphicsContext = dragShareableImage->createGraphicsContext();
+ RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(IntSize([image size]), ShareableBitmap::SupportsAlpha);
+ OwnPtr<GraphicsContext> graphicsContext = bitmap->createGraphicsContext();
- [NSGraphicsContext saveGraphicsState];
- NSGraphicsContext* bitmapContext = [NSGraphicsContext graphicsContextWithGraphicsPort:graphicsContext->platformContext() flipped:YES];
- [NSGraphicsContext setCurrentContext: bitmapContext];
-
- [dragNSImage drawInRect:NSMakeRect(0, 0, [dragNSImage size].width , [dragNSImage size].height) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1 respectFlipped:YES hints:nil];
- [NSGraphicsContext restoreGraphicsState];
-
- SharedMemory::Handle handle;
- if (!dragShareableImage->createHandle(handle))
+ RetainPtr<NSGraphicsContext> savedContext = [NSGraphicsContext currentContext];
+
+ [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:graphicsContext->platformContext() flipped:YES]];
+ [image drawInRect:NSMakeRect(0, 0, bitmap->size().width(), bitmap->size().height()) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1 respectFlipped:YES hints:nil];
+
+ [NSGraphicsContext setCurrentContext:savedContext.get()];
+
+ return bitmap.release();
+}
+
+void WebDragClient::startDrag(RetainPtr<NSImage> image, const IntPoint& point, const IntPoint&, Clipboard*, Frame* frame, bool linkDrag)
+{
+ RefPtr<ShareableBitmap> bitmap = convertImageToBitmap(image.get());
+ ShareableBitmap::Handle handle;
+ if (!bitmap->createHandle(handle))
return;
- IntPoint clientPoint(at);
- m_page->send(Messages::WebPageProxy::SetDragImage(clientPoint, IntSize([dragNSImage size]), handle, linkDrag));
+
+ // FIXME: Seems this message should be named StartDrag, not SetDragImage.
+ m_page->send(Messages::WebPageProxy::SetDragImage(frame->view()->contentsToWindow(point), handle, linkDrag));
}
-static void writeURL(NSPasteboard* pasteboard, NSURL* URL, NSString* title, NSArray* types)
+static CachedImage* cachedImage(Element* element)
{
- ASSERT(URL);
-
+ RenderObject* renderer = element->renderer();
+ if (!renderer)
+ return 0;
+ if (!renderer->isRenderImage())
+ return 0;
+ CachedImage* image = toRenderImage(renderer)->cachedImage();
+ if (!image || image->errorOccurred())
+ return 0;
+ return image;
+}
+
+static NSArray *arrayForURLsWithTitles(NSURL *URL, NSString *title)
+{
+ return [NSArray arrayWithObjects:[NSArray arrayWithObject:[URL _web_originalDataAsString]],
+ [NSArray arrayWithObject:[title _webkit_stringByTrimmingWhitespace]], nil];
+}
+
+void WebDragClient::declareAndWriteDragImage(NSPasteboard *pasteboard, DOMElement *element, NSURL *URL, NSString *title, WebCore::Frame*)
+{
+ ASSERT(element);
+ ASSERT(pasteboard && pasteboard == [NSPasteboard pasteboardWithName:NSDragPboard]);
+
+ Element* coreElement = core(element);
+
+ CachedImage* image = cachedImage(coreElement);
+
+ NSString *extension = @"";
+ if (image) {
+ extension = image->image()->filenameExtension();
+ if (![extension length])
+ return;
+ }
+
if (![title length]) {
title = [[URL path] lastPathComponent];
if (![title length])
title = [URL _web_userVisibleString];
}
-
- if ([types containsObject:NSURLPboardType])
- [URL writeToPasteboard:pasteboard];
- if ([types containsObject:PasteboardTypes::WebURLPboardType])
- [pasteboard setString:[URL _web_originalDataAsString] forType:PasteboardTypes::WebURLPboardType];
- if ([types containsObject:PasteboardTypes::WebURLNamePboardType])
- [pasteboard setString:title forType:PasteboardTypes::WebURLNamePboardType];
- if ([types containsObject:NSStringPboardType])
- [pasteboard setString:[URL _web_userVisibleString] forType:NSStringPboardType];
- if ([types containsObject:PasteboardTypes::WebURLsWithTitlesPboardType]) {
- NSArray* URLs = [NSArray arrayWithObject:URL];
- unsigned count = [URLs count];
-
- if (!count || [pasteboard availableTypeFromArray:[NSArray arrayWithObject:PasteboardTypes::WebURLsWithTitlesPboardType]] == nil)
- return;
- NSArray* titles = [NSArray arrayWithObject:title];
-
- if (count != [titles count])
- titles = nil;
-
- NSMutableArray* URLStrings = [NSMutableArray arrayWithCapacity:count];
- NSMutableArray* titlesOrEmptyStrings = [NSMutableArray arrayWithCapacity:count];
- for (unsigned index = 0; index < count; ++index) {
- [URLStrings addObject:[[URLs objectAtIndex:index] _web_originalDataAsString]];
- [titlesOrEmptyStrings addObject:(titles == nil) ? @"" : [[titles objectAtIndex:index] _webkit_stringByTrimmingWhitespace]];
+ RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(coreElement);
+
+ RetainPtr<NSMutableArray> types(AdoptNS, [[NSMutableArray alloc] initWithObjects:NSFilesPromisePboardType, nil]);
+ [types.get() addObjectsFromArray:archive ? PasteboardTypes::forImagesWithArchive() : PasteboardTypes::forImages()];
+
+ RetainPtr<WKPasteboardOwner> pasteboardOwner(AdoptNS, [[WKPasteboardOwner alloc] initWithImage:image]);
+
+ RetainPtr<WKPasteboardFilePromiseOwner> filePromiseOwner(AdoptNS, [(WKPasteboardFilePromiseOwner *)[WKPasteboardFilePromiseOwner alloc] initWithSource:pasteboardOwner.get()]);
+ m_page->setDragSource(filePromiseOwner.get());
+
+ [pasteboard declareTypes:types.get() owner:pasteboardOwner.get()];
+
+ [pasteboard setPropertyList:[NSArray arrayWithObject:extension] forType:NSFilesPromisePboardType];
+
+ [filePromiseOwner.get() setTypes:[pasteboard propertyListForType:NSFilesPromisePboardType] onPasteboard:pasteboard];
+
+ [URL writeToPasteboard:pasteboard];
+
+ [pasteboard setString:[URL _web_originalDataAsString] forType:PasteboardTypes::WebURLPboardType];
+
+ [pasteboard setString:title forType:PasteboardTypes::WebURLNamePboardType];
+
+ [pasteboard setString:[URL _web_userVisibleString] forType:NSStringPboardType];
+
+ [pasteboard setPropertyList:arrayForURLsWithTitles(URL, title) forType:PasteboardTypes::WebURLsWithTitlesPboardType];
+
+ if (archive)
+ [pasteboard setData:(NSData *)archive->rawDataRepresentation().get() forType:PasteboardTypes::WebArchivePboardType];
+}
+
+} // namespace WebKit
+
+@implementation WKPasteboardFilePromiseOwner
+
+// The AppKit implementation of copyDropDirectory gets the current pasteboard in
+// a way that only works in the process where the drag is initiated. We supply
+// an implementation that gets the pasteboard by name instead.
+- (CFURLRef)copyDropDirectory
+{
+ PasteboardRef pasteboard;
+ OSStatus status = PasteboardCreate((CFStringRef)NSDragPboard, &pasteboard);
+ if (status != noErr || !pasteboard)
+ return 0;
+ CFURLRef location = 0;
+ status = PasteboardCopyPasteLocation(pasteboard, &location);
+ CFRelease(pasteboard);
+ if (status != noErr || !location)
+ return 0;
+ CFMakeCollectable(location);
+ return location;
+}
+
+@end
+
+@implementation WKPasteboardOwner
+
+static CachedResourceClient* promisedDataClient()
+{
+ static CachedResourceClient* client = new CachedResourceClient;
+ return client;
+}
+
+- (void)clearImage
+{
+ if (!_image)
+ return;
+ _image->removeClient(promisedDataClient());
+ _image = 0;
+}
+
+- (id)initWithImage:(CachedImage*)image
+{
+ self = [super init];
+ if (!self)
+ return nil;
+
+ _image = image;
+ if (image)
+ image->addClient(promisedDataClient());
+ return self;
+}
+
+- (void)dealloc
+{
+ [self clearImage];
+ [super dealloc];
+}
+
+- (void)finalize
+{
+ [self clearImage];
+ [super finalize];
+}
+
+- (void)pasteboard:(NSPasteboard *)pasteboard provideDataForType:(NSString *)type
+{
+ if ([type isEqual:NSTIFFPboardType]) {
+ if (_image) {
+ if (Image* image = _image->image())
+ [pasteboard setData:(NSData *)image->getTIFFRepresentation() forType:NSTIFFPboardType];
+ [self clearImage];
}
-
- [pasteboard setPropertyList:[NSArray arrayWithObjects:URLStrings, titlesOrEmptyStrings, nil]
- forType:PasteboardTypes::WebURLsWithTitlesPboardType];
+ return;
}
+ // FIXME: Handle RTFD here.
}
-
-static void writeImage(NSPasteboard* pasteboard, NSImage *image, DOMElement* element, NSURL* URL, NSString* title, LegacyWebArchive* archive, NSArray* types)
+
+- (void)pasteboardChangedOwner:(NSPasteboard *)pasteboard
{
- ASSERT(image || element);
- ASSERT(URL);
-
- writeURL(pasteboard, URL, title, types);
-
- if ([types containsObject:NSTIFFPboardType]) {
- // FIXME: we should add handling of promised types.
- if (image)
- [pasteboard setData:[image TIFFRepresentation] forType:NSTIFFPboardType];
- else if (element)
- [pasteboard setData:[element _imageTIFFRepresentation] forType:NSTIFFPboardType];
- }
-
- if (archive && [types containsObject:PasteboardTypes::WebArchivePboardType])
- [pasteboard setData:[[(NSData *)archive->rawDataRepresentation().get() retain] autorelease] forType:PasteboardTypes::WebArchivePboardType];
+ [self clearImage];
}
-
-void WebDragClient::declareAndWriteDragImage(NSPasteboard* pasteboard, DOMElement* element, NSURL* URL, NSString* title, WebCore::Frame*)
+
+static bool matchesExtensionOrEquivalent(NSString *filename, NSString *extension)
{
- ASSERT(element);
- ASSERT(pasteboard && pasteboard == [NSPasteboard pasteboardWithName:NSDragPboard]);
+ NSString *extensionAsSuffix = [@"." stringByAppendingString:extension];
+ return [filename _webkit_hasCaseInsensitiveSuffix:extensionAsSuffix]
+ || ([extension _webkit_isCaseInsensitiveEqualToString:@"jpeg"]
+ && [filename _webkit_hasCaseInsensitiveSuffix:@".jpg"]);
+}
+
+- (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
+{
+ NSFileWrapper *wrapper = nil;
+ NSURL *draggingImageURL = nil;
- NSString *extension = @"";
- if (RenderObject* renderer = core(element)->renderer()) {
- if (renderer->isImage()) {
- if (CachedImage* image = toRenderImage(renderer)->cachedImage()) {
- extension = image->image()->filenameExtension();
- if (![extension length])
- return;
- }
+ if (_image) {
+ if (SharedBuffer* buffer = _image->CachedResource::data()) {
+ NSData *data = buffer->createNSData();
+ NSURLResponse *response = _image->response().nsURLResponse();
+ draggingImageURL = [response URL];
+ wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:data] autorelease];
+ NSString* filename = [response suggestedFilename];
+ NSString* trueExtension(_image->image()->filenameExtension());
+ if (!matchesExtensionOrEquivalent(filename, trueExtension))
+ filename = [[filename stringByAppendingString:@"."] stringByAppendingString:trueExtension];
+ [wrapper setPreferredFilename:filename];
}
}
+
+ // FIXME: Do we need to handle the case where we do not have a CachedImage?
+ // WebKit1 had code for this case.
- RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(core(element));
- NSMutableArray *types = [[NSMutableArray alloc] initWithObjects:NSFilesPromisePboardType, nil];
- [types addObjectsFromArray:(archive) ? PasteboardTypes::forImagesWithArchive() : PasteboardTypes::forImages()];
- [pasteboard declareTypes:types owner:nil];
- writeImage(pasteboard, nil, element, URL, title, archive.get(), types);
- [types release];
-
- NSArray *extensions = [[NSArray alloc] initWithObjects:extension, nil];
- [pasteboard setPropertyList:extensions forType:NSFilesPromisePboardType];
- [extensions release];
+ if (!wrapper) {
+ LOG_ERROR("Failed to create image file.");
+ return nil;
+ }
+
+ // FIXME: Report an error if we fail to create a file.
+ NSString *path = [[dropDestination path] stringByAppendingPathComponent:[wrapper preferredFilename]];
+ path = [[NSFileManager defaultManager] _webkit_pathWithUniqueFilenameForPath:path];
+ if (![wrapper writeToFile:path atomically:NO updateFilenames:YES])
+ LOG_ERROR("Failed to create image file via -[NSFileWrapper writeToFile:atomically:updateFilenames:] at path %@", path);
+
+ if (draggingImageURL)
+ [[NSFileManager defaultManager] _webkit_setMetadataURL:[draggingImageURL absoluteString] referrer:nil atPath:path];
+
+ return [NSArray arrayWithObject:[path lastPathComponent]];
}
-} // namespace WebKit
+@end