Commit 95c31a31 authored by Paolo Bacchilega's avatar Paolo Bacchilega

image preloader: implemented a smarter cache

parent 1e8f2388
......@@ -149,6 +149,7 @@ _cairo_image_surface_create_from_jpeg (GInputStream *istream,
int requested_size,
int *original_width_p,
int *original_height_p,
gboolean *loaded_original_p,
gpointer user_data,
GCancellable *cancellable,
GError **error)
......@@ -536,6 +537,8 @@ _cairo_image_surface_create_from_jpeg (GInputStream *istream,
*original_width_p = original_width;
if (original_height_p != NULL)
*original_height_p = original_height;
if (loaded_original_p != NULL)
*loaded_original_p = ! load_scaled;
jpeg_finish_decompress (&srcinfo);
jpeg_destroy_decompress (&srcinfo);
......
......@@ -32,6 +32,7 @@ GthImage * _cairo_image_surface_create_from_jpeg (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error);
......
......@@ -136,6 +136,7 @@ _cairo_image_surface_create_from_png (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
......
......@@ -32,6 +32,7 @@ GthImage * _cairo_image_surface_create_from_png (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error);
......
......@@ -168,6 +168,7 @@ _cairo_image_surface_create_from_svg (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
......
......@@ -32,6 +32,7 @@ GthImage * _cairo_image_surface_create_from_svg (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error);
......
......@@ -35,6 +35,7 @@ _cairo_image_surface_create_from_webp (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
......
......@@ -32,6 +32,7 @@ GthImage * _cairo_image_surface_create_from_webp (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error);
......
......@@ -954,6 +954,7 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
......
......@@ -32,6 +32,7 @@ GthImage * _cairo_image_surface_create_from_xcf (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error);
......
......@@ -933,6 +933,7 @@ image_loader_ready_cb (GObject *source_object,
&image,
&original_width,
&original_height,
NULL,
&error))
{
gth_task_completed (GTH_TASK (self), error);
......
......@@ -404,6 +404,7 @@ facebook_thumbnail_loader (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
......
......@@ -411,6 +411,7 @@ flickr_thumbnail_loader (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
......
......@@ -119,6 +119,7 @@ image_loader_ready_cb (GObject *source_object,
&image,
NULL,
NULL,
NULL,
&error);
if (error == NULL)
......
......@@ -267,7 +267,7 @@ different_quality_ready_cb (GObject *source_object,
return;
}
if (! _g_file_equal (requested->file, self->priv->file_data->file))
if (! (self->priv->image_changed && requested == NULL) && ! _g_file_equal (requested->file, self->priv->file_data->file))
goto clear_data;
if (image == NULL)
......@@ -295,11 +295,14 @@ clear_data:
static void
update_image_quality_if_required (GthImageViewerPage *self)
{
double zoom;
GthFileData *file_data;
double zoom;
if (self->priv->image_changed || self->priv->loading_image)
if (self->priv->loading_image)
return;
file_data = self->priv->image_changed ? GTH_MODIFIED_IMAGE : self->priv->file_data;
zoom = gth_image_viewer_get_zoom (GTH_IMAGE_VIEWER (self->priv->viewer));
if (zoom >= 1.0) {
int requested_size;
......@@ -312,7 +315,7 @@ update_image_quality_if_required (GthImageViewerPage *self)
&original_height);
if ((requested_size > 0) && (MAX (original_width, original_height) > requested_size)) {
gth_image_preloader_load (self->priv->preloader,
self->priv->file_data,
file_data,
GTH_ORIGINAL_SIZE,
NULL,
different_quality_ready_cb,
......@@ -329,7 +332,7 @@ update_image_quality_if_required (GthImageViewerPage *self)
new_requested_size = _gth_image_preloader_get_requested_size (self);
if (old_requested_size != new_requested_size) {
gth_image_preloader_load (self->priv->preloader,
self->priv->file_data,
file_data,
new_requested_size,
NULL,
different_quality_ready_cb,
......@@ -1395,6 +1398,8 @@ _gth_image_viewer_page_set_image (GthImageViewerPage *self,
if (image == NULL)
return;
if (requested_size == -1)
gth_image_preloader_set_modified_image (self->priv->preloader, image);
gth_image_viewer_set_surface (GTH_IMAGE_VIEWER (self->priv->viewer), image, -1, -1);
gth_image_viewer_set_requested_size (GTH_IMAGE_VIEWER (self->priv->viewer), requested_size);
......
......@@ -337,6 +337,7 @@ picasa_web_thumbnail_loader (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
......
......@@ -97,6 +97,7 @@ _libraw_read_jpeg_data (void *buffer,
NULL,
NULL,
NULL,
NULL,
cancellable,
error);
......@@ -226,6 +227,7 @@ _cairo_image_surface_create_from_raw (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
......@@ -268,6 +270,9 @@ _cairo_image_surface_create_from_raw (GInputStream *istream,
if (requested_size > 0) {
if (loaded_original != NULL)
*loaded_original = FALSE;
/* read the thumbnail */
result = libraw_unpack_thumb (raw_data);
......@@ -464,6 +469,7 @@ dcraw_pixbuf_animation_new_from_file (GInputStream *istream,
int requested_size,
int *original_width,
int *original_height,
gboolean *loaded_original,
gpointer user_data,
GCancellable *cancellable,
GError **error)
......
......@@ -2569,6 +2569,7 @@ image_loader_ready_cb (GObject *source_object,
&image,
NULL,
NULL,
NULL,
NULL))
{
load_next_file (self);
......
......@@ -26,6 +26,7 @@
#include "cairo-utils.h"
#include "cairo-scale.h"
#include "gfixed.h"
#include "glib-utils.h"
#define CLAMP_PIXEL(v) (((v) <= 0) ? 0 : ((v) >= 255) ? 255 : (v));
......@@ -503,13 +504,14 @@ _cairo_image_surface_scale (cairo_surface_t *image,
scale_filter_t filter,
GthAsyncTask *task)
{
int src_width;
int src_height;
cairo_surface_t *scaled;
resize_filter_t *resize_filter;
ScaleReal x_factor;
ScaleReal y_factor;
cairo_surface_t *tmp;
int src_width;
int src_height;
cairo_surface_t *scaled;
cairo_surface_metadata_t *metadata;
resize_filter_t *resize_filter;
ScaleReal x_factor;
ScaleReal y_factor;
cairo_surface_t *tmp;
src_width = cairo_image_surface_get_width (image);
src_height = cairo_image_surface_get_height (image);
......@@ -520,6 +522,10 @@ _cairo_image_surface_scale (cairo_surface_t *image,
scaled = _cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
scaled_width,
scaled_height);
metadata = _cairo_image_surface_get_metadata (scaled);
metadata->original_width = src_width;
metadata->original_height = src_height;
if (scaled == NULL)
return NULL;
......@@ -905,3 +911,115 @@ _cairo_image_surface_scale_bilinear (cairo_surface_t *image,
return tmp2;
}
/* -- _cairo_image_surface_scale_async -- */
typedef struct {
cairo_surface_t *original;
int new_width;
int new_height;
scale_filter_t quality;
cairo_surface_t *scaled;
GthTask *task;
} ScaleData;
static ScaleData *
scale_data_new (cairo_surface_t *image,
int new_width,
int new_height,
scale_filter_t quality,
GCancellable *cancellable)
{
ScaleData *scale_data;
scale_data = g_new0 (ScaleData, 1);
scale_data->original = cairo_surface_reference (image);
scale_data->new_width = new_width;
scale_data->new_height = new_height;
scale_data->quality = quality;
scale_data->scaled = NULL;
scale_data->task = gth_async_task_new (NULL, NULL, NULL, NULL, NULL);
gth_task_set_cancellable (scale_data->task, cancellable);
return scale_data;
}
static void
scale_data_free (ScaleData *scale_data)
{
_g_object_unref (scale_data->task);
cairo_surface_destroy (scale_data->scaled);
cairo_surface_destroy (scale_data->original);
g_free (scale_data);
}
static void
scale_image_thread (GSimpleAsyncResult *result,
GObject *object,
GCancellable *cancellable)
{
ScaleData *scale_data;
scale_data = g_simple_async_result_get_op_res_gpointer (result);
scale_data->scaled = _cairo_image_surface_scale (scale_data->original,
scale_data->new_width,
scale_data->new_height,
scale_data->quality,
GTH_ASYNC_TASK (scale_data->task));
}
void
_cairo_image_surface_scale_async (cairo_surface_t *image,
int new_width,
int new_height,
scale_filter_t quality,
GCancellable *cancellable,
GAsyncReadyCallback ready_callback,
gpointer user_data)
{
GSimpleAsyncResult *result;
result = g_simple_async_result_new (NULL,
ready_callback,
user_data,
_cairo_image_surface_scale_async);
g_simple_async_result_set_op_res_gpointer (result,
scale_data_new (image,
new_width,
new_height,
quality,
cancellable),
(GDestroyNotify) scale_data_free);
g_simple_async_result_run_in_thread (result,
scale_image_thread,
G_PRIORITY_DEFAULT,
cancellable);
g_object_unref (result);
}
cairo_surface_t *
_cairo_image_surface_scale_finish (GAsyncResult *result,
GError **error)
{
GSimpleAsyncResult *simple;
ScaleData *scale_data;
g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, _cairo_image_surface_scale_async), NULL);
simple = G_SIMPLE_ASYNC_RESULT (result);
if (g_simple_async_result_propagate_error (simple, error))
return NULL;
scale_data = g_simple_async_result_get_op_res_gpointer (simple);
return cairo_surface_reference (scale_data->scaled);
}
......@@ -47,21 +47,30 @@ typedef enum /*< skip >*/ {
} scale_filter_t;
cairo_surface_t * _cairo_image_surface_scale_nearest (cairo_surface_t *image,
int new_width,
int new_height);
cairo_surface_t * _cairo_image_surface_scale (cairo_surface_t *image,
int width,
int height,
scale_filter_t quality,
GthAsyncTask *task);
cairo_surface_t * _cairo_image_surface_scale_squared (cairo_surface_t *image,
int size,
scale_filter_t quality,
GthAsyncTask *task);
cairo_surface_t * _cairo_image_surface_scale_bilinear (cairo_surface_t *image,
int new_width,
int new_height);
cairo_surface_t * _cairo_image_surface_scale_nearest (cairo_surface_t *image,
int new_width,
int new_height);
cairo_surface_t * _cairo_image_surface_scale (cairo_surface_t *image,
int width,
int height,
scale_filter_t quality,
GthAsyncTask *task);
cairo_surface_t * _cairo_image_surface_scale_squared (cairo_surface_t *image,
int size,
scale_filter_t quality,
GthAsyncTask *task);
cairo_surface_t * _cairo_image_surface_scale_bilinear (cairo_surface_t *image,
int new_width,
int new_height);
void _cairo_image_surface_scale_async (cairo_surface_t *image,
int new_width,
int new_height,
scale_filter_t quality,
GCancellable *cancellable,
GAsyncReadyCallback ready_callback,
gpointer user_data);
cairo_surface_t * _cairo_image_surface_scale_finish (GAsyncResult *result,
GError **error);
G_END_DECLS
......
......@@ -85,7 +85,7 @@ _g_object_list_ref (GList *list)
void
_g_object_list_unref (GList *list)
{
g_list_foreach (list, (GFunc) g_object_unref, NULL);
g_list_foreach (list, (GFunc) _g_object_unref, NULL);
g_list_free (list);
}
......
......@@ -113,6 +113,7 @@ typedef struct {
GthImage *image;
int original_width;
int original_height;
gboolean loaded_original;
} LoadData;
......@@ -127,6 +128,7 @@ load_data_new (GthFileData *file_data,
load_data->file_data = _g_object_ref (file_data);
load_data->requested_size = requested_size;
load_data->cancellable = _g_object_ref (cancellable);
load_data->loaded_original = TRUE;
return load_data;
}
......@@ -143,14 +145,15 @@ load_data_unref (LoadData *load_data)
static void
load_pixbuf_thread (GSimpleAsyncResult *result,
GObject *object,
GCancellable *cancellable)
load_image_thread (GSimpleAsyncResult *result,
GObject *object,
GCancellable *cancellable)
{
GthImageLoader *self = GTH_IMAGE_LOADER (object);
LoadData *load_data;
int original_width;
int original_height;
gboolean loaded_original;
GInputStream *istream;
GthImage *image = NULL;
GError *error = NULL;
......@@ -166,12 +169,15 @@ load_pixbuf_thread (GSimpleAsyncResult *result,
return;
}
loaded_original = TRUE;
if (self->priv->loader_func != NULL) {
image = (*self->priv->loader_func) (istream,
load_data->file_data,
load_data->requested_size,
&original_width,
&original_height,
&loaded_original,
self->priv->loader_data,
cancellable,
&error);
......@@ -190,6 +196,7 @@ load_pixbuf_thread (GSimpleAsyncResult *result,
load_data->requested_size,
&original_width,
&original_height,
&loaded_original,
NULL,
cancellable,
&error);
......@@ -214,6 +221,7 @@ load_pixbuf_thread (GSimpleAsyncResult *result,
load_data->image = image;
load_data->original_width = original_width;
load_data->original_height = original_height;
load_data->loaded_original = loaded_original;
}
......@@ -238,7 +246,7 @@ gth_image_loader_load (GthImageLoader *loader,
cancellable),
(GDestroyNotify) load_data_unref);
g_simple_async_result_run_in_thread (result,
load_pixbuf_thread,
load_image_thread,
io_priority,
cancellable);
......@@ -252,6 +260,7 @@ gth_image_loader_load_finish (GthImageLoader *loader,
GthImage **image,
int *original_width,
int *original_height,
gboolean *loaded_original,
GError **error)
{
GSimpleAsyncResult *simple;
......@@ -271,6 +280,8 @@ gth_image_loader_load_finish (GthImageLoader *loader,
*original_width = load_data->original_width;
if (original_height != NULL)
*original_height = load_data->original_height;
if (loaded_original != NULL)
*loaded_original = load_data->loaded_original;
return TRUE;
}
......@@ -301,6 +312,7 @@ gth_image_new_from_stream (GInputStream *istream,
&original_width,
&original_height,
NULL,
NULL,
cancellable,
&error);
}
......
......@@ -69,6 +69,7 @@ gboolean gth_image_loader_load_finish (GthImageLoader
GthImage **image,
int *original_width,
int *original_height,
gboolean *loaded_original,
GError **error);
GthImage * gth_image_new_from_stream (GInputStream *istream,
int requested_size,
......
......@@ -23,8 +23,11 @@
#include <config.h>
#include <string.h>
#include <glib.h>
#include "cairo-scale.h"
#include "cairo-utils.h"
#include "glib-utils.h"
#include "gth-image-preloader.h"
#include "gth-image-utils.h"
#include "gth-marshal.h"
......@@ -121,15 +124,51 @@ cache_data_unref (CacheData *cache_data)
}
static inline gboolean
cache_data_file_matches (CacheData *cache_data,
GthFileData *file_data)
{
if ((file_data == GTH_MODIFIED_IMAGE) && (cache_data->file_data == GTH_MODIFIED_IMAGE))
return TRUE;
if ((file_data == GTH_MODIFIED_IMAGE) || (cache_data->file_data == GTH_MODIFIED_IMAGE))
return FALSE;
if (g_file_equal (cache_data->file_data->file, file_data->file)
&& (_g_time_val_cmp (gth_file_data_get_modification_time (file_data),
gth_file_data_get_modification_time (cache_data->file_data)) == 0))
{
return TRUE;
}
return FALSE;
}
static gboolean
cache_data_is_valid_for_request (CacheData *cache_data,
GthFileData *file_data,
int requested_size)
{
return ((cache_data->requested_size == requested_size)
&& g_file_equal (cache_data->file_data->file, file_data->file)
&& (_g_time_val_cmp (gth_file_data_get_modification_time (file_data),
gth_file_data_get_modification_time (cache_data->file_data)) == 0));
if (! cache_data_file_matches (cache_data, file_data))
return FALSE;
return cache_data->requested_size == requested_size;
}
static gboolean
cache_data_has_better_quality_for_request (CacheData *cache_data,
GthFileData *file_data,
int requested_size)
{
if (! cache_data_file_matches (cache_data, file_data))
return FALSE;