Bug 1810850 - Part 3: Move clipboard cache code for HasDataMatchingFlavors to nsBaseClipboard; r=cmartin,mstange

Depends on D179993

Differential Revision: https://phabricator.services.mozilla.com/D179999
This commit is contained in:
Edgar Chen 2023-06-26 21:02:40 +00:00
Родитель 2dd7f27175
Коммит 1d8c57b7a7
7 изменённых файлов: 140 добавлений и 103 удалений

Просмотреть файл

@ -24,8 +24,6 @@ class nsClipboard : public nsBaseClipboard {
NS_DECL_ISUPPORTS_INHERITED
// nsIClipboard
NS_IMETHOD HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard,
bool* _retval) override;
NS_IMETHOD EmptyClipboard(int32_t aWhichClipboard) override;
// On macOS, cache the transferable of the current selection (chrome/content)
@ -50,6 +48,8 @@ class nsClipboard : public nsBaseClipboard {
int32_t aWhichClipboard) override;
mozilla::Result<int32_t, nsresult> GetNativeClipboardSequenceNumber(
int32_t aWhichClipboard) override;
mozilla::Result<bool, nsresult> HasNativeClipboardDataMatchingFlavors(
const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard) override;
void ClearSelectionCache();
void SetSelectionCache(nsITransferable* aTransferable);

Просмотреть файл

@ -347,59 +347,16 @@ nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhi
}
// returns true if we have *any* of the passed in flavors available for pasting
NS_IMETHODIMP
nsClipboard::HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard,
bool* outResult) {
mozilla::Result<bool, nsresult> nsClipboard::HasNativeClipboardDataMatchingFlavors(
const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard) {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
CLIPBOARD_LOG("%s: clipboard=%i", __FUNCTION__, aWhichClipboard);
CLIPBOARD_LOG(" Asking for content:\n");
for (auto& flavor : aFlavorList) {
CLIPBOARD_LOG(" MIME %s\n", flavor.get());
}
*outResult = false;
// We only support the set operation on kSelectionCache type, see bug 1835059.
if ((aWhichClipboard != kGlobalClipboard && aWhichClipboard != kFindClipboard)) {
return NS_OK;
}
// XXX we only support the set operation on kSelectionCache type, see bug 1835059.
MOZ_DIAGNOSTIC_ASSERT(kSelectionCache != aWhichClipboard);
MOZ_DIAGNOSTIC_ASSERT(nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
NSPasteboard* cocoaPasteboard = GetPasteboard(aWhichClipboard);
MOZ_ASSERT(cocoaPasteboard);
if (mCachedClipboard == aWhichClipboard) {
const auto& clipboardCache = mCaches[mCachedClipboard];
MOZ_ASSERT(clipboardCache);
if (mChangeCount != [cocoaPasteboard changeCount]) {
// Clear the cached transferable as it is no longer valid.
clipboardCache->Clear();
} else if (nsITransferable* cachedTrans = clipboardCache->GetTransferable()) {
// See if we have data for this in our cached transferable.
nsTArray<nsCString> flavors;
nsresult rv = cachedTrans->FlavorsTransferableCanImport(flavors);
if (NS_SUCCEEDED(rv)) {
if (CLIPBOARD_LOG_ENABLED()) {
CLIPBOARD_LOG(" Cached transferable types (nums %zu)\n", flavors.Length());
for (uint32_t j = 0; j < flavors.Length(); j++) {
CLIPBOARD_LOG(" MIME %s\n", flavors[j].get());
}
}
for (uint32_t j = 0; j < flavors.Length(); j++) {
const nsCString& transferableFlavorStr = flavors[j];
for (uint32_t k = 0; k < aFlavorList.Length(); k++) {
if (transferableFlavorStr.Equals(aFlavorList[k])) {
CLIPBOARD_LOG(" has %s\n", aFlavorList[k].get());
*outResult = true;
return NS_OK;
}
}
}
}
}
}
if (CLIPBOARD_LOG_ENABLED()) {
NSArray* types = [cocoaPasteboard types];
uint32_t count = [types count];
@ -421,8 +378,7 @@ nsClipboard::HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList, int3
[cocoaPasteboard availableTypeFromArray:[NSArray arrayWithObject:pboardType]];
if (availableType && [availableType isEqualToString:pboardType]) {
CLIPBOARD_LOG(" has %s\n", mimeType.get());
*outResult = true;
break;
return true;
}
} else if (mimeType.EqualsLiteral(kCustomTypesMime)) {
NSString* availableType = [cocoaPasteboard
@ -430,8 +386,7 @@ nsClipboard::HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList, int3
[NSArray arrayWithObject:[UTIHelper stringFromPboardType:kMozCustomTypesPboardType]]];
if (availableType) {
CLIPBOARD_LOG(" has %s\n", mimeType.get());
*outResult = true;
break;
return true;
}
} else if (mimeType.EqualsLiteral(kJPEGImageMime) || mimeType.EqualsLiteral(kJPGImageMime) ||
mimeType.EqualsLiteral(kPNGImageMime) || mimeType.EqualsLiteral(kGIFImageMime)) {
@ -441,8 +396,7 @@ nsClipboard::HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList, int3
[UTIHelper stringFromPboardType:NSPasteboardTypePNG], nil]];
if (availableType) {
CLIPBOARD_LOG(" has %s\n", mimeType.get());
*outResult = true;
break;
return true;
}
} else if (mimeType.EqualsLiteral(kFileMime)) {
NSArray* items = [cocoaPasteboard pasteboardItems];
@ -456,21 +410,20 @@ nsClipboard::HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList, int3
stringFromPboardType:(NSString*)kUTTypeFileURL],
nil]]) {
CLIPBOARD_LOG(" has %s\n", mimeType.get());
*outResult = true;
break;
return true;
}
}
}
}
}
if (CLIPBOARD_LOG_ENABLED() && !(*outResult)) {
if (CLIPBOARD_LOG_ENABLED()) {
CLIPBOARD_LOG(" no targets at clipboard (bad match)\n");
}
return NS_OK;
return false;
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
NS_OBJC_END_TRY_BLOCK_RETURN(mozilla::Err(NS_ERROR_FAILURE));
}
// static

