5bc26f74d802f9ba804f319a25ad2e9c62e19647
[WebKit-https.git] / Source / WebCore / platform / chromium / ClipboardChromium.cpp
1 /*
2  * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
3  * Copyright (C) 2008, 2009 Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "ClipboardChromium.h"
29
30 #include "CachedImage.h"
31 #include "ChromiumDataObject.h"
32 #include "ClipboardMimeTypes.h"
33 #include "ClipboardUtilitiesChromium.h"
34 #include "DataTransferItemsChromium.h"
35 #include "Document.h"
36 #include "DragData.h"
37 #include "Element.h"
38 #include "FileList.h"
39 #include "Frame.h"
40 #include "HTMLNames.h"
41 #include "HTMLParserIdioms.h"
42 #include "Image.h"
43 #include "MIMETypeRegistry.h"
44 #include "NamedNodeMap.h"
45 #include "Range.h"
46 #include "RenderImage.h"
47 #include "ScriptExecutionContext.h"
48 #include "markup.h"
49
50 #include <wtf/text/StringBuilder.h>
51 #include <wtf/text/WTFString.h>
52
53 namespace WebCore {
54
55 using namespace HTMLNames;
56
57 // We provide the IE clipboard types (URL and Text), and the clipboard types specified in the WHATWG Web Applications 1.0 draft
58 // see http://www.whatwg.org/specs/web-apps/current-work/ Section 6.3.5.3
59
60 static String normalizeType(const String& type)
61 {
62     String cleanType = type.stripWhiteSpace().lower();
63     if (cleanType == mimeTypeText || cleanType.startsWith(mimeTypeTextPlainEtc))
64         return mimeTypeTextPlain;
65     return cleanType;
66 }
67
68 PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy policy, DragData* dragData, Frame* frame)
69 {
70     return ClipboardChromium::create(DragAndDrop, dragData->platformData(), policy, frame);
71 }
72
73 ClipboardChromium::ClipboardChromium(ClipboardType clipboardType,
74                                      PassRefPtr<ChromiumDataObject> dataObject,
75                                      ClipboardAccessPolicy policy,
76                                      Frame* frame)
77     : Clipboard(policy, clipboardType)
78     , m_dataObject(dataObject)
79     , m_frame(frame)
80 {
81 }
82
83 PassRefPtr<ClipboardChromium> ClipboardChromium::create(ClipboardType clipboardType,
84     PassRefPtr<ChromiumDataObject> dataObject, ClipboardAccessPolicy policy, Frame* frame)
85 {
86     return adoptRef(new ClipboardChromium(clipboardType, dataObject, policy, frame));
87 }
88
89 void ClipboardChromium::clearData(const String& type)
90 {
91     if (policy() != ClipboardWritable || !m_dataObject)
92         return;
93
94     m_dataObject->clearData(normalizeType(type));
95
96     ASSERT_NOT_REACHED();
97 }
98
99 void ClipboardChromium::clearAllData()
100 {
101     if (policy() != ClipboardWritable)
102         return;
103
104     m_dataObject->clearAll();
105 }
106
107 String ClipboardChromium::getData(const String& type, bool& success) const
108 {
109     success = false;
110     if (policy() != ClipboardReadable || !m_dataObject)
111         return String();
112
113     return m_dataObject->getData(normalizeType(type), success);
114 }
115
116 bool ClipboardChromium::setData(const String& type, const String& data)
117 {
118     if (policy() != ClipboardWritable)
119         return false;
120
121     return m_dataObject->setData(normalizeType(type), data);
122 }
123
124 // extensions beyond IE's API
125 HashSet<String> ClipboardChromium::types() const
126 {
127     HashSet<String> results;
128     if (policy() != ClipboardReadable && policy() != ClipboardTypesReadable)
129         return results;
130
131     if (!m_dataObject)
132         return results;
133
134     results = m_dataObject->types();
135
136     if (m_dataObject->containsFilenames())
137         results.add(mimeTypeFiles);
138
139     return results;
140 }
141
142 PassRefPtr<FileList> ClipboardChromium::files() const
143 {
144     if (policy() != ClipboardReadable)
145         return FileList::create();
146
147     if (!m_dataObject)
148         return FileList::create();
149
150     const Vector<String>& filenames = m_dataObject->filenames();
151     RefPtr<FileList> fileList = FileList::create();
152     for (size_t i = 0; i < filenames.size(); ++i)
153         fileList->append(File::create(filenames.at(i)));
154
155     return fileList.release();
156 }
157
158 void ClipboardChromium::setDragImage(CachedImage* image, Node* node, const IntPoint& loc)
159 {
160     if (policy() != ClipboardImageWritable && policy() != ClipboardWritable)
161         return;
162
163     if (m_dragImage)
164         m_dragImage->removeClient(this);
165     m_dragImage = image;
166     if (m_dragImage)
167         m_dragImage->addClient(this);
168
169     m_dragLoc = loc;
170     m_dragImageElement = node;
171 }
172
173 void ClipboardChromium::setDragImage(CachedImage* img, const IntPoint& loc)
174 {
175     setDragImage(img, 0, loc);
176 }
177
178 void ClipboardChromium::setDragImageElement(Node* node, const IntPoint& loc)
179 {
180     setDragImage(0, node, loc);
181 }
182
183 DragImageRef ClipboardChromium::createDragImage(IntPoint& loc) const
184 {
185     DragImageRef result = 0;
186     if (m_dragImageElement) {
187         if (m_frame) {
188             result = m_frame->nodeImage(m_dragImageElement.get());
189             loc = m_dragLoc;
190         }
191     } else if (m_dragImage) {
192         result = createDragImageFromImage(m_dragImage->image());
193         loc = m_dragLoc;
194     }
195     return result;
196 }
197
198 static CachedImage* getCachedImage(Element* element)
199 {
200     // Attempt to pull CachedImage from element
201     ASSERT(element);
202     RenderObject* renderer = element->renderer();
203     if (!renderer || !renderer->isImage())
204         return 0;
205
206     RenderImage* image = toRenderImage(renderer);
207     if (image->cachedImage() && !image->cachedImage()->errorOccurred())
208         return image->cachedImage();
209
210     return 0;
211 }
212
213 static void writeImageToDataObject(ChromiumDataObject* dataObject, Element* element,
214                                    const KURL& url)
215 {
216     // Shove image data into a DataObject for use as a file
217     CachedImage* cachedImage = getCachedImage(element);
218     if (!cachedImage || !cachedImage->image() || !cachedImage->isLoaded())
219         return;
220
221     SharedBuffer* imageBuffer = cachedImage->image()->data();
222     if (!imageBuffer || !imageBuffer->size())
223         return;
224
225     dataObject->setFileContent(imageBuffer);
226
227     // Determine the filename for the file contents of the image.  We try to
228     // use the alt tag if one exists, otherwise we fall back on the suggested
229     // filename in the http header, and finally we resort to using the filename
230     // in the URL.
231     String extension = MIMETypeRegistry::getPreferredExtensionForMIMEType(
232         cachedImage->response().mimeType());
233     dataObject->setFileExtension(extension.isEmpty() ? emptyString() : "." + extension);
234     String title = element->getAttribute(altAttr);
235     if (title.isEmpty())
236         title = cachedImage->response().suggestedFilename();
237
238     title = ClipboardChromium::validateFileName(title, dataObject);
239     dataObject->setFileContentFilename(title + dataObject->fileExtension());
240 }
241
242 void ClipboardChromium::declareAndWriteDragImage(Element* element, const KURL& url, const String& title, Frame* frame)
243 {
244     if (!m_dataObject)
245         return;
246
247     m_dataObject->setData(mimeTypeURL, url);
248     m_dataObject->setUrlTitle(title);
249
250     // Write the bytes in the image to the file format.
251     writeImageToDataObject(m_dataObject.get(), element, url);
252
253     AtomicString imageURL = element->getAttribute(srcAttr);
254     if (imageURL.isEmpty())
255         return;
256
257     KURL fullURL = frame->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(imageURL));
258     if (fullURL.isEmpty())
259         return;
260
261     // Put img tag on the clipboard referencing the image
262     m_dataObject->setData(mimeTypeTextHTML, imageToMarkup(fullURL, element));
263 }
264
265 void ClipboardChromium::writeURL(const KURL& url, const String& title, Frame*)
266 {
267     if (!m_dataObject)
268         return;
269     ASSERT(!url.isEmpty());
270     m_dataObject->setData(mimeTypeURL, url);
271     m_dataObject->setUrlTitle(title);
272
273     // The URL can also be used as plain text.
274     m_dataObject->setData(mimeTypeTextPlain, url.string());
275
276     // The URL can also be used as an HTML fragment.
277     m_dataObject->setData(mimeTypeTextHTML, urlToMarkup(url, title));
278     m_dataObject->setHtmlBaseUrl(url);
279 }
280
281 void ClipboardChromium::writeRange(Range* selectedRange, Frame* frame)
282 {
283     ASSERT(selectedRange);
284     if (!m_dataObject)
285          return;
286
287     m_dataObject->setData(mimeTypeTextHTML, createMarkup(selectedRange, 0, AnnotateForInterchange, false, AbsoluteURLs));
288     m_dataObject->setHtmlBaseUrl(frame->document()->url());
289
290     String str = frame->editor()->selectedText();
291 #if OS(WINDOWS)
292     replaceNewlinesWithWindowsStyleNewlines(str);
293 #endif
294     replaceNBSPWithSpace(str);
295     m_dataObject->setData(mimeTypeTextPlain, str);
296 }
297
298 void ClipboardChromium::writePlainText(const String& text)
299 {
300     if (!m_dataObject)
301         return;
302
303     String str = text;
304 #if OS(WINDOWS)
305     replaceNewlinesWithWindowsStyleNewlines(str);
306 #endif
307     replaceNBSPWithSpace(str);
308     m_dataObject->setData(mimeTypeTextPlain, str);
309 }
310
311 bool ClipboardChromium::hasData()
312 {
313     if (!m_dataObject)
314         return false;
315
316     return m_dataObject->hasData();
317 }
318
319 #if ENABLE(DATA_TRANSFER_ITEMS)
320 PassRefPtr<DataTransferItems> ClipboardChromium::items()
321 {
322     RefPtr<DataTransferItemsChromium> items = DataTransferItemsChromium::create(this, m_frame->document()->scriptExecutionContext());
323
324     if (!m_dataObject)
325         return items;
326
327     if (isForCopyAndPaste() && policy() == ClipboardReadable) {
328         // Iterate through the types and add them.
329         HashSet<String> types = m_dataObject->types();
330         for (HashSet<String>::const_iterator it = types.begin(); it != types.end(); ++it)
331             items->addPasteboardItem(*it);
332     }
333     return items;
334 }
335 #endif
336
337 } // namespace WebCore