]> www.fi.muni.cz Git - evince.git/blob - pdf/ev-poppler.cc
Really make use of the orientation bit of the render context. Use the
[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 PopplerOrientation
208 get_document_orientation (PdfDocument *pdf_document)
209 {
210         PopplerOrientation orientation;
211         PopplerPage *page;
212
213         /* Should prolly be smarter here and check more than first page */
214         page = poppler_document_get_page (pdf_document->document, 0);
215         if (page) {
216                 orientation = poppler_page_get_orientation (page);
217         } else {
218                 orientation = POPPLER_ORIENTATION_PORTRAIT;
219         }
220         g_object_unref (page);
221
222         return orientation;
223 }
224
225 static gboolean
226 pdf_document_load (EvDocument   *document,
227                    const char   *uri,
228                    GError      **error)
229 {
230         GError *poppler_error = NULL;
231         PdfDocument *pdf_document = PDF_DOCUMENT (document);
232
233         pdf_document->document =
234                 poppler_document_new_from_file (uri, pdf_document->password, &poppler_error);
235
236         if (pdf_document->document == NULL) {
237                 convert_error (poppler_error, error);
238                 return FALSE;
239         }
240
241         return TRUE;
242 }
243
244 static int
245 pdf_document_get_n_pages (EvDocument *document)
246 {
247         return poppler_document_get_n_pages (PDF_DOCUMENT (document)->document);
248 }
249
250 /* FIXME This should not be necessary, poppler should rember it */
251 static void
252 set_page_orientation (PdfDocument *pdf_document, PopplerPage *page, EvOrientation orientation)
253 {
254         PopplerOrientation poppler_orientation;
255
256         switch (orientation) {
257                 case EV_ORIENTATION_PORTRAIT:
258                         poppler_orientation = POPPLER_ORIENTATION_PORTRAIT;
259                         break;
260                 case EV_ORIENTATION_LANDSCAPE:
261                         poppler_orientation = POPPLER_ORIENTATION_LANDSCAPE;
262                         break;
263                 case EV_ORIENTATION_UPSIDEDOWN:
264                         poppler_orientation = POPPLER_ORIENTATION_UPSIDEDOWN;
265                         break;
266                 case EV_ORIENTATION_SEASCAPE:
267                         poppler_orientation = POPPLER_ORIENTATION_SEASCAPE;
268                         break;
269                 default:
270                         g_assert_not_reached ();
271         }
272
273         poppler_page_set_orientation (page, poppler_orientation);
274 }
275
276 static void
277 pdf_document_get_page_size (EvDocument   *document,
278                             int           page,
279                             double       *width,
280                             double       *height)
281 {
282         PdfDocument *pdf_document = PDF_DOCUMENT (document);
283         PopplerPage *poppler_page;
284
285         poppler_page = poppler_document_get_page (pdf_document->document, page);
286         poppler_page_get_size (poppler_page, width, height);
287         g_object_unref (poppler_page);
288 }
289
290 static char *
291 pdf_document_get_page_label (EvDocument *document,
292                              int         page)
293 {
294         PopplerPage *poppler_page;
295         char *label = NULL;
296
297         poppler_page = poppler_document_get_page (PDF_DOCUMENT (document)->document,
298                                                   page);
299
300         g_object_get (G_OBJECT (poppler_page),
301                       "label", &label,
302                       NULL);
303         g_object_unref (poppler_page);
304
305         return label;
306 }
307
308 static GList *
309 pdf_document_get_links (EvDocument *document,
310                         int         page)
311 {
312         PdfDocument *pdf_document;
313         PopplerPage *poppler_page;
314         GList *retval = NULL;
315         GList *mapping_list;
316         GList *list;
317         double height;
318
319         pdf_document = PDF_DOCUMENT (document);
320         poppler_page = poppler_document_get_page (pdf_document->document,
321                                                   page);
322         mapping_list = poppler_page_get_link_mapping (poppler_page);
323         poppler_page_get_size (poppler_page, NULL, &height);
324
325         for (list = mapping_list; list; list = list->next) {
326                 PopplerLinkMapping *link_mapping;
327                 EvLinkMapping *ev_link_mapping;
328
329                 link_mapping = (PopplerLinkMapping *)list->data;
330                 ev_link_mapping = g_new (EvLinkMapping, 1);
331                 ev_link_mapping->link = ev_link_from_action (link_mapping->action);
332                 ev_link_mapping->x1 = link_mapping->area.x1;
333                 ev_link_mapping->x2 = link_mapping->area.x2;
334                 /* Invert this for X-style coordinates */
335                 ev_link_mapping->y1 = height - link_mapping->area.y2;
336                 ev_link_mapping->y2 = height - link_mapping->area.y1;
337
338                 retval = g_list_prepend (retval, ev_link_mapping);
339         }
340
341         poppler_page_free_link_mapping (mapping_list);
342         g_object_unref (poppler_page);
343
344         return g_list_reverse (retval);
345 }
346                         
347
348 static GdkPixbuf *
349 pdf_document_render_pixbuf (EvDocument   *document,
350                             EvRenderContext *rc)
351 {
352         PdfDocument *pdf_document;
353         PopplerPage *poppler_page;
354         GdkPixbuf *pixbuf;
355         double width_points, height_points;
356         gint width, height;
357
358         pdf_document = PDF_DOCUMENT (document);
359         poppler_page = poppler_document_get_page (pdf_document->document,
360                                                   rc->page);
361         set_page_orientation (pdf_document, poppler_page, rc->orientation);
362
363         poppler_page_get_size (poppler_page, &width_points, &height_points);
364         width = (int) ((width_points * rc->scale) + 0.5);
365         height = (int) ((height_points * rc->scale) + 0.5);
366
367         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
368                                  FALSE, 8,
369                                  width, height);
370
371         poppler_page_render_to_pixbuf (poppler_page,
372                                        0, 0,
373                                        width, height,
374                                        rc->scale,
375                                        pixbuf);
376         
377         g_object_unref (poppler_page);
378         
379         return pixbuf;
380 }
381
382 /* EvDocumentSecurity */
383
384 static gboolean
385 pdf_document_has_document_security (EvDocumentSecurity *document_security)
386 {
387         /* FIXME: do we really need to have this? */
388         return FALSE;
389 }
390
391 static void
392 pdf_document_set_password (EvDocumentSecurity *document_security,
393                            const char         *password)
394 {
395         PdfDocument *document = PDF_DOCUMENT (document_security);
396
397         if (document->password)
398                 g_free (document->password);
399
400         document->password = g_strdup (password);
401 }
402
403 static gboolean
404 pdf_document_can_get_text (EvDocument *document)
405 {
406         return TRUE;
407 }
408
409 static EvDocumentInfo *
410 pdf_document_get_info (EvDocument *document)
411 {
412         EvDocumentInfo *info;
413         PopplerPageLayout layout;
414         PopplerPageMode mode;
415         PopplerViewerPreferences view_prefs;
416         PopplerPermissions permissions;
417
418         info = g_new0 (EvDocumentInfo, 1);
419
420         info->fields_mask = EV_DOCUMENT_INFO_TITLE |
421                             EV_DOCUMENT_INFO_FORMAT |
422                             EV_DOCUMENT_INFO_AUTHOR |
423                             EV_DOCUMENT_INFO_SUBJECT |
424                             EV_DOCUMENT_INFO_KEYWORDS |
425                             EV_DOCUMENT_INFO_LAYOUT |
426                             EV_DOCUMENT_INFO_START_MODE |
427                             EV_DOCUMENT_INFO_PERMISSIONS |
428                             EV_DOCUMENT_INFO_UI_HINTS |
429                             EV_DOCUMENT_INFO_CREATOR |
430                             EV_DOCUMENT_INFO_PRODUCER |
431                             EV_DOCUMENT_INFO_CREATION_DATE |
432                             EV_DOCUMENT_INFO_MOD_DATE |
433                             EV_DOCUMENT_INFO_LINEARIZED |
434                             EV_DOCUMENT_INFO_N_PAGES |
435                             EV_DOCUMENT_INFO_SECURITY;
436
437
438         g_object_get (PDF_DOCUMENT (document)->document,
439                       "title", &(info->title),
440                       "format", &(info->format),
441                       "author", &(info->author),
442                       "subject", &(info->subject),
443                       "keywords", &(info->keywords),
444                       "page-mode", &mode,
445                       "page-layout", &layout,
446                       "viewer-preferences", &view_prefs,
447                       "permissions", &permissions,
448                       "creator", &(info->creator),
449                       "producer", &(info->producer),
450                       "creation-date", &(info->creation_date),
451                       "mod-date", &(info->modified_date),
452                       "linearized", &(info->linearized),
453                       NULL);
454
455         switch (layout) {
456                 case POPPLER_PAGE_LAYOUT_SINGLE_PAGE:
457                         info->layout = EV_DOCUMENT_LAYOUT_SINGLE_PAGE;
458                         break;
459                 case POPPLER_PAGE_LAYOUT_ONE_COLUMN:
460                         info->layout = EV_DOCUMENT_LAYOUT_ONE_COLUMN;
461                         break;
462                 case POPPLER_PAGE_LAYOUT_TWO_COLUMN_LEFT:
463                         info->layout = EV_DOCUMENT_LAYOUT_TWO_COLUMN_LEFT;
464                         break;
465                 case POPPLER_PAGE_LAYOUT_TWO_COLUMN_RIGHT:
466                         info->layout = EV_DOCUMENT_LAYOUT_TWO_COLUMN_RIGHT;
467                 case POPPLER_PAGE_LAYOUT_TWO_PAGE_LEFT:
468                         info->layout = EV_DOCUMENT_LAYOUT_TWO_PAGE_LEFT;
469                         break;
470                 case POPPLER_PAGE_LAYOUT_TWO_PAGE_RIGHT:
471                         info->layout = EV_DOCUMENT_LAYOUT_TWO_PAGE_RIGHT;
472                         break;
473                 default:
474                         break;
475         }
476
477         switch (mode) {
478                 case POPPLER_PAGE_MODE_NONE:
479                         info->mode = EV_DOCUMENT_MODE_NONE;
480                         break;
481                 case POPPLER_PAGE_MODE_USE_THUMBS:
482                         info->mode = EV_DOCUMENT_MODE_USE_THUMBS;
483                         break;
484                 case POPPLER_PAGE_MODE_USE_OC:
485                         info->mode = EV_DOCUMENT_MODE_USE_OC;
486                         break;
487                 case POPPLER_PAGE_MODE_FULL_SCREEN:
488                         info->mode = EV_DOCUMENT_MODE_FULL_SCREEN;
489                         break;
490                 case POPPLER_PAGE_MODE_USE_ATTACHMENTS:
491                         info->mode = EV_DOCUMENT_MODE_USE_ATTACHMENTS;
492                 default:
493                         break;
494         }
495
496         info->ui_hints = 0;
497         if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_TOOLBAR) {
498                 info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_TOOLBAR;
499         }
500         if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_MENUBAR) {
501                 info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_MENUBAR;
502         }
503         if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_WINDOWUI) {
504                 info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_WINDOWUI;
505         }
506         if (view_prefs & POPPLER_VIEWER_PREFERENCES_FIT_WINDOW) {
507                 info->ui_hints |= EV_DOCUMENT_UI_HINT_FIT_WINDOW;
508         }
509         if (view_prefs & POPPLER_VIEWER_PREFERENCES_CENTER_WINDOW) {
510                 info->ui_hints |= EV_DOCUMENT_UI_HINT_CENTER_WINDOW;
511         }
512         if (view_prefs & POPPLER_VIEWER_PREFERENCES_DISPLAY_DOC_TITLE) {
513                 info->ui_hints |= EV_DOCUMENT_UI_HINT_DISPLAY_DOC_TITLE;
514         }
515         if (view_prefs & POPPLER_VIEWER_PREFERENCES_DIRECTION_RTL) {
516                 info->ui_hints |=  EV_DOCUMENT_UI_HINT_DIRECTION_RTL;
517         }
518
519         info->permissions = 0;
520         if (permissions & POPPLER_PERMISSIONS_OK_TO_PRINT) {
521                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_PRINT;
522         }
523         if (permissions & POPPLER_PERMISSIONS_OK_TO_MODIFY) {
524                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_MODIFY;
525         }
526         if (permissions & POPPLER_PERMISSIONS_OK_TO_COPY) {
527                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_COPY;
528         }
529         if (permissions & POPPLER_PERMISSIONS_OK_TO_ADD_NOTES) {
530                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_ADD_NOTES;
531         }
532
533         info->n_pages = ev_document_get_n_pages (document);
534
535         if (ev_document_security_has_document_security (EV_DOCUMENT_SECURITY (document))) {
536                 /* translators: this is the document security state */
537                 info->security = g_strdup (_("Yes"));
538         } else {
539                 /* translators: this is the document security state */
540                 info->security = g_strdup (_("No"));
541         }
542
543         return info;
544 }
545
546 static char *
547 pdf_document_get_text (EvDocument *document, int page, EvRectangle *rect)
548 {
549         PdfDocument *pdf_document = PDF_DOCUMENT (document);
550         PopplerPage *poppler_page;
551         PopplerRectangle r;
552         double height;
553         char *text;
554         
555         poppler_page = poppler_document_get_page (pdf_document->document, page);
556         g_return_val_if_fail (poppler_page != NULL, NULL);
557
558         poppler_page_get_size (poppler_page, NULL, &height);
559         r.x1 = rect->x1;
560         r.y1 = height - rect->y2;
561         r.x2 = rect->x2;
562         r.y2 = height - rect->y1;
563
564         text = poppler_page_get_text (poppler_page, &r);
565
566         g_object_unref (poppler_page);
567
568         return text;
569 }
570
571 static EvOrientation
572 pdf_document_get_orientation (EvDocument *document)
573 {
574         EvOrientation result;
575         PdfDocument *pdf_document = PDF_DOCUMENT (document);
576
577         switch (get_document_orientation (pdf_document)) {
578         case POPPLER_ORIENTATION_PORTRAIT:
579                 result = EV_ORIENTATION_PORTRAIT;
580                 break;
581         case POPPLER_ORIENTATION_LANDSCAPE:
582                 result = EV_ORIENTATION_LANDSCAPE;
583                 break;
584         case POPPLER_ORIENTATION_UPSIDEDOWN:
585                 result = EV_ORIENTATION_UPSIDEDOWN;
586                 break;
587         case POPPLER_ORIENTATION_SEASCAPE:
588                 result = EV_ORIENTATION_SEASCAPE;
589                 break;
590         default:
591                 g_assert_not_reached ();
592         }
593
594         return result;
595 }
596
597 static void
598 pdf_document_document_iface_init (EvDocumentIface *iface)
599 {
600         iface->save = pdf_document_save;
601         iface->load = pdf_document_load;
602         iface->get_n_pages = pdf_document_get_n_pages;
603         iface->get_page_size = pdf_document_get_page_size;
604         iface->get_page_label = pdf_document_get_page_label;
605         iface->get_links = pdf_document_get_links;
606         iface->render_pixbuf = pdf_document_render_pixbuf;
607         iface->get_text = pdf_document_get_text;
608         iface->can_get_text = pdf_document_can_get_text;
609         iface->get_info = pdf_document_get_info;
610         iface->get_orientation = pdf_document_get_orientation;
611 };
612
613 static void
614 pdf_document_security_iface_init (EvDocumentSecurityIface *iface)
615 {
616         iface->has_document_security = pdf_document_has_document_security;
617         iface->set_password = pdf_document_set_password;
618 }
619
620 static gdouble
621 pdf_document_fonts_get_progress (EvDocumentFonts *document_fonts)
622 {
623         PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
624         int n_pages;
625
626         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (pdf_document));
627
628         return (double)pdf_document->fonts_scanned_pages / (double)n_pages;
629 }
630
631 static gboolean
632 pdf_document_fonts_scan (EvDocumentFonts *document_fonts,
633                          int              n_pages)
634 {
635         PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
636         gboolean result;
637
638         g_return_val_if_fail (PDF_IS_DOCUMENT (document_fonts), FALSE);
639
640         if (pdf_document->font_info == NULL) { 
641                 pdf_document->font_info = poppler_font_info_new (pdf_document->document);
642         }
643
644         if (pdf_document->fonts_iter) {
645                 poppler_fonts_iter_free (pdf_document->fonts_iter);
646         }
647
648         pdf_document->fonts_scanned_pages += n_pages;
649
650         result = poppler_font_info_scan (pdf_document->font_info, n_pages,
651                                          &pdf_document->fonts_iter);
652         if (!result) {
653                 pdf_document->fonts_scanned_pages = 0;
654                 poppler_font_info_free (pdf_document->font_info);
655                 pdf_document->font_info = NULL; 
656         }
657
658         return result;
659 }
660
661 static const char *
662 font_type_to_string (PopplerFontType type)
663 {
664         switch (type)
665         {
666         case POPPLER_FONT_TYPE_TYPE1:
667                 return _("Type 1");
668         case POPPLER_FONT_TYPE_TYPE1C:
669                 return _("Type 1C");
670         case POPPLER_FONT_TYPE_TYPE3:
671                 return _("Type 3");
672         case POPPLER_FONT_TYPE_TRUETYPE:
673                 return _("TrueType");
674         case POPPLER_FONT_TYPE_CID_TYPE0:
675                 return _("Type 1 (CID)");
676         case POPPLER_FONT_TYPE_CID_TYPE0C:
677                 return _("Type 1C (CID)");
678         case POPPLER_FONT_TYPE_CID_TYPE2:
679                 return _("TrueType (CID)");
680         default:
681                 return _("Unknown font type");
682         }
683 }
684
685 static void
686 pdf_document_fonts_fill_model (EvDocumentFonts *document_fonts,
687                                GtkTreeModel    *model)
688 {
689         PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
690         PopplerFontsIter *iter = pdf_document->fonts_iter;
691
692         g_return_if_fail (PDF_IS_DOCUMENT (document_fonts));
693
694         if (!iter)
695                 return;
696
697         do {
698                 GtkTreeIter list_iter;
699                 const char *name;
700                 const char *type;
701                 const char *embedded;
702                 char *details;
703                 
704                 name = poppler_fonts_iter_get_name (iter);
705
706                 if (name == NULL) {
707                         name = _("No name");
708                 }
709
710                 type = font_type_to_string (
711                         poppler_fonts_iter_get_font_type (iter));
712
713                 if (poppler_fonts_iter_is_embedded (iter)) {
714                         if (poppler_fonts_iter_is_subset (iter))
715                                 embedded = _("Embedded subset");
716                         else
717                                 embedded = _("Embedded");
718                 } else {
719                         embedded = _("Not embedded");
720                 }
721
722                 details = g_markup_printf_escaped ("%s\n%s", type, embedded);
723
724                 gtk_list_store_append (GTK_LIST_STORE (model), &list_iter);
725                 gtk_list_store_set (GTK_LIST_STORE (model), &list_iter,
726                                     EV_DOCUMENT_FONTS_COLUMN_NAME, name,
727                                     EV_DOCUMENT_FONTS_COLUMN_DETAILS, details,
728                                     -1);
729
730                 g_free (details);
731         } while (poppler_fonts_iter_next (iter));
732 }
733
734 static void
735 pdf_document_document_fonts_iface_init (EvDocumentFontsIface *iface)
736 {
737         iface->fill_model = pdf_document_fonts_fill_model;
738         iface->scan = pdf_document_fonts_scan;
739         iface->get_progress = pdf_document_fonts_get_progress;
740 }
741
742 static gboolean
743 pdf_document_links_has_document_links (EvDocumentLinks *document_links)
744 {
745         PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
746         PopplerIndexIter *iter;
747
748         g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
749
750         iter = poppler_index_iter_new (pdf_document->document);
751         if (iter == NULL)
752                 return FALSE;
753         poppler_index_iter_free (iter);
754
755         return TRUE;
756 }
757
758 static EvLink *
759 ev_link_from_action (PopplerAction *action)
760 {
761         EvLink *link;
762         const char *title;
763
764         title = action->any.title;
765         
766         if (action->type == POPPLER_ACTION_GOTO_DEST) {
767                 link = ev_link_new_page (title, action->goto_dest.dest->page_num - 1);
768         } else if (action->type == POPPLER_ACTION_URI) {
769                 link = ev_link_new_external (title, action->uri.uri);
770         } else {
771                 link = ev_link_new_title (title);
772         }
773
774         return link;    
775 }
776
777 static void
778 build_tree (PdfDocument      *pdf_document,
779             GtkTreeModel     *model,
780             GtkTreeIter      *parent,
781             PopplerIndexIter *iter)
782 {
783
784         do {
785                 GtkTreeIter tree_iter;
786                 PopplerIndexIter *child;
787                 PopplerAction *action;
788                 EvLink *link;
789                 gboolean expand;
790                 
791                 action = poppler_index_iter_get_action (iter);
792                 expand = poppler_index_iter_is_open (iter);
793                 if (action) {
794                         gtk_tree_store_append (GTK_TREE_STORE (model), &tree_iter, parent);
795                         link = ev_link_from_action (action);
796                         poppler_action_free (action);
797
798                         gtk_tree_store_set (GTK_TREE_STORE (model), &tree_iter,
799                                             EV_DOCUMENT_LINKS_COLUMN_MARKUP, ev_link_get_title (link),
800                                             EV_DOCUMENT_LINKS_COLUMN_LINK, link,
801                                             EV_DOCUMENT_LINKS_COLUMN_EXPAND, expand,
802                                             -1);
803                         g_object_unref (link);
804                         child = poppler_index_iter_get_child (iter);
805                         if (child)
806                                 build_tree (pdf_document, model, &tree_iter, child);
807                         poppler_index_iter_free (child);
808                 }
809         } while (poppler_index_iter_next (iter));
810 }
811
812
813 static GtkTreeModel *
814 pdf_document_links_get_links_model (EvDocumentLinks *document_links)
815 {
816         PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
817         GtkTreeModel *model = NULL;
818         PopplerIndexIter *iter;
819
820         g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), NULL);
821
822         iter = poppler_index_iter_new (pdf_document->document);
823         /* Create the model if we have items*/
824         if (iter != NULL) {
825                 model = (GtkTreeModel *) gtk_tree_store_new (EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS,
826                                                              G_TYPE_STRING,
827                                                              G_TYPE_OBJECT,
828                                                              G_TYPE_BOOLEAN);
829                 build_tree (pdf_document, model, NULL, iter);
830                 poppler_index_iter_free (iter);
831         }
832         
833         return model;
834 }
835
836 static void
837 pdf_document_document_links_iface_init (EvDocumentLinksIface *iface)
838 {
839         iface->has_document_links = pdf_document_links_has_document_links;
840         iface->get_links_model = pdf_document_links_get_links_model;
841 }
842
843 static GdkPixbuf *
844 make_thumbnail_for_size (PdfDocument   *pdf_document,
845                          gint           page,
846                          EvOrientation  orientation,
847                          gint           size,
848                          gboolean       border)
849 {
850         PopplerPage *poppler_page;
851         GdkPixbuf *pixbuf, *sub_pixbuf;
852         int width, height;
853         double scale;
854         gdouble unscaled_width, unscaled_height;
855
856         poppler_page = poppler_document_get_page (pdf_document->document, page);
857         set_page_orientation (pdf_document, poppler_page, orientation);
858         g_return_val_if_fail (poppler_page != NULL, NULL);
859
860         pdf_document_thumbnails_get_dimensions (EV_DOCUMENT_THUMBNAILS (pdf_document), page,
861                                                 size, &width, &height);
862         poppler_page_get_size (poppler_page, &unscaled_width, &unscaled_height);
863         scale = width / unscaled_width;
864
865         if (border) {
866                 pixbuf = ev_document_misc_get_thumbnail_frame (width, height, NULL);
867
868                 sub_pixbuf = gdk_pixbuf_new_subpixbuf (pixbuf,
869                                                        1, 1,
870                                                        width - 1, height - 1);
871         } else {
872                 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
873                                          width, height);
874                 gdk_pixbuf_fill (pixbuf, 0xffffffff);
875                 sub_pixbuf = gdk_pixbuf_new_subpixbuf (pixbuf,
876                                                        0, 0,
877                                                        width, height);
878         }
879
880         poppler_page_render_to_pixbuf (poppler_page, 0, 0,
881                                        width, height,
882                                        scale, sub_pixbuf);
883
884         g_object_unref (G_OBJECT (sub_pixbuf));
885
886         g_object_unref (poppler_page);
887         return pixbuf;
888 }
889
890 static GdkPixbuf *
891 pdf_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document_thumbnails,
892                                        gint                  page,
893                                        EvOrientation         orientation,
894                                        gint                  size,
895                                        gboolean              border)
896 {
897         PdfDocument *pdf_document;
898         PopplerPage *poppler_page;
899         GdkPixbuf *pixbuf;
900
901         pdf_document = PDF_DOCUMENT (document_thumbnails);
902
903         poppler_page = poppler_document_get_page (pdf_document->document, page);
904         set_page_orientation (pdf_document, poppler_page, orientation);
905         g_return_val_if_fail (poppler_page != NULL, NULL);
906
907         pixbuf = poppler_page_get_thumbnail (poppler_page);
908         
909         if (pixbuf != NULL) {
910                 /* The document provides its own thumbnails. */
911                 if (border) {
912                         GdkPixbuf *real_pixbuf;
913
914                         real_pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, pixbuf);
915                         g_object_unref (pixbuf);
916                         pixbuf = real_pixbuf;
917                 }
918         } else {
919                 /* There is no provided thumbnail.  We need to make one. */
920                 pixbuf = make_thumbnail_for_size (pdf_document, page, orientation, size, border);
921         }
922
923         g_object_unref (poppler_page);
924         
925         return pixbuf;
926 }
927
928 static void
929 pdf_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnails,
930                                         gint                  page,
931                                         gint                  size,
932                                         gint                 *width,
933                                         gint                 *height)
934 {
935         PdfDocument *pdf_document;
936         PopplerPage *poppler_page;
937         gint has_thumb;
938         
939         pdf_document = PDF_DOCUMENT (document_thumbnails);
940         poppler_page = poppler_document_get_page (pdf_document->document, page);
941
942         g_return_if_fail (width != NULL);
943         g_return_if_fail (height != NULL);
944         g_return_if_fail (poppler_page != NULL);
945
946         has_thumb = poppler_page_get_thumbnail_size (poppler_page, width, height);
947
948         if (!has_thumb) {
949                 double page_width, page_height;
950
951                 poppler_page_get_size (poppler_page, &page_width, &page_height);
952                 if (page_width > page_height) {
953                         *width = size;
954                         *height = (int) (size * page_height / page_width);
955                 } else {
956                         *width = (int) (size * page_width / page_height);
957                         *height = size;
958                 }
959         }
960         g_object_unref (poppler_page);
961 }
962
963 static void
964 pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
965 {
966         iface->get_thumbnail = pdf_document_thumbnails_get_thumbnail;
967         iface->get_dimensions = pdf_document_thumbnails_get_dimensions;
968 }
969
970
971 static gboolean
972 pdf_document_search_idle_callback (void *data)
973 {
974         PdfDocumentSearch *search = (PdfDocumentSearch*) data;
975         PdfDocument *pdf_document = search->document;
976         int n_pages;
977         GList *matches;
978         PopplerPage *page;
979
980         page = poppler_document_get_page (search->document->document,
981                                           search->search_page);
982
983         ev_document_doc_mutex_lock ();
984         matches = poppler_page_find_text (page, search->text);
985         ev_document_doc_mutex_unlock ();
986
987         g_object_unref (page);
988
989         search->pages[search->search_page] = matches;
990         ev_document_find_changed (EV_DOCUMENT_FIND (pdf_document),
991                                   search->search_page);
992
993         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (search->document));
994         search->search_page += 1;
995         if (search->search_page == n_pages) {
996                 /* wrap around */
997                 search->search_page = 0;
998         }
999
1000         if (search->search_page != search->start_page) {
1001                 return TRUE;
1002         }
1003
1004         /* We're done. */
1005         search->idle = 0; /* will return FALSE to remove */
1006         return FALSE;
1007 }
1008
1009
1010 static PdfDocumentSearch *
1011 pdf_document_search_new (PdfDocument *pdf_document,
1012                          int          start_page,
1013                          const char  *text)
1014 {
1015         PdfDocumentSearch *search;
1016         int n_pages;
1017         int i;
1018
1019         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (pdf_document));
1020
1021         search = g_new0 (PdfDocumentSearch, 1);
1022
1023         search->text = g_strdup (text);
1024         search->pages = g_new0 (GList *, n_pages);
1025         for (i = 0; i < n_pages; i++) {
1026                 search->pages[i] = NULL;
1027         }
1028
1029         search->document = pdf_document;
1030
1031         /* We add at low priority so the progress bar repaints */
1032         search->idle = g_idle_add_full (G_PRIORITY_LOW,
1033                                         pdf_document_search_idle_callback,
1034                                         search,
1035                                         NULL);
1036
1037         search->start_page = start_page;
1038         search->search_page = start_page;
1039
1040         return search;
1041 }
1042
1043 static void
1044 pdf_document_find_begin (EvDocumentFind   *document,
1045                          int               page,
1046                          const char       *search_string,
1047                          gboolean          case_sensitive)
1048 {
1049         PdfDocument *pdf_document = PDF_DOCUMENT (document);
1050
1051         /* FIXME handle case_sensitive (right now XPDF
1052          * code is always case insensitive for ASCII
1053          * and case sensitive for all other languaages)
1054          */
1055
1056         if (pdf_document->search &&
1057             strcmp (search_string, pdf_document->search->text) == 0)
1058                 return;
1059
1060         if (pdf_document->search)
1061                 pdf_document_search_free (pdf_document->search);
1062
1063         pdf_document->search = pdf_document_search_new (pdf_document,
1064                                                         page,
1065                                                         search_string);
1066 }
1067
1068 int
1069 pdf_document_find_get_n_results (EvDocumentFind *document_find, int page)
1070 {
1071         PdfDocumentSearch *search = PDF_DOCUMENT (document_find)->search;
1072
1073         if (search) {
1074                 return g_list_length (search->pages[page]);
1075         } else {
1076                 return 0;
1077         }
1078 }
1079
1080 gboolean
1081 pdf_document_find_get_result (EvDocumentFind *document_find,
1082                               int             page,
1083                               int             n_result,
1084                               EvRectangle    *rectangle)
1085 {
1086         PdfDocument *pdf_document = PDF_DOCUMENT (document_find);
1087         PdfDocumentSearch *search = pdf_document->search;
1088         PopplerPage *poppler_page;
1089         PopplerRectangle *r;
1090         double height;
1091
1092         if (search == NULL)
1093                 return FALSE;
1094
1095         r = (PopplerRectangle *) g_list_nth_data (search->pages[page],
1096                                                   n_result);
1097         if (r == NULL)
1098                 return FALSE;
1099
1100         poppler_page = poppler_document_get_page (pdf_document->document, page);
1101         poppler_page_get_size (poppler_page, NULL, &height);
1102         rectangle->x1 = r->x1;
1103         rectangle->y1 = height - r->y2;
1104         rectangle->x2 = r->x2;
1105         rectangle->y2 = height - r->y1;
1106         g_object_unref (poppler_page);
1107                 
1108         return TRUE;
1109 }
1110
1111 int
1112 pdf_document_find_page_has_results (EvDocumentFind *document_find,
1113                                     int             page)
1114 {
1115         PdfDocumentSearch *search = PDF_DOCUMENT (document_find)->search;
1116
1117         g_return_val_if_fail (search != NULL, FALSE);
1118
1119         return search->pages[page] != NULL;
1120 }
1121
1122 double
1123 pdf_document_find_get_progress (EvDocumentFind *document_find)
1124 {
1125         PdfDocumentSearch *search;
1126         int n_pages, pages_done;
1127
1128         search = PDF_DOCUMENT (document_find)->search;
1129
1130         if (search == NULL) {
1131                 return 0;
1132         }
1133
1134         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (document_find));
1135         if (search->search_page > search->start_page) {
1136                 pages_done = search->search_page - search->start_page + 1;
1137         } else if (search->search_page == search->start_page) {
1138                 pages_done = n_pages;
1139         } else {
1140                 pages_done = n_pages - search->start_page + search->search_page;
1141         }
1142
1143         return pages_done / (double) n_pages;
1144 }
1145
1146 static void
1147 pdf_document_find_cancel (EvDocumentFind *document)
1148 {
1149         PdfDocument *pdf_document = PDF_DOCUMENT (document);
1150
1151         if (pdf_document->search) {
1152                 pdf_document_search_free (pdf_document->search);
1153                 pdf_document->search = NULL;
1154         }
1155 }
1156
1157 static void
1158 pdf_document_find_iface_init (EvDocumentFindIface *iface)
1159 {
1160         iface->begin = pdf_document_find_begin;
1161         iface->get_n_results = pdf_document_find_get_n_results;
1162         iface->get_result = pdf_document_find_get_result;
1163         iface->page_has_results = pdf_document_find_page_has_results;
1164         iface->get_progress = pdf_document_find_get_progress;
1165         iface->cancel = pdf_document_find_cancel;
1166 }
1167
1168 static void
1169 pdf_document_ps_exporter_begin (EvPSExporter *exporter, const char *filename,
1170                                 int first_page, int last_page,
1171                                 double width, double height, gboolean duplex)
1172 {
1173         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1174         
1175         pdf_document->ps_file = poppler_ps_file_new (pdf_document->document, filename,
1176                                                      first_page,
1177                                                      last_page - first_page + 1);
1178         poppler_ps_file_set_paper_size (pdf_document->ps_file, width, height);
1179         poppler_ps_file_set_duplex (pdf_document->ps_file, duplex);
1180 }
1181
1182 static void
1183 pdf_document_ps_exporter_do_page (EvPSExporter *exporter, EvRenderContext *rc)
1184 {
1185         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1186         PopplerPage *poppler_page;
1187
1188         g_return_if_fail (pdf_document->ps_file != NULL);
1189
1190         poppler_page = poppler_document_get_page (pdf_document->document, rc->page);
1191         set_page_orientation (pdf_document, poppler_page, rc->orientation);
1192         poppler_page_render_to_ps (poppler_page, pdf_document->ps_file);
1193         g_object_unref (poppler_page);
1194 }
1195
1196 static void
1197 pdf_document_ps_exporter_end (EvPSExporter *exporter)
1198 {
1199         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1200
1201         poppler_ps_file_free (pdf_document->ps_file);
1202         pdf_document->ps_file = NULL;
1203 }
1204
1205 static void
1206 pdf_document_ps_exporter_iface_init (EvPSExporterIface *iface)
1207 {
1208         iface->begin = pdf_document_ps_exporter_begin;
1209         iface->do_page = pdf_document_ps_exporter_do_page;
1210         iface->end = pdf_document_ps_exporter_end;
1211 }
1212
1213
1214 void
1215 pdf_selection_render_selection (EvSelection      *selection,
1216                                 EvRenderContext  *rc,
1217                                 GdkPixbuf       **pixbuf,
1218                                 EvRectangle      *points,
1219                                 EvRectangle      *old_points)
1220 {
1221         PdfDocument *pdf_document;
1222         PopplerPage *poppler_page;
1223         double width_points, height_points;
1224         gint width, height;
1225
1226         pdf_document = PDF_DOCUMENT (selection);
1227         poppler_page = poppler_document_get_page (pdf_document->document,
1228                                                   rc->page);
1229         set_page_orientation (pdf_document, poppler_page, rc->orientation);
1230
1231         poppler_page_get_size (poppler_page, &width_points, &height_points);
1232         width = (int) ((width_points * rc->scale) + 0.5);
1233         height = (int) ((height_points * rc->scale) + 0.5);
1234
1235         if (*pixbuf == NULL) {
1236                 * pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
1237                                            TRUE, 8,
1238                                            width, height);
1239         }
1240         
1241         poppler_page_render_selection (poppler_page,
1242                                        rc->scale, *pixbuf,
1243                                        (PopplerRectangle *)points,
1244                                        (PopplerRectangle *)old_points);
1245         g_object_unref (poppler_page);
1246
1247 }
1248
1249
1250 GdkRegion *
1251 pdf_selection_get_selection_region (EvSelection     *selection,
1252                                     EvRenderContext *rc,
1253                                     EvRectangle     *points)
1254 {
1255         PdfDocument *pdf_document;
1256         PopplerPage *poppler_page;
1257         GdkRegion *retval;
1258
1259         pdf_document = PDF_DOCUMENT (selection);
1260         poppler_page = poppler_document_get_page (pdf_document->document,
1261                                                   rc->page);
1262         set_page_orientation (pdf_document, poppler_page, rc->orientation);
1263
1264         retval = poppler_page_get_selection_region (poppler_page, rc->scale, (PopplerRectangle *) points);
1265         g_object_unref (poppler_page);
1266
1267         return retval;
1268 }
1269
1270 GdkRegion *
1271 pdf_selection_get_selection_map (EvSelection     *selection,
1272                                  EvRenderContext *rc)
1273 {
1274         PdfDocument *pdf_document;
1275         PopplerPage *poppler_page;
1276         PopplerRectangle points;
1277         GdkRegion *retval;
1278
1279         pdf_document = PDF_DOCUMENT (selection);
1280         poppler_page = poppler_document_get_page (pdf_document->document,
1281                                                   rc->page);
1282         set_page_orientation (pdf_document, poppler_page, rc->orientation);
1283
1284         points.x1 = 0.0;
1285         points.y1 = 0.0;
1286         poppler_page_get_size (poppler_page, &(points.x2), &(points.y2));
1287         retval = poppler_page_get_selection_region (poppler_page, 1.0, &points);
1288         g_object_unref (poppler_page);
1289
1290         return retval;
1291 }
1292
1293 static void
1294 pdf_selection_iface_init (EvSelectionIface *iface)
1295 {
1296         iface->render_selection = pdf_selection_render_selection;
1297         iface->get_selection_region = pdf_selection_get_selection_region;
1298         iface->get_selection_map = pdf_selection_get_selection_map;
1299 }
1300
1301 PdfDocument *
1302 pdf_document_new (void)
1303 {
1304         return PDF_DOCUMENT (g_object_new (PDF_TYPE_DOCUMENT, NULL));
1305 }