Просмотреть файл

@ -293,8 +293,67 @@ NS_IMETHODIMP nsBaseClipboard::EmptyClipboard(int32_t aWhichClipboard) {
NS_IMETHODIMP
nsBaseClipboard::HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList,
int32_t aWhichClipboard,
bool* outResult) {
*outResult = true; // say we always do.
bool* aOutResult) {
CLIPBOARD_LOG("%s: clipboard=%d", __FUNCTION__, aWhichClipboard);
if (CLIPBOARD_LOG_ENABLED()) {
CLIPBOARD_LOG(" Asking for content clipboard=%i:\n", aWhichClipboard);
for (const auto& flavor : aFlavorList) {
CLIPBOARD_LOG(" MIME %s", flavor.get());
}
}
*aOutResult = false;
// XXX as of now, we only support the set operation on kSelectionCache type,
// should we also support the get operation? See also bug 1835059.
if (kSelectionCache == aWhichClipboard ||
!nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)) {
CLIPBOARD_LOG("%s: clipboard %d is not supported.", __FUNCTION__,
aWhichClipboard);
// XXX should we return a error instead?
return NS_OK;
}
if (mozilla::StaticPrefs::widget_clipboard_use_cached_data_enabled()) {
if (auto* clipboardCache = GetClipboardCacheIfValid(aWhichClipboard)) {
MOZ_ASSERT(clipboardCache->GetTransferable());
// first see if we have data for this in our cached transferable
nsTArray<nsCString> transferableFlavors;
nsresult rv =
clipboardCache->GetTransferable()->FlavorsTransferableCanImport(
transferableFlavors);
if (NS_SUCCEEDED(rv)) {
if (CLIPBOARD_LOG_ENABLED()) {
CLIPBOARD_LOG(" Cached transferable types (nums %zu)\n",
transferableFlavors.Length());
for (const auto& transferableFlavor : transferableFlavors) {
CLIPBOARD_LOG(" MIME %s", transferableFlavor.get());
}
}
for (const auto& transferableFlavor : transferableFlavors) {
for (const auto& flavor : aFlavorList) {
if (transferableFlavor.Equals(flavor)) {
CLIPBOARD_LOG(" has %s", flavor.get());
*aOutResult = true;
return NS_OK;
}
}
}
}
}
}
auto resultOrError =
HasNativeClipboardDataMatchingFlavors(aFlavorList, aWhichClipboard);
if (resultOrError.isErr()) {
CLIPBOARD_LOG("%s: checking native clipboard data matching flavors falied.",
__FUNCTION__);
return resultOrError.unwrapErr();
}
*aOutResult = resultOrError.unwrap();
return NS_OK;
}

