]> www.fi.muni.cz Git - evince.git/blob - libview/ev-page-cache.c
231af3b146acf171ecc442375a44b669eba218d7
[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 struct _EvPageCache
9 {
10         GObject parent;
11
12         EvDocument *document;
13
14         gint current_page;
15
16         gboolean dual_even_left;
17
18         double* height_to_page;
19         double* dual_height_to_page;
20
21         int rotation;
22 };
23
24 struct _EvPageCacheClass
25 {
26         GObjectClass parent_class;
27
28         void (* page_changed) (EvPageCache *page_cache, gint page);
29         void (* history_changed) (EvPageCache *page_cache, gint page);
30 };
31
32 enum
33 {
34         PAGE_CHANGED,
35         HISTORY_CHANGED,
36         N_SIGNALS,
37 };
38
39 static guint signals[N_SIGNALS] = {0, };
40
41 static void ev_page_cache_init       (EvPageCache      *page_cache);
42 static void ev_page_cache_class_init (EvPageCacheClass *page_cache);
43 static void ev_page_cache_finalize   (GObject *object);
44
45 G_DEFINE_TYPE (EvPageCache, ev_page_cache, G_TYPE_OBJECT)
46
47 static void
48 ev_page_cache_init (EvPageCache *page_cache)
49 {
50         page_cache->current_page = -1;
51 }
52
53 static void
54 ev_page_cache_class_init (EvPageCacheClass *class)
55 {
56         GObjectClass *object_class;
57
58         object_class = G_OBJECT_CLASS (class);
59
60         object_class->finalize = ev_page_cache_finalize;
61
62         signals [PAGE_CHANGED] =
63                 g_signal_new ("page-changed",
64                               EV_TYPE_PAGE_CACHE,
65                               G_SIGNAL_RUN_LAST,
66                               G_STRUCT_OFFSET (EvPageCacheClass, page_changed),
67                               NULL, NULL,
68                               g_cclosure_marshal_VOID__INT,
69                               G_TYPE_NONE, 1,
70                               G_TYPE_INT);
71
72         signals [HISTORY_CHANGED] =
73                 g_signal_new ("history-changed",
74                               EV_TYPE_PAGE_CACHE,
75                               G_SIGNAL_RUN_LAST,
76                               G_STRUCT_OFFSET (EvPageCacheClass, history_changed),
77                               NULL, NULL,
78                               g_cclosure_marshal_VOID__INT,
79                               G_TYPE_NONE, 1,
80                               G_TYPE_INT);
81
82 }
83
84 static void
85 ev_page_cache_finalize (GObject *object)
86 {
87         EvPageCache *page_cache = EV_PAGE_CACHE (object);
88
89         page_cache->document = NULL;
90
91         if (page_cache->height_to_page) {
92                 g_free (page_cache->height_to_page);
93                 page_cache->height_to_page = NULL;
94         }
95
96         if (page_cache->dual_height_to_page) {
97                 g_free (page_cache->dual_height_to_page);
98                 page_cache->dual_height_to_page = NULL;
99         }
100
101         G_OBJECT_CLASS (ev_page_cache_parent_class)->finalize (object);
102 }
103
104 static void
105 build_height_to_page (EvPageCache *page_cache)
106 {
107         gboolean swap, uniform, dual_even_left;
108         int i;
109         double uniform_height, page_height, next_page_height;
110         double saved_height;
111         gdouble u_width, u_height;
112         gint n_pages;
113
114         swap = (page_cache->rotation == 90 ||
115                 page_cache->rotation == 270);
116
117         uniform = ev_document_is_page_size_uniform (page_cache->document);
118         n_pages = ev_document_get_n_pages (page_cache->document);
119         dual_even_left = (n_pages > 2);
120
121         g_free (page_cache->height_to_page);
122         g_free (page_cache->dual_height_to_page);
123
124         page_cache->height_to_page = g_new0 (double, n_pages + 1);
125         page_cache->dual_height_to_page = g_new0 (double, n_pages + 2);
126
127         if (uniform)
128                 ev_document_get_page_size (page_cache->document, 0, &u_width, &u_height);
129
130         saved_height = 0;
131         for (i = 0; i <= n_pages; i++) {
132                 if (uniform) {
133                         uniform_height = swap ? u_width : u_height;
134                         page_cache->height_to_page[i] = i * uniform_height;
135                 } else {
136                         if (i < n_pages) {
137                                 gdouble w, h;
138
139                                 ev_document_get_page_size (page_cache->document, i, &w, &h);
140                                 page_height = swap ? w : h;
141                         } else {
142                                 page_height = 0;
143                         }
144                         page_cache->height_to_page[i] = saved_height;
145                         saved_height += page_height;
146                 }
147         }
148
149         if (dual_even_left && !uniform) {
150                 gdouble w, h;
151
152                 ev_document_get_page_size (page_cache->document, 0, &w, &h);
153                 saved_height = swap ? w : h;
154         } else {
155                 saved_height = 0;
156         }
157
158         for (i = dual_even_left; i < n_pages + 2; i += 2) {
159                 if (uniform) {
160                         uniform_height = swap ? u_width : u_height;
161                         page_cache->dual_height_to_page[i] = ((i + dual_even_left) / 2) * uniform_height;
162                         if (i + 1 < n_pages + 2)
163                                 page_cache->dual_height_to_page[i + 1] = ((i + dual_even_left) / 2) * uniform_height;
164                 } else {
165                         if (i + 1 < n_pages) {
166                                 gdouble w, h;
167
168                                 ev_document_get_page_size (page_cache->document, i + 1, &w, &h);
169                                 next_page_height = swap ? w : h;
170                         } else {
171                                 next_page_height = 0;
172                         }
173
174                         if (i < n_pages) {
175                                 gdouble w, h;
176
177                                 ev_document_get_page_size (page_cache->document, i, &w, &h);
178                                 page_height = swap ? w : h;
179                         } else {
180                                 page_height = 0;
181                         }
182
183                         if (i + 1 < n_pages + 2) {
184                                 page_cache->dual_height_to_page[i] = saved_height;
185                                 page_cache->dual_height_to_page[i + 1] = saved_height;
186                                 saved_height += MAX(page_height, next_page_height);
187                         } else {
188                                 page_cache->dual_height_to_page[i] = saved_height;
189                         }
190                 }
191         }
192 }
193
194 static EvPageCache *
195 ev_page_cache_new (EvDocument *document)
196 {
197         EvPageCache *page_cache;
198
199         page_cache = (EvPageCache *) g_object_new (EV_TYPE_PAGE_CACHE, NULL);
200         page_cache->document = document;
201
202         build_height_to_page (page_cache);
203
204         if (ev_document_get_n_pages (page_cache->document) > 0)
205                 ev_page_cache_set_current_page (page_cache, 0);
206
207         return page_cache;
208 }
209
210 gboolean
211 ev_page_cache_check_dimensions (EvPageCache *page_cache)
212 {
213         gdouble document_width, document_height;
214
215         ev_document_get_max_page_size (page_cache->document,
216                                        &document_width, &document_height);
217
218         return (document_width > 0 && document_height > 0);
219 }
220
221 gint
222 ev_page_cache_get_current_page (EvPageCache *page_cache)
223 {
224         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0);
225
226         return page_cache->current_page;
227 }
228
229 void
230 ev_page_cache_set_current_page (EvPageCache *page_cache,
231                                 int          page)
232 {
233         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
234
235         if (page == page_cache->current_page)
236                 return;
237
238         page_cache->current_page = page;
239         g_signal_emit (page_cache, signals[PAGE_CHANGED], 0, page);
240 }
241
242 void
243 ev_page_cache_set_current_page_history (EvPageCache *page_cache,
244                                         int          page)
245 {
246         if (abs (page - page_cache->current_page) > 1)
247                 g_signal_emit (page_cache, signals [HISTORY_CHANGED], 0, page);
248         
249         ev_page_cache_set_current_page (page_cache, page);
250 }
251
252 gboolean
253 ev_page_cache_set_page_label (EvPageCache *page_cache,
254                               const gchar *page_label)
255 {
256         gint page;
257
258         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE);
259
260         if (ev_document_find_page_by_label (page_cache->document, page_label, &page)) {
261                 ev_page_cache_set_current_page (page_cache, page);
262                 return TRUE;
263         }
264
265         return FALSE;
266 }
267
268 void
269 ev_page_cache_get_size (EvPageCache  *page_cache,
270                         gint          page,
271                         gint          rotation,
272                         gfloat        scale,
273                         gint         *width,
274                         gint         *height)
275 {
276         double w, h;
277
278         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
279
280         ev_document_get_page_size (page_cache->document, page, &w, &h);
281
282         w = w * scale + 0.5;
283         h = h * scale + 0.5;
284
285         if (rotation == 0 || rotation == 180) {
286                 if (width) *width = (int)w;
287                 if (height) *height = (int)h;
288         } else {
289                 if (width) *width = (int)h;
290                 if (height) *height = (int)w;
291         }
292 }
293
294 void
295 ev_page_cache_get_max_width (EvPageCache   *page_cache,
296                              gint           rotation,
297                              gfloat         scale,
298                              gint          *width)
299 {
300         double w, h;
301
302         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
303
304         if (!width)
305                 return;
306
307         ev_document_get_max_page_size (page_cache->document, &w, &h);
308         *width = (rotation == 0 || rotation == 180) ? w * scale : h * scale;
309 }
310
311 void
312 ev_page_cache_get_max_height (EvPageCache   *page_cache,
313                               gint           rotation,
314                               gfloat         scale,
315                               gint          *height)
316 {
317         double w, h;
318
319         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
320
321         if (!height)
322                 return;
323
324         ev_document_get_max_page_size (page_cache->document, &w, &h);
325         *height = (rotation == 0 || rotation == 180) ? h * scale : w * scale;
326 }
327
328 void
329 ev_page_cache_get_height_to_page (EvPageCache   *page_cache,
330                                   gint           page,
331                                   gint           rotation,
332                                   gfloat         scale,
333                                   gint          *height,
334                                   gint          *dual_height)
335 {
336         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
337         g_return_if_fail (page >= 0);
338
339         if (page_cache->rotation != rotation) {
340                 page_cache->rotation = rotation;
341                 build_height_to_page (page_cache);
342         }
343
344         if (height)
345                 *height = page_cache->height_to_page[page] * scale;
346
347         if (dual_height)
348                 *dual_height = page_cache->dual_height_to_page[page] * scale;
349 }
350
351 gboolean
352 ev_page_cache_get_dual_even_left (EvPageCache *page_cache)
353 {
354         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0);
355
356         return (ev_document_get_n_pages (page_cache->document) > 2);
357 }
358
359 #define PAGE_CACHE_STRING "ev-page-cache"
360
361 EvPageCache *
362 ev_page_cache_get (EvDocument *document)
363 {
364         EvPageCache *page_cache;
365
366         g_return_val_if_fail (EV_IS_DOCUMENT (document), NULL);
367
368         page_cache = g_object_get_data (G_OBJECT (document), PAGE_CACHE_STRING);
369         if (page_cache == NULL) {
370                 page_cache = ev_page_cache_new (document);
371                 g_object_set_data_full (G_OBJECT (document), PAGE_CACHE_STRING, page_cache, g_object_unref);
372         }
373
374         return page_cache;
375 }