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