cd0bf78cfffbc233a0d1faea4ac3d7620150b735
[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 "DataTransferItemListChromium.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 "PlatformSupport.h"
46 #include "Range.h"
47 #include "RenderImage.h"
48 #include "ScriptExecutionContext.h"
49 #include "markup.h"
50
51 #include <wtf/text/StringBuilder.h>
52 #include <wtf/text/WTFString.h>
53
54 namespace WebCore {
55
56 using namespace HTMLNames;
57
58 // We provide the IE clipboard types (URL and Text), and the clipboard types specified in the WHATWG Web Applications 1.0 draft
59 // see http://www.whatwg.org/specs/web-apps/current-work/ Section 6.3.5.3
60
61 static String normalizeType(const String& type)
62 {
63     String cleanType = type.stripWhiteSpace().lower();
64     if (cleanType == mimeTypeText || cleanType.startsWith(mimeTypeTextPlainEtc))
65         return mimeTypeTextPlain;
66     return cleanType;
67 }
68
69 PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy policy, DragData* dragData, Frame* frame)
70 {
71     return ClipboardChromium::create(DragAndDrop, dragData->platformData(), policy, frame);
72 }
73
74 ClipboardChromium::ClipboardChromium(ClipboardType clipboardType,
75                                      PassRefPtr<ChromiumDataObject> dataObject,
76                                      ClipboardAccessPolicy policy,
77                                      Frame* frame)
78     : Clipboard(policy, clipboardType)
79     , m_dataObject(dataObject)
80     , m_frame(frame)
81     , m_originalSequenceNumber(PlatformSupport::clipboardSequenceNumber(currentPasteboardBuffer()))
82 {
83 }
84
85 PassRefPtr<ClipboardChromium> ClipboardChromium::create(ClipboardType clipboardType,
86     PassRefPtr<ChromiumDataObject> dataObject, ClipboardAccessPolicy policy, Frame* frame)
87 {
88     return adoptRef(new ClipboardChromium(clipboardType, dataObject, policy, frame));
89 }
90
91 void ClipboardChromium::clearData(const String& type)
92 {
93     if (policy() != ClipboardWritable || !m_dataObject)
94         return;
95
96     m_dataObject->clearData(normalizeType(type));
97
98     ASSERT_NOT_REACHED();
99 }
100
101 void ClipboardChromium::clearAllData()
102 {
103     if (policy() != ClipboardWritable)
104         return;
105
106     m_dataObject->clearAll();
107 }
108
109 String ClipboardChromium::getData(const String& type, bool& success) const
110 {
111     success = false;
112     if (policy() != ClipboardReadable || !m_dataObject)
113         return String();
114
115     if (isForCopyAndPaste() && platformClipboardChanged())
116         return String();
117
118     return m_dataObject->getData(normalizeType(type), success);
119 }
120
121 bool ClipboardChromium::setData(const String& type, const String& data)
122 {
123     if (policy() != ClipboardWritable)
124         return false;
125
126     return m_dataObject->setData(normalizeType(type), data);
127 }
128
129 bool ClipboardChromium::platformClipboardChanged() const
130 {
131     return PlatformSupport::clipboardSequenceNumber(currentPasteboardBuffer()) != m_originalSequenceNumber;
132 }
133
134 // extensions beyond IE's API
135 HashSet<String> ClipboardChromium::types() const
136 {
137     HashSet<String> results;
138     if (policy() != ClipboardReadable && policy() != ClipboardTypesReadable)
139         return results;
140
141     if (!m_dataObject)
142         return results;
143
144     results = m_dataObject->types();
145
146     if (m_dataObject->containsFilenames())
147         results.add(mimeTypeFiles);
148
149     return results;
150 }
151
152 PassRefPtr<FileList> ClipboardChromium::files() const
153 {
154     if (policy() != ClipboardReadable)
155         return FileList::create();
156
157     if (!m_dataObject)
158         return FileList::create();
159
160     const Vector<String>& filenames = m_dataObject->filenames();
161     RefPtr<FileList> fileList = FileList::create();
162     for (size_t i = 0; i < filenames.size(); ++i)
163         fileList->append(File::create(filenames.at(i)));
164
165     return fileList.release();
166 }
167
168 void ClipboardChromium::setDragImage(CachedImage* image, Node* node, const IntPoint& loc)
169 {
170     if (policy() != ClipboardImageWritable && policy() != ClipboardWritable)
171         return;
172
173     if (m_dragImage)
174         m_dragImage->removeClient(this);
175     m_dragImage = image;
176     if (m_dragImage)
177         m_dragImage->addClient(this);
178
179     m_dragLoc = loc;
180     m_dragImageElement = node;
181 }
182
183 void ClipboardChromium::setDragImage(CachedImage* img, const IntPoint& loc)
184 {
185     setDragImage(img, 0, loc);
186 }
187
188 void ClipboardChromium::setDragImageElement(Node* node, const IntPoint& loc)
189 {
190     setDragImage(0, node, loc);
191 }
192
193 DragImageRef ClipboardChromium::createDragImage(IntPoint& loc) const
194 {
195     DragImageRef result = 0;
196     if (m_dragImageElement) {
197         if (m_frame) {
198             result = m_frame->nodeImage(m_dragImageElement.get());
199             loc = m_dragLoc;
200         }
201     } else if (m_dragImage) {
202         result = createDragImageFromImage(m_dragImage->image());
203         loc = m_dragLoc;
204     }
205     return result;
206 }
207
208 static CachedImage* getCachedImage(Element* element)
209 {
210     // Attempt to pull CachedImage from element
211     ASSERT(element);
212     RenderObject* renderer = element->renderer();
213     if (!renderer || !renderer->isImage())
214         return 0;
215
216     RenderImage* image = toRenderImage(renderer);
217     if (image->cachedImage() && !image->cachedImage()->errorOccurred())
218         return image->cachedImage();
219
220     return 0;
221 }
222
223 static void writeImageToDataObject(ChromiumDataObject* dataObject, Element* element,
224                                    const KURL& url)
225 {
226     // Shove image data into a DataObject for use as a file
227     CachedImage* cachedImage = getCachedImage(element);
228     if (!cachedImage || !cachedImage->imageForRenderer(element->renderer()) || !cachedImage->isLoaded())
229         return;
230
231     SharedBuffer* imageBuffer = cachedImage->imageForRenderer(element->renderer())->data();
232     if (!imageBuffer || !imageBuffer->size())
233         return;
234
235     dataObject->setFileContent(imageBuffer);
236
237     // Determine the filename for the file contents of the image.
238     String filename = cachedImage->response().suggestedFilename();
239     if (filename.isEmpty())
240         filename = url.lastPathComponent();
241     if (filename.isEmpty())
242         filename = element->getAttribute(altAttr);
243     else {
244         // Strip any existing extension. Assume that alt text is usually not a filename.
245         int extensionIndex = filename.reverseFind('.');
246         if (extensionIndex != -1)
247             filename.truncate(extensionIndex);
248     }
249     filename = ClipboardChromium::validateFileName(filename, dataObject);
250
251     String extension = MIMETypeRegistry::getPreferredExtensionForMIMEType(
252         cachedImage->response().mimeType());
253     dataObject->setFileExtension(extension.isEmpty() ? emptyString() : "." + extension);
254
255     dataObject->setFileContentFilename(filename + dataObject->fileExtension());
256 }
257
258 void ClipboardChromium::declareAndWriteDragImage(Element* element, const KURL& url, const String& title, Frame* frame)
259 {
260     if (!m_dataObject)
261         return;
262
263     m_dataObject->setData(mimeTypeURL, url);
264     m_dataObject->setUrlTitle(title);
265
266     // Write the bytes in the image to the file format.
267     writeImageToDataObject(m_dataObject.get(), element, url);
268
269     // Put img tag on the clipboard referencing the image
270     m_dataObject->setData(mimeTypeTextHTML, createMarkup(element, IncludeNode, 0, ResolveAllURLs));
271 }
272
273 void ClipboardChromium::writeURL(const KURL& url, const String& title, Frame*)
274 {
275     if (!m_dataObject)
276         return;
277     ASSERT(!url.isEmpty());
278     m_dataObject->setData(mimeTypeURL, url);
279     m_dataObject->setUrlTitle(title);
280
281     // The URL can also be used as plain text.
282     m_dataObject->setData(mimeTypeTextPlain, url.string());
283
284     // The URL can also be used as an HTML fragment.
285     m_dataObject->setData(mimeTypeTextHTML, urlToMarkup(url, title));
286     m_dataObject->setHtmlBaseUrl(url);
287 }
288
289 void ClipboardChromium::writeRange(Range* selectedRange, Frame* frame)
290 {
291     ASSERT(selectedRange);
292     if (!m_dataObject)
293          return;
294
295     m_dataObject->setData(mimeTypeTextHTML, createMarkup(selectedRange, 0, AnnotateForInterchange, false, ResolveNonLocalURLs));
296     m_dataObject->setHtmlBaseUrl(frame->document()->url());
297
298     String str = frame->editor()->selectedText();
299 #if OS(WINDOWS)
300     replaceNewlinesWithWindowsStyleNewlines(str);
301 #endif
302     replaceNBSPWithSpace(str);
303     m_dataObject->setData(mimeTypeTextPlain, str);
304 }
305
306 void ClipboardChromium::writePlainText(const String& text)
307 {
308     if (!m_dataObject)
309         return;
310
311     String str = text;
312 #if OS(WINDOWS)
313     replaceNewlinesWithWindowsStyleNewlines(str);
314 #endif
315     replaceNBSPWithSpace(str);
316     m_dataObject->setData(mimeTypeTextPlain, str);
317 }
318
319 bool ClipboardChromium::hasData()
320 {
321     ASSERT(isForDragAndDrop());
322     if (!m_dataObject)
323         return false;
324
325     return m_dataObject->hasData();
326 }
327
328 #if ENABLE(DATA_TRANSFER_ITEMS)
329 PassRefPtr<DataTransferItemList> ClipboardChromium::items()
330 {
331     RefPtr<DataTransferItemListChromium> items = DataTransferItemListChromium::create(this, m_frame->document()->scriptExecutionContext());
332
333     if (!m_dataObject)
334         return items;
335
336     if (isForCopyAndPaste() && policy() == ClipboardReadable) {
337         // Iterate through the types and add them.
338         HashSet<String> types = m_dataObject->types();
339         for (HashSet<String>::const_iterator it = types.begin(); it != types.end(); ++it)
340             items->addPasteboardItem(*it);
341     }
342     return items;
343 }
344 #endif
345
346 } // namespace WebCore