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