]> www.fi.muni.cz Git - evince.git/blob - pdf/ev-poppler.cc
Add page transition support in presentation mode. At the moment only page
[evince.git] / pdf / ev-poppler.cc
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /* pdfdocument.h: Implementation of EvDocument for PDF
3  * Copyright (C) 2004, Red Hat, Inc.
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 <math.h>
23 #include <string.h>
24 #include <gtk/gtk.h>
25 #include <poppler.h>
26 #include <poppler-document.h>
27 #include <poppler-page.h>
28 #ifdef HAVE_CAIRO_PDF
29 #include <cairo-pdf.h>
30 #endif
31 #include <glib/gi18n.h>
32
33 #include "ev-poppler.h"
34 #include "ev-file-exporter.h"
35 #include "ev-document-find.h"
36 #include "ev-document-misc.h"
37 #include "ev-document-links.h"
38 #include "ev-document-fonts.h"
39 #include "ev-document-security.h"
40 #include "ev-document-thumbnails.h"
41 #include "ev-document-transition.h"
42 #include "ev-selection.h"
43 #include "ev-attachment.h"
44
45 typedef struct {
46         PdfDocument *document;
47         char *text;
48         GList **pages;
49         guint idle;
50         int start_page;
51         int search_page;
52 } PdfDocumentSearch;
53
54 typedef struct {
55         EvFileExporterFormat format;
56         PopplerPSFile *ps_file;
57 #ifdef HAVE_CAIRO_PDF
58         cairo_t *pdf_cairo;
59 #endif
60 } PdfPrintContext;
61
62 struct _PdfDocumentClass
63 {
64         GObjectClass parent_class;
65 };
66
67 struct _PdfDocument
68 {
69         GObject parent_instance;
70
71         PopplerDocument *document;
72         gchar *password;
73
74         PopplerFontInfo *font_info;
75         PopplerFontsIter *fonts_iter;
76         int fonts_scanned_pages;
77
78         PdfDocumentSearch *search;
79         PdfPrintContext *print_ctx;
80 };
81
82 static void pdf_document_document_iface_init            (EvDocumentIface           *iface);
83 static void pdf_document_security_iface_init            (EvDocumentSecurityIface   *iface);
84 static void pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface);
85 static void pdf_document_document_links_iface_init      (EvDocumentLinksIface      *iface);
86 static void pdf_document_document_fonts_iface_init      (EvDocumentFontsIface      *iface);
87 static void pdf_document_find_iface_init                (EvDocumentFindIface       *iface);
88 static void pdf_document_file_exporter_iface_init       (EvFileExporterIface       *iface);
89 static void pdf_selection_iface_init                    (EvSelectionIface          *iface);
90 static void pdf_document_page_transition_iface_init     (EvDocumentTransitionIface *iface);
91 static void pdf_document_thumbnails_get_dimensions      (EvDocumentThumbnails      *document_thumbnails,
92                                                          gint                       page,
93                                                          gint                       size,
94                                                          gint                      *width,
95                                                          gint                      *height);
96 static int  pdf_document_get_n_pages                    (EvDocument                *document);
97
98 static EvLinkDest *ev_link_dest_from_dest   (PdfDocument       *pdf_document,
99                                              PopplerDest       *dest);
100 static EvLink     *ev_link_from_action      (PdfDocument       *pdf_document,
101                                              PopplerAction     *action);
102 static void        pdf_document_search_free (PdfDocumentSearch *search);
103 static void        pdf_print_context_free   (PdfPrintContext   *ctx);
104
105
106 G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT,
107                          {
108                                  G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
109                                                         pdf_document_document_iface_init);
110                                  G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_SECURITY,
111                                                         pdf_document_security_iface_init);
112                                  G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
113                                                         pdf_document_document_thumbnails_iface_init);
114                                  G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_LINKS,
115                                                         pdf_document_document_links_iface_init);
116                                  G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FONTS,
117                                                         pdf_document_document_fonts_iface_init);
118                                  G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FIND,
119                                                         pdf_document_find_iface_init);
120                                  G_IMPLEMENT_INTERFACE (EV_TYPE_FILE_EXPORTER,
121                                                         pdf_document_file_exporter_iface_init);
122                                  G_IMPLEMENT_INTERFACE (EV_TYPE_SELECTION,
123                                                         pdf_selection_iface_init);
124                                  G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_TRANSITION,
125                                                         pdf_document_page_transition_iface_init);
126                          });
127
128
129 static void
130 set_rc_data (PdfDocument     *pdf_document,
131              EvRenderContext *rc)
132 {
133         if (rc->data == NULL) {
134                 rc->data = poppler_document_get_page (pdf_document->document,
135                                                       rc->page);
136                 rc->destroy = g_object_unref;
137         } else {
138                 g_assert (rc->page == poppler_page_get_index (POPPLER_PAGE (rc->data)));
139         }
140 }
141
142 static void
143 pdf_document_search_free (PdfDocumentSearch   *search)
144 {
145         PdfDocument *pdf_document = search->document;
146         int n_pages;
147         int i;
148
149         if (search->idle != 0)
150                 g_source_remove (search->idle);
151
152         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (pdf_document));
153         for (i = 0; i < n_pages; i++) {
154                 g_list_foreach (search->pages[i], (GFunc) g_free, NULL);
155                 g_list_free (search->pages[i]);
156         }
157         g_free (search->pages);
158         
159         g_free (search->text);
160         g_free (search);
161 }
162
163 static void
164 pdf_document_dispose (GObject *object)
165 {
166         PdfDocument *pdf_document = PDF_DOCUMENT(object);
167
168         if (pdf_document->print_ctx) {
169                 pdf_print_context_free (pdf_document->print_ctx);
170                 pdf_document->print_ctx = NULL;
171         }
172         
173         if (pdf_document->search) {
174                 pdf_document_search_free (pdf_document->search);
175                 pdf_document->search = NULL;
176         }
177
178         if (pdf_document->document) {
179                 g_object_unref (pdf_document->document);
180         }
181
182         if (pdf_document->font_info) { 
183                 poppler_font_info_free (pdf_document->font_info);
184         }
185
186         if (pdf_document->fonts_iter) {
187                 poppler_fonts_iter_free (pdf_document->fonts_iter);
188         }
189 }
190
191 static void
192 pdf_document_class_init (PdfDocumentClass *klass)
193 {
194         GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
195
196         g_object_class->dispose = pdf_document_dispose;
197 }
198
199 static void
200 pdf_document_init (PdfDocument *pdf_document)
201 {
202         pdf_document->password = NULL;
203 }
204
205 static void
206 convert_error (GError  *poppler_error,
207                GError **error)
208 {
209         if (poppler_error == NULL)
210                 return;
211
212         if (poppler_error->domain == POPPLER_ERROR) {
213                 /* convert poppler errors into EvDocument errors */
214                 gint code = EV_DOCUMENT_ERROR_INVALID;
215                 if (poppler_error->code == POPPLER_ERROR_INVALID)
216                         code = EV_DOCUMENT_ERROR_INVALID;
217                 else if (poppler_error->code == POPPLER_ERROR_ENCRYPTED)
218                         code = EV_DOCUMENT_ERROR_ENCRYPTED;
219                         
220
221                 g_set_error (error,
222                              EV_DOCUMENT_ERROR,
223                              code,
224                              poppler_error->message,
225                              NULL);
226         } else {
227                 g_propagate_error (error, poppler_error);
228         }
229 }
230
231
232 /* EvDocument */
233 static gboolean
234 pdf_document_save (EvDocument  *document,
235                    const char  *uri,
236                    GError     **error)
237 {
238         gboolean retval;
239         GError *poppler_error = NULL;
240
241         retval = poppler_document_save (PDF_DOCUMENT (document)->document,
242                                         uri,
243                                         &poppler_error);
244         if (! retval)
245                 convert_error (poppler_error, error);
246
247         return retval;
248 }
249
250 static gboolean
251 pdf_document_load (EvDocument   *document,
252                    const char   *uri,
253                    GError      **error)
254 {
255         GError *poppler_error = NULL;
256         PdfDocument *pdf_document = PDF_DOCUMENT (document);
257
258         pdf_document->document =
259                 poppler_document_new_from_file (uri, pdf_document->password, &poppler_error);
260
261         if (pdf_document->document == NULL) {
262                 convert_error (poppler_error, error);
263                 return FALSE;
264         }
265
266         return TRUE;
267 }
268
269 static int
270 pdf_document_get_n_pages (EvDocument *document)
271 {
272         return poppler_document_get_n_pages (PDF_DOCUMENT (document)->document);
273 }
274
275 static void
276 pdf_document_get_page_size (EvDocument   *document,
277                             int           page,
278                             double       *width,
279                             double       *height)
280 {
281         PdfDocument *pdf_document = PDF_DOCUMENT (document);
282         PopplerPage *poppler_page;
283
284         poppler_page = poppler_document_get_page (pdf_document->document, page);
285         poppler_page_get_size (poppler_page, width, height);
286         g_object_unref (poppler_page);
287 }
288
289 static char *
290 pdf_document_get_page_label (EvDocument *document,
291                              int         page)
292 {
293         PopplerPage *poppler_page;
294         char *label = NULL;
295
296         poppler_page = poppler_document_get_page (PDF_DOCUMENT (document)->document,
297                                                   page);
298
299         g_object_get (G_OBJECT (poppler_page),
300                       "label", &label,
301                       NULL);
302         g_object_unref (poppler_page);
303
304         return label;
305 }
306
307 static gboolean
308 pdf_document_has_attachments (EvDocument *document)
309 {
310         PdfDocument *pdf_document;
311
312         pdf_document = PDF_DOCUMENT (document);
313
314         return poppler_document_has_attachments (pdf_document->document);
315 }
316
317 struct SaveToBufferData {
318         gchar *buffer;
319         gsize len, max;
320 };
321
322 static gboolean
323 attachment_save_to_buffer_callback (const gchar  *buf,
324                                     gsize         count,
325                                     gpointer      user_data,
326                                     GError      **error)
327 {
328         struct SaveToBufferData *sdata = (SaveToBufferData *)user_data;
329         gchar *new_buffer;
330         gsize new_max;
331
332         if (sdata->len + count > sdata->max) {
333                 new_max = MAX (sdata->max * 2, sdata->len + count);
334                 new_buffer = (gchar *)g_realloc (sdata->buffer, new_max);
335
336                 sdata->buffer = new_buffer;
337                 sdata->max = new_max;
338         }
339         
340         memcpy (sdata->buffer + sdata->len, buf, count);
341         sdata->len += count;
342         
343         return TRUE;
344 }
345
346 static gboolean
347 attachment_save_to_buffer (PopplerAttachment  *attachment,
348                            gchar             **buffer,
349                            gsize              *buffer_size,
350                            GError            **error)
351 {
352         static const gint initial_max = 1024;
353         struct SaveToBufferData sdata;
354
355         *buffer = NULL;
356         *buffer_size = 0;
357
358         sdata.buffer = (gchar *) g_malloc (initial_max);
359         sdata.max = initial_max;
360         sdata.len = 0;
361
362         if (! poppler_attachment_save_to_callback (attachment,
363                                                    attachment_save_to_buffer_callback,
364                                                    &sdata,
365                                                    error)) {
366                 g_free (sdata.buffer);
367                 return FALSE;
368         }
369
370         *buffer = sdata.buffer;
371         *buffer_size = sdata.len;
372         
373         return TRUE;
374 }
375
376 static GList *
377 pdf_document_get_attachments (EvDocument *document)
378 {
379         PdfDocument *pdf_document;
380         GList *attachments;
381         GList *list;
382         GList *retval = NULL;
383
384         pdf_document = PDF_DOCUMENT (document);
385
386         if (!pdf_document_has_attachments (document))
387                 return NULL;
388
389         attachments = poppler_document_get_attachments (pdf_document->document);
390         
391         for (list = attachments; list; list = list->next) {
392                 PopplerAttachment *attachment;
393                 EvAttachment *ev_attachment;
394                 gchar *data = NULL;
395                 gsize size;
396                 GError *error = NULL;
397
398                 attachment = (PopplerAttachment *) list->data;
399
400                 if (attachment_save_to_buffer (attachment, &data, &size, &error)) {
401                         ev_attachment = ev_attachment_new (attachment->name,
402                                                            attachment->description,
403                                                            attachment->mtime,
404                                                            attachment->ctime,
405                                                            size, data);
406                         
407                         retval = g_list_prepend (retval, ev_attachment);
408                 } else {
409                         if (error) {
410                                 g_warning ("%s", error->message);
411                                 g_error_free (error);
412
413                                 g_free (data);
414                         }
415                 }
416
417                 g_object_unref (attachment);
418         }
419
420         return g_list_reverse (retval);
421 }
422
423 static GdkPixbuf *
424 pdf_document_render_pixbuf (EvDocument   *document,
425                             EvRenderContext *rc)
426 {
427         PdfDocument *pdf_document;
428         GdkPixbuf *pixbuf;
429         double width_points, height_points;
430         gint width, height;
431
432         pdf_document = PDF_DOCUMENT (document);
433
434         set_rc_data (pdf_document, rc);
435
436         poppler_page_get_size (POPPLER_PAGE (rc->data), &width_points, &height_points);
437
438         if (rc->rotation == 90 || rc->rotation == 270) {
439                 width = (int) ((height_points * rc->scale) + 0.5);
440                 height = (int) ((width_points * rc->scale) + 0.5);
441         } else {
442                 width = (int) ((width_points * rc->scale) + 0.5);
443                 height = (int) ((height_points * rc->scale) + 0.5);
444         }
445
446         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
447                                  FALSE, 8,
448                                  width, height);
449
450         poppler_page_render_to_pixbuf (POPPLER_PAGE (rc->data),
451                                        0, 0,
452                                        width, height,
453                                        rc->scale,
454                                        rc->rotation,
455                                        pixbuf);
456         
457         
458         return pixbuf;
459 }
460
461 /* EvDocumentSecurity */
462
463 static gboolean
464 pdf_document_has_document_security (EvDocumentSecurity *document_security)
465 {
466         /* FIXME: do we really need to have this? */
467         return FALSE;
468 }
469
470 static void
471 pdf_document_set_password (EvDocumentSecurity *document_security,
472                            const char         *password)
473 {
474         PdfDocument *document = PDF_DOCUMENT (document_security);
475
476         if (document->password)
477                 g_free (document->password);
478
479         document->password = g_strdup (password);
480 }
481
482 static gboolean
483 pdf_document_can_get_text (EvDocument *document)
484 {
485         return TRUE;
486 }
487
488 static EvDocumentInfo *
489 pdf_document_get_info (EvDocument *document)
490 {
491         EvDocumentInfo *info;
492         PopplerPageLayout layout;
493         PopplerPageMode mode;
494         PopplerViewerPreferences view_prefs;
495         PopplerPermissions permissions;
496
497         info = g_new0 (EvDocumentInfo, 1);
498
499         info->fields_mask = EV_DOCUMENT_INFO_TITLE |
500                             EV_DOCUMENT_INFO_FORMAT |
501                             EV_DOCUMENT_INFO_AUTHOR |
502                             EV_DOCUMENT_INFO_SUBJECT |
503                             EV_DOCUMENT_INFO_KEYWORDS |
504                             EV_DOCUMENT_INFO_LAYOUT |
505                             EV_DOCUMENT_INFO_START_MODE |
506                             EV_DOCUMENT_INFO_PERMISSIONS |
507                             EV_DOCUMENT_INFO_UI_HINTS |
508                             EV_DOCUMENT_INFO_CREATOR |
509                             EV_DOCUMENT_INFO_PRODUCER |
510                             EV_DOCUMENT_INFO_CREATION_DATE |
511                             EV_DOCUMENT_INFO_MOD_DATE |
512                             EV_DOCUMENT_INFO_LINEARIZED |
513                             EV_DOCUMENT_INFO_N_PAGES |
514                             EV_DOCUMENT_INFO_SECURITY | 
515                             EV_DOCUMENT_INFO_PAPER_SIZE;
516
517         g_object_get (PDF_DOCUMENT (document)->document,
518                       "title", &(info->title),
519                       "format", &(info->format),
520                       "author", &(info->author),
521                       "subject", &(info->subject),
522                       "keywords", &(info->keywords),
523                       "page-mode", &mode,
524                       "page-layout", &layout,
525                       "viewer-preferences", &view_prefs,
526                       "permissions", &permissions,
527                       "creator", &(info->creator),
528                       "producer", &(info->producer),
529                       "creation-date", &(info->creation_date),
530                       "mod-date", &(info->modified_date),
531                       "linearized", &(info->linearized),
532                       NULL);
533
534         pdf_document_get_page_size(document, 0,
535                                    &(info->paper_width),
536                                    &(info->paper_height));
537
538         // Convert to mm.
539         info->paper_width = info->paper_width / 72.0f * 25.4f;
540         info->paper_height = info->paper_height / 72.0f * 25.4f;
541
542         switch (layout) {
543                 case POPPLER_PAGE_LAYOUT_SINGLE_PAGE:
544                         info->layout = EV_DOCUMENT_LAYOUT_SINGLE_PAGE;
545                         break;
546                 case POPPLER_PAGE_LAYOUT_ONE_COLUMN:
547                         info->layout = EV_DOCUMENT_LAYOUT_ONE_COLUMN;
548                         break;
549                 case POPPLER_PAGE_LAYOUT_TWO_COLUMN_LEFT:
550                         info->layout = EV_DOCUMENT_LAYOUT_TWO_COLUMN_LEFT;
551                         break;
552                 case POPPLER_PAGE_LAYOUT_TWO_COLUMN_RIGHT:
553                         info->layout = EV_DOCUMENT_LAYOUT_TWO_COLUMN_RIGHT;
554                 case POPPLER_PAGE_LAYOUT_TWO_PAGE_LEFT:
555                         info->layout = EV_DOCUMENT_LAYOUT_TWO_PAGE_LEFT;
556                         break;
557                 case POPPLER_PAGE_LAYOUT_TWO_PAGE_RIGHT:
558                         info->layout = EV_DOCUMENT_LAYOUT_TWO_PAGE_RIGHT;
559                         break;
560                 default:
561                         break;
562         }
563
564         switch (mode) {
565                 case POPPLER_PAGE_MODE_NONE:
566                         info->mode = EV_DOCUMENT_MODE_NONE;
567                         break;
568                 case POPPLER_PAGE_MODE_USE_THUMBS:
569                         info->mode = EV_DOCUMENT_MODE_USE_THUMBS;
570                         break;
571                 case POPPLER_PAGE_MODE_USE_OC:
572                         info->mode = EV_DOCUMENT_MODE_USE_OC;
573                         break;
574                 case POPPLER_PAGE_MODE_FULL_SCREEN:
575                         info->mode = EV_DOCUMENT_MODE_FULL_SCREEN;
576                         break;
577                 case POPPLER_PAGE_MODE_USE_ATTACHMENTS:
578                         info->mode = EV_DOCUMENT_MODE_USE_ATTACHMENTS;
579                 default:
580                         break;
581         }
582
583         info->ui_hints = 0;
584         if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_TOOLBAR) {
585                 info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_TOOLBAR;
586         }
587         if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_MENUBAR) {
588                 info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_MENUBAR;
589         }
590         if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_WINDOWUI) {
591                 info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_WINDOWUI;
592         }
593         if (view_prefs & POPPLER_VIEWER_PREFERENCES_FIT_WINDOW) {
594                 info->ui_hints |= EV_DOCUMENT_UI_HINT_FIT_WINDOW;
595         }
596         if (view_prefs & POPPLER_VIEWER_PREFERENCES_CENTER_WINDOW) {
597                 info->ui_hints |= EV_DOCUMENT_UI_HINT_CENTER_WINDOW;
598         }
599         if (view_prefs & POPPLER_VIEWER_PREFERENCES_DISPLAY_DOC_TITLE) {
600                 info->ui_hints |= EV_DOCUMENT_UI_HINT_DISPLAY_DOC_TITLE;
601         }
602         if (view_prefs & POPPLER_VIEWER_PREFERENCES_DIRECTION_RTL) {
603                 info->ui_hints |=  EV_DOCUMENT_UI_HINT_DIRECTION_RTL;
604         }
605
606         info->permissions = 0;
607         if (permissions & POPPLER_PERMISSIONS_OK_TO_PRINT) {
608                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_PRINT;
609         }
610         if (permissions & POPPLER_PERMISSIONS_OK_TO_MODIFY) {
611                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_MODIFY;
612         }
613         if (permissions & POPPLER_PERMISSIONS_OK_TO_COPY) {
614                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_COPY;
615         }
616         if (permissions & POPPLER_PERMISSIONS_OK_TO_ADD_NOTES) {
617                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_ADD_NOTES;
618         }
619
620         info->n_pages = ev_document_get_n_pages (document);
621
622         if (ev_document_security_has_document_security (EV_DOCUMENT_SECURITY (document))) {
623                 /* translators: this is the document security state */
624                 info->security = g_strdup (_("Yes"));
625         } else {
626                 /* translators: this is the document security state */
627                 info->security = g_strdup (_("No"));
628         }
629
630         return info;
631 }
632
633 static char *
634 pdf_document_get_text (EvDocument *document, int page, EvRectangle *rect)
635 {
636         PdfDocument *pdf_document = PDF_DOCUMENT (document);
637         PopplerPage *poppler_page;
638         PopplerRectangle r;
639         double height;
640         char *text;
641         
642         poppler_page = poppler_document_get_page (pdf_document->document, page);
643         g_return_val_if_fail (poppler_page != NULL, NULL);
644
645         poppler_page_get_size (poppler_page, NULL, &height);
646         r.x1 = rect->x1;
647         r.y1 = height - rect->y2;
648         r.x2 = rect->x2;
649         r.y2 = height - rect->y1;
650
651         text = poppler_page_get_text (poppler_page, &r);
652
653         g_object_unref (poppler_page);
654
655         return text;
656 }
657
658 static void
659 pdf_document_document_iface_init (EvDocumentIface *iface)
660 {
661         iface->save = pdf_document_save;
662         iface->load = pdf_document_load;
663         iface->get_n_pages = pdf_document_get_n_pages;
664         iface->get_page_size = pdf_document_get_page_size;
665         iface->get_page_label = pdf_document_get_page_label;
666         iface->has_attachments = pdf_document_has_attachments;
667         iface->get_attachments = pdf_document_get_attachments;
668         iface->render_pixbuf = pdf_document_render_pixbuf;
669         iface->get_text = pdf_document_get_text;
670         iface->can_get_text = pdf_document_can_get_text;
671         iface->get_info = pdf_document_get_info;
672 };
673
674 static void
675 pdf_document_security_iface_init (EvDocumentSecurityIface *iface)
676 {
677         iface->has_document_security = pdf_document_has_document_security;
678         iface->set_password = pdf_document_set_password;
679 }
680
681 static gdouble
682 pdf_document_fonts_get_progress (EvDocumentFonts *document_fonts)
683 {
684         PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
685         int n_pages;
686
687         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (pdf_document));
688
689         return (double)pdf_document->fonts_scanned_pages / (double)n_pages;
690 }
691
692 static gboolean
693 pdf_document_fonts_scan (EvDocumentFonts *document_fonts,
694                          int              n_pages)
695 {
696         PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
697         gboolean result;
698
699         g_return_val_if_fail (PDF_IS_DOCUMENT (document_fonts), FALSE);
700
701         if (pdf_document->font_info == NULL) { 
702                 pdf_document->font_info = poppler_font_info_new (pdf_document->document);
703         }
704
705         if (pdf_document->fonts_iter) {
706                 poppler_fonts_iter_free (pdf_document->fonts_iter);
707         }
708
709         pdf_document->fonts_scanned_pages += n_pages;
710
711         result = poppler_font_info_scan (pdf_document->font_info, n_pages,
712                                          &pdf_document->fonts_iter);
713         if (!result) {
714                 pdf_document->fonts_scanned_pages = 0;
715                 poppler_font_info_free (pdf_document->font_info);
716                 pdf_document->font_info = NULL; 
717         }
718
719         return result;
720 }
721
722 static const char *
723 font_type_to_string (PopplerFontType type)
724 {
725         switch (type) {
726                 case POPPLER_FONT_TYPE_TYPE1:
727                         return _("Type 1");
728                 case POPPLER_FONT_TYPE_TYPE1C:
729                         return _("Type 1C");
730                 case POPPLER_FONT_TYPE_TYPE3:
731                         return _("Type 3");
732                 case POPPLER_FONT_TYPE_TRUETYPE:
733                         return _("TrueType");
734                 case POPPLER_FONT_TYPE_CID_TYPE0:
735                         return _("Type 1 (CID)");
736                 case POPPLER_FONT_TYPE_CID_TYPE0C:
737                         return _("Type 1C (CID)");
738                 case POPPLER_FONT_TYPE_CID_TYPE2:
739                         return _("TrueType (CID)");
740                 default:
741                         return _("Unknown font type");
742         }
743 }
744
745 static void
746 pdf_document_fonts_fill_model (EvDocumentFonts *document_fonts,
747                                GtkTreeModel    *model)
748 {
749         PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
750         PopplerFontsIter *iter = pdf_document->fonts_iter;
751
752         g_return_if_fail (PDF_IS_DOCUMENT (document_fonts));
753
754         if (!iter)
755                 return;
756
757         do {
758                 GtkTreeIter list_iter;
759                 const char *name;
760                 const char *type;
761                 const char *embedded;
762                 char *details;
763                 
764                 name = poppler_fonts_iter_get_name (iter);
765
766                 if (name == NULL) {
767                         name = _("No name");
768                 }
769
770                 type = font_type_to_string (
771                         poppler_fonts_iter_get_font_type (iter));
772
773                 if (poppler_fonts_iter_is_embedded (iter)) {
774                         if (poppler_fonts_iter_is_subset (iter))
775                                 embedded = _("Embedded subset");
776                         else
777                                 embedded = _("Embedded");
778                 } else {
779                         embedded = _("Not embedded");
780                 }
781
782                 details = g_markup_printf_escaped ("%s\n%s", type, embedded);
783
784                 gtk_list_store_append (GTK_LIST_STORE (model), &list_iter);
785                 gtk_list_store_set (GTK_LIST_STORE (model), &list_iter,
786                                     EV_DOCUMENT_FONTS_COLUMN_NAME, name,
787                                     EV_DOCUMENT_FONTS_COLUMN_DETAILS, details,
788                                     -1);
789
790                 g_free (details);
791         } while (poppler_fonts_iter_next (iter));
792 }
793
794 static void
795 pdf_document_document_fonts_iface_init (EvDocumentFontsIface *iface)
796 {
797         iface->fill_model = pdf_document_fonts_fill_model;
798         iface->scan = pdf_document_fonts_scan;
799         iface->get_progress = pdf_document_fonts_get_progress;
800 }
801
802 static gboolean
803 pdf_document_links_has_document_links (EvDocumentLinks *document_links)
804 {
805         PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
806         PopplerIndexIter *iter;
807
808         g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
809
810         iter = poppler_index_iter_new (pdf_document->document);
811         if (iter == NULL)
812                 return FALSE;
813         poppler_index_iter_free (iter);
814
815         return TRUE;
816 }
817
818 static EvLinkDest *
819 ev_link_dest_from_dest (PdfDocument *pdf_document,
820                         PopplerDest *dest)
821 {
822         EvLinkDest *ev_dest = NULL;
823         const char *unimplemented_dest = NULL;
824
825         g_assert (dest != NULL);
826
827         switch (dest->type) {
828                 case POPPLER_DEST_XYZ: {
829                         PopplerPage *poppler_page;
830                         double height;
831
832                         poppler_page = poppler_document_get_page (pdf_document->document,
833                                                                   MAX (0, dest->page_num - 1));
834                         poppler_page_get_size (poppler_page, NULL, &height);
835                         ev_dest = ev_link_dest_new_xyz (dest->page_num - 1,
836                                                         dest->left,
837                                                         height - dest->top,
838                                                         dest->zoom);
839                         g_object_unref (poppler_page);
840                 }
841                         break;
842                 case POPPLER_DEST_FIT:
843                         ev_dest = ev_link_dest_new_fit (dest->page_num - 1);
844                         break;
845                 case POPPLER_DEST_FITH: {
846                         PopplerPage *poppler_page;
847                         double height;
848
849                         poppler_page = poppler_document_get_page (pdf_document->document,
850                                                                   MAX (0, dest->page_num - 1));
851                         poppler_page_get_size (poppler_page, NULL, &height);
852                         ev_dest = ev_link_dest_new_fith (dest->page_num - 1,
853                                                          height - dest->top);
854                         g_object_unref (poppler_page);
855                 }
856                         break;
857                 case POPPLER_DEST_FITV:
858                         ev_dest = ev_link_dest_new_fitv (dest->page_num - 1,
859                                                          dest->left);
860                         break;
861                 case POPPLER_DEST_FITR: {
862                         PopplerPage *poppler_page;
863                         double height;
864
865                         poppler_page = poppler_document_get_page (pdf_document->document,
866                                                                   MAX (0, dest->page_num - 1));
867                         poppler_page_get_size (poppler_page, NULL, &height);
868                         ev_dest = ev_link_dest_new_fitr (dest->page_num - 1,
869                                                          dest->left,
870                                                          height - dest->bottom,
871                                                          dest->right,
872                                                          height - dest->top);
873                         g_object_unref (poppler_page);
874                 }
875                         break;
876                 case POPPLER_DEST_FITB:
877                         unimplemented_dest = "POPPLER_DEST_FITB";
878                         break;
879                 case POPPLER_DEST_FITBH:
880                         unimplemented_dest = "POPPLER_DEST_FITBH";
881                         break;
882                 case POPPLER_DEST_FITBV:
883                         unimplemented_dest = "POPPLER_DEST_FITBV";
884                         break;
885                 case POPPLER_DEST_NAMED:
886                         ev_dest = ev_link_dest_new_named (dest->named_dest);
887                         break;
888                 case POPPLER_DEST_UNKNOWN:
889                         unimplemented_dest = "POPPLER_DEST_UNKNOWN";
890                         break;
891         }
892
893         if (unimplemented_dest) {
894                 g_warning ("Unimplemented named action: %s, please post a "
895                            "bug report in Evince bugzilla "
896                            "(http://bugzilla.gnome.org) with a testcase.",
897                            unimplemented_dest);
898         }
899
900         if (!ev_dest)
901                 ev_dest = ev_link_dest_new_page (dest->page_num - 1);
902         
903         return ev_dest;
904 }
905
906 static EvLink *
907 ev_link_from_action (PdfDocument   *pdf_document,
908                      PopplerAction *action)
909 {
910         EvLink       *link = NULL;
911         EvLinkAction *ev_action = NULL;
912         const char   *unimplemented_action = NULL;
913
914         switch (action->type) {
915                 case POPPLER_ACTION_GOTO_DEST: {
916                         EvLinkDest *dest;
917                         
918                         dest = ev_link_dest_from_dest (pdf_document, action->goto_dest.dest);
919                         ev_action = ev_link_action_new_dest (dest);
920                 }
921                         break;
922                 case POPPLER_ACTION_GOTO_REMOTE: {
923                         EvLinkDest *dest;
924                         
925                         dest = ev_link_dest_from_dest (pdf_document, action->goto_remote.dest);
926                         ev_action = ev_link_action_new_remote (dest, 
927                                                                action->goto_remote.file_name);
928                         
929                 }
930                         break;
931                 case POPPLER_ACTION_LAUNCH:
932                         ev_action = ev_link_action_new_launch (action->launch.file_name,
933                                                                action->launch.params);
934                         break;
935                 case POPPLER_ACTION_URI:
936                         ev_action = ev_link_action_new_external_uri (action->uri.uri);
937                         break;
938                 case POPPLER_ACTION_NAMED:
939                         ev_action = ev_link_action_new_named (action->named.named_dest);
940                         break;
941                 case POPPLER_ACTION_MOVIE:
942                         unimplemented_action = "POPPLER_ACTION_MOVIE";
943                         break;
944                 case POPPLER_ACTION_UNKNOWN:
945                         unimplemented_action = "POPPLER_ACTION_UNKNOWN";
946         }
947         
948         if (unimplemented_action) {
949                 g_warning ("Unimplemented action: %s, please post a bug report with a testcase.",
950                            unimplemented_action);
951         }
952         
953         link = ev_link_new (action->any.title, ev_action);
954         
955         return link;    
956 }
957
958 static void
959 build_tree (PdfDocument      *pdf_document,
960             GtkTreeModel     *model,
961             GtkTreeIter      *parent,
962             PopplerIndexIter *iter)
963 {
964         
965         do {
966                 GtkTreeIter tree_iter;
967                 PopplerIndexIter *child;
968                 PopplerAction *action;
969                 EvLink *link = NULL;
970                 gboolean expand;
971                 char *title_markup;
972                 
973                 action = poppler_index_iter_get_action (iter);
974                 expand = poppler_index_iter_is_open (iter);
975
976                 if (!action)
977                         continue;
978
979                 switch (action->type) {
980                         case POPPLER_ACTION_GOTO_DEST: {
981                                 /* For bookmarks, solve named destinations */
982                                 if (action->goto_dest.dest->type == POPPLER_DEST_NAMED) {
983                                         PopplerDest *dest;
984                                         EvLinkDest *ev_dest = NULL;
985                                         EvLinkAction *ev_action;
986                                         
987                                         dest = poppler_document_find_dest (pdf_document->document,
988                                                                            action->goto_dest.dest->named_dest);
989                                         if (!dest) {
990                                                 link = ev_link_from_action (pdf_document, action);
991                                                 break;
992                                         }
993                                         
994                                         ev_dest = ev_link_dest_from_dest (pdf_document, dest);
995                                         poppler_dest_free (dest);
996                                         
997                                         ev_action = ev_link_action_new_dest (ev_dest);
998                                         link = ev_link_new (action->any.title, ev_action);
999                                 } else {
1000                                         link = ev_link_from_action (pdf_document, action);
1001                                 }
1002                         }
1003                                 break;
1004                         default:
1005                                 link = ev_link_from_action (pdf_document, action);
1006                                 break;
1007                 }
1008                 
1009                 if (!link) {
1010                         poppler_action_free (action);
1011                         continue;
1012                 }
1013
1014                 gtk_tree_store_append (GTK_TREE_STORE (model), &tree_iter, parent);
1015                 title_markup = g_markup_escape_text (ev_link_get_title (link), -1);
1016                 
1017                 gtk_tree_store_set (GTK_TREE_STORE (model), &tree_iter,
1018                                     EV_DOCUMENT_LINKS_COLUMN_MARKUP, title_markup,
1019                                     EV_DOCUMENT_LINKS_COLUMN_LINK, link,
1020                                     EV_DOCUMENT_LINKS_COLUMN_EXPAND, expand,
1021                                     -1);
1022                 
1023                 g_free (title_markup);
1024                 g_object_unref (link);
1025                 
1026                 child = poppler_index_iter_get_child (iter);
1027                 if (child)
1028                         build_tree (pdf_document, model, &tree_iter, child);
1029                 poppler_index_iter_free (child);
1030                 poppler_action_free (action);
1031                 
1032         } while (poppler_index_iter_next (iter));
1033 }
1034
1035 static GtkTreeModel *
1036 pdf_document_links_get_links_model (EvDocumentLinks *document_links)
1037 {
1038         PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
1039         GtkTreeModel *model = NULL;
1040         PopplerIndexIter *iter;
1041         
1042         g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), NULL);
1043
1044         iter = poppler_index_iter_new (pdf_document->document);
1045         /* Create the model if we have items*/
1046         if (iter != NULL) {
1047                 model = (GtkTreeModel *) gtk_tree_store_new (EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS,
1048                                                              G_TYPE_STRING,
1049                                                              G_TYPE_OBJECT,
1050                                                              G_TYPE_BOOLEAN);
1051                 build_tree (pdf_document, model, NULL, iter);
1052                 poppler_index_iter_free (iter);
1053         }
1054         
1055         return model;
1056 }
1057
1058 static GList *
1059 pdf_document_links_get_links (EvDocumentLinks *document_links,
1060                               gint             page)
1061 {
1062         PdfDocument *pdf_document;
1063         PopplerPage *poppler_page;
1064         GList *retval = NULL;
1065         GList *mapping_list;
1066         GList *list;
1067         double height;
1068
1069         pdf_document = PDF_DOCUMENT (document_links);
1070         poppler_page = poppler_document_get_page (pdf_document->document,
1071                                                   page);
1072         mapping_list = poppler_page_get_link_mapping (poppler_page);
1073         poppler_page_get_size (poppler_page, NULL, &height);
1074
1075         for (list = mapping_list; list; list = list->next) {
1076                 PopplerLinkMapping *link_mapping;
1077                 EvLinkMapping *ev_link_mapping;
1078
1079                 link_mapping = (PopplerLinkMapping *)list->data;
1080                 ev_link_mapping = g_new (EvLinkMapping, 1);
1081                 ev_link_mapping->link = ev_link_from_action (pdf_document,
1082                                                              link_mapping->action);
1083                 ev_link_mapping->x1 = link_mapping->area.x1;
1084                 ev_link_mapping->x2 = link_mapping->area.x2;
1085                 /* Invert this for X-style coordinates */
1086                 ev_link_mapping->y1 = height - link_mapping->area.y2;
1087                 ev_link_mapping->y2 = height - link_mapping->area.y1;
1088
1089                 retval = g_list_prepend (retval, ev_link_mapping);
1090         }
1091
1092         poppler_page_free_link_mapping (mapping_list);
1093         g_object_unref (poppler_page);
1094
1095         return g_list_reverse (retval);
1096 }
1097
1098 static EvLinkDest *
1099 pdf_document_links_find_link_dest (EvDocumentLinks  *document_links,
1100                                    const gchar      *link_name)
1101 {
1102         PdfDocument *pdf_document;
1103         PopplerDest *dest;
1104         EvLinkDest *ev_dest = NULL;
1105
1106         pdf_document = PDF_DOCUMENT (document_links);
1107         dest = poppler_document_find_dest (pdf_document->document,
1108                                            link_name);
1109         if (dest) {
1110                 ev_dest = ev_link_dest_from_dest (pdf_document, dest);
1111                 poppler_dest_free (dest);
1112         }
1113
1114         return ev_dest;
1115 }
1116
1117 static void
1118 pdf_document_document_links_iface_init (EvDocumentLinksIface *iface)
1119 {
1120         iface->has_document_links = pdf_document_links_has_document_links;
1121         iface->get_links_model = pdf_document_links_get_links_model;
1122         iface->get_links = pdf_document_links_get_links;
1123         iface->find_link_dest = pdf_document_links_find_link_dest;
1124 }
1125
1126 static GdkPixbuf *
1127 make_thumbnail_for_size (PdfDocument   *pdf_document,
1128                          gint           page,
1129                          int            rotation,
1130                          gint           size)
1131 {
1132         PopplerPage *poppler_page;
1133         GdkPixbuf *pixbuf;
1134         int width, height;
1135         double scale;
1136         gdouble unscaled_width, unscaled_height;
1137
1138         poppler_page = poppler_document_get_page (pdf_document->document, page);
1139         g_return_val_if_fail (poppler_page != NULL, NULL);
1140
1141         pdf_document_thumbnails_get_dimensions (EV_DOCUMENT_THUMBNAILS (pdf_document), page,
1142                                                 size, &width, &height);
1143         poppler_page_get_size (poppler_page, &unscaled_width, &unscaled_height);
1144         scale = width / unscaled_width;
1145
1146         /* rotate */
1147         if (rotation == 90 || rotation == 270) {
1148                 int temp;
1149                 temp = width;
1150                 width = height;
1151                 height = temp;
1152         }
1153
1154         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
1155                                  width, height);
1156         gdk_pixbuf_fill (pixbuf, 0xffffffff);
1157
1158         ev_document_fc_mutex_lock ();
1159         poppler_page_render_to_pixbuf (poppler_page, 0, 0,
1160                                        width, height,
1161                                        scale, rotation, pixbuf);
1162         ev_document_fc_mutex_unlock ();
1163        
1164
1165         g_object_unref (poppler_page);
1166
1167         return pixbuf;
1168 }
1169
1170 static GdkPixbuf *
1171 pdf_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document_thumbnails,
1172                                        gint                  page,
1173                                        gint                  rotation,
1174                                        gint                  size,
1175                                        gboolean              border)
1176 {
1177         PdfDocument *pdf_document;
1178         PopplerPage *poppler_page;
1179         GdkPixbuf *pixbuf;
1180         GdkPixbuf *border_pixbuf;
1181
1182         pdf_document = PDF_DOCUMENT (document_thumbnails);
1183
1184         poppler_page = poppler_document_get_page (pdf_document->document, page);
1185         g_return_val_if_fail (poppler_page != NULL, NULL);
1186
1187         pixbuf = poppler_page_get_thumbnail (poppler_page);
1188         
1189         if (pixbuf == NULL) {
1190                 /* There is no provided thumbnail.  We need to make one. */
1191                 pixbuf = make_thumbnail_for_size (pdf_document, page, rotation, size);
1192         }
1193
1194         if (border) {           
1195                 border_pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, rotation, pixbuf);
1196                 g_object_unref (pixbuf);
1197                 pixbuf = border_pixbuf;
1198         }               
1199
1200         g_object_unref (poppler_page);
1201         
1202         return pixbuf;
1203 }
1204
1205 static void
1206 pdf_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnails,
1207                                         gint                  page,
1208                                         gint                  size,
1209                                         gint                 *width,
1210                                         gint                 *height)
1211 {
1212         PdfDocument *pdf_document;
1213         PopplerPage *poppler_page;
1214         gint has_thumb;
1215         
1216         pdf_document = PDF_DOCUMENT (document_thumbnails);
1217         poppler_page = poppler_document_get_page (pdf_document->document, page);
1218
1219         g_return_if_fail (width != NULL);
1220         g_return_if_fail (height != NULL);
1221         g_return_if_fail (poppler_page != NULL);
1222
1223         has_thumb = poppler_page_get_thumbnail_size (poppler_page, width, height);
1224
1225         if (!has_thumb) {
1226                 double page_width, page_height;
1227
1228                 poppler_page_get_size (poppler_page, &page_width, &page_height);
1229                 *width = size;
1230                 *height = (int) (size * page_height / page_width);
1231         }
1232         g_object_unref (poppler_page);
1233 }
1234
1235 static void
1236 pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
1237 {
1238         iface->get_thumbnail = pdf_document_thumbnails_get_thumbnail;
1239         iface->get_dimensions = pdf_document_thumbnails_get_dimensions;
1240 }
1241
1242
1243 static gboolean
1244 pdf_document_search_idle_callback (void *data)
1245 {
1246         PdfDocumentSearch *search = (PdfDocumentSearch*) data;
1247         PdfDocument *pdf_document = search->document;
1248         int n_pages;
1249         GList *matches;
1250         PopplerPage *page;
1251
1252         page = poppler_document_get_page (search->document->document,
1253                                           search->search_page);
1254
1255         ev_document_doc_mutex_lock ();
1256         matches = poppler_page_find_text (page, search->text);
1257         ev_document_doc_mutex_unlock ();
1258
1259         g_object_unref (page);
1260
1261         search->pages[search->search_page] = matches;
1262         ev_document_find_changed (EV_DOCUMENT_FIND (pdf_document),
1263                                   search->search_page);
1264
1265         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (search->document));
1266         search->search_page += 1;
1267         if (search->search_page == n_pages) {
1268                 /* wrap around */
1269                 search->search_page = 0;
1270         }
1271
1272         if (search->search_page != search->start_page) {
1273                 return TRUE;
1274         }
1275
1276         /* We're done. */
1277         search->idle = 0; /* will return FALSE to remove */
1278         return FALSE;
1279 }
1280
1281
1282 static PdfDocumentSearch *
1283 pdf_document_search_new (PdfDocument *pdf_document,
1284                          int          start_page,
1285                          const char  *text)
1286 {
1287         PdfDocumentSearch *search;
1288         int n_pages;
1289         int i;
1290
1291         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (pdf_document));
1292
1293         search = g_new0 (PdfDocumentSearch, 1);
1294
1295         search->text = g_strdup (text);
1296         search->pages = g_new0 (GList *, n_pages);
1297         search->document = pdf_document;
1298
1299         /* We add at low priority so the progress bar repaints */
1300         search->idle = g_idle_add_full (G_PRIORITY_LOW,
1301                                         pdf_document_search_idle_callback,
1302                                         search,
1303                                         NULL);
1304
1305         search->start_page = start_page;
1306         search->search_page = start_page;
1307
1308         return search;
1309 }
1310
1311 static void
1312 pdf_document_find_begin (EvDocumentFind   *document,
1313                          int               page,
1314                          const char       *search_string,
1315                          gboolean          case_sensitive)
1316 {
1317         PdfDocument *pdf_document = PDF_DOCUMENT (document);
1318
1319         /* FIXME handle case_sensitive (right now XPDF
1320          * code is always case insensitive for ASCII
1321          * and case sensitive for all other languaages)
1322          */
1323
1324         if (pdf_document->search &&
1325             strcmp (search_string, pdf_document->search->text) == 0)
1326                 return;
1327
1328         if (pdf_document->search)
1329                 pdf_document_search_free (pdf_document->search);
1330
1331         pdf_document->search = pdf_document_search_new (pdf_document,
1332                                                         page,
1333                                                         search_string);
1334 }
1335
1336 static int
1337 pdf_document_find_get_n_results (EvDocumentFind *document_find, int page)
1338 {
1339         PdfDocumentSearch *search = PDF_DOCUMENT (document_find)->search;
1340
1341         if (search) {
1342                 return g_list_length (search->pages[page]);
1343         } else {
1344                 return 0;
1345         }
1346 }
1347
1348 static gboolean
1349 pdf_document_find_get_result (EvDocumentFind *document_find,
1350                               int             page,
1351                               int             n_result,
1352                               EvRectangle    *rectangle)
1353 {
1354         PdfDocument *pdf_document = PDF_DOCUMENT (document_find);
1355         PdfDocumentSearch *search = pdf_document->search;
1356         PopplerPage *poppler_page;
1357         PopplerRectangle *r;
1358         double height;
1359
1360         if (search == NULL)
1361                 return FALSE;
1362
1363         r = (PopplerRectangle *) g_list_nth_data (search->pages[page],
1364                                                   n_result);
1365         if (r == NULL)
1366                 return FALSE;
1367
1368         poppler_page = poppler_document_get_page (pdf_document->document, page);
1369         poppler_page_get_size (poppler_page, NULL, &height);
1370         rectangle->x1 = r->x1;
1371         rectangle->y1 = height - r->y2;
1372         rectangle->x2 = r->x2;
1373         rectangle->y2 = height - r->y1;
1374         g_object_unref (poppler_page);
1375                 
1376         return TRUE;
1377 }
1378
1379 static int
1380 pdf_document_find_page_has_results (EvDocumentFind *document_find,
1381                                     int             page)
1382 {
1383         PdfDocumentSearch *search = PDF_DOCUMENT (document_find)->search;
1384
1385         return search && search->pages[page] != NULL;
1386 }
1387
1388 static double
1389 pdf_document_find_get_progress (EvDocumentFind *document_find)
1390 {
1391         PdfDocumentSearch *search;
1392         int n_pages, pages_done;
1393
1394         search = PDF_DOCUMENT (document_find)->search;
1395
1396         if (search == NULL) {
1397                 return 0;
1398         }
1399
1400         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (document_find));
1401         if (search->search_page > search->start_page) {
1402                 pages_done = search->search_page - search->start_page + 1;
1403         } else if (search->search_page == search->start_page) {
1404                 pages_done = n_pages;
1405         } else {
1406                 pages_done = n_pages - search->start_page + search->search_page;
1407         }
1408
1409         return pages_done / (double) n_pages;
1410 }
1411
1412 static void
1413 pdf_document_find_cancel (EvDocumentFind *document)
1414 {
1415         PdfDocument *pdf_document = PDF_DOCUMENT (document);
1416
1417         if (pdf_document->search) {
1418                 pdf_document_search_free (pdf_document->search);
1419                 pdf_document->search = NULL;
1420         }
1421 }
1422
1423 static void
1424 pdf_document_find_iface_init (EvDocumentFindIface *iface)
1425 {
1426         iface->begin = pdf_document_find_begin;
1427         iface->get_n_results = pdf_document_find_get_n_results;
1428         iface->get_result = pdf_document_find_get_result;
1429         iface->page_has_results = pdf_document_find_page_has_results;
1430         iface->get_progress = pdf_document_find_get_progress;
1431         iface->cancel = pdf_document_find_cancel;
1432 }
1433
1434 static const gboolean supported_formats[] = {
1435         TRUE, /* EV_FILE_FORMAT_PS */
1436 #ifdef HAVE_CAIRO_PDF
1437 #ifdef HAVE_POPPLER_PAGE_RENDER
1438         TRUE, /* EV_FILE_FORMAT_PDF */
1439 #else
1440         FALSE, /* EV_FILE_FORMAT_PDF */
1441 #endif
1442 #endif
1443 };
1444
1445 static void
1446 pdf_print_context_free (PdfPrintContext *ctx)
1447 {
1448         if (!ctx)
1449                 return;
1450
1451         if (ctx->ps_file) {
1452                 poppler_ps_file_free (ctx->ps_file);
1453                 ctx->ps_file = NULL;
1454         }
1455 #ifdef HAVE_CAIRO_PDF
1456         if (ctx->pdf_cairo) {
1457                 cairo_destroy (ctx->pdf_cairo);
1458                 ctx->pdf_cairo = NULL;
1459         }
1460 #endif
1461         g_free (ctx);
1462 }
1463
1464 static gboolean
1465 pdf_document_file_exporter_format_supported (EvFileExporter      *exporter,
1466                                              EvFileExporterFormat format)
1467 {
1468         return supported_formats[format];
1469 }
1470
1471 static void
1472 pdf_document_file_exporter_begin (EvFileExporter      *exporter,
1473                                   EvFileExporterFormat format,
1474                                   const char          *filename,
1475                                   int                  first_page,
1476                                   int                  last_page,
1477                                   double               width,
1478                                   double               height,
1479                                   gboolean             duplex)
1480 {
1481         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1482         PdfPrintContext *ctx;
1483
1484         if (pdf_document->print_ctx)
1485                 pdf_print_context_free (pdf_document->print_ctx);
1486         pdf_document->print_ctx = g_new0 (PdfPrintContext, 1);
1487         ctx = pdf_document->print_ctx;
1488         ctx->format = format;
1489         
1490         switch (format) {
1491                 case EV_FILE_FORMAT_PS:
1492                         ctx->ps_file = poppler_ps_file_new (pdf_document->document,
1493                                                             filename, first_page,
1494                                                             last_page - first_page + 1);
1495                         poppler_ps_file_set_paper_size (ctx->ps_file, width, height);
1496                         poppler_ps_file_set_duplex (ctx->ps_file, duplex);
1497
1498                         break;
1499                 case EV_FILE_FORMAT_PDF: {
1500 #ifdef HAVE_CAIRO_PDF
1501                         cairo_surface_t *surface;
1502                         
1503                         surface = cairo_pdf_surface_create (filename, width, height);
1504                         ctx->pdf_cairo = cairo_create (surface);
1505                         cairo_surface_destroy (surface);
1506 #endif
1507                 }
1508                         break;
1509                 default:
1510                         g_assert_not_reached ();
1511         }
1512 }
1513
1514 static void
1515 pdf_document_file_exporter_do_page (EvFileExporter *exporter, EvRenderContext *rc)
1516 {
1517         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1518         PdfPrintContext *ctx = pdf_document->print_ctx;
1519         PopplerPage *poppler_page;
1520
1521         g_return_if_fail (pdf_document->print_ctx != NULL);
1522
1523         poppler_page = poppler_document_get_page (pdf_document->document, rc->page);
1524
1525         switch (ctx->format) {
1526                 case EV_FILE_FORMAT_PS:
1527                         poppler_page_render_to_ps (poppler_page, ctx->ps_file);
1528                         break;
1529                 case EV_FILE_FORMAT_PDF:
1530 #ifdef HAVE_POPPLER_PAGE_RENDER
1531                         poppler_page_render (poppler_page, ctx->pdf_cairo);
1532 #endif
1533 #ifdef HAVE_CAIRO_PDF
1534                         cairo_show_page (ctx->pdf_cairo);
1535 #endif
1536                         break;
1537                 default:
1538                         g_assert_not_reached ();
1539         }
1540         
1541         g_object_unref (poppler_page);
1542 }
1543
1544 static void
1545 pdf_document_file_exporter_end (EvFileExporter *exporter)
1546 {
1547         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1548
1549         pdf_print_context_free (pdf_document->print_ctx);
1550         pdf_document->print_ctx = NULL;
1551 }
1552
1553 static void
1554 pdf_document_file_exporter_iface_init (EvFileExporterIface *iface)
1555 {
1556         iface->format_supported = pdf_document_file_exporter_format_supported;
1557         iface->begin = pdf_document_file_exporter_begin;
1558         iface->do_page = pdf_document_file_exporter_do_page;
1559         iface->end = pdf_document_file_exporter_end;
1560 }
1561
1562 static void
1563 pdf_selection_render_selection (EvSelection      *selection,
1564                                 EvRenderContext  *rc,
1565                                 GdkPixbuf       **pixbuf,
1566                                 EvRectangle      *points,
1567                                 EvRectangle      *old_points,
1568                                 GdkColor        *text,
1569                                 GdkColor        *base)
1570 {
1571         PdfDocument *pdf_document;
1572         double width_points, height_points;
1573         gint width, height;
1574
1575         pdf_document = PDF_DOCUMENT (selection);
1576         set_rc_data (pdf_document, rc);
1577
1578         poppler_page_get_size (POPPLER_PAGE (rc->data), &width_points, &height_points);
1579         width = (int) ((width_points * rc->scale) + 0.5);
1580         height = (int) ((height_points * rc->scale) + 0.5);
1581
1582         if (*pixbuf == NULL) {
1583                 * pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
1584                                            TRUE, 8,
1585                                            width, height);
1586         }
1587         
1588         poppler_page_render_selection (POPPLER_PAGE (rc->data),
1589                                        rc->scale, rc->rotation, *pixbuf,
1590                                        (PopplerRectangle *)points,
1591                                        (PopplerRectangle *)old_points,
1592                                        text,
1593                                        base);
1594 }
1595
1596
1597 static GdkRegion *
1598 pdf_selection_get_selection_region (EvSelection     *selection,
1599                                     EvRenderContext *rc,
1600                                     EvRectangle     *points)
1601 {
1602         PdfDocument *pdf_document;
1603         GdkRegion *retval;
1604
1605         pdf_document = PDF_DOCUMENT (selection);
1606
1607         set_rc_data (pdf_document, rc);
1608
1609         retval = poppler_page_get_selection_region ((PopplerPage *)rc->data, rc->scale, (PopplerRectangle *) points);
1610
1611         return retval;
1612 }
1613
1614 static GdkRegion *
1615 pdf_selection_get_selection_map (EvSelection     *selection,
1616                                  EvRenderContext *rc)
1617 {
1618         PdfDocument *pdf_document;
1619         PopplerPage *poppler_page;
1620         PopplerRectangle points;
1621         GdkRegion *retval;
1622
1623         pdf_document = PDF_DOCUMENT (selection);
1624         poppler_page = poppler_document_get_page (pdf_document->document,
1625                                                   rc->page);
1626
1627         points.x1 = 0.0;
1628         points.y1 = 0.0;
1629         poppler_page_get_size (poppler_page, &(points.x2), &(points.y2));
1630         retval = poppler_page_get_selection_region (poppler_page, 1.0, &points);
1631         g_object_unref (poppler_page);
1632
1633         return retval;
1634 }
1635
1636 static void
1637 pdf_selection_iface_init (EvSelectionIface *iface)
1638 {
1639         iface->render_selection = pdf_selection_render_selection;
1640         iface->get_selection_region = pdf_selection_get_selection_region;
1641         iface->get_selection_map = pdf_selection_get_selection_map;
1642 }
1643
1644 /* Page Transitions */
1645 static gdouble
1646 pdf_document_get_page_duration (EvDocumentTransition *trans,
1647                                 gint                  page)
1648 {
1649 #ifdef HAVE_POPPLER_PAGE_GET_DURATION   
1650         PdfDocument *pdf_document;
1651         PopplerPage *poppler_page;
1652         gdouble      duration = -1;
1653
1654         pdf_document = PDF_DOCUMENT (trans);
1655         poppler_page = poppler_document_get_page (pdf_document->document, page);
1656         if (!poppler_page)
1657                 return -1;
1658
1659         duration = poppler_page_get_duration (poppler_page);
1660         g_object_unref (poppler_page);
1661
1662         return duration;
1663 #else
1664         return -1;
1665 #endif /* HAVE_POPPLER_PAGE_GET_DURATION */
1666 }
1667
1668 static void
1669 pdf_document_page_transition_iface_init (EvDocumentTransitionIface *iface)
1670 {
1671         iface->get_page_duration = pdf_document_get_page_duration;
1672 }
1673
1674 PdfDocument *
1675 pdf_document_new (void)
1676 {
1677         return PDF_DOCUMENT (g_object_new (PDF_TYPE_DOCUMENT, NULL));
1678 }