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 <QApplication>
11 #include <QImageWriter>
14 #include "mozilla/Util.h"
16 #include "nsClipboard.h"
17 #include "nsISupportsPrimitives.h"
18 #include "nsXPIDLString.h"
19 #include "nsPrimitiveHelpers.h"
20 #include "nsIInputStream.h"
21 #include "nsReadableUtils.h"
22 #include "nsStringStream.h"
23 #include "nsComponentManagerUtils.h"
25 #include "imgIContainer.h"
26 #include "gfxImageSurface.h"
28 using namespace mozilla
;
30 NS_IMPL_ISUPPORTS1(nsClipboard
, nsIClipboard
)
32 //-------------------------------------------------------------------------
34 // nsClipboard constructor
36 //-------------------------------------------------------------------------
37 nsClipboard::nsClipboard() : nsIClipboard(),
38 mSelectionOwner(nullptr),
39 mGlobalOwner(nullptr),
40 mSelectionTransferable(nullptr),
41 mGlobalTransferable(nullptr)
43 // No implementation needed
46 //-------------------------------------------------------------------------
48 // nsClipboard destructor
50 //-------------------------------------------------------------------------
51 nsClipboard::~nsClipboard()
55 static inline QImage::Format
56 _gfximage_to_qformat(gfxASurface::gfxImageFormat aFormat
)
59 case gfxASurface::ImageFormatARGB32
:
60 return QImage::Format_ARGB32_Premultiplied
;
61 case gfxASurface::ImageFormatRGB24
:
62 return QImage::Format_ARGB32
;
63 case gfxASurface::ImageFormatRGB16_565
:
64 return QImage::Format_RGB16
;
66 return QImage::Format_Invalid
;
70 // nsClipboard::SetNativeClipboardData ie. Copy
73 nsClipboard::SetNativeClipboardData( nsITransferable
*aTransferable
,
74 QClipboard::Mode clipboardMode
)
76 if (nullptr == aTransferable
)
78 NS_WARNING("nsClipboard::SetNativeClipboardData(): no transferable!");
79 return NS_ERROR_FAILURE
;
82 // get flavor list that includes all flavors that can be written (including
83 // ones obtained through conversion)
84 nsCOMPtr
<nsISupportsArray
> flavorList
;
85 nsresult rv
= aTransferable
->FlavorsTransferableCanExport( getter_AddRefs(flavorList
) );
89 NS_WARNING("nsClipboard::SetNativeClipboardData(): no FlavorsTransferable !");
90 return NS_ERROR_FAILURE
;
93 QClipboard
*cb
= QApplication::clipboard();
94 QMimeData
*mimeData
= new QMimeData
;
96 uint32_t flavorCount
= 0;
97 flavorList
->Count(&flavorCount
);
98 bool imageAdded
= false;
100 for (uint32_t i
= 0; i
< flavorCount
; ++i
)
102 nsCOMPtr
<nsISupports
> genericFlavor
;
103 flavorList
->GetElementAt(i
,getter_AddRefs(genericFlavor
));
104 nsCOMPtr
<nsISupportsCString
> currentFlavor(do_QueryInterface(genericFlavor
));
108 // flavorStr is the mime type
109 nsXPIDLCString flavorStr
;
110 currentFlavor
->ToString(getter_Copies(flavorStr
));
112 // Clip is the data which will be sent to the clipboard
113 nsCOMPtr
<nsISupports
> clip
;
114 // len is the length of the data
118 if (!strcmp(flavorStr
.get(), kUnicodeMime
))
120 rv
= aTransferable
->GetTransferData(flavorStr
,getter_AddRefs(clip
),&len
);
121 nsCOMPtr
<nsISupportsString
> wideString
;
122 wideString
= do_QueryInterface(clip
);
123 if (!wideString
|| NS_FAILED(rv
))
126 nsAutoString utf16string
;
127 wideString
->GetData(utf16string
);
128 QString str
= QString::fromUtf16(utf16string
.get());
130 // Add text to the mimeData
131 mimeData
->setText(str
);
135 else if (!strcmp(flavorStr
.get(), kHTMLMime
))
137 rv
= aTransferable
->GetTransferData(flavorStr
,getter_AddRefs(clip
),&len
);
138 nsCOMPtr
<nsISupportsString
> wideString
;
139 wideString
= do_QueryInterface(clip
);
140 if (!wideString
|| NS_FAILED(rv
))
143 nsAutoString utf16string
;
144 wideString
->GetData(utf16string
);
145 QString str
= QString::fromUtf16(utf16string
.get());
147 // Add html to the mimeData
148 mimeData
->setHtml(str
);
152 else if (!imageAdded
// image is added only once to the clipboard
153 && (!strcmp(flavorStr
.get(), kNativeImageMime
)
154 || !strcmp(flavorStr
.get(), kPNGImageMime
)
155 || !strcmp(flavorStr
.get(), kJPEGImageMime
)
156 || !strcmp(flavorStr
.get(), kJPGImageMime
)
157 || !strcmp(flavorStr
.get(), kGIFImageMime
))
160 // Look through our transfer data for the image
161 static const char* const imageMimeTypes
[] = {
162 kNativeImageMime
, kPNGImageMime
, kJPEGImageMime
, kJPGImageMime
, kGIFImageMime
};
163 nsCOMPtr
<nsISupportsInterfacePointer
> ptrPrimitive
;
164 for (uint32_t i
= 0; !ptrPrimitive
&& i
< ArrayLength(imageMimeTypes
); i
++)
166 aTransferable
->GetTransferData(imageMimeTypes
[i
], getter_AddRefs(clip
), &len
);
167 ptrPrimitive
= do_QueryInterface(clip
);
173 nsCOMPtr
<nsISupports
> primitiveData
;
174 ptrPrimitive
->GetData(getter_AddRefs(primitiveData
));
175 nsCOMPtr
<imgIContainer
> image(do_QueryInterface(primitiveData
));
176 if (!image
) // Not getting an image for an image mime type!?
179 nsRefPtr
<gfxASurface
> surface
;
180 image
->GetFrame(imgIContainer::FRAME_CURRENT
,
181 imgIContainer::FLAG_SYNC_DECODE
,
182 getter_AddRefs(surface
));
186 nsRefPtr
<gfxImageSurface
> frame(surface
->GetAsReadableARGB32ImageSurface());
190 QImage
qImage(frame
->Data(),
194 _gfximage_to_qformat(frame
->Format()));
196 // Add image to the mimeData
197 mimeData
->setImageData(qImage
);
201 // Other flavors, adding data to clipboard "as is"
204 rv
= aTransferable
->GetTransferData(flavorStr
.get(), getter_AddRefs(clip
), &len
);
206 if (!clip
|| NS_FAILED(rv
))
209 void *primitive_data
= nullptr;
210 nsPrimitiveHelpers::CreateDataFromPrimitive(flavorStr
.get(), clip
,
211 &primitive_data
, len
);
215 QByteArray
data ((const char *)primitive_data
, len
);
216 // Add data to the mimeData
217 mimeData
->setData(flavorStr
.get(), data
);
218 nsMemory::Free(primitive_data
);
224 // If we have some mime data, add it to the clipboard
225 if(!mimeData
->formats().isEmpty())
226 cb
->setMimeData(mimeData
, clipboardMode
);
233 // nsClipboard::GetNativeClipboardData ie. Paste
236 nsClipboard::GetNativeClipboardData(nsITransferable
*aTransferable
,
237 QClipboard::Mode clipboardMode
)
239 if (nullptr == aTransferable
)
241 NS_WARNING("GetNativeClipboardData: Transferable is null!");
242 return NS_ERROR_FAILURE
;
245 // get flavor list that includes all acceptable flavors (including
246 // ones obtained through conversion)
247 nsCOMPtr
<nsISupportsArray
> flavorList
;
248 nsresult errCode
= aTransferable
->FlavorsTransferableCanImport(
249 getter_AddRefs(flavorList
));
251 if (NS_FAILED(errCode
))
253 NS_WARNING("nsClipboard::GetNativeClipboardData(): no FlavorsTransferable!");
254 return NS_ERROR_FAILURE
;
257 QClipboard
*cb
= QApplication::clipboard();
258 const QMimeData
*mimeData
= cb
->mimeData(clipboardMode
);
260 // Walk through flavors and see which flavor matches the one being pasted
261 uint32_t flavorCount
;
262 flavorList
->Count(&flavorCount
);
263 nsAutoCString foundFlavor
;
265 for (uint32_t i
= 0; i
< flavorCount
; ++i
)
267 nsCOMPtr
<nsISupports
> genericFlavor
;
268 flavorList
->GetElementAt(i
,getter_AddRefs(genericFlavor
));
269 nsCOMPtr
<nsISupportsCString
> currentFlavor(do_QueryInterface( genericFlavor
) );
273 nsXPIDLCString flavorStr
;
274 currentFlavor
->ToString(getter_Copies(flavorStr
));
276 // Ok, so which flavor the data being pasted could be?
278 if (!strcmp(flavorStr
.get(), kUnicodeMime
) && mimeData
->hasText())
280 // Clipboard has text and flavor accepts text, so lets
281 // handle the data as text
282 foundFlavor
= nsAutoCString(flavorStr
);
284 // Get the text data from clipboard
285 QString text
= mimeData
->text();
286 const QChar
*unicode
= text
.unicode();
287 // Is there a more correct way to get the size in UTF16?
288 uint32_t len
= (uint32_t) 2*text
.size();
290 // And then to genericDataWrapper
291 nsCOMPtr
<nsISupports
> genericDataWrapper
;
292 nsPrimitiveHelpers::CreatePrimitiveForData(
296 getter_AddRefs(genericDataWrapper
));
297 // Data is good, set it to the transferable
298 aTransferable
->SetTransferData(foundFlavor
.get(),
299 genericDataWrapper
,len
);
305 if (!strcmp(flavorStr
.get(), kHTMLMime
) && mimeData
->hasHtml())
307 // Clipboard has text/html and flavor accepts text/html, so lets
308 // handle the data as text/html
309 foundFlavor
= nsAutoCString(flavorStr
);
311 // Get the text data from clipboard
312 QString html
= mimeData
->html();
313 const QChar
*unicode
= html
.unicode();
314 // Is there a more correct way to get the size in UTF16?
315 uint32_t len
= (uint32_t) 2*html
.size();
317 // And then to genericDataWrapper
318 nsCOMPtr
<nsISupports
> genericDataWrapper
;
319 nsPrimitiveHelpers::CreatePrimitiveForData(
323 getter_AddRefs(genericDataWrapper
));
324 // Data is good, set it to the transferable
325 aTransferable
->SetTransferData(foundFlavor
.get(),
326 genericDataWrapper
,len
);
332 if (( !strcmp(flavorStr
.get(), kJPEGImageMime
)
333 || !strcmp(flavorStr
.get(), kJPGImageMime
)
334 || !strcmp(flavorStr
.get(), kPNGImageMime
)
335 || !strcmp(flavorStr
.get(), kGIFImageMime
))
336 && mimeData
->hasImage())
338 // Try to retrieve an image from clipboard
339 QImage image
= cb
->image();
343 // Lets set the image format
344 QByteArray imageFormat
;
345 if (!strcmp(flavorStr
.get(), kJPEGImageMime
) || !strcmp(flavorStr
.get(), kJPGImageMime
))
346 imageFormat
= "jpeg";
347 else if (!strcmp(flavorStr
.get(), kPNGImageMime
))
349 else if (!strcmp(flavorStr
.get(), kGIFImageMime
))
354 // Write image from clippboard to a QByteArrayBuffer
355 QByteArray imageData
;
356 QBuffer
imageBuffer(&imageData
);
357 QImageWriter
imageWriter(&imageBuffer
, imageFormat
);
358 if(!imageWriter
.write(image
))
361 // Add the data to inputstream
362 nsCOMPtr
<nsIInputStream
> byteStream
;
363 NS_NewByteInputStream(getter_AddRefs(byteStream
), imageData
.constData(),
364 imageData
.size(), NS_ASSIGNMENT_COPY
);
365 // Data is good, set it to the transferable
366 aTransferable
->SetTransferData(flavorStr
, byteStream
, sizeof(nsIInputStream
*));
375 // Trying to forward the data "as is"
376 if(mimeData
->hasFormat(flavorStr
.get()))
378 // get the data from the clipboard
379 QByteArray clipboardData
= mimeData
->data(flavorStr
.get());
380 // And add it to genericDataWrapper
381 nsCOMPtr
<nsISupports
> genericDataWrapper
;
382 nsPrimitiveHelpers::CreatePrimitiveForData(
384 (void*) clipboardData
.data(),
385 clipboardData
.size(),
386 getter_AddRefs(genericDataWrapper
));
388 // Data is good, set it to the transferable
389 aTransferable
->SetTransferData(foundFlavor
.get(),
390 genericDataWrapper
,clipboardData
.size());
401 nsClipboard::HasDataMatchingFlavors(const char** aFlavorList
, uint32_t aLength
,
402 int32_t aWhichClipboard
, bool *_retval
)
405 if (aWhichClipboard
!= kGlobalClipboard
)
408 // Which kind of data in the clipboard
409 QClipboard
*cb
= QApplication::clipboard();
410 const QMimeData
*mimeData
= cb
->mimeData();
411 const char *flavor
=NULL
;
412 QStringList formats
= mimeData
->formats();
413 for (uint32_t i
= 0; i
< aLength
; ++i
)
415 flavor
= aFlavorList
[i
];
418 QString
qflavor(flavor
);
420 if (strcmp(flavor
,kTextMime
) == 0)
422 NS_WARNING("DO NOT USE THE text/plain DATA FLAVOR ANY MORE. USE text/unicode INSTEAD");
425 // QClipboard says it has text/plain, mozilla wants to
426 // know if the data is text/unicode -> interpret text/plain to text/unicode
427 if (formats
.contains(qflavor
) ||
428 strcmp(flavor
, kUnicodeMime
) == 0)
430 // A match has been found, return'
440 * Sets the transferable object
443 nsClipboard::SetData(nsITransferable
*aTransferable
,
444 nsIClipboardOwner
*aOwner
,
445 int32_t aWhichClipboard
)
447 // See if we can short cut
449 (aWhichClipboard
== kGlobalClipboard
450 && aTransferable
== mGlobalTransferable
.get()
451 && aOwner
== mGlobalOwner
.get()
454 (aWhichClipboard
== kSelectionClipboard
455 && aTransferable
== mSelectionTransferable
.get()
456 && aOwner
== mSelectionOwner
.get()
464 if (!mPrivacyHandler
) {
465 rv
= NS_NewClipboardPrivacyHandler(getter_AddRefs(mPrivacyHandler
));
466 NS_ENSURE_SUCCESS(rv
, rv
);
468 rv
= mPrivacyHandler
->PrepareDataForClipboard(aTransferable
);
469 NS_ENSURE_SUCCESS(rv
, rv
);
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
= QApplication::clipboard();
549 if (cb
->supportsSelection())
551 *_retval
= true; // we support the selection clipboard