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