]> www.fi.muni.cz Git - evince.git/blob - shell/ev-page-cache.c
Fixes program description translation issue. Bug #450148.
[evince.git] / shell / ev-page-cache.c
1 #include "ev-page-cache.h"
2 #include "ev-job-queue.h"
3 #include <stdlib.h>
4 #include <string.h>
5
6 typedef struct _EvPageCacheInfo
7 {
8         double width;
9         double height;
10 }
11 EvPageCacheInfo;
12
13
14 struct _EvPageCache
15 {
16         GObject parent;
17
18         gint current_page;
19         int n_pages;
20         char *title;
21         char **page_labels;
22         
23         gint max_label_chars;
24         gboolean has_labels;
25         gboolean uniform;
26         gboolean dual_even_left;
27         
28         double uniform_width;
29         double uniform_height;
30
31         double  max_width;
32         double  max_height;
33
34         double* height_to_page;
35         double* dual_height_to_page;
36
37         int rotation;
38
39         EvPageCacheInfo *size_cache;
40         EvDocumentInfo *page_info;
41 };
42
43 struct _EvPageCacheClass
44 {
45         GObjectClass parent_class;
46
47         void (* page_changed) (EvPageCache *page_cache, gint page);
48         void (* history_changed) (EvPageCache *page_cache, gint page);
49 };
50
51 enum
52 {
53         PAGE_CHANGED,
54         HISTORY_CHANGED,
55         N_SIGNALS,
56 };
57
58 static guint signals[N_SIGNALS] = {0, };
59
60 static void ev_page_cache_init       (EvPageCache      *page_cache);
61 static void ev_page_cache_class_init (EvPageCacheClass *page_cache);
62 static void ev_page_cache_finalize   (GObject *object);
63
64 G_DEFINE_TYPE (EvPageCache, ev_page_cache, G_TYPE_OBJECT)
65
66 static void
67 ev_page_cache_init (EvPageCache *page_cache)
68 {
69         page_cache->current_page = -1;
70         page_cache->max_label_chars = 0;
71 }
72
73 static void
74 ev_page_cache_class_init (EvPageCacheClass *class)
75 {
76         GObjectClass *object_class;
77
78         object_class = G_OBJECT_CLASS (class);
79
80         object_class->finalize = ev_page_cache_finalize;
81
82         signals [PAGE_CHANGED] =
83                 g_signal_new ("page-changed",
84                               EV_TYPE_PAGE_CACHE,
85                               G_SIGNAL_RUN_LAST,
86                               G_STRUCT_OFFSET (EvPageCacheClass, page_changed),
87                               NULL, NULL,
88                               g_cclosure_marshal_VOID__INT,
89                               G_TYPE_NONE, 1,
90                               G_TYPE_INT);
91
92         signals [HISTORY_CHANGED] =
93                 g_signal_new ("history-changed",
94                               EV_TYPE_PAGE_CACHE,
95                               G_SIGNAL_RUN_LAST,
96                               G_STRUCT_OFFSET (EvPageCacheClass, history_changed),
97                               NULL, NULL,
98                               g_cclosure_marshal_VOID__INT,
99                               G_TYPE_NONE, 1,
100                               G_TYPE_INT);
101
102 }
103
104 static void
105 ev_page_cache_finalize (GObject *object)
106 {
107         EvPageCache *page_cache;
108
109         page_cache = EV_PAGE_CACHE (object);
110
111         if (page_cache->title) {
112                 g_free (page_cache->title);
113                 page_cache->title = NULL;
114         }
115
116         if (page_cache->size_cache) {
117                 g_free (page_cache->size_cache);
118                 page_cache->size_cache = NULL;
119         }
120
121         if (page_cache->height_to_page) {
122                 g_free (page_cache->height_to_page);
123                 page_cache->height_to_page = NULL;
124         }
125
126         if (page_cache->dual_height_to_page) {
127                 g_free (page_cache->dual_height_to_page);
128                 page_cache->dual_height_to_page = NULL;
129         }
130
131         if (page_cache->page_labels) {
132                 gint i;
133
134                 for (i = 0; i < page_cache->n_pages; i++) {
135                         if (page_cache->page_labels[i])
136                                 g_free (page_cache->page_labels[i]);
137                 }
138                 g_free (page_cache->page_labels);
139                 page_cache->page_labels = NULL;
140         }
141
142         if (page_cache->page_info) {
143                 ev_document_info_free (page_cache->page_info);
144                 page_cache->page_info = NULL;
145         }
146
147         G_OBJECT_CLASS (ev_page_cache_parent_class)->finalize (object);
148 }
149
150 static void
151 build_height_to_page (EvPageCache *page_cache)
152 {
153         gboolean swap;
154         int i;
155         double uniform_height, page_height, next_page_height;
156         double saved_height;
157
158         swap = (page_cache->rotation == 90 ||
159                 page_cache->rotation == 270);
160
161         g_free (page_cache->height_to_page);
162         g_free (page_cache->dual_height_to_page);
163
164         page_cache->height_to_page = g_new0(double, page_cache->n_pages + 1);
165         page_cache->dual_height_to_page = g_new0(double, page_cache->n_pages + 2);
166         
167         saved_height = 0;
168         for (i = 0; i <= page_cache->n_pages; i++) {
169                 if (page_cache->uniform) {
170                         if (!swap) {
171                                 uniform_height = page_cache->uniform_height;
172                         } else {
173                                 uniform_height = page_cache->uniform_width;
174                         }
175                         page_cache->height_to_page [i] = i * uniform_height;
176                 } else {
177                         if (!swap) {
178                                 page_height = page_cache->size_cache [i].height;
179                         } else {
180                                 page_height = page_cache->size_cache [i].width;
181                         }
182                         page_cache->height_to_page [i] = saved_height;
183                         saved_height += page_height;
184                 }
185         }
186
187         if (page_cache->dual_even_left && !page_cache->uniform) {
188                 if (!swap) {
189                         saved_height = page_cache->size_cache [0].height;
190                 } else {
191                         saved_height = page_cache->size_cache [0].width;
192                 }
193         } else {
194                 saved_height = 0;
195         }
196         for (i = page_cache->dual_even_left; i < page_cache->n_pages + 2; i += 2) {
197                 if (page_cache->uniform) {
198                         if (!swap) {
199                                 uniform_height = page_cache->uniform_height;
200                         } else {
201                                 uniform_height = page_cache->uniform_width;
202                         }
203                         page_cache->dual_height_to_page [i] = ((i + page_cache->dual_even_left) / 2) * uniform_height;
204                         if (i + 1 < page_cache->n_pages + 2)
205                                 page_cache->dual_height_to_page [i + 1] = ((i + page_cache->dual_even_left) / 2) * uniform_height;
206                 } else {
207                         if (i + 1 < page_cache->n_pages) {
208                                 if (!swap) {
209                                         next_page_height = page_cache->size_cache [i + 1].height;
210                                 } else {
211                                         next_page_height = page_cache->size_cache [i + 1].width;
212                                 }
213                         } else {
214                                 next_page_height = 0;
215                         }
216                         if (i < page_cache->n_pages) {
217                                 if (!swap) {
218                                         page_height = page_cache->size_cache [i].height;
219                                 } else {
220                                         page_height = page_cache->size_cache [i].width;
221                                 }
222                         } else {
223                                 page_height = 0;
224                         }
225                         if (i + 1 < page_cache->n_pages + 2) {
226                                 page_cache->dual_height_to_page [i] = saved_height;
227                                 page_cache->dual_height_to_page [i + 1] = saved_height;
228                                 saved_height += MAX(page_height, next_page_height);
229                         } else {
230                                 page_cache->dual_height_to_page [i] = saved_height;
231                         }
232                 }
233         }
234 }
235
236 EvPageCache *
237 ev_page_cache_new (EvDocument *document)
238 {
239         EvPageCache *page_cache;
240         EvPageCacheInfo *info;
241         gint i;
242
243         page_cache = (EvPageCache *) g_object_new (EV_TYPE_PAGE_CACHE, NULL);
244
245         ev_document_doc_mutex_lock ();
246
247         /* We read page information out of the document */
248
249         /* Assume all pages are the same size until proven otherwise */
250         page_cache->uniform = TRUE;
251         page_cache->has_labels = FALSE;
252         page_cache->n_pages = ev_document_get_n_pages (document);
253         page_cache->dual_even_left = (page_cache->n_pages > 2);
254         page_cache->page_labels = g_new0 (char *, page_cache->n_pages);
255         page_cache->max_width = 0;
256         page_cache->max_height = 0;
257         page_cache->page_info = ev_document_get_info (document);
258
259         if (page_cache->page_info->fields_mask & EV_DOCUMENT_INFO_TITLE) {
260                 page_cache->title = g_strdup (page_cache->page_info->title);
261         } else {
262                 page_cache->title = NULL;
263         }
264
265         for (i = 0; i < page_cache->n_pages; i++) {
266                 double page_width = 0;
267                 double page_height = 0;
268                 
269                 ev_document_get_page_size (document, i, &page_width, &page_height);
270
271                 page_cache->page_labels[i] = ev_document_get_page_label (document, i);
272                 
273                 if (page_cache->page_labels[i] != NULL) {
274                 
275                         page_cache->max_label_chars = MAX(page_cache->max_label_chars, 
276                                                             g_utf8_strlen (page_cache->page_labels[i], 256));
277                         if (!page_cache->has_labels) {
278                                 gchar *expected_label;
279                         
280                                 expected_label = g_strdup_printf ("%d", i + 1);
281                                 if (strcmp (expected_label, page_cache->page_labels[i]))  
282                                         page_cache->has_labels = TRUE;
283                                 g_free (expected_label);
284                         }
285                 }
286
287                 if (page_width > page_cache->max_width) {
288                         page_cache->max_width = page_width;
289                 }
290
291                 if (page_height > page_cache->max_height) {
292                         page_cache->max_height = page_height;
293                 }
294                         
295                 if (i == 0) {
296                         page_cache->uniform_width = page_width;
297                         page_cache->uniform_height = page_height;
298                 } else if (page_cache->uniform &&
299                            (page_cache->uniform_width != page_width ||
300                             page_cache->uniform_height != page_height)) {
301                         /* It's a different page size.  Backfill the array. */
302                         int j;
303
304                         page_cache->size_cache = g_new0 (EvPageCacheInfo, page_cache->n_pages);
305
306                         for (j = 0; j < i; j++) {
307                                 info = &(page_cache->size_cache [j]);
308                                 info->width = page_cache->uniform_width;
309                                 info->height = page_cache->uniform_height;
310                         }
311                         page_cache->uniform = FALSE;
312
313                 }
314
315                 if (! page_cache->uniform) {
316                         info = &(page_cache->size_cache [i]);
317
318                         info->width = page_width;
319                         info->height = page_height;
320                 }
321         }
322
323         build_height_to_page (page_cache);
324
325         /* make some sanity check assertions */
326         if (! page_cache->uniform)
327                 g_assert (page_cache->size_cache != NULL);
328         if (page_cache->uniform && page_cache->n_pages > 0)
329                 g_assert (page_cache->uniform_width > 0 && page_cache->uniform_height > 0);
330
331         ev_document_doc_mutex_unlock ();
332
333         if (page_cache->n_pages > 0)
334                 ev_page_cache_set_current_page (page_cache, 0);
335
336         return page_cache;
337 }
338
339 gint
340 ev_page_cache_get_n_pages (EvPageCache *page_cache)
341 {
342         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0);
343
344         return page_cache->n_pages;
345 }
346
347 gint
348 ev_page_cache_get_current_page (EvPageCache *page_cache)
349 {
350         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0);
351
352         return page_cache->current_page;
353 }
354
355 void
356 ev_page_cache_set_current_page (EvPageCache *page_cache,
357                                 int          page)
358 {
359         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
360         g_return_if_fail (page >= 0 || page < page_cache->n_pages);
361
362         if (page == page_cache->current_page)
363                 return;
364
365         page_cache->current_page = page;
366         g_signal_emit (page_cache, signals[PAGE_CHANGED], 0, page);
367 }
368
369 void
370 ev_page_cache_set_current_page_history (EvPageCache *page_cache,
371                                         int          page)
372 {
373         if (abs (page - page_cache->current_page) > 1)
374                 g_signal_emit (page_cache, signals [HISTORY_CHANGED], 0, page);
375         
376         ev_page_cache_set_current_page (page_cache, page);
377 }
378
379 gboolean
380 ev_page_cache_set_page_label (EvPageCache *page_cache,
381                               const char  *page_label)
382 {
383         gint i, page;
384         long value;
385         char *endptr = NULL;
386         
387         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE);
388         g_return_val_if_fail (page_label != NULL, FALSE);
389
390         /* First, look for a literal label match */
391         for (i = 0; i < page_cache->n_pages; i ++) {
392                 if (page_cache->page_labels[i] != NULL &&
393                     ! strcmp (page_label, page_cache->page_labels[i])) {
394                         ev_page_cache_set_current_page (page_cache, i);
395                         return TRUE;
396                 }
397         }
398
399         /* Next, parse the label, and see if the number fits */
400         value = strtol (page_label, &endptr, 10);
401         if (endptr[0] == '\0') {
402                 /* Page number is an integer */
403                 page = MIN (G_MAXINT, value);
404
405                 /* convert from a page label to a page offset */
406                 page --;
407                 if (page >= 0 &&
408                     page < page_cache->n_pages) {
409                         ev_page_cache_set_current_page (page_cache, page);
410                         return TRUE;
411                 }
412         }
413
414         return FALSE;
415 }
416
417 const char *
418 ev_page_cache_get_title (EvPageCache *page_cache)
419 {
420         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), NULL);
421
422         return page_cache->title;
423 }
424
425 void
426 ev_page_cache_get_size (EvPageCache  *page_cache,
427                         gint          page,
428                         gint          rotation,
429                         gfloat        scale,
430                         gint         *width,
431                         gint         *height)
432 {
433         double w, h;
434
435         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
436         g_return_if_fail (page >= 0 && page < page_cache->n_pages);
437
438         if (page_cache->uniform) {
439                 w = page_cache->uniform_width;
440                 h = page_cache->uniform_height;
441         } else {
442                 EvPageCacheInfo *info;
443
444                 info = &(page_cache->size_cache [page]);
445                 
446                 w = info->width;
447                 h = info->height;
448         }
449
450         w = w * scale + 0.5;
451         h = h * scale + 0.5;
452
453         if (rotation == 0 || rotation == 180) {
454                 if (width) *width = (int)w;
455                 if (height) *height = (int)h;
456         } else {
457                 if (width) *width = (int)h;
458                 if (height) *height = (int)w;
459         }
460 }
461
462 void
463 ev_page_cache_get_max_width (EvPageCache   *page_cache,
464                              gint           rotation,
465                              gfloat         scale,
466                              gint          *width)
467 {
468         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
469
470         if (width) {
471                 if (rotation == 0 || rotation == 180) {
472                         *width = page_cache->max_width * scale;
473                 } else {
474                         *width = page_cache->max_height * scale;
475                 }
476         }
477 }
478
479 void
480 ev_page_cache_get_max_height (EvPageCache   *page_cache,
481                               gint           rotation,
482                               gfloat         scale,
483                               gint          *height)
484 {
485         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
486
487         if (height) {
488                 if (rotation == 0 || rotation == 180) {
489                         *height = page_cache->max_height * scale;
490                 } else {
491                         *height = page_cache->max_width * scale;
492                 }
493         }
494 }
495
496 void    
497 ev_page_cache_get_height_to_page (EvPageCache   *page_cache,
498                                   gint           page,
499                                   gint           rotation,
500                                   gfloat         scale,
501                                   gint          *height,
502                                   gint          *dual_height)
503 {
504         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
505
506         if (page_cache->rotation != rotation) {
507                 page_cache->rotation = rotation;
508                 build_height_to_page (page_cache);
509         }
510         
511         if (height)
512                 *height = page_cache->height_to_page [page] * scale;
513
514         if (dual_height)
515                 *dual_height = page_cache->dual_height_to_page [page] * scale;
516 }
517
518 gint
519 ev_page_cache_get_max_label_chars (EvPageCache *page_cache)
520 {
521         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0);
522         
523         return page_cache->max_label_chars;
524 }
525
526 gboolean
527 ev_page_cache_get_dual_even_left (EvPageCache *page_cache)
528 {
529         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0);
530         
531         return page_cache->dual_even_left;
532 }
533
534 gchar *
535 ev_page_cache_get_page_label (EvPageCache *page_cache,
536                               gint         page)
537 {
538         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), NULL);
539         g_return_val_if_fail (page >= 0 && page < page_cache->n_pages, NULL);
540
541         if (page_cache->page_labels[page] == NULL)
542                 return g_strdup_printf ("%d", page + 1);
543
544         return g_strdup (page_cache->page_labels[page]);
545 }
546
547 gboolean
548 ev_page_cache_has_nonnumeric_page_labels (EvPageCache *page_cache)
549 {
550         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE);
551         return page_cache->has_labels;
552 }
553
554 const EvDocumentInfo *
555 ev_page_cache_get_info (EvPageCache *page_cache)
556 {
557         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), NULL);
558
559         return page_cache->page_info;
560 }
561
562 #define PAGE_CACHE_STRING "ev-page-cache"
563
564 EvPageCache *
565 ev_page_cache_get (EvDocument *document)
566 {
567         EvPageCache *page_cache;
568
569         g_return_val_if_fail (EV_IS_DOCUMENT (document), NULL);
570
571         page_cache = g_object_get_data (G_OBJECT (document), PAGE_CACHE_STRING);
572         if (page_cache == NULL) {
573                 page_cache = ev_page_cache_new (document);
574                 g_object_set_data_full (G_OBJECT (document), PAGE_CACHE_STRING, page_cache, g_object_unref);
575         }
576
577         return page_cache;
578 }