summaryrefslogtreecommitdiffstats
path: root/widget/nsClipboardProxy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'widget/nsClipboardProxy.cpp')
-rw-r--r--widget/nsClipboardProxy.cpp271
1 files changed, 271 insertions, 0 deletions
diff --git a/widget/nsClipboardProxy.cpp b/widget/nsClipboardProxy.cpp
new file mode 100644
index 0000000000..41f285461b
--- /dev/null
+++ b/widget/nsClipboardProxy.cpp
@@ -0,0 +1,271 @@
+/* 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 "nsClipboardProxy.h"
+
+#if defined(ACCESSIBILITY) && defined(XP_WIN)
+# include "mozilla/a11y/Compatibility.h"
+#endif
+#include "mozilla/ClipboardReadRequestChild.h"
+#include "mozilla/ClipboardWriteRequestChild.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/net/CookieJarSettings.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/dom/WindowGlobalChild.h"
+#include "mozilla/Unused.h"
+#include "nsArrayUtils.h"
+#include "nsBaseClipboard.h"
+#include "nsISupportsPrimitives.h"
+#include "nsCOMPtr.h"
+#include "nsComponentManagerUtils.h"
+#include "nsXULAppAPI.h"
+#include "nsContentUtils.h"
+#include "PermissionMessageUtils.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+NS_IMPL_ISUPPORTS(nsClipboardProxy, nsIClipboard, nsIClipboardProxy)
+
+nsClipboardProxy::nsClipboardProxy() : mClipboardCaps(false, false, false) {}
+
+NS_IMETHODIMP
+nsClipboardProxy::SetData(nsITransferable* aTransferable,
+ nsIClipboardOwner* anOwner, int32_t aWhichClipboard) {
+#if defined(ACCESSIBILITY) && defined(XP_WIN)
+ a11y::Compatibility::SuppressA11yForClipboardCopy();
+#endif
+
+ ContentChild* child = ContentChild::GetSingleton();
+ IPCTransferable ipcTransferable;
+ nsContentUtils::TransferableToIPCTransferable(aTransferable, &ipcTransferable,
+ false, nullptr);
+ child->SendSetClipboard(std::move(ipcTransferable), aWhichClipboard);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsClipboardProxy::AsyncSetData(
+ int32_t aWhichClipboard, nsIAsyncClipboardRequestCallback* aCallback,
+ nsIAsyncSetClipboardData** _retval) {
+ RefPtr<ClipboardWriteRequestChild> request =
+ MakeRefPtr<ClipboardWriteRequestChild>(aCallback);
+ ContentChild::GetSingleton()->SendPClipboardWriteRequestConstructor(
+ request, aWhichClipboard);
+ request.forget(_retval);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsClipboardProxy::GetData(nsITransferable* aTransferable,
+ int32_t aWhichClipboard,
+ mozilla::dom::WindowContext* aWindowContext) {
+ MOZ_DIAGNOSTIC_ASSERT(aWindowContext && aWindowContext->IsInProcess(),
+ "content clipboard reads must be associated with an "
+ "in-process WindowContext");
+ if (aWindowContext->IsDiscarded()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ nsTArray<nsCString> types;
+ aTransferable->FlavorsTransferableCanImport(types);
+
+ IPCTransferableData transferable;
+ ContentChild::GetSingleton()->SendGetClipboard(types, aWhichClipboard,
+ aWindowContext, &transferable);
+ return nsContentUtils::IPCTransferableDataToTransferable(
+ transferable, false /* aAddDataFlavor */, aTransferable,
+ false /* aFilterUnknownFlavors */);
+}
+
+namespace {
+
+class AsyncGetClipboardDataProxy final : public nsIAsyncGetClipboardData {
+ public:
+ explicit AsyncGetClipboardDataProxy(ClipboardReadRequestChild* aActor)
+ : mActor(aActor) {
+ MOZ_ASSERT(mActor);
+ }
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIASYNCGETCLIPBOARDDATA
+
+ private:
+ virtual ~AsyncGetClipboardDataProxy() {
+ MOZ_ASSERT(mActor);
+ if (mActor->CanSend()) {
+ PClipboardReadRequestChild::Send__delete__(mActor);
+ }
+ };
+
+ RefPtr<ClipboardReadRequestChild> mActor;
+};
+
+NS_IMPL_ISUPPORTS(AsyncGetClipboardDataProxy, nsIAsyncGetClipboardData)
+
+NS_IMETHODIMP AsyncGetClipboardDataProxy::GetValid(bool* aOutResult) {
+ MOZ_ASSERT(mActor);
+ *aOutResult = mActor->CanSend();
+ return NS_OK;
+}
+
+NS_IMETHODIMP AsyncGetClipboardDataProxy::GetFlavorList(
+ nsTArray<nsCString>& aFlavorList) {
+ MOZ_ASSERT(mActor);
+ aFlavorList.AppendElements(mActor->FlavorList());
+ return NS_OK;
+}
+
+NS_IMETHODIMP AsyncGetClipboardDataProxy::GetData(
+ nsITransferable* aTransferable,
+ nsIAsyncClipboardRequestCallback* aCallback) {
+ if (!aTransferable || !aCallback) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ // Get a list of flavors this transferable can import
+ nsTArray<nsCString> flavors;
+ nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ MOZ_ASSERT(mActor);
+ // If the requested flavor is not in the list, throw an error.
+ for (const auto& flavor : flavors) {
+ if (!mActor->FlavorList().Contains(flavor)) {
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ if (!mActor->CanSend()) {
+ return aCallback->OnComplete(NS_ERROR_FAILURE);
+ }
+
+ mActor->SendGetData(flavors)->Then(
+ GetMainThreadSerialEventTarget(), __func__,
+ /* resolve */
+ [self = RefPtr{this}, callback = nsCOMPtr{aCallback},
+ transferable = nsCOMPtr{aTransferable}](
+ const IPCTransferableDataOrError& aIpcTransferableDataOrError) {
+ if (aIpcTransferableDataOrError.type() ==
+ IPCTransferableDataOrError::Tnsresult) {
+ MOZ_ASSERT(NS_FAILED(aIpcTransferableDataOrError.get_nsresult()));
+ callback->OnComplete(aIpcTransferableDataOrError.get_nsresult());
+ return;
+ }
+
+ nsresult rv = nsContentUtils::IPCTransferableDataToTransferable(
+ aIpcTransferableDataOrError.get_IPCTransferableData(),
+ false /* aAddDataFlavor */, transferable,
+ false /* aFilterUnknownFlavors */);
+ if (NS_FAILED(rv)) {
+ callback->OnComplete(rv);
+ return;
+ }
+
+ callback->OnComplete(NS_OK);
+ },
+ /* reject */
+ [callback =
+ nsCOMPtr{aCallback}](mozilla::ipc::ResponseRejectReason aReason) {
+ callback->OnComplete(NS_ERROR_FAILURE);
+ });
+
+ return NS_OK;
+}
+
+} // namespace
+
+NS_IMETHODIMP nsClipboardProxy::AsyncGetData(
+ const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard,
+ mozilla::dom::WindowContext* aRequestingWindowContext,
+ nsIPrincipal* aRequestingPrincipal,
+ nsIAsyncClipboardGetCallback* aCallback) {
+ if (!aCallback || !aRequestingPrincipal || aFlavorList.IsEmpty()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ if (!nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)) {
+ MOZ_CLIPBOARD_LOG("%s: clipboard %d is not supported.", __FUNCTION__,
+ aWhichClipboard);
+ return NS_ERROR_FAILURE;
+ }
+
+ ContentChild::GetSingleton()
+ ->SendGetClipboardAsync(aFlavorList, aWhichClipboard,
+ aRequestingWindowContext,
+ WrapNotNull(aRequestingPrincipal))
+ ->Then(
+ GetMainThreadSerialEventTarget(), __func__,
+ /* resolve */
+ [callback = nsCOMPtr{aCallback}](const PClipboardReadRequestOrError&
+ aClipboardReadRequestOrError) {
+ if (aClipboardReadRequestOrError.type() ==
+ PClipboardReadRequestOrError::Tnsresult) {
+ MOZ_ASSERT(
+ NS_FAILED(aClipboardReadRequestOrError.get_nsresult()));
+ callback->OnError(aClipboardReadRequestOrError.get_nsresult());
+ return;
+ }
+
+ auto asyncGetClipboardData = MakeRefPtr<AsyncGetClipboardDataProxy>(
+ static_cast<ClipboardReadRequestChild*>(
+ aClipboardReadRequestOrError.get_PClipboardReadRequest()
+ .AsChild()
+ .get()));
+
+ callback->OnSuccess(asyncGetClipboardData);
+ },
+ /* reject */
+ [callback = nsCOMPtr{aCallback}](
+ mozilla::ipc::ResponseRejectReason aReason) {
+ callback->OnError(NS_ERROR_FAILURE);
+ });
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsClipboardProxy::EmptyClipboard(int32_t aWhichClipboard) {
+ ContentChild::GetSingleton()->SendEmptyClipboard(aWhichClipboard);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsClipboardProxy::HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList,
+ int32_t aWhichClipboard,
+ bool* aHasType) {
+ *aHasType = false;
+
+ ContentChild::GetSingleton()->SendClipboardHasType(aFlavorList,
+ aWhichClipboard, aHasType);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsClipboardProxy::IsClipboardTypeSupported(int32_t aWhichClipboard,
+ bool* aIsSupported) {
+ switch (aWhichClipboard) {
+ case kGlobalClipboard:
+ // We always support the global clipboard.
+ *aIsSupported = true;
+ return NS_OK;
+ case kSelectionClipboard:
+ *aIsSupported = mClipboardCaps.supportsSelectionClipboard();
+ return NS_OK;
+ case kFindClipboard:
+ *aIsSupported = mClipboardCaps.supportsFindClipboard();
+ return NS_OK;
+ case kSelectionCache:
+ *aIsSupported = mClipboardCaps.supportsSelectionCache();
+ return NS_OK;
+ }
+
+ *aIsSupported = false;
+ return NS_OK;
+}
+
+void nsClipboardProxy::SetCapabilities(
+ const ClipboardCapabilities& aClipboardCaps) {
+ mClipboardCaps = aClipboardCaps;
+}