diff --git a/fastiv-browser.c b/fastiv-browser.c index ba6d8a3..818006c 100644 --- a/fastiv-browser.c +++ b/fastiv-browser.c @@ -37,6 +37,8 @@ entry_free(Entry *self) cairo_surface_destroy(self->thumbnail); } +static const double g_row_height = 256; + // --- Boilerplate ------------------------------------------------------------- struct _FastivBrowser { @@ -135,8 +137,6 @@ fastiv_browser_draw(GtkWidget *widget, cairo_t *cr) gtk_render_background(gtk_widget_get_style_context(widget), cr, 0, 0, allocation.width, allocation.height); - const double row_height = 256; - gint occupied_width = 0, y = 0; for (guint i = 0; i < self->entries->len; i++) { const Entry *entry = &g_array_index(self->entries, Entry, i); @@ -145,65 +145,19 @@ fastiv_browser_draw(GtkWidget *widget, cairo_t *cr) int width = cairo_image_surface_get_width(entry->thumbnail); int height = cairo_image_surface_get_height(entry->thumbnail); - - double scale_x = 1; - double scale_y = 1; - if (width > 2 * height) { - scale_x = 2 * row_height / width; - scale_y = round(scale_x * height) / height; - } else { - scale_y = row_height / height; - scale_x = round(scale_y * width) / width; - } - - int projected_width = round(scale_x * width); - int projected_height = round(scale_y * height); - cairo_surface_t *scaled = cairo_image_surface_create( - CAIRO_FORMAT_ARGB32, projected_width, projected_height); - - // pixman can take gamma into account when scaling, unlike Cairo. - struct pixman_f_transform xform_floating; - struct pixman_transform xform; - - pixman_image_t *src = pixman_image_create_bits( - PIXMAN_a8r8g8b8_sRGB, width, height, - (uint32_t *) cairo_image_surface_get_data(entry->thumbnail), - cairo_image_surface_get_stride(entry->thumbnail)); - pixman_image_t *dest = pixman_image_create_bits( - PIXMAN_a8r8g8b8_sRGB, - cairo_image_surface_get_width(scaled), - cairo_image_surface_get_height(scaled), - (uint32_t *) cairo_image_surface_get_data(scaled), - cairo_image_surface_get_stride(scaled)); - - pixman_f_transform_init_scale(&xform_floating, scale_x, scale_y); - pixman_f_transform_invert(&xform_floating, &xform_floating); - pixman_transform_from_pixman_f_transform(&xform, &xform_floating); - pixman_image_set_transform(src, &xform); - pixman_image_set_filter(src, PIXMAN_FILTER_BILINEAR, NULL, 0); - pixman_image_set_repeat(src, PIXMAN_REPEAT_PAD); - - pixman_image_composite(PIXMAN_OP_SRC, src, NULL, dest, 0, 0, 0, 0, 0, 0, - projected_width, projected_height); - pixman_image_unref(src); - pixman_image_unref(dest); - - cairo_surface_mark_dirty(scaled); - if (occupied_width != 0 && - occupied_width + projected_width > allocation.width) { + occupied_width + width > allocation.width) { occupied_width = 0; - y += row_height; + y += g_row_height; } cairo_save(cr); - cairo_translate(cr, occupied_width, y + row_height - projected_height); - cairo_set_source_surface(cr, scaled, 0, 0); - cairo_surface_destroy(scaled); + cairo_translate(cr, occupied_width, y + g_row_height - height); + cairo_set_source_surface(cr, entry->thumbnail, 0, 0); cairo_paint(cr); cairo_restore(cr); - occupied_width += projected_width; + occupied_width += width; } return TRUE; } @@ -241,6 +195,64 @@ fastiv_browser_init(FastivBrowser *self) self->selected = -1; } +static cairo_surface_t * +rescale_thumbnail(cairo_surface_t *thumbnail) +{ + if (!thumbnail) + return thumbnail; + + int width = cairo_image_surface_get_width(thumbnail); + int height = cairo_image_surface_get_height(thumbnail); + + double scale_x = 1; + double scale_y = 1; + if (width > 2 * height) { + scale_x = 2 * g_row_height / width; + scale_y = round(scale_x * height) / height; + } else { + scale_y = g_row_height / height; + scale_x = round(scale_y * width) / width; + } + if (scale_x == 1 && scale_y == 1) + return thumbnail; + + int projected_width = round(scale_x * width); + int projected_height = round(scale_y * height); + cairo_surface_t *scaled = cairo_image_surface_create( + CAIRO_FORMAT_ARGB32, projected_width, projected_height); + + // pixman can take gamma into account when scaling, unlike Cairo. + struct pixman_f_transform xform_floating; + struct pixman_transform xform; + + pixman_image_t *src = pixman_image_create_bits( + PIXMAN_a8r8g8b8_sRGB, width, height, + (uint32_t *) cairo_image_surface_get_data(thumbnail), + cairo_image_surface_get_stride(thumbnail)); + pixman_image_t *dest = pixman_image_create_bits( + PIXMAN_a8r8g8b8_sRGB, + cairo_image_surface_get_width(scaled), + cairo_image_surface_get_height(scaled), + (uint32_t *) cairo_image_surface_get_data(scaled), + cairo_image_surface_get_stride(scaled)); + + pixman_f_transform_init_scale(&xform_floating, scale_x, scale_y); + pixman_f_transform_invert(&xform_floating, &xform_floating); + pixman_transform_from_pixman_f_transform(&xform, &xform_floating); + pixman_image_set_transform(src, &xform); + pixman_image_set_filter(src, PIXMAN_FILTER_BILINEAR, NULL, 0); + pixman_image_set_repeat(src, PIXMAN_REPEAT_PAD); + + pixman_image_composite(PIXMAN_OP_SRC, src, NULL, dest, 0, 0, 0, 0, 0, 0, + projected_width, projected_height); + pixman_image_unref(src); + pixman_image_unref(dest); + + cairo_surface_destroy(thumbnail); + cairo_surface_mark_dirty(scaled); + return scaled; +} + void fastiv_browser_load(FastivBrowser *self, const char *path) { @@ -259,7 +271,8 @@ fastiv_browser_load(FastivBrowser *self, const char *path) gchar *subpath = g_build_filename(path, filename, NULL); g_array_append_val(self->entries, ((Entry){ - .thumbnail = fastiv_io_lookup_thumbnail(subpath), + .thumbnail = + rescale_thumbnail(fastiv_io_lookup_thumbnail(subpath)), .filename = subpath, })); }