]> www.fi.muni.cz Git - evince.git/blob - backend/djvu/djvu-document.c
daf09a5c5b0b2482408508e8cce155ba7c453e92
[evince.git] / backend / djvu / djvu-document.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /*
3  * Copyright (C) 2005, Nickolay V. Shmyrev <nshmyrev@yandex.ru>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include <config.h>
23 #include "djvu-document.h"
24 #include "djvu-text-page.h"
25 #include "djvu-links.h"
26 #include "djvu-document-private.h"
27 #include "ev-document-thumbnails.h"
28 #include "ev-file-exporter.h"
29 #include "ev-document-misc.h"
30 #include "ev-document-find.h"
31 #include "ev-document-links.h"
32 #include "ev-selection.h"
33 #include "ev-file-helpers.h"
34
35 #include <glib.h>
36 #include <gdk-pixbuf/gdk-pixbuf.h>
37 #include <glib/gi18n-lib.h>
38 #include <string.h>
39
40 #define SCALE_FACTOR 0.2
41
42 enum {
43         PROP_0,
44         PROP_TITLE
45 };
46
47 struct _DjvuDocumentClass
48 {
49         GObjectClass parent_class;
50 };
51
52 typedef struct _DjvuDocumentClass DjvuDocumentClass;
53
54 static void djvu_document_document_iface_init (EvDocumentIface *iface);
55 static void djvu_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface);
56 static void djvu_document_file_exporter_iface_init (EvFileExporterIface *iface);
57 static void djvu_document_find_iface_init (EvDocumentFindIface *iface);
58 static void djvu_document_document_links_iface_init  (EvDocumentLinksIface *iface);
59 static void djvu_selection_iface_init (EvSelectionIface *iface);
60
61 EV_BACKEND_REGISTER_WITH_CODE (DjvuDocument, djvu_document,
62     {
63       EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS, djvu_document_document_thumbnails_iface_init);
64       EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_FILE_EXPORTER, djvu_document_file_exporter_iface_init);
65       EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FIND, djvu_document_find_iface_init);
66       EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_LINKS, djvu_document_document_links_iface_init);
67       EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_SELECTION, djvu_selection_iface_init);
68      });
69
70
71 #define EV_DJVU_ERROR ev_djvu_error_quark ()
72
73 static GQuark
74 ev_djvu_error_quark (void)
75 {
76         static GQuark q = 0;
77         if (q == 0)
78                 q = g_quark_from_string ("ev-djvu-quark");
79         
80         return q;
81 }
82
83 static void
84 handle_message (const ddjvu_message_t *msg, GError **error)
85 {
86         switch (msg->m_any.tag) {
87                 case DDJVU_ERROR: {
88                         gchar *error_str;
89                         
90                         if (msg->m_error.filename) {
91                                 error_str = g_strdup_printf ("DjvuLibre error: %s:%d",
92                                                              msg->m_error.filename,
93                                                              msg->m_error.lineno);
94                         } else {
95                                 error_str = g_strdup_printf ("DjvuLibre error: %s",
96                                                              msg->m_error.message);
97                         }
98                         
99                         if (error) {
100                                 g_set_error_literal (error, EV_DJVU_ERROR, 0, error_str);
101                         } else {
102                                 g_warning ("%s", error_str);
103                         }
104                                 
105                         g_free (error_str);
106                         return;
107                         }                                                    
108                         break;
109                 default:
110                         break;
111         }
112 }
113
114 void
115 djvu_handle_events (DjvuDocument *djvu_document, int wait, GError **error)
116 {
117         ddjvu_context_t *ctx = djvu_document->d_context;
118         const ddjvu_message_t *msg;
119         
120         if (!ctx)
121                 return;
122
123         if (wait)
124                 ddjvu_message_wait (ctx);
125
126         while ((msg = ddjvu_message_peek (ctx))) {
127                 handle_message (msg, error);
128                 ddjvu_message_pop (ctx);
129                 if (error && *error)
130                         return;
131         }
132 }
133
134 static void
135 djvu_wait_for_message (DjvuDocument *djvu_document, ddjvu_message_tag_t message, GError **error)
136 {
137         ddjvu_context_t *ctx = djvu_document->d_context;
138         const ddjvu_message_t *msg;
139
140         ddjvu_message_wait (ctx);
141         while ((msg = ddjvu_message_peek (ctx)) && (msg->m_any.tag != message)) {
142                 handle_message (msg, error);
143                 ddjvu_message_pop (ctx);
144                 if (error && *error)
145                         return;
146         }
147         if (msg && msg->m_any.tag == message)
148                 ddjvu_message_pop (ctx);
149 }
150
151 static gboolean
152 djvu_document_load (EvDocument  *document,
153                     const char  *uri,
154                     GError     **error)
155 {
156         DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
157         ddjvu_document_t *doc;
158         gchar *filename;
159         gboolean missing_files = FALSE;
160         GError *djvu_error = NULL;
161
162         /* FIXME: We could actually load uris  */
163         filename = g_filename_from_uri (uri, NULL, error);
164         if (!filename)
165                 return FALSE;
166         
167         doc = ddjvu_document_create_by_filename (djvu_document->d_context, filename, TRUE);
168
169         if (!doc) {
170                 g_free (filename);
171                 g_set_error_literal (error,
172                                      EV_DOCUMENT_ERROR,
173                                      EV_DOCUMENT_ERROR_INVALID,
174                                      _("DJVU document has incorrect format"));
175                 return FALSE;
176         }
177
178         if (djvu_document->d_document)
179             ddjvu_document_release (djvu_document->d_document);
180
181         djvu_document->d_document = doc;
182
183         djvu_wait_for_message (djvu_document, DDJVU_DOCINFO, &djvu_error);
184         if (djvu_error) {
185                 g_set_error_literal (error,
186                                      EV_DOCUMENT_ERROR,
187                                      EV_DOCUMENT_ERROR_INVALID,
188                                      djvu_error->message);
189                 g_error_free (djvu_error);
190                 g_free (filename);
191                 ddjvu_document_release (djvu_document->d_document);
192                 djvu_document->d_document = NULL;
193
194                 return FALSE;
195         }
196
197         if (ddjvu_document_decoding_error (djvu_document->d_document))
198                 djvu_handle_events (djvu_document, TRUE, &djvu_error);
199
200         if (djvu_error) {
201                 g_set_error_literal (error,
202                                      EV_DOCUMENT_ERROR,
203                                      EV_DOCUMENT_ERROR_INVALID,
204                                      djvu_error->message);
205                 g_error_free (djvu_error);
206                 g_free (filename);
207                 ddjvu_document_release (djvu_document->d_document);
208                 djvu_document->d_document = NULL;
209                 
210                 return FALSE;
211         }
212         
213         g_free (djvu_document->uri);
214         djvu_document->uri = g_strdup (uri);
215
216         if (ddjvu_document_get_type (djvu_document->d_document) == DDJVU_DOCTYPE_INDIRECT) {
217                 gint n_files;
218                 gint i;
219                 gchar *base;
220
221                 base = g_path_get_dirname (filename);
222
223                 n_files = ddjvu_document_get_filenum (djvu_document->d_document);
224                 for (i = 0; i < n_files; i++) {
225                         struct ddjvu_fileinfo_s fileinfo;
226                         gchar *file;
227                         
228                         ddjvu_document_get_fileinfo (djvu_document->d_document,
229                                                      i, &fileinfo);
230
231                         if (fileinfo.type != 'P')
232                                 continue;
233
234                         file = g_build_filename (base, fileinfo.id, NULL);
235                         if (!g_file_test (file, G_FILE_TEST_EXISTS)) {
236                                 missing_files = TRUE;
237                                 g_free (file);
238                                 
239                                 break;
240                         }
241                         g_free (file);
242                 }
243                 g_free (base);
244         }
245         g_free (filename);
246
247         if (missing_files) {
248                 g_set_error_literal (error,
249                                      G_FILE_ERROR,
250                                      G_FILE_ERROR_EXIST,
251                                      _("The document is composed of several files. "
252                                        "One or more of such files cannot be accessed."));
253
254                 return FALSE;
255         }
256
257         return TRUE;
258 }
259
260
261 static gboolean
262 djvu_document_save (EvDocument  *document,
263                     const char  *uri,
264                     GError     **error)
265 {
266         DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
267
268         return ev_xfer_uri_simple (djvu_document->uri, uri, error);
269 }
270
271 int
272 djvu_document_get_n_pages (EvDocument  *document)
273 {
274         DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
275         
276         g_return_val_if_fail (djvu_document->d_document, 0);
277         
278         return ddjvu_document_get_pagenum (djvu_document->d_document);
279 }
280
281 static void
282 document_get_page_size (DjvuDocument *djvu_document,
283                         gint          page,
284                         double       *width,
285                         double       *height)
286 {
287         ddjvu_pageinfo_t info;
288         ddjvu_status_t r;
289         
290         while ((r = ddjvu_document_get_pageinfo(djvu_document->d_document, page, &info)) < DDJVU_JOB_OK)
291                 djvu_handle_events(djvu_document, TRUE, NULL);
292         
293         if (r >= DDJVU_JOB_FAILED)
294                 djvu_handle_events(djvu_document, TRUE, NULL);
295
296         *width = info.width * SCALE_FACTOR; 
297         *height = info.height * SCALE_FACTOR;
298 }
299
300 static void
301 djvu_document_get_page_size (EvDocument   *document,
302                              EvPage       *page,
303                              double       *width,
304                              double       *height)
305 {
306         DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
307
308         g_return_if_fail (djvu_document->d_document);
309
310         document_get_page_size (djvu_document, page->index,
311                                 width, height);
312 }
313
314 static cairo_surface_t *
315 djvu_document_render (EvDocument      *document, 
316                       EvRenderContext *rc)
317 {
318         DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
319         cairo_surface_t *surface;
320         gchar *pixels;
321         gint   rowstride;
322         ddjvu_rect_t rrect;
323         ddjvu_rect_t prect;
324         ddjvu_page_t *d_page;
325         ddjvu_page_rotation_t rotation;
326         double page_width, page_height, tmp;
327         static const cairo_user_data_key_t key;
328
329         d_page = ddjvu_page_create_by_pageno (djvu_document->d_document, rc->page->index);
330         
331         while (!ddjvu_page_decoding_done (d_page))
332                 djvu_handle_events(djvu_document, TRUE, NULL);
333
334         page_width = ddjvu_page_get_width (d_page) * rc->scale * SCALE_FACTOR + 0.5;
335         page_height = ddjvu_page_get_height (d_page) * rc->scale * SCALE_FACTOR + 0.5;
336         
337         switch (rc->rotation) {
338                 case 90:
339                         rotation = DDJVU_ROTATE_90;
340                         tmp = page_height;
341                         page_height = page_width;
342                         page_width = tmp;
343                         
344                         break;
345                 case 180:
346                         rotation = DDJVU_ROTATE_180;
347                         
348                         break;
349                 case 270:
350                         rotation = DDJVU_ROTATE_270;
351                         tmp = page_height;
352                         page_height = page_width;
353                         page_width = tmp;
354                         
355                         break;
356                 default:
357                         rotation = DDJVU_ROTATE_0;
358         }
359 #ifdef HAVE_CAIRO_FORMAT_STRIDE_FOR_WIDTH
360         rowstride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, page_width);
361 #else
362         rowstride = page_width * 4;
363 #endif
364         pixels = (gchar *) g_malloc (page_height * rowstride);
365         surface = cairo_image_surface_create_for_data ((guchar *)pixels,
366                                                        CAIRO_FORMAT_RGB24,
367                                                        page_width,
368                                                        page_height,
369                                                        rowstride);
370         cairo_surface_set_user_data (surface, &key,
371                                      pixels, (cairo_destroy_func_t)g_free);
372         prect.x = 0;
373         prect.y = 0;
374         prect.w = page_width;
375         prect.h = page_height;
376         rrect = prect;
377
378         ddjvu_page_set_rotation (d_page, rotation);
379         
380         ddjvu_page_render (d_page, DDJVU_RENDER_COLOR,
381                            &prect,
382                            &rrect,
383                            djvu_document->d_format,
384                            rowstride,
385                            pixels);
386
387         return surface;
388 }
389
390 static void
391 djvu_document_finalize (GObject *object)
392 {
393         DjvuDocument *djvu_document = DJVU_DOCUMENT (object);
394
395         if (djvu_document->d_document)
396             ddjvu_document_release (djvu_document->d_document);
397             
398         if (djvu_document->opts)
399             g_string_free (djvu_document->opts, TRUE);
400
401         if (djvu_document->ps_filename)
402             g_free (djvu_document->ps_filename);
403             
404         ddjvu_context_release (djvu_document->d_context);
405         ddjvu_format_release (djvu_document->d_format);
406         ddjvu_format_release (djvu_document->thumbs_format);
407         g_free (djvu_document->uri);
408         
409         G_OBJECT_CLASS (djvu_document_parent_class)->finalize (object);
410 }
411
412 static void
413 djvu_document_class_init (DjvuDocumentClass *klass)
414 {
415         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
416
417         gobject_class->finalize = djvu_document_finalize;
418 }
419
420 static EvDocumentInfo *
421 djvu_document_get_info (EvDocument *document)
422 {
423         EvDocumentInfo *info;
424
425         info = g_new0 (EvDocumentInfo, 1);
426
427         return info;
428 }
429
430 static void
431 djvu_document_document_iface_init (EvDocumentIface *iface)
432 {
433         iface->load = djvu_document_load;
434         iface->save = djvu_document_save;
435         iface->get_n_pages = djvu_document_get_n_pages;
436         iface->get_page_size = djvu_document_get_page_size;
437         iface->render = djvu_document_render;
438         iface->get_info = djvu_document_get_info;
439 }
440
441 static gchar *
442 djvu_text_copy (DjvuDocument *djvu_document,
443                 gint           page,
444                 EvRectangle  *rectangle)
445 {
446         miniexp_t page_text;
447         gchar    *text = NULL;
448
449         while ((page_text =
450                 ddjvu_document_get_pagetext (djvu_document->d_document,
451                                              page, "char")) == miniexp_dummy)
452                 djvu_handle_events (djvu_document, TRUE, NULL);
453
454         if (page_text != miniexp_nil) {
455                 DjvuTextPage *page = djvu_text_page_new (page_text);
456                 
457                 text = djvu_text_page_copy (page, rectangle);
458                 djvu_text_page_free (page);
459                 ddjvu_miniexp_release (djvu_document->d_document, page_text);
460         }
461
462         return text;
463 }
464
465 static gchar *
466 djvu_selection_get_selected_text (EvSelection     *selection,
467                                   EvRenderContext *rc,
468                                   EvSelectionStyle style,
469                                   EvRectangle     *points)
470 {
471         DjvuDocument *djvu_document = DJVU_DOCUMENT (selection);
472         double width, height;
473         EvRectangle rectangle;
474         gchar *text;
475              
476         djvu_document_get_page_size (EV_DOCUMENT (djvu_document),
477                                      rc->page, &width, &height);                
478         rectangle.x1 = points->x1 / SCALE_FACTOR;
479         rectangle.y1 = (height - points->y2) / SCALE_FACTOR;
480         rectangle.x2 = points->x2 / SCALE_FACTOR;
481         rectangle.y2 = (height - points->y1) / SCALE_FACTOR;
482                 
483         text = djvu_text_copy (djvu_document, rc->page->index, &rectangle);
484       
485         if (text == NULL)
486                 text = g_strdup ("");
487                 
488         return text;
489 }
490
491 static void
492 djvu_selection_iface_init (EvSelectionIface *iface)
493 {
494         iface->get_selected_text = djvu_selection_get_selected_text;
495 }
496
497 static void
498 djvu_document_thumbnails_get_dimensions (EvDocumentThumbnails *document,
499                                          EvRenderContext      *rc, 
500                                          gint                 *width,
501                                          gint                 *height)
502 {
503         DjvuDocument *djvu_document = DJVU_DOCUMENT (document); 
504         gdouble page_width, page_height;
505         
506         djvu_document_get_page_size (EV_DOCUMENT(djvu_document), rc->page,
507                                      &page_width, &page_height);
508
509         if (rc->rotation == 90 || rc->rotation == 270) {
510                 *width = (gint) (page_height * rc->scale);
511                 *height = (gint) (page_width * rc->scale);
512         } else {
513                 *width = (gint) (page_width * rc->scale);
514                 *height = (gint) (page_height * rc->scale);
515         }
516 }
517
518 static GdkPixbuf *
519 djvu_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
520                                         EvRenderContext      *rc,
521                                         gboolean              border)
522 {
523         DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
524         GdkPixbuf *pixbuf, *rotated_pixbuf;
525         gdouble page_width, page_height;
526         gint thumb_width, thumb_height;
527         guchar *pixels;
528         
529         g_return_val_if_fail (djvu_document->d_document, NULL);
530
531         djvu_document_get_page_size (EV_DOCUMENT(djvu_document), rc->page,
532                                      &page_width, &page_height);
533         
534         thumb_width = (gint) (page_width * rc->scale);
535         thumb_height = (gint) (page_height * rc->scale);
536
537         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
538                                  thumb_width, thumb_height);
539         gdk_pixbuf_fill (pixbuf, 0xffffffff);
540         pixels = gdk_pixbuf_get_pixels (pixbuf);
541         
542         while (ddjvu_thumbnail_status (djvu_document->d_document, rc->page->index, 1) < DDJVU_JOB_OK)
543                 djvu_handle_events(djvu_document, TRUE, NULL);
544                     
545         ddjvu_thumbnail_render (djvu_document->d_document, rc->page->index, 
546                                 &thumb_width, &thumb_height,
547                                 djvu_document->thumbs_format,
548                                 gdk_pixbuf_get_rowstride (pixbuf), 
549                                 (gchar *)pixels);
550
551         rotated_pixbuf = gdk_pixbuf_rotate_simple (pixbuf, 360 - rc->rotation);
552         g_object_unref (pixbuf);
553
554         if (border) {
555               GdkPixbuf *tmp_pixbuf = rotated_pixbuf;
556               
557               rotated_pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf);
558               g_object_unref (tmp_pixbuf);
559         }
560         
561         return rotated_pixbuf;
562 }
563
564 static void
565 djvu_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
566 {
567         iface->get_thumbnail = djvu_document_thumbnails_get_thumbnail;
568         iface->get_dimensions = djvu_document_thumbnails_get_dimensions;
569 }
570
571 /* EvFileExporterIface */
572 static void
573 djvu_document_file_exporter_begin (EvFileExporter        *exporter,
574                                    EvFileExporterContext *fc)
575 {
576         DjvuDocument *djvu_document = DJVU_DOCUMENT (exporter);
577         
578         if (djvu_document->ps_filename)
579                 g_free (djvu_document->ps_filename);    
580         djvu_document->ps_filename = g_strdup (fc->filename);
581
582         g_string_assign (djvu_document->opts, "-page=");
583 }
584
585 static void
586 djvu_document_file_exporter_do_page (EvFileExporter  *exporter,
587                                      EvRenderContext *rc)
588 {
589         DjvuDocument *djvu_document = DJVU_DOCUMENT (exporter);
590         
591         g_string_append_printf (djvu_document->opts, "%d,", (rc->page->index) + 1); 
592 }
593
594 static void
595 djvu_document_file_exporter_end (EvFileExporter *exporter)
596 {
597         int d_optc = 1; 
598         const char *d_optv[d_optc];
599
600         DjvuDocument *djvu_document = DJVU_DOCUMENT (exporter);
601
602         FILE *fn = fopen (djvu_document->ps_filename, "w");
603         if (fn == NULL) {
604                 g_warning ("Cannot open file ā€œ%sā€.", djvu_document->ps_filename);
605                 return;
606         }
607         
608         d_optv[0] = djvu_document->opts->str; 
609
610         ddjvu_job_t * job = ddjvu_document_print(djvu_document->d_document, fn, d_optc, d_optv);
611         while (!ddjvu_job_done(job)) {  
612                 djvu_handle_events (djvu_document, TRUE, NULL);
613         }
614
615         fclose(fn); 
616 }
617
618 static EvFileExporterCapabilities
619 djvu_document_file_exporter_get_capabilities (EvFileExporter *exporter)
620 {
621         return  EV_FILE_EXPORTER_CAN_PAGE_SET |
622                 EV_FILE_EXPORTER_CAN_COPIES |
623                 EV_FILE_EXPORTER_CAN_COLLATE |
624                 EV_FILE_EXPORTER_CAN_REVERSE |
625                 EV_FILE_EXPORTER_CAN_GENERATE_PS;
626 }
627
628 static void
629 djvu_document_file_exporter_iface_init (EvFileExporterIface *iface)
630 {
631         iface->begin = djvu_document_file_exporter_begin;
632         iface->do_page = djvu_document_file_exporter_do_page;
633         iface->end = djvu_document_file_exporter_end;
634         iface->get_capabilities = djvu_document_file_exporter_get_capabilities;
635 }
636
637 static void
638 djvu_document_init (DjvuDocument *djvu_document)
639 {
640         guint masks[4] = { 0xff0000, 0xff00, 0xff, 0xff000000 };
641         
642         djvu_document->d_context = ddjvu_context_create ("Evince");
643         djvu_document->d_format = ddjvu_format_create (DDJVU_FORMAT_RGBMASK32, 4, masks);
644         ddjvu_format_set_row_order (djvu_document->d_format, 1);
645
646         djvu_document->thumbs_format = ddjvu_format_create (DDJVU_FORMAT_RGB24, 0, 0);
647         ddjvu_format_set_row_order (djvu_document->thumbs_format, 1);
648
649         djvu_document->ps_filename = NULL;
650         djvu_document->opts = g_string_new ("");
651         
652         djvu_document->d_document = NULL;
653 }
654
655 static GList *
656 djvu_document_find_find_text (EvDocumentFind   *document,
657                               EvPage           *page,
658                               const char       *text,
659                               gboolean          case_sensitive)
660 {
661         DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
662         miniexp_t page_text;
663         gdouble width, height;
664         GList *matches = NULL, *l;
665
666         g_return_val_if_fail (text != NULL, NULL);
667
668         while ((page_text = ddjvu_document_get_pagetext (djvu_document->d_document,
669                                                          page->index,
670                                                          "char")) == miniexp_dummy)
671                 djvu_handle_events (djvu_document, TRUE, NULL);
672
673         if (page_text != miniexp_nil) {
674                 DjvuTextPage *tpage = djvu_text_page_new (page_text);
675                 
676                 djvu_text_page_prepare_search (tpage, case_sensitive);
677                 if (tpage->links->len > 0) {
678                         djvu_text_page_search (tpage, text);
679                         matches = tpage->results;
680                 }
681                 djvu_text_page_free (tpage);
682                 ddjvu_miniexp_release (djvu_document->d_document, page_text);
683         }
684
685         if (!matches)
686                 return NULL;
687
688         document_get_page_size (djvu_document, page->index, &width, &height);
689         for (l = matches; l && l->data; l = g_list_next (l)) {
690                 EvRectangle *r = (EvRectangle *)l->data;
691                 gdouble      tmp;
692
693                 tmp = r->y1;
694                 
695                 r->x1 *= SCALE_FACTOR;
696                 r->x2 *= SCALE_FACTOR;
697
698                 tmp = r->y1;
699                 r->y1 = height - r->y2 * SCALE_FACTOR;
700                 r->y2 = height - tmp * SCALE_FACTOR;
701         }
702         
703
704         return matches;
705 }
706
707 static void
708 djvu_document_find_iface_init (EvDocumentFindIface *iface)
709 {
710         iface->find_text = djvu_document_find_find_text;
711 }
712
713 static GList *
714 djvu_document_links_get_links (EvDocumentLinks *document_links,
715                                gint             page)
716 {
717         return djvu_links_get_links (document_links, page, SCALE_FACTOR);
718 }
719
720 static void
721 djvu_document_document_links_iface_init  (EvDocumentLinksIface *iface)
722 {
723         iface->has_document_links = djvu_links_has_document_links;
724         iface->get_links_model = djvu_links_get_links_model;
725         iface->get_links = djvu_document_links_get_links;
726         iface->find_link_dest = djvu_links_find_link_dest;
727 }