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