]> www.fi.muni.cz Git - evince.git/blob - backend/ev-page-cache.c
Add Continuous and Dual page modes.
[evince.git] / backend / 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         gboolean uniform;
24         double uniform_width;
25         double uniform_height;
26
27         double max_width_page_width;
28         double max_width_page_height;
29         double max_height_page_width;
30         double max_height_page_height;
31
32         EvPageCacheInfo *size_cache;
33 };
34
35 struct _EvPageCacheClass
36 {
37         GObjectClass parent_class;
38
39         void (* page_changed) (EvPageCache *page_cache, gint page);
40 };
41
42 enum
43 {
44         PAGE_CHANGED,
45         N_SIGNALS,
46 };
47
48 static guint signals[N_SIGNALS] = {0, };
49
50 static void ev_page_cache_init       (EvPageCache      *page_cache);
51 static void ev_page_cache_class_init (EvPageCacheClass *page_cache);
52 static void ev_page_cache_finalize   (GObject *object);
53
54 G_DEFINE_TYPE (EvPageCache, ev_page_cache, G_TYPE_OBJECT)
55
56 static void
57 ev_page_cache_init (EvPageCache *page_cache)
58 {
59         page_cache->current_page = -1;
60 }
61
62 static void
63 ev_page_cache_class_init (EvPageCacheClass *class)
64 {
65         GObjectClass *object_class;
66
67         object_class = G_OBJECT_CLASS (class);
68
69         object_class->finalize = ev_page_cache_finalize;
70
71         signals [PAGE_CHANGED] =
72                 g_signal_new ("page-changed",
73                               EV_TYPE_PAGE_CACHE,
74                               G_SIGNAL_RUN_LAST,
75                               G_STRUCT_OFFSET (EvPageCacheClass, page_changed),
76                               NULL, NULL,
77                               g_cclosure_marshal_VOID__INT,
78                               G_TYPE_NONE, 1,
79                               G_TYPE_INT);
80
81 }
82
83 static void
84 ev_page_cache_finalize (GObject *object)
85 {
86         EvPageCache *page_cache;
87
88         page_cache = EV_PAGE_CACHE (object);
89
90         g_free (page_cache->title);
91         g_free (page_cache->size_cache);
92 }
93
94 EvPageCache *
95 _ev_page_cache_new (EvDocument *document)
96 {
97         EvDocumentInfo *doc_info;
98         EvPageCache *page_cache;
99         EvPageCacheInfo *info;
100         gint i;
101
102         page_cache = (EvPageCache *) g_object_new (EV_TYPE_PAGE_CACHE, NULL);
103
104         ev_document_doc_mutex_lock ();
105
106         /* We read page information out of the document */
107
108         /* Assume all pages are the same size until proven otherwise */
109         page_cache->uniform = TRUE;
110         page_cache->n_pages = ev_document_get_n_pages (document);
111         page_cache->page_labels = g_new0 (char *, page_cache->n_pages);
112         page_cache->max_width_page_width = 0;
113         page_cache->max_width_page_height = 0;
114         page_cache->max_height_page_width = 0;
115         page_cache->max_height_page_height = 0;
116
117         doc_info = ev_document_get_info (document);
118         if (doc_info->fields_mask & EV_DOCUMENT_INFO_TITLE) {
119                 page_cache->title = g_strdup (doc_info->title);
120         } else {
121                 page_cache->title = NULL;
122         }
123         g_free (doc_info);
124
125         for (i = 0; i < page_cache->n_pages; i++) {
126                 double page_width = 0;
127                 double page_height = 0;
128
129                 ev_document_get_page_size (document, i, &page_width, &page_height);
130                 page_cache->page_labels[i] = ev_document_get_page_label (document, i);
131
132                 if (page_width > page_cache->max_width_page_width) {
133                         page_cache->max_width_page_width = page_width;
134                         page_cache->max_width_page_height = page_height;
135                 }
136
137                 if (page_height > page_cache->max_height_page_height) {
138                         page_cache->max_height_page_width = page_width;
139                         page_cache->max_height_page_height = page_height;
140                 }
141
142                 if (i == 0) {
143                         page_cache->uniform_width = page_width;
144                         page_cache->uniform_height = page_height;
145                 } else if (page_cache->uniform &&
146                            (page_cache->uniform_width != page_width ||
147                             page_cache->uniform_height != page_height)) {
148                         /* It's a different page size.  Backfill the array. */
149                         int j;
150
151                         page_cache->size_cache = g_new0 (EvPageCacheInfo, page_cache->n_pages);
152
153                         for (j = 0; j < i; j++) {
154                                 info = &(page_cache->size_cache [j]);
155                                 info->width = page_cache->uniform_width;
156                                 info->height = page_cache->uniform_height;
157                         }
158                         page_cache->uniform = FALSE;
159
160                 }
161
162                 if (! page_cache->uniform) {
163                         info = &(page_cache->size_cache [i]);
164
165                         info->width = page_width;
166                         info->height = page_height;
167                 }
168         }
169
170         /* make some sanity check assertions */
171         if (! page_cache->uniform)
172                 g_assert (page_cache->size_cache != NULL);
173         if (page_cache->uniform)
174                 g_assert (page_cache->uniform_width > 0 && page_cache->uniform_height > 0);
175
176         ev_document_doc_mutex_unlock ();
177
178         if (page_cache->n_pages > 0)
179                 ev_page_cache_set_current_page (page_cache, 0);
180
181         return page_cache;
182 }
183
184 gint
185 ev_page_cache_get_n_pages (EvPageCache *page_cache)
186 {
187         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0);
188
189         return page_cache->n_pages;
190 }
191
192 gint
193 ev_page_cache_get_current_page (EvPageCache *page_cache)
194 {
195         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0);
196
197         return page_cache->current_page;
198 }
199
200 void
201 ev_page_cache_set_current_page (EvPageCache *page_cache,
202                                 int          page)
203 {
204         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
205         g_return_if_fail (page >= 0 || page < page_cache->n_pages);
206
207         if (page == page_cache->current_page)
208                 return;
209
210         page_cache->current_page = page;
211         g_signal_emit (page_cache, signals[PAGE_CHANGED], 0, page);
212 }
213
214 gboolean
215 ev_page_cache_set_page_label (EvPageCache *page_cache,
216                               const char  *page_label)
217 {
218         gint i, page;
219         long value;
220         char *endptr = NULL;
221         
222         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE);
223         g_return_val_if_fail (page_label != NULL, FALSE);
224
225         /* First, look for a literal label match */
226         for (i = 0; i < page_cache->n_pages; i ++) {
227                 if (page_cache->page_labels[i] != NULL &&
228                     ! strcmp (page_label, page_cache->page_labels[i])) {
229                         ev_page_cache_set_current_page (page_cache, i);
230                         return TRUE;
231                 }
232         }
233
234         /* Next, parse the label, and see if the number fits */
235         value = strtol (page_label, &endptr, 10);
236         if (endptr[0] == '\0') {
237                 /* Page number is an integer */
238                 page = MIN (G_MAXINT, value);
239
240                 /* convert from a page label to a page offset */
241                 page --;
242                 if (page >= 0 &&
243                     page < page_cache->n_pages &&
244                     page_cache->page_labels[page] == NULL) {
245                         ev_page_cache_set_current_page (page_cache, page);
246                         return TRUE;
247                 }
248         }
249
250         return FALSE;
251 }
252
253 void
254 ev_page_cache_set_link (EvPageCache *page_cache,
255                         EvLink      *link)
256 {
257         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
258         g_return_if_fail (EV_IS_LINK (link));
259
260         ev_page_cache_set_current_page (page_cache, ev_link_get_page (link));
261 }
262
263 char *
264 ev_page_cache_get_title (EvPageCache *page_cache)
265 {
266         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), NULL);
267
268         return page_cache->title;
269 }
270
271 void
272 ev_page_cache_get_size (EvPageCache *page_cache,
273                         gint         page,
274                         gfloat       scale,
275                         gint        *width,
276                         gint        *height)
277 {
278         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
279         g_return_if_fail (page >= 0 && page < page_cache->n_pages);
280
281         if (page_cache->uniform) {
282                 if (width)
283                         *width = page_cache->uniform_width;
284                 if (height)
285                         *height = page_cache->uniform_height;
286         } else {
287                 EvPageCacheInfo *info;
288
289                 info = &(page_cache->size_cache [page]);
290                 
291                 if (width)
292                         *width = info->width;
293                 if (height)
294                         *height = info->height;
295         }
296
297         if (width)
298                 *width = (*width) * scale;
299         if (width)
300                 *height = (*height) * scale;
301
302 }
303
304
305 /* Note that these aren't necessarily from the same page.
306  */
307 void
308 ev_page_cache_get_max_width_size (EvPageCache *page_cache,
309                                   gfloat       scale,
310                                   gint        *width,
311                                   gint        *height)
312 {
313         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
314
315         if (width)
316                 *width = page_cache->max_width_page_width * scale;
317         if (height)
318                 *height = page_cache->max_width_page_height * scale;
319 }
320
321 void
322 ev_page_cache_get_max_height_size (EvPageCache *page_cache,
323                                    gfloat       scale,
324                                    gint        *width,
325                                    gint        *height)
326 {
327         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
328
329         if (width)
330                 *width = page_cache->max_height_page_width * scale;
331         if (height)
332                 *height = page_cache->max_height_page_height * scale;
333 }
334
335
336 gchar *
337 ev_page_cache_get_page_label (EvPageCache *page_cache,
338                               gint         page)
339 {
340         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), NULL);
341         g_return_val_if_fail (page >= 0 && page < page_cache->n_pages, NULL);
342
343         if (page_cache->page_labels[page] == NULL)
344                 return g_strdup_printf ("%d", page + 1);
345
346         return g_strdup (page_cache->page_labels[page]);
347 }
348
349
350 gboolean
351 ev_page_cache_next_page (EvPageCache *page_cache)
352 {
353         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE);
354
355         if (page_cache->current_page >= page_cache->n_pages - 1)
356                 return FALSE;
357
358         ev_page_cache_set_current_page (page_cache, page_cache->current_page + 1);
359         return TRUE;
360
361 }
362
363 gboolean
364 ev_page_cache_prev_page (EvPageCache *page_cache)
365 {
366         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE);
367
368         if (page_cache->current_page <= 0)
369                 return FALSE;
370
371         ev_page_cache_set_current_page (page_cache, page_cache->current_page - 1);
372         return TRUE;
373 }
374