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