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