1/*
2 * Copyright (C) 2011 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#import "config.h"
27#import "WebDragClient.h"
28
29#if ENABLE(DRAG_SUPPORT)
30
31#import "PasteboardTypes.h"
32#import "ShareableBitmap.h"
33#import "WebCoreArgumentCoders.h"
34#import "WebPage.h"
35#import "WebPageProxyMessages.h"
36#import <WebCore/CachedImage.h>
37#import <WebCore/DOMElementInternal.h>
38#import <WebCore/DOMPrivate.h>
39#import <WebCore/DragController.h>
40#import <WebCore/Frame.h>
41#import <WebCore/FrameView.h>
42#import <WebCore/GraphicsContext.h>
43#import <WebCore/LegacyWebArchive.h>
44#import <WebCore/Page.h>
45#import <WebCore/RenderImage.h>
46#import <WebCore/ResourceHandle.h>
47#import <WebCore/StringTruncator.h>
48#import <WebKit/WebArchive.h>
49#import <WebKit/WebKitNSStringExtras.h>
50#import <WebKit/WebNSFileManagerExtras.h>
51#import <WebKit/WebNSPasteboardExtras.h>
52#import <WebKit/WebNSURLExtras.h>
53#import <WebKitSystemInterface.h>
54#import <wtf/StdLibExtras.h>
55
56using namespace WebCore;
57using namespace WebKit;
58
59namespace WebKit {
60
61static PassRefPtr<ShareableBitmap> convertImageToBitmap(NSImage *image, const IntSize& size)
62{
63    RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(size, ShareableBitmap::SupportsAlpha);
64    if (!bitmap)
65        return nullptr;
66
67    OwnPtr<GraphicsContext> graphicsContext = bitmap->createGraphicsContext();
68
69    RetainPtr<NSGraphicsContext> savedContext = [NSGraphicsContext currentContext];
70
71    [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:graphicsContext->platformContext() flipped:YES]];
72    [image drawInRect:NSMakeRect(0, 0, bitmap->size().width(), bitmap->size().height()) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1 respectFlipped:YES hints:nil];
73
74    [NSGraphicsContext setCurrentContext:savedContext.get()];
75
76    return bitmap.release();
77}
78
79void WebDragClient::startDrag(RetainPtr<NSImage> image, const IntPoint& point, const IntPoint&, Clipboard*, Frame* frame, bool linkDrag)
80{
81    IntSize bitmapSize([image.get() size]);
82    bitmapSize.scale(frame->page()->deviceScaleFactor());
83    RefPtr<ShareableBitmap> bitmap = convertImageToBitmap(image.get(), bitmapSize);
84    ShareableBitmap::Handle handle;
85    if (!bitmap || !bitmap->createHandle(handle))
86        return;
87
88    // FIXME: Seems this message should be named StartDrag, not SetDragImage.
89    m_page->send(Messages::WebPageProxy::SetDragImage(frame->view()->contentsToWindow(point), handle, linkDrag));
90}
91
92static WebCore::CachedImage* cachedImage(Element* element)
93{
94    RenderObject* renderer = element->renderer();
95    if (!renderer)
96        return 0;
97    if (!renderer->isRenderImage())
98        return 0;
99    WebCore::CachedImage* image = toRenderImage(renderer)->cachedImage();
100    if (!image || image->errorOccurred())
101        return 0;
102    return image;
103}
104
105void WebDragClient::declareAndWriteDragImage(const String& pasteboardName, DOMElement *element, NSURL *URL, NSString *title, WebCore::Frame*)
106{
107    ASSERT(element);
108    ASSERT(pasteboardName == String(NSDragPboard));
109
110    Element* coreElement = core(element);
111
112    WebCore::CachedImage* image = cachedImage(coreElement);
113
114    NSString *extension = @"";
115    if (image) {
116        extension = image->image()->filenameExtension();
117        if (![extension length])
118            return;
119    }
120
121    if (![title length]) {
122        title = [[URL path] lastPathComponent];
123        if (![title length])
124            title = [URL _web_userVisibleString];
125    }
126
127    RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(coreElement);
128
129    NSURLResponse *response = image->response().nsURLResponse();
130
131    RefPtr<SharedBuffer> imageBuffer = image->image()->data();
132    size_t imageSize = imageBuffer->size();
133    SharedMemory::Handle imageHandle;
134
135    RefPtr<SharedMemory> sharedMemoryBuffer = SharedMemory::create(imageBuffer->size());
136    memcpy(sharedMemoryBuffer->data(), imageBuffer->data(), imageSize);
137    sharedMemoryBuffer->createHandle(imageHandle, SharedMemory::ReadOnly);
138
139    RetainPtr<CFDataRef> data = archive ? archive->rawDataRepresentation() : 0;
140    SharedMemory::Handle archiveHandle;
141    size_t archiveSize = 0;
142    if (data) {
143        RefPtr<SharedBuffer> buffer = SharedBuffer::wrapNSData((NSData *)data.get());
144        RefPtr<SharedMemory> sharedMemoryBuffer = SharedMemory::create(buffer->size());
145        archiveSize = buffer->size();
146        memcpy(sharedMemoryBuffer->data(), buffer->data(), archiveSize);
147        sharedMemoryBuffer->createHandle(archiveHandle, SharedMemory::ReadOnly);
148    }
149    m_page->send(Messages::WebPageProxy::SetPromisedData(pasteboardName, imageHandle, imageSize, String([response suggestedFilename]), String(extension), String(title), String([[response URL] absoluteString]), String([URL _web_userVisibleString]), archiveHandle, archiveSize));
150}
151
152} // namespace WebKit
153
154#endif // ENABLE(DRAG_SUPPORT)
155