summaryrefslogtreecommitdiffstats
path: root/dom/events/Clipboard.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /dom/events/Clipboard.cpp
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/events/Clipboard.cpp')
-rw-r--r--dom/events/Clipboard.cpp216
1 files changed, 216 insertions, 0 deletions
diff --git a/dom/events/Clipboard.cpp b/dom/events/Clipboard.cpp
new file mode 100644
index 0000000000..1f9efdc2cf
--- /dev/null
+++ b/dom/events/Clipboard.cpp
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/AbstractThread.h"
+#include "mozilla/BasePrincipal.h"
+#include "mozilla/dom/Clipboard.h"
+#include "mozilla/dom/ClipboardBinding.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/DataTransfer.h"
+#include "mozilla/dom/DataTransferItemList.h"
+#include "mozilla/dom/DataTransferItem.h"
+#include "mozilla/dom/Document.h"
+#include "mozilla/StaticPrefs_dom.h"
+#include "nsIClipboard.h"
+#include "nsComponentManagerUtils.h"
+#include "nsContentUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsITransferable.h"
+#include "nsArrayUtils.h"
+
+static mozilla::LazyLogModule gClipboardLog("Clipboard");
+
+namespace mozilla::dom {
+
+Clipboard::Clipboard(nsPIDOMWindowInner* aWindow)
+ : DOMEventTargetHelper(aWindow) {}
+
+Clipboard::~Clipboard() = default;
+
+already_AddRefed<Promise> Clipboard::ReadHelper(
+ nsIPrincipal& aSubjectPrincipal, ClipboardReadType aClipboardReadType,
+ ErrorResult& aRv) {
+ // Create a new promise
+ RefPtr<Promise> p = dom::Promise::Create(GetOwnerGlobal(), aRv);
+ if (aRv.Failed()) {
+ return nullptr;
+ }
+
+ // We want to disable security check for automated tests that have the pref
+ // dom.events.testing.asyncClipboard set to true
+ if (!IsTestingPrefEnabled() &&
+ !nsContentUtils::PrincipalHasPermission(aSubjectPrincipal,
+ nsGkAtoms::clipboardRead)) {
+ MOZ_LOG(GetClipboardLog(), LogLevel::Debug,
+ ("Clipboard, ReadHelper, "
+ "Don't have permissions for reading\n"));
+ p->MaybeRejectWithUndefined();
+ return p.forget();
+ }
+
+ // Want isExternal = true in order to use the data transfer object to perform
+ // a read
+ RefPtr<DataTransfer> dataTransfer = new DataTransfer(
+ this, ePaste, /* is external */ true, nsIClipboard::kGlobalClipboard);
+
+ // Create a new runnable
+ RefPtr<nsIRunnable> r = NS_NewRunnableFunction(
+ "Clipboard::Read",
+ [p, dataTransfer, &aSubjectPrincipal, aClipboardReadType]() {
+ IgnoredErrorResult ier;
+ switch (aClipboardReadType) {
+ case eRead:
+ MOZ_LOG(GetClipboardLog(), LogLevel::Debug,
+ ("Clipboard, ReadHelper, read case\n"));
+ dataTransfer->FillAllExternalData();
+ // If there are items on the clipboard, data transfer will contain
+ // those, else, data transfer will be empty and we will be resolving
+ // with an empty data transfer
+ p->MaybeResolve(dataTransfer);
+ break;
+ case eReadText:
+ MOZ_LOG(GetClipboardLog(), LogLevel::Debug,
+ ("Clipboard, ReadHelper, read text case\n"));
+ nsAutoString str;
+ dataTransfer->GetData(NS_LITERAL_STRING_FROM_CSTRING(kTextMime),
+ str, aSubjectPrincipal, ier);
+ // Either resolve with a string extracted from data transfer item
+ // or resolve with an empty string if nothing was found
+ p->MaybeResolve(str);
+ break;
+ }
+ });
+ // Dispatch the runnable
+ GetParentObject()->Dispatch(TaskCategory::Other, r.forget());
+ return p.forget();
+}
+
+already_AddRefed<Promise> Clipboard::Read(nsIPrincipal& aSubjectPrincipal,
+ ErrorResult& aRv) {
+ return ReadHelper(aSubjectPrincipal, eRead, aRv);
+}
+
+already_AddRefed<Promise> Clipboard::ReadText(nsIPrincipal& aSubjectPrincipal,
+ ErrorResult& aRv) {
+ return ReadHelper(aSubjectPrincipal, eReadText, aRv);
+}
+
+already_AddRefed<Promise> Clipboard::Write(DataTransfer& aData,
+ nsIPrincipal& aSubjectPrincipal,
+ ErrorResult& aRv) {
+ // Create a promise
+ RefPtr<Promise> p = dom::Promise::Create(GetOwnerGlobal(), aRv);
+ if (aRv.Failed()) {
+ return nullptr;
+ }
+
+ nsPIDOMWindowInner* owner = GetOwner();
+ Document* doc = owner ? owner->GetDoc() : nullptr;
+
+ // We want to disable security check for automated tests that have the pref
+ // dom.events.testing.asyncClipboard set to true
+ if (!IsTestingPrefEnabled() &&
+ !nsContentUtils::IsCutCopyAllowed(doc, aSubjectPrincipal)) {
+ MOZ_LOG(GetClipboardLog(), LogLevel::Debug,
+ ("Clipboard, Write, Not allowed to write to clipboard\n"));
+ p->MaybeRejectWithNotAllowedError(
+ "Clipboard write was blocked due to lack of user activation.");
+ return p.forget();
+ }
+
+ // Get the clipboard service
+ nsCOMPtr<nsIClipboard> clipboard(
+ do_GetService("@mozilla.org/widget/clipboard;1"));
+ if (!clipboard) {
+ p->MaybeRejectWithUndefined();
+ return p.forget();
+ }
+
+ nsILoadContext* context = doc ? doc->GetLoadContext() : nullptr;
+ if (!context) {
+ p->MaybeRejectWithUndefined();
+ return p.forget();
+ }
+
+ // Get the transferable
+ RefPtr<nsITransferable> transferable = aData.GetTransferable(0, context);
+ if (!transferable) {
+ p->MaybeRejectWithUndefined();
+ return p.forget();
+ }
+
+ // Create a runnable
+ RefPtr<nsIRunnable> r = NS_NewRunnableFunction(
+ "Clipboard::Write", [transferable, p, clipboard]() {
+ nsresult rv =
+ clipboard->SetData(transferable,
+ /* owner of the transferable */ nullptr,
+ nsIClipboard::kGlobalClipboard);
+ if (NS_FAILED(rv)) {
+ p->MaybeRejectWithUndefined();
+ return;
+ }
+ p->MaybeResolveWithUndefined();
+ return;
+ });
+ // Dispatch the runnable
+ GetParentObject()->Dispatch(TaskCategory::Other, r.forget());
+ return p.forget();
+}
+
+already_AddRefed<Promise> Clipboard::WriteText(const nsAString& aData,
+ nsIPrincipal& aSubjectPrincipal,
+ ErrorResult& aRv) {
+ // We create a data transfer with text/plain format so that
+ // we can reuse Clipboard::Write(...) member function
+ RefPtr<DataTransfer> dataTransfer = new DataTransfer(this, eCopy,
+ /* is external */ true,
+ /* clipboard type */ -1);
+ dataTransfer->SetData(NS_LITERAL_STRING_FROM_CSTRING(kTextMime), aData,
+ aSubjectPrincipal, aRv);
+ return Write(*dataTransfer, aSubjectPrincipal, aRv);
+}
+
+JSObject* Clipboard::WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) {
+ return Clipboard_Binding::Wrap(aCx, this, aGivenProto);
+}
+
+/* static */
+LogModule* Clipboard::GetClipboardLog() { return gClipboardLog; }
+
+/* static */
+bool Clipboard::ReadTextEnabled(JSContext* aCx, JSObject* aGlobal) {
+ nsIPrincipal* prin = nsContentUtils::SubjectPrincipal(aCx);
+ return IsTestingPrefEnabled() || prin->GetIsAddonOrExpandedAddonPrincipal() ||
+ prin->IsSystemPrincipal();
+}
+
+/* static */
+bool Clipboard::IsTestingPrefEnabled() {
+ bool clipboardTestingEnabled =
+ StaticPrefs::dom_events_testing_asyncClipboard_DoNotUseDirectly();
+ MOZ_LOG(GetClipboardLog(), LogLevel::Debug,
+ ("Clipboard, Is testing enabled? %d\n", clipboardTestingEnabled));
+ return clipboardTestingEnabled;
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(Clipboard)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Clipboard,
+ DOMEventTargetHelper)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Clipboard, DOMEventTargetHelper)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Clipboard)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+NS_IMPL_ADDREF_INHERITED(Clipboard, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(Clipboard, DOMEventTargetHelper)
+
+} // namespace mozilla::dom