Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/libview
diff options
context:
space:
mode:
authorCarlos Garcia Campos <carlosgc@gnome.org>2010-05-31 15:57:33 (GMT)
committer Carlos Garcia Campos <carlosgc@gnome.org>2010-05-31 16:57:59 (GMT)
commitd375c36972ff3a01b7979984b5a1043eb4c807b0 (patch)
tree17f63422f7a6a9c3285a199bb6386e77f340473d /libview
parent51261c0750f10aa8cc8687857a0a3b932fd87e3c (diff)
Use a dynamic pixbuf cache size based on document page size
Instead of using a static number of pages to cache, we use a size in bytes, and the number of pages that will be cached depends on the current zoom level. It allows us caching more pages for lower scale factors and increase zoom level by caching fewer pages. See bug #303365.
Diffstat (limited to 'libview')
-rw-r--r--libview/ev-pixbuf-cache.c162
-rw-r--r--libview/ev-pixbuf-cache.h6
-rw-r--r--libview/ev-view-private.h1
-rw-r--r--libview/ev-view.c27
-rw-r--r--libview/ev-view.h18
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);