diff options
Diffstat (limited to 'widget/gonk/nsClipboard.cpp')
-rw-r--r-- | widget/gonk/nsClipboard.cpp | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/widget/gonk/nsClipboard.cpp b/widget/gonk/nsClipboard.cpp new file mode 100644 index 000000000..a1eabe8e5 --- /dev/null +++ b/widget/gonk/nsClipboard.cpp @@ -0,0 +1,366 @@ +/* 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 "nsArrayUtils.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<nsIArray> flavorList; + nsresult rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList)); + if (!flavorList || NS_FAILED(rv)) { + return NS_ERROR_FAILURE; + } + + uint32_t flavorCount = 0; + flavorList->GetLength(&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<nsIArray> 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->GetLength(&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; + nsresult rv = imgTool->EncodeImage(imageContainer, + flavorStr, + EmptyString(), + getter_AddRefs(byteStream)); + if (NS_WARN_IF(NS_FAILED(rv))) { + continue; + } + + // Set transferable. + 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; +} + |