]> www.fi.muni.cz Git - evince.git/blob - backend/ev-page-cache.c
08d1be459029c4414cc8e1879b703d7560328b44
[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         gint width;
9         gint 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         gint uniform_width;
25         gint 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 = 0;
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         EvPageCache *page_cache;
93         EvPageCacheInfo *info;
94         gint i;
95
96         page_cache = (EvPageCache *) g_object_new (EV_TYPE_PAGE_CACHE, NULL);
97
98         g_mutex_lock (EV_DOC_MUTEX);
99
100         /* We read page information out of the document */
101
102         /* Assume all pages are the same size until proven otherwise */
103         page_cache->uniform = TRUE;
104         page_cache->n_pages = ev_document_get_n_pages (document);
105         page_cache->title = ev_document_get_title (document);
106         page_cache->page_labels = g_new0 (char *, page_cache->n_pages);
107
108         ev_document_set_scale (document, 1.0);
109         for (i = 0; i < page_cache->n_pages; i++) {
110                 gint page_width = 0;
111                 gint page_height = 0;
112
113                 ev_document_get_page_size (document, i, &page_width, &page_height);
114                 page_cache->page_labels[i] = ev_document_get_page_label (document, i);
115
116                 if (i == 0) {
117                         page_cache->uniform_width = page_width;
118                         page_cache->uniform_height = page_height;
119                 } else if (page_cache->uniform &&
120                            (page_cache->uniform_width != page_width ||
121                             page_cache->uniform_height != page_height)) {
122                         /* It's a different page size.  Backfill the array. */
123                         int j;
124
125                         page_cache->size_cache = g_new0 (EvPageCacheInfo, page_cache->n_pages);
126
127                         for (j = 1; j < i; j++) {
128                                 info = &(page_cache->size_cache [j - 1]);
129                                 info->width = page_width;
130                                 info->height = page_height;
131                         }
132                         page_cache->uniform = FALSE;
133
134                 }
135
136                 if (! page_cache->uniform) {
137                         info = &(page_cache->size_cache [i - 1]);
138
139                         info->width = page_width;
140                         info->height = page_height;
141                 }
142         }
143
144         /* make some sanity check assertions */
145         g_assert (page_cache->n_pages > 0);
146         if (! page_cache->uniform)
147                 g_assert (page_cache->size_cache != NULL);
148         if (page_cache->uniform)
149                 g_assert (page_cache->uniform_width > 0 && page_cache->uniform_height > 0);
150
151         g_mutex_unlock (EV_DOC_MUTEX);
152
153         return page_cache;
154 }
155
156 gint
157 ev_page_cache_get_n_pages (EvPageCache *page_cache)
158 {
159         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0);
160
161         return page_cache->n_pages;
162 }
163
164 gint
165 ev_page_cache_get_current_page (EvPageCache *page_cache)
166 {
167         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0);
168
169         return page_cache->current_page;
170 }
171
172 void
173 ev_page_cache_set_current_page (EvPageCache *page_cache,
174                                 int          page)
175 {
176         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
177         g_return_if_fail (page >= 0 || page < page_cache->n_pages);
178
179         if (page == page_cache->current_page)
180                 return;
181
182         page_cache->current_page = page;
183         g_signal_emit (page_cache, signals[PAGE_CHANGED], 0, page);
184 }
185
186 gboolean
187 ev_page_cache_set_page_label (EvPageCache *page_cache,
188                               const char  *page_label)
189 {
190         gint i, page;
191         long value;
192         char *endptr = NULL;
193         
194         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE);
195         g_return_val_if_fail (page_label != NULL, FALSE);
196
197         /* First, look for a literal label match */
198         for (i = 0; i < page_cache->n_pages; i ++) {
199                 if (page_cache->page_labels[i] != NULL &&
200                     ! strcmp (page_label, page_cache->page_labels[i])) {
201                         ev_page_cache_set_current_page (page_cache, i);
202                         return TRUE;
203                 }
204         }
205
206         /* Next, parse the label, and see if the number fits */
207         value = strtol (page_label, &endptr, 10);
208         if (endptr[0] == '\0') {
209                 /* Page number is an integer */
210                 page = MIN (G_MAXINT, value);
211
212                 /* convert from a page label to a page offset */
213                 page --;
214                 if (page >= 0 &&
215                     page < page_cache->n_pages &&
216                     page_cache->page_labels[page] == NULL) {
217                         ev_page_cache_set_current_page (page_cache, page);
218                         return TRUE;
219                 }
220         }
221
222         return FALSE;
223 }
224
225 void
226 ev_page_cache_set_link (EvPageCache *page_cache,
227                         EvLink      *link)
228 {
229         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
230         g_return_if_fail (EV_IS_LINK (link));
231
232         ev_page_cache_set_current_page (page_cache, ev_link_get_page (link));
233 }
234
235 char *
236 ev_page_cache_get_title (EvPageCache *page_cache)
237 {
238         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), NULL);
239
240         return page_cache->title;
241 }
242
243 void
244 ev_page_cache_get_size (EvPageCache *page_cache,
245                         gint         page,
246                         gfloat       scale,
247                         gint        *width,
248                         gint        *height)
249 {
250         g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
251         g_return_if_fail (page >= 0 && page < page_cache->n_pages);
252
253         if (page_cache->uniform) {
254                 if (width)
255                         *width = page_cache->uniform_width;
256                 if (height)
257                         *height = page_cache->uniform_height;
258         } else {
259                 EvPageCacheInfo *info;
260
261                 info = &(page_cache->size_cache [page]);
262                 
263                 if (width)
264                         *width = info->width;
265                 if (height)
266                         *height = info->height;
267         }
268
269         if (width)
270                 *width = (*width) * scale;
271         if (width)
272                 *height = (*height) * scale;
273
274 }
275 gchar *
276 ev_page_cache_get_page_label (EvPageCache *page_cache,
277                               gint         page)
278 {
279         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), NULL);
280         g_return_val_if_fail (page >= 0 && page < page_cache->n_pages, NULL);
281
282         if (page_cache->page_labels[page] == NULL)
283                 return g_strdup_printf ("%d", page + 1);
284
285         return g_strdup (page_cache->page_labels[page]);
286 }
287
288
289 gboolean
290 ev_page_cache_next_page (EvPageCache *page_cache)
291 {
292         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE);
293
294         if (page_cache->current_page > page_cache->n_pages)
295                 return FALSE;
296
297         ev_page_cache_set_current_page (page_cache, page_cache->current_page + 1);
298         return TRUE;
299
300 }
301
302 gboolean
303 ev_page_cache_prev_page (EvPageCache *page_cache)
304 {
305         g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE);
306
307         if (page_cache->current_page <= 0)
308                 return FALSE;
309
310         ev_page_cache_set_current_page (page_cache, page_cache->current_page - 1);
311         return TRUE;
312 }
313