X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;f=libview%2Fev-page-cache.c;h=c3c570417285e9303a294872c6f6ce4b25274770;hb=6d7f952b641bf6ab8b71150a61c3ba23c8bec64b;hp=d6fa538b04dcbb781d2dc6a2b8265ecb3967bd19;hpb=e8fe8f92b5b9c4116e3950b4c8ad33236412495e;p=evince.git diff --git a/libview/ev-page-cache.c b/libview/ev-page-cache.c index d6fa538b..c3c57041 100644 --- a/libview/ev-page-cache.c +++ b/libview/ev-page-cache.c @@ -1,236 +1,521 @@ +/* this file is part of evince, a gnome document viewer + * + * Copyright (C) 2009 Carlos Garcia Campos + * + * Evince is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Evince is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #include + +#include +#include "ev-jobs.h" +#include "ev-job-scheduler.h" +#include "ev-mapping-list.h" +#include "ev-selection.h" +#include "ev-document-links.h" +#include "ev-document-forms.h" +#include "ev-document-images.h" +#include "ev-document-annotations.h" +#include "ev-document-text.h" #include "ev-page-cache.h" -#include "ev-document-thumbnails.h" -#include "ev-page.h" -#include -#include -struct _EvPageCache -{ +typedef struct _EvPageCacheData { + EvJob *job; + gboolean done : 1; + gboolean dirty : 1; + EvJobPageDataFlags flags; + + EvMappingList *link_mapping; + EvMappingList *image_mapping; + EvMappingList *form_field_mapping; + EvMappingList *annot_mapping; + cairo_region_t *text_mapping; + EvRectangle *text_layout; + guint text_layout_length; + gchar *text; +} EvPageCacheData; + +struct _EvPageCache { GObject parent; - EvDocument *document; - - gint current_page; + EvDocument *document; + EvPageCacheData *page_list; + gint n_pages; - gboolean dual_even_left; + /* Current range */ + gint start_page; + gint end_page; - int rotation; + EvJobPageDataFlags flags; }; -struct _EvPageCacheClass -{ +struct _EvPageCacheClass { GObjectClass parent_class; - - void (* page_changed) (EvPageCache *page_cache, gint page); - void (* history_changed) (EvPageCache *page_cache, gint page); }; -enum -{ - PAGE_CHANGED, - HISTORY_CHANGED, - N_SIGNALS, -}; +#define EV_PAGE_DATA_FLAGS_DEFAULT ( \ + EV_PAGE_DATA_INCLUDE_LINKS | \ + EV_PAGE_DATA_INCLUDE_TEXT_MAPPING | \ + EV_PAGE_DATA_INCLUDE_IMAGES | \ + EV_PAGE_DATA_INCLUDE_FORMS | \ + EV_PAGE_DATA_INCLUDE_ANNOTS) -static guint signals[N_SIGNALS] = {0, }; -static void ev_page_cache_init (EvPageCache *page_cache); -static void ev_page_cache_class_init (EvPageCacheClass *page_cache); -static void ev_page_cache_finalize (GObject *object); +static void job_page_data_finished_cb (EvJob *job, + EvPageCache *cache); +static void job_page_data_cancelled_cb (EvJob *job, + EvPageCacheData *data); G_DEFINE_TYPE (EvPageCache, ev_page_cache, G_TYPE_OBJECT) static void -ev_page_cache_init (EvPageCache *page_cache) +ev_page_cache_data_free (EvPageCacheData *data) { - page_cache->current_page = -1; -} + if (data->job) { + g_object_unref (data->job); + data->job = NULL; + } -static void -ev_page_cache_class_init (EvPageCacheClass *class) -{ - GObjectClass *object_class; + if (data->link_mapping) { + ev_mapping_list_unref (data->link_mapping); + data->link_mapping = NULL; + } + + if (data->image_mapping) { + ev_mapping_list_unref (data->image_mapping); + data->image_mapping = NULL; + } - object_class = G_OBJECT_CLASS (class); + if (data->form_field_mapping) { + ev_mapping_list_unref (data->form_field_mapping); + data->form_field_mapping = NULL; + } - object_class->finalize = ev_page_cache_finalize; + if (data->annot_mapping) { + ev_mapping_list_unref (data->annot_mapping); + data->annot_mapping = NULL; + } - signals [PAGE_CHANGED] = - g_signal_new ("page-changed", - EV_TYPE_PAGE_CACHE, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EvPageCacheClass, page_changed), - NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); + if (data->text_mapping) { + cairo_region_destroy (data->text_mapping); + data->text_mapping = NULL; + } - signals [HISTORY_CHANGED] = - g_signal_new ("history-changed", - EV_TYPE_PAGE_CACHE, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EvPageCacheClass, history_changed), - NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); + if (data->text_layout) { + g_free (data->text_layout); + data->text_layout = NULL; + data->text_layout_length = 0; + } + if (data->text) { + g_free (data->text); + data->text = NULL; + } } static void ev_page_cache_finalize (GObject *object) { - EvPageCache *page_cache = EV_PAGE_CACHE (object); + EvPageCache *cache = EV_PAGE_CACHE (object); + gint i; + + if (cache->page_list) { + for (i = 0; i < cache->n_pages; i++) { + EvPageCacheData *data; + + data = &cache->page_list[i]; + + if (data->job) { + g_signal_handlers_disconnect_by_func (data->job, + G_CALLBACK (job_page_data_finished_cb), + cache); + g_signal_handlers_disconnect_by_func (data->job, + G_CALLBACK (job_page_data_cancelled_cb), + data); + } + ev_page_cache_data_free (data); + } + + g_free (cache->page_list); + cache->page_list = NULL; + cache->n_pages = 0; + } - page_cache->document = NULL; + if (cache->document) { + g_object_unref (cache->document); + cache->document = NULL; + } G_OBJECT_CLASS (ev_page_cache_parent_class)->finalize (object); } -static EvPageCache * +static void +ev_page_cache_init (EvPageCache *cache) +{ +} + +static void +ev_page_cache_class_init (EvPageCacheClass *klass) +{ + GObjectClass *g_object_class = G_OBJECT_CLASS (klass); + + g_object_class->finalize = ev_page_cache_finalize; +} + +static EvJobPageDataFlags +ev_page_cache_get_flags_for_data (EvPageCache *cache, + EvPageCacheData *data) +{ + EvJobPageDataFlags flags = EV_PAGE_DATA_INCLUDE_NONE; + + if (data->flags == cache->flags && !data->dirty) + return cache->flags; + + /* Flags changed or data is dirty */ + if (cache->flags & EV_PAGE_DATA_INCLUDE_LINKS) { + flags = (data->link_mapping) ? + flags & ~EV_PAGE_DATA_INCLUDE_LINKS : + flags | EV_PAGE_DATA_INCLUDE_LINKS; + } + + if (cache->flags & EV_PAGE_DATA_INCLUDE_IMAGES) { + flags = (data->image_mapping) ? + flags & ~EV_PAGE_DATA_INCLUDE_IMAGES : + flags | EV_PAGE_DATA_INCLUDE_IMAGES; + } + + if (cache->flags & EV_PAGE_DATA_INCLUDE_FORMS) { + flags = (data->form_field_mapping) ? + flags & ~EV_PAGE_DATA_INCLUDE_FORMS : + flags | EV_PAGE_DATA_INCLUDE_FORMS; + } + + if (cache->flags & EV_PAGE_DATA_INCLUDE_ANNOTS) { + flags = (data->annot_mapping) ? + flags & ~EV_PAGE_DATA_INCLUDE_ANNOTS : + flags | EV_PAGE_DATA_INCLUDE_ANNOTS; + } + + if (cache->flags & EV_PAGE_DATA_INCLUDE_TEXT_MAPPING) { + flags = (data->text_mapping) ? + flags & ~EV_PAGE_DATA_INCLUDE_TEXT_MAPPING : + flags | EV_PAGE_DATA_INCLUDE_TEXT_MAPPING; + } + + if (cache->flags & EV_PAGE_DATA_INCLUDE_TEXT) { + flags = (data->text) ? + flags & ~EV_PAGE_DATA_INCLUDE_TEXT : + flags | EV_PAGE_DATA_INCLUDE_TEXT; + } + + if (cache->flags & EV_PAGE_DATA_INCLUDE_TEXT_LAYOUT) { + flags = (data->text_layout_length > 0) ? + flags & ~EV_PAGE_DATA_INCLUDE_TEXT_LAYOUT : + flags | EV_PAGE_DATA_INCLUDE_TEXT_LAYOUT; + } + + return flags; +} + +EvPageCache * ev_page_cache_new (EvDocument *document) { - EvPageCache *page_cache; + EvPageCache *cache; - page_cache = (EvPageCache *) g_object_new (EV_TYPE_PAGE_CACHE, NULL); - page_cache->document = document; + g_return_val_if_fail (EV_IS_DOCUMENT (document), NULL); - if (ev_document_get_n_pages (page_cache->document) > 0) - ev_page_cache_set_current_page (page_cache, 0); + cache = EV_PAGE_CACHE (g_object_new (EV_TYPE_PAGE_CACHE, NULL)); + cache->document = g_object_ref (document); + cache->n_pages = ev_document_get_n_pages (document); + cache->flags = EV_PAGE_DATA_FLAGS_DEFAULT; + cache->page_list = g_new0 (EvPageCacheData, cache->n_pages); - return page_cache; + return cache; } -gint -ev_page_cache_get_current_page (EvPageCache *page_cache) +static void +job_page_data_finished_cb (EvJob *job, + EvPageCache *cache) { - g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0); + EvJobPageData *job_data = EV_JOB_PAGE_DATA (job); + EvPageCacheData *data; + + data = &cache->page_list[job_data->page]; + + if (job_data->flags & EV_PAGE_DATA_INCLUDE_LINKS) + data->link_mapping = job_data->link_mapping; + if (job_data->flags & EV_PAGE_DATA_INCLUDE_IMAGES) + data->image_mapping = job_data->image_mapping; + if (job_data->flags & EV_PAGE_DATA_INCLUDE_FORMS) + data->form_field_mapping = job_data->form_field_mapping; + if (job_data->flags & EV_PAGE_DATA_INCLUDE_ANNOTS) + data->annot_mapping = job_data->annot_mapping; + if (job_data->flags & EV_PAGE_DATA_INCLUDE_TEXT_MAPPING) + data->text_mapping = job_data->text_mapping; + if (job_data->flags & EV_PAGE_DATA_INCLUDE_TEXT_LAYOUT) { + data->text_layout = job_data->text_layout; + data->text_layout_length = job_data->text_layout_length; + } + if (job_data->flags & EV_PAGE_DATA_INCLUDE_TEXT) + data->text = job_data->text; + data->done = TRUE; + data->dirty = FALSE; - return page_cache->current_page; + g_object_unref (data->job); + data->job = NULL; +} + +static void +job_page_data_cancelled_cb (EvJob *job, + EvPageCacheData *data) +{ + g_object_unref (data->job); + data->job = NULL; } void -ev_page_cache_set_current_page (EvPageCache *page_cache, - int page) +ev_page_cache_set_page_range (EvPageCache *cache, + gint start, + gint end) { - g_return_if_fail (EV_IS_PAGE_CACHE (page_cache)); + gint i; - if (page == page_cache->current_page) + if (cache->flags == EV_PAGE_DATA_INCLUDE_NONE) return; - page_cache->current_page = page; - g_signal_emit (page_cache, signals[PAGE_CHANGED], 0, page); + cache->start_page = start; + cache->end_page = end; + + for (i = start; i <= end; i++) { + EvPageCacheData *data = &cache->page_list[i]; + EvJobPageDataFlags flags; + + if (data->flags == cache->flags && !data->dirty && (data->done || data->job)) + continue; + + if (data->job) + ev_job_cancel (data->job); + + flags = ev_page_cache_get_flags_for_data (cache, data); + + data->flags = cache->flags; + data->job = ev_job_page_data_new (cache->document, i, flags); + g_signal_connect (data->job, "finished", + G_CALLBACK (job_page_data_finished_cb), + cache); + g_signal_connect (data->job, "cancelled", + G_CALLBACK (job_page_data_cancelled_cb), + data); + ev_job_scheduler_push_job (data->job, EV_JOB_PRIORITY_NONE); + } +} + +EvJobPageDataFlags +ev_page_cache_get_flags (EvPageCache *cache) +{ + return cache->flags; } void -ev_page_cache_set_current_page_history (EvPageCache *page_cache, - int page) +ev_page_cache_set_flags (EvPageCache *cache, + EvJobPageDataFlags flags) { - if (abs (page - page_cache->current_page) > 1) - g_signal_emit (page_cache, signals [HISTORY_CHANGED], 0, page); - - ev_page_cache_set_current_page (page_cache, page); + if (cache->flags == flags) + return; + + cache->flags = flags; + + /* Update the current range for new flags */ + ev_page_cache_set_page_range (cache, cache->start_page, cache->end_page); } -gboolean -ev_page_cache_set_page_label (EvPageCache *page_cache, - const gchar *page_label) +void +ev_page_cache_mark_dirty (EvPageCache *cache, + gint page) { - gint page; + EvPageCacheData *data; - g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE); + g_return_if_fail (EV_IS_PAGE_CACHE (cache)); - if (ev_document_find_page_by_label (page_cache->document, page_label, &page)) { - ev_page_cache_set_current_page (page_cache, page); - return TRUE; - } + data = &cache->page_list[page]; + data->dirty = TRUE; - return FALSE; + /* Update the current range */ + ev_page_cache_set_page_range (cache, cache->start_page, cache->end_page); } -void -ev_page_cache_get_size (EvPageCache *page_cache, - gint page, - gint rotation, - gfloat scale, - gint *width, - gint *height) +EvMappingList * +ev_page_cache_get_link_mapping (EvPageCache *cache, + gint page) { - double w, h; + EvPageCacheData *data; - g_return_if_fail (EV_IS_PAGE_CACHE (page_cache)); + g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL); + g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL); - ev_document_get_page_size (page_cache->document, page, &w, &h); + if (!(cache->flags & EV_PAGE_DATA_INCLUDE_LINKS)) + return NULL; - w = w * scale + 0.5; - h = h * scale + 0.5; + data = &cache->page_list[page]; + if (data->done) + return data->link_mapping; - if (rotation == 0 || rotation == 180) { - if (width) *width = (int)w; - if (height) *height = (int)h; - } else { - if (width) *width = (int)h; - if (height) *height = (int)w; - } + if (data->job) + return EV_JOB_PAGE_DATA (data->job)->link_mapping; + + return data->link_mapping; } -void -ev_page_cache_get_max_width (EvPageCache *page_cache, - gint rotation, - gfloat scale, - gint *width) +EvMappingList * +ev_page_cache_get_image_mapping (EvPageCache *cache, + gint page) { - double w, h; + EvPageCacheData *data; - g_return_if_fail (EV_IS_PAGE_CACHE (page_cache)); + g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL); + g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL); - if (!width) - return; + if (!(cache->flags & EV_PAGE_DATA_INCLUDE_IMAGES)) + return NULL; + + data = &cache->page_list[page]; + if (data->done) + return data->image_mapping; - ev_document_get_max_page_size (page_cache->document, &w, &h); - *width = (rotation == 0 || rotation == 180) ? w * scale : h * scale; + if (data->job) + return EV_JOB_PAGE_DATA (data->job)->image_mapping; + + return data->image_mapping; } -void -ev_page_cache_get_max_height (EvPageCache *page_cache, - gint rotation, - gfloat scale, - gint *height) +EvMappingList * +ev_page_cache_get_form_field_mapping (EvPageCache *cache, + gint page) { - double w, h; + EvPageCacheData *data; - g_return_if_fail (EV_IS_PAGE_CACHE (page_cache)); + g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL); + g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL); - if (!height) - return; + if (!(cache->flags & EV_PAGE_DATA_INCLUDE_FORMS)) + return NULL; + + data = &cache->page_list[page]; + if (data->done) + return data->form_field_mapping; - ev_document_get_max_page_size (page_cache->document, &w, &h); - *height = (rotation == 0 || rotation == 180) ? h * scale : w * scale; + if (data->job) + return EV_JOB_PAGE_DATA (data->job)->form_field_mapping; + + return data->form_field_mapping; } -gboolean -ev_page_cache_get_dual_even_left (EvPageCache *page_cache) +EvMappingList * +ev_page_cache_get_annot_mapping (EvPageCache *cache, + gint page) +{ + EvPageCacheData *data; + + g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL); + g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL); + + if (!(cache->flags & EV_PAGE_DATA_INCLUDE_ANNOTS)) + return NULL; + + data = &cache->page_list[page]; + if (data->done) + return data->annot_mapping; + + if (data->job) + return EV_JOB_PAGE_DATA (data->job)->annot_mapping; + + return data->annot_mapping; +} + +cairo_region_t * +ev_page_cache_get_text_mapping (EvPageCache *cache, + gint page) { - g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0); + EvPageCacheData *data; + + g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL); + g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL); - return (ev_document_get_n_pages (page_cache->document) > 2); + if (!(cache->flags & EV_PAGE_DATA_INCLUDE_TEXT_MAPPING)) + return NULL; + + data = &cache->page_list[page]; + if (data->done) + return data->text_mapping; + + if (data->job) + return EV_JOB_PAGE_DATA (data->job)->text_mapping; + + return data->text_mapping; } -#define PAGE_CACHE_STRING "ev-page-cache" +const gchar * +ev_page_cache_get_text (EvPageCache *cache, + gint page) +{ + EvPageCacheData *data; -EvPageCache * -ev_page_cache_get (EvDocument *document) + g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL); + g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL); + + if (!(cache->flags & EV_PAGE_DATA_INCLUDE_TEXT)) + return NULL; + + data = &cache->page_list[page]; + if (data->done) + return data->text; + + if (data->job) + return EV_JOB_PAGE_DATA (data->job)->text; + + return data->text; +} + +gboolean +ev_page_cache_get_text_layout (EvPageCache *cache, + gint page, + EvRectangle **areas, + guint *n_areas) { - EvPageCache *page_cache; + EvPageCacheData *data; - g_return_val_if_fail (EV_IS_DOCUMENT (document), NULL); + g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), FALSE); + g_return_val_if_fail (page >= 0 && page < cache->n_pages, FALSE); + + if (!(cache->flags & EV_PAGE_DATA_INCLUDE_TEXT_LAYOUT)) + return FALSE; - page_cache = g_object_get_data (G_OBJECT (document), PAGE_CACHE_STRING); - if (page_cache == NULL) { - page_cache = ev_page_cache_new (document); - g_object_set_data_full (G_OBJECT (document), PAGE_CACHE_STRING, page_cache, g_object_unref); + data = &cache->page_list[page]; + if (data->done) { + *areas = data->text_layout; + *n_areas = data->text_layout_length; + + return TRUE; } - return page_cache; + if (data->job) { + *areas = EV_JOB_PAGE_DATA (data->job)->text_layout; + *n_areas = EV_JOB_PAGE_DATA (data->job)->text_layout_length; + + return TRUE; + } + + return FALSE; }