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 "nsBaseClipboard.h"
8 #include "nsIClipboardOwner.h"
12 using mozilla::GenericPromise
;
13 using mozilla::LogLevel
;
15 NS_IMPL_ISUPPORTS(ClipboardSetDataHelper::AsyncSetClipboardData
,
16 nsIAsyncSetClipboardData
)
18 ClipboardSetDataHelper::AsyncSetClipboardData::AsyncSetClipboardData(
19 int32_t aClipboardType
, ClipboardSetDataHelper
* aClipboard
,
20 nsIAsyncSetClipboardDataCallback
* aCallback
)
21 : mClipboardType(aClipboardType
),
22 mClipboard(aClipboard
),
23 mCallback(aCallback
) {
24 MOZ_ASSERT(mClipboard
);
25 MOZ_ASSERT(mClipboard
->IsClipboardTypeSupported(mClipboardType
));
29 ClipboardSetDataHelper::AsyncSetClipboardData::SetData(
30 nsITransferable
* aTransferable
, nsIClipboardOwner
* aOwner
) {
32 return NS_ERROR_FAILURE
;
35 MOZ_ASSERT(mClipboard
);
36 MOZ_ASSERT(mClipboard
->IsClipboardTypeSupported(mClipboardType
));
37 MOZ_DIAGNOSTIC_ASSERT(mClipboard
->mPendingWriteRequests
[mClipboardType
] ==
40 RefPtr
<AsyncSetClipboardData
> request
=
41 std::move(mClipboard
->mPendingWriteRequests
[mClipboardType
]);
42 nsresult rv
= mClipboard
->SetData(aTransferable
, aOwner
, mClipboardType
);
43 MaybeNotifyCallback(rv
);
49 ClipboardSetDataHelper::AsyncSetClipboardData::Abort(nsresult aReason
) {
50 // Note: This may be called during destructor, so it should not attempt to
51 // take a reference to mClipboard.
53 if (!IsValid() || !NS_FAILED(aReason
)) {
54 return NS_ERROR_FAILURE
;
57 MaybeNotifyCallback(aReason
);
61 void ClipboardSetDataHelper::AsyncSetClipboardData::MaybeNotifyCallback(
63 // Note: This may be called during destructor, so it should not attempt to
64 // take a reference to mClipboard.
66 MOZ_ASSERT(IsValid());
67 if (nsCOMPtr
<nsIAsyncSetClipboardDataCallback
> callback
=
69 callback
->OnComplete(aResult
);
71 // Once the callback is notified, setData should not be allowed, so invalidate
76 NS_IMPL_ISUPPORTS(ClipboardSetDataHelper
, nsIClipboard
)
78 ClipboardSetDataHelper::~ClipboardSetDataHelper() {
79 for (auto& request
: mPendingWriteRequests
) {
81 request
->Abort(NS_ERROR_ABORT
);
87 void ClipboardSetDataHelper::RejectPendingAsyncSetDataRequestIfAny(
88 int32_t aClipboardType
) {
89 MOZ_ASSERT(nsIClipboard::IsClipboardTypeSupported(aClipboardType
));
90 auto& request
= mPendingWriteRequests
[aClipboardType
];
92 request
->Abort(NS_ERROR_ABORT
);
98 ClipboardSetDataHelper::SetData(nsITransferable
* aTransferable
,
99 nsIClipboardOwner
* aOwner
,
100 int32_t aWhichClipboard
) {
101 NS_ENSURE_ARG(aTransferable
);
102 if (!nsIClipboard::IsClipboardTypeSupported(aWhichClipboard
)) {
103 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
106 // Reject existing pending asyncSetData request if any.
107 RejectPendingAsyncSetDataRequestIfAny(aWhichClipboard
);
109 return SetNativeClipboardData(aTransferable
, aOwner
, aWhichClipboard
);
112 NS_IMETHODIMP
ClipboardSetDataHelper::AsyncSetData(
113 int32_t aWhichClipboard
, nsIAsyncSetClipboardDataCallback
* aCallback
,
114 nsIAsyncSetClipboardData
** _retval
) {
116 if (!nsIClipboard::IsClipboardTypeSupported(aWhichClipboard
)) {
117 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
120 // Reject existing pending AsyncSetData request if any.
121 RejectPendingAsyncSetDataRequestIfAny(aWhichClipboard
);
123 // Create a new AsyncSetClipboardData.
124 RefPtr
<AsyncSetClipboardData
> request
=
125 mozilla::MakeRefPtr
<AsyncSetClipboardData
>(aWhichClipboard
, this,
127 mPendingWriteRequests
[aWhichClipboard
] = request
;
128 request
.forget(_retval
);
132 nsBaseClipboard::nsBaseClipboard() : mEmptyingForSetData(false) {}
134 nsBaseClipboard::~nsBaseClipboard() {
135 EmptyClipboard(kSelectionClipboard
);
136 EmptyClipboard(kGlobalClipboard
);
137 EmptyClipboard(kFindClipboard
);
140 NS_IMPL_ISUPPORTS_INHERITED0(nsBaseClipboard
, ClipboardSetDataHelper
)
143 * Sets the transferable object
146 NS_IMETHODIMP
nsBaseClipboard::SetData(nsITransferable
* aTransferable
,
147 nsIClipboardOwner
* anOwner
,
148 int32_t aWhichClipboard
) {
149 NS_ASSERTION(aTransferable
, "clipboard given a null transferable");
151 CLIPBOARD_LOG("%s", __FUNCTION__
);
153 if (aTransferable
== mTransferable
&& anOwner
== mClipboardOwner
) {
154 CLIPBOARD_LOG("%s: skipping update.", __FUNCTION__
);
158 if (!nsIClipboard::IsClipboardTypeSupported(kSelectionClipboard
) &&
159 !nsIClipboard::IsClipboardTypeSupported(kFindClipboard
) &&
160 aWhichClipboard
!= kGlobalClipboard
) {
161 return NS_ERROR_FAILURE
;
164 mEmptyingForSetData
= true;
165 if (NS_FAILED(EmptyClipboard(aWhichClipboard
))) {
166 CLIPBOARD_LOG("%s: emptying clipboard failed.", __FUNCTION__
);
168 mEmptyingForSetData
= false;
170 mClipboardOwner
= anOwner
;
171 mTransferable
= aTransferable
;
173 nsresult rv
= NS_ERROR_FAILURE
;
175 mIgnoreEmptyNotification
= true;
176 rv
= ClipboardSetDataHelper::SetData(aTransferable
, anOwner
,
178 mIgnoreEmptyNotification
= false;
181 CLIPBOARD_LOG("%s: setting native clipboard data failed.", __FUNCTION__
);
188 * Gets the transferable object
191 NS_IMETHODIMP
nsBaseClipboard::GetData(nsITransferable
* aTransferable
,
192 int32_t aWhichClipboard
) {
193 NS_ASSERTION(aTransferable
, "clipboard given a null transferable");
195 CLIPBOARD_LOG("%s", __FUNCTION__
);
197 if (!nsIClipboard::IsClipboardTypeSupported(kSelectionClipboard
) &&
198 !nsIClipboard::IsClipboardTypeSupported(kFindClipboard
) &&
199 aWhichClipboard
!= kGlobalClipboard
) {
200 return NS_ERROR_FAILURE
;
204 return GetNativeClipboardData(aTransferable
, aWhichClipboard
);
206 return NS_ERROR_FAILURE
;
209 RefPtr
<GenericPromise
> nsBaseClipboard::AsyncGetData(
210 nsITransferable
* aTransferable
, int32_t aWhichClipboard
) {
211 nsresult rv
= GetData(aTransferable
, aWhichClipboard
);
213 return GenericPromise::CreateAndReject(rv
, __func__
);
216 return GenericPromise::CreateAndResolve(true, __func__
);
219 NS_IMETHODIMP
nsBaseClipboard::EmptyClipboard(int32_t aWhichClipboard
) {
220 CLIPBOARD_LOG("%s: clipboard=%i", __FUNCTION__
, aWhichClipboard
);
222 if (!nsIClipboard::IsClipboardTypeSupported(kSelectionClipboard
) &&
223 !nsIClipboard::IsClipboardTypeSupported(kFindClipboard
) &&
224 aWhichClipboard
!= kGlobalClipboard
) {
225 return NS_ERROR_FAILURE
;
228 if (mIgnoreEmptyNotification
) {
229 MOZ_DIAGNOSTIC_ASSERT(false, "How did we get here?");
233 ClearClipboardCache();
238 nsBaseClipboard::HasDataMatchingFlavors(const nsTArray
<nsCString
>& aFlavorList
,
239 int32_t aWhichClipboard
,
241 *outResult
= true; // say we always do.
245 RefPtr
<DataFlavorsPromise
> nsBaseClipboard::AsyncHasDataMatchingFlavors(
246 const nsTArray
<nsCString
>& aFlavorList
, int32_t aWhichClipboard
) {
247 nsTArray
<nsCString
> results
;
248 for (const auto& flavor
: aFlavorList
) {
249 bool hasMatchingFlavor
= false;
250 nsresult rv
= HasDataMatchingFlavors(AutoTArray
<nsCString
, 1>{flavor
},
251 aWhichClipboard
, &hasMatchingFlavor
);
252 if (NS_SUCCEEDED(rv
) && hasMatchingFlavor
) {
253 results
.AppendElement(flavor
);
257 return DataFlavorsPromise::CreateAndResolve(std::move(results
), __func__
);
261 nsBaseClipboard::IsClipboardTypeSupported(int32_t aWhichClipboard
,
263 NS_ENSURE_ARG_POINTER(_retval
);
264 // We support global clipboard by default.
265 *_retval
= kGlobalClipboard
== aWhichClipboard
;
269 void nsBaseClipboard::ClearClipboardCache() {
270 if (mClipboardOwner
) {
271 mClipboardOwner
->LosingOwnership(mTransferable
);
272 mClipboardOwner
= nullptr;
274 mTransferable
= nullptr;