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"
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"
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) {}
34 nsClipboardProxy::SetData(nsITransferable
* aTransferable
,
35 nsIClipboardOwner
* anOwner
, int32_t aWhichClipboard
,
36 mozilla::dom::WindowContext
* aWindowContext
) {
37 #if defined(ACCESSIBILITY) && defined(XP_WIN)
38 a11y::Compatibility::SuppressA11yForClipboardCopy();
41 ContentChild
* child
= ContentChild::GetSingleton();
42 IPCTransferable ipcTransferable
;
43 nsContentUtils::TransferableToIPCTransferable(aTransferable
, &ipcTransferable
,
45 child
->SendSetClipboard(std::move(ipcTransferable
), aWhichClipboard
,
50 NS_IMETHODIMP
nsClipboardProxy::AsyncSetData(
51 int32_t aWhichClipboard
, mozilla::dom::WindowContext
* aSettingWindowContext
,
52 nsIAsyncClipboardRequestCallback
* aCallback
,
53 nsIAsyncSetClipboardData
** _retval
) {
54 RefPtr
<ClipboardWriteRequestChild
> request
=
55 MakeRefPtr
<ClipboardWriteRequestChild
>(aCallback
);
56 ContentChild::GetSingleton()->SendPClipboardWriteRequestConstructor(
57 request
, aWhichClipboard
, aSettingWindowContext
);
58 request
.forget(_retval
);
63 nsClipboardProxy::GetData(nsITransferable
* aTransferable
,
64 int32_t aWhichClipboard
,
65 mozilla::dom::WindowContext
* aWindowContext
) {
66 MOZ_DIAGNOSTIC_ASSERT(aWindowContext
&& aWindowContext
->IsInProcess(),
67 "content clipboard reads must be associated with an "
68 "in-process WindowContext");
69 if (aWindowContext
->IsDiscarded()) {
70 return NS_ERROR_NOT_AVAILABLE
;
72 nsTArray
<nsCString
> types
;
73 aTransferable
->FlavorsTransferableCanImport(types
);
75 IPCTransferableData transferable
;
76 ContentChild::GetSingleton()->SendGetClipboard(types
, aWhichClipboard
,
77 aWindowContext
, &transferable
);
78 return nsContentUtils::IPCTransferableDataToTransferable(
79 transferable
, false /* aAddDataFlavor */, aTransferable
,
80 false /* aFilterUnknownFlavors */);
85 class AsyncGetClipboardDataProxy final
: public nsIAsyncGetClipboardData
{
87 explicit AsyncGetClipboardDataProxy(ClipboardReadRequestChild
* aActor
)
93 NS_DECL_NSIASYNCGETCLIPBOARDDATA
96 virtual ~AsyncGetClipboardDataProxy() {
98 if (mActor
->CanSend()) {
99 PClipboardReadRequestChild::Send__delete__(mActor
);
103 RefPtr
<ClipboardReadRequestChild
> mActor
;
106 NS_IMPL_ISUPPORTS(AsyncGetClipboardDataProxy
, nsIAsyncGetClipboardData
)
108 NS_IMETHODIMP
AsyncGetClipboardDataProxy::GetValid(bool* aOutResult
) {
110 *aOutResult
= mActor
->CanSend();
114 NS_IMETHODIMP
AsyncGetClipboardDataProxy::GetFlavorList(
115 nsTArray
<nsCString
>& aFlavorList
) {
117 aFlavorList
.AppendElements(mActor
->FlavorList());
121 NS_IMETHODIMP
AsyncGetClipboardDataProxy::GetData(
122 nsITransferable
* aTransferable
,
123 nsIAsyncClipboardRequestCallback
* aCallback
) {
124 if (!aTransferable
|| !aCallback
) {
125 return NS_ERROR_INVALID_ARG
;
128 // Get a list of flavors this transferable can import
129 nsTArray
<nsCString
> flavors
;
130 nsresult rv
= aTransferable
->FlavorsTransferableCanImport(flavors
);
136 // If the requested flavor is not in the list, throw an error.
137 for (const auto& flavor
: flavors
) {
138 if (!mActor
->FlavorList().Contains(flavor
)) {
139 return NS_ERROR_FAILURE
;
143 if (!mActor
->CanSend()) {
144 return aCallback
->OnComplete(NS_ERROR_FAILURE
);
147 mActor
->SendGetData(flavors
)->Then(
148 GetMainThreadSerialEventTarget(), __func__
,
150 [self
= RefPtr
{this}, callback
= nsCOMPtr
{aCallback
},
151 transferable
= nsCOMPtr
{aTransferable
}](
152 const IPCTransferableDataOrError
& aIpcTransferableDataOrError
) {
153 if (aIpcTransferableDataOrError
.type() ==
154 IPCTransferableDataOrError::Tnsresult
) {
155 MOZ_ASSERT(NS_FAILED(aIpcTransferableDataOrError
.get_nsresult()));
156 callback
->OnComplete(aIpcTransferableDataOrError
.get_nsresult());
160 nsresult rv
= nsContentUtils::IPCTransferableDataToTransferable(
161 aIpcTransferableDataOrError
.get_IPCTransferableData(),
162 false /* aAddDataFlavor */, transferable
,
163 false /* aFilterUnknownFlavors */);
165 callback
->OnComplete(rv
);
169 callback
->OnComplete(NS_OK
);
173 nsCOMPtr
{aCallback
}](mozilla::ipc::ResponseRejectReason aReason
) {
174 callback
->OnComplete(NS_ERROR_FAILURE
);
180 static Result
<RefPtr
<AsyncGetClipboardDataProxy
>, nsresult
>
181 CreateAsyncGetClipboardDataProxy(
182 ClipboardReadRequestOrError
&& aClipboardReadRequestOrError
) {
183 if (aClipboardReadRequestOrError
.type() ==
184 ClipboardReadRequestOrError::Tnsresult
) {
185 MOZ_ASSERT(NS_FAILED(aClipboardReadRequestOrError
.get_nsresult()));
186 return Err(aClipboardReadRequestOrError
.get_nsresult());
189 ClipboardReadRequest
& request
=
190 aClipboardReadRequestOrError
.get_ClipboardReadRequest();
191 auto requestChild
= MakeRefPtr
<ClipboardReadRequestChild
>(
192 std::move(request
.availableTypes()));
194 !ContentChild::GetSingleton()->BindPClipboardReadRequestEndpoint(
195 std::move(request
.childEndpoint()), requestChild
))) {
196 return Err(NS_ERROR_FAILURE
);
199 return MakeRefPtr
<AsyncGetClipboardDataProxy
>(requestChild
);
204 NS_IMETHODIMP
nsClipboardProxy::AsyncGetData(
205 const nsTArray
<nsCString
>& aFlavorList
, int32_t aWhichClipboard
,
206 mozilla::dom::WindowContext
* aRequestingWindowContext
,
207 nsIPrincipal
* aRequestingPrincipal
,
208 nsIAsyncClipboardGetCallback
* aCallback
) {
209 if (!aCallback
|| !aRequestingPrincipal
|| aFlavorList
.IsEmpty()) {
210 return NS_ERROR_INVALID_ARG
;
213 if (!nsIClipboard::IsClipboardTypeSupported(aWhichClipboard
)) {
214 MOZ_CLIPBOARD_LOG("%s: clipboard %d is not supported.", __FUNCTION__
,
216 return NS_ERROR_FAILURE
;
219 ContentChild::GetSingleton()
220 ->SendGetClipboardAsync(aFlavorList
, aWhichClipboard
,
221 aRequestingWindowContext
,
222 WrapNotNull(aRequestingPrincipal
))
224 GetMainThreadSerialEventTarget(), __func__
,
226 [callback
= nsCOMPtr
{aCallback
}](
227 ClipboardReadRequestOrError
&& aClipboardReadRequestOrError
) {
228 auto result
= CreateAsyncGetClipboardDataProxy(
229 std::move(aClipboardReadRequestOrError
));
230 if (result
.isErr()) {
231 callback
->OnError(result
.unwrapErr());
235 callback
->OnSuccess(result
.inspect());
238 [callback
= nsCOMPtr
{aCallback
}](
239 mozilla::ipc::ResponseRejectReason aReason
) {
240 callback
->OnError(NS_ERROR_FAILURE
);
245 NS_IMETHODIMP
nsClipboardProxy::GetDataSnapshotSync(
246 const nsTArray
<nsCString
>& aFlavorList
, int32_t aWhichClipboard
,
247 mozilla::dom::WindowContext
* aRequestingWindowContext
,
248 nsIAsyncGetClipboardData
** _retval
) {
251 if (aFlavorList
.IsEmpty()) {
252 return NS_ERROR_INVALID_ARG
;
255 if (!nsIClipboard::IsClipboardTypeSupported(aWhichClipboard
)) {
256 MOZ_CLIPBOARD_LOG("%s: clipboard %d is not supported.", __FUNCTION__
,
258 return NS_ERROR_FAILURE
;
261 ContentChild
* contentChild
= ContentChild::GetSingleton();
262 ClipboardReadRequestOrError requestOrError
;
263 contentChild
->SendGetClipboardDataSnapshotSync(
264 aFlavorList
, aWhichClipboard
, aRequestingWindowContext
, &requestOrError
);
265 auto result
= CreateAsyncGetClipboardDataProxy(std::move(requestOrError
));
266 if (result
.isErr()) {
267 return result
.unwrapErr();
270 result
.unwrap().forget(_retval
);
275 nsClipboardProxy::EmptyClipboard(int32_t aWhichClipboard
) {
276 ContentChild::GetSingleton()->SendEmptyClipboard(aWhichClipboard
);
281 nsClipboardProxy::HasDataMatchingFlavors(const nsTArray
<nsCString
>& aFlavorList
,
282 int32_t aWhichClipboard
,
286 ContentChild::GetSingleton()->SendClipboardHasType(aFlavorList
,
287 aWhichClipboard
, aHasType
);
293 nsClipboardProxy::IsClipboardTypeSupported(int32_t aWhichClipboard
,
294 bool* aIsSupported
) {
295 switch (aWhichClipboard
) {
296 case kGlobalClipboard
:
297 // We always support the global clipboard.
298 *aIsSupported
= true;
300 case kSelectionClipboard
:
301 *aIsSupported
= mClipboardCaps
.supportsSelectionClipboard();
304 *aIsSupported
= mClipboardCaps
.supportsFindClipboard();
306 case kSelectionCache
:
307 *aIsSupported
= mClipboardCaps
.supportsSelectionCache();
311 *aIsSupported
= false;
315 void nsClipboardProxy::SetCapabilities(
316 const ClipboardCapabilities
& aClipboardCaps
) {
317 mClipboardCaps
= aClipboardCaps
;