Bug 1942006 - Upstream a variety of Servo-specific code from Servo's downstream fork...
[gecko.git] / widget / ClipboardReadRequestParent.cpp
blob0aabfcd4d35c05744de2e51e9d0a739808f1478b
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/ClipboardReadRequestParent.h"
8 #include "mozilla/dom/ContentParent.h"
9 #include "mozilla/net/CookieJarSettings.h"
10 #include "nsComponentManagerUtils.h"
11 #include "nsIClipboard.h"
12 #include "nsITransferable.h"
13 #include "nsThreadManager.h"
14 #include "nsWidgetsCID.h"
16 using mozilla::dom::ContentParent;
17 using mozilla::ipc::IPCResult;
19 namespace mozilla {
21 namespace {
23 class ClipboardGetDataCallback final : public nsIAsyncClipboardRequestCallback {
24 public:
25 explicit ClipboardGetDataCallback(std::function<void(nsresult)>&& aCallback)
26 : mCallback(std::move(aCallback)) {}
28 // This object will never be held by a cycle-collected object, so it doesn't
29 // need to be cycle-collected despite holding alive cycle-collected objects.
30 NS_DECL_ISUPPORTS
32 // nsIAsyncClipboardRequestCallback
33 NS_IMETHOD OnComplete(nsresult aResult) override {
34 mCallback(aResult);
35 return NS_OK;
38 protected:
39 ~ClipboardGetDataCallback() = default;
41 std::function<void(nsresult)> mCallback;
44 NS_IMPL_ISUPPORTS(ClipboardGetDataCallback, nsIAsyncClipboardRequestCallback)
46 static Result<nsCOMPtr<nsITransferable>, nsresult> CreateTransferable(
47 const nsTArray<nsCString>& aTypes) {
48 nsresult rv;
49 nsCOMPtr<nsITransferable> trans =
50 do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
51 if (NS_FAILED(rv)) {
52 return Err(rv);
55 MOZ_TRY(trans->Init(nullptr));
56 // The private flag is only used to prevent the data from being cached to the
57 // disk. The flag is not exported to the IPCDataTransfer object.
58 // The flag is set because we are not sure whether the clipboard data is used
59 // in a private browsing context. The transferable is only used in this scope,
60 // so the cache would not reduce memory consumption anyway.
61 trans->SetIsPrivateData(true);
62 // Fill out flavors for transferable
63 for (uint32_t t = 0; t < aTypes.Length(); t++) {
64 MOZ_TRY(trans->AddDataFlavor(aTypes[t].get()));
67 return std::move(trans);
70 } // namespace
72 IPCResult ClipboardReadRequestParent::RecvGetData(
73 const nsTArray<nsCString>& aFlavors, GetDataResolver&& aResolver) {
74 bool valid = false;
75 if (NS_FAILED(mClipboardDataSnapshot->GetValid(&valid)) || !valid) {
76 Unused << PClipboardReadRequestParent::Send__delete__(this);
77 aResolver(NS_ERROR_NOT_AVAILABLE);
78 return IPC_OK();
81 // Create transferable
82 auto result = CreateTransferable(aFlavors);
83 if (result.isErr()) {
84 aResolver(result.unwrapErr());
85 return IPC_OK();
88 nsCOMPtr<nsITransferable> trans = result.unwrap();
89 RefPtr<ClipboardGetDataCallback> callback =
90 MakeRefPtr<ClipboardGetDataCallback>([self = RefPtr{this},
91 resolver = std::move(aResolver),
92 trans,
93 manager = mManager](nsresult aRv) {
94 if (NS_FAILED(aRv)) {
95 bool valid = false;
96 if (NS_FAILED(self->mClipboardDataSnapshot->GetValid(&valid)) ||
97 !valid) {
98 Unused << PClipboardReadRequestParent::Send__delete__(self);
100 resolver(aRv);
101 return;
104 dom::IPCTransferableData ipcTransferableData;
105 nsContentUtils::TransferableToIPCTransferableData(
106 trans, &ipcTransferableData, false /* aInSyncMessage */, manager);
107 resolver(std::move(ipcTransferableData));
109 nsresult rv = mClipboardDataSnapshot->GetData(trans, callback);
110 if (NS_FAILED(rv)) {
111 callback->OnComplete(rv);
113 return IPC_OK();
116 IPCResult ClipboardReadRequestParent::RecvGetDataSync(
117 const nsTArray<nsCString>& aFlavors,
118 dom::IPCTransferableDataOrError* aTransferableDataOrError) {
119 auto destroySoon = [&] {
120 // Delete this actor, but don't do it in the middle of this sync IPC call
121 // Make sure nothing else gets processed before this deletion, so use
122 // DispatchDirectTaskToCurrentThread()
123 RefPtr<nsIRunnable> task = NS_NewRunnableFunction(
124 "ClipboardReadRequestParent_SyncError", [self = RefPtr{this}]() {
125 Unused << PClipboardReadRequestParent::Send__delete__(self);
127 nsThreadManager::get().DispatchDirectTaskToCurrentThread(task);
130 bool valid = false;
131 if (NS_FAILED(mClipboardDataSnapshot->GetValid(&valid)) || !valid) {
132 destroySoon();
133 *aTransferableDataOrError = NS_ERROR_NOT_AVAILABLE;
134 return IPC_OK();
137 // Create transferable
138 auto result = CreateTransferable(aFlavors);
139 if (result.isErr()) {
140 *aTransferableDataOrError = result.unwrapErr();
141 return IPC_OK();
144 nsCOMPtr<nsITransferable> trans = result.unwrap();
145 nsresult rv = mClipboardDataSnapshot->GetDataSync(trans);
146 if (NS_FAILED(rv)) {
147 *aTransferableDataOrError = rv;
148 if (NS_FAILED(mClipboardDataSnapshot->GetValid(&valid)) || !valid) {
149 destroySoon();
151 return IPC_OK();
153 dom::IPCTransferableData ipcTransferableData;
154 nsContentUtils::TransferableToIPCTransferableData(
155 trans, &ipcTransferableData, true /* aInSyncMessage */, mManager);
156 *aTransferableDataOrError = std::move(ipcTransferableData);
157 return IPC_OK();
160 } // namespace mozilla