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 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
|
/* -*- 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/. */
#ifndef nsBaseClipboard_h__
#define nsBaseClipboard_h__
#include "mozilla/Array.h"
#include "mozilla/dom/PContent.h"
#include "mozilla/Logging.h"
#include "mozilla/MoveOnlyFunction.h"
#include "mozilla/Result.h"
#include "nsIClipboard.h"
#include "nsITransferable.h"
#include "nsCOMPtr.h"
extern mozilla::LazyLogModule gWidgetClipboardLog;
#define MOZ_CLIPBOARD_LOG(...) \
MOZ_LOG(gWidgetClipboardLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
#define MOZ_CLIPBOARD_LOG_ENABLED() \
MOZ_LOG_TEST(gWidgetClipboardLog, mozilla::LogLevel::Debug)
class nsITransferable;
class nsIClipboardOwner;
class nsIPrincipal;
class nsIWidget;
namespace mozilla::dom {
class WindowContext;
} // namespace mozilla::dom
/**
* A base clipboard class for all platform, so that they can share the same
* implementation.
*/
class nsBaseClipboard : public nsIClipboard {
public:
explicit nsBaseClipboard(
const mozilla::dom::ClipboardCapabilities& aClipboardCaps);
// nsISupports
NS_DECL_ISUPPORTS
// nsIClipboard
NS_IMETHOD SetData(
nsITransferable* aTransferable, nsIClipboardOwner* aOwner,
ClipboardType aWhichClipboard,
mozilla::dom::WindowContext* aWindowContext) override final;
NS_IMETHOD AsyncSetData(ClipboardType aWhichClipboard,
mozilla::dom::WindowContext* aSettingWindowContext,
nsIAsyncClipboardRequestCallback* aCallback,
nsIAsyncSetClipboardData** _retval) override final;
NS_IMETHOD GetData(
nsITransferable* aTransferable, ClipboardType aWhichClipboard,
mozilla::dom::WindowContext* aWindowContext) override final;
NS_IMETHOD GetDataSnapshot(
const nsTArray<nsCString>& aFlavorList, ClipboardType aWhichClipboard,
mozilla::dom::WindowContext* aRequestingWindowContext,
nsIPrincipal* aRequestingPrincipal,
nsIClipboardGetDataSnapshotCallback* aCallback) override final;
NS_IMETHOD GetDataSnapshotSync(
const nsTArray<nsCString>& aFlavorList, ClipboardType aWhichClipboard,
mozilla::dom::WindowContext* aRequestingWindowContext,
nsIClipboardDataSnapshot** _retval) override final;
NS_IMETHOD EmptyClipboard(ClipboardType aWhichClipboard) override final;
NS_IMETHOD HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList,
ClipboardType aWhichClipboard,
bool* aOutResult) override final;
NS_IMETHOD IsClipboardTypeSupported(ClipboardType aWhichClipboard,
bool* aRetval) override final;
void GetDataSnapshotInternal(
const nsTArray<nsCString>& aFlavorList,
nsIClipboard::ClipboardType aClipboardType,
mozilla::dom::WindowContext* aRequestingWindowContext,
nsIClipboardGetDataSnapshotCallback* aCallback);
using GetNativeDataCallback = mozilla::MoveOnlyFunction<void(
mozilla::Result<nsCOMPtr<nsISupports>, nsresult>)>;
using HasMatchingFlavorsCallback = mozilla::MoveOnlyFunction<void(
mozilla::Result<nsTArray<nsCString>, nsresult>)>;
mozilla::Maybe<uint64_t> GetClipboardCacheInnerWindowId(
ClipboardType aClipboardType);
virtual mozilla::Result<int32_t, nsresult> GetNativeClipboardSequenceNumber(
ClipboardType aWhichClipboard) = 0;
class ClipboardPopulatedDataSnapshot final : public nsIClipboardDataSnapshot {
public:
explicit ClipboardPopulatedDataSnapshot(nsITransferable* aTransferable);
NS_DECL_ISUPPORTS
NS_DECL_NSICLIPBOARDDATASNAPSHOT
private:
virtual ~ClipboardPopulatedDataSnapshot() = default;
nsCOMPtr<nsITransferable> mTransferable;
// List of available data types for clipboard content.
nsTArray<nsCString> mFlavors;
};
protected:
virtual ~nsBaseClipboard();
// Implement the native clipboard behavior.
NS_IMETHOD SetNativeClipboardData(nsITransferable* aTransferable,
ClipboardType aWhichClipboard) = 0;
virtual mozilla::Result<nsCOMPtr<nsISupports>, nsresult>
GetNativeClipboardData(const nsACString& aFlavor,
ClipboardType aWhichClipboard) = 0;
virtual void AsyncGetNativeClipboardData(const nsACString& aFlavor,
ClipboardType aWhichClipboard,
GetNativeDataCallback&& aCallback);
virtual nsresult EmptyNativeClipboardData(ClipboardType aWhichClipboard) = 0;
virtual mozilla::Result<bool, nsresult> HasNativeClipboardDataMatchingFlavors(
const nsTArray<nsCString>& aFlavorList,
ClipboardType aWhichClipboard) = 0;
virtual void AsyncHasNativeClipboardDataMatchingFlavors(
const nsTArray<nsCString>& aFlavorList, ClipboardType aWhichClipboard,
HasMatchingFlavorsCallback&& aCallback);
void ClearClipboardCache(ClipboardType aClipboardType);
private:
void RejectPendingAsyncSetDataRequestIfAny(ClipboardType aClipboardType);
class AsyncSetClipboardData final : public nsIAsyncSetClipboardData {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIASYNCSETCLIPBOARDDATA
AsyncSetClipboardData(nsIClipboard::ClipboardType aClipboardType,
nsBaseClipboard* aClipboard,
mozilla::dom::WindowContext* aRequestingWindowContext,
nsIAsyncClipboardRequestCallback* aCallback);
private:
virtual ~AsyncSetClipboardData() = default;
bool IsValid() const {
// If this request is no longer valid, the callback should be notified.
MOZ_ASSERT_IF(!mClipboard, !mCallback);
return !!mClipboard;
}
void MaybeNotifyCallback(nsresult aResult);
// The clipboard type defined in nsIClipboard.
nsIClipboard::ClipboardType mClipboardType;
// It is safe to use a raw pointer as it will be nullified (by calling
// NotifyCallback()) once nsBaseClipboard stops tracking us. This is
// also used to indicate whether this request is valid.
nsBaseClipboard* mClipboard;
RefPtr<mozilla::dom::WindowContext> mWindowContext;
// mCallback will be nullified once the callback is notified to ensure the
// callback is only notified once.
nsCOMPtr<nsIAsyncClipboardRequestCallback> mCallback;
};
class ClipboardDataSnapshot final : public nsIClipboardDataSnapshot {
public:
ClipboardDataSnapshot(
nsIClipboard::ClipboardType aClipboardType, int32_t aSequenceNumber,
nsTArray<nsCString>&& aFlavors, bool aFromCache,
nsBaseClipboard* aClipboard,
mozilla::dom::WindowContext* aRequestingWindowContext);
NS_DECL_ISUPPORTS
NS_DECL_NSICLIPBOARDDATASNAPSHOT
private:
virtual ~ClipboardDataSnapshot() = default;
bool IsValid();
using GetDataInternalCallback = mozilla::MoveOnlyFunction<void(nsresult)>;
void GetDataInternal(nsTArray<nsCString>&& aTypes,
nsTArray<nsCString>::index_type aIndex,
nsITransferable* aTransferable,
GetDataInternalCallback&& aCallback);
// The clipboard type defined in nsIClipboard.
const nsIClipboard::ClipboardType mClipboardType;
// The sequence number associated with the clipboard content for this
// request. If it doesn't match with the current sequence number in system
// clipboard, this request targets stale data and is deemed invalid.
const int32_t mSequenceNumber;
// List of available data types for clipboard content.
const nsTArray<nsCString> mFlavors;
// Data should be read from cache.
const bool mFromCache;
// This is also used to indicate whether this request is still valid.
RefPtr<nsBaseClipboard> mClipboard;
// The requesting window, which is used for Content Analysis purposes.
RefPtr<mozilla::dom::WindowContext> mRequestingWindowContext;
};
class ClipboardCache final {
public:
~ClipboardCache() {
// In order to notify the old clipboard owner.
Clear();
}
/**
* Clear the cached transferable and notify the original clipboard owner
* that it has lost ownership.
*/
void Clear();
void Update(nsITransferable* aTransferable,
nsIClipboardOwner* aClipboardOwner, int32_t aSequenceNumber,
mozilla::Maybe<uint64_t> aInnerWindowId) {
// Clear first to notify the old clipboard owner.
Clear();
mTransferable = aTransferable;
mClipboardOwner = aClipboardOwner;
mSequenceNumber = aSequenceNumber;
mInnerWindowId = aInnerWindowId;
}
nsITransferable* GetTransferable() const { return mTransferable; }
nsIClipboardOwner* GetClipboardOwner() const { return mClipboardOwner; }
int32_t GetSequenceNumber() const { return mSequenceNumber; }
mozilla::Maybe<uint64_t> GetInnerWindowId() const { return mInnerWindowId; }
nsresult GetData(nsITransferable* aTransferable) const;
private:
nsCOMPtr<nsITransferable> mTransferable;
nsCOMPtr<nsIClipboardOwner> mClipboardOwner;
int32_t mSequenceNumber = -1;
mozilla::Maybe<uint64_t> mInnerWindowId;
};
void MaybeRetryGetAvailableFlavors(
const nsTArray<nsCString>& aFlavorList,
nsIClipboard::ClipboardType aWhichClipboard,
nsIClipboardGetDataSnapshotCallback* aCallback, int32_t aRetryCount,
mozilla::dom::WindowContext* aRequestingWindowContext);
// Return clipboard cache if the cached data is valid, otherwise clear the
// cached data and returns null.
ClipboardCache* GetClipboardCacheIfValid(ClipboardType aClipboardType);
mozilla::Result<nsTArray<nsCString>, nsresult> GetFlavorsFromClipboardCache(
ClipboardType aClipboardType);
nsresult GetDataFromClipboardCache(nsITransferable* aTransferable,
ClipboardType aClipboardType);
void RequestUserConfirmation(ClipboardType aClipboardType,
const nsTArray<nsCString>& aFlavorList,
mozilla::dom::WindowContext* aWindowContext,
nsIPrincipal* aRequestingPrincipal,
nsIClipboardGetDataSnapshotCallback* aCallback);
already_AddRefed<nsIClipboardDataSnapshot>
MaybeCreateGetRequestFromClipboardCache(
const nsTArray<nsCString>& aFlavorList, ClipboardType aClipboardType,
mozilla::dom::WindowContext* aRequestingWindowContext);
// Clean up data in transferable for posting to clipboard or dragging. This
// guarantees that text data does not include NUL characters.
static nsresult SanitizeForClipboard(nsITransferable* aTransferable);
// Track the pending request for each clipboard type separately. And only need
// to track the latest request for each clipboard type as the prior pending
// request will be canceled when a new request is made.
mozilla::Array<RefPtr<AsyncSetClipboardData>,
nsIClipboard::kClipboardTypeCount>
mPendingWriteRequests;
mozilla::Array<mozilla::UniquePtr<ClipboardCache>,
nsIClipboard::kClipboardTypeCount>
mCaches;
const mozilla::dom::ClipboardCapabilities mClipboardCaps;
bool mIgnoreEmptyNotification = false;
};
#endif // nsBaseClipboard_h__
|