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