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