diff options
Diffstat (limited to 'libview')
-rw-r--r-- | libview/ev-pixbuf-cache.c | 162 | ||||
-rw-r--r-- | libview/ev-pixbuf-cache.h | 6 | ||||
-rw-r--r-- | libview/ev-view-private.h | 1 | ||||
-rw-r--r-- | libview/ev-view.c | 27 | ||||
-rw-r--r-- | libview/ev-view.h | 18 |
5 files changed, 181 insertions, 33 deletions
diff --git a/libview/ev-pixbuf-cache.c b/libview/ev-pixbuf-cache.c index 8658711..530f084 100644 --- a/libview/ev-pixbuf-cache.c +++ b/libview/ev-pixbuf-cache.c @@ -37,10 +37,13 @@ struct _EvPixbufCache /* We keep a link to our containing view just for style information. */ GtkWidget *view; EvDocument *document; + EvDocumentModel *model; int start_page; int end_page; gboolean inverted_colors; + gsize max_size; + /* preload_cache_size is the number of pages prior to the current * visible area that we cache. It's normally 1, but could be 2 in the * case of twin pages. @@ -89,18 +92,15 @@ static gboolean new_selection_surface_needed(EvPixbufCache *pixbuf_cac #define PAGE_CACHE_LEN(pixbuf_cache) \ ((pixbuf_cache->end_page - pixbuf_cache->start_page) + 1) +#define MAX_PRELOADED_PAGES 3 + G_DEFINE_TYPE (EvPixbufCache, ev_pixbuf_cache, G_TYPE_OBJECT) static void ev_pixbuf_cache_init (EvPixbufCache *pixbuf_cache) { - pixbuf_cache->start_page = 0; - pixbuf_cache->end_page = 0; - pixbuf_cache->job_list = g_new0 (CacheJobInfo, PAGE_CACHE_LEN (pixbuf_cache)); - - pixbuf_cache->preload_cache_size = 2; - pixbuf_cache->prev_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size); - pixbuf_cache->next_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size); + pixbuf_cache->start_page = -1; + pixbuf_cache->end_page = -1; } static void @@ -135,6 +135,8 @@ ev_pixbuf_cache_finalize (GObject *object) g_free (pixbuf_cache->job_list); g_free (pixbuf_cache->next_job); + g_object_unref (pixbuf_cache->model); + G_OBJECT_CLASS (ev_pixbuf_cache_parent_class)->finalize (object); } @@ -195,19 +197,34 @@ ev_pixbuf_cache_dispose (GObject *object) EvPixbufCache * -ev_pixbuf_cache_new (GtkWidget *view, - EvDocument *document) +ev_pixbuf_cache_new (GtkWidget *view, + EvDocumentModel *model, + gsize max_size) { EvPixbufCache *pixbuf_cache; pixbuf_cache = (EvPixbufCache *) g_object_new (EV_TYPE_PIXBUF_CACHE, NULL); /* This is a backlink, so we don't ref this */ pixbuf_cache->view = view; - pixbuf_cache->document = document; + pixbuf_cache->model = g_object_ref (model); + pixbuf_cache->document = ev_document_model_get_document (model); + pixbuf_cache->max_size = max_size; return pixbuf_cache; } +void +ev_pixbuf_cache_set_max_size (EvPixbufCache *pixbuf_cache, + gsize max_size) +{ + if (pixbuf_cache->max_size == max_size) + return; + + if (pixbuf_cache->max_size > max_size) + ev_pixbuf_cache_clear (pixbuf_cache); + pixbuf_cache->max_size = max_size; +} + static void copy_job_to_job_info (EvJobRender *job_render, CacheJobInfo *job_info, @@ -313,6 +330,7 @@ move_one_job (CacheJobInfo *job_info, CacheJobInfo *new_job_list, CacheJobInfo *new_prev_job, CacheJobInfo *new_next_job, + int new_preload_cache_size, int start_page, int end_page, gint priority) @@ -321,25 +339,25 @@ move_one_job (CacheJobInfo *job_info, int page_offset; gint new_priority; - if (page < (start_page - pixbuf_cache->preload_cache_size) || - page > (end_page + pixbuf_cache->preload_cache_size)) { + if (page < (start_page - new_preload_cache_size) || + page > (end_page + new_preload_cache_size)) { dispose_cache_job_info (job_info, pixbuf_cache); return; } /* find the target page to copy it over to. */ if (page < start_page) { - page_offset = (page - (start_page - pixbuf_cache->preload_cache_size)); + page_offset = (page - (start_page - new_preload_cache_size)); g_assert (page_offset >= 0 && - page_offset < pixbuf_cache->preload_cache_size); + page_offset < new_preload_cache_size); target_page = new_prev_job + page_offset; new_priority = EV_JOB_PRIORITY_LOW; } else if (page > end_page) { page_offset = (page - (end_page + 1)); g_assert (page_offset >= 0 && - page_offset < pixbuf_cache->preload_cache_size); + page_offset < new_preload_cache_size); target_page = new_next_job + page_offset; new_priority = EV_JOB_PRIORITY_LOW; } else { @@ -360,23 +378,103 @@ move_one_job (CacheJobInfo *job_info, } } +static gsize +ev_pixbuf_cache_get_page_size (EvPixbufCache *pixbuf_cache, + gint page_index, + gdouble scale, + gint rotation) +{ + gint width, height; + + _get_page_size_for_scale_and_rotation (pixbuf_cache->document, + page_index, scale, rotation, + &width, &height); + return height * cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width); +} + +static gint +ev_pixbuf_cache_get_preload_size (EvPixbufCache *pixbuf_cache, + gint start_page, + gint end_page, + gdouble scale, + gint rotation) +{ + gsize range_size = 0; + gint new_preload_cache_size = 0; + gint i; + guint n_pages = ev_document_get_n_pages (pixbuf_cache->document); + + /* Get the size of the current range */ + for (i = start_page; i <= end_page; i++) { + range_size += ev_pixbuf_cache_get_page_size (pixbuf_cache, i, scale, rotation); + } + + if (range_size >= pixbuf_cache->max_size) + return new_preload_cache_size; + + i = 1; + while (((start_page - i > 0) || (end_page + i < n_pages)) && + new_preload_cache_size < MAX_PRELOADED_PAGES) { + gsize page_size; + gboolean updated = FALSE; + + if (end_page + i < n_pages) { + page_size = ev_pixbuf_cache_get_page_size (pixbuf_cache, end_page + i, + scale, rotation); + if (page_size + range_size <= pixbuf_cache->max_size) { + range_size += page_size; + new_preload_cache_size++; + updated = TRUE; + } else { + break; + } + } + + if (start_page - i > 0) { + page_size = ev_pixbuf_cache_get_page_size (pixbuf_cache, start_page - i, + scale, rotation); + if (page_size + range_size <= pixbuf_cache->max_size) { + range_size += page_size; + if (!updated) + new_preload_cache_size++; + } else { + break; + } + } + i++; + } + + return new_preload_cache_size; +} + static void ev_pixbuf_cache_update_range (EvPixbufCache *pixbuf_cache, gint start_page, gint end_page) { CacheJobInfo *new_job_list; - CacheJobInfo *new_prev_job; - CacheJobInfo *new_next_job; - int i, page; - + CacheJobInfo *new_prev_job = NULL; + CacheJobInfo *new_next_job = NULL; + gint new_preload_cache_size; + int i, page; + gdouble scale = ev_document_model_get_scale (pixbuf_cache->model); + gint rotation = ev_document_model_get_rotation (pixbuf_cache->model); + + new_preload_cache_size = ev_pixbuf_cache_get_preload_size (pixbuf_cache, + start_page, + end_page, + scale, + rotation); if (pixbuf_cache->start_page == start_page && - pixbuf_cache->end_page == end_page) + pixbuf_cache->end_page == end_page && + pixbuf_cache->preload_cache_size == new_preload_cache_size) return; new_job_list = g_new0 (CacheJobInfo, (end_page - start_page) + 1); - new_prev_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size); - new_next_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size); + if (new_preload_cache_size > 0) { + new_prev_job = g_new0 (CacheJobInfo, new_preload_cache_size); + new_next_job = g_new0 (CacheJobInfo, new_preload_cache_size); + } /* We go through each job in the old cache and either clear it or move * it to a new location. */ @@ -390,16 +488,18 @@ ev_pixbuf_cache_update_range (EvPixbufCache *pixbuf_cache, move_one_job (pixbuf_cache->prev_job + i, pixbuf_cache, page, new_job_list, new_prev_job, new_next_job, + new_preload_cache_size, start_page, end_page, EV_JOB_PRIORITY_LOW); } page ++; } page = pixbuf_cache->start_page; - for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) { + for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache) && page >= 0; i++) { move_one_job (pixbuf_cache->job_list + i, pixbuf_cache, page, new_job_list, new_prev_job, new_next_job, + new_preload_cache_size, start_page, end_page, EV_JOB_PRIORITY_URGENT); page ++; } @@ -411,6 +511,7 @@ ev_pixbuf_cache_update_range (EvPixbufCache *pixbuf_cache, move_one_job (pixbuf_cache->next_job + i, pixbuf_cache, page, new_job_list, new_prev_job, new_next_job, + new_preload_cache_size, start_page, end_page, EV_JOB_PRIORITY_LOW); } page ++; @@ -420,6 +521,8 @@ ev_pixbuf_cache_update_range (EvPixbufCache *pixbuf_cache, g_free (pixbuf_cache->prev_job); g_free (pixbuf_cache->next_job); + pixbuf_cache->preload_cache_size = new_preload_cache_size; + pixbuf_cache->job_list = new_job_list; pixbuf_cache->prev_job = new_prev_job; pixbuf_cache->next_job = new_next_job; @@ -550,6 +653,19 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache, cairo_image_surface_get_height (job_info->surface) == height) return; + /* Free old surfaces for non visible pages */ + if (priority == EV_JOB_PRIORITY_LOW) { + if (job_info->surface) { + cairo_surface_destroy (job_info->surface); + job_info->surface = NULL; + } + + if (job_info->selection) { + cairo_surface_destroy (job_info->selection); + job_info->selection = NULL; + } + } + add_job (pixbuf_cache, job_info, NULL, width, height, page, rotation, scale, priority); diff --git a/libview/ev-pixbuf-cache.h b/libview/ev-pixbuf-cache.h index af71546..bdf6743 100644 --- a/libview/ev-pixbuf-cache.h +++ b/libview/ev-pixbuf-cache.h @@ -31,6 +31,7 @@ #include <gtk/gtk.h> #include <evince-document.h> +#include <evince-view.h> G_BEGIN_DECLS @@ -55,7 +56,10 @@ typedef struct _EvPixbufCacheClass EvPixbufCacheClass; GType ev_pixbuf_cache_get_type (void) G_GNUC_CONST; EvPixbufCache *ev_pixbuf_cache_new (GtkWidget *view, - EvDocument *document); + EvDocumentModel *model, + gsize max_size); +void ev_pixbuf_cache_set_max_size (EvPixbufCache *pixbuf_cache, + gsize max_size); void ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache, gint start_page, gint end_page, diff --git a/libview/ev-view-private.h b/libview/ev-view-private.h index 01e260b..0362bcd 100644 --- a/libview/ev-view-private.h +++ b/libview/ev-view-private.h @@ -120,6 +120,7 @@ struct _EvView { EvDocumentModel *model; EvPixbufCache *pixbuf_cache; + gsize pixbuf_cache_size; EvPageCache *page_cache; EvHeightToPageCache *height_to_page_cache; EvViewCursor cursor; diff --git a/libview/ev-view.c b/libview/ev-view.c index 7cc0f79..c26aabc 100644 --- a/libview/ev-view.c +++ b/libview/ev-view.c @@ -4554,7 +4554,7 @@ setup_caches (EvView *view) gboolean inverted_colors; view->height_to_page_cache = ev_view_get_height_to_page_cache (view); - view->pixbuf_cache = ev_pixbuf_cache_new (GTK_WIDGET (view), view->document); + view->pixbuf_cache = ev_pixbuf_cache_new (GTK_WIDGET (view), view->model, view->pixbuf_cache_size); view->page_cache = ev_page_cache_new (view->document); inverted_colors = ev_document_model_get_inverted_colors (view->model); ev_pixbuf_cache_set_inverted_colors (view->pixbuf_cache, inverted_colors); @@ -4575,6 +4575,31 @@ clear_caches (EvView *view) } } +/** + * ev_view_set_page_cache_size: + * @view: + * @cache_size: + * + * Sets the maximum size in bytes that will be used to cache + * rendered pages. Use 0 to disable caching rendered pages. + * + * Note that this limit doesn't affect the current visible page range, + * which will always be rendered. In order to limit the total memory used + * you have to use ev_document_model_set_max_scale() too. + * + */ +void +ev_view_set_page_cache_size (EvView *view, + gsize cache_size) +{ + if (view->pixbuf_cache_size == cache_size) + return; + + view->pixbuf_cache_size = cache_size; + if (view->pixbuf_cache) + ev_pixbuf_cache_set_max_size (view->pixbuf_cache, cache_size); +} + void ev_view_set_loading (EvView *view, gboolean loading) diff --git a/libview/ev-view.h b/libview/ev-view.h index 49f77e4..86e09db 100644 --- a/libview/ev-view.h +++ b/libview/ev-view.h @@ -44,14 +44,16 @@ typedef enum { EV_VIEW_SELECTION_RECTANGLE, } EvViewSelectionMode; -GType ev_view_get_type (void) G_GNUC_CONST; - -GtkWidget* ev_view_new (void); -void ev_view_set_model (EvView *view, - EvDocumentModel *model); -void ev_view_set_loading (EvView *view, - gboolean loading); -void ev_view_reload (EvView *view); +GType ev_view_get_type (void) G_GNUC_CONST; + +GtkWidget* ev_view_new (void); +void ev_view_set_model (EvView *view, + EvDocumentModel *model); +void ev_view_set_loading (EvView *view, + gboolean loading); +void ev_view_reload (EvView *view); +void ev_view_set_page_cache_size (EvView *view, + gsize cache_size); /* Clipboard */ void ev_view_copy (EvView *view); |