/* 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 "mozilla/java/ClipboardWrappers.h" #include "mozilla/java/GeckoAppShellWrappers.h" #include "nsClipboard.h" #include "nsISupportsPrimitives.h" #include "nsCOMPtr.h" #include "nsComponentManagerUtils.h" #include "nsMemory.h" #include "nsStringStream.h" #include "nsPrimitiveHelpers.h" using namespace mozilla; NS_IMPL_ISUPPORTS_INHERITED0(nsClipboard, nsBaseClipboard) /* The Android clipboard only supports text and doesn't support mime types * so we assume all clipboard data is text/plain for now. Documentation * indicates that support for other data types is planned for future * releases. */ nsClipboard::nsClipboard() : nsBaseClipboard(mozilla::dom::ClipboardCapabilities( false /* supportsSelectionClipboard */, false /* supportsFindClipboard */, false /* supportsSelectionCache */)) { java::Clipboard::StartTrackingClipboardData( java::GeckoAppShell::GetApplicationContext()); } nsClipboard::~nsClipboard() { java::Clipboard::StopTrackingClipboardData( java::GeckoAppShell::GetApplicationContext()); } // static nsresult nsClipboard::GetTextFromTransferable(nsITransferable* aTransferable, nsString& aText, nsString& aHTML) { nsTArray flavors; nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors); if (NS_FAILED(rv)) { return rv; } for (auto& flavorStr : flavors) { if (flavorStr.EqualsLiteral(kTextMime)) { nsCOMPtr item; nsresult rv = aTransferable->GetTransferData(kTextMime, getter_AddRefs(item)); if (NS_WARN_IF(NS_FAILED(rv))) { continue; } nsCOMPtr supportsString = do_QueryInterface(item); if (supportsString) { supportsString->GetData(aText); } } else if (flavorStr.EqualsLiteral(kHTMLMime)) { nsCOMPtr item; nsresult rv = aTransferable->GetTransferData(kHTMLMime, getter_AddRefs(item)); if (NS_WARN_IF(NS_FAILED(rv))) { continue; } nsCOMPtr supportsString = do_QueryInterface(item); if (supportsString) { supportsString->GetData(aHTML); } } } return NS_OK; } NS_IMETHODIMP nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhichClipboard) { MOZ_DIAGNOSTIC_ASSERT(aTransferable); MOZ_DIAGNOSTIC_ASSERT( nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)); if (!jni::IsAvailable()) { return NS_ERROR_NOT_AVAILABLE; } nsString text; nsString html; nsresult rv = GetTextFromTransferable(aTransferable, text, html); if (NS_FAILED(rv)) { return rv; } if (!html.IsEmpty() && java::Clipboard::SetHTML(java::GeckoAppShell::GetApplicationContext(), text, html)) { return NS_OK; } if (!text.IsEmpty() && java::Clipboard::SetText(java::GeckoAppShell::GetApplicationContext(), text)) { return NS_OK; } return NS_ERROR_FAILURE; } NS_IMETHODIMP nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhichClipboard) { MOZ_DIAGNOSTIC_ASSERT(aTransferable); MOZ_DIAGNOSTIC_ASSERT( nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)); if (!jni::IsAvailable()) { return NS_ERROR_NOT_AVAILABLE; } nsTArray flavors; aTransferable->FlavorsTransferableCanImport(flavors); for (auto& flavorStr : flavors) { if (flavorStr.EqualsLiteral(kTextMime) || flavorStr.EqualsLiteral(kHTMLMime)) { auto text = java::Clipboard::GetTextData( java::GeckoAppShell::GetApplicationContext(), flavorStr); if (!text) { continue; } nsString buffer = text->ToString(); if (buffer.IsEmpty()) { continue; } nsCOMPtr wrapper; nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, buffer.get(), buffer.Length() * 2, getter_AddRefs(wrapper)); if (wrapper) { aTransferable->SetTransferData(flavorStr.get(), wrapper); return NS_OK; } continue; } mozilla::jni::ByteArray::LocalRef bytes; nsresult rv = java::Clipboard::GetRawData(flavorStr, &bytes); if (NS_FAILED(rv) || !bytes) { continue; } nsCOMPtr byteStream; rv = NS_NewByteInputStream( getter_AddRefs(byteStream), mozilla::Span( reinterpret_cast(bytes->GetElements().Elements()), bytes->Length()), NS_ASSIGNMENT_COPY); if (NS_WARN_IF(NS_FAILED(rv))) { continue; } rv = aTransferable->SetTransferData(flavorStr.get(), byteStream); if (NS_WARN_IF(NS_FAILED(rv))) { continue; } } return NS_ERROR_FAILURE; } nsresult nsClipboard::EmptyNativeClipboardData(int32_t aWhichClipboard) { MOZ_DIAGNOSTIC_ASSERT( nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)); if (!jni::IsAvailable()) { return NS_ERROR_NOT_AVAILABLE; } java::Clipboard::Clear(java::GeckoAppShell::GetApplicationContext()); return NS_OK; } mozilla::Result nsClipboard::GetNativeClipboardSequenceNumber(int32_t aWhichClipboard) { MOZ_DIAGNOSTIC_ASSERT( nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)); if (!jni::IsAvailable()) { return Err(NS_ERROR_NOT_AVAILABLE); } return java::Clipboard::GetSequenceNumber( java::GeckoAppShell::GetApplicationContext()); } mozilla::Result nsClipboard::HasNativeClipboardDataMatchingFlavors( const nsTArray& aFlavorList, int32_t aWhichClipboard) { MOZ_DIAGNOSTIC_ASSERT( nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)); if (!jni::IsAvailable()) { return Err(NS_ERROR_NOT_AVAILABLE); } for (auto& flavor : aFlavorList) { if (java::Clipboard::HasData(java::GeckoAppShell::GetApplicationContext(), NS_ConvertASCIItoUTF16(flavor))) { return true; } } return false; }