Bug 1889091 - Part 4: Remove extra stack pointer move. r=jandem
[gecko.git] / widget / nsClipboardProxy.cpp
blob3b27d5954d460060edd46f891ed0f549d300c5f7
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "nsClipboardProxy.h"
7 #if defined(ACCESSIBILITY) && defined(XP_WIN)
8 # include "mozilla/a11y/Compatibility.h"
9 #endif
10 #include "mozilla/ClipboardReadRequestChild.h"
11 #include "mozilla/ClipboardWriteRequestChild.h"
12 #include "mozilla/dom/ContentChild.h"
13 #include "mozilla/net/CookieJarSettings.h"
14 #include "mozilla/Maybe.h"
15 #include "mozilla/dom/WindowGlobalChild.h"
16 #include "mozilla/Unused.h"
17 #include "nsArrayUtils.h"
18 #include "nsBaseClipboard.h"
19 #include "nsISupportsPrimitives.h"
20 #include "nsCOMPtr.h"
21 #include "nsComponentManagerUtils.h"
22 #include "nsXULAppAPI.h"
23 #include "nsContentUtils.h"
24 #include "PermissionMessageUtils.h"
26 using namespace mozilla;
27 using namespace mozilla::dom;
29 NS_IMPL_ISUPPORTS(nsClipboardProxy, nsIClipboard, nsIClipboardProxy)
31 nsClipboardProxy::nsClipboardProxy() : mClipboardCaps(false, false, false) {}
33 NS_IMETHODIMP
34 nsClipboardProxy::SetData(nsITransferable* aTransferable,
35 nsIClipboardOwner* anOwner, int32_t aWhichClipboard) {
36 #if defined(ACCESSIBILITY) && defined(XP_WIN)
37 a11y::Compatibility::SuppressA11yForClipboardCopy();
38 #endif
40 ContentChild* child = ContentChild::GetSingleton();
41 IPCTransferable ipcTransferable;
42 nsContentUtils::TransferableToIPCTransferable(aTransferable, &ipcTransferable,
43 false, nullptr);
44 child->SendSetClipboard(std::move(ipcTransferable), aWhichClipboard);
45 return NS_OK;
48 NS_IMETHODIMP nsClipboardProxy::AsyncSetData(
49 int32_t aWhichClipboard, nsIAsyncClipboardRequestCallback* aCallback,
50 nsIAsyncSetClipboardData** _retval) {
51 RefPtr<ClipboardWriteRequestChild> request =
52 MakeRefPtr<ClipboardWriteRequestChild>(aCallback);
53 ContentChild::GetSingleton()->SendPClipboardWriteRequestConstructor(
54 request, aWhichClipboard);
55 request.forget(_retval);
56 return NS_OK;
59 NS_IMETHODIMP
60 nsClipboardProxy::GetData(nsITransferable* aTransferable,
61 int32_t aWhichClipboard,
62 mozilla::dom::WindowContext* aWindowContext) {
63 MOZ_DIAGNOSTIC_ASSERT(aWindowContext && aWindowContext->IsInProcess(),
64 "content clipboard reads must be associated with an "
65 "in-process WindowContext");
66 if (aWindowContext->IsDiscarded()) {
67 return NS_ERROR_NOT_AVAILABLE;
69 nsTArray<nsCString> types;
70 aTransferable->FlavorsTransferableCanImport(types);
72 IPCTransferableData transferable;
73 ContentChild::GetSingleton()->SendGetClipboard(types, aWhichClipboard,
74 aWindowContext, &transferable);
75 return nsContentUtils::IPCTransferableDataToTransferable(
76 transferable, false /* aAddDataFlavor */, aTransferable,
77 false /* aFilterUnknownFlavors */);
80 namespace {
82 class AsyncGetClipboardDataProxy final : public nsIAsyncGetClipboardData {
83 public:
84 explicit AsyncGetClipboardDataProxy(ClipboardReadRequestChild* aActor)
85 : mActor(aActor) {
86 MOZ_ASSERT(mActor);
89 NS_DECL_ISUPPORTS
90 NS_DECL_NSIASYNCGETCLIPBOARDDATA
92 private:
93 virtual ~AsyncGetClipboardDataProxy() {
94 MOZ_ASSERT(mActor);
95 if (mActor->CanSend()) {
96 PClipboardReadRequestChild::Send__delete__(mActor);
100 RefPtr<ClipboardReadRequestChild> mActor;
103 NS_IMPL_ISUPPORTS(AsyncGetClipboardDataProxy, nsIAsyncGetClipboardData)
105 NS_IMETHODIMP AsyncGetClipboardDataProxy::GetValid(bool* aOutResult) {
106 MOZ_ASSERT(mActor);
107 *aOutResult = mActor->CanSend();
108 return NS_OK;
111 NS_IMETHODIMP AsyncGetClipboardDataProxy::GetFlavorList(
112 nsTArray<nsCString>& aFlavorList) {
113 MOZ_ASSERT(mActor);
114 aFlavorList.AppendElements(mActor->FlavorList());
115 return NS_OK;
118 NS_IMETHODIMP AsyncGetClipboardDataProxy::GetData(
119 nsITransferable* aTransferable,
120 nsIAsyncClipboardRequestCallback* aCallback) {
121 if (!aTransferable || !aCallback) {
122 return NS_ERROR_INVALID_ARG;
125 // Get a list of flavors this transferable can import
126 nsTArray<nsCString> flavors;
127 nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
128 if (NS_FAILED(rv)) {
129 return rv;
132 MOZ_ASSERT(mActor);
133 // If the requested flavor is not in the list, throw an error.
134 for (const auto& flavor : flavors) {
135 if (!mActor->FlavorList().Contains(flavor)) {
136 return NS_ERROR_FAILURE;
140 if (!mActor->CanSend()) {
141 return aCallback->OnComplete(NS_ERROR_FAILURE);
144 mActor->SendGetData(flavors)->Then(
145 GetMainThreadSerialEventTarget(), __func__,
146 /* resolve */
147 [self = RefPtr{this}, callback = nsCOMPtr{aCallback},
148 transferable = nsCOMPtr{aTransferable}](
149 const IPCTransferableDataOrError& aIpcTransferableDataOrError) {
150 if (aIpcTransferableDataOrError.type() ==
151 IPCTransferableDataOrError::Tnsresult) {
152 MOZ_ASSERT(NS_FAILED(aIpcTransferableDataOrError.get_nsresult()));
153 callback->OnComplete(aIpcTransferableDataOrError.get_nsresult());
154 return;
157 nsresult rv = nsContentUtils::IPCTransferableDataToTransferable(
158 aIpcTransferableDataOrError.get_IPCTransferableData(),
159 false /* aAddDataFlavor */, transferable,
160 false /* aFilterUnknownFlavors */);
161 if (NS_FAILED(rv)) {
162 callback->OnComplete(rv);
163 return;
166 callback->OnComplete(NS_OK);
168 /* reject */
169 [callback =
170 nsCOMPtr{aCallback}](mozilla::ipc::ResponseRejectReason aReason) {
171 callback->OnComplete(NS_ERROR_FAILURE);
174 return NS_OK;
177 static Result<RefPtr<AsyncGetClipboardDataProxy>, nsresult>
178 CreateAsyncGetClipboardDataProxy(
179 ClipboardReadRequestOrError&& aClipboardReadRequestOrError) {
180 if (aClipboardReadRequestOrError.type() ==
181 ClipboardReadRequestOrError::Tnsresult) {
182 MOZ_ASSERT(NS_FAILED(aClipboardReadRequestOrError.get_nsresult()));
183 return Err(aClipboardReadRequestOrError.get_nsresult());
186 ClipboardReadRequest& request =
187 aClipboardReadRequestOrError.get_ClipboardReadRequest();
188 auto requestChild = MakeRefPtr<ClipboardReadRequestChild>(
189 std::move(request.availableTypes()));
190 if (NS_WARN_IF(
191 !ContentChild::GetSingleton()->BindPClipboardReadRequestEndpoint(
192 std::move(request.childEndpoint()), requestChild))) {
193 return Err(NS_ERROR_FAILURE);
196 return MakeRefPtr<AsyncGetClipboardDataProxy>(requestChild);
199 } // namespace
201 NS_IMETHODIMP nsClipboardProxy::AsyncGetData(
202 const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard,
203 mozilla::dom::WindowContext* aRequestingWindowContext,
204 nsIPrincipal* aRequestingPrincipal,
205 nsIAsyncClipboardGetCallback* aCallback) {
206 if (!aCallback || !aRequestingPrincipal || aFlavorList.IsEmpty()) {
207 return NS_ERROR_INVALID_ARG;
210 if (!nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)) {
211 MOZ_CLIPBOARD_LOG("%s: clipboard %d is not supported.", __FUNCTION__,
212 aWhichClipboard);
213 return NS_ERROR_FAILURE;
216 ContentChild::GetSingleton()
217 ->SendGetClipboardAsync(aFlavorList, aWhichClipboard,
218 aRequestingWindowContext,
219 WrapNotNull(aRequestingPrincipal))
220 ->Then(
221 GetMainThreadSerialEventTarget(), __func__,
222 /* resolve */
223 [callback = nsCOMPtr{aCallback}](
224 ClipboardReadRequestOrError&& aClipboardReadRequestOrError) {
225 auto result = CreateAsyncGetClipboardDataProxy(
226 std::move(aClipboardReadRequestOrError));
227 if (result.isErr()) {
228 callback->OnError(result.unwrapErr());
229 return;
232 callback->OnSuccess(result.inspect());
234 /* reject */
235 [callback = nsCOMPtr{aCallback}](
236 mozilla::ipc::ResponseRejectReason aReason) {
237 callback->OnError(NS_ERROR_FAILURE);
239 return NS_OK;
242 NS_IMETHODIMP nsClipboardProxy::GetDataSnapshotSync(
243 const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard,
244 mozilla::dom::WindowContext* aRequestingWindowContext,
245 nsIAsyncGetClipboardData** _retval) {
246 *_retval = nullptr;
248 if (aFlavorList.IsEmpty()) {
249 return NS_ERROR_INVALID_ARG;
252 if (!nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)) {
253 MOZ_CLIPBOARD_LOG("%s: clipboard %d is not supported.", __FUNCTION__,
254 aWhichClipboard);
255 return NS_ERROR_FAILURE;
258 ContentChild* contentChild = ContentChild::GetSingleton();
259 ClipboardReadRequestOrError requestOrError;
260 contentChild->SendGetClipboardDataSnapshotSync(
261 aFlavorList, aWhichClipboard, aRequestingWindowContext, &requestOrError);
262 auto result = CreateAsyncGetClipboardDataProxy(std::move(requestOrError));
263 if (result.isErr()) {
264 return result.unwrapErr();
267 result.unwrap().forget(_retval);
268 return NS_OK;
271 NS_IMETHODIMP
272 nsClipboardProxy::EmptyClipboard(int32_t aWhichClipboard) {
273 ContentChild::GetSingleton()->SendEmptyClipboard(aWhichClipboard);
274 return NS_OK;
277 NS_IMETHODIMP
278 nsClipboardProxy::HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList,
279 int32_t aWhichClipboard,
280 bool* aHasType) {
281 *aHasType = false;
283 ContentChild::GetSingleton()->SendClipboardHasType(aFlavorList,
284 aWhichClipboard, aHasType);
286 return NS_OK;
289 NS_IMETHODIMP
290 nsClipboardProxy::IsClipboardTypeSupported(int32_t aWhichClipboard,
291 bool* aIsSupported) {
292 switch (aWhichClipboard) {
293 case kGlobalClipboard:
294 // We always support the global clipboard.
295 *aIsSupported = true;
296 return NS_OK;
297 case kSelectionClipboard:
298 *aIsSupported = mClipboardCaps.supportsSelectionClipboard();
299 return NS_OK;
300 case kFindClipboard:
301 *aIsSupported = mClipboardCaps.supportsFindClipboard();
302 return NS_OK;
303 case kSelectionCache:
304 *aIsSupported = mClipboardCaps.supportsSelectionCache();
305 return NS_OK;
308 *aIsSupported = false;
309 return NS_OK;
312 void nsClipboardProxy::SetCapabilities(
313 const ClipboardCapabilities& aClipboardCaps) {
314 mClipboardCaps = aClipboardCaps;