1 /*
2 * Copyright (C) 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
4 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
5 * Copyright (C) 2010 Sencha, Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "config.h"
30 #include "ClipboardQt.h"
31
32 #include "CachedImage.h"
33 #include "Document.h"
34 #include "DragData.h"
35 #include "Element.h"
36 #include "FileList.h"
37 #include "Frame.h"
38 #include "HTMLNames.h"
39 #include "HTMLParserIdioms.h"
40 #include "Image.h"
41 #include "IntPoint.h"
42 #include "KURL.h"
43 #include "NotImplemented.h"
44 #include "PlatformString.h"
45 #include "Range.h"
46 #include "RenderImage.h"
47 #include "markup.h"
48 #include <wtf/text/StringHash.h>
49
50 #include <QApplication>
51 #include <QClipboard>
52 #include <QList>
53 #include <QMimeData>
54 #include <QStringList>
55 #include <QTextCodec>
56 #include <QUrl>
57 #include <qdebug.h>
58
59 #define methodDebug() qDebug("ClipboardQt: %s", __FUNCTION__)
60
61 namespace WebCore {
62
isTextMimeType(const String & type)63 static bool isTextMimeType(const String& type)
64 {
65 return type == "text/plain" || type.startsWith("text/plain;");
66 }
67
isHtmlMimeType(const String & type)68 static bool isHtmlMimeType(const String& type)
69 {
70 return type == "text/html" || type.startsWith("text/html;");
71 }
72
create(ClipboardAccessPolicy policy,DragData * dragData,Frame *)73 PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy policy, DragData* dragData, Frame*)
74 {
75 return ClipboardQt::create(policy, dragData->platformData());
76 }
77
ClipboardQt(ClipboardAccessPolicy policy,const QMimeData * readableClipboard)78 ClipboardQt::ClipboardQt(ClipboardAccessPolicy policy, const QMimeData* readableClipboard)
79 : Clipboard(policy, DragAndDrop)
80 , m_readableData(readableClipboard)
81 , m_writableData(0)
82 {
83 Q_ASSERT(policy == ClipboardReadable || policy == ClipboardTypesReadable);
84 }
85
ClipboardQt(ClipboardAccessPolicy policy,ClipboardType clipboardType)86 ClipboardQt::ClipboardQt(ClipboardAccessPolicy policy, ClipboardType clipboardType)
87 : Clipboard(policy, clipboardType)
88 , m_readableData(0)
89 , m_writableData(0)
90 {
91 Q_ASSERT(policy == ClipboardReadable || policy == ClipboardWritable || policy == ClipboardNumb);
92
93 #ifndef QT_NO_CLIPBOARD
94 if (policy != ClipboardWritable) {
95 Q_ASSERT(isForCopyAndPaste());
96 m_readableData = QApplication::clipboard()->mimeData();
97 }
98 #endif
99 }
100
~ClipboardQt()101 ClipboardQt::~ClipboardQt()
102 {
103 if (m_writableData && isForCopyAndPaste())
104 m_writableData = 0;
105 else
106 delete m_writableData;
107 m_readableData = 0;
108 }
109
clearData(const String & type)110 void ClipboardQt::clearData(const String& type)
111 {
112 if (policy() != ClipboardWritable)
113 return;
114
115 if (m_writableData) {
116 m_writableData->removeFormat(type);
117 if (m_writableData->formats().isEmpty()) {
118 if (isForDragAndDrop())
119 delete m_writableData;
120 m_writableData = 0;
121 }
122 }
123 #ifndef QT_NO_CLIPBOARD
124 if (isForCopyAndPaste())
125 QApplication::clipboard()->setMimeData(m_writableData);
126 #endif
127 }
128
clearAllData()129 void ClipboardQt::clearAllData()
130 {
131 if (policy() != ClipboardWritable)
132 return;
133
134 #ifndef QT_NO_CLIPBOARD
135 if (isForCopyAndPaste())
136 QApplication::clipboard()->setMimeData(0);
137 else
138 #endif
139 delete m_writableData;
140 m_writableData = 0;
141 }
142
getData(const String & type,bool & success) const143 String ClipboardQt::getData(const String& type, bool& success) const
144 {
145
146 if (policy() != ClipboardReadable) {
147 success = false;
148 return String();
149 }
150
151 if (isHtmlMimeType(type) && m_readableData->hasHtml()) {
152 success = true;
153 return m_readableData->html();
154 }
155
156 if (isTextMimeType(type) && m_readableData->hasText()) {
157 success = true;
158 return m_readableData->text();
159 }
160
161 ASSERT(m_readableData);
162 QByteArray rawData = m_readableData->data(type);
163 QString data = QTextCodec::codecForName("UTF-16")->toUnicode(rawData);
164 success = !data.isEmpty();
165 return data;
166 }
167
setData(const String & type,const String & data)168 bool ClipboardQt::setData(const String& type, const String& data)
169 {
170 if (policy() != ClipboardWritable)
171 return false;
172
173 if (!m_writableData)
174 m_writableData = new QMimeData;
175
176 if (isTextMimeType(type))
177 m_writableData->setText(QString(data));
178 else if (isHtmlMimeType(type))
179 m_writableData->setHtml(QString(data));
180 else {
181 QByteArray array(reinterpret_cast<const char*>(data.characters()), data.length() * 2);
182 m_writableData->setData(QString(type), array);
183 }
184
185 #ifndef QT_NO_CLIPBOARD
186 if (isForCopyAndPaste())
187 QApplication::clipboard()->setMimeData(m_writableData);
188 #endif
189 return true;
190 }
191
192 // extensions beyond IE's API
types() const193 HashSet<String> ClipboardQt::types() const
194 {
195 if (policy() != ClipboardReadable && policy() != ClipboardTypesReadable)
196 return HashSet<String>();
197
198 ASSERT(m_readableData);
199 HashSet<String> result;
200 QStringList formats = m_readableData->formats();
201 for (int i = 0; i < formats.count(); ++i)
202 result.add(formats.at(i));
203 return result;
204 }
205
files() const206 PassRefPtr<FileList> ClipboardQt::files() const
207 {
208 if (policy() != ClipboardReadable || !m_readableData->hasUrls())
209 return FileList::create();
210
211 RefPtr<FileList> fileList = FileList::create();
212 QList<QUrl> urls = m_readableData->urls();
213
214 for (int i = 0; i < urls.size(); i++) {
215 QUrl url = urls[i];
216 if (url.scheme() != QLatin1String("file"))
217 continue;
218 fileList->append(File::create(url.toLocalFile()));
219 }
220
221 return fileList.release();
222 }
223
setDragImage(CachedImage * image,const IntPoint & point)224 void ClipboardQt::setDragImage(CachedImage* image, const IntPoint& point)
225 {
226 setDragImage(image, 0, point);
227 }
228
setDragImageElement(Node * node,const IntPoint & point)229 void ClipboardQt::setDragImageElement(Node* node, const IntPoint& point)
230 {
231 setDragImage(0, node, point);
232 }
233
setDragImage(CachedImage * image,Node * node,const IntPoint & loc)234 void ClipboardQt::setDragImage(CachedImage* image, Node *node, const IntPoint &loc)
235 {
236 if (policy() != ClipboardImageWritable && policy() != ClipboardWritable)
237 return;
238
239 if (m_dragImage)
240 m_dragImage->removeClient(this);
241 m_dragImage = image;
242 if (m_dragImage)
243 m_dragImage->addClient(this);
244
245 m_dragLoc = loc;
246 m_dragImageElement = node;
247 }
248
createDragImage(IntPoint & dragLoc) const249 DragImageRef ClipboardQt::createDragImage(IntPoint& dragLoc) const
250 {
251 if (!m_dragImage)
252 return 0;
253 dragLoc = m_dragLoc;
254 return m_dragImage->image()->nativeImageForCurrentFrame();
255 }
256
257
getCachedImage(Element * element)258 static CachedImage* getCachedImage(Element* element)
259 {
260 // Attempt to pull CachedImage from element
261 ASSERT(element);
262 RenderObject* renderer = element->renderer();
263 if (!renderer || !renderer->isImage())
264 return 0;
265
266 RenderImage* image = toRenderImage(renderer);
267 if (image->cachedImage() && !image->cachedImage()->errorOccurred())
268 return image->cachedImage();
269
270 return 0;
271 }
272
declareAndWriteDragImage(Element * element,const KURL & url,const String & title,Frame * frame)273 void ClipboardQt::declareAndWriteDragImage(Element* element, const KURL& url, const String& title, Frame* frame)
274 {
275 ASSERT(frame);
276
277 // WebCore::writeURL(m_writableDataObject.get(), url, title, true, false);
278 if (!m_writableData)
279 m_writableData = new QMimeData;
280
281 CachedImage* cachedImage = getCachedImage(element);
282 if (!cachedImage || !cachedImage->image() || !cachedImage->isLoaded())
283 return;
284 QPixmap* pixmap = cachedImage->image()->nativeImageForCurrentFrame();
285 if (pixmap)
286 m_writableData->setImageData(*pixmap);
287
288 AtomicString imageURL = element->getAttribute(HTMLNames::srcAttr);
289 if (imageURL.isEmpty())
290 return;
291
292 KURL fullURL = frame->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(imageURL));
293 if (fullURL.isEmpty())
294 return;
295
296 QList<QUrl> urls;
297 urls.append(url);
298 urls.append(fullURL);
299
300 m_writableData->setText(title);
301 m_writableData->setUrls(urls);
302 m_writableData->setHtml(createMarkup(element, IncludeNode, 0, AbsoluteURLs));
303 #ifndef QT_NO_CLIPBOARD
304 if (isForCopyAndPaste())
305 QApplication::clipboard()->setMimeData(m_writableData);
306 #endif
307 }
308
writeURL(const KURL & url,const String & title,Frame * frame)309 void ClipboardQt::writeURL(const KURL& url, const String& title, Frame* frame)
310 {
311 ASSERT(frame);
312
313 QList<QUrl> urls;
314 urls.append(frame->document()->completeURL(url.string()));
315 if (!m_writableData)
316 m_writableData = new QMimeData;
317 m_writableData->setUrls(urls);
318 m_writableData->setText(title);
319 #ifndef QT_NO_CLIPBOARD
320 if (isForCopyAndPaste())
321 QApplication::clipboard()->setMimeData(m_writableData);
322 #endif
323 }
324
writeRange(Range * range,Frame * frame)325 void ClipboardQt::writeRange(Range* range, Frame* frame)
326 {
327 ASSERT(range);
328 ASSERT(frame);
329
330 if (!m_writableData)
331 m_writableData = new QMimeData;
332 QString text = frame->editor()->selectedText();
333 text.replace(QChar(0xa0), QLatin1Char(' '));
334 m_writableData->setText(text);
335 m_writableData->setHtml(createMarkup(range, 0, AnnotateForInterchange, false, AbsoluteURLs));
336 #ifndef QT_NO_CLIPBOARD
337 if (isForCopyAndPaste())
338 QApplication::clipboard()->setMimeData(m_writableData);
339 #endif
340 }
341
writePlainText(const String & str)342 void ClipboardQt::writePlainText(const String& str)
343 {
344 if (!m_writableData)
345 m_writableData = new QMimeData;
346 QString text = str;
347 text.replace(QChar(0xa0), QLatin1Char(' '));
348 m_writableData->setText(text);
349 #ifndef QT_NO_CLIPBOARD
350 if (isForCopyAndPaste())
351 QApplication::clipboard()->setMimeData(m_writableData);
352 #endif
353 }
354
hasData()355 bool ClipboardQt::hasData()
356 {
357 const QMimeData *data = m_readableData ? m_readableData : m_writableData;
358 if (!data)
359 return false;
360 return data->formats().count() > 0;
361 }
362
363 }
364