]> www.fi.muni.cz Git - evince.git/blob - libview/ev-page-cache.c
[dualscreen] fix crash on ctrl+w and fix control window closing
[evince.git] / libview / ev-page-cache.c
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"
30 #include "ev-document-annotations.h"
31 #include "ev-document-text.h"
32 #include "ev-page-cache.h"
33
34 typedef struct _EvPageCacheData {
35         EvJob             *job;
36         gboolean           done : 1;
37         gboolean           dirty : 1;
38         EvJobPageDataFlags flags;
39
40         EvMappingList     *link_mapping;
41         EvMappingList     *image_mapping;
42         EvMappingList     *form_field_mapping;
43         EvMappingList     *annot_mapping;
44         cairo_region_t    *text_mapping;
45         EvRectangle       *text_layout;
46         guint              text_layout_length;
47         gchar             *text;
48 } EvPageCacheData;
49
50 struct _EvPageCache {
51         GObject parent;
52
53         EvDocument        *document;
54         EvPageCacheData   *page_list;
55         gint               n_pages;
56
57         /* Current range */
58         gint               start_page;
59         gint               end_page;
60
61         EvJobPageDataFlags flags;
62 };
63
64 struct _EvPageCacheClass {
65         GObjectClass parent_class;
66 };
67
68 #define EV_PAGE_DATA_FLAGS_DEFAULT (        \
69         EV_PAGE_DATA_INCLUDE_LINKS        | \
70         EV_PAGE_DATA_INCLUDE_TEXT_MAPPING | \
71         EV_PAGE_DATA_INCLUDE_IMAGES       | \
72         EV_PAGE_DATA_INCLUDE_FORMS        | \
73         EV_PAGE_DATA_INCLUDE_ANNOTS)
74
75
76 static void job_page_data_finished_cb (EvJob       *job,
77                                        EvPageCache *cache);
78 static void job_page_data_cancelled_cb (EvJob       *job,
79                                         EvPageCacheData *data);
80
81 G_DEFINE_TYPE (EvPageCache, ev_page_cache, G_TYPE_OBJECT)
82
83 static void
84 ev_page_cache_data_free (EvPageCacheData *data)
85 {
86         if (data->job) {
87                 g_object_unref (data->job);
88                 data->job = NULL;
89         }
90
91         if (data->link_mapping) {
92                 ev_mapping_list_unref (data->link_mapping);
93                 data->link_mapping = NULL;
94         }
95
96         if (data->image_mapping) {
97                 ev_mapping_list_unref (data->image_mapping);
98                 data->image_mapping = NULL;
99         }
100
101         if (data->form_field_mapping) {
102                 ev_mapping_list_unref (data->form_field_mapping);
103                 data->form_field_mapping = NULL;
104         }
105
106         if (data->annot_mapping) {
107                 ev_mapping_list_unref (data->annot_mapping);
108                 data->annot_mapping = NULL;
109         }
110
111         if (data->text_mapping) {
112                 cairo_region_destroy (data->text_mapping);
113                 data->text_mapping = NULL;
114         }
115
116         if (data->text_layout) {
117                 g_free (data->text_layout);
118                 data->text_layout = NULL;
119                 data->text_layout_length = 0;
120         }
121
122         if (data->text) {
123                 g_free (data->text);
124                 data->text = NULL;
125         }
126 }
127
128 static void
129 ev_page_cache_finalize (GObject *object)
130 {
131         EvPageCache *cache = EV_PAGE_CACHE (object);
132         gint         i;
133
134         if (cache->page_list) {
135                 for (i = 0; i < cache->n_pages; i++) {
136                         EvPageCacheData *data;
137
138                         data = &cache->page_list[i];
139
140                         if (data->job) {
141                                 g_signal_handlers_disconnect_by_func (data->job,
142                                                                       G_CALLBACK (job_page_data_finished_cb),
143                                                                       cache);
144                                 g_signal_handlers_disconnect_by_func (data->job,
145                                                                       G_CALLBACK (job_page_data_cancelled_cb),
146                                                                       data);
147                         }
148                         ev_page_cache_data_free (data);
149                 }
150
151                 g_free (cache->page_list);
152                 cache->page_list = NULL;
153                 cache->n_pages = 0;
154         }
155
156         if (cache->document) {
157                 g_object_unref (cache->document);
158                 cache->document = NULL;
159         }
160
161         G_OBJECT_CLASS (ev_page_cache_parent_class)->finalize (object);
162 }
163
164 static void
165 ev_page_cache_init (EvPageCache *cache)
166 {
167 }
168
169 static void
170 ev_page_cache_class_init (EvPageCacheClass *klass)
171 {
172         GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
173
174         g_object_class->finalize = ev_page_cache_finalize;
175 }
176
177 static EvJobPageDataFlags
178 ev_page_cache_get_flags_for_data (EvPageCache     *cache,
179                                   EvPageCacheData *data)
180 {
181         EvJobPageDataFlags flags = EV_PAGE_DATA_INCLUDE_NONE;
182
183         if (data->flags == cache->flags && !data->dirty)
184                 return cache->flags;
185
186         /* Flags changed or data is dirty */
187         if (cache->flags & EV_PAGE_DATA_INCLUDE_LINKS) {
188                 flags = (data->link_mapping) ?
189                         flags & ~EV_PAGE_DATA_INCLUDE_LINKS :
190                         flags | EV_PAGE_DATA_INCLUDE_LINKS;
191         }
192
193         if (cache->flags & EV_PAGE_DATA_INCLUDE_IMAGES) {
194                 flags = (data->image_mapping) ?
195                         flags & ~EV_PAGE_DATA_INCLUDE_IMAGES :
196                         flags | EV_PAGE_DATA_INCLUDE_IMAGES;
197         }
198
199         if (cache->flags & EV_PAGE_DATA_INCLUDE_FORMS) {
200                 flags = (data->form_field_mapping) ?
201                         flags & ~EV_PAGE_DATA_INCLUDE_FORMS :
202                         flags | EV_PAGE_DATA_INCLUDE_FORMS;
203         }
204
205         if (cache->flags & EV_PAGE_DATA_INCLUDE_ANNOTS) {
206                 flags = (data->annot_mapping) ?
207                         flags & ~EV_PAGE_DATA_INCLUDE_ANNOTS :
208                         flags | EV_PAGE_DATA_INCLUDE_ANNOTS;
209         }
210
211         if (cache->flags & EV_PAGE_DATA_INCLUDE_TEXT_MAPPING) {
212                 flags = (data->text_mapping) ?
213                         flags & ~EV_PAGE_DATA_INCLUDE_TEXT_MAPPING :
214                         flags | EV_PAGE_DATA_INCLUDE_TEXT_MAPPING;
215         }
216
217         if (cache->flags & EV_PAGE_DATA_INCLUDE_TEXT) {
218                 flags = (data->text) ?
219                         flags & ~EV_PAGE_DATA_INCLUDE_TEXT :
220                         flags | EV_PAGE_DATA_INCLUDE_TEXT;
221         }
222
223         if (cache->flags & EV_PAGE_DATA_INCLUDE_TEXT_LAYOUT) {
224                 flags = (data->text_layout_length > 0) ?
225                         flags & ~EV_PAGE_DATA_INCLUDE_TEXT_LAYOUT :
226                         flags | EV_PAGE_DATA_INCLUDE_TEXT_LAYOUT;
227         }
228
229         return flags;
230 }
231
232 EvPageCache *
233 ev_page_cache_new (EvDocument *document)
234 {
235         EvPageCache *cache;
236
237         g_return_val_if_fail (EV_IS_DOCUMENT (document), NULL);
238
239         cache = EV_PAGE_CACHE (g_object_new (EV_TYPE_PAGE_CACHE, NULL));
240         cache->document = g_object_ref (document);
241         cache->n_pages = ev_document_get_n_pages (document);
242         cache->flags = EV_PAGE_DATA_FLAGS_DEFAULT;
243         cache->page_list = g_new0 (EvPageCacheData, cache->n_pages);
244
245         return cache;
246 }
247
248 static void
249 job_page_data_finished_cb (EvJob       *job,
250                            EvPageCache *cache)
251 {
252         EvJobPageData   *job_data = EV_JOB_PAGE_DATA (job);
253         EvPageCacheData *data;
254
255         data = &cache->page_list[job_data->page];
256
257         if (job_data->flags & EV_PAGE_DATA_INCLUDE_LINKS)
258                 data->link_mapping = job_data->link_mapping;
259         if (job_data->flags & EV_PAGE_DATA_INCLUDE_IMAGES)
260                 data->image_mapping = job_data->image_mapping;
261         if (job_data->flags & EV_PAGE_DATA_INCLUDE_FORMS)
262                 data->form_field_mapping = job_data->form_field_mapping;
263         if (job_data->flags & EV_PAGE_DATA_INCLUDE_ANNOTS)
264                 data->annot_mapping = job_data->annot_mapping;
265         if (job_data->flags & EV_PAGE_DATA_INCLUDE_TEXT_MAPPING)
266                 data->text_mapping = job_data->text_mapping;
267         if (job_data->flags & EV_PAGE_DATA_INCLUDE_TEXT_LAYOUT) {
268                 data->text_layout = job_data->text_layout;
269                 data->text_layout_length = job_data->text_layout_length;
270         }
271         if (job_data->flags & EV_PAGE_DATA_INCLUDE_TEXT)
272                 data->text = job_data->text;
273         data->done = TRUE;
274         data->dirty = FALSE;
275
276         g_object_unref (data->job);
277         data->job = NULL;
278 }
279
280 static void
281 job_page_data_cancelled_cb (EvJob           *job,
282                             EvPageCacheData *data)
283 {
284         g_object_unref (data->job);
285         data->job = NULL;
286 }
287
288 void
289 ev_page_cache_set_page_range (EvPageCache *cache,
290                               gint         start,
291                               gint         end)
292 {
293         gint i;
294
295         if (cache->flags == EV_PAGE_DATA_INCLUDE_NONE)
296                 return;
297
298         cache->start_page = start;
299         cache->end_page = end;
300
301         for (i = start; i <= end; i++) {
302                 EvPageCacheData   *data = &cache->page_list[i];
303                 EvJobPageDataFlags flags;
304
305                 if (data->flags == cache->flags && !data->dirty && (data->done || data->job))
306                         continue;
307
308                 if (data->job)
309                         ev_job_cancel (data->job);
310
311                 flags = ev_page_cache_get_flags_for_data (cache, data);
312
313                 data->flags = cache->flags;
314                 data->job = ev_job_page_data_new (cache->document, i, flags);
315                 g_signal_connect (data->job, "finished",
316                                   G_CALLBACK (job_page_data_finished_cb),
317                                   cache);
318                 g_signal_connect (data->job, "cancelled",
319                                   G_CALLBACK (job_page_data_cancelled_cb),
320                                   data);
321                 ev_job_scheduler_push_job (data->job, EV_JOB_PRIORITY_NONE);
322         }
323 }
324
325 EvJobPageDataFlags
326 ev_page_cache_get_flags (EvPageCache *cache)
327 {
328         return cache->flags;
329 }
330
331 void
332 ev_page_cache_set_flags (EvPageCache       *cache,
333                          EvJobPageDataFlags flags)
334 {
335         if (cache->flags == flags)
336                 return;
337
338         cache->flags = flags;
339
340         /* Update the current range for new flags */
341         ev_page_cache_set_page_range (cache, cache->start_page, cache->end_page);
342 }
343
344 void
345 ev_page_cache_mark_dirty (EvPageCache *cache,
346                           gint         page)
347 {
348         EvPageCacheData *data;
349
350         g_return_if_fail (EV_IS_PAGE_CACHE (cache));
351
352         data = &cache->page_list[page];
353         data->dirty = TRUE;
354
355         /* Update the current range */
356         ev_page_cache_set_page_range (cache, cache->start_page, cache->end_page);
357 }
358
359 EvMappingList *
360 ev_page_cache_get_link_mapping (EvPageCache *cache,
361                                 gint         page)
362 {
363         EvPageCacheData *data;
364
365         g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL);
366         g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL);
367
368         if (!(cache->flags & EV_PAGE_DATA_INCLUDE_LINKS))
369                 return NULL;
370
371         data = &cache->page_list[page];
372         if (data->done)
373                 return data->link_mapping;
374
375         if (data->job)
376                 return EV_JOB_PAGE_DATA (data->job)->link_mapping;
377
378         return data->link_mapping;
379 }
380
381 EvMappingList *
382 ev_page_cache_get_image_mapping (EvPageCache *cache,
383                                  gint         page)
384 {
385         EvPageCacheData *data;
386
387         g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL);
388         g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL);
389
390         if (!(cache->flags & EV_PAGE_DATA_INCLUDE_IMAGES))
391                 return NULL;
392
393         data = &cache->page_list[page];
394         if (data->done)
395                 return data->image_mapping;
396
397         if (data->job)
398                 return EV_JOB_PAGE_DATA (data->job)->image_mapping;
399
400         return data->image_mapping;
401 }
402
403 EvMappingList *
404 ev_page_cache_get_form_field_mapping (EvPageCache *cache,
405                                       gint         page)
406 {
407         EvPageCacheData *data;
408
409         g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL);
410         g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL);
411
412         if (!(cache->flags & EV_PAGE_DATA_INCLUDE_FORMS))
413                 return NULL;
414
415         data = &cache->page_list[page];
416         if (data->done)
417                 return data->form_field_mapping;
418
419         if (data->job)
420                 return EV_JOB_PAGE_DATA (data->job)->form_field_mapping;
421
422         return data->form_field_mapping;
423 }
424
425 EvMappingList *
426 ev_page_cache_get_annot_mapping (EvPageCache *cache,
427                                  gint         page)
428 {
429         EvPageCacheData *data;
430
431         g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL);
432         g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL);
433
434         if (!(cache->flags & EV_PAGE_DATA_INCLUDE_ANNOTS))
435                 return NULL;
436
437         data = &cache->page_list[page];
438         if (data->done)
439                 return data->annot_mapping;
440
441         if (data->job)
442                 return EV_JOB_PAGE_DATA (data->job)->annot_mapping;
443
444         return data->annot_mapping;
445 }
446
447 cairo_region_t *
448 ev_page_cache_get_text_mapping (EvPageCache *cache,
449                                 gint         page)
450 {
451         EvPageCacheData *data;
452
453         g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL);
454         g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL);
455
456         if (!(cache->flags & EV_PAGE_DATA_INCLUDE_TEXT_MAPPING))
457                 return NULL;
458
459         data = &cache->page_list[page];
460         if (data->done)
461                 return data->text_mapping;
462
463         if (data->job)
464                 return EV_JOB_PAGE_DATA (data->job)->text_mapping;
465
466         return data->text_mapping;
467 }
468
469 const gchar *
470 ev_page_cache_get_text (EvPageCache *cache,
471                              gint         page)
472 {
473         EvPageCacheData *data;
474
475         g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), NULL);
476         g_return_val_if_fail (page >= 0 && page < cache->n_pages, NULL);
477
478         if (!(cache->flags & EV_PAGE_DATA_INCLUDE_TEXT))
479                 return NULL;
480
481         data = &cache->page_list[page];
482         if (data->done)
483                 return data->text;
484
485         if (data->job)
486                 return EV_JOB_PAGE_DATA (data->job)->text;
487
488         return data->text;
489 }
490
491 gboolean
492 ev_page_cache_get_text_layout (EvPageCache  *cache,
493                                gint          page,
494                                EvRectangle **areas,
495                                guint        *n_areas)
496 {
497         EvPageCacheData *data;
498
499         g_return_val_if_fail (EV_IS_PAGE_CACHE (cache), FALSE);
500         g_return_val_if_fail (page >= 0 && page < cache->n_pages, FALSE);
501
502         if (!(cache->flags & EV_PAGE_DATA_INCLUDE_TEXT_LAYOUT))
503                 return FALSE;
504
505         data = &cache->page_list[page];
506         if (data->done) {
507                 *areas = data->text_layout;
508                 *n_areas = data->text_layout_length;
509
510                 return TRUE;
511         }
512
513         if (data->job) {
514                 *areas = EV_JOB_PAGE_DATA (data->job)->text_layout;
515                 *n_areas = EV_JOB_PAGE_DATA (data->job)->text_layout_length;
516
517                 return TRUE;
518         }
519
520         return FALSE;
521 }