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