Bumping manifests a=b2g-bump
[gecko.git] / widget / qt / nsClipboard.cpp
blob5939a43007b5a195aa04e82a58531ae3d9ff6a72
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include <QGuiApplication>
6 #include <QMimeData>
7 #include <QString>
8 #include <QStringList>
9 #include <QByteArray>
10 #include <QImage>
11 #include <QImageWriter>
12 #include <QBuffer>
14 #include "gfxPlatform.h"
15 #include "mozilla/ArrayUtils.h"
16 #include "mozilla/gfx/2D.h"
18 #include "nsClipboard.h"
19 #include "nsISupportsPrimitives.h"
20 #include "nsXPIDLString.h"
21 #include "nsPrimitiveHelpers.h"
22 #include "nsIInputStream.h"
23 #include "nsReadableUtils.h"
24 #include "nsStringStream.h"
25 #include "nsComponentManagerUtils.h"
27 #include "imgIContainer.h"
29 using namespace mozilla;
30 using namespace mozilla::gfx;
32 NS_IMPL_ISUPPORTS(nsClipboard, nsIClipboard)
34 //-------------------------------------------------------------------------
36 // nsClipboard constructor
38 //-------------------------------------------------------------------------
39 nsClipboard::nsClipboard() : nsIClipboard(),
40 mSelectionOwner(nullptr),
41 mGlobalOwner(nullptr),
42 mSelectionTransferable(nullptr),
43 mGlobalTransferable(nullptr)
45 // No implementation needed
48 //-------------------------------------------------------------------------
50 // nsClipboard destructor
52 //-------------------------------------------------------------------------
53 nsClipboard::~nsClipboard()
57 static inline QImage::Format
58 _moz2dformat_to_qformat(SurfaceFormat aFormat)
60 switch (aFormat) {
61 case SurfaceFormat::B8G8R8A8:
62 return QImage::Format_ARGB32_Premultiplied;
63 case SurfaceFormat::B8G8R8X8:
64 return QImage::Format_ARGB32;
65 case SurfaceFormat::R5G6B5:
66 return QImage::Format_RGB16;
67 default:
68 return QImage::Format_Invalid;
72 // nsClipboard::SetNativeClipboardData ie. Copy
74 NS_IMETHODIMP
75 nsClipboard::SetNativeClipboardData( nsITransferable *aTransferable,
76 QClipboard::Mode clipboardMode )
78 if (nullptr == aTransferable)
80 NS_WARNING("nsClipboard::SetNativeClipboardData(): no transferable!");
81 return NS_ERROR_FAILURE;
84 // get flavor list that includes all flavors that can be written (including
85 // ones obtained through conversion)
86 nsCOMPtr<nsISupportsArray> flavorList;
87 nsresult rv = aTransferable->FlavorsTransferableCanExport( getter_AddRefs(flavorList) );
89 if (NS_FAILED(rv))
91 NS_WARNING("nsClipboard::SetNativeClipboardData(): no FlavorsTransferable !");
92 return NS_ERROR_FAILURE;
95 QClipboard *cb = QGuiApplication::clipboard();
96 QMimeData *mimeData = new QMimeData;
98 uint32_t flavorCount = 0;
99 flavorList->Count(&flavorCount);
100 bool imageAdded = false;
102 for (uint32_t i = 0; i < flavorCount; ++i)
104 nsCOMPtr<nsISupports> genericFlavor;
105 flavorList->GetElementAt(i,getter_AddRefs(genericFlavor));
106 nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
108 if (currentFlavor)
110 // flavorStr is the mime type
111 nsXPIDLCString flavorStr;
112 currentFlavor->ToString(getter_Copies(flavorStr));
114 // Clip is the data which will be sent to the clipboard
115 nsCOMPtr<nsISupports> clip;
116 // len is the length of the data
117 uint32_t len;
119 // Unicode text?
120 if (!strcmp(flavorStr.get(), kUnicodeMime))
122 rv = aTransferable->GetTransferData(flavorStr,getter_AddRefs(clip),&len);
123 nsCOMPtr<nsISupportsString> wideString;
124 wideString = do_QueryInterface(clip);
125 if (!wideString || NS_FAILED(rv))
126 continue;
128 nsAutoString utf16string;
129 wideString->GetData(utf16string);
130 QString str = QString::fromUtf16((const ushort*)utf16string.get());
132 // Add text to the mimeData
133 mimeData->setText(str);
136 // html?
137 else if (!strcmp(flavorStr.get(), kHTMLMime))
139 rv = aTransferable->GetTransferData(flavorStr,getter_AddRefs(clip),&len);
140 nsCOMPtr<nsISupportsString> wideString;
141 wideString = do_QueryInterface(clip);
142 if (!wideString || NS_FAILED(rv))
143 continue;
145 nsAutoString utf16string;
146 wideString->GetData(utf16string);
147 QString str = QString::fromUtf16((const ushort*)utf16string.get());
149 // Add html to the mimeData
150 mimeData->setHtml(str);
153 // image?
154 else if (!imageAdded // image is added only once to the clipboard
155 && (!strcmp(flavorStr.get(), kNativeImageMime)
156 || !strcmp(flavorStr.get(), kPNGImageMime)
157 || !strcmp(flavorStr.get(), kJPEGImageMime)
158 || !strcmp(flavorStr.get(), kJPGImageMime)
159 || !strcmp(flavorStr.get(), kGIFImageMime))
162 // Look through our transfer data for the image
163 static const char* const imageMimeTypes[] = {
164 kNativeImageMime, kPNGImageMime, kJPEGImageMime, kJPGImageMime, kGIFImageMime };
165 nsCOMPtr<nsISupportsInterfacePointer> ptrPrimitive;
166 for (uint32_t i = 0; !ptrPrimitive && i < ArrayLength(imageMimeTypes); i++)
168 aTransferable->GetTransferData(imageMimeTypes[i], getter_AddRefs(clip), &len);
169 ptrPrimitive = do_QueryInterface(clip);
172 if (!ptrPrimitive)
173 continue;
175 nsCOMPtr<nsISupports> primitiveData;
176 ptrPrimitive->GetData(getter_AddRefs(primitiveData));
177 nsCOMPtr<imgIContainer> image(do_QueryInterface(primitiveData));
178 if (!image) // Not getting an image for an image mime type!?
179 continue;
181 RefPtr<SourceSurface> surface =
182 image->GetFrame(imgIContainer::FRAME_CURRENT,
183 imgIContainer::FLAG_SYNC_DECODE);
184 if (!surface)
185 continue;
187 RefPtr<DataSourceSurface> dataSurface =
188 surface->GetDataSurface();
189 if (!dataSurface)
190 continue;
192 DataSourceSurface::MappedSurface map;
193 if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map))
194 continue;
196 QImage qImage(map.mData,
197 dataSurface->GetSize().width,
198 dataSurface->GetSize().height,
199 map.mStride,
200 _moz2dformat_to_qformat(dataSurface->GetFormat()));
202 dataSurface->Unmap();
204 // Add image to the mimeData
205 mimeData->setImageData(qImage);
206 imageAdded = true;
209 // Other flavors, adding data to clipboard "as is"
210 else
212 rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(clip), &len);
213 // nothing found?
214 if (!clip || NS_FAILED(rv))
215 continue;
217 void *primitive_data = nullptr;
218 nsPrimitiveHelpers::CreateDataFromPrimitive(flavorStr.get(), clip,
219 &primitive_data, len);
221 if (primitive_data)
223 QByteArray data ((const char *)primitive_data, len);
224 // Add data to the mimeData
225 mimeData->setData(flavorStr.get(), data);
226 nsMemory::Free(primitive_data);
232 // If we have some mime data, add it to the clipboard
233 if(!mimeData->formats().isEmpty())
234 cb->setMimeData(mimeData, clipboardMode);
235 else
236 delete mimeData;
238 return NS_OK;
241 // nsClipboard::GetNativeClipboardData ie. Paste
243 NS_IMETHODIMP
244 nsClipboard::GetNativeClipboardData(nsITransferable *aTransferable,
245 QClipboard::Mode clipboardMode)
247 if (nullptr == aTransferable)
249 NS_WARNING("GetNativeClipboardData: Transferable is null!");
250 return NS_ERROR_FAILURE;
253 // get flavor list that includes all acceptable flavors (including
254 // ones obtained through conversion)
255 nsCOMPtr<nsISupportsArray> flavorList;
256 nsresult errCode = aTransferable->FlavorsTransferableCanImport(
257 getter_AddRefs(flavorList));
259 if (NS_FAILED(errCode))
261 NS_WARNING("nsClipboard::GetNativeClipboardData(): no FlavorsTransferable!");
262 return NS_ERROR_FAILURE;
265 QClipboard *cb = QGuiApplication::clipboard();
266 const QMimeData *mimeData = cb->mimeData(clipboardMode);
268 // Walk through flavors and see which flavor matches the one being pasted
269 uint32_t flavorCount;
270 flavorList->Count(&flavorCount);
271 nsAutoCString foundFlavor;
273 for (uint32_t i = 0; i < flavorCount; ++i)
275 nsCOMPtr<nsISupports> genericFlavor;
276 flavorList->GetElementAt(i,getter_AddRefs(genericFlavor));
277 nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface( genericFlavor) );
279 if (currentFlavor)
281 nsXPIDLCString flavorStr;
282 currentFlavor->ToString(getter_Copies(flavorStr));
284 // Ok, so which flavor the data being pasted could be?
285 // Text?
286 if (!strcmp(flavorStr.get(), kUnicodeMime) && mimeData->hasText())
288 // Clipboard has text and flavor accepts text, so lets
289 // handle the data as text
290 foundFlavor = nsAutoCString(flavorStr);
292 // Get the text data from clipboard
293 QString text = mimeData->text();
294 const QChar *unicode = text.unicode();
295 // Is there a more correct way to get the size in UTF16?
296 uint32_t len = (uint32_t) 2*text.size();
298 // And then to genericDataWrapper
299 nsCOMPtr<nsISupports> genericDataWrapper;
300 nsPrimitiveHelpers::CreatePrimitiveForData(
301 foundFlavor.get(),
302 (void*)unicode,
303 len,
304 getter_AddRefs(genericDataWrapper));
305 // Data is good, set it to the transferable
306 aTransferable->SetTransferData(foundFlavor.get(),
307 genericDataWrapper,len);
308 // And thats all
309 break;
312 // html?
313 if (!strcmp(flavorStr.get(), kHTMLMime) && mimeData->hasHtml())
315 // Clipboard has text/html and flavor accepts text/html, so lets
316 // handle the data as text/html
317 foundFlavor = nsAutoCString(flavorStr);
319 // Get the text data from clipboard
320 QString html = mimeData->html();
321 const QChar *unicode = html.unicode();
322 // Is there a more correct way to get the size in UTF16?
323 uint32_t len = (uint32_t) 2*html.size();
325 // And then to genericDataWrapper
326 nsCOMPtr<nsISupports> genericDataWrapper;
327 nsPrimitiveHelpers::CreatePrimitiveForData(
328 foundFlavor.get(),
329 (void*)unicode,
330 len,
331 getter_AddRefs(genericDataWrapper));
332 // Data is good, set it to the transferable
333 aTransferable->SetTransferData(foundFlavor.get(),
334 genericDataWrapper,len);
335 // And thats all
336 break;
339 // Image?
340 if (( !strcmp(flavorStr.get(), kJPEGImageMime)
341 || !strcmp(flavorStr.get(), kJPGImageMime)
342 || !strcmp(flavorStr.get(), kPNGImageMime)
343 || !strcmp(flavorStr.get(), kGIFImageMime))
344 && mimeData->hasImage())
346 // Try to retrieve an image from clipboard
347 QImage image = cb->image();
348 if(image.isNull())
349 continue;
351 // Lets set the image format
352 QByteArray imageFormat;
353 if (!strcmp(flavorStr.get(), kJPEGImageMime) || !strcmp(flavorStr.get(), kJPGImageMime))
354 imageFormat = "jpeg";
355 else if (!strcmp(flavorStr.get(), kPNGImageMime))
356 imageFormat = "png";
357 else if (!strcmp(flavorStr.get(), kGIFImageMime))
358 imageFormat = "gif";
359 else
360 continue;
362 // Write image from clippboard to a QByteArrayBuffer
363 QByteArray imageData;
364 QBuffer imageBuffer(&imageData);
365 QImageWriter imageWriter(&imageBuffer, imageFormat);
366 if(!imageWriter.write(image))
367 continue;
369 // Add the data to inputstream
370 nsCOMPtr<nsIInputStream> byteStream;
371 NS_NewByteInputStream(getter_AddRefs(byteStream), imageData.constData(),
372 imageData.size(), NS_ASSIGNMENT_COPY);
373 // Data is good, set it to the transferable
374 aTransferable->SetTransferData(flavorStr, byteStream, sizeof(nsIInputStream*));
376 imageBuffer.close();
378 // And thats all
379 break;
382 // Other mimetype?
383 // Trying to forward the data "as is"
384 if(mimeData->hasFormat(flavorStr.get()))
386 // get the data from the clipboard
387 QByteArray clipboardData = mimeData->data(flavorStr.get());
388 // And add it to genericDataWrapper
389 nsCOMPtr<nsISupports> genericDataWrapper;
390 nsPrimitiveHelpers::CreatePrimitiveForData(
391 foundFlavor.get(),
392 (void*) clipboardData.data(),
393 clipboardData.size(),
394 getter_AddRefs(genericDataWrapper));
396 // Data is good, set it to the transferable
397 aTransferable->SetTransferData(foundFlavor.get(),
398 genericDataWrapper,clipboardData.size());
399 // And thats all
400 break;
405 return NS_OK;
408 NS_IMETHODIMP
409 nsClipboard::HasDataMatchingFlavors(const char** aFlavorList, uint32_t aLength,
410 int32_t aWhichClipboard, bool *_retval)
412 *_retval = false;
413 if (aWhichClipboard != kGlobalClipboard)
414 return NS_OK;
416 // Which kind of data in the clipboard
417 QClipboard *cb = QGuiApplication::clipboard();
418 const QMimeData *mimeData = cb->mimeData();
419 const char *flavor=nullptr;
420 QStringList formats = mimeData->formats();
421 for (uint32_t i = 0; i < aLength; ++i)
423 flavor = aFlavorList[i];
424 if (flavor)
426 QString qflavor(flavor);
428 if (strcmp(flavor,kTextMime) == 0)
430 NS_WARNING("DO NOT USE THE text/plain DATA FLAVOR ANY MORE. USE text/unicode INSTEAD");
433 // QClipboard says it has text/plain, mozilla wants to
434 // know if the data is text/unicode -> interpret text/plain to text/unicode
435 if (formats.contains(qflavor) ||
436 strcmp(flavor, kUnicodeMime) == 0)
438 // A match has been found, return'
439 *_retval = true;
440 break;
444 return NS_OK;
448 * Sets the transferable object
450 NS_IMETHODIMP
451 nsClipboard::SetData(nsITransferable *aTransferable,
452 nsIClipboardOwner *aOwner,
453 int32_t aWhichClipboard)
455 // See if we can short cut
456 if (
457 (aWhichClipboard == kGlobalClipboard
458 && aTransferable == mGlobalTransferable.get()
459 && aOwner == mGlobalOwner.get()
462 (aWhichClipboard == kSelectionClipboard
463 && aTransferable == mSelectionTransferable.get()
464 && aOwner == mSelectionOwner.get()
468 return NS_OK;
471 EmptyClipboard(aWhichClipboard);
473 QClipboard::Mode mode;
475 if (kGlobalClipboard == aWhichClipboard)
477 mGlobalOwner = aOwner;
478 mGlobalTransferable = aTransferable;
480 mode = QClipboard::Clipboard;
482 else
484 mSelectionOwner = aOwner;
485 mSelectionTransferable = aTransferable;
487 mode = QClipboard::Selection;
489 return SetNativeClipboardData( aTransferable, mode );
493 * Gets the transferable object
495 NS_IMETHODIMP
496 nsClipboard::GetData(nsITransferable *aTransferable, int32_t aWhichClipboard)
498 if (nullptr != aTransferable)
500 QClipboard::Mode mode;
501 if (kGlobalClipboard == aWhichClipboard)
503 mode = QClipboard::Clipboard;
505 else
507 mode = QClipboard::Selection;
509 return GetNativeClipboardData(aTransferable, mode);
511 else
513 NS_WARNING("nsClipboard::GetData(), aTransferable is NULL.");
515 return NS_ERROR_FAILURE;
518 NS_IMETHODIMP
519 nsClipboard::EmptyClipboard(int32_t aWhichClipboard)
521 if (aWhichClipboard == kSelectionClipboard)
523 if (mSelectionOwner)
525 mSelectionOwner->LosingOwnership(mSelectionTransferable);
526 mSelectionOwner = nullptr;
528 mSelectionTransferable = nullptr;
530 else
532 if (mGlobalOwner)
534 mGlobalOwner->LosingOwnership(mGlobalTransferable);
535 mGlobalOwner = nullptr;
537 mGlobalTransferable = nullptr;
540 return NS_OK;
543 NS_IMETHODIMP
544 nsClipboard::SupportsSelectionClipboard(bool *_retval)
546 NS_ENSURE_ARG_POINTER(_retval);
548 QClipboard *cb = QGuiApplication::clipboard();
549 if (cb->supportsSelection())
551 *_retval = true; // we support the selection clipboard
553 else
555 *_retval = false;
558 return NS_OK;
561 NS_IMETHODIMP
562 nsClipboard::SupportsFindClipboard(bool* _retval)
564 NS_ENSURE_ARG_POINTER(_retval);
566 *_retval = false;
567 return NS_OK;