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>
11 #include <QImageWriter>
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
)
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
;
68 return QImage::Format_Invalid
;
72 // nsClipboard::SetNativeClipboardData ie. Copy
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
) );
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
));
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
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
))
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
);
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
))
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
);
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
);
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!?
181 RefPtr
<SourceSurface
> surface
=
182 image
->GetFrame(imgIContainer::FRAME_CURRENT
,
183 imgIContainer::FLAG_SYNC_DECODE
);
187 RefPtr
<DataSourceSurface
> dataSurface
=
188 surface
->GetDataSurface();
192 DataSourceSurface::MappedSurface map
;
193 if (!dataSurface
->Map(DataSourceSurface::MapType::READ
, &map
))
196 QImage
qImage(map
.mData
,
197 dataSurface
->GetSize().width
,
198 dataSurface
->GetSize().height
,
200 _moz2dformat_to_qformat(dataSurface
->GetFormat()));
202 dataSurface
->Unmap();
204 // Add image to the mimeData
205 mimeData
->setImageData(qImage
);
209 // Other flavors, adding data to clipboard "as is"
212 rv
= aTransferable
->GetTransferData(flavorStr
.get(), getter_AddRefs(clip
), &len
);
214 if (!clip
|| NS_FAILED(rv
))
217 void *primitive_data
= nullptr;
218 nsPrimitiveHelpers::CreateDataFromPrimitive(flavorStr
.get(), clip
,
219 &primitive_data
, len
);
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
);
241 // nsClipboard::GetNativeClipboardData ie. Paste
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
) );
281 nsXPIDLCString flavorStr
;
282 currentFlavor
->ToString(getter_Copies(flavorStr
));
284 // Ok, so which flavor the data being pasted could be?
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(
304 getter_AddRefs(genericDataWrapper
));
305 // Data is good, set it to the transferable
306 aTransferable
->SetTransferData(foundFlavor
.get(),
307 genericDataWrapper
,len
);
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(
331 getter_AddRefs(genericDataWrapper
));
332 // Data is good, set it to the transferable
333 aTransferable
->SetTransferData(foundFlavor
.get(),
334 genericDataWrapper
,len
);
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();
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
))
357 else if (!strcmp(flavorStr
.get(), kGIFImageMime
))
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
))
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
*));
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(
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());
409 nsClipboard::HasDataMatchingFlavors(const char** aFlavorList
, uint32_t aLength
,
410 int32_t aWhichClipboard
, bool *_retval
)
413 if (aWhichClipboard
!= kGlobalClipboard
)
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
];
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'
448 * Sets the transferable object
451 nsClipboard::SetData(nsITransferable
*aTransferable
,
452 nsIClipboardOwner
*aOwner
,
453 int32_t aWhichClipboard
)
455 // See if we can short cut
457 (aWhichClipboard
== kGlobalClipboard
458 && aTransferable
== mGlobalTransferable
.get()
459 && aOwner
== mGlobalOwner
.get()
462 (aWhichClipboard
== kSelectionClipboard
463 && aTransferable
== mSelectionTransferable
.get()
464 && aOwner
== mSelectionOwner
.get()
471 EmptyClipboard(aWhichClipboard
);
473 QClipboard::Mode mode
;
475 if (kGlobalClipboard
== aWhichClipboard
)
477 mGlobalOwner
= aOwner
;
478 mGlobalTransferable
= aTransferable
;
480 mode
= QClipboard::Clipboard
;
484 mSelectionOwner
= aOwner
;
485 mSelectionTransferable
= aTransferable
;
487 mode
= QClipboard::Selection
;
489 return SetNativeClipboardData( aTransferable
, mode
);
493 * Gets the transferable object
496 nsClipboard::GetData(nsITransferable
*aTransferable
, int32_t aWhichClipboard
)
498 if (nullptr != aTransferable
)
500 QClipboard::Mode mode
;
501 if (kGlobalClipboard
== aWhichClipboard
)
503 mode
= QClipboard::Clipboard
;
507 mode
= QClipboard::Selection
;
509 return GetNativeClipboardData(aTransferable
, mode
);
513 NS_WARNING("nsClipboard::GetData(), aTransferable is NULL.");
515 return NS_ERROR_FAILURE
;
519 nsClipboard::EmptyClipboard(int32_t aWhichClipboard
)
521 if (aWhichClipboard
== kSelectionClipboard
)
525 mSelectionOwner
->LosingOwnership(mSelectionTransferable
);
526 mSelectionOwner
= nullptr;
528 mSelectionTransferable
= nullptr;
534 mGlobalOwner
->LosingOwnership(mGlobalTransferable
);
535 mGlobalOwner
= nullptr;
537 mGlobalTransferable
= nullptr;
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
562 nsClipboard::SupportsFindClipboard(bool* _retval
)
564 NS_ENSURE_ARG_POINTER(_retval
);