Просмотреть файл

@ -110,13 +110,14 @@ class nsBaseClipboard : public ClipboardSetDataHelper {
NS_IMETHOD EmptyClipboard(int32_t aWhichClipboard) override;
NS_IMETHOD HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList,
int32_t aWhichClipboard,
bool* _retval) override;
bool* aOutResult) override final;
NS_IMETHOD IsClipboardTypeSupported(int32_t aWhichClipboard,
bool* aRetval) override final;
RefPtr<mozilla::GenericPromise> AsyncGetData(
nsITransferable* aTransferable, int32_t aWhichClipboard) override final;
RefPtr<DataFlavorsPromise> AsyncHasDataMatchingFlavors(
const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard) override;
const nsTArray<nsCString>& aFlavorList,
int32_t aWhichClipboard) override final;
protected:
virtual ~nsBaseClipboard() = default;
@ -126,7 +127,12 @@ class nsBaseClipboard : public ClipboardSetDataHelper {
int32_t aWhichClipboard) = 0;
virtual mozilla::Result<int32_t, nsresult> GetNativeClipboardSequenceNumber(
int32_t aWhichClipboard) = 0;
virtual mozilla::Result<bool, nsresult> HasNativeClipboardDataMatchingFlavors(
const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard) = 0;
bool mEmptyingForSetData = false;
private:
class ClipboardCache final {
public:
~ClipboardCache() {
@ -157,14 +163,11 @@ class nsBaseClipboard : public ClipboardSetDataHelper {
int32_t mSequenceNumber = -1;
};
mozilla::UniquePtr<ClipboardCache> mCaches[nsIClipboard::kClipboardTypeCount];
bool mEmptyingForSetData = false;
private:
// Return clipboard cache if the cached data is valid, otherwise clear the
// cached data and returns null.
ClipboardCache* GetClipboardCacheIfValid(int32_t aClipboardType);
mozilla::UniquePtr<ClipboardCache> mCaches[nsIClipboard::kClipboardTypeCount];
const mozilla::dom::ClipboardCapabilities mClipboardCaps;
bool mIgnoreEmptyNotification = false;
};

Просмотреть файл

@ -82,28 +82,56 @@ clipboardTypes.forEach(function(type) {
return;
}
if (clipboard.kGlobalClipboard != type) {
add_task(function test_clipboard_hasDataMatchingFlavors() {
info(`Test write data to clipboard type ${type}`);
add_task(function test_clipboard_hasDataMatchingFlavors() {
const trans = generateNewTransferable("text/plain", generateRandomString());
// Write text/plain data to main clipboard.
writeRandomStringToClipboard("text/plain", clipboard.kGlobalClipboard);
ok(clipboard.hasDataMatchingFlavors(["text/plain"], clipboard.kGlobalClipboard),
"Should have text/plain flavor");
ok(!clipboard.hasDataMatchingFlavors(["text/html"], clipboard.kGlobalClipboard),
"Should not have text/html flavor");
info(`Write text/plain data to clipboard ${type}`);
clipboard.setData(trans, null, type);
ok(clipboard.hasDataMatchingFlavors(["text/plain"], type),
`Check if there is text/plain flavor on clipboard ${type}`);
ok(!clipboard.hasDataMatchingFlavors(["text/foo"], type),
`Check if there is text/foo flavor on clipboard ${type}`);
// Write text/html data to other clipboard.
writeRandomStringToClipboard("text/html", type);
ok(clipboard.hasDataMatchingFlavors(["text/plain"], clipboard.kGlobalClipboard),
"Should have text/plain flavor");
ok(!clipboard.hasDataMatchingFlavors(["text/html"], clipboard.kGlobalClipboard),
"Should not have text/html flavor");
info(`Add text/foo data to transferable`);
addStringToTransferable("text/foo", generateRandomString(), trans);
ok(clipboard.hasDataMatchingFlavors(["text/plain"], type),
`Check if there is text/plain flavor on clipboard ${type}`);
is(clipboard.hasDataMatchingFlavors(["text/foo"], type),
isSupportGetFromCachedTransferable,
`Check if there is text/foo flavor on clipboard ${type}`);
// Clean clipboard data.
cleanupAllClipboard();
// Check other clipboard types.
clipboardTypes.forEach(function(otherType) {
if (otherType != clipboard.kSelectionCache &&
otherType != type &&
clipboard.isClipboardTypeSupported(otherType)) {
ok(!clipboard.hasDataMatchingFlavors(["text/plain"], otherType),
`Check if there is text/plain flavor on clipboard ${otherType}`);
ok(!clipboard.hasDataMatchingFlavors(["text/foo"], otherType),
`Check if there is text/foo flavor on clipboard ${otherType}`);
info(`Write text/plain data to clipboard ${otherType}`);
writeRandomStringToClipboard("text/plain", otherType);
}
});
}
// Check again.
ok(clipboard.hasDataMatchingFlavors(["text/plain"], type),
`Check if there is text/plain flavor on clipboard ${type}`);
is(clipboard.hasDataMatchingFlavors(["text/foo"], type),
isSupportGetFromCachedTransferable,
`Check if there is text/foo flavor on clipboard ${type}`);
info(`Write text/plain data to clipboard ${type} again`);
writeRandomStringToClipboard("text/plain", type);
ok(clipboard.hasDataMatchingFlavors(["text/plain"], type),
`Check if there is text/plain flavor on clipboard ${type}`);
ok(!clipboard.hasDataMatchingFlavors(["text/foo"], type),
`Check if there is text/foo flavor on clipboard ${type}`);
// Clean clipboard data.
cleanupAllClipboard();
});
// Test sync set clipboard data.
testClipboardCache(type, false);

Просмотреть файл

@ -1361,23 +1361,18 @@ nsClipboard::GetNativeClipboardSequenceNumber(int32_t aWhichClipboard) {
}
//-------------------------------------------------------------------------
NS_IMETHODIMP nsClipboard::HasDataMatchingFlavors(
const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard,
bool* _retval) {
*_retval = false;
if (aWhichClipboard != kGlobalClipboard) {
return NS_OK;
}
for (auto& flavor : aFlavorList) {
mozilla::Result<bool, nsresult>
nsClipboard::HasNativeClipboardDataMatchingFlavors(
const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard) {
MOZ_DIAGNOSTIC_ASSERT(
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
for (const auto& flavor : aFlavorList) {
UINT format = GetFormat(flavor.get());
if (IsClipboardFormatAvailable(format)) {
*_retval = true;
break;
return true;
}
}
return NS_OK;
return false;
}
//-------------------------------------------------------------------------

Просмотреть файл

@ -34,9 +34,6 @@ class nsClipboard : public nsBaseClipboard, public nsIObserver {
NS_DECL_NSIOBSERVER
// nsIClipboard
NS_IMETHOD HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList,
int32_t aWhichClipboard,
bool* _retval) override;
NS_IMETHOD EmptyClipboard(int32_t aWhichClipboard) override;
// Internal Native Routines
@ -84,6 +81,8 @@ class nsClipboard : public nsBaseClipboard, public nsIObserver {
int32_t aWhichClipboard) override;
mozilla::Result<int32_t, nsresult> GetNativeClipboardSequenceNumber(
int32_t aWhichClipboard) override;
mozilla::Result<bool, nsresult> HasNativeClipboardDataMatchingFlavors(
const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard) override;
static bool IsInternetShortcut(const nsAString& inFileName);
static bool FindURLFromLocalFile(IDataObject* inDataObject, UINT inIndex,