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