X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;ds=sidebyside;f=libview%2Fev-pixbuf-cache.c;h=42dd1def5349ccfb22056b5e35140583232212de;hb=2297bff1e7d745f0f837d44feeda03244368d7f1;hp=87e78b4ceedbe138bb88ba6963181d862fa90303;hpb=fb3b7017807d601bdbcfb48f290fb78ef1669a83;p=evince.git diff --git a/libview/ev-pixbuf-cache.c b/libview/ev-pixbuf-cache.c index 87e78b4c..42dd1def 100644 --- a/libview/ev-pixbuf-cache.c +++ b/libview/ev-pixbuf-cache.c @@ -37,15 +37,20 @@ 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. */ int preload_cache_size; + guint job_list_len; + CacheJobInfo *prev_job; CacheJobInfo *job_list; CacheJobInfo *next_job; @@ -89,18 +94,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 @@ -131,9 +133,23 @@ ev_pixbuf_cache_finalize (GObject *object) pixbuf_cache = EV_PIXBUF_CACHE (object); - g_free (pixbuf_cache->prev_job); - g_free (pixbuf_cache->job_list); - g_free (pixbuf_cache->next_job); + if (pixbuf_cache->job_list) { + g_slice_free1 (sizeof (CacheJobInfo) * pixbuf_cache->job_list_len, + pixbuf_cache->job_list); + pixbuf_cache->job_list = NULL; + } + if (pixbuf_cache->prev_job) { + g_slice_free1 (sizeof (CacheJobInfo) * pixbuf_cache->preload_cache_size, + pixbuf_cache->prev_job); + pixbuf_cache->prev_job = NULL; + } + if (pixbuf_cache->next_job) { + g_slice_free1 (sizeof (CacheJobInfo) * pixbuf_cache->preload_cache_size, + pixbuf_cache->next_job); + pixbuf_cache->next_job = NULL; + } + + g_object_unref (pixbuf_cache->model); G_OBJECT_CLASS (ev_pixbuf_cache_parent_class)->finalize (object); } @@ -195,19 +211,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 +344,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 +353,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 +392,105 @@ 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) + gint end_page, + guint rotation, + gdouble scale) { 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; + guint new_job_list_len; + int i, page; + + 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); + new_job_list_len = (end_page - start_page) + 1; + new_job_list = g_slice_alloc0 (sizeof (CacheJobInfo) * new_job_list_len); + if (new_preload_cache_size > 0) { + new_prev_job = g_slice_alloc0 (sizeof (CacheJobInfo) * new_preload_cache_size); + new_next_job = g_slice_alloc0 (sizeof (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 +504,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,14 +527,27 @@ 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 ++; } - g_free (pixbuf_cache->job_list); - g_free (pixbuf_cache->prev_job); - g_free (pixbuf_cache->next_job); + if (pixbuf_cache->job_list) { + g_slice_free1 (sizeof (CacheJobInfo) * pixbuf_cache->job_list_len, + pixbuf_cache->job_list); + } + if (pixbuf_cache->prev_job) { + g_slice_free1 (sizeof (CacheJobInfo) * pixbuf_cache->preload_cache_size, + pixbuf_cache->prev_job); + } + if (pixbuf_cache->next_job) { + g_slice_free1 (sizeof (CacheJobInfo) * pixbuf_cache->preload_cache_size, + pixbuf_cache->next_job); + } + + pixbuf_cache->preload_cache_size = new_preload_cache_size; + pixbuf_cache->job_list_len = new_job_list_len; pixbuf_cache->job_list = new_job_list; pixbuf_cache->prev_job = new_prev_job; @@ -479,13 +608,15 @@ ev_pixbuf_cache_clear_job_sizes (EvPixbufCache *pixbuf_cache, static void get_selection_colors (GtkWidget *widget, GdkColor **text, GdkColor **base) { - if (GTK_WIDGET_HAS_FOCUS (widget)) { - *text = &widget->style->text [GTK_STATE_SELECTED]; - *base = &widget->style->base [GTK_STATE_SELECTED]; - } else { - *text = &widget->style->text [GTK_STATE_ACTIVE]; - *base = &widget->style->base [GTK_STATE_ACTIVE]; - } + GtkStyle *style = gtk_widget_get_style (widget); + + if (gtk_widget_has_focus (widget)) { + *text = &style->text [GTK_STATE_SELECTED]; + *base = &style->base [GTK_STATE_SELECTED]; + } else { + *text = &style->text [GTK_STATE_ACTIVE]; + *base = &style->base [GTK_STATE_ACTIVE]; + } } static void @@ -548,6 +679,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); @@ -595,10 +739,11 @@ void ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache, gint start_page, gint end_page, - gint rotation, - gfloat scale, GList *selection_list) { + gdouble scale = ev_document_model_get_scale (pixbuf_cache->model); + gint rotation = ev_document_model_get_rotation (pixbuf_cache->model); + g_return_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache)); g_return_if_fail (start_page >= 0 && start_page < ev_document_get_n_pages (pixbuf_cache->document)); @@ -607,7 +752,7 @@ ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache, /* First, resize the page_range as needed. We cull old pages * mercilessly. */ - ev_pixbuf_cache_update_range (pixbuf_cache, start_page, end_page); + ev_pixbuf_cache_update_range (pixbuf_cache, start_page, end_page, rotation, scale); /* Then, we update the current jobs to see if any of them are the wrong * size, we remove them if we need to. */ @@ -724,6 +869,9 @@ ev_pixbuf_cache_clear (EvPixbufCache *pixbuf_cache) { int i; + if (!pixbuf_cache->job_list) + return; + for (i = 0; i < pixbuf_cache->preload_cache_size; i++) { dispose_cache_job_info (pixbuf_cache->prev_job + i, pixbuf_cache); dispose_cache_job_info (pixbuf_cache->next_job + i, pixbuf_cache); @@ -740,6 +888,9 @@ ev_pixbuf_cache_style_changed (EvPixbufCache *pixbuf_cache) { gint i; + if (!pixbuf_cache->job_list) + return; + /* FIXME: doesn't update running jobs. */ for (i = 0; i < pixbuf_cache->preload_cache_size; i++) { CacheJobInfo *job_info;