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