gecko-dev/widget/gonk/nsClipboard.cpp

360 lines
12 KiB
C++

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsClipboard.h"
#include "gfxDrawable.h"
#include "gfxUtils.h"
#include "ImageOps.h"
#include "imgIContainer.h"
#include "imgTools.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/Preferences.h"
#include "nsClipboardProxy.h"
#include "nsISupportsPrimitives.h"
#include "nsComponentManagerUtils.h"
#include "nsCOMPtr.h"
#include "nsServiceManagerUtils.h"
#include "nsStringStream.h"
#include "nsXULAppAPI.h"
using namespace mozilla;
using mozilla::dom::ContentChild;
#define LOG_TAG "Clipboard"
#define LOGI(args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, ## args)
#define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, ## args)
NS_IMPL_ISUPPORTS(nsClipboard, nsIClipboard)
nsClipboard::nsClipboard()
: mClipboard(mozilla::MakeUnique<GonkClipboardData>())
{
}
NS_IMETHODIMP
nsClipboard::SetData(nsITransferable *aTransferable,
nsIClipboardOwner *anOwner,
int32_t aWhichClipboard)
{
if (aWhichClipboard != kGlobalClipboard) {
return NS_ERROR_NOT_IMPLEMENTED;
}
if (!XRE_IsParentProcess()) {
// Re-direct to the clipboard proxy.
RefPtr<nsClipboardProxy> clipboardProxy = new nsClipboardProxy();
return clipboardProxy->SetData(aTransferable, anOwner, aWhichClipboard);
}
// Clear out the clipboard in order to set the new data.
EmptyClipboard(aWhichClipboard);
// Use a pref to toggle rich text/non-text support.
if (Preferences::GetBool("clipboard.plainTextOnly")) {
nsCOMPtr<nsISupports> clip;
uint32_t len;
nsresult rv = aTransferable->GetTransferData(kUnicodeMime,
getter_AddRefs(clip),
&len);
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsISupportsString> wideString = do_QueryInterface(clip);
if (!wideString) {
return NS_ERROR_NOT_IMPLEMENTED;
}
nsAutoString utf16string;
wideString->GetData(utf16string);
mClipboard->SetText(utf16string);
return NS_OK;
}
// Get the types of supported flavors.
nsCOMPtr<nsISupportsArray> flavorList;
nsresult rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
if (!flavorList || NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
uint32_t flavorCount = 0;
flavorList->Count(&flavorCount);
bool imageAdded = false;
for (uint32_t i = 0; i < flavorCount; ++i) {
nsCOMPtr<nsISupportsCString> currentFlavor = do_QueryElementAt(flavorList, i);
if (currentFlavor) {
// MIME type
nsXPIDLCString flavorStr;
currentFlavor->ToString(getter_Copies(flavorStr));
// Clip is the data which will be sent to the clipboard.
nsCOMPtr<nsISupports> clip;
uint32_t len;
if (flavorStr.EqualsLiteral(kUnicodeMime)) {
// text/plain
rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(clip), &len);
nsCOMPtr<nsISupportsString> wideString = do_QueryInterface(clip);
if (!wideString || NS_FAILED(rv)) {
continue;
}
nsAutoString utf16string;
wideString->GetData(utf16string);
mClipboard->SetText(utf16string);
} else if (flavorStr.EqualsLiteral(kHTMLMime)) {
// text/html
rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(clip), &len);
nsCOMPtr<nsISupportsString> wideString = do_QueryInterface(clip);
if (!wideString || NS_FAILED(rv)) {
continue;
}
nsAutoString utf16string;
wideString->GetData(utf16string);
mClipboard->SetHTML(utf16string);
} else if (!imageAdded && // image is added only once to the clipboard.
(flavorStr.EqualsLiteral(kNativeImageMime) ||
flavorStr.EqualsLiteral(kPNGImageMime) ||
flavorStr.EqualsLiteral(kJPEGImageMime) ||
flavorStr.EqualsLiteral(kJPGImageMime))) {
// image/[png|jpeg|jpg] or application/x-moz-nativeimage
// Look through our transfer data for the image.
static const char* const imageMimeTypes[] = {
kNativeImageMime, kPNGImageMime, kJPEGImageMime, kJPGImageMime };
nsCOMPtr<nsISupportsInterfacePointer> imgPtr;
for (uint32_t i = 0; !imgPtr && i < ArrayLength(imageMimeTypes); ++i) {
aTransferable->GetTransferData(imageMimeTypes[i], getter_AddRefs(clip), &len);
imgPtr = do_QueryInterface(clip);
}
if (!imgPtr) {
continue;
}
nsCOMPtr<nsISupports> imageData;
imgPtr->GetData(getter_AddRefs(imageData));
nsCOMPtr<imgIContainer> image(do_QueryInterface(imageData));
if (!image) {
continue;
}
RefPtr<gfx::SourceSurface> surface =
image->GetFrame(imgIContainer::FRAME_CURRENT,
imgIContainer::FLAG_SYNC_DECODE);
if (!surface) {
continue;
}
RefPtr<gfx::DataSourceSurface> dataSurface;
if (surface->GetFormat() == gfx::SurfaceFormat::B8G8R8A8) {
dataSurface = surface->GetDataSurface();
} else {
// Convert format to SurfaceFormat::B8G8R8A8.
dataSurface = gfxUtils::CopySurfaceToDataSourceSurfaceWithFormat(surface, gfx::SurfaceFormat::B8G8R8A8);
}
mClipboard->SetImage(dataSurface);
imageAdded = true;
}
}
}
return NS_OK;
}
NS_IMETHODIMP
nsClipboard::GetData(nsITransferable *aTransferable,
int32_t aWhichClipboard)
{
if (aWhichClipboard != kGlobalClipboard) {
return NS_ERROR_NOT_IMPLEMENTED;
}
if (!XRE_IsParentProcess()) {
// Re-direct to the clipboard proxy.
RefPtr<nsClipboardProxy> clipboardProxy = new nsClipboardProxy();
return clipboardProxy->GetData(aTransferable, aWhichClipboard);
}
// Use a pref to toggle rich text/non-text support.
if (Preferences::GetBool("clipboard.plainTextOnly")) {
nsresult rv;
nsCOMPtr<nsISupportsString> dataWrapper =
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
rv = dataWrapper->SetData(mClipboard->GetText());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsISupports> genericDataWrapper = do_QueryInterface(dataWrapper);
uint32_t len = mClipboard->GetText().Length() * sizeof(char16_t);
rv = aTransferable->SetTransferData(kUnicodeMime, genericDataWrapper, len);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
// Get flavor list that includes all acceptable flavors (including
// ones obtained through conversion).
// Note: We don't need to call nsITransferable::AddDataFlavor here
// because ContentParent already did.
nsCOMPtr<nsISupportsArray> flavorList;
nsresult rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList));
if (!flavorList || NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
// Walk through flavors and see which flavor matches the one being pasted.
uint32_t flavorCount;
flavorList->Count(&flavorCount);
for (uint32_t i = 0; i < flavorCount; ++i) {
nsCOMPtr<nsISupportsCString> currentFlavor = do_QueryElementAt(flavorList, i);
if (currentFlavor) {
// flavorStr is the mime type.
nsXPIDLCString flavorStr;
currentFlavor->ToString(getter_Copies(flavorStr));
// text/plain, text/Unicode
if (flavorStr.EqualsLiteral(kUnicodeMime) && mClipboard->HasText()) {
nsresult rv;
nsCOMPtr<nsISupportsString> dataWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
rv = dataWrapper->SetData(mClipboard->GetText());
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
nsCOMPtr<nsISupports> genericDataWrapper = do_QueryInterface(dataWrapper);
uint32_t len = mClipboard->GetText().Length() * sizeof(char16_t);
rv = aTransferable->SetTransferData(flavorStr, genericDataWrapper, len);
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
break;
}
// text/html
if (flavorStr.EqualsLiteral(kHTMLMime) && mClipboard->HasHTML()) {
nsresult rv;
nsCOMPtr<nsISupportsString> dataWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
rv = dataWrapper->SetData(mClipboard->GetHTML());
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
nsCOMPtr<nsISupports> genericDataWrapper = do_QueryInterface(dataWrapper);
uint32_t len = mClipboard->GetHTML().Length() * sizeof(char16_t);
rv = aTransferable->SetTransferData(flavorStr, genericDataWrapper, len);
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
break;
}
// image/[png|jpeg|jpg]
if ((flavorStr.EqualsLiteral(kPNGImageMime) ||
flavorStr.EqualsLiteral(kJPEGImageMime) ||
flavorStr.EqualsLiteral(kJPGImageMime)) &&
mClipboard->HasImage() ) {
// Get image buffer from clipboard.
RefPtr<gfx::DataSourceSurface> image = mClipboard->GetImage();
// Encode according to MIME type.
RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(image, image->GetSize());
nsCOMPtr<imgIContainer> imageContainer(image::ImageOps::CreateFromDrawable(drawable));
nsCOMPtr<imgITools> imgTool = do_GetService(NS_IMGTOOLS_CID);
nsCOMPtr<nsIInputStream> byteStream;
imgTool->EncodeImage(imageContainer, flavorStr, EmptyString(), getter_AddRefs(byteStream));
// Set transferable.
nsresult rv = aTransferable->SetTransferData(flavorStr,
byteStream,
sizeof(nsIInputStream*));
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
break;
}
}
}
return NS_OK;
}
NS_IMETHODIMP
nsClipboard::EmptyClipboard(int32_t aWhichClipboard)
{
if (aWhichClipboard != kGlobalClipboard) {
return NS_ERROR_NOT_IMPLEMENTED;
}
if (XRE_IsParentProcess()) {
mClipboard->Clear();
} else {
ContentChild::GetSingleton()->SendEmptyClipboard(aWhichClipboard);
}
return NS_OK;
}
NS_IMETHODIMP
nsClipboard::HasDataMatchingFlavors(const char **aFlavorList,
uint32_t aLength, int32_t aWhichClipboard,
bool *aHasType)
{
*aHasType = false;
if (aWhichClipboard != kGlobalClipboard) {
return NS_ERROR_NOT_IMPLEMENTED;
}
if (XRE_IsParentProcess()) {
// Retrieve the union of all aHasType in aFlavorList
for (uint32_t i = 0; i < aLength; ++i) {
const char *flavor = aFlavorList[i];
if (!flavor) {
continue;
}
if (!strcmp(flavor, kUnicodeMime) && mClipboard->HasText()) {
*aHasType = true;
} else if (!strcmp(flavor, kHTMLMime) && mClipboard->HasHTML()) {
*aHasType = true;
} else if (!strcmp(flavor, kJPEGImageMime) ||
!strcmp(flavor, kJPGImageMime) ||
!strcmp(flavor, kPNGImageMime)) {
// We will encode the image into any format you want, so we don't
// need to check each specific format
if (mClipboard->HasImage()) {
*aHasType = true;
}
}
}
} else {
RefPtr<nsClipboardProxy> clipboardProxy = new nsClipboardProxy();
return clipboardProxy->HasDataMatchingFlavors(aFlavorList, aLength, aWhichClipboard, aHasType);
}
return NS_OK;
}
NS_IMETHODIMP
nsClipboard::SupportsSelectionClipboard(bool *aIsSupported)
{
*aIsSupported = false;
return NS_OK;
}
NS_IMETHODIMP
nsClipboard::SupportsFindClipboard(bool* _retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = false;
return NS_OK;
}