2011-06-01 Daniel Cheng <dcheng@chromium.org>
[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.
228     String filename = cachedImage->response().suggestedFilename();
229     if (filename.isEmpty())
230         filename = url.lastPathComponent();
231     if (filename.isEmpty())
232         filename = element->getAttribute(altAttr);
233     else {
234         // Strip any existing extension. Assume that alt text is usually not a filename.
235         int extensionIndex = filename.reverseFind('.');
236         if (extensionIndex != -1)
237             filename.truncate(extensionIndex);
238     }
239     filename = ClipboardChromium::validateFileName(filename, dataObject);
240
241     String extension = MIMETypeRegistry::getPreferredExtensionForMIMEType(
242         cachedImage->response().mimeType());
243     dataObject->setFileExtension(extension.isEmpty() ? emptyString() : "." + extension);
244
245     dataObject->setFileContentFilename(filename + dataObject->fileExtension());
246 }
247
248 void ClipboardChromium::declareAndWriteDragImage(Element* element, const KURL& url, const String& title, Frame* frame)
249 {
250     if (!m_dataObject)
251         return;
252
253     m_dataObject->setData(mimeTypeURL, url);
254     m_dataObject->setUrlTitle(title);
255
256     // Write the bytes in the image to the file format.
257     writeImageToDataObject(m_dataObject.get(), element, url);
258
259     AtomicString imageURL = element->getAttribute(srcAttr);
260     if (imageURL.isEmpty())
261         return;
262
263     KURL fullURL = frame->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(imageURL));
264     if (fullURL.isEmpty())
265         return;
266
267     // Put img tag on the clipboard referencing the image
268     m_dataObject->setData(mimeTypeTextHTML, imageToMarkup(fullURL, element));
269 }
270
271 void ClipboardChromium::writeURL(const KURL& url, const String& title, Frame*)
272 {
273     if (!m_dataObject)
274         return;
275     ASSERT(!url.isEmpty());
276     m_dataObject->setData(mimeTypeURL, url);
277     m_dataObject->setUrlTitle(title);
278
279     // The URL can also be used as plain text.
280     m_dataObject->setData(mimeTypeTextPlain, url.string());
281
282     // The URL can also be used as an HTML fragment.
283     m_dataObject->setData(mimeTypeTextHTML, urlToMarkup(url, title));
284     m_dataObject->setHtmlBaseUrl(url);
285 }
286
287 void ClipboardChromium::writeRange(Range* selectedRange, Frame* frame)
288 {
289     ASSERT(selectedRange);
290     if (!m_dataObject)
291          return;
292
293     m_dataObject->setData(mimeTypeTextHTML, createMarkup(selectedRange, 0, AnnotateForInterchange, false, AbsoluteURLs));
294     m_dataObject->setHtmlBaseUrl(frame->document()->url());
295
296     String str = frame->editor()->selectedText();
297 #if OS(WINDOWS)
298     replaceNewlinesWithWindowsStyleNewlines(str);
299 #endif
300     replaceNBSPWithSpace(str);
301     m_dataObject->setData(mimeTypeTextPlain, str);
302 }
303
304 void ClipboardChromium::writePlainText(const String& text)
305 {
306     if (!m_dataObject)
307         return;
308
309     String str = text;
310 #if OS(WINDOWS)
311     replaceNewlinesWithWindowsStyleNewlines(str);
312 #endif
313     replaceNBSPWithSpace(str);
314     m_dataObject->setData(mimeTypeTextPlain, str);
315 }
316
317 bool ClipboardChromium::hasData()
318 {
319     if (!m_dataObject)
320         return false;
321
322     return m_dataObject->hasData();
323 }
324
325 #if ENABLE(DATA_TRANSFER_ITEMS)
326 PassRefPtr<DataTransferItems> ClipboardChromium::items()
327 {
328     RefPtr<DataTransferItemsChromium> items = DataTransferItemsChromium::create(this, m_frame->document()->scriptExecutionContext());
329
330     if (!m_dataObject)
331         return items;
332
333     if (isForCopyAndPaste() && policy() == ClipboardReadable) {
334         // Iterate through the types and add them.
335         HashSet<String> types = m_dataObject->types();
336         for (HashSet<String>::const_iterator it = types.begin(); it != types.end(); ++it)
337             items->addPasteboardItem(*it);
338     }
339     return items;
340 }
341 #endif
342
343 } // namespace WebCore