Bug 1812543 - [Cocoa] Check cached transferable properly in nsClipboard::HasDataMatchingFlavors; r=spohl

Differential Revision: https://phabricator.services.mozilla.com/D167932
This commit is contained in:
Edgar Chen 2023-01-26 20:04:30 +00:00
parent d05bc6c6f5
commit 38bdecc2a6
5 changed files with 125 additions and 26 deletions

View file

@ -350,36 +350,42 @@ nsClipboard::HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList, int3
*outResult = false;
if (aWhichClipboard != kGlobalClipboard) return NS_OK;
if (aWhichClipboard != kGlobalClipboard) {
return NS_OK;
}
// first see if we have data for this in our cached transferable
if (mTransferable) {
nsTArray<nsCString> flavors;
nsresult rv = mTransferable->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());
NSPasteboard* generalPBoard = [NSPasteboard generalPasteboard];
if (mCachedClipboard == aWhichClipboard) {
if (mChangeCount != [generalPBoard changeCount]) {
// Clear the cached transferable as it is no longer valid.
ClearClipboardCache();
} else if (mTransferable) {
// See if we have data for this in our cached transferable.
nsTArray<nsCString> flavors;
nsresult rv = mTransferable->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 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;
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;
}
}
}
}
}
}
NSPasteboard* generalPBoard = [NSPasteboard generalPasteboard];
if (CLIPBOARD_LOG_ENABLED()) {
NSArray* types = [generalPBoard types];
uint32_t count = [types count];

View file

@ -115,12 +115,7 @@ NS_IMETHODIMP nsBaseClipboard::EmptyClipboard(int32_t aWhichClipboard) {
return NS_OK;
}
if (mClipboardOwner) {
mClipboardOwner->LosingOwnership(mTransferable);
mClipboardOwner = nullptr;
}
mTransferable = nullptr;
ClearClipboardCache();
return NS_OK;
}
@ -155,3 +150,11 @@ nsBaseClipboard::IsClipboardTypeSupported(int32_t aWhichClipboard,
*_retval = kGlobalClipboard == aWhichClipboard;
return NS_OK;
}
void nsBaseClipboard::ClearClipboardCache() {
if (mClipboardOwner) {
mClipboardOwner->LosingOwnership(mTransferable);
mClipboardOwner = nullptr;
}
mTransferable = nullptr;
}

View file

@ -42,6 +42,8 @@ class nsBaseClipboard : public nsIClipboard {
NS_IMETHOD GetNativeClipboardData(nsITransferable* aTransferable,
int32_t aWhichClipboard) = 0;
void ClearClipboardCache();
bool mEmptyingForSetData;
nsCOMPtr<nsIClipboardOwner> mClipboardOwner;
nsCOMPtr<nsITransferable> mTransferable;

View file

@ -38,6 +38,7 @@ skip-if =
skip-if = toolkit != "cocoa" && toolkit != "windows" || (os == "win" && os_version == "10.0" && !ccov) # Bug 1456811
[test_bug760802.xhtml]
[test_clipboard.xhtml]
[test_clipboard_cache.xhtml]
[test_panel_mouse_coords.xhtml]
skip-if = toolkit == "windows" # bug 1009955

View file

@ -0,0 +1,87 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1812543
-->
<window title="Mozilla Bug 1812543"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
</body>
<!-- test code goes here -->
<script class="testbody" type="application/javascript">
<![CDATA[
const clipboard = SpecialPowers.Services.clipboard;
const clipboardTypes = [
clipboard.kSelectionClipboard,
clipboard.kFindClipboard,
];
function GenerateRandomString() {
return "random number: " + Math.random();
}
function writeStringToClipboard(aStr, aFlavor, aClipboardType) {
let trans = Cc["@mozilla.org/widget/transferable;1"].createInstance(Ci.nsITransferable);
trans.init(null);
trans.addDataFlavor(aFlavor);
let supportsStr = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
supportsStr.data = aStr;
trans.setTransferData(aFlavor, supportsStr);
clipboard.setData(trans, null, aClipboardType);
}
function CleanupAllClipboard() {
clipboard.emptyClipboard(clipboard.kGlobalClipboard);
clipboardTypes.forEach(function(type) {
if (clipboard.isClipboardTypeSupported(type)) {
info(`cleanup clipboard ${type}`);
clipboard.emptyClipboard(type);
}
});
}
let supportOtherClipboardTypes = false;
clipboardTypes.forEach(function(type) {
if (clipboard.isClipboardTypeSupported(type)) {
supportOtherClipboardTypes = true;
add_task(function test_clipboard_hasDataMatchingFlavors() {
info(`Test write data to clipboard type ${type}`);
// Write text/unicode data to main clipboard.
writeStringToClipboard(GenerateRandomString(), "text/unicode", clipboard.kGlobalClipboard);
ok(clipboard.hasDataMatchingFlavors(["text/unicode"], clipboard.kGlobalClipboard),
"Should have text/unicode flavor");
ok(!clipboard.hasDataMatchingFlavors(["text/html"], clipboard.kGlobalClipboard),
"Should not have text/html flavor");
// Write text/html data to other clipboard.
writeStringToClipboard(GenerateRandomString(), "text/html", type);
ok(clipboard.hasDataMatchingFlavors(["text/unicode"], clipboard.kGlobalClipboard),
"Should have text/unicode flavor");
ok(!clipboard.hasDataMatchingFlavors(["text/html"], clipboard.kGlobalClipboard),
"Should not have text/html flavor");
// Clean clipboard data.
CleanupAllClipboard();
});
}
});
if (!supportOtherClipboardTypes) {
ok(true, "Don't support other clipboard types, skip tests");
}
]]>
</script>
</window>