Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ev-page-cache.c
Go to the documentation of this file.
1 /* this file is part of evince, a gnome document viewer
2  *
3  * Copyright (C) 2009 Carlos Garcia Campos
4  *
5  * Evince is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * Evince is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 #include <config.h>
21 
22 #include <glib.h>
23 #include "ev-jobs.h"
24 #include "ev-job-scheduler.h"
25 #include "ev-mapping-list.h"
26 #include "ev-selection.h"
27 #include "ev-document-links.h"
28 #include "ev-document-forms.h"
29 #include "ev-document-images.h"
31 #include "ev-document-media.h"
32 #include "ev-document-text.h"
33 #include "ev-page-cache.h"
34 
35 enum {
38 };
39 
40 static guint ev_page_cache_signals[LAST_SIGNAL] = {0};
41 
42 typedef struct _EvPageCacheData {
44  gboolean done : 1;
45  gboolean dirty : 1;
47 
53  cairo_region_t *text_mapping;
56  gchar *text;
57  PangoAttrList *text_attrs;
58  PangoLogAttr *text_log_attrs;
61 
62 struct _EvPageCache {
63  GObject parent;
64 
67  gint n_pages;
68 
69  /* Current range */
70  gint start_page;
71  gint end_page;
72 
74 };
75 
77  GObjectClass parent_class;
78 };
79 
80 #define EV_PAGE_DATA_FLAGS_DEFAULT ( \
81  EV_PAGE_DATA_INCLUDE_LINKS | \
82  EV_PAGE_DATA_INCLUDE_TEXT_MAPPING | \
83  EV_PAGE_DATA_INCLUDE_IMAGES | \
84  EV_PAGE_DATA_INCLUDE_FORMS | \
85  EV_PAGE_DATA_INCLUDE_ANNOTS | \
86  EV_PAGE_DATA_INCLUDE_MEDIA)
87 
88 #define PRE_CACHE_SIZE 1
89 
90 static void job_page_data_finished_cb (EvJob *job,
91  EvPageCache *cache);
92 static void job_page_data_cancelled_cb (EvJob *job,
93  EvPageCacheData *data);
94 
95 G_DEFINE_TYPE (EvPageCache, ev_page_cache, G_TYPE_OBJECT)
96 
97 static void
99 {
100  if (data->job) {
101  g_object_unref (data->job);
102  data->job = NULL;
103  }
104 
105  if (data->link_mapping) {
106  ev_mapping_list_unref (data->link_mapping);
107  data->link_mapping = NULL;
108  }
109 
110  if (data->image_mapping) {
111  ev_mapping_list_unref (data->image_mapping);
112  data->image_mapping = NULL;
113  }
114 
115  if (data->form_field_mapping) {
116  ev_mapping_list_unref (data->form_field_mapping);
117  data->form_field_mapping = NULL;
118  }
119 
120  if (data->annot_mapping) {
121  ev_mapping_list_unref (data->annot_mapping);
122  data->annot_mapping = NULL;
123  }
124 
125  if (data->media_mapping) {
126  ev_mapping_list_unref (data->media_mapping);
127  data->media_mapping = NULL;
128  }
129 
130  if (data->text_mapping) {
131  cairo_region_destroy (data->text_mapping);
132  data->text_mapping = NULL;
133  }
134 
135  if (data->text_layout) {
136  g_free (data->text_layout);
137  data->text_layout = NULL;
138  data->text_layout_length = 0;
139  }
140 
141  if (data->text) {
142  g_free (data->text);
143  data->text = NULL;
144  }
145 
146  if (data->text_attrs) {
147  pango_attr_list_unref (data->text_attrs);
148  data->text_attrs = NULL;
149  }
150 
151  if (data->text_log_attrs) {
152  g_free (data->text_log_attrs);
153  data->text_log_attrs = NULL;
154  data->text_log_attrs_length = 0;
155  }
156 }
157 
158 static void
159 ev_page_cache_finalize (GObject *object)
160 {
161  EvPageCache *cache = EV_PAGE_CACHE (object);
162  gint i;
163 
164  if (cache->page_list) {
165  for (i = 0; i < cache->n_pages; i++) {
166  EvPageCacheData *data;
167 
168  data = &cache->page_list[i];
169 
170  if (data->job) {
171  g_signal_handlers_disconnect_by_func (data->job,
172  G_CALLBACK (job_page_data_finished_cb),
173  cache);
174  g_signal_handlers_disconnect_by_func (data->job,
175  G_CALLBACK (job_page_data_cancelled_cb),
176  data);
177  }
179  }
180 
181  g_free (cache->page_list);
182  cache->page_list = NULL;
183  cache->n_pages = 0;
184  }
185 
186  if (cache->document) {
187  g_object_unref (cache->document);
188  cache->document = NULL;
189  }
190 
191  G_OBJECT_CLASS (ev_page_cache_parent_class)->finalize (object);
192 }
193 
194 static void
196 {
197 }
198 
199 static void
201 {
202  GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
203 
204  g_object_class->finalize = ev_page_cache_finalize;
205 
207  g_signal_new ("page-cached",
209  G_SIGNAL_RUN_LAST,
210  0,
211  NULL, NULL,
212  g_cclosure_marshal_VOID__INT,
213  G_TYPE_NONE, 1, G_TYPE_INT);
214 }
215 
216 static EvJobPageDataFlags
218  EvPageCacheData *data)
219 {
221 
222  if (data->flags == cache->flags && !data->dirty)
223  return cache->flags;
224 
225  /* Flags changed or data is dirty */
226  if (cache->flags & EV_PAGE_DATA_INCLUDE_LINKS) {
227  flags = (data->link_mapping) ?
228  flags & ~EV_PAGE_DATA_INCLUDE_LINKS :
230  }
231 
232  if (cache->flags & EV_PAGE_DATA_INCLUDE_IMAGES) {
233  flags = (data->image_mapping) ?
234  flags & ~EV_PAGE_DATA_INCLUDE_IMAGES :
236  }
237 
238  if (cache->flags & EV_PAGE_DATA_INCLUDE_FORMS) {
239  flags = (data->form_field_mapping) ?
240  flags & ~EV_PAGE_DATA_INCLUDE_FORMS :
242  }
243 
244  if (cache->flags & EV_PAGE_DATA_INCLUDE_ANNOTS) {
245  flags = (data->annot_mapping) ?
246  flags & ~EV_PAGE_DATA_INCLUDE_ANNOTS :
248  }
249 
250  if (cache->flags & EV_PAGE_DATA_INCLUDE_MEDIA) {
251  flags = (data->media_mapping) ?
252  flags & ~EV_PAGE_DATA_INCLUDE_MEDIA :
254  }
255 
257  flags = (data->text_mapping) ?
260  }
261 
262  if (cache->flags & EV_PAGE_DATA_INCLUDE_TEXT) {
263  flags = (data->text) ?
264  flags & ~EV_PAGE_DATA_INCLUDE_TEXT :
266  }
267 
269  flags = (data->text_layout_length > 0) ?
272  }
273 
274  if (cache->flags & EV_PAGE_DATA_INCLUDE_TEXT_ATTRS) {
275  flags = (data->text_attrs) ?
278  }
279 
281  flags = (data->text_log_attrs) ?
284  }
285 
286  return flags;
287 }
288 
289 EvPageCache *
291 {
292  EvPageCache *cache;
293 
294  g_return_val_if_fail (EV_IS_DOCUMENT (document), NULL);
295 
296  cache = EV_PAGE_CACHE (g_object_new (EV_TYPE_PAGE_CACHE, NULL));
297  cache->document = g_object_ref (document);
298  cache->n_pages = ev_document_get_n_pages (document);
300  cache->page_list = g_new0 (EvPageCacheData, cache->n_pages);
301 
302  return cache;
303 }
304 
305 static void
307  EvPageCache *cache)
308 {
309  EvJobPageData *job_data = EV_JOB_PAGE_DATA (job);
310  EvPageCacheData *data;
311 
312  data = &cache->page_list[job_data->page];
313 
314  if (job_data->flags & EV_PAGE_DATA_INCLUDE_LINKS)
315  data->link_mapping = job_data->link_mapping;
316  if (job_data->flags & EV_PAGE_DATA_INCLUDE_IMAGES)
317  data->image_mapping = job_data->image_mapping;
318  if (job_data->flags & EV_PAGE_DATA_INCLUDE_FORMS)
319  data->form_field_mapping = job_data->form_field_mapping;
320  if (job_data->flags & EV_PAGE_DATA_INCLUDE_ANNOTS)
321  data->annot_mapping = job_data->annot_mapping;
322  if (job_data->flags & EV_PAGE_DATA_INCLUDE_MEDIA)
323  data->media_mapping = job_data->media_mapping;
325  data->text_mapping = job_data->text_mapping;
326  if (job_data->flags & EV_PAGE_DATA_INCLUDE_TEXT_LAYOUT) {
327  data->text_layout = job_data->text_layout;
328  data->text_layout_length = job_data->text_layout_length;
329  }
330  if (job_data->flags & EV_PAGE_DATA_INCLUDE_TEXT)
331  data->text = job_data->text;
332  if (job_data->flags & EV_PAGE_DATA_INCLUDE_TEXT_ATTRS)
333  data->text_attrs = job_data->text_attrs;
334  if (job_data->flags & EV_PAGE_DATA_INCLUDE_TEXT_LOG_ATTRS) {
335  data->text_log_attrs = job_data->text_log_attrs;
337  }
338 
339  data->done = TRUE;
340  data->dirty = FALSE;
341 
342  g_object_unref (data->job);
343  data->job = NULL;
344 
345  g_signal_emit (cache, ev_page_cache_signals[PAGE_CACHED], 0, job_data->page);
346 }
347 
348 static void
350  EvPageCacheData *data)
351 {
352  g_object_unref (data->job);
353  data->job = NULL;
354 }
355 
356 static void
358  gint page)
359 {
360  EvPageCacheData *data = &cache->page_list[page];
361  EvJobPageDataFlags flags;
362 
363  if (data->flags == cache->flags && !data->dirty && (data->done || data->job))
364  return;
365 
366  if (data->job)
367  ev_job_cancel (data->job);
368 
369  flags = ev_page_cache_get_flags_for_data (cache, data);
370 
371  data->flags = cache->flags;
372  data->job = ev_job_page_data_new (cache->document, page, flags);
373  g_signal_connect (data->job, "finished",
374  G_CALLBACK (job_page_data_finished_cb),
375  cache);
376  g_signal_connect (data->job, "cancelled",
377  G_CALLBACK (job_page_data_cancelled_cb),
378  data);
380 
381 }
382 
383 void
385  gint start,
386  gint end)
387 {
388  gint i;
389  gint pages_to_pre_cache;
390 
391  if (cache->flags == EV_PAGE_DATA_INCLUDE_NONE)
392  return;
393 
394  for (i = start; i <= end; i++)
396 
397  cache->start_page = start;
398  cache->end_page = end;
399 
400  i = 1;
401  pages_to_pre_cache = PRE_CACHE_SIZE * 2;
402  while ((start - i > 0) || (end + i < cache->n_pages)) {
403  if (end + i < cache->n_pages) {
404  ev_page_cache_schedule_job_if_needed (cache, end + i);
405  if (--pages_to_pre_cache == 0)
406  break;
407  }
408 
409  if (start - i > 0) {
410  ev_page_cache_schedule_job_if_needed (cache, start - i);
411  if (--pages_to_pre_cache == 0)
412  break;
413  }
414  i++;
415  }
416 }
417 
420 {
421  return cache->flags;
422 }
423 
424 void
426  EvJobPageDataFlags flags)
427 {
428  if (cache->flags == flags)
429  return;
430 
431  cache->flags = flags;
432 
433  /* Update the current range for new flags */
434  ev_page_cache_set_page_range (cache, cache->start_page, cache->end_page);
435 }
436 
437 void
439  gint page,
440  EvJobPageDataFlags flags)
441 {
442  EvPageCacheData *data;
443 
444  g_return_if_fail (EV_IS_PAGE_CACHE (cache));
445 
446  data = &cache->page_list[page];
447  data->dirty = TRUE;
448 
449  if (flags & EV_PAGE_DATA_INCLUDE_LINKS)
450  g_clear_pointer (&data->link_mapping, ev_mapping_list_unref);
451 
452  if (flags & EV_PAGE_DATA_INCLUDE_IMAGES)
453  g_clear_pointer (&data->image_mapping, ev_mapping_list_unref);
454 
455  if (flags & EV_PAGE_DATA_INCLUDE_FORMS)
456  g_clear_pointer (&data->form_field_mapping, ev_mapping_list_unref);
457 
458  if (flags & EV_PAGE_DATA_INCLUDE_ANNOTS)
459  g_clear_pointer (&data->annot_mapping, ev_mapping_list_unref);
460 
461  if (flags & EV_PAGE_DATA_INCLUDE_MEDIA)
462  g_clear_pointer (&data->media_mapping, ev_mapping_list_unref);
463 
465  g_clear_pointer (&data->text_mapping, cairo_region_destroy);
466 
467  if (flags & EV_PAGE_DATA_INCLUDE_TEXT)
468  g_clear_pointer (&data->text, g_free);
469 
470  if (flags & EV_PAGE_DATA_INCLUDE_TEXT_LAYOUT) {
471  g_clear_pointer (&data->text_layout, g_free);
472  data->text_layout_length = 0;
473  }
474 
476  g_clear_pointer (&data->text_attrs, pango_attr_list_unref);
477 
479  g_clear_pointer (&data->text_log_attrs, g_free);
480  data->text_log_attrs_length = 0;
481  }
482 
483  /* Update the current range */
484  ev_page_cache_set_page_range (cache, cache->start_page, cache->end_page);
485 }
486 
489  gint page)
490 {
491  EvPageCacheData *data;
492 
493  g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL);
494  g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL);
495 
496  if (!(cache->flags & EV_PAGE_DATA_INCLUDE_LINKS))
497  return NULL;
498 
499  data = &cache->page_list[page];
500  if (data->done)
501  return data->link_mapping;
502 
503  if (data->job)
504  return EV_JOB_PAGE_DATA (data->job)->link_mapping;
505 
506  return data->link_mapping;
507 }
508 
511  gint page)
512 {
513  EvPageCacheData *data;
514 
515  g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL);
516  g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL);
517 
518  if (!(cache->flags & EV_PAGE_DATA_INCLUDE_IMAGES))
519  return NULL;
520 
521  data = &cache->page_list[page];
522  if (data->done)
523  return data->image_mapping;
524 
525  if (data->job)
526  return EV_JOB_PAGE_DATA (data->job)->image_mapping;
527 
528  return data->image_mapping;
529 }
530 
533  gint page)
534 {
535  EvPageCacheData *data;
536 
537  g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL);
538  g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL);
539 
540  if (!(cache->flags & EV_PAGE_DATA_INCLUDE_FORMS))
541  return NULL;
542 
543  data = &cache->page_list[page];
544  if (data->done)
545  return data->form_field_mapping;
546 
547  if (data->job)
548  return EV_JOB_PAGE_DATA (data->job)->form_field_mapping;
549 
550  return data->form_field_mapping;
551 }
552 
555  gint page)
556 {
557  EvPageCacheData *data;
558 
559  g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL);
560  g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL);
561 
562  if (!(cache->flags & EV_PAGE_DATA_INCLUDE_ANNOTS))
563  return NULL;
564 
565  data = &cache->page_list[page];
566  if (data->done)
567  return data->annot_mapping;
568 
569  if (data->job)
570  return EV_JOB_PAGE_DATA (data->job)->annot_mapping;
571 
572  return data->annot_mapping;
573 }
574 
577  gint page)
578 {
579  EvPageCacheData *data;
580 
581  g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL);
582  g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL);
583 
584  if (!(cache->flags & EV_PAGE_DATA_INCLUDE_MEDIA))
585  return NULL;
586 
587  data = &cache->page_list[page];
588  if (data->done)
589  return data->media_mapping;
590 
591  if (data->job)
592  return EV_JOB_PAGE_DATA (data->job)->media_mapping;
593 
594  return data->media_mapping;
595 }
596 
597 cairo_region_t *
599  gint page)
600 {
601  EvPageCacheData *data;
602 
603  g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL);
604  g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL);
605 
607  return NULL;
608 
609  data = &cache->page_list[page];
610  if (data->done)
611  return data->text_mapping;
612 
613  if (data->job)
614  return EV_JOB_PAGE_DATA (data->job)->text_mapping;
615 
616  return data->text_mapping;
617 }
618 
619 const gchar *
621  gint page)
622 {
623  EvPageCacheData *data;
624 
625  g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL);
626  g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL);
627 
628  if (!(cache->flags & EV_PAGE_DATA_INCLUDE_TEXT))
629  return NULL;
630 
631  data = &cache->page_list[page];
632  if (data->done)
633  return data->text;
634 
635  if (data->job)
636  return EV_JOB_PAGE_DATA (data->job)->text;
637 
638  return data->text;
639 }
640 
641 gboolean
643  gint page,
644  EvRectangle **areas,
645  guint *n_areas)
646 {
647  EvPageCacheData *data;
648 
649  g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), FALSE);
650  g_return_val_if_fail (page >= 0 && page < cache->n_pages, FALSE);
651 
652  if (!(cache->flags & EV_PAGE_DATA_INCLUDE_TEXT_LAYOUT))
653  return FALSE;
654 
655  data = &cache->page_list[page];
656  if (data->done) {
657  *areas = data->text_layout;
658  *n_areas = data->text_layout_length;
659 
660  return TRUE;
661  }
662 
663  if (data->job) {
664  *areas = EV_JOB_PAGE_DATA (data->job)->text_layout;
665  *n_areas = EV_JOB_PAGE_DATA (data->job)->text_layout_length;
666 
667  return TRUE;
668  }
669 
670  return FALSE;
671 }
672 
682 PangoAttrList *
684  gint page)
685 {
686  EvPageCacheData *data;
687 
688  g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL);
689  g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL);
690 
691  if (!(cache->flags & EV_PAGE_DATA_INCLUDE_TEXT_ATTRS))
692  return NULL;
693 
694  data = &cache->page_list[page];
695  if (data->done)
696  return data->text_attrs;
697 
698  if (data->job)
699  return EV_JOB_PAGE_DATA(data->job)->text_attrs;
700 
701  return data->text_attrs;
702 }
703 
717 gboolean
719  gint page,
720  PangoLogAttr **log_attrs,
721  gulong *n_attrs)
722 {
723  EvPageCacheData *data;
724 
725  g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), FALSE);
726  g_return_val_if_fail (page >= 0 && page < cache->n_pages, FALSE);
727 
729  return FALSE;
730 
731  data = &cache->page_list[page];
732  if (data->done) {
733  *log_attrs = data->text_log_attrs;
734  *n_attrs = data->text_log_attrs_length;
735 
736  return TRUE;
737  }
738 
739  if (data->job) {
740  *log_attrs = EV_JOB_PAGE_DATA (data->job)->text_log_attrs;
741  *n_attrs = EV_JOB_PAGE_DATA (data->job)->text_log_attrs_length;
742 
743  return TRUE;
744  }
745 
746  return FALSE;
747 }
748 
749 void
751  gint page)
752 {
753  g_return_if_fail (EV_IS_PAGE_CACHE (cache));
754  g_return_if_fail (page >= 0 && page < cache->n_pages);
755 
757 }
758 
759 gboolean
761  gint page)
762 {
763  EvPageCacheData *data;
764 
765  g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), FALSE);
766  g_return_val_if_fail (page >= 0 && page < cache->n_pages, FALSE);
767 
768  data = &cache->page_list[page];
769 
770  return data->done;
771 }