]> www.fi.muni.cz Git - evince.git/blob - pdf/ev-poppler.cc
a90c52413a1c769d0c516460fe8e4d6e6abc8c08
[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
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         switch (layout) {
527                 case POPPLER_PAGE_LAYOUT_SINGLE_PAGE:
528                         info->layout = EV_DOCUMENT_LAYOUT_SINGLE_PAGE;
529                         break;
530                 case POPPLER_PAGE_LAYOUT_ONE_COLUMN:
531                         info->layout = EV_DOCUMENT_LAYOUT_ONE_COLUMN;
532                         break;
533                 case POPPLER_PAGE_LAYOUT_TWO_COLUMN_LEFT:
534                         info->layout = EV_DOCUMENT_LAYOUT_TWO_COLUMN_LEFT;
535                         break;
536                 case POPPLER_PAGE_LAYOUT_TWO_COLUMN_RIGHT:
537                         info->layout = EV_DOCUMENT_LAYOUT_TWO_COLUMN_RIGHT;
538                 case POPPLER_PAGE_LAYOUT_TWO_PAGE_LEFT:
539                         info->layout = EV_DOCUMENT_LAYOUT_TWO_PAGE_LEFT;
540                         break;
541                 case POPPLER_PAGE_LAYOUT_TWO_PAGE_RIGHT:
542                         info->layout = EV_DOCUMENT_LAYOUT_TWO_PAGE_RIGHT;
543                         break;
544                 default:
545                         break;
546         }
547
548         switch (mode) {
549                 case POPPLER_PAGE_MODE_NONE:
550                         info->mode = EV_DOCUMENT_MODE_NONE;
551                         break;
552                 case POPPLER_PAGE_MODE_USE_THUMBS:
553                         info->mode = EV_DOCUMENT_MODE_USE_THUMBS;
554                         break;
555                 case POPPLER_PAGE_MODE_USE_OC:
556                         info->mode = EV_DOCUMENT_MODE_USE_OC;
557                         break;
558                 case POPPLER_PAGE_MODE_FULL_SCREEN:
559                         info->mode = EV_DOCUMENT_MODE_FULL_SCREEN;
560                         break;
561                 case POPPLER_PAGE_MODE_USE_ATTACHMENTS:
562                         info->mode = EV_DOCUMENT_MODE_USE_ATTACHMENTS;
563                 default:
564                         break;
565         }
566
567         info->ui_hints = 0;
568         if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_TOOLBAR) {
569                 info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_TOOLBAR;
570         }
571         if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_MENUBAR) {
572                 info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_MENUBAR;
573         }
574         if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_WINDOWUI) {
575                 info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_WINDOWUI;
576         }
577         if (view_prefs & POPPLER_VIEWER_PREFERENCES_FIT_WINDOW) {
578                 info->ui_hints |= EV_DOCUMENT_UI_HINT_FIT_WINDOW;
579         }
580         if (view_prefs & POPPLER_VIEWER_PREFERENCES_CENTER_WINDOW) {
581                 info->ui_hints |= EV_DOCUMENT_UI_HINT_CENTER_WINDOW;
582         }
583         if (view_prefs & POPPLER_VIEWER_PREFERENCES_DISPLAY_DOC_TITLE) {
584                 info->ui_hints |= EV_DOCUMENT_UI_HINT_DISPLAY_DOC_TITLE;
585         }
586         if (view_prefs & POPPLER_VIEWER_PREFERENCES_DIRECTION_RTL) {
587                 info->ui_hints |=  EV_DOCUMENT_UI_HINT_DIRECTION_RTL;
588         }
589
590         info->permissions = 0;
591         if (permissions & POPPLER_PERMISSIONS_OK_TO_PRINT) {
592                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_PRINT;
593         }
594         if (permissions & POPPLER_PERMISSIONS_OK_TO_MODIFY) {
595                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_MODIFY;
596         }
597         if (permissions & POPPLER_PERMISSIONS_OK_TO_COPY) {
598                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_COPY;
599         }
600         if (permissions & POPPLER_PERMISSIONS_OK_TO_ADD_NOTES) {
601                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_ADD_NOTES;
602         }
603
604         info->n_pages = ev_document_get_n_pages (document);
605
606         if (ev_document_security_has_document_security (EV_DOCUMENT_SECURITY (document))) {
607                 /* translators: this is the document security state */
608                 info->security = g_strdup (_("Yes"));
609         } else {
610                 /* translators: this is the document security state */
611                 info->security = g_strdup (_("No"));
612         }
613
614         return info;
615 }
616
617 static char *
618 pdf_document_get_text (EvDocument *document, int page, EvRectangle *rect)
619 {
620         PdfDocument *pdf_document = PDF_DOCUMENT (document);
621         PopplerPage *poppler_page;
622         PopplerRectangle r;
623         double height;
624         char *text;
625         
626         poppler_page = poppler_document_get_page (pdf_document->document, page);
627         g_return_val_if_fail (poppler_page != NULL, NULL);
628
629         poppler_page_get_size (poppler_page, NULL, &height);
630         r.x1 = rect->x1;
631         r.y1 = height - rect->y2;
632         r.x2 = rect->x2;
633         r.y2 = height - rect->y1;
634
635         text = poppler_page_get_text (poppler_page, &r);
636
637         g_object_unref (poppler_page);
638
639         return text;
640 }
641
642 static void
643 pdf_document_document_iface_init (EvDocumentIface *iface)
644 {
645         iface->save = pdf_document_save;
646         iface->load = pdf_document_load;
647         iface->get_n_pages = pdf_document_get_n_pages;
648         iface->get_page_size = pdf_document_get_page_size;
649         iface->get_page_label = pdf_document_get_page_label;
650         iface->has_attachments = pdf_document_has_attachments;
651         iface->get_attachments = pdf_document_get_attachments;
652         iface->render_pixbuf = pdf_document_render_pixbuf;
653         iface->get_text = pdf_document_get_text;
654         iface->can_get_text = pdf_document_can_get_text;
655         iface->get_info = pdf_document_get_info;
656 };
657
658 static void
659 pdf_document_security_iface_init (EvDocumentSecurityIface *iface)
660 {
661         iface->has_document_security = pdf_document_has_document_security;
662         iface->set_password = pdf_document_set_password;
663 }
664
665 static gdouble
666 pdf_document_fonts_get_progress (EvDocumentFonts *document_fonts)
667 {
668         PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
669         int n_pages;
670
671         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (pdf_document));
672
673         return (double)pdf_document->fonts_scanned_pages / (double)n_pages;
674 }
675
676 static gboolean
677 pdf_document_fonts_scan (EvDocumentFonts *document_fonts,
678                          int              n_pages)
679 {
680         PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
681         gboolean result;
682
683         g_return_val_if_fail (PDF_IS_DOCUMENT (document_fonts), FALSE);
684
685         if (pdf_document->font_info == NULL) { 
686                 pdf_document->font_info = poppler_font_info_new (pdf_document->document);
687         }
688
689         if (pdf_document->fonts_iter) {
690                 poppler_fonts_iter_free (pdf_document->fonts_iter);
691         }
692
693         pdf_document->fonts_scanned_pages += n_pages;
694
695         result = poppler_font_info_scan (pdf_document->font_info, n_pages,
696                                          &pdf_document->fonts_iter);
697         if (!result) {
698                 pdf_document->fonts_scanned_pages = 0;
699                 poppler_font_info_free (pdf_document->font_info);
700                 pdf_document->font_info = NULL; 
701         }
702
703         return result;
704 }
705
706 static const char *
707 font_type_to_string (PopplerFontType type)
708 {
709         switch (type) {
710                 case POPPLER_FONT_TYPE_TYPE1:
711                         return _("Type 1");
712                 case POPPLER_FONT_TYPE_TYPE1C:
713                         return _("Type 1C");
714                 case POPPLER_FONT_TYPE_TYPE3:
715                         return _("Type 3");
716                 case POPPLER_FONT_TYPE_TRUETYPE:
717                         return _("TrueType");
718                 case POPPLER_FONT_TYPE_CID_TYPE0:
719                         return _("Type 1 (CID)");
720                 case POPPLER_FONT_TYPE_CID_TYPE0C:
721                         return _("Type 1C (CID)");
722                 case POPPLER_FONT_TYPE_CID_TYPE2:
723                         return _("TrueType (CID)");
724                 default:
725                         return _("Unknown font type");
726         }
727 }
728
729 static void
730 pdf_document_fonts_fill_model (EvDocumentFonts *document_fonts,
731                                GtkTreeModel    *model)
732 {
733         PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
734         PopplerFontsIter *iter = pdf_document->fonts_iter;
735
736         g_return_if_fail (PDF_IS_DOCUMENT (document_fonts));
737
738         if (!iter)
739                 return;
740
741         do {
742                 GtkTreeIter list_iter;
743                 const char *name;
744                 const char *type;
745                 const char *embedded;
746                 char *details;
747                 
748                 name = poppler_fonts_iter_get_name (iter);
749
750                 if (name == NULL) {
751                         name = _("No name");
752                 }
753
754                 type = font_type_to_string (
755                         poppler_fonts_iter_get_font_type (iter));
756
757                 if (poppler_fonts_iter_is_embedded (iter)) {
758                         if (poppler_fonts_iter_is_subset (iter))
759                                 embedded = _("Embedded subset");
760                         else
761                                 embedded = _("Embedded");
762                 } else {
763                         embedded = _("Not embedded");
764                 }
765
766                 details = g_markup_printf_escaped ("%s\n%s", type, embedded);
767
768                 gtk_list_store_append (GTK_LIST_STORE (model), &list_iter);
769                 gtk_list_store_set (GTK_LIST_STORE (model), &list_iter,
770                                     EV_DOCUMENT_FONTS_COLUMN_NAME, name,
771                                     EV_DOCUMENT_FONTS_COLUMN_DETAILS, details,
772                                     -1);
773
774                 g_free (details);
775         } while (poppler_fonts_iter_next (iter));
776 }
777
778 static void
779 pdf_document_document_fonts_iface_init (EvDocumentFontsIface *iface)
780 {
781         iface->fill_model = pdf_document_fonts_fill_model;
782         iface->scan = pdf_document_fonts_scan;
783         iface->get_progress = pdf_document_fonts_get_progress;
784 }
785
786 static gboolean
787 pdf_document_links_has_document_links (EvDocumentLinks *document_links)
788 {
789         PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
790         PopplerIndexIter *iter;
791
792         g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
793
794         iter = poppler_index_iter_new (pdf_document->document);
795         if (iter == NULL)
796                 return FALSE;
797         poppler_index_iter_free (iter);
798
799         return TRUE;
800 }
801
802 static EvLinkDest *
803 ev_link_dest_from_dest (PdfDocument *pdf_document,
804                         PopplerDest *dest)
805 {
806         EvLinkDest *ev_dest = NULL;
807         const char *unimplemented_dest = NULL;
808
809         g_assert (dest != NULL);
810
811         switch (dest->type) {
812                 case POPPLER_DEST_XYZ: {
813                         PopplerPage *poppler_page;
814                         double height;
815
816                         poppler_page = poppler_document_get_page (pdf_document->document,
817                                                                   MAX (0, dest->page_num - 1));
818                         poppler_page_get_size (poppler_page, NULL, &height);
819                         ev_dest = ev_link_dest_new_xyz (dest->page_num - 1,
820                                                         dest->left,
821                                                         height - dest->top,
822                                                         dest->zoom);
823                         g_object_unref (poppler_page);
824                 }
825                         break;
826                 case POPPLER_DEST_FIT:
827                         ev_dest = ev_link_dest_new_fit (dest->page_num - 1);
828                         break;
829                 case POPPLER_DEST_FITH: {
830                         PopplerPage *poppler_page;
831                         double height;
832
833                         poppler_page = poppler_document_get_page (pdf_document->document,
834                                                                   MAX (0, dest->page_num - 1));
835                         poppler_page_get_size (poppler_page, NULL, &height);
836                         ev_dest = ev_link_dest_new_fith (dest->page_num - 1,
837                                                          height - dest->top);
838                         g_object_unref (poppler_page);
839                 }
840                         break;
841                 case POPPLER_DEST_FITV:
842                         ev_dest = ev_link_dest_new_fitv (dest->page_num - 1,
843                                                          dest->left);
844                         break;
845                 case POPPLER_DEST_FITR: {
846                         PopplerPage *poppler_page;
847                         double height;
848
849                         poppler_page = poppler_document_get_page (pdf_document->document,
850                                                                   MAX (0, dest->page_num - 1));
851                         poppler_page_get_size (poppler_page, NULL, &height);
852                         ev_dest = ev_link_dest_new_fitr (dest->page_num - 1,
853                                                          dest->left,
854                                                          height - dest->bottom,
855                                                          dest->right,
856                                                          height - dest->top);
857                         g_object_unref (poppler_page);
858                 }
859                         break;
860                 case POPPLER_DEST_FITB:
861                         unimplemented_dest = "POPPLER_DEST_FITB";
862                         break;
863                 case POPPLER_DEST_FITBH:
864                         unimplemented_dest = "POPPLER_DEST_FITBH";
865                         break;
866                 case POPPLER_DEST_FITBV:
867                         unimplemented_dest = "POPPLER_DEST_FITBV";
868                         break;
869                 case POPPLER_DEST_NAMED:
870                         ev_dest = ev_link_dest_new_named (dest->named_dest);
871                         break;
872                 case POPPLER_DEST_UNKNOWN:
873                         unimplemented_dest = "POPPLER_DEST_UNKNOWN";
874                         break;
875         }
876
877         if (unimplemented_dest) {
878                 g_warning ("Unimplemented named action: %s, please post a "
879                            "bug report in Evince bugzilla "
880                            "(http://bugzilla.gnome.org) with a testcase.",
881                            unimplemented_dest);
882         }
883
884         if (!ev_dest)
885                 ev_dest = ev_link_dest_new_page (dest->page_num - 1);
886         
887         return ev_dest;
888 }
889
890 static EvLink *
891 ev_link_from_action (PdfDocument   *pdf_document,
892                      PopplerAction *action)
893 {
894         EvLink       *link = NULL;
895         EvLinkAction *ev_action = NULL;
896         const char   *unimplemented_action = NULL;
897
898         switch (action->type) {
899                 case POPPLER_ACTION_GOTO_DEST: {
900                         EvLinkDest *dest;
901                         
902                         dest = ev_link_dest_from_dest (pdf_document, action->goto_dest.dest);
903                         ev_action = ev_link_action_new_dest (dest);
904                 }
905                         break;
906                 case POPPLER_ACTION_GOTO_REMOTE: {
907                         EvLinkDest *dest;
908                         
909                         dest = ev_link_dest_from_dest (pdf_document, action->goto_remote.dest);
910                         ev_action = ev_link_action_new_remote (dest, 
911                                                                action->goto_remote.file_name);
912                         
913                 }
914                         break;
915                 case POPPLER_ACTION_LAUNCH:
916                         ev_action = ev_link_action_new_launch (action->launch.file_name,
917                                                                action->launch.params);
918                         break;
919                 case POPPLER_ACTION_URI:
920                         ev_action = ev_link_action_new_external_uri (action->uri.uri);
921                         break;
922                 case POPPLER_ACTION_NAMED:
923                         ev_action = ev_link_action_new_named (action->named.named_dest);
924                         break;
925                 case POPPLER_ACTION_MOVIE:
926                         unimplemented_action = "POPPLER_ACTION_MOVIE";
927                         break;
928                 case POPPLER_ACTION_UNKNOWN:
929                         unimplemented_action = "POPPLER_ACTION_UNKNOWN";
930         }
931         
932         if (unimplemented_action) {
933                 g_warning ("Unimplemented action: %s, please post a bug report with a testcase.",
934                            unimplemented_action);
935         }
936         
937         link = ev_link_new (action->any.title, ev_action);
938         
939         return link;    
940 }
941
942 static void
943 build_tree (PdfDocument      *pdf_document,
944             GtkTreeModel     *model,
945             GtkTreeIter      *parent,
946             PopplerIndexIter *iter)
947 {
948         
949         do {
950                 GtkTreeIter tree_iter;
951                 PopplerIndexIter *child;
952                 PopplerAction *action;
953                 EvLink *link = NULL;
954                 gboolean expand;
955                 char *title_markup;
956                 
957                 action = poppler_index_iter_get_action (iter);
958                 expand = poppler_index_iter_is_open (iter);
959
960                 if (!action)
961                         continue;
962
963                 switch (action->type) {
964                         case POPPLER_ACTION_GOTO_DEST: {
965                                 /* For bookmarks, solve named destinations */
966                                 if (action->goto_dest.dest->type == POPPLER_DEST_NAMED) {
967                                         PopplerDest *dest;
968                                         EvLinkDest *ev_dest = NULL;
969                                         EvLinkAction *ev_action;
970                                         
971                                         dest = poppler_document_find_dest (pdf_document->document,
972                                                                            action->goto_dest.dest->named_dest);
973                                         if (!dest) {
974                                                 link = ev_link_from_action (pdf_document, action);
975                                                 break;
976                                         }
977                                         
978                                         ev_dest = ev_link_dest_from_dest (pdf_document, dest);
979                                         poppler_dest_free (dest);
980                                         
981                                         ev_action = ev_link_action_new_dest (ev_dest);
982                                         link = ev_link_new (action->any.title, ev_action);
983                                 } else {
984                                         link = ev_link_from_action (pdf_document, action);
985                                 }
986                         }
987                                 break;
988                         default:
989                                 link = ev_link_from_action (pdf_document, action);
990                                 break;
991                 }
992                 
993                 if (!link) {
994                         poppler_action_free (action);
995                         continue;
996                 }
997
998                 gtk_tree_store_append (GTK_TREE_STORE (model), &tree_iter, parent);
999                 title_markup = g_markup_escape_text (ev_link_get_title (link), -1);
1000                 
1001                 gtk_tree_store_set (GTK_TREE_STORE (model), &tree_iter,
1002                                     EV_DOCUMENT_LINKS_COLUMN_MARKUP, title_markup,
1003                                     EV_DOCUMENT_LINKS_COLUMN_LINK, link,
1004                                     EV_DOCUMENT_LINKS_COLUMN_EXPAND, expand,
1005                                     -1);
1006                 
1007                 g_free (title_markup);
1008                 g_object_unref (link);
1009                 
1010                 child = poppler_index_iter_get_child (iter);
1011                 if (child)
1012                         build_tree (pdf_document, model, &tree_iter, child);
1013                 poppler_index_iter_free (child);
1014                 poppler_action_free (action);
1015                 
1016         } while (poppler_index_iter_next (iter));
1017 }
1018
1019 static GtkTreeModel *
1020 pdf_document_links_get_links_model (EvDocumentLinks *document_links)
1021 {
1022         PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
1023         GtkTreeModel *model = NULL;
1024         PopplerIndexIter *iter;
1025         
1026         g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), NULL);
1027
1028         iter = poppler_index_iter_new (pdf_document->document);
1029         /* Create the model if we have items*/
1030         if (iter != NULL) {
1031                 model = (GtkTreeModel *) gtk_tree_store_new (EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS,
1032                                                              G_TYPE_STRING,
1033                                                              G_TYPE_OBJECT,
1034                                                              G_TYPE_BOOLEAN);
1035                 build_tree (pdf_document, model, NULL, iter);
1036                 poppler_index_iter_free (iter);
1037         }
1038         
1039         return model;
1040 }
1041
1042 static GList *
1043 pdf_document_links_get_links (EvDocumentLinks *document_links,
1044                               gint             page)
1045 {
1046         PdfDocument *pdf_document;
1047         PopplerPage *poppler_page;
1048         GList *retval = NULL;
1049         GList *mapping_list;
1050         GList *list;
1051         double height;
1052
1053         pdf_document = PDF_DOCUMENT (document_links);
1054         poppler_page = poppler_document_get_page (pdf_document->document,
1055                                                   page);
1056         mapping_list = poppler_page_get_link_mapping (poppler_page);
1057         poppler_page_get_size (poppler_page, NULL, &height);
1058
1059         for (list = mapping_list; list; list = list->next) {
1060                 PopplerLinkMapping *link_mapping;
1061                 EvLinkMapping *ev_link_mapping;
1062
1063                 link_mapping = (PopplerLinkMapping *)list->data;
1064                 ev_link_mapping = g_new (EvLinkMapping, 1);
1065                 ev_link_mapping->link = ev_link_from_action (pdf_document,
1066                                                              link_mapping->action);
1067                 ev_link_mapping->x1 = link_mapping->area.x1;
1068                 ev_link_mapping->x2 = link_mapping->area.x2;
1069                 /* Invert this for X-style coordinates */
1070                 ev_link_mapping->y1 = height - link_mapping->area.y2;
1071                 ev_link_mapping->y2 = height - link_mapping->area.y1;
1072
1073                 retval = g_list_prepend (retval, ev_link_mapping);
1074         }
1075
1076         poppler_page_free_link_mapping (mapping_list);
1077         g_object_unref (poppler_page);
1078
1079         return g_list_reverse (retval);
1080 }
1081
1082 static EvLinkDest *
1083 pdf_document_links_find_link_dest (EvDocumentLinks  *document_links,
1084                                    const gchar      *link_name)
1085 {
1086         PdfDocument *pdf_document;
1087         PopplerDest *dest;
1088         EvLinkDest *ev_dest = NULL;
1089
1090         pdf_document = PDF_DOCUMENT (document_links);
1091         dest = poppler_document_find_dest (pdf_document->document,
1092                                            link_name);
1093         if (dest) {
1094                 ev_dest = ev_link_dest_from_dest (pdf_document, dest);
1095                 poppler_dest_free (dest);
1096         }
1097
1098         return ev_dest;
1099 }
1100
1101 static void
1102 pdf_document_document_links_iface_init (EvDocumentLinksIface *iface)
1103 {
1104         iface->has_document_links = pdf_document_links_has_document_links;
1105         iface->get_links_model = pdf_document_links_get_links_model;
1106         iface->get_links = pdf_document_links_get_links;
1107         iface->find_link_dest = pdf_document_links_find_link_dest;
1108 }
1109
1110 static GdkPixbuf *
1111 make_thumbnail_for_size (PdfDocument   *pdf_document,
1112                          gint           page,
1113                          int            rotation,
1114                          gint           size)
1115 {
1116         PopplerPage *poppler_page;
1117         GdkPixbuf *pixbuf;
1118         int width, height;
1119         double scale;
1120         gdouble unscaled_width, unscaled_height;
1121
1122         poppler_page = poppler_document_get_page (pdf_document->document, page);
1123         g_return_val_if_fail (poppler_page != NULL, NULL);
1124
1125         pdf_document_thumbnails_get_dimensions (EV_DOCUMENT_THUMBNAILS (pdf_document), page,
1126                                                 size, &width, &height);
1127         poppler_page_get_size (poppler_page, &unscaled_width, &unscaled_height);
1128         scale = width / unscaled_width;
1129
1130         /* rotate */
1131         if (rotation == 90 || rotation == 270) {
1132                 int temp;
1133                 temp = width;
1134                 width = height;
1135                 height = temp;
1136         }
1137
1138         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
1139                                  width, height);
1140         gdk_pixbuf_fill (pixbuf, 0xffffffff);
1141
1142         poppler_page_render_to_pixbuf (poppler_page, 0, 0,
1143                                        width, height,
1144                                        scale, rotation, pixbuf);
1145        
1146
1147         g_object_unref (poppler_page);
1148
1149         return pixbuf;
1150 }
1151
1152 static GdkPixbuf *
1153 pdf_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document_thumbnails,
1154                                        gint                  page,
1155                                        gint                  rotation,
1156                                        gint                  size,
1157                                        gboolean              border)
1158 {
1159         PdfDocument *pdf_document;
1160         PopplerPage *poppler_page;
1161         GdkPixbuf *pixbuf;
1162         GdkPixbuf *border_pixbuf;
1163
1164         pdf_document = PDF_DOCUMENT (document_thumbnails);
1165
1166         poppler_page = poppler_document_get_page (pdf_document->document, page);
1167         g_return_val_if_fail (poppler_page != NULL, NULL);
1168
1169         pixbuf = poppler_page_get_thumbnail (poppler_page);
1170         
1171         if (pixbuf == NULL) {
1172                 /* There is no provided thumbnail.  We need to make one. */
1173                 pixbuf = make_thumbnail_for_size (pdf_document, page, rotation, size);
1174         }
1175
1176         if (border) {           
1177                 border_pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, rotation, pixbuf);
1178                 g_object_unref (pixbuf);
1179                 pixbuf = border_pixbuf;
1180         }               
1181
1182         g_object_unref (poppler_page);
1183         
1184         return pixbuf;
1185 }
1186
1187 static void
1188 pdf_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnails,
1189                                         gint                  page,
1190                                         gint                  size,
1191                                         gint                 *width,
1192                                         gint                 *height)
1193 {
1194         PdfDocument *pdf_document;
1195         PopplerPage *poppler_page;
1196         gint has_thumb;
1197         
1198         pdf_document = PDF_DOCUMENT (document_thumbnails);
1199         poppler_page = poppler_document_get_page (pdf_document->document, page);
1200
1201         g_return_if_fail (width != NULL);
1202         g_return_if_fail (height != NULL);
1203         g_return_if_fail (poppler_page != NULL);
1204
1205         has_thumb = poppler_page_get_thumbnail_size (poppler_page, width, height);
1206
1207         if (!has_thumb) {
1208                 double page_width, page_height;
1209
1210                 poppler_page_get_size (poppler_page, &page_width, &page_height);
1211                 *width = size;
1212                 *height = (int) (size * page_height / page_width);
1213         }
1214         g_object_unref (poppler_page);
1215 }
1216
1217 static void
1218 pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
1219 {
1220         iface->get_thumbnail = pdf_document_thumbnails_get_thumbnail;
1221         iface->get_dimensions = pdf_document_thumbnails_get_dimensions;
1222 }
1223
1224
1225 static gboolean
1226 pdf_document_search_idle_callback (void *data)
1227 {
1228         PdfDocumentSearch *search = (PdfDocumentSearch*) data;
1229         PdfDocument *pdf_document = search->document;
1230         int n_pages;
1231         GList *matches;
1232         PopplerPage *page;
1233
1234         page = poppler_document_get_page (search->document->document,
1235                                           search->search_page);
1236
1237         ev_document_doc_mutex_lock ();
1238         matches = poppler_page_find_text (page, search->text);
1239         ev_document_doc_mutex_unlock ();
1240
1241         g_object_unref (page);
1242
1243         search->pages[search->search_page] = matches;
1244         ev_document_find_changed (EV_DOCUMENT_FIND (pdf_document),
1245                                   search->search_page);
1246
1247         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (search->document));
1248         search->search_page += 1;
1249         if (search->search_page == n_pages) {
1250                 /* wrap around */
1251                 search->search_page = 0;
1252         }
1253
1254         if (search->search_page != search->start_page) {
1255                 return TRUE;
1256         }
1257
1258         /* We're done. */
1259         search->idle = 0; /* will return FALSE to remove */
1260         return FALSE;
1261 }
1262
1263
1264 static PdfDocumentSearch *
1265 pdf_document_search_new (PdfDocument *pdf_document,
1266                          int          start_page,
1267                          const char  *text)
1268 {
1269         PdfDocumentSearch *search;
1270         int n_pages;
1271         int i;
1272
1273         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (pdf_document));
1274
1275         search = g_new0 (PdfDocumentSearch, 1);
1276
1277         search->text = g_strdup (text);
1278         search->pages = g_new0 (GList *, n_pages);
1279         search->document = pdf_document;
1280
1281         /* We add at low priority so the progress bar repaints */
1282         search->idle = g_idle_add_full (G_PRIORITY_LOW,
1283                                         pdf_document_search_idle_callback,
1284                                         search,
1285                                         NULL);
1286
1287         search->start_page = start_page;
1288         search->search_page = start_page;
1289
1290         return search;
1291 }
1292
1293 static void
1294 pdf_document_find_begin (EvDocumentFind   *document,
1295                          int               page,
1296                          const char       *search_string,
1297                          gboolean          case_sensitive)
1298 {
1299         PdfDocument *pdf_document = PDF_DOCUMENT (document);
1300
1301         /* FIXME handle case_sensitive (right now XPDF
1302          * code is always case insensitive for ASCII
1303          * and case sensitive for all other languaages)
1304          */
1305
1306         if (pdf_document->search &&
1307             strcmp (search_string, pdf_document->search->text) == 0)
1308                 return;
1309
1310         if (pdf_document->search)
1311                 pdf_document_search_free (pdf_document->search);
1312
1313         pdf_document->search = pdf_document_search_new (pdf_document,
1314                                                         page,
1315                                                         search_string);
1316 }
1317
1318 int
1319 pdf_document_find_get_n_results (EvDocumentFind *document_find, int page)
1320 {
1321         PdfDocumentSearch *search = PDF_DOCUMENT (document_find)->search;
1322
1323         if (search) {
1324                 return g_list_length (search->pages[page]);
1325         } else {
1326                 return 0;
1327         }
1328 }
1329
1330 gboolean
1331 pdf_document_find_get_result (EvDocumentFind *document_find,
1332                               int             page,
1333                               int             n_result,
1334                               EvRectangle    *rectangle)
1335 {
1336         PdfDocument *pdf_document = PDF_DOCUMENT (document_find);
1337         PdfDocumentSearch *search = pdf_document->search;
1338         PopplerPage *poppler_page;
1339         PopplerRectangle *r;
1340         double height;
1341
1342         if (search == NULL)
1343                 return FALSE;
1344
1345         r = (PopplerRectangle *) g_list_nth_data (search->pages[page],
1346                                                   n_result);
1347         if (r == NULL)
1348                 return FALSE;
1349
1350         poppler_page = poppler_document_get_page (pdf_document->document, page);
1351         poppler_page_get_size (poppler_page, NULL, &height);
1352         rectangle->x1 = r->x1;
1353         rectangle->y1 = height - r->y2;
1354         rectangle->x2 = r->x2;
1355         rectangle->y2 = height - r->y1;
1356         g_object_unref (poppler_page);
1357                 
1358         return TRUE;
1359 }
1360
1361 int
1362 pdf_document_find_page_has_results (EvDocumentFind *document_find,
1363                                     int             page)
1364 {
1365         PdfDocumentSearch *search = PDF_DOCUMENT (document_find)->search;
1366
1367         return search && search->pages[page] != NULL;
1368 }
1369
1370 double
1371 pdf_document_find_get_progress (EvDocumentFind *document_find)
1372 {
1373         PdfDocumentSearch *search;
1374         int n_pages, pages_done;
1375
1376         search = PDF_DOCUMENT (document_find)->search;
1377
1378         if (search == NULL) {
1379                 return 0;
1380         }
1381
1382         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (document_find));
1383         if (search->search_page > search->start_page) {
1384                 pages_done = search->search_page - search->start_page + 1;
1385         } else if (search->search_page == search->start_page) {
1386                 pages_done = n_pages;
1387         } else {
1388                 pages_done = n_pages - search->start_page + search->search_page;
1389         }
1390
1391         return pages_done / (double) n_pages;
1392 }
1393
1394 static void
1395 pdf_document_find_cancel (EvDocumentFind *document)
1396 {
1397         PdfDocument *pdf_document = PDF_DOCUMENT (document);
1398
1399         if (pdf_document->search) {
1400                 pdf_document_search_free (pdf_document->search);
1401                 pdf_document->search = NULL;
1402         }
1403 }
1404
1405 static void
1406 pdf_document_find_iface_init (EvDocumentFindIface *iface)
1407 {
1408         iface->begin = pdf_document_find_begin;
1409         iface->get_n_results = pdf_document_find_get_n_results;
1410         iface->get_result = pdf_document_find_get_result;
1411         iface->page_has_results = pdf_document_find_page_has_results;
1412         iface->get_progress = pdf_document_find_get_progress;
1413         iface->cancel = pdf_document_find_cancel;
1414 }
1415
1416 static const gboolean supported_formats[] = {
1417         TRUE, /* EV_FILE_FORMAT_PS */
1418 #ifdef HAVE_POPPLER_PAGE_RENDER
1419         TRUE, /* EV_FILE_FORMAT_PDF */
1420 #else
1421         FALSE, /* EV_FILE_FORMAT_PDF */
1422 #endif
1423 };
1424
1425 static void
1426 pdf_print_context_free (PdfPrintContext *ctx)
1427 {
1428         if (!ctx)
1429                 return;
1430
1431         if (ctx->ps_file) {
1432                 poppler_ps_file_free (ctx->ps_file);
1433                 ctx->ps_file = NULL;
1434         }
1435
1436         if (ctx->pdf_cairo) {
1437                 cairo_destroy (ctx->pdf_cairo);
1438                 ctx->pdf_cairo = NULL;
1439         }
1440
1441         g_free (ctx);
1442 }
1443
1444 static gboolean
1445 pdf_document_file_exporter_format_supported (EvFileExporter      *exporter,
1446                                              EvFileExporterFormat format)
1447 {
1448         return supported_formats[format];
1449 }
1450
1451 static void
1452 pdf_document_file_exporter_begin (EvFileExporter      *exporter,
1453                                   EvFileExporterFormat format,
1454                                   const char          *filename,
1455                                   int                  first_page,
1456                                   int                  last_page,
1457                                   double               width,
1458                                   double               height,
1459                                   gboolean             duplex)
1460 {
1461         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1462         PdfPrintContext *ctx;
1463
1464         if (pdf_document->print_ctx)
1465                 pdf_print_context_free (pdf_document->print_ctx);
1466         pdf_document->print_ctx = g_new0 (PdfPrintContext, 1);
1467         ctx = pdf_document->print_ctx;
1468         ctx->format = format;
1469         
1470         switch (format) {
1471                 case EV_FILE_FORMAT_PS:
1472                         ctx->ps_file = poppler_ps_file_new (pdf_document->document,
1473                                                             filename, first_page,
1474                                                             last_page - first_page + 1);
1475                         poppler_ps_file_set_paper_size (ctx->ps_file, width, height);
1476                         poppler_ps_file_set_duplex (ctx->ps_file, duplex);
1477
1478                         break;
1479                 case EV_FILE_FORMAT_PDF: {
1480                         cairo_surface_t *surface;
1481                         
1482                         surface = cairo_pdf_surface_create (filename, width, height);
1483                         ctx->pdf_cairo = cairo_create (surface);
1484                         cairo_surface_destroy (surface);
1485                 }
1486                         break;
1487                 default:
1488                         g_assert_not_reached ();
1489         }
1490 }
1491
1492 static void
1493 pdf_document_file_exporter_do_page (EvFileExporter *exporter, EvRenderContext *rc)
1494 {
1495         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1496         PdfPrintContext *ctx = pdf_document->print_ctx;
1497         PopplerPage *poppler_page;
1498
1499         g_return_if_fail (pdf_document->print_ctx != NULL);
1500
1501         poppler_page = poppler_document_get_page (pdf_document->document, rc->page);
1502
1503         switch (ctx->format) {
1504                 case EV_FILE_FORMAT_PS:
1505                         poppler_page_render_to_ps (poppler_page, ctx->ps_file);
1506                         break;
1507                 case EV_FILE_FORMAT_PDF:
1508 #ifdef HAVE_POPPLER_PAGE_RENDER
1509                         poppler_page_render (poppler_page, ctx->pdf_cairo);
1510 #endif
1511                         cairo_show_page (ctx->pdf_cairo);
1512                         break;
1513                 default:
1514                         g_assert_not_reached ();
1515         }
1516         
1517         g_object_unref (poppler_page);
1518 }
1519
1520 static void
1521 pdf_document_file_exporter_end (EvFileExporter *exporter)
1522 {
1523         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1524
1525         pdf_print_context_free (pdf_document->print_ctx);
1526         pdf_document->print_ctx = NULL;
1527 }
1528
1529 static void
1530 pdf_document_file_exporter_iface_init (EvFileExporterIface *iface)
1531 {
1532         iface->format_supported = pdf_document_file_exporter_format_supported;
1533         iface->begin = pdf_document_file_exporter_begin;
1534         iface->do_page = pdf_document_file_exporter_do_page;
1535         iface->end = pdf_document_file_exporter_end;
1536 }
1537
1538 void
1539 pdf_selection_render_selection (EvSelection      *selection,
1540                                 EvRenderContext  *rc,
1541                                 GdkPixbuf       **pixbuf,
1542                                 EvRectangle      *points,
1543                                 EvRectangle      *old_points,
1544                                 GdkColor        *text,
1545                                 GdkColor        *base)
1546 {
1547         PdfDocument *pdf_document;
1548         double width_points, height_points;
1549         gint width, height;
1550
1551         pdf_document = PDF_DOCUMENT (selection);
1552         set_rc_data (pdf_document, rc);
1553
1554         poppler_page_get_size (POPPLER_PAGE (rc->data), &width_points, &height_points);
1555         width = (int) ((width_points * rc->scale) + 0.5);
1556         height = (int) ((height_points * rc->scale) + 0.5);
1557
1558         if (*pixbuf == NULL) {
1559                 * pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
1560                                            TRUE, 8,
1561                                            width, height);
1562         }
1563         
1564         poppler_page_render_selection (POPPLER_PAGE (rc->data),
1565                                        rc->scale, rc->rotation, *pixbuf,
1566                                        (PopplerRectangle *)points,
1567                                        (PopplerRectangle *)old_points,
1568                                        text,
1569                                        base);
1570 }
1571
1572
1573 GdkRegion *
1574 pdf_selection_get_selection_region (EvSelection     *selection,
1575                                     EvRenderContext *rc,
1576                                     EvRectangle     *points)
1577 {
1578         PdfDocument *pdf_document;
1579         GdkRegion *retval;
1580
1581         pdf_document = PDF_DOCUMENT (selection);
1582
1583         set_rc_data (pdf_document, rc);
1584
1585         retval = poppler_page_get_selection_region ((PopplerPage *)rc->data, rc->scale, (PopplerRectangle *) points);
1586
1587         return retval;
1588 }
1589
1590 GdkRegion *
1591 pdf_selection_get_selection_map (EvSelection     *selection,
1592                                  EvRenderContext *rc)
1593 {
1594         PdfDocument *pdf_document;
1595         PopplerPage *poppler_page;
1596         PopplerRectangle points;
1597         GdkRegion *retval;
1598
1599         pdf_document = PDF_DOCUMENT (selection);
1600         poppler_page = poppler_document_get_page (pdf_document->document,
1601                                                   rc->page);
1602
1603         points.x1 = 0.0;
1604         points.y1 = 0.0;
1605         poppler_page_get_size (poppler_page, &(points.x2), &(points.y2));
1606         retval = poppler_page_get_selection_region (poppler_page, 1.0, &points);
1607         g_object_unref (poppler_page);
1608
1609         return retval;
1610 }
1611
1612 static void
1613 pdf_selection_iface_init (EvSelectionIface *iface)
1614 {
1615         iface->render_selection = pdf_selection_render_selection;
1616         iface->get_selection_region = pdf_selection_get_selection_region;
1617         iface->get_selection_map = pdf_selection_get_selection_map;
1618 }
1619
1620 PdfDocument *
1621 pdf_document_new (void)
1622 {
1623         return PDF_DOCUMENT (g_object_new (PDF_TYPE_DOCUMENT, NULL));
1624 }