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