]> www.fi.muni.cz Git - evince.git/blob - pdf/ev-poppler.cc
2c5b5265b3a4e2263948602db7ba3cb9bd397034
[evince.git] / pdf / ev-poppler.cc
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /* pdfdocument.h: Implementation of EvDocument for PDF
3  * Copyright (C) 2004, Red Hat, Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #include <math.h>
21 #include <string.h>
22 #include <gtk/gtk.h>
23 #include <poppler.h>
24 #include <poppler-document.h>
25 #include <poppler-page.h>
26 #include <glib/gi18n.h>
27
28 #include "ev-poppler.h"
29 #include "ev-ps-exporter.h"
30 #include "ev-document-find.h"
31 #include "ev-document-misc.h"
32 #include "ev-document-links.h"
33 #include "ev-document-fonts.h"
34 #include "ev-document-security.h"
35 #include "ev-document-thumbnails.h"
36 #include "ev-selection.h"
37
38 typedef struct {
39         PdfDocument *document;
40         char *text;
41         GList **pages;
42         guint idle;
43         int start_page;
44         int search_page;
45 } PdfDocumentSearch;
46
47 struct _PdfDocumentClass
48 {
49         GObjectClass parent_class;
50 };
51
52 struct _PdfDocument
53 {
54         GObject parent_instance;
55
56         PopplerDocument *document;
57         PopplerPSFile *ps_file;
58         gchar *password;
59
60         PopplerFontInfo *font_info;
61         PopplerFontsIter *fonts_iter;
62         int fonts_scanned_pages;
63
64         PdfDocumentSearch *search;
65 };
66
67 static void pdf_document_document_iface_init            (EvDocumentIface           *iface);
68 static void pdf_document_security_iface_init            (EvDocumentSecurityIface   *iface);
69 static void pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface);
70 static void pdf_document_document_links_iface_init      (EvDocumentLinksIface      *iface);
71 static void pdf_document_document_fonts_iface_init      (EvDocumentFontsIface      *iface);
72 static void pdf_document_find_iface_init                (EvDocumentFindIface       *iface);
73 static void pdf_document_ps_exporter_iface_init         (EvPSExporterIface         *iface);
74 static void pdf_selection_iface_init                    (EvSelectionIface          *iface);
75 static void pdf_document_thumbnails_get_dimensions      (EvDocumentThumbnails      *document_thumbnails,
76                                                          gint                       page,
77                                                          gint                       size,
78                                                          gint                      *width,
79                                                          gint                      *height);
80 static int  pdf_document_get_n_pages                    (EvDocument                *document);
81
82 static EvLink * ev_link_from_action (PopplerAction *action);
83 static void pdf_document_search_free (PdfDocumentSearch   *search);
84
85
86 G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT,
87                          {
88                                  G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
89                                                         pdf_document_document_iface_init);
90                                  G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_SECURITY,
91                                                         pdf_document_security_iface_init);
92                                  G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
93                                                         pdf_document_document_thumbnails_iface_init);
94                                  G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_LINKS,
95                                                         pdf_document_document_links_iface_init);
96                                  G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FONTS,
97                                                         pdf_document_document_fonts_iface_init);
98                                  G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FIND,
99                                                         pdf_document_find_iface_init);
100                                  G_IMPLEMENT_INTERFACE (EV_TYPE_PS_EXPORTER,
101                                                         pdf_document_ps_exporter_iface_init);
102                                  G_IMPLEMENT_INTERFACE (EV_TYPE_SELECTION,
103                                                         pdf_selection_iface_init);
104                          });
105
106 static void
107 pdf_document_search_free (PdfDocumentSearch   *search)
108 {
109         PdfDocument *pdf_document = search->document;
110         int n_pages;
111         int i;
112
113         if (search->idle != 0)
114                 g_source_remove (search->idle);
115
116         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (pdf_document));
117         for (i = 0; i < n_pages; i++) {
118                 g_list_foreach (search->pages[i], (GFunc) g_free, NULL);
119                 g_list_free (search->pages[i]);
120         }
121         
122         g_free (search->text);
123 }
124
125 static void
126 pdf_document_dispose (GObject *object)
127 {
128         PdfDocument *pdf_document = PDF_DOCUMENT(object);
129
130         if (pdf_document->search) {
131                 pdf_document_search_free (pdf_document->search);
132                 pdf_document->search = NULL;
133         }
134
135         if (pdf_document->document) {
136                 g_object_unref (pdf_document->document);
137         }
138
139         if (pdf_document->font_info) { 
140                 poppler_font_info_free (pdf_document->font_info);
141         }
142
143         if (pdf_document->fonts_iter) {
144                 poppler_fonts_iter_free (pdf_document->fonts_iter);
145         }
146 }
147
148 static void
149 pdf_document_class_init (PdfDocumentClass *klass)
150 {
151         GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
152
153         g_object_class->dispose = pdf_document_dispose;
154 }
155
156 static void
157 pdf_document_init (PdfDocument *pdf_document)
158 {
159         pdf_document->password = NULL;
160 }
161
162 static void
163 convert_error (GError  *poppler_error,
164                GError **error)
165 {
166         if (poppler_error == NULL)
167                 return;
168
169         if (poppler_error->domain == POPPLER_ERROR) {
170                 /* convert poppler errors into EvDocument errors */
171                 gint code = EV_DOCUMENT_ERROR_INVALID;
172                 if (poppler_error->code == POPPLER_ERROR_INVALID)
173                         code = EV_DOCUMENT_ERROR_INVALID;
174                 else if (poppler_error->code == POPPLER_ERROR_ENCRYPTED)
175                         code = EV_DOCUMENT_ERROR_ENCRYPTED;
176                         
177
178                 g_set_error (error,
179                              EV_DOCUMENT_ERROR,
180                              code,
181                              poppler_error->message,
182                              NULL);
183         } else {
184                 g_propagate_error (error, poppler_error);
185         }
186 }
187
188
189 /* EvDocument */
190 static gboolean
191 pdf_document_save (EvDocument  *document,
192                    const char  *uri,
193                    GError     **error)
194 {
195         gboolean retval;
196         GError *poppler_error = NULL;
197
198         retval = poppler_document_save (PDF_DOCUMENT (document)->document,
199                                         uri,
200                                         &poppler_error);
201         if (! retval)
202                 convert_error (poppler_error, error);
203
204         return retval;
205 }
206
207 static gboolean
208 pdf_document_load (EvDocument   *document,
209                    const char   *uri,
210                    GError      **error)
211 {
212         GError *poppler_error = NULL;
213         PdfDocument *pdf_document = PDF_DOCUMENT (document);
214
215         pdf_document->document =
216                 poppler_document_new_from_file (uri, pdf_document->password, &poppler_error);
217
218         if (pdf_document->document == NULL) {
219                 convert_error (poppler_error, error);
220                 return FALSE;
221         }
222
223         return TRUE;
224 }
225
226 static int
227 pdf_document_get_n_pages (EvDocument *document)
228 {
229         return poppler_document_get_n_pages (PDF_DOCUMENT (document)->document);
230 }
231
232 static void
233 set_page_orientation (PdfDocument *pdf_document, PopplerPage *page, int rotation)
234 {
235         PopplerOrientation orientation;
236         int r = rotation;
237
238         orientation = poppler_page_get_orientation (page);
239
240         while (r > 0) {
241                 if (orientation == POPPLER_ORIENTATION_PORTRAIT) {
242                         orientation = POPPLER_ORIENTATION_LANDSCAPE;
243                 } else if (orientation == POPPLER_ORIENTATION_LANDSCAPE) {
244                         orientation = POPPLER_ORIENTATION_UPSIDEDOWN;
245                 } else if (orientation == POPPLER_ORIENTATION_UPSIDEDOWN) {
246                         orientation = POPPLER_ORIENTATION_SEASCAPE;
247                 } else {
248                         orientation = POPPLER_ORIENTATION_PORTRAIT;
249                 }
250                 r -= 90;
251         }
252
253         poppler_page_set_orientation (page, orientation);
254 }
255
256 static void
257 pdf_document_get_page_size (EvDocument   *document,
258                             int           page,
259                             double       *width,
260                             double       *height)
261 {
262         PdfDocument *pdf_document = PDF_DOCUMENT (document);
263         PopplerPage *poppler_page;
264
265         poppler_page = poppler_document_get_page (pdf_document->document, page);
266         poppler_page_get_size (poppler_page, width, height);
267         g_object_unref (poppler_page);
268 }
269
270 static char *
271 pdf_document_get_page_label (EvDocument *document,
272                              int         page)
273 {
274         PopplerPage *poppler_page;
275         char *label = NULL;
276
277         poppler_page = poppler_document_get_page (PDF_DOCUMENT (document)->document,
278                                                   page);
279
280         g_object_get (G_OBJECT (poppler_page),
281                       "label", &label,
282                       NULL);
283         g_object_unref (poppler_page);
284
285         return label;
286 }
287
288 static GList *
289 pdf_document_get_links (EvDocument *document,
290                         int         page)
291 {
292         PdfDocument *pdf_document;
293         PopplerPage *poppler_page;
294         GList *retval = NULL;
295         GList *mapping_list;
296         GList *list;
297         double height;
298
299         pdf_document = PDF_DOCUMENT (document);
300         poppler_page = poppler_document_get_page (pdf_document->document,
301                                                   page);
302         mapping_list = poppler_page_get_link_mapping (poppler_page);
303         poppler_page_get_size (poppler_page, NULL, &height);
304
305         for (list = mapping_list; list; list = list->next) {
306                 PopplerLinkMapping *link_mapping;
307                 EvLinkMapping *ev_link_mapping;
308
309                 link_mapping = (PopplerLinkMapping *)list->data;
310                 ev_link_mapping = g_new (EvLinkMapping, 1);
311                 ev_link_mapping->link = ev_link_from_action (link_mapping->action);
312                 ev_link_mapping->x1 = link_mapping->area.x1;
313                 ev_link_mapping->x2 = link_mapping->area.x2;
314                 /* Invert this for X-style coordinates */
315                 ev_link_mapping->y1 = height - link_mapping->area.y2;
316                 ev_link_mapping->y2 = height - link_mapping->area.y1;
317
318                 retval = g_list_prepend (retval, ev_link_mapping);
319         }
320
321         poppler_page_free_link_mapping (mapping_list);
322         g_object_unref (poppler_page);
323
324         return g_list_reverse (retval);
325 }
326                         
327
328 static GdkPixbuf *
329 pdf_document_render_pixbuf (EvDocument   *document,
330                             EvRenderContext *rc)
331 {
332         PdfDocument *pdf_document;
333         PopplerPage *poppler_page;
334         GdkPixbuf *pixbuf;
335         double width_points, height_points;
336         gint width, height;
337
338         pdf_document = PDF_DOCUMENT (document);
339         poppler_page = poppler_document_get_page (pdf_document->document,
340                                                   rc->page);
341         set_page_orientation (pdf_document, poppler_page, rc->rotation);
342
343         poppler_page_get_size (poppler_page, &width_points, &height_points);
344         width = (int) ((width_points * rc->scale) + 0.5);
345         height = (int) ((height_points * rc->scale) + 0.5);
346
347         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
348                                  FALSE, 8,
349                                  width, height);
350
351         poppler_page_render_to_pixbuf (poppler_page,
352                                        0, 0,
353                                        width, height,
354                                        rc->scale,
355                                        pixbuf);
356         
357         g_object_unref (poppler_page);
358         
359         return pixbuf;
360 }
361
362 /* EvDocumentSecurity */
363
364 static gboolean
365 pdf_document_has_document_security (EvDocumentSecurity *document_security)
366 {
367         /* FIXME: do we really need to have this? */
368         return FALSE;
369 }
370
371 static void
372 pdf_document_set_password (EvDocumentSecurity *document_security,
373                            const char         *password)
374 {
375         PdfDocument *document = PDF_DOCUMENT (document_security);
376
377         if (document->password)
378                 g_free (document->password);
379
380         document->password = g_strdup (password);
381 }
382
383 static gboolean
384 pdf_document_can_get_text (EvDocument *document)
385 {
386         return TRUE;
387 }
388
389 static EvDocumentInfo *
390 pdf_document_get_info (EvDocument *document)
391 {
392         EvDocumentInfo *info;
393         PopplerPageLayout layout;
394         PopplerPageMode mode;
395         PopplerViewerPreferences view_prefs;
396         PopplerPermissions permissions;
397
398         info = g_new0 (EvDocumentInfo, 1);
399
400         info->fields_mask = EV_DOCUMENT_INFO_TITLE |
401                             EV_DOCUMENT_INFO_FORMAT |
402                             EV_DOCUMENT_INFO_AUTHOR |
403                             EV_DOCUMENT_INFO_SUBJECT |
404                             EV_DOCUMENT_INFO_KEYWORDS |
405                             EV_DOCUMENT_INFO_LAYOUT |
406                             EV_DOCUMENT_INFO_START_MODE |
407                             EV_DOCUMENT_INFO_PERMISSIONS |
408                             EV_DOCUMENT_INFO_UI_HINTS |
409                             EV_DOCUMENT_INFO_CREATOR |
410                             EV_DOCUMENT_INFO_PRODUCER |
411                             EV_DOCUMENT_INFO_CREATION_DATE |
412                             EV_DOCUMENT_INFO_MOD_DATE |
413                             EV_DOCUMENT_INFO_LINEARIZED |
414                             EV_DOCUMENT_INFO_N_PAGES |
415                             EV_DOCUMENT_INFO_SECURITY;
416
417
418         g_object_get (PDF_DOCUMENT (document)->document,
419                       "title", &(info->title),
420                       "format", &(info->format),
421                       "author", &(info->author),
422                       "subject", &(info->subject),
423                       "keywords", &(info->keywords),
424                       "page-mode", &mode,
425                       "page-layout", &layout,
426                       "viewer-preferences", &view_prefs,
427                       "permissions", &permissions,
428                       "creator", &(info->creator),
429                       "producer", &(info->producer),
430                       "creation-date", &(info->creation_date),
431                       "mod-date", &(info->modified_date),
432                       "linearized", &(info->linearized),
433                       NULL);
434
435         switch (layout) {
436                 case POPPLER_PAGE_LAYOUT_SINGLE_PAGE:
437                         info->layout = EV_DOCUMENT_LAYOUT_SINGLE_PAGE;
438                         break;
439                 case POPPLER_PAGE_LAYOUT_ONE_COLUMN:
440                         info->layout = EV_DOCUMENT_LAYOUT_ONE_COLUMN;
441                         break;
442                 case POPPLER_PAGE_LAYOUT_TWO_COLUMN_LEFT:
443                         info->layout = EV_DOCUMENT_LAYOUT_TWO_COLUMN_LEFT;
444                         break;
445                 case POPPLER_PAGE_LAYOUT_TWO_COLUMN_RIGHT:
446                         info->layout = EV_DOCUMENT_LAYOUT_TWO_COLUMN_RIGHT;
447                 case POPPLER_PAGE_LAYOUT_TWO_PAGE_LEFT:
448                         info->layout = EV_DOCUMENT_LAYOUT_TWO_PAGE_LEFT;
449                         break;
450                 case POPPLER_PAGE_LAYOUT_TWO_PAGE_RIGHT:
451                         info->layout = EV_DOCUMENT_LAYOUT_TWO_PAGE_RIGHT;
452                         break;
453                 default:
454                         break;
455         }
456
457         switch (mode) {
458                 case POPPLER_PAGE_MODE_NONE:
459                         info->mode = EV_DOCUMENT_MODE_NONE;
460                         break;
461                 case POPPLER_PAGE_MODE_USE_THUMBS:
462                         info->mode = EV_DOCUMENT_MODE_USE_THUMBS;
463                         break;
464                 case POPPLER_PAGE_MODE_USE_OC:
465                         info->mode = EV_DOCUMENT_MODE_USE_OC;
466                         break;
467                 case POPPLER_PAGE_MODE_FULL_SCREEN:
468                         info->mode = EV_DOCUMENT_MODE_FULL_SCREEN;
469                         break;
470                 case POPPLER_PAGE_MODE_USE_ATTACHMENTS:
471                         info->mode = EV_DOCUMENT_MODE_USE_ATTACHMENTS;
472                 default:
473                         break;
474         }
475
476         info->ui_hints = 0;
477         if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_TOOLBAR) {
478                 info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_TOOLBAR;
479         }
480         if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_MENUBAR) {
481                 info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_MENUBAR;
482         }
483         if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_WINDOWUI) {
484                 info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_WINDOWUI;
485         }
486         if (view_prefs & POPPLER_VIEWER_PREFERENCES_FIT_WINDOW) {
487                 info->ui_hints |= EV_DOCUMENT_UI_HINT_FIT_WINDOW;
488         }
489         if (view_prefs & POPPLER_VIEWER_PREFERENCES_CENTER_WINDOW) {
490                 info->ui_hints |= EV_DOCUMENT_UI_HINT_CENTER_WINDOW;
491         }
492         if (view_prefs & POPPLER_VIEWER_PREFERENCES_DISPLAY_DOC_TITLE) {
493                 info->ui_hints |= EV_DOCUMENT_UI_HINT_DISPLAY_DOC_TITLE;
494         }
495         if (view_prefs & POPPLER_VIEWER_PREFERENCES_DIRECTION_RTL) {
496                 info->ui_hints |=  EV_DOCUMENT_UI_HINT_DIRECTION_RTL;
497         }
498
499         info->permissions = 0;
500         if (permissions & POPPLER_PERMISSIONS_OK_TO_PRINT) {
501                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_PRINT;
502         }
503         if (permissions & POPPLER_PERMISSIONS_OK_TO_MODIFY) {
504                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_MODIFY;
505         }
506         if (permissions & POPPLER_PERMISSIONS_OK_TO_COPY) {
507                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_COPY;
508         }
509         if (permissions & POPPLER_PERMISSIONS_OK_TO_ADD_NOTES) {
510                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_ADD_NOTES;
511         }
512
513         info->n_pages = ev_document_get_n_pages (document);
514
515         if (ev_document_security_has_document_security (EV_DOCUMENT_SECURITY (document))) {
516                 /* translators: this is the document security state */
517                 info->security = g_strdup (_("Yes"));
518         } else {
519                 /* translators: this is the document security state */
520                 info->security = g_strdup (_("No"));
521         }
522
523         return info;
524 }
525
526 static char *
527 pdf_document_get_text (EvDocument *document, int page, EvRectangle *rect)
528 {
529         PdfDocument *pdf_document = PDF_DOCUMENT (document);
530         PopplerPage *poppler_page;
531         PopplerRectangle r;
532         double height;
533         char *text;
534         
535         poppler_page = poppler_document_get_page (pdf_document->document, page);
536         g_return_val_if_fail (poppler_page != NULL, NULL);
537
538         poppler_page_get_size (poppler_page, NULL, &height);
539         r.x1 = rect->x1;
540         r.y1 = height - rect->y2;
541         r.x2 = rect->x2;
542         r.y2 = height - rect->y1;
543
544         text = poppler_page_get_text (poppler_page, &r);
545
546         g_object_unref (poppler_page);
547
548         return text;
549 }
550
551 static void
552 pdf_document_document_iface_init (EvDocumentIface *iface)
553 {
554         iface->save = pdf_document_save;
555         iface->load = pdf_document_load;
556         iface->get_n_pages = pdf_document_get_n_pages;
557         iface->get_page_size = pdf_document_get_page_size;
558         iface->get_page_label = pdf_document_get_page_label;
559         iface->get_links = pdf_document_get_links;
560         iface->render_pixbuf = pdf_document_render_pixbuf;
561         iface->get_text = pdf_document_get_text;
562         iface->can_get_text = pdf_document_can_get_text;
563         iface->get_info = pdf_document_get_info;
564 };
565
566 static void
567 pdf_document_security_iface_init (EvDocumentSecurityIface *iface)
568 {
569         iface->has_document_security = pdf_document_has_document_security;
570         iface->set_password = pdf_document_set_password;
571 }
572
573 static gdouble
574 pdf_document_fonts_get_progress (EvDocumentFonts *document_fonts)
575 {
576         PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
577         int n_pages;
578
579         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (pdf_document));
580
581         return (double)pdf_document->fonts_scanned_pages / (double)n_pages;
582 }
583
584 static gboolean
585 pdf_document_fonts_scan (EvDocumentFonts *document_fonts,
586                          int              n_pages)
587 {
588         PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
589         gboolean result;
590
591         g_return_val_if_fail (PDF_IS_DOCUMENT (document_fonts), FALSE);
592
593         if (pdf_document->font_info == NULL) { 
594                 pdf_document->font_info = poppler_font_info_new (pdf_document->document);
595         }
596
597         if (pdf_document->fonts_iter) {
598                 poppler_fonts_iter_free (pdf_document->fonts_iter);
599         }
600
601         pdf_document->fonts_scanned_pages += n_pages;
602
603         result = poppler_font_info_scan (pdf_document->font_info, n_pages,
604                                          &pdf_document->fonts_iter);
605         if (!result) {
606                 pdf_document->fonts_scanned_pages = 0;
607                 poppler_font_info_free (pdf_document->font_info);
608                 pdf_document->font_info = NULL; 
609         }
610
611         return result;
612 }
613
614 static const char *
615 font_type_to_string (PopplerFontType type)
616 {
617         switch (type)
618         {
619         case POPPLER_FONT_TYPE_TYPE1:
620                 return _("Type 1");
621         case POPPLER_FONT_TYPE_TYPE1C:
622                 return _("Type 1C");
623         case POPPLER_FONT_TYPE_TYPE3:
624                 return _("Type 3");
625         case POPPLER_FONT_TYPE_TRUETYPE:
626                 return _("TrueType");
627         case POPPLER_FONT_TYPE_CID_TYPE0:
628                 return _("Type 1 (CID)");
629         case POPPLER_FONT_TYPE_CID_TYPE0C:
630                 return _("Type 1C (CID)");
631         case POPPLER_FONT_TYPE_CID_TYPE2:
632                 return _("TrueType (CID)");
633         default:
634                 return _("Unknown font type");
635         }
636 }
637
638 static void
639 pdf_document_fonts_fill_model (EvDocumentFonts *document_fonts,
640                                GtkTreeModel    *model)
641 {
642         PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
643         PopplerFontsIter *iter = pdf_document->fonts_iter;
644
645         g_return_if_fail (PDF_IS_DOCUMENT (document_fonts));
646
647         if (!iter)
648                 return;
649
650         do {
651                 GtkTreeIter list_iter;
652                 const char *name;
653                 const char *type;
654                 const char *embedded;
655                 char *details;
656                 
657                 name = poppler_fonts_iter_get_name (iter);
658
659                 if (name == NULL) {
660                         name = _("No name");
661                 }
662
663                 type = font_type_to_string (
664                         poppler_fonts_iter_get_font_type (iter));
665
666                 if (poppler_fonts_iter_is_embedded (iter)) {
667                         if (poppler_fonts_iter_is_subset (iter))
668                                 embedded = _("Embedded subset");
669                         else
670                                 embedded = _("Embedded");
671                 } else {
672                         embedded = _("Not embedded");
673                 }
674
675                 details = g_markup_printf_escaped ("%s\n%s", type, embedded);
676
677                 gtk_list_store_append (GTK_LIST_STORE (model), &list_iter);
678                 gtk_list_store_set (GTK_LIST_STORE (model), &list_iter,
679                                     EV_DOCUMENT_FONTS_COLUMN_NAME, name,
680                                     EV_DOCUMENT_FONTS_COLUMN_DETAILS, details,
681                                     -1);
682
683                 g_free (details);
684         } while (poppler_fonts_iter_next (iter));
685 }
686
687 static void
688 pdf_document_document_fonts_iface_init (EvDocumentFontsIface *iface)
689 {
690         iface->fill_model = pdf_document_fonts_fill_model;
691         iface->scan = pdf_document_fonts_scan;
692         iface->get_progress = pdf_document_fonts_get_progress;
693 }
694
695 static gboolean
696 pdf_document_links_has_document_links (EvDocumentLinks *document_links)
697 {
698         PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
699         PopplerIndexIter *iter;
700
701         g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
702
703         iter = poppler_index_iter_new (pdf_document->document);
704         if (iter == NULL)
705                 return FALSE;
706         poppler_index_iter_free (iter);
707
708         return TRUE;
709 }
710
711 static EvLink *
712 ev_link_from_action (PopplerAction *action)
713 {
714         EvLink *link;
715         const char *title;
716
717         title = action->any.title;
718         
719         if (action->type == POPPLER_ACTION_GOTO_DEST) {
720                 link = ev_link_new_page (title, action->goto_dest.dest->page_num - 1);
721         } else if (action->type == POPPLER_ACTION_URI) {
722                 link = ev_link_new_external (title, action->uri.uri);
723         } else {
724                 link = ev_link_new_title (title);
725         }
726
727         return link;    
728 }
729
730 static void
731 build_tree (PdfDocument      *pdf_document,
732             GtkTreeModel     *model,
733             GtkTreeIter      *parent,
734             PopplerIndexIter *iter)
735 {
736
737         do {
738                 GtkTreeIter tree_iter;
739                 PopplerIndexIter *child;
740                 PopplerAction *action;
741                 EvLink *link;
742                 gboolean expand;
743                 
744                 action = poppler_index_iter_get_action (iter);
745                 expand = poppler_index_iter_is_open (iter);
746                 if (action) {
747                         gtk_tree_store_append (GTK_TREE_STORE (model), &tree_iter, parent);
748                         link = ev_link_from_action (action);
749                         poppler_action_free (action);
750
751                         gtk_tree_store_set (GTK_TREE_STORE (model), &tree_iter,
752                                             EV_DOCUMENT_LINKS_COLUMN_MARKUP, ev_link_get_title (link),
753                                             EV_DOCUMENT_LINKS_COLUMN_LINK, link,
754                                             EV_DOCUMENT_LINKS_COLUMN_EXPAND, expand,
755                                             -1);
756                         g_object_unref (link);
757                         child = poppler_index_iter_get_child (iter);
758                         if (child)
759                                 build_tree (pdf_document, model, &tree_iter, child);
760                         poppler_index_iter_free (child);
761                 }
762         } while (poppler_index_iter_next (iter));
763 }
764
765
766 static GtkTreeModel *
767 pdf_document_links_get_links_model (EvDocumentLinks *document_links)
768 {
769         PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
770         GtkTreeModel *model = NULL;
771         PopplerIndexIter *iter;
772
773         g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), NULL);
774
775         iter = poppler_index_iter_new (pdf_document->document);
776         /* Create the model if we have items*/
777         if (iter != NULL) {
778                 model = (GtkTreeModel *) gtk_tree_store_new (EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS,
779                                                              G_TYPE_STRING,
780                                                              G_TYPE_OBJECT,
781                                                              G_TYPE_BOOLEAN);
782                 build_tree (pdf_document, model, NULL, iter);
783                 poppler_index_iter_free (iter);
784         }
785         
786         return model;
787 }
788
789 static void
790 pdf_document_document_links_iface_init (EvDocumentLinksIface *iface)
791 {
792         iface->has_document_links = pdf_document_links_has_document_links;
793         iface->get_links_model = pdf_document_links_get_links_model;
794 }
795
796 static GdkPixbuf *
797 make_thumbnail_for_size (PdfDocument   *pdf_document,
798                          gint           page,
799                          int            rotation,
800                          gint           size,
801                          gboolean       border)
802 {
803         PopplerPage *poppler_page;
804         GdkPixbuf *pixbuf, *sub_pixbuf;
805         int width, height;
806         double scale;
807         gdouble unscaled_width, unscaled_height;
808
809         poppler_page = poppler_document_get_page (pdf_document->document, page);
810         set_page_orientation (pdf_document, poppler_page, rotation);
811         g_return_val_if_fail (poppler_page != NULL, NULL);
812
813         pdf_document_thumbnails_get_dimensions (EV_DOCUMENT_THUMBNAILS (pdf_document), page,
814                                                 size, &width, &height);
815         poppler_page_get_size (poppler_page, &unscaled_width, &unscaled_height);
816         scale = width / unscaled_width;
817
818         if (border) {
819                 pixbuf = ev_document_misc_get_thumbnail_frame (width, height, NULL);
820
821                 sub_pixbuf = gdk_pixbuf_new_subpixbuf (pixbuf,
822                                                        1, 1,
823                                                        width - 1, height - 1);
824         } else {
825                 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
826                                          width, height);
827                 gdk_pixbuf_fill (pixbuf, 0xffffffff);
828                 sub_pixbuf = gdk_pixbuf_new_subpixbuf (pixbuf,
829                                                        0, 0,
830                                                        width, height);
831         }
832
833         poppler_page_render_to_pixbuf (poppler_page, 0, 0,
834                                        width, height,
835                                        scale, sub_pixbuf);
836
837         g_object_unref (G_OBJECT (sub_pixbuf));
838
839         g_object_unref (poppler_page);
840         return pixbuf;
841 }
842
843 static GdkPixbuf *
844 pdf_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document_thumbnails,
845                                        gint                  page,
846                                        gint                  rotation,
847                                        gint                  size,
848                                        gboolean              border)
849 {
850         PdfDocument *pdf_document;
851         PopplerPage *poppler_page;
852         GdkPixbuf *pixbuf;
853
854         pdf_document = PDF_DOCUMENT (document_thumbnails);
855
856         poppler_page = poppler_document_get_page (pdf_document->document, page);
857         set_page_orientation (pdf_document, poppler_page, rotation);
858         g_return_val_if_fail (poppler_page != NULL, NULL);
859
860         pixbuf = poppler_page_get_thumbnail (poppler_page);
861         
862         if (pixbuf != NULL) {
863                 /* The document provides its own thumbnails. */
864                 if (border) {
865                         GdkPixbuf *real_pixbuf;
866
867                         real_pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, pixbuf);
868                         g_object_unref (pixbuf);
869                         pixbuf = real_pixbuf;
870                 }
871         } else {
872                 /* There is no provided thumbnail.  We need to make one. */
873                 pixbuf = make_thumbnail_for_size (pdf_document, page, rotation, size, border);
874         }
875
876         g_object_unref (poppler_page);
877         
878         return pixbuf;
879 }
880
881 static void
882 pdf_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnails,
883                                         gint                  page,
884                                         gint                  size,
885                                         gint                 *width,
886                                         gint                 *height)
887 {
888         PdfDocument *pdf_document;
889         PopplerPage *poppler_page;
890         gint has_thumb;
891         
892         pdf_document = PDF_DOCUMENT (document_thumbnails);
893         poppler_page = poppler_document_get_page (pdf_document->document, page);
894
895         g_return_if_fail (width != NULL);
896         g_return_if_fail (height != NULL);
897         g_return_if_fail (poppler_page != NULL);
898
899         has_thumb = poppler_page_get_thumbnail_size (poppler_page, width, height);
900
901         if (!has_thumb) {
902                 double page_width, page_height;
903
904                 poppler_page_get_size (poppler_page, &page_width, &page_height);
905                 if (page_width > page_height) {
906                         *width = size;
907                         *height = (int) (size * page_height / page_width);
908                 } else {
909                         *width = (int) (size * page_width / page_height);
910                         *height = size;
911                 }
912         }
913         g_object_unref (poppler_page);
914 }
915
916 static void
917 pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
918 {
919         iface->get_thumbnail = pdf_document_thumbnails_get_thumbnail;
920         iface->get_dimensions = pdf_document_thumbnails_get_dimensions;
921 }
922
923
924 static gboolean
925 pdf_document_search_idle_callback (void *data)
926 {
927         PdfDocumentSearch *search = (PdfDocumentSearch*) data;
928         PdfDocument *pdf_document = search->document;
929         int n_pages;
930         GList *matches;
931         PopplerPage *page;
932
933         page = poppler_document_get_page (search->document->document,
934                                           search->search_page);
935
936         ev_document_doc_mutex_lock ();
937         matches = poppler_page_find_text (page, search->text);
938         ev_document_doc_mutex_unlock ();
939
940         g_object_unref (page);
941
942         search->pages[search->search_page] = matches;
943         ev_document_find_changed (EV_DOCUMENT_FIND (pdf_document),
944                                   search->search_page);
945
946         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (search->document));
947         search->search_page += 1;
948         if (search->search_page == n_pages) {
949                 /* wrap around */
950                 search->search_page = 0;
951         }
952
953         if (search->search_page != search->start_page) {
954                 return TRUE;
955         }
956
957         /* We're done. */
958         search->idle = 0; /* will return FALSE to remove */
959         return FALSE;
960 }
961
962
963 static PdfDocumentSearch *
964 pdf_document_search_new (PdfDocument *pdf_document,
965                          int          start_page,
966                          const char  *text)
967 {
968         PdfDocumentSearch *search;
969         int n_pages;
970         int i;
971
972         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (pdf_document));
973
974         search = g_new0 (PdfDocumentSearch, 1);
975
976         search->text = g_strdup (text);
977         search->pages = g_new0 (GList *, n_pages);
978         for (i = 0; i < n_pages; i++) {
979                 search->pages[i] = NULL;
980         }
981
982         search->document = pdf_document;
983
984         /* We add at low priority so the progress bar repaints */
985         search->idle = g_idle_add_full (G_PRIORITY_LOW,
986                                         pdf_document_search_idle_callback,
987                                         search,
988                                         NULL);
989
990         search->start_page = start_page;
991         search->search_page = start_page;
992
993         return search;
994 }
995
996 static void
997 pdf_document_find_begin (EvDocumentFind   *document,
998                          int               page,
999                          const char       *search_string,
1000                          gboolean          case_sensitive)
1001 {
1002         PdfDocument *pdf_document = PDF_DOCUMENT (document);
1003
1004         /* FIXME handle case_sensitive (right now XPDF
1005          * code is always case insensitive for ASCII
1006          * and case sensitive for all other languaages)
1007          */
1008
1009         if (pdf_document->search &&
1010             strcmp (search_string, pdf_document->search->text) == 0)
1011                 return;
1012
1013         if (pdf_document->search)
1014                 pdf_document_search_free (pdf_document->search);
1015
1016         pdf_document->search = pdf_document_search_new (pdf_document,
1017                                                         page,
1018                                                         search_string);
1019 }
1020
1021 int
1022 pdf_document_find_get_n_results (EvDocumentFind *document_find, int page)
1023 {
1024         PdfDocumentSearch *search = PDF_DOCUMENT (document_find)->search;
1025
1026         if (search) {
1027                 return g_list_length (search->pages[page]);
1028         } else {
1029                 return 0;
1030         }
1031 }
1032
1033 gboolean
1034 pdf_document_find_get_result (EvDocumentFind *document_find,
1035                               int             page,
1036                               int             n_result,
1037                               EvRectangle    *rectangle)
1038 {
1039         PdfDocument *pdf_document = PDF_DOCUMENT (document_find);
1040         PdfDocumentSearch *search = pdf_document->search;
1041         PopplerPage *poppler_page;
1042         PopplerRectangle *r;
1043         double height;
1044
1045         if (search == NULL)
1046                 return FALSE;
1047
1048         r = (PopplerRectangle *) g_list_nth_data (search->pages[page],
1049                                                   n_result);
1050         if (r == NULL)
1051                 return FALSE;
1052
1053         poppler_page = poppler_document_get_page (pdf_document->document, page);
1054         poppler_page_get_size (poppler_page, NULL, &height);
1055         rectangle->x1 = r->x1;
1056         rectangle->y1 = height - r->y2;
1057         rectangle->x2 = r->x2;
1058         rectangle->y2 = height - r->y1;
1059         g_object_unref (poppler_page);
1060                 
1061         return TRUE;
1062 }
1063
1064 int
1065 pdf_document_find_page_has_results (EvDocumentFind *document_find,
1066                                     int             page)
1067 {
1068         PdfDocumentSearch *search = PDF_DOCUMENT (document_find)->search;
1069
1070         g_return_val_if_fail (search != NULL, FALSE);
1071
1072         return search->pages[page] != NULL;
1073 }
1074
1075 double
1076 pdf_document_find_get_progress (EvDocumentFind *document_find)
1077 {
1078         PdfDocumentSearch *search;
1079         int n_pages, pages_done;
1080
1081         search = PDF_DOCUMENT (document_find)->search;
1082
1083         if (search == NULL) {
1084                 return 0;
1085         }
1086
1087         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (document_find));
1088         if (search->search_page > search->start_page) {
1089                 pages_done = search->search_page - search->start_page + 1;
1090         } else if (search->search_page == search->start_page) {
1091                 pages_done = n_pages;
1092         } else {
1093                 pages_done = n_pages - search->start_page + search->search_page;
1094         }
1095
1096         return pages_done / (double) n_pages;
1097 }
1098
1099 static void
1100 pdf_document_find_cancel (EvDocumentFind *document)
1101 {
1102         PdfDocument *pdf_document = PDF_DOCUMENT (document);
1103
1104         if (pdf_document->search) {
1105                 pdf_document_search_free (pdf_document->search);
1106                 pdf_document->search = NULL;
1107         }
1108 }
1109
1110 static void
1111 pdf_document_find_iface_init (EvDocumentFindIface *iface)
1112 {
1113         iface->begin = pdf_document_find_begin;
1114         iface->get_n_results = pdf_document_find_get_n_results;
1115         iface->get_result = pdf_document_find_get_result;
1116         iface->page_has_results = pdf_document_find_page_has_results;
1117         iface->get_progress = pdf_document_find_get_progress;
1118         iface->cancel = pdf_document_find_cancel;
1119 }
1120
1121 static void
1122 pdf_document_ps_exporter_begin (EvPSExporter *exporter, const char *filename,
1123                                 int first_page, int last_page,
1124                                 double width, double height, gboolean duplex)
1125 {
1126         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1127         
1128         pdf_document->ps_file = poppler_ps_file_new (pdf_document->document, filename,
1129                                                      first_page,
1130                                                      last_page - first_page + 1);
1131         poppler_ps_file_set_paper_size (pdf_document->ps_file, width, height);
1132         poppler_ps_file_set_duplex (pdf_document->ps_file, duplex);
1133 }
1134
1135 static void
1136 pdf_document_ps_exporter_do_page (EvPSExporter *exporter, EvRenderContext *rc)
1137 {
1138         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1139         PopplerPage *poppler_page;
1140
1141         g_return_if_fail (pdf_document->ps_file != NULL);
1142
1143         poppler_page = poppler_document_get_page (pdf_document->document, rc->page);
1144         set_page_orientation (pdf_document, poppler_page, rc->rotation);
1145         poppler_page_render_to_ps (poppler_page, pdf_document->ps_file);
1146         g_object_unref (poppler_page);
1147 }
1148
1149 static void
1150 pdf_document_ps_exporter_end (EvPSExporter *exporter)
1151 {
1152         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1153
1154         poppler_ps_file_free (pdf_document->ps_file);
1155         pdf_document->ps_file = NULL;
1156 }
1157
1158 static void
1159 pdf_document_ps_exporter_iface_init (EvPSExporterIface *iface)
1160 {
1161         iface->begin = pdf_document_ps_exporter_begin;
1162         iface->do_page = pdf_document_ps_exporter_do_page;
1163         iface->end = pdf_document_ps_exporter_end;
1164 }
1165
1166
1167 void
1168 pdf_selection_render_selection (EvSelection      *selection,
1169                                 EvRenderContext  *rc,
1170                                 GdkPixbuf       **pixbuf,
1171                                 EvRectangle      *points,
1172                                 EvRectangle      *old_points)
1173 {
1174         PdfDocument *pdf_document;
1175         PopplerPage *poppler_page;
1176         double width_points, height_points;
1177         gint width, height;
1178
1179         pdf_document = PDF_DOCUMENT (selection);
1180         poppler_page = poppler_document_get_page (pdf_document->document,
1181                                                   rc->page);
1182         set_page_orientation (pdf_document, poppler_page, rc->rotation);
1183
1184         poppler_page_get_size (poppler_page, &width_points, &height_points);
1185         width = (int) ((width_points * rc->scale) + 0.5);
1186         height = (int) ((height_points * rc->scale) + 0.5);
1187
1188         if (*pixbuf == NULL) {
1189                 * pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
1190                                            TRUE, 8,
1191                                            width, height);
1192         }
1193         
1194         /* FIXME: Hardcoded clearlooks selection color.  We should
1195          * track theme color changes and focus out event and update
1196          * selection color accordingly. */
1197         poppler_page_render_selection (poppler_page,
1198                                        rc->scale, *pixbuf,
1199                                        (PopplerRectangle *)points,
1200                                        (PopplerRectangle *)old_points,
1201                                        0x00ffffff, 0x007c99ad);
1202         g_object_unref (poppler_page);
1203
1204 }
1205
1206
1207 GdkRegion *
1208 pdf_selection_get_selection_region (EvSelection     *selection,
1209                                     EvRenderContext *rc,
1210                                     EvRectangle     *points)
1211 {
1212         PdfDocument *pdf_document;
1213         PopplerPage *poppler_page;
1214         GdkRegion *retval;
1215
1216         pdf_document = PDF_DOCUMENT (selection);
1217         poppler_page = poppler_document_get_page (pdf_document->document,
1218                                                   rc->page);
1219         set_page_orientation (pdf_document, poppler_page, rc->rotation);
1220
1221         retval = poppler_page_get_selection_region (poppler_page, rc->scale, (PopplerRectangle *) points);
1222         g_object_unref (poppler_page);
1223
1224         return retval;
1225 }
1226
1227 GdkRegion *
1228 pdf_selection_get_selection_map (EvSelection     *selection,
1229                                  EvRenderContext *rc)
1230 {
1231         PdfDocument *pdf_document;
1232         PopplerPage *poppler_page;
1233         PopplerRectangle points;
1234         GdkRegion *retval;
1235
1236         pdf_document = PDF_DOCUMENT (selection);
1237         poppler_page = poppler_document_get_page (pdf_document->document,
1238                                                   rc->page);
1239         set_page_orientation (pdf_document, poppler_page, rc->rotation);
1240
1241         points.x1 = 0.0;
1242         points.y1 = 0.0;
1243         poppler_page_get_size (poppler_page, &(points.x2), &(points.y2));
1244         retval = poppler_page_get_selection_region (poppler_page, 1.0, &points);
1245         g_object_unref (poppler_page);
1246
1247         return retval;
1248 }
1249
1250 static void
1251 pdf_selection_iface_init (EvSelectionIface *iface)
1252 {
1253         iface->render_selection = pdf_selection_render_selection;
1254         iface->get_selection_region = pdf_selection_get_selection_region;
1255         iface->get_selection_map = pdf_selection_get_selection_map;
1256 }
1257
1258 PdfDocument *
1259 pdf_document_new (void)
1260 {
1261         return PDF_DOCUMENT (g_object_new (PDF_TYPE_DOCUMENT, NULL));
1262 }