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