]> www.fi.muni.cz Git - evince.git/blob - backend/pdf/ev-poppler.cc
Do not include ev-poppler.h when pdf is disabled.
[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                 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_size (PdfDocument   *pdf_document,
1177                          gint           page,
1178                          int            rotation,
1179                          gint           size)
1180 {
1181         PopplerPage *poppler_page;
1182         GdkPixbuf *pixbuf;
1183         int width, height;
1184         double scale;
1185         gdouble unscaled_width, unscaled_height;
1186
1187         poppler_page = poppler_document_get_page (pdf_document->document, page);
1188         g_return_val_if_fail (poppler_page != NULL, NULL);
1189
1190         pdf_document_thumbnails_get_dimensions (EV_DOCUMENT_THUMBNAILS (pdf_document), page,
1191                                                 size, &width, &height);
1192         poppler_page_get_size (poppler_page, &unscaled_width, &unscaled_height);
1193         scale = width / unscaled_width;
1194
1195         /* rotate */
1196         if (rotation == 90 || rotation == 270) {
1197                 int temp;
1198                 temp = width;
1199                 width = height;
1200                 height = temp;
1201         }
1202
1203         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
1204                                  width, height);
1205         gdk_pixbuf_fill (pixbuf, 0xffffffff);
1206
1207         ev_document_fc_mutex_lock ();
1208         poppler_page_render_to_pixbuf (poppler_page, 0, 0,
1209                                        width, height,
1210                                        scale, rotation, pixbuf);
1211         ev_document_fc_mutex_unlock ();
1212        
1213
1214         g_object_unref (poppler_page);
1215
1216         return pixbuf;
1217 }
1218
1219 static GdkPixbuf *
1220 pdf_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document_thumbnails,
1221                                        gint                  page,
1222                                        gint                  rotation,
1223                                        gint                  size,
1224                                        gboolean              border)
1225 {
1226         PdfDocument *pdf_document;
1227         PopplerPage *poppler_page;
1228         GdkPixbuf *pixbuf;
1229         GdkPixbuf *border_pixbuf;
1230
1231         pdf_document = PDF_DOCUMENT (document_thumbnails);
1232
1233         poppler_page = poppler_document_get_page (pdf_document->document, page);
1234         g_return_val_if_fail (poppler_page != NULL, NULL);
1235
1236         pixbuf = poppler_page_get_thumbnail (poppler_page);
1237         
1238         if (pixbuf == NULL) {
1239                 /* There is no provided thumbnail.  We need to make one. */
1240                 pixbuf = make_thumbnail_for_size (pdf_document, page, rotation, size);
1241         }
1242
1243         if (border) {           
1244                 border_pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, rotation, pixbuf);
1245                 g_object_unref (pixbuf);
1246                 pixbuf = border_pixbuf;
1247         }               
1248
1249         g_object_unref (poppler_page);
1250         
1251         return pixbuf;
1252 }
1253
1254 static void
1255 pdf_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnails,
1256                                         gint                  page,
1257                                         gint                  size,
1258                                         gint                 *width,
1259                                         gint                 *height)
1260 {
1261         PdfDocument *pdf_document;
1262         PopplerPage *poppler_page;
1263         gint has_thumb;
1264         
1265         pdf_document = PDF_DOCUMENT (document_thumbnails);
1266         poppler_page = poppler_document_get_page (pdf_document->document, page);
1267
1268         g_return_if_fail (width != NULL);
1269         g_return_if_fail (height != NULL);
1270         g_return_if_fail (poppler_page != NULL);
1271
1272         has_thumb = poppler_page_get_thumbnail_size (poppler_page, width, height);
1273
1274         if (!has_thumb) {
1275                 double page_width, page_height;
1276
1277                 poppler_page_get_size (poppler_page, &page_width, &page_height);
1278                 *width = size;
1279                 *height = (int) (size * page_height / page_width);
1280         }
1281         g_object_unref (poppler_page);
1282 }
1283
1284 static void
1285 pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
1286 {
1287         iface->get_thumbnail = pdf_document_thumbnails_get_thumbnail;
1288         iface->get_dimensions = pdf_document_thumbnails_get_dimensions;
1289 }
1290
1291
1292 static gboolean
1293 pdf_document_search_idle_callback (void *data)
1294 {
1295         PdfDocumentSearch *search = (PdfDocumentSearch*) data;
1296         PdfDocument *pdf_document = search->document;
1297         int n_pages;
1298         GList *matches;
1299         PopplerPage *page;
1300
1301         page = poppler_document_get_page (search->document->document,
1302                                           search->search_page);
1303
1304         ev_document_doc_mutex_lock ();
1305         matches = poppler_page_find_text (page, search->text);
1306         ev_document_doc_mutex_unlock ();
1307
1308         g_object_unref (page);
1309
1310         search->pages[search->search_page] = matches;
1311         ev_document_find_changed (EV_DOCUMENT_FIND (pdf_document),
1312                                   search->search_page);
1313
1314         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (search->document));
1315         search->search_page += 1;
1316         if (search->search_page == n_pages) {
1317                 /* wrap around */
1318                 search->search_page = 0;
1319         }
1320
1321         if (search->search_page != search->start_page) {
1322                 return TRUE;
1323         }
1324
1325         /* We're done. */
1326         search->idle = 0; /* will return FALSE to remove */
1327         return FALSE;
1328 }
1329
1330
1331 static PdfDocumentSearch *
1332 pdf_document_search_new (PdfDocument *pdf_document,
1333                          int          start_page,
1334                          const char  *text)
1335 {
1336         PdfDocumentSearch *search;
1337         int n_pages;
1338         int i;
1339
1340         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (pdf_document));
1341
1342         search = g_new0 (PdfDocumentSearch, 1);
1343
1344         search->text = g_strdup (text);
1345         search->pages = g_new0 (GList *, n_pages);
1346         search->document = pdf_document;
1347
1348         /* We add at low priority so the progress bar repaints */
1349         search->idle = g_idle_add_full (G_PRIORITY_LOW,
1350                                         pdf_document_search_idle_callback,
1351                                         search,
1352                                         NULL);
1353
1354         search->start_page = start_page;
1355         search->search_page = start_page;
1356
1357         return search;
1358 }
1359
1360 static void
1361 pdf_document_find_begin (EvDocumentFind   *document,
1362                          int               page,
1363                          const char       *search_string,
1364                          gboolean          case_sensitive)
1365 {
1366         PdfDocument *pdf_document = PDF_DOCUMENT (document);
1367
1368         /* FIXME handle case_sensitive (right now XPDF
1369          * code is always case insensitive for ASCII
1370          * and case sensitive for all other languaages)
1371          */
1372
1373         if (pdf_document->search &&
1374             strcmp (search_string, pdf_document->search->text) == 0)
1375                 return;
1376
1377         if (pdf_document->search)
1378                 pdf_document_search_free (pdf_document->search);
1379
1380         pdf_document->search = pdf_document_search_new (pdf_document,
1381                                                         page,
1382                                                         search_string);
1383 }
1384
1385 static int
1386 pdf_document_find_get_n_results (EvDocumentFind *document_find, int page)
1387 {
1388         PdfDocumentSearch *search = PDF_DOCUMENT (document_find)->search;
1389
1390         if (search) {
1391                 return g_list_length (search->pages[page]);
1392         } else {
1393                 return 0;
1394         }
1395 }
1396
1397 static gboolean
1398 pdf_document_find_get_result (EvDocumentFind *document_find,
1399                               int             page,
1400                               int             n_result,
1401                               EvRectangle    *rectangle)
1402 {
1403         PdfDocument *pdf_document = PDF_DOCUMENT (document_find);
1404         PdfDocumentSearch *search = pdf_document->search;
1405         PopplerPage *poppler_page;
1406         PopplerRectangle *r;
1407         double height;
1408
1409         if (search == NULL)
1410                 return FALSE;
1411
1412         r = (PopplerRectangle *) g_list_nth_data (search->pages[page],
1413                                                   n_result);
1414         if (r == NULL)
1415                 return FALSE;
1416
1417         poppler_page = poppler_document_get_page (pdf_document->document, page);
1418         poppler_page_get_size (poppler_page, NULL, &height);
1419         rectangle->x1 = r->x1;
1420         rectangle->y1 = height - r->y2;
1421         rectangle->x2 = r->x2;
1422         rectangle->y2 = height - r->y1;
1423         g_object_unref (poppler_page);
1424                 
1425         return TRUE;
1426 }
1427
1428 static int
1429 pdf_document_find_page_has_results (EvDocumentFind *document_find,
1430                                     int             page)
1431 {
1432         PdfDocumentSearch *search = PDF_DOCUMENT (document_find)->search;
1433
1434         return search && search->pages[page] != NULL;
1435 }
1436
1437 static double
1438 pdf_document_find_get_progress (EvDocumentFind *document_find)
1439 {
1440         PdfDocumentSearch *search;
1441         int n_pages, pages_done;
1442
1443         search = PDF_DOCUMENT (document_find)->search;
1444
1445         if (search == NULL) {
1446                 return 0;
1447         }
1448
1449         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (document_find));
1450         if (search->search_page > search->start_page) {
1451                 pages_done = search->search_page - search->start_page + 1;
1452         } else if (search->search_page == search->start_page) {
1453                 pages_done = n_pages;
1454         } else {
1455                 pages_done = n_pages - search->start_page + search->search_page;
1456         }
1457
1458         return pages_done / (double) n_pages;
1459 }
1460
1461 static void
1462 pdf_document_find_cancel (EvDocumentFind *document)
1463 {
1464         PdfDocument *pdf_document = PDF_DOCUMENT (document);
1465
1466         if (pdf_document->search) {
1467                 pdf_document_search_free (pdf_document->search);
1468                 pdf_document->search = NULL;
1469         }
1470 }
1471
1472 static void
1473 pdf_document_find_iface_init (EvDocumentFindIface *iface)
1474 {
1475         iface->begin = pdf_document_find_begin;
1476         iface->get_n_results = pdf_document_find_get_n_results;
1477         iface->get_result = pdf_document_find_get_result;
1478         iface->page_has_results = pdf_document_find_page_has_results;
1479         iface->get_progress = pdf_document_find_get_progress;
1480         iface->cancel = pdf_document_find_cancel;
1481 }
1482
1483 static const gboolean supported_formats[] = {
1484         TRUE, /* EV_FILE_FORMAT_PS */
1485 #ifdef HAVE_CAIRO_PDF
1486 #ifdef HAVE_POPPLER_PAGE_RENDER
1487         TRUE, /* EV_FILE_FORMAT_PDF */
1488 #else
1489         FALSE, /* EV_FILE_FORMAT_PDF */
1490 #endif
1491 #endif
1492 };
1493
1494 static void
1495 pdf_print_context_free (PdfPrintContext *ctx)
1496 {
1497         if (!ctx)
1498                 return;
1499
1500         if (ctx->ps_file) {
1501                 poppler_ps_file_free (ctx->ps_file);
1502                 ctx->ps_file = NULL;
1503         }
1504 #ifdef HAVE_CAIRO_PDF
1505         if (ctx->pdf_cairo) {
1506                 cairo_destroy (ctx->pdf_cairo);
1507                 ctx->pdf_cairo = NULL;
1508         }
1509 #endif
1510         g_free (ctx);
1511 }
1512
1513 static gboolean
1514 pdf_document_file_exporter_format_supported (EvFileExporter      *exporter,
1515                                              EvFileExporterFormat format)
1516 {
1517         return supported_formats[format];
1518 }
1519
1520 static void
1521 pdf_document_file_exporter_begin (EvFileExporter      *exporter,
1522                                   EvFileExporterFormat format,
1523                                   const char          *filename,
1524                                   int                  first_page,
1525                                   int                  last_page,
1526                                   double               width,
1527                                   double               height,
1528                                   gboolean             duplex)
1529 {
1530         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1531         PdfPrintContext *ctx;
1532
1533         if (pdf_document->print_ctx)
1534                 pdf_print_context_free (pdf_document->print_ctx);
1535         pdf_document->print_ctx = g_new0 (PdfPrintContext, 1);
1536         ctx = pdf_document->print_ctx;
1537         ctx->format = format;
1538         
1539         switch (format) {
1540                 case EV_FILE_FORMAT_PS:
1541                         ctx->ps_file = poppler_ps_file_new (pdf_document->document,
1542                                                             filename, first_page,
1543                                                             last_page - first_page + 1);
1544                         poppler_ps_file_set_paper_size (ctx->ps_file, width, height);
1545                         poppler_ps_file_set_duplex (ctx->ps_file, duplex);
1546
1547                         break;
1548                 case EV_FILE_FORMAT_PDF: {
1549 #ifdef HAVE_CAIRO_PDF
1550                         cairo_surface_t *surface;
1551                         
1552                         surface = cairo_pdf_surface_create (filename, width, height);
1553                         ctx->pdf_cairo = cairo_create (surface);
1554                         cairo_surface_destroy (surface);
1555 #endif
1556                 }
1557                         break;
1558                 default:
1559                         g_assert_not_reached ();
1560         }
1561 }
1562
1563 static void
1564 pdf_document_file_exporter_do_page (EvFileExporter *exporter, EvRenderContext *rc)
1565 {
1566         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1567         PdfPrintContext *ctx = pdf_document->print_ctx;
1568         PopplerPage *poppler_page;
1569
1570         g_return_if_fail (pdf_document->print_ctx != NULL);
1571
1572         poppler_page = poppler_document_get_page (pdf_document->document, rc->page);
1573
1574         switch (ctx->format) {
1575                 case EV_FILE_FORMAT_PS:
1576                         poppler_page_render_to_ps (poppler_page, ctx->ps_file);
1577                         break;
1578                 case EV_FILE_FORMAT_PDF:
1579 #ifdef HAVE_POPPLER_PAGE_RENDER
1580                         poppler_page_render (poppler_page, ctx->pdf_cairo);
1581 #endif
1582 #ifdef HAVE_CAIRO_PDF
1583                         cairo_show_page (ctx->pdf_cairo);
1584 #endif
1585                         break;
1586                 default:
1587                         g_assert_not_reached ();
1588         }
1589         
1590         g_object_unref (poppler_page);
1591 }
1592
1593 static void
1594 pdf_document_file_exporter_end (EvFileExporter *exporter)
1595 {
1596         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1597
1598         pdf_print_context_free (pdf_document->print_ctx);
1599         pdf_document->print_ctx = NULL;
1600 }
1601
1602 static void
1603 pdf_document_file_exporter_iface_init (EvFileExporterIface *iface)
1604 {
1605         iface->format_supported = pdf_document_file_exporter_format_supported;
1606         iface->begin = pdf_document_file_exporter_begin;
1607         iface->do_page = pdf_document_file_exporter_do_page;
1608         iface->end = pdf_document_file_exporter_end;
1609 }
1610
1611 static void
1612 pdf_selection_render_selection (EvSelection      *selection,
1613                                 EvRenderContext  *rc,
1614                                 GdkPixbuf       **pixbuf,
1615                                 EvRectangle      *points,
1616                                 EvRectangle      *old_points,
1617                                 GdkColor        *text,
1618                                 GdkColor        *base)
1619 {
1620         PdfDocument *pdf_document;
1621         double width_points, height_points;
1622         gint width, height;
1623
1624         pdf_document = PDF_DOCUMENT (selection);
1625         set_rc_data (pdf_document, rc);
1626
1627         poppler_page_get_size (POPPLER_PAGE (rc->data), &width_points, &height_points);
1628         width = (int) ((width_points * rc->scale) + 0.5);
1629         height = (int) ((height_points * rc->scale) + 0.5);
1630
1631         if (*pixbuf == NULL) {
1632                 * pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
1633                                            TRUE, 8,
1634                                            width, height);
1635         }
1636         
1637         poppler_page_render_selection (POPPLER_PAGE (rc->data),
1638                                        rc->scale, rc->rotation, *pixbuf,
1639                                        (PopplerRectangle *)points,
1640                                        (PopplerRectangle *)old_points,
1641                                        text,
1642                                        base);
1643 }
1644
1645
1646 static GdkRegion *
1647 pdf_selection_get_selection_region (EvSelection     *selection,
1648                                     EvRenderContext *rc,
1649                                     EvRectangle     *points)
1650 {
1651         PdfDocument *pdf_document;
1652         GdkRegion *retval;
1653
1654         pdf_document = PDF_DOCUMENT (selection);
1655
1656         set_rc_data (pdf_document, rc);
1657
1658         retval = poppler_page_get_selection_region ((PopplerPage *)rc->data, rc->scale, (PopplerRectangle *) points);
1659
1660         return retval;
1661 }
1662
1663 static GdkRegion *
1664 pdf_selection_get_selection_map (EvSelection     *selection,
1665                                  EvRenderContext *rc)
1666 {
1667         PdfDocument *pdf_document;
1668         PopplerPage *poppler_page;
1669         PopplerRectangle points;
1670         GdkRegion *retval;
1671
1672         pdf_document = PDF_DOCUMENT (selection);
1673         poppler_page = poppler_document_get_page (pdf_document->document,
1674                                                   rc->page);
1675
1676         points.x1 = 0.0;
1677         points.y1 = 0.0;
1678         poppler_page_get_size (poppler_page, &(points.x2), &(points.y2));
1679         retval = poppler_page_get_selection_region (poppler_page, 1.0, &points);
1680         g_object_unref (poppler_page);
1681
1682         return retval;
1683 }
1684
1685 static void
1686 pdf_selection_iface_init (EvSelectionIface *iface)
1687 {
1688         iface->render_selection = pdf_selection_render_selection;
1689         iface->get_selection_region = pdf_selection_get_selection_region;
1690         iface->get_selection_map = pdf_selection_get_selection_map;
1691 }
1692
1693 /* Page Transitions */
1694 static gdouble
1695 pdf_document_get_page_duration (EvDocumentTransition *trans,
1696                                 gint                  page)
1697 {
1698 #ifdef HAVE_POPPLER_PAGE_GET_DURATION   
1699         PdfDocument *pdf_document;
1700         PopplerPage *poppler_page;
1701         gdouble      duration = -1;
1702
1703         pdf_document = PDF_DOCUMENT (trans);
1704         poppler_page = poppler_document_get_page (pdf_document->document, page);
1705         if (!poppler_page)
1706                 return -1;
1707
1708         duration = poppler_page_get_duration (poppler_page);
1709         g_object_unref (poppler_page);
1710
1711         return duration;
1712 #else
1713         return -1;
1714 #endif /* HAVE_POPPLER_PAGE_GET_DURATION */
1715 }
1716
1717 static void
1718 pdf_document_page_transition_iface_init (EvDocumentTransitionIface *iface)
1719 {
1720         iface->get_page_duration = pdf_document_get_page_duration;
1721 }
1722
1723 PdfDocument *
1724 pdf_document_new (void)
1725 {
1726         return PDF_DOCUMENT (g_object_new (PDF_TYPE_DOCUMENT, NULL));
1727 }