Pre-scale loaded thumbnails, and only when needed
This commit is contained in:
		
							parent
							
								
									dbc500ae9f
								
							
						
					
					
						commit
						cdb8d852a6
					
				
							
								
								
									
										121
									
								
								fastiv-browser.c
									
									
									
									
									
								
							
							
						
						
									
										121
									
								
								fastiv-browser.c
									
									
									
									
									
								
							| @ -37,6 +37,8 @@ entry_free(Entry *self) | |||||||
| 		cairo_surface_destroy(self->thumbnail); | 		cairo_surface_destroy(self->thumbnail); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static const double g_row_height = 256; | ||||||
|  | 
 | ||||||
| // --- Boilerplate -------------------------------------------------------------
 | // --- Boilerplate -------------------------------------------------------------
 | ||||||
| 
 | 
 | ||||||
| struct _FastivBrowser { | 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, | 	gtk_render_background(gtk_widget_get_style_context(widget), cr, 0, 0, | ||||||
| 		allocation.width, allocation.height); | 		allocation.width, allocation.height); | ||||||
| 
 | 
 | ||||||
| 	const double row_height = 256; |  | ||||||
| 
 |  | ||||||
| 	gint occupied_width = 0, y = 0; | 	gint occupied_width = 0, y = 0; | ||||||
| 	for (guint i = 0; i < self->entries->len; i++) { | 	for (guint i = 0; i < self->entries->len; i++) { | ||||||
| 		const Entry *entry = &g_array_index(self->entries, Entry, 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 width = cairo_image_surface_get_width(entry->thumbnail); | ||||||
| 		int height = cairo_image_surface_get_height(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 && | 		if (occupied_width != 0 && | ||||||
| 			occupied_width + projected_width > allocation.width) { | 			occupied_width + width > allocation.width) { | ||||||
| 			occupied_width = 0; | 			occupied_width = 0; | ||||||
| 			y += row_height; | 			y += g_row_height; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		cairo_save(cr); | 		cairo_save(cr); | ||||||
| 		cairo_translate(cr, occupied_width, y + row_height - projected_height); | 		cairo_translate(cr, occupied_width, y + g_row_height - height); | ||||||
| 		cairo_set_source_surface(cr, scaled, 0, 0); | 		cairo_set_source_surface(cr, entry->thumbnail, 0, 0); | ||||||
| 		cairo_surface_destroy(scaled); |  | ||||||
| 		cairo_paint(cr); | 		cairo_paint(cr); | ||||||
| 		cairo_restore(cr); | 		cairo_restore(cr); | ||||||
| 
 | 
 | ||||||
| 		occupied_width += projected_width; | 		occupied_width += width; | ||||||
| 	} | 	} | ||||||
| 	return TRUE; | 	return TRUE; | ||||||
| } | } | ||||||
| @ -241,6 +195,64 @@ fastiv_browser_init(FastivBrowser *self) | |||||||
| 	self->selected = -1; | 	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 | void | ||||||
| fastiv_browser_load(FastivBrowser *self, const char *path) | 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); | 		gchar *subpath = g_build_filename(path, filename, NULL); | ||||||
| 		g_array_append_val(self->entries, | 		g_array_append_val(self->entries, | ||||||
| 			((Entry){ | 			((Entry){ | ||||||
| 				.thumbnail = fastiv_io_lookup_thumbnail(subpath), | 				.thumbnail = | ||||||
|  | 					rescale_thumbnail(fastiv_io_lookup_thumbnail(subpath)), | ||||||
| 				.filename = subpath, | 				.filename = subpath, | ||||||
| 			})); | 			})); | ||||||
| 	} | 	} | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user