Employ embedded thumbnail extraction

And store all direct thumbnailer output in the browser's cache--
low-quality thumbnails will always be regenerated, as is desired,
and we'll reload faster on devices where we don't store thumbnails.

This change improves latency at the cost of overall efficiency,
seeing as images with thumbnails will be spent cycles on twice.

Keeping this out-of-process avoids undesired lock-ups.
Moreover, embedded thumbnails can be fairly expensive to decode.
This commit is contained in:
Přemysl Eric Janouch 2022-06-08 01:05:04 +02:00
parent 8dfbd0dee2
commit a8f7532abd
Signed by: p
GPG Key ID: A0420B94F92B9493
1 changed files with 42 additions and 15 deletions

View File

@ -439,6 +439,9 @@ entry_add_thumbnail(gpointer data, gpointer user_data)
(intptr_t) cairo_surface_get_user_data( (intptr_t) cairo_surface_get_user_data(
cached, &fiv_browser_key_mtime_msec) == self->mtime_msec) { cached, &fiv_browser_key_mtime_msec) == self->mtime_msec) {
self->thumbnail = cairo_surface_reference(cached); self->thumbnail = cairo_surface_reference(cached);
// TODO(p): If this hit is low-quality, see if a high-quality thumbnail
// hasn't been produced without our knowledge (avoid launching a minion
// unnecessarily; we might also shift the concern there).
} else { } else {
cairo_surface_t *found = fiv_thumbnail_lookup( cairo_surface_t *found = fiv_thumbnail_lookup(
self->uri, self->mtime_msec, browser->item_size); self->uri, self->mtime_msec, browser->item_size);
@ -555,19 +558,31 @@ thumbnailer_reprocess_entry(FivBrowser *self, GBytes *output, Entry *entry)
{ {
g_clear_object(&entry->icon); g_clear_object(&entry->icon);
g_clear_pointer(&entry->thumbnail, cairo_surface_destroy); g_clear_pointer(&entry->thumbnail, cairo_surface_destroy);
guint64 dummy;
if (!output || !(entry->thumbnail = rescale_thumbnail(
fiv_io_deserialize(output, &dummy), self->item_height))) {
entry_add_thumbnail(entry, self);
materialize_icon(self, entry);
} else {
// This choice of mtime favours unnecessary thumbnail reloading.
cairo_surface_set_user_data(entry->thumbnail,
&fiv_browser_key_mtime_msec, (void *) (intptr_t) entry->mtime_msec,
NULL);
}
gtk_widget_queue_resize(GTK_WIDGET(self)); gtk_widget_queue_resize(GTK_WIDGET(self));
guint64 flags = 0;
if (!output || !(entry->thumbnail = rescale_thumbnail(
fiv_io_deserialize(output, &flags), self->item_height))) {
entry_add_thumbnail(entry, self);
materialize_icon(self, entry);
return;
}
if ((flags & FIV_IO_SERIALIZE_LOW_QUALITY)) {
cairo_surface_set_user_data(entry->thumbnail, &fiv_thumbnail_key_lq,
(void *) (intptr_t) 1, NULL);
// TODO(p): Improve complexity; this will iterate the whole linked list.
self->thumbnailers_queue =
g_list_append(self->thumbnailers_queue, entry);
}
// This choice of mtime favours unnecessary thumbnail reloading.
cairo_surface_set_user_data(entry->thumbnail,
&fiv_browser_key_mtime_msec, (void *) (intptr_t) entry->mtime_msec,
NULL);
g_hash_table_insert(self->thumbnail_cache, g_strdup(entry->uri),
cairo_surface_reference(entry->thumbnail));
} }
static void static void
@ -629,11 +644,23 @@ thumbnailer_next(Thumbnailer *t)
self->thumbnailers_queue = self->thumbnailers_queue =
g_list_delete_link(self->thumbnailers_queue, self->thumbnailers_queue); g_list_delete_link(self->thumbnailers_queue, self->thumbnailers_queue);
// Case analysis:
// - We haven't found any thumbnail for the entry at all
// (and it has a symbolic icon as a result):
// we want to fill the void ASAP, so go for embedded thumbnails first.
// - We've found one, but we're not quite happy with it:
// always run the full process for a high-quality wide thumbnail.
// - We can't end up here in any other cases.
const char *argv_faster[] = {PROJECT_NAME, "--extract-thumbnail",
"--thumbnail", fiv_thumbnail_sizes[self->item_size].thumbnail_spec_name,
"--", t->target->uri, NULL};
const char *argv_slower[] = {PROJECT_NAME,
"--thumbnail", fiv_thumbnail_sizes[self->item_size].thumbnail_spec_name,
"--", t->target->uri, NULL};
GError *error = NULL; GError *error = NULL;
t->minion = g_subprocess_new(G_SUBPROCESS_FLAGS_STDOUT_PIPE, &error, t->minion = g_subprocess_newv(t->target->icon ? argv_faster : argv_slower,
PROJECT_NAME, "--thumbnail", G_SUBPROCESS_FLAGS_STDOUT_PIPE, &error);
fiv_thumbnail_sizes[self->item_size].thumbnail_spec_name, "--",
t->target->uri, NULL);
if (error) { if (error) {
g_warning("%s", error->message); g_warning("%s", error->message);
g_error_free(error); g_error_free(error);