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