]> www.fi.muni.cz Git - evince.git/blob - pdf/ev-poppler.cc
f6b1d64fa195387d2475d5039b84e8d42c3bfd28
[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 named action: %s, please post a "
835                            "bug report in Evince bugzilla "
836                            "(http://bugzilla.gnome.org) with a testcase.",
837                            unimplemented_dest);
838         }
839
840         if (!ev_dest)
841                 ev_dest = ev_link_dest_new_page (dest->page_num - 1);
842         
843         return ev_dest;
844 }
845
846 static EvLink *
847 ev_link_from_action (PopplerAction *action)
848 {
849         EvLink       *link = NULL;
850         EvLinkAction *ev_action = NULL;
851         const char   *unimplemented_action = NULL;
852
853         switch (action->type) {
854                 case POPPLER_ACTION_GOTO_DEST: {
855                         EvLinkDest *dest;
856                         
857                         dest = ev_link_dest_from_dest (action->goto_dest.dest);
858                         ev_action = ev_link_action_new_dest (dest);
859                 }
860                         break;
861                 case POPPLER_ACTION_GOTO_REMOTE: {
862                         EvLinkDest *dest;
863                         
864                         dest = ev_link_dest_from_dest (action->goto_remote.dest);
865                         ev_action = ev_link_action_new_remote (dest, 
866                                                                action->goto_remote.file_name);
867                         
868                 }
869                         break;
870                 case POPPLER_ACTION_LAUNCH:
871                         ev_action = ev_link_action_new_launch (action->launch.file_name,
872                                                                action->launch.params);
873                         break;
874                 case POPPLER_ACTION_URI:
875                         ev_action = ev_link_action_new_external_uri (action->uri.uri);
876                         break;
877                 case POPPLER_ACTION_NAMED:
878                         ev_action = ev_link_action_new_named (action->named.named_dest);
879                         break;
880                 case POPPLER_ACTION_MOVIE:
881                         unimplemented_action = "POPPLER_ACTION_MOVIE";
882                         break;
883                 case POPPLER_ACTION_UNKNOWN:
884                         unimplemented_action = "POPPLER_ACTION_UNKNOWN";
885         }
886         
887         if (unimplemented_action) {
888                 g_warning ("Unimplemented action: %s, please post a bug report with a testcase.",
889                            unimplemented_action);
890         }
891         
892         link = ev_link_new (action->any.title, ev_action);
893         
894         return link;    
895 }
896
897 static void
898 build_tree (PdfDocument      *pdf_document,
899             GtkTreeModel     *model,
900             GtkTreeIter      *parent,
901             PopplerIndexIter *iter)
902 {
903         
904         do {
905                 GtkTreeIter tree_iter;
906                 PopplerIndexIter *child;
907                 PopplerAction *action;
908                 EvLink *link = NULL;
909                 gboolean expand;
910                 char *title_markup;
911                 
912                 action = poppler_index_iter_get_action (iter);
913                 expand = poppler_index_iter_is_open (iter);
914
915                 if (!action)
916                         continue;
917
918                 switch (action->type) {
919                         case POPPLER_ACTION_GOTO_DEST: {
920                                 /* For bookmarks, solve named destinations */
921                                 if (action->goto_dest.dest->type == POPPLER_DEST_NAMED) {
922                                         PopplerDest *dest;
923                                         EvLinkDest *ev_dest = NULL;
924                                         EvLinkAction *ev_action;
925                                         
926                                         dest = poppler_document_find_dest (pdf_document->document,
927                                                                            action->goto_dest.dest->named_dest);
928                                         if (!dest) {
929                                                 link = ev_link_from_action (action);
930                                                 break;
931                                         }
932                                         
933                                         ev_dest = ev_link_dest_from_dest (dest);
934                                         poppler_dest_free (dest);
935                                         
936                                         ev_action = ev_link_action_new_dest (ev_dest);
937                                         link = ev_link_new (action->any.title, ev_action);
938                                 } else {
939                                         link = ev_link_from_action (action);
940                                 }
941                         }
942                                 break;
943                         default:
944                                 link = ev_link_from_action (action);
945                                 break;
946                 }
947                 
948                 if (!link) {
949                         poppler_action_free (action);
950                         continue;
951                 }
952
953                 gtk_tree_store_append (GTK_TREE_STORE (model), &tree_iter, parent);
954                 title_markup = g_markup_escape_text (ev_link_get_title (link), -1);
955                 
956                 gtk_tree_store_set (GTK_TREE_STORE (model), &tree_iter,
957                                     EV_DOCUMENT_LINKS_COLUMN_MARKUP, title_markup,
958                                     EV_DOCUMENT_LINKS_COLUMN_LINK, link,
959                                     EV_DOCUMENT_LINKS_COLUMN_EXPAND, expand,
960                                     -1);
961                 
962                 g_free (title_markup);
963                 g_object_unref (link);
964                 
965                 child = poppler_index_iter_get_child (iter);
966                 if (child)
967                         build_tree (pdf_document, model, &tree_iter, child);
968                 poppler_index_iter_free (child);
969                 poppler_action_free (action);
970                 
971         } while (poppler_index_iter_next (iter));
972 }
973
974 static GtkTreeModel *
975 pdf_document_links_get_links_model (EvDocumentLinks *document_links)
976 {
977         PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
978         GtkTreeModel *model = NULL;
979         PopplerIndexIter *iter;
980         
981         g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), NULL);
982
983         iter = poppler_index_iter_new (pdf_document->document);
984         /* Create the model if we have items*/
985         if (iter != NULL) {
986                 model = (GtkTreeModel *) gtk_tree_store_new (EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS,
987                                                              G_TYPE_STRING,
988                                                              G_TYPE_OBJECT,
989                                                              G_TYPE_BOOLEAN);
990                 build_tree (pdf_document, model, NULL, iter);
991                 poppler_index_iter_free (iter);
992         }
993         
994         return model;
995 }
996
997 static GList *
998 pdf_document_links_get_links (EvDocumentLinks *document_links,
999                               gint             page)
1000 {
1001         PdfDocument *pdf_document;
1002         PopplerPage *poppler_page;
1003         GList *retval = NULL;
1004         GList *mapping_list;
1005         GList *list;
1006         double height;
1007
1008         pdf_document = PDF_DOCUMENT (document_links);
1009         poppler_page = poppler_document_get_page (pdf_document->document,
1010                                                   page);
1011         mapping_list = poppler_page_get_link_mapping (poppler_page);
1012         poppler_page_get_size (poppler_page, NULL, &height);
1013
1014         for (list = mapping_list; list; list = list->next) {
1015                 PopplerLinkMapping *link_mapping;
1016                 EvLinkMapping *ev_link_mapping;
1017
1018                 link_mapping = (PopplerLinkMapping *)list->data;
1019                 ev_link_mapping = g_new (EvLinkMapping, 1);
1020                 ev_link_mapping->link = ev_link_from_action (link_mapping->action);
1021                 ev_link_mapping->x1 = link_mapping->area.x1;
1022                 ev_link_mapping->x2 = link_mapping->area.x2;
1023                 /* Invert this for X-style coordinates */
1024                 ev_link_mapping->y1 = height - link_mapping->area.y2;
1025                 ev_link_mapping->y2 = height - link_mapping->area.y1;
1026
1027                 retval = g_list_prepend (retval, ev_link_mapping);
1028         }
1029
1030         poppler_page_free_link_mapping (mapping_list);
1031         g_object_unref (poppler_page);
1032
1033         return g_list_reverse (retval);
1034 }
1035
1036 static EvLinkDest *
1037 pdf_document_links_find_link_dest (EvDocumentLinks  *document_links,
1038                                    const gchar      *link_name)
1039 {
1040         PdfDocument *pdf_document;
1041         PopplerDest *dest;
1042         EvLinkDest *ev_dest = NULL;
1043
1044         pdf_document = PDF_DOCUMENT (document_links);
1045         dest = poppler_document_find_dest (pdf_document->document,
1046                                            link_name);
1047         if (dest) {
1048                 ev_dest = ev_link_dest_from_dest (dest);
1049                 poppler_dest_free (dest);
1050         }
1051
1052         return ev_dest;
1053 }
1054
1055 static void
1056 pdf_document_document_links_iface_init (EvDocumentLinksIface *iface)
1057 {
1058         iface->has_document_links = pdf_document_links_has_document_links;
1059         iface->get_links_model = pdf_document_links_get_links_model;
1060         iface->get_links = pdf_document_links_get_links;
1061         iface->find_link_dest = pdf_document_links_find_link_dest;
1062 }
1063
1064 static GdkPixbuf *
1065 make_thumbnail_for_size (PdfDocument   *pdf_document,
1066                          gint           page,
1067                          int            rotation,
1068                          gint           size)
1069 {
1070         PopplerPage *poppler_page;
1071         GdkPixbuf *pixbuf;
1072         int width, height;
1073         double scale;
1074         gdouble unscaled_width, unscaled_height;
1075
1076         poppler_page = poppler_document_get_page (pdf_document->document, page);
1077         g_return_val_if_fail (poppler_page != NULL, NULL);
1078
1079         pdf_document_thumbnails_get_dimensions (EV_DOCUMENT_THUMBNAILS (pdf_document), page,
1080                                                 size, &width, &height);
1081         poppler_page_get_size (poppler_page, &unscaled_width, &unscaled_height);
1082         scale = width / unscaled_width;
1083
1084         /* rotate */
1085         if (rotation == 90 || rotation == 270) {
1086                 int temp;
1087                 temp = width;
1088                 width = height;
1089                 height = temp;
1090         }
1091
1092         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
1093                                  width, height);
1094         gdk_pixbuf_fill (pixbuf, 0xffffffff);
1095
1096         poppler_page_render_to_pixbuf (poppler_page, 0, 0,
1097                                        width, height,
1098                                        scale, rotation, pixbuf);
1099        
1100
1101         g_object_unref (poppler_page);
1102
1103         return pixbuf;
1104 }
1105
1106 static GdkPixbuf *
1107 pdf_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document_thumbnails,
1108                                        gint                  page,
1109                                        gint                  rotation,
1110                                        gint                  size,
1111                                        gboolean              border)
1112 {
1113         PdfDocument *pdf_document;
1114         PopplerPage *poppler_page;
1115         GdkPixbuf *pixbuf;
1116         GdkPixbuf *border_pixbuf;
1117
1118         pdf_document = PDF_DOCUMENT (document_thumbnails);
1119
1120         poppler_page = poppler_document_get_page (pdf_document->document, page);
1121         g_return_val_if_fail (poppler_page != NULL, NULL);
1122
1123         pixbuf = poppler_page_get_thumbnail (poppler_page);
1124         
1125         if (pixbuf == NULL) {
1126                 /* There is no provided thumbnail.  We need to make one. */
1127                 pixbuf = make_thumbnail_for_size (pdf_document, page, rotation, size);
1128         }
1129
1130         if (border) {           
1131                 border_pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, rotation, pixbuf);
1132                 g_object_unref (pixbuf);
1133                 pixbuf = border_pixbuf;
1134         }               
1135
1136         g_object_unref (poppler_page);
1137         
1138         return pixbuf;
1139 }
1140
1141 static void
1142 pdf_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnails,
1143                                         gint                  page,
1144                                         gint                  size,
1145                                         gint                 *width,
1146                                         gint                 *height)
1147 {
1148         PdfDocument *pdf_document;
1149         PopplerPage *poppler_page;
1150         gint has_thumb;
1151         
1152         pdf_document = PDF_DOCUMENT (document_thumbnails);
1153         poppler_page = poppler_document_get_page (pdf_document->document, page);
1154
1155         g_return_if_fail (width != NULL);
1156         g_return_if_fail (height != NULL);
1157         g_return_if_fail (poppler_page != NULL);
1158
1159         has_thumb = poppler_page_get_thumbnail_size (poppler_page, width, height);
1160
1161         if (!has_thumb) {
1162                 double page_width, page_height;
1163
1164                 poppler_page_get_size (poppler_page, &page_width, &page_height);
1165                 *width = size;
1166                 *height = (int) (size * page_height / page_width);
1167         }
1168         g_object_unref (poppler_page);
1169 }
1170
1171 static void
1172 pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
1173 {
1174         iface->get_thumbnail = pdf_document_thumbnails_get_thumbnail;
1175         iface->get_dimensions = pdf_document_thumbnails_get_dimensions;
1176 }
1177
1178
1179 static gboolean
1180 pdf_document_search_idle_callback (void *data)
1181 {
1182         PdfDocumentSearch *search = (PdfDocumentSearch*) data;
1183         PdfDocument *pdf_document = search->document;
1184         int n_pages;
1185         GList *matches;
1186         PopplerPage *page;
1187
1188         page = poppler_document_get_page (search->document->document,
1189                                           search->search_page);
1190
1191         ev_document_doc_mutex_lock ();
1192         matches = poppler_page_find_text (page, search->text);
1193         ev_document_doc_mutex_unlock ();
1194
1195         g_object_unref (page);
1196
1197         search->pages[search->search_page] = matches;
1198         ev_document_find_changed (EV_DOCUMENT_FIND (pdf_document),
1199                                   search->search_page);
1200
1201         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (search->document));
1202         search->search_page += 1;
1203         if (search->search_page == n_pages) {
1204                 /* wrap around */
1205                 search->search_page = 0;
1206         }
1207
1208         if (search->search_page != search->start_page) {
1209                 return TRUE;
1210         }
1211
1212         /* We're done. */
1213         search->idle = 0; /* will return FALSE to remove */
1214         return FALSE;
1215 }
1216
1217
1218 static PdfDocumentSearch *
1219 pdf_document_search_new (PdfDocument *pdf_document,
1220                          int          start_page,
1221                          const char  *text)
1222 {
1223         PdfDocumentSearch *search;
1224         int n_pages;
1225         int i;
1226
1227         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (pdf_document));
1228
1229         search = g_new0 (PdfDocumentSearch, 1);
1230
1231         search->text = g_strdup (text);
1232         search->pages = g_new0 (GList *, n_pages);
1233         for (i = 0; i < n_pages; i++) {
1234                 search->pages[i] = NULL;
1235         }
1236
1237         search->document = pdf_document;
1238
1239         /* We add at low priority so the progress bar repaints */
1240         search->idle = g_idle_add_full (G_PRIORITY_LOW,
1241                                         pdf_document_search_idle_callback,
1242                                         search,
1243                                         NULL);
1244
1245         search->start_page = start_page;
1246         search->search_page = start_page;
1247
1248         return search;
1249 }
1250
1251 static void
1252 pdf_document_find_begin (EvDocumentFind   *document,
1253                          int               page,
1254                          const char       *search_string,
1255                          gboolean          case_sensitive)
1256 {
1257         PdfDocument *pdf_document = PDF_DOCUMENT (document);
1258
1259         /* FIXME handle case_sensitive (right now XPDF
1260          * code is always case insensitive for ASCII
1261          * and case sensitive for all other languaages)
1262          */
1263
1264         if (pdf_document->search &&
1265             strcmp (search_string, pdf_document->search->text) == 0)
1266                 return;
1267
1268         if (pdf_document->search)
1269                 pdf_document_search_free (pdf_document->search);
1270
1271         pdf_document->search = pdf_document_search_new (pdf_document,
1272                                                         page,
1273                                                         search_string);
1274 }
1275
1276 int
1277 pdf_document_find_get_n_results (EvDocumentFind *document_find, int page)
1278 {
1279         PdfDocumentSearch *search = PDF_DOCUMENT (document_find)->search;
1280
1281         if (search) {
1282                 return g_list_length (search->pages[page]);
1283         } else {
1284                 return 0;
1285         }
1286 }
1287
1288 gboolean
1289 pdf_document_find_get_result (EvDocumentFind *document_find,
1290                               int             page,
1291                               int             n_result,
1292                               EvRectangle    *rectangle)
1293 {
1294         PdfDocument *pdf_document = PDF_DOCUMENT (document_find);
1295         PdfDocumentSearch *search = pdf_document->search;
1296         PopplerPage *poppler_page;
1297         PopplerRectangle *r;
1298         double height;
1299
1300         if (search == NULL)
1301                 return FALSE;
1302
1303         r = (PopplerRectangle *) g_list_nth_data (search->pages[page],
1304                                                   n_result);
1305         if (r == NULL)
1306                 return FALSE;
1307
1308         poppler_page = poppler_document_get_page (pdf_document->document, page);
1309         poppler_page_get_size (poppler_page, NULL, &height);
1310         rectangle->x1 = r->x1;
1311         rectangle->y1 = height - r->y2;
1312         rectangle->x2 = r->x2;
1313         rectangle->y2 = height - r->y1;
1314         g_object_unref (poppler_page);
1315                 
1316         return TRUE;
1317 }
1318
1319 int
1320 pdf_document_find_page_has_results (EvDocumentFind *document_find,
1321                                     int             page)
1322 {
1323         PdfDocumentSearch *search = PDF_DOCUMENT (document_find)->search;
1324
1325         return search && search->pages[page] != NULL;
1326 }
1327
1328 double
1329 pdf_document_find_get_progress (EvDocumentFind *document_find)
1330 {
1331         PdfDocumentSearch *search;
1332         int n_pages, pages_done;
1333
1334         search = PDF_DOCUMENT (document_find)->search;
1335
1336         if (search == NULL) {
1337                 return 0;
1338         }
1339
1340         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (document_find));
1341         if (search->search_page > search->start_page) {
1342                 pages_done = search->search_page - search->start_page + 1;
1343         } else if (search->search_page == search->start_page) {
1344                 pages_done = n_pages;
1345         } else {
1346                 pages_done = n_pages - search->start_page + search->search_page;
1347         }
1348
1349         return pages_done / (double) n_pages;
1350 }
1351
1352 static void
1353 pdf_document_find_cancel (EvDocumentFind *document)
1354 {
1355         PdfDocument *pdf_document = PDF_DOCUMENT (document);
1356
1357         if (pdf_document->search) {
1358                 pdf_document_search_free (pdf_document->search);
1359                 pdf_document->search = NULL;
1360         }
1361 }
1362
1363 static void
1364 pdf_document_find_iface_init (EvDocumentFindIface *iface)
1365 {
1366         iface->begin = pdf_document_find_begin;
1367         iface->get_n_results = pdf_document_find_get_n_results;
1368         iface->get_result = pdf_document_find_get_result;
1369         iface->page_has_results = pdf_document_find_page_has_results;
1370         iface->get_progress = pdf_document_find_get_progress;
1371         iface->cancel = pdf_document_find_cancel;
1372 }
1373
1374 static void
1375 pdf_document_ps_exporter_begin (EvPSExporter *exporter, const char *filename,
1376                                 int first_page, int last_page,
1377                                 double width, double height, gboolean duplex)
1378 {
1379         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1380         
1381         pdf_document->ps_file = poppler_ps_file_new (pdf_document->document, filename,
1382                                                      first_page,
1383                                                      last_page - first_page + 1);
1384         poppler_ps_file_set_paper_size (pdf_document->ps_file, width, height);
1385         poppler_ps_file_set_duplex (pdf_document->ps_file, duplex);
1386 }
1387
1388 static void
1389 pdf_document_ps_exporter_do_page (EvPSExporter *exporter, EvRenderContext *rc)
1390 {
1391         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1392         PopplerPage *poppler_page;
1393
1394         g_return_if_fail (pdf_document->ps_file != NULL);
1395
1396         poppler_page = poppler_document_get_page (pdf_document->document, rc->page);
1397         poppler_page_render_to_ps (poppler_page, pdf_document->ps_file);
1398         g_object_unref (poppler_page);
1399 }
1400
1401 static void
1402 pdf_document_ps_exporter_end (EvPSExporter *exporter)
1403 {
1404         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1405
1406         poppler_ps_file_free (pdf_document->ps_file);
1407         pdf_document->ps_file = NULL;
1408 }
1409
1410 static void
1411 pdf_document_ps_exporter_iface_init (EvPSExporterIface *iface)
1412 {
1413         iface->begin = pdf_document_ps_exporter_begin;
1414         iface->do_page = pdf_document_ps_exporter_do_page;
1415         iface->end = pdf_document_ps_exporter_end;
1416 }
1417
1418
1419 void
1420 pdf_selection_render_selection (EvSelection      *selection,
1421                                 EvRenderContext  *rc,
1422                                 GdkPixbuf       **pixbuf,
1423                                 EvRectangle      *points,
1424                                 EvRectangle      *old_points,
1425                                 GdkColor        *text,
1426                                 GdkColor        *base)
1427 {
1428         PdfDocument *pdf_document;
1429         double width_points, height_points;
1430         gint width, height;
1431
1432         pdf_document = PDF_DOCUMENT (selection);
1433         set_rc_data (pdf_document, rc);
1434
1435         poppler_page_get_size (POPPLER_PAGE (rc->data), &width_points, &height_points);
1436         width = (int) ((width_points * rc->scale) + 0.5);
1437         height = (int) ((height_points * rc->scale) + 0.5);
1438
1439         if (*pixbuf == NULL) {
1440                 * pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
1441                                            TRUE, 8,
1442                                            width, height);
1443         }
1444         
1445         poppler_page_render_selection (POPPLER_PAGE (rc->data),
1446                                        rc->scale, rc->rotation, *pixbuf,
1447                                        (PopplerRectangle *)points,
1448                                        (PopplerRectangle *)old_points,
1449                                        text,
1450                                        base);
1451 }
1452
1453
1454 GdkRegion *
1455 pdf_selection_get_selection_region (EvSelection     *selection,
1456                                     EvRenderContext *rc,
1457                                     EvRectangle     *points)
1458 {
1459         PdfDocument *pdf_document;
1460         GdkRegion *retval;
1461
1462         pdf_document = PDF_DOCUMENT (selection);
1463
1464         set_rc_data (pdf_document, rc);
1465
1466         retval = poppler_page_get_selection_region ((PopplerPage *)rc->data, rc->scale, (PopplerRectangle *) points);
1467
1468         return retval;
1469 }
1470
1471 GdkRegion *
1472 pdf_selection_get_selection_map (EvSelection     *selection,
1473                                  EvRenderContext *rc)
1474 {
1475         PdfDocument *pdf_document;
1476         PopplerPage *poppler_page;
1477         PopplerRectangle points;
1478         GdkRegion *retval;
1479
1480         pdf_document = PDF_DOCUMENT (selection);
1481         poppler_page = poppler_document_get_page (pdf_document->document,
1482                                                   rc->page);
1483
1484         points.x1 = 0.0;
1485         points.y1 = 0.0;
1486         poppler_page_get_size (poppler_page, &(points.x2), &(points.y2));
1487         retval = poppler_page_get_selection_region (poppler_page, 1.0, &points);
1488         g_object_unref (poppler_page);
1489
1490         return retval;
1491 }
1492
1493 static void
1494 pdf_selection_iface_init (EvSelectionIface *iface)
1495 {
1496         iface->render_selection = pdf_selection_render_selection;
1497         iface->get_selection_region = pdf_selection_get_selection_region;
1498         iface->get_selection_map = pdf_selection_get_selection_map;
1499 }
1500
1501 PdfDocument *
1502 pdf_document_new (void)
1503 {
1504         return PDF_DOCUMENT (g_object_new (PDF_TYPE_DOCUMENT, NULL));
1505 }