Bug 1743365 [Linux] Cache clipboard targets r=emilio

nsClipboard::HasDataMatchingFlavors() calls nsRetrievalContext::GetTargets() which obtains clipboard targets. We need to call Gtk code for that and spin evetn loop to get the targets.
In this patch we store clipboard tragets internally to speed up nsClipboard::HasDataMatchingFlavors() calls. We also listen at owner-change signal to clear target cache when clipboard content changes.

Differential Revision: https://phabricator.services.mozilla.com/D137899
This commit is contained in:
stransky
2022-02-11 07:43:11 +00:00
parent 4d16dd7018
commit b33b3dc3d1
6 changed files with 109 additions and 20 deletions

View File

@@ -58,6 +58,9 @@ static const char kHTMLMarkupPrefix[] =
static const char kURIListMime[] = "text/uri-list";
ClipboardTargets nsRetrievalContext::sClipboardTargets;
ClipboardTargets nsRetrievalContext::sPrimaryTargets;
// Callback when someone asks us for the data
void clipboard_get_cb(GtkClipboard* aGtkClipboard,
GtkSelectionData* aSelectionData, guint info,
@@ -71,6 +74,22 @@ static bool ConvertHTMLtoUCS2(Span<const char> aData, nsCString& charset,
static bool GetHTMLCharset(Span<const char> aData, nsCString& str);
ClipboardTargets ClipboardTargets::Clone() {
ClipboardTargets ret;
ret.mCount = mCount;
if (mCount) {
ret.mTargets.reset(
reinterpret_cast<GdkAtom*>(g_malloc(sizeof(GdkAtom) * mCount)));
memcpy(ret.mTargets.get(), mTargets.get(), sizeof(GdkAtom) * mCount);
}
return ret;
}
void ClipboardTargets::Set(ClipboardTargets aTargets) {
mCount = aTargets.mCount;
mTargets = std::move(aTargets.mTargets);
}
void ClipboardData::SetData(Span<const uint8_t> aData) {
mData = nullptr;
mLength = aData.Length();
@@ -118,6 +137,54 @@ int GetGeckoClipboardType(GtkClipboard* aGtkClipboard) {
return -1; // THAT AIN'T NO CLIPBOARD I EVER HEARD OF
}
void nsRetrievalContext::ClearCachedTargetsClipboard(GtkClipboard* aClipboard,
GdkEvent* aEvent,
gpointer data) {
LOGCLIP("nsRetrievalContext::ClearCachedTargetsClipboard()");
sClipboardTargets.Clear();
}
void nsRetrievalContext::ClearCachedTargetsPrimary(GtkClipboard* aClipboard,
GdkEvent* aEvent,
gpointer data) {
LOGCLIP("nsRetrievalContext::ClearCachedTargetsPrimary()");
sPrimaryTargets.Clear();
}
ClipboardTargets nsRetrievalContext::GetTargets(int32_t aWhichClipboard) {
LOGCLIP("nsRetrievalContext::GetTargets(%s)\n",
aWhichClipboard == nsClipboard::kSelectionClipboard ? "primary"
: "clipboard");
ClipboardTargets& storedTargets =
(aWhichClipboard == nsClipboard::kSelectionClipboard) ? sPrimaryTargets
: sClipboardTargets;
if (!storedTargets) {
LOGCLIP(" getting targets from system");
storedTargets.Set(GetTargetsImpl(aWhichClipboard));
} else {
LOGCLIP(" using cached targets");
}
return storedTargets.Clone();
}
nsRetrievalContext::nsRetrievalContext() {
g_signal_connect(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), "owner-change",
G_CALLBACK(ClearCachedTargetsClipboard), this);
g_signal_connect(gtk_clipboard_get(GDK_SELECTION_PRIMARY), "owner-change",
G_CALLBACK(ClearCachedTargetsPrimary), this);
}
nsRetrievalContext::~nsRetrievalContext() {
g_signal_handlers_disconnect_by_func(
gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
FuncToGpointer(ClearCachedTargetsClipboard), this);
g_signal_handlers_disconnect_by_func(
gtk_clipboard_get(GDK_SELECTION_PRIMARY),
FuncToGpointer(ClearCachedTargetsPrimary), this);
sClipboardTargets.Clear();
sPrimaryTargets.Clear();
}
nsClipboard::nsClipboard() = default;
nsClipboard::~nsClipboard() {
@@ -241,6 +308,8 @@ nsClipboard::SetData(nsITransferable* aTransferable, nsIClipboardOwner* aOwner,
return NS_ERROR_FAILURE;
}
ClearCachedTargets(aWhichClipboard);
// Set getcallback and request to store data after an application exit
if (gtk_clipboard_set_with_data(gtkClipboard, gtkTargets, numTargets,
clipboard_get_cb, clipboard_clear_cb, this)) {
@@ -524,7 +593,7 @@ nsClipboard::EmptyClipboard(int32_t aWhichClipboard) {
MOZ_ASSERT(!mGlobalTransferable);
}
}
ClearCachedTargets(aWhichClipboard);
return NS_OK;
}
@@ -561,7 +630,6 @@ nsClipboard::HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList,
}
auto targets = mContext->GetTargets(aWhichClipboard);
if (!targets) {
LOGCLIP(" no targes at clipboard (null)\n");
return NS_OK;
@@ -842,15 +910,22 @@ void nsClipboard::SelectionGetEvent(GtkClipboard* aClipboard,
free(primitive_data);
}
void nsClipboard::ClearCachedTargets(int32_t aWhichClipboard) {
if (aWhichClipboard == kSelectionClipboard) {
nsRetrievalContext::ClearCachedTargetsPrimary(nullptr, nullptr, nullptr);
} else {
nsRetrievalContext::ClearCachedTargetsClipboard(nullptr, nullptr, nullptr);
}
}
void nsClipboard::SelectionClearEvent(GtkClipboard* aGtkClipboard) {
int32_t whichClipboard = GetGeckoClipboardType(aGtkClipboard);
if (whichClipboard < 0) {
return;
}
LOGCLIP("nsClipboard::SelectionClearEvent (%s)\n",
whichClipboard == kSelectionClipboard ? "primary" : "clipboard");
ClearCachedTargets(whichClipboard);
ClearTransferable(whichClipboard);
}

View File

@@ -41,6 +41,13 @@ class ClipboardTargets {
ClipboardTargets(mozilla::GUniquePtr<GdkAtom> aTargets, uint32_t aCount)
: mTargets(std::move(aTargets)), mCount(aCount) {}
void Set(ClipboardTargets);
ClipboardTargets Clone();
void Clear() {
mTargets = nullptr;
mCount = 0;
};
mozilla::Span<GdkAtom> AsSpan() const { return {mTargets.get(), mCount}; }
explicit operator bool() const { return bool(mTargets); }
};
@@ -80,12 +87,23 @@ class nsRetrievalContext {
virtual mozilla::GUniquePtr<char> GetClipboardText(
int32_t aWhichClipboard) = 0;
// Get data mime types which can be obtained from clipboard. The returned
// array has to be released by g_free().
virtual ClipboardTargets GetTargets(int32_t aWhichClipboard) = 0;
// Get data mime types which can be obtained from clipboard.
ClipboardTargets GetTargets(int32_t aWhichClipboard);
// Clipboard/Primary selection owner changed. Clear internal cached data.
static void ClearCachedTargetsClipboard(GtkClipboard* aClipboard,
GdkEvent* aEvent, gpointer data);
static void ClearCachedTargetsPrimary(GtkClipboard* aClipboard,
GdkEvent* aEvent, gpointer data);
nsRetrievalContext();
protected:
virtual ~nsRetrievalContext() = default;
virtual ClipboardTargets GetTargetsImpl(int32_t aWhichClipboard) = 0;
virtual ~nsRetrievalContext();
static ClipboardTargets sClipboardTargets;
static ClipboardTargets sPrimaryTargets;
};
class nsClipboard : public nsIClipboard, public nsIObserver {
@@ -118,6 +136,7 @@ class nsClipboard : public nsIClipboard, public nsIObserver {
uint32_t aClipboardDataLength);
void ClearTransferable(int32_t aWhichClipboard);
void ClearCachedTargets(int32_t aWhichClipboard);
bool FilterImportedFlavors(int32_t aWhichClipboard,
nsTArray<nsCString>& aFlavors);

View File

@@ -20,9 +20,9 @@ using namespace mozilla;
nsRetrievalContextWayland::nsRetrievalContextWayland() = default;
ClipboardTargets nsRetrievalContextWayland::GetTargets(
ClipboardTargets nsRetrievalContextWayland::GetTargetsImpl(
int32_t aWhichClipboard) {
LOGCLIP("nsRetrievalContextWayland::GetTargets()\n");
LOGCLIP("nsRetrievalContextWayland::GetTargetsImpl()\n");
return WaitForClipboardData(ClipboardDataType::Targets, aWhichClipboard)
.ExtractTargets();

View File

@@ -15,15 +15,10 @@ class nsRetrievalContextWayland final : public nsRetrievalContext {
public:
nsRetrievalContextWayland();
// Successful call of GetClipboardData()/GetClipboardText() needs to be paired
// with ReleaseClipboardData().
ClipboardData GetClipboardData(const char* aMimeType,
int32_t aWhichClipboard) override;
mozilla::GUniquePtr<char> GetClipboardText(int32_t aWhichClipboard) override;
// GetTargets() uses clipboard data internally so it can't be used between
// GetClipboardData()/GetClipboardText() and ReleaseClipboardData() calls.
ClipboardTargets GetTargets(int32_t aWhichClipboard) override;
ClipboardTargets GetTargetsImpl(int32_t aWhichClipboard) override;
private:
ClipboardData WaitForClipboardData(ClipboardDataType, int32_t aWhichClipboard,

View File

@@ -138,11 +138,11 @@ ClipboardData nsRetrievalContextX11::WaitForClipboardData(
return {};
}
ClipboardTargets nsRetrievalContextX11::GetTargets(int32_t aWhichClipboard) {
LOGCLIP("nsRetrievalContextX11::GetTargets(%s)\n",
ClipboardTargets nsRetrievalContextX11::GetTargetsImpl(
int32_t aWhichClipboard) {
LOGCLIP("nsRetrievalContextX11::GetTargetsImpl(%s)\n",
aWhichClipboard == nsClipboard::kSelectionClipboard ? "primary"
: "clipboard");
return WaitForClipboardData(ClipboardDataType::Targets, aWhichClipboard)
.ExtractTargets();
}

View File

@@ -18,7 +18,7 @@ class nsRetrievalContextX11 : public nsRetrievalContext {
ClipboardData GetClipboardData(const char* aMimeType,
int32_t aWhichClipboard) override;
mozilla::GUniquePtr<char> GetClipboardText(int32_t aWhichClipboard) override;
ClipboardTargets GetTargets(int32_t aWhichClipboard) override;
ClipboardTargets GetTargetsImpl(int32_t aWhichClipboard) override;
nsRetrievalContextX11();