summaryrefslogtreecommitdiff
path: root/libview/ev-page-cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'libview/ev-page-cache.c')
-rw-r--r--libview/ev-page-cache.c521
1 files changed, 521 insertions, 0 deletions
diff --git a/libview/ev-page-cache.c b/libview/ev-page-cache.c
new file mode 100644
index 00000000..c4dc062c
--- /dev/null
+++ b/libview/ev-page-cache.c
@@ -0,0 +1,521 @@
+/* this file is part of evince, a mate 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 <config.h>
+
+#include <glib.h>
+#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"
+
+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;
+ EvPageCacheData *page_list;
+ gint n_pages;
+
+ /* Current range */
+ gint start_page;
+ gint end_page;
+
+ EvJobPageDataFlags flags;
+};
+
+struct _EvPageCacheClass {
+ GObjectClass parent_class;
+};
+
+#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 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_data_free (EvPageCacheData *data)
+{
+ if (data->job) {
+ g_object_unref (data->job);
+ data->job = NULL;
+ }
+
+ 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;
+ }
+
+ if (data->form_field_mapping) {
+ ev_mapping_list_unref (data->form_field_mapping);
+ data->form_field_mapping = NULL;
+ }
+
+ if (data->annot_mapping) {
+ ev_mapping_list_unref (data->annot_mapping);
+ data->annot_mapping = NULL;
+ }
+
+ if (data->text_mapping) {
+ cairo_region_destroy (data->text_mapping);
+ data->text_mapping = NULL;
+ }
+
+ 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 *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;
+ }
+
+ if (cache->document) {
+ g_object_unref (cache->document);
+ cache->document = NULL;
+ }
+
+ G_OBJECT_CLASS (ev_page_cache_parent_class)->finalize (object);
+}
+
+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 *cache;
+
+ g_return_val_if_fail (EV_IS_DOCUMENT (document), NULL);
+
+ 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 cache;
+}
+
+static void
+job_page_data_finished_cb (EvJob *job,
+ EvPageCache *cache)
+{
+ 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;
+
+ 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_page_range (EvPageCache *cache,
+ gint start,
+ gint end)
+{
+ gint i;
+
+ if (cache->flags == EV_PAGE_DATA_INCLUDE_NONE)
+ return;
+
+ 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_flags (EvPageCache *cache,
+ EvJobPageDataFlags flags)
+{
+ 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);
+}
+
+void
+ev_page_cache_mark_dirty (EvPageCache *cache,
+ gint page)
+{
+ EvPageCacheData *data;
+
+ g_return_if_fail (EV_IS_PAGE_CACHE (cache));
+
+ data = &cache->page_list[page];
+ data->dirty = TRUE;
+
+ /* Update the current range */
+ ev_page_cache_set_page_range (cache, cache->start_page, cache->end_page);
+}
+
+EvMappingList *
+ev_page_cache_get_link_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_LINKS))
+ return NULL;
+
+ data = &cache->page_list[page];
+ if (data->done)
+ return data->link_mapping;
+
+ if (data->job)
+ return EV_JOB_PAGE_DATA (data->job)->link_mapping;
+
+ return data->link_mapping;
+}
+
+EvMappingList *
+ev_page_cache_get_image_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_IMAGES))
+ return NULL;
+
+ data = &cache->page_list[page];
+ if (data->done)
+ return data->image_mapping;
+
+ if (data->job)
+ return EV_JOB_PAGE_DATA (data->job)->image_mapping;
+
+ return data->image_mapping;
+}
+
+EvMappingList *
+ev_page_cache_get_form_field_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_FORMS))
+ return NULL;
+
+ data = &cache->page_list[page];
+ if (data->done)
+ return data->form_field_mapping;
+
+ if (data->job)
+ return EV_JOB_PAGE_DATA (data->job)->form_field_mapping;
+
+ return data->form_field_mapping;
+}
+
+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)
+{
+ 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_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;
+}
+
+const gchar *
+ev_page_cache_get_text (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_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)
+{
+ EvPageCacheData *data;
+
+ 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;
+
+ data = &cache->page_list[page];
+ if (data->done) {
+ *areas = data->text_layout;
+ *n_areas = data->text_layout_length;
+
+ return TRUE;
+ }
+
+ 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;
+}