]> www.fi.muni.cz Git - evince.git/blob - libview/ev-page-cache.c
Move part of the EvPageCache to EvDocument
[evince.git] / libview / ev-page-cache.c
1 #include <config.h>
2 #include "ev-page-cache.h"
3 #include "ev-document-thumbnails.h"
4 #include "ev-page.h"
5 #include <stdlib.h>
6 #include <string.h>
7
8 #define THUMBNAIL_WIDTH 100
9
10 typedef struct _EvPageThumbsInfo
11 {
12         gint width;
13         gint height;
14 } EvPageThumbsInfo;
15
16 struct _EvPageCache
17 {
18         GObject parent;
19
20         EvDocument *document;
21
22         gint current_page;
23
24         gboolean dual_even_left;
25
26         double* height_to_page;
27         double* dual_height_to_page;
28
29         int rotation;
30
31         /* Thumbnail dimensions */
32         gboolean thumbs_uniform;
33         gint thumbs_uniform_width;
34         gint thumbs_uniform_height;
35         gint thumbs_max_width;
36         gint thumbs_max_height;
37         EvPageThumbsInfo *thumbs_size_cache;
38 };
39
40 struct _EvPageCacheClass
41 {
42         GObjectClass parent_class;
43
44         void (* page_changed) (EvPageCache *page_cache, gint page);
45         void (* history_changed) (EvPageCache *page_cache, gint page);
46 };
47
48 enum
49 {
50         PAGE_CHANGED,
51         HISTORY_CHANGED,
52         N_SIGNALS,
53 };
54
55 static guint signals[N_SIGNALS] = {0, };
56
57 static void ev_page_cache_init       (EvPageCache      *page_cache);
58 static void ev_page_cache_class_init (EvPageCacheClass *page_cache);
59 static void ev_page_cache_finalize   (GObject *object);
60
61 G_DEFINE_TYPE (EvPageCache, ev_page_cache, G_TYPE_OBJECT)
62
63 static void
64 ev_page_cache_init (EvPageCache *page_cache)
65 {
66         page_cache->current_page = -1;
67 }
68
69 static void
70 ev_page_cache_class_init (EvPageCacheClass *class)
71 {
72         GObjectClass *object_class;
73
74         object_class = G_OBJECT_CLASS (class);
75
76         object_class->finalize = ev_page_cache_finalize;
77
78         signals [PAGE_CHANGED] =
79                 g_signal_new ("page-changed",
80                               EV_TYPE_PAGE_CACHE,
81                               G_SIGNAL_RUN_LAST,
82                               G_STRUCT_OFFSET (EvPageCacheClass, page_changed),
83                               NULL, NULL,
84                               g_cclosure_marshal_VOID__INT,
85                               G_TYPE_NONE, 1,
86                               G_TYPE_INT);
87
88         signals [HISTORY_CHANGED] =
89                 g_signal_new ("history-changed",
90                               EV_TYPE_PAGE_CACHE,
91                               G_SIGNAL_RUN_LAST,
92                               G_STRUCT_OFFSET (EvPageCacheClass, history_changed),
93                               NULL, NULL,
94                               g_cclosure_marshal_VOID__INT,
95                               G_TYPE_NONE, 1,
96                               G_TYPE_INT);
97
98 }
99
100 static void
101 ev_page_cache_finalize (GObject *object)
102 {
103         EvPageCache *page_cache = EV_PAGE_CACHE (object);
104
105         page_cache->document = NULL;
106
107         if (page_cache->thumbs_size_cache) {
108                 g_free (page_cache->thumbs_size_cache);
109                 page_cache->thumbs_size_cache = NULL;
110         }
111
112         if (page_cache->height_to_page) {
113                 g_free (page_cache->height_to_page);
114                 page_cache->height_to_page = NULL;
115         }
116
117         if (page_cache->dual_height_to_page) {
118                 g_free (page_cache->dual_height_to_page);
119                 page_cache->dual_height_to_page = NULL;
120         }
121
122         G_OBJECT_CLASS (ev_page_cache_parent_class)->finalize (object);
123 }
124
125 static void
126 build_height_to_page (EvPageCache *page_cache)
127 {
128         gboolean swap, uniform, dual_even_left;
129         int i;
130         double uniform_height, page_height, next_page_height;
131         double saved_height;
132         gdouble u_width, u_height;
133         gint n_pages;
134
135         swap = (page_cache->rotation == 90 ||
136                 page_cache->rotation == 270);
137
138         uniform = ev_document_is_page_size_uniform (page_cache->document);
139         n_pages = ev_document_get_n_pages (page_cache->document);
140         dual_even_left = (n_pages > 2);
141
142         g_free (page_cache->height_to_page);
143         g_free (page_cache->dual_height_to_page);
144
145         page_cache->height_to_page = g_new0 (double, n_pages + 1);
146         page_cache->dual_height_to_page = g_new0 (double, n_pages + 2);
147
148         if (uniform)
149                 ev_document_get_page_size (page_cache->document, 0, &u_width, &u_height);
150
151         saved_height = 0;
152         for (i = 0; i <= n_pages; i++) {
153                 if (uniform) {
154                         uniform_height = swap ? u_width : u_height;
155                         page_cache->height_to_page[i] = i * uniform_height;
156                 } else {
157                         if (i < n_pages) {
158                                 gdouble w, h;
159
160                                 ev_document_get_page_size (page_cache->document, i, &w, &h);
161                                 page_height = swap ? w : h;
162                         } else {
163                                 page_height = 0;
164                         }
165                         page_cache->height_to_page[i] = saved_height;
166                         saved_height += page_height;
167                 }
168         }
169
170         if (dual_even_left && !uniform) {
171                 gdouble w, h;
172
173                 ev_document_get_page_size (page_cache->document, 0, &w, &h);
174                 saved_height = swap ? w : h;
175         } else {
176                 saved_height = 0;
177         }
178
179         for (i = dual_even_left; i < n_pages + 2; i += 2) {
180                 if (uniform) {
181                         uniform_height = swap ? u_width : u_height;
182                         page_cache->dual_height_to_page[i] = ((i + dual_even_left) / 2) * uniform_height;
183                         if (i + 1 < n_pages + 2)
184                                 page_cache->dual_height_to_page[i + 1] = ((i + dual_even_left) / 2) * uniform_height;
185                 } else {
186                         if (i + 1 < n_pages) {
187                                 gdouble w, h;
188
189                                 ev_document_get_page_size (page_cache->document, i + 1, &w, &h);
190                                 next_page_height = swap ? w : h;
191                         } else {
192                                 next_page_height = 0;
193                         }
194
195                         if (i < n_pages) {
196                                 gdouble w, h;
197
198                                 ev_document_get_page_size (page_cache->document, i, &w, &h);
199                                 page_height = swap ? w : h;
200                         } else {
201                                 page_height = 0;
202                         }
203
204                         if (i + 1 < n_pages + 2) {
205                                 page_cache->dual_height_to_page[i] = saved_height;
206                                 page_cache->dual_height_to_page[i + 1] = saved_height;
207                                 saved_height += MAX(page_height, next_page_height);
208                         } else {
209                                 page_cache->dual_height_to_page[i] = saved_height;
210                         }
211                 }
212         }
213 }
214
215 static EvPageCache *
216 ev_page_cache_new (EvDocument *document)
217 {
218         EvPageCache *page_cache;
219         EvPageThumbsInfo *thumb_info;
220         EvRenderContext *rc = NULL;
221         gint i, n_pages;
222
223         page_cache = (EvPageCache *) g_object_new (EV_TYPE_PAGE_CACHE, NULL);
224         page_cache->document = document;
225
226         n_pages = ev_document_get_n_pages (document);
227
228         build_height_to_page (page_cache);
229
230         if (!EV_IS_DOCUMENT_THUMBNAILS (document)) {
231                 if (n_pages > 0)
232                         ev_page_cache_set_current_page (page_cache, 0);
233                 return page_cache;
234         }
235
236         /* Assume all pages are the same size until proven otherwise */
237         page_cache->thumbs_uniform = TRUE;
238
239         for (i = 0; i < n_pages; i++) {
240                 EvPage *page;
241                 gdouble page_width, page_height;
242                 gint    thumb_width = 0;
243                 gint    thumb_height = 0;
244
245                 page = ev_document_get_page (document, i);
246
247                 ev_document_get_page_size (document, i, &page_width, &page_height);
248
249                 if (!rc) {
250                         rc = ev_render_context_new (page, 0, (gdouble)THUMBNAIL_WIDTH / page_width);
251                 } else {
252                         ev_render_context_set_page (rc, page);
253                         ev_render_context_set_scale (rc, (gdouble)THUMBNAIL_WIDTH / page_width);
254                 }
255
256                 ev_document_thumbnails_get_dimensions (EV_DOCUMENT_THUMBNAILS (document),
257                                                        rc, &thumb_width, &thumb_height);
258
259                 if (thumb_width > page_cache->thumbs_max_width) {
260                         page_cache->thumbs_max_width = thumb_width;
261                 }
262
263                 if (thumb_height > page_cache->thumbs_max_height) {
264                         page_cache->thumbs_max_height = thumb_height;
265                 }
266
267                 if (i == 0) {
268                         page_cache->thumbs_uniform_width = thumb_width;
269                         page_cache->thumbs_uniform_height = thumb_height;
270                 } else if (page_cache->thumbs_uniform &&
271                            (page_cache->thumbs_uniform_width != thumb_width ||
272                             page_cache->thumbs_uniform_height != thumb_height)) {
273                         /* It's a different thumbnail size.  Backfill the array. */
274                         int j;
275
276                         page_cache->thumbs_size_cache = g_new0 (EvPageThumbsInfo, n_pages);
277
278                         for (j = 0; j < i; j++) {
279                                 thumb_info = &(page_cache->thumbs_size_cache[j]);
280                                 thumb_info->width = page_cache->thumbs_uniform_width;
281                                 thumb_info->height = page_cache->thumbs_uniform_height;
282                         }
283                         page_cache->thumbs_uniform = FALSE;
284                 }
285
286                 if (! page_cache->thumbs_uniform) {
287                         thumb_info = &(page_cache->thumbs_size_cache[i]);
288
289                         thumb_info->width = thumb_width;
290                         thumb_info->height = thumb_height;
291                 }
292
293                 g_object_unref (page);
294         }
295
296         if (rc) {
297                 g_object_unref (rc);
298         }
299
300         if (n_pages > 0)
301                 ev_page_cache_set_current_page (page_cache, 0);
302
303         return page_cache;
304 }
305
306 gboolean
307 ev_page_cache_check_dimensions (EvPageCache *page_cache)
308 {
309         gdouble document_width, document_height;
310
311         ev_document_get_max_page_size (page_cache->document,
312                                        &document_width, &document_height);
313
314         return (document_width > 0 && document_height > 0);
315 }
316
317 gint
318 ev_page_cache_get_current_page (EvPageCache *page_cache)
319 {
320         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0);
321
322         return page_cache->current_page;
323 }
324
325 void
326 ev_page_cache_set_current_page (EvPageCache *page_cache,
327                                 int          page)
328 {
329         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
330
331         if (page == page_cache->current_page)
332                 return;
333
334         page_cache->current_page = page;
335         g_signal_emit (page_cache, signals[PAGE_CHANGED], 0, page);
336 }
337
338 void
339 ev_page_cache_set_current_page_history (EvPageCache *page_cache,
340                                         int          page)
341 {
342         if (abs (page - page_cache->current_page) > 1)
343                 g_signal_emit (page_cache, signals [HISTORY_CHANGED], 0, page);
344         
345         ev_page_cache_set_current_page (page_cache, page);
346 }
347
348 gboolean
349 ev_page_cache_set_page_label (EvPageCache *page_cache,
350                               const gchar *page_label)
351 {
352         gint page;
353
354         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE);
355
356         if (ev_document_find_page_by_label (page_cache->document, page_label, &page)) {
357                 ev_page_cache_set_current_page (page_cache, page);
358                 return TRUE;
359         }
360
361         return FALSE;
362 }
363
364 void
365 ev_page_cache_get_size (EvPageCache  *page_cache,
366                         gint          page,
367                         gint          rotation,
368                         gfloat        scale,
369                         gint         *width,
370                         gint         *height)
371 {
372         double w, h;
373
374         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
375
376         ev_document_get_page_size (page_cache->document, page, &w, &h);
377
378         w = w * scale + 0.5;
379         h = h * scale + 0.5;
380
381         if (rotation == 0 || rotation == 180) {
382                 if (width) *width = (int)w;
383                 if (height) *height = (int)h;
384         } else {
385                 if (width) *width = (int)h;
386                 if (height) *height = (int)w;
387         }
388 }
389
390 void
391 ev_page_cache_get_max_width (EvPageCache   *page_cache,
392                              gint           rotation,
393                              gfloat         scale,
394                              gint          *width)
395 {
396         double w, h;
397
398         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
399
400         if (!width)
401                 return;
402
403         ev_document_get_max_page_size (page_cache->document, &w, &h);
404         *width = (rotation == 0 || rotation == 180) ? w * scale : h * scale;
405 }
406
407 void
408 ev_page_cache_get_max_height (EvPageCache   *page_cache,
409                               gint           rotation,
410                               gfloat         scale,
411                               gint          *height)
412 {
413         double w, h;
414
415         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
416
417         if (!height)
418                 return;
419
420         ev_document_get_max_page_size (page_cache->document, &w, &h);
421         *height = (rotation == 0 || rotation == 180) ? h * scale : w * scale;
422 }
423
424 void
425 ev_page_cache_get_height_to_page (EvPageCache   *page_cache,
426                                   gint           page,
427                                   gint           rotation,
428                                   gfloat         scale,
429                                   gint          *height,
430                                   gint          *dual_height)
431 {
432         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
433         g_return_if_fail (page >= 0);
434
435         if (page_cache->rotation != rotation) {
436                 page_cache->rotation = rotation;
437                 build_height_to_page (page_cache);
438         }
439
440         if (height)
441                 *height = page_cache->height_to_page[page] * scale;
442
443         if (dual_height)
444                 *dual_height = page_cache->dual_height_to_page[page] * scale;
445 }
446
447 void
448 ev_page_cache_get_thumbnail_size (EvPageCache  *page_cache,
449                                   gint          page,
450                                   gint          rotation,
451                                   gint         *width,
452                                   gint         *height)
453 {
454         gint w, h;
455
456         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
457
458         if (page_cache->thumbs_uniform) {
459                 w = page_cache->thumbs_uniform_width;
460                 h = page_cache->thumbs_uniform_height;
461         } else {
462                 EvPageThumbsInfo *info;
463
464                 info = &(page_cache->thumbs_size_cache [page]);
465                 
466                 w = info->width;
467                 h = info->height;
468         }
469
470         if (rotation == 0 || rotation == 180) {
471                 if (width) *width = w;
472                 if (height) *height = h;
473         } else {
474                 if (width) *width = h;
475                 if (height) *height = w;
476         }
477 }
478
479 gboolean
480 ev_page_cache_get_dual_even_left (EvPageCache *page_cache)
481 {
482         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0);
483
484         return (ev_document_get_n_pages (page_cache->document) > 2);
485 }
486
487 #define PAGE_CACHE_STRING "ev-page-cache"
488
489 EvPageCache *
490 ev_page_cache_get (EvDocument *document)
491 {
492         EvPageCache *page_cache;
493
494         g_return_val_if_fail (EV_IS_DOCUMENT (document), NULL);
495
496         page_cache = g_object_get_data (G_OBJECT (document), PAGE_CACHE_STRING);
497         if (page_cache == NULL) {
498                 page_cache = ev_page_cache_new (document);
499                 g_object_set_data_full (G_OBJECT (document), PAGE_CACHE_STRING, page_cache, g_object_unref);
500         }
501
502         return page_cache;
503 }