]> www.fi.muni.cz Git - evince.git/blob - backend/pdf/ev-poppler.cc
d68c7b173a97219f9fe2d2f9231bbfffba5e6e4b
[evince.git] / backend / pdf / ev-poppler.cc
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /* this file is part of evince, a gnome document viewer
3  *
4  * Copyright (C) 2009, Juanjo MarĂ­n <juanj.marin@juntadeandalucia.es>
5  * Copyright (C) 2004, Red Hat, Inc.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23
24 #include <math.h>
25 #include <string.h>
26 #include <gtk/gtk.h>
27 #include <poppler.h>
28 #include <poppler-document.h>
29 #include <poppler-page.h>
30 #ifdef HAVE_CAIRO_PDF
31 #include <cairo-pdf.h>
32 #endif
33 #ifdef HAVE_CAIRO_PS
34 #include <cairo-ps.h>
35 #endif
36 #include <glib/gi18n-lib.h>
37
38 #include "ev-poppler.h"
39 #include "ev-file-exporter.h"
40 #include "ev-document-find.h"
41 #include "ev-document-misc.h"
42 #include "ev-document-links.h"
43 #include "ev-document-images.h"
44 #include "ev-document-fonts.h"
45 #include "ev-document-security.h"
46 #include "ev-document-transition.h"
47 #include "ev-document-forms.h"
48 #include "ev-document-layers.h"
49 #include "ev-document-print.h"
50 #include "ev-document-annotations.h"
51 #include "ev-document-attachments.h"
52 #include "ev-document-text.h"
53 #include "ev-selection.h"
54 #include "ev-transition-effect.h"
55 #include "ev-attachment.h"
56 #include "ev-image.h"
57
58 #include <libxml/tree.h>
59 #include <libxml/parser.h>
60 #include <libxml/xpath.h>
61 #include <libxml/xpathInternals.h>
62
63 #if (defined (HAVE_CAIRO_PDF) || defined (HAVE_CAIRO_PS))
64 #define HAVE_CAIRO_PRINT
65 #endif
66
67 /* fields from the XMP Rights Management Schema, XMP Specification Sept 2005, pag. 45 */
68 #define LICENSE_MARKED "/x:xmpmeta/rdf:RDF/rdf:Description/xmpRights:Marked"
69 #define LICENSE_TEXT "/x:xmpmeta/rdf:RDF/rdf:Description/dc:rights/rdf:Alt/rdf:li[lang('%s')]"
70 #define LICENSE_WEB_STATEMENT "/x:xmpmeta/rdf:RDF/rdf:Description/xmpRights:WebStatement"
71 /* license field from Creative Commons schema, http://creativecommons.org/ns */
72 #define LICENSE_URI "/x:xmpmeta/rdf:RDF/rdf:Description/cc:license/@rdf:resource"
73
74 typedef struct {
75         EvFileExporterFormat format;
76
77         /* Pages per sheet */
78         gint pages_per_sheet;
79         gint pages_printed;
80         gint pages_x;
81         gint pages_y;
82         gdouble paper_width;
83         gdouble paper_height;
84         
85 #ifdef HAVE_CAIRO_PRINT
86         cairo_t *cr;
87 #else
88         PopplerPSFile *ps_file;
89 #endif
90 } PdfPrintContext;
91
92 struct _PdfDocumentClass
93 {
94         EvDocumentClass parent_class;
95 };
96
97 struct _PdfDocument
98 {
99         EvDocument parent_instance;
100
101         PopplerDocument *document;
102         gchar *password;
103         gboolean forms_modified;
104         gboolean annots_modified;
105
106         PopplerFontInfo *font_info;
107         PopplerFontsIter *fonts_iter;
108         int fonts_scanned_pages;
109
110         PdfPrintContext *print_ctx;
111
112         GList *layers;
113         GHashTable *annots;
114 };
115
116 static void pdf_document_security_iface_init             (EvDocumentSecurityInterface    *iface);
117 static void pdf_document_document_links_iface_init       (EvDocumentLinksInterface       *iface);
118 static void pdf_document_document_images_iface_init      (EvDocumentImagesInterface      *iface);
119 static void pdf_document_document_forms_iface_init       (EvDocumentFormsInterface       *iface);
120 static void pdf_document_document_fonts_iface_init       (EvDocumentFontsInterface       *iface);
121 static void pdf_document_document_layers_iface_init      (EvDocumentLayersInterface      *iface);
122 static void pdf_document_document_print_iface_init       (EvDocumentPrintInterface       *iface);
123 static void pdf_document_document_annotations_iface_init (EvDocumentAnnotationsInterface *iface);
124 static void pdf_document_document_attachments_iface_init (EvDocumentAttachmentsInterface *iface);
125 static void pdf_document_find_iface_init                 (EvDocumentFindInterface        *iface);
126 static void pdf_document_file_exporter_iface_init        (EvFileExporterInterface        *iface);
127 static void pdf_selection_iface_init                     (EvSelectionInterface           *iface);
128 static void pdf_document_page_transition_iface_init      (EvDocumentTransitionInterface  *iface);
129 static void pdf_document_text_iface_init                 (EvDocumentTextInterface        *iface);
130 static int  pdf_document_get_n_pages                     (EvDocument                     *document);
131
132 static EvLinkDest *ev_link_dest_from_dest    (PdfDocument       *pdf_document,
133                                               PopplerDest       *dest);
134 static EvLink     *ev_link_from_action       (PdfDocument       *pdf_document,
135                                               PopplerAction     *action);
136 static void        pdf_print_context_free    (PdfPrintContext   *ctx);
137 static gboolean    attachment_save_to_buffer (PopplerAttachment *attachment,
138                                               gchar            **buffer,
139                                               gsize             *buffer_size,
140                                               GError           **error);
141
142 EV_BACKEND_REGISTER_WITH_CODE (PdfDocument, pdf_document,
143                          {
144                                  EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_SECURITY,
145                                                                  pdf_document_security_iface_init);
146                                  EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_LINKS,
147                                                                  pdf_document_document_links_iface_init);
148                                  EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_IMAGES,
149                                                                  pdf_document_document_images_iface_init);
150                                  EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FORMS,
151                                                                  pdf_document_document_forms_iface_init);
152                                  EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FONTS,
153                                                                  pdf_document_document_fonts_iface_init);
154                                  EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_LAYERS,
155                                                                  pdf_document_document_layers_iface_init);
156                                  EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_PRINT,
157                                                                  pdf_document_document_print_iface_init);
158                                  EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_ANNOTATIONS,
159                                                                  pdf_document_document_annotations_iface_init);
160                                  EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_ATTACHMENTS,
161                                                                  pdf_document_document_attachments_iface_init);
162                                  EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FIND,
163                                                                  pdf_document_find_iface_init);
164                                  EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_FILE_EXPORTER,
165                                                                  pdf_document_file_exporter_iface_init);
166                                  EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_SELECTION,
167                                                                  pdf_selection_iface_init);
168                                  EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_TRANSITION,
169                                                                  pdf_document_page_transition_iface_init);
170                                  EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_TEXT,
171                                                                  pdf_document_text_iface_init);
172                          });
173
174 static void
175 pdf_document_dispose (GObject *object)
176 {
177         PdfDocument *pdf_document = PDF_DOCUMENT(object);
178
179         if (pdf_document->print_ctx) {
180                 pdf_print_context_free (pdf_document->print_ctx);
181                 pdf_document->print_ctx = NULL;
182         }
183
184         if (pdf_document->annots) {
185                 g_hash_table_destroy (pdf_document->annots);
186                 pdf_document->annots = NULL;
187         }
188
189         if (pdf_document->document) {
190                 g_object_unref (pdf_document->document);
191         }
192
193         if (pdf_document->font_info) { 
194                 poppler_font_info_free (pdf_document->font_info);
195         }
196
197         if (pdf_document->fonts_iter) {
198                 poppler_fonts_iter_free (pdf_document->fonts_iter);
199         }
200
201         if (pdf_document->layers) {
202                 g_list_foreach (pdf_document->layers, (GFunc)g_object_unref, NULL);
203                 g_list_free (pdf_document->layers);
204         }
205
206         G_OBJECT_CLASS (pdf_document_parent_class)->dispose (object);
207 }
208
209 static void
210 pdf_document_init (PdfDocument *pdf_document)
211 {
212         pdf_document->password = NULL;
213 }
214
215 static void
216 convert_error (GError  *poppler_error,
217                GError **error)
218 {
219         if (poppler_error == NULL)
220                 return;
221
222         if (poppler_error->domain == POPPLER_ERROR) {
223                 /* convert poppler errors into EvDocument errors */
224                 gint code = EV_DOCUMENT_ERROR_INVALID;
225                 if (poppler_error->code == POPPLER_ERROR_INVALID)
226                         code = EV_DOCUMENT_ERROR_INVALID;
227                 else if (poppler_error->code == POPPLER_ERROR_ENCRYPTED)
228                         code = EV_DOCUMENT_ERROR_ENCRYPTED;
229                         
230                 g_set_error_literal (error,
231                                      EV_DOCUMENT_ERROR,
232                                      code,
233                                      poppler_error->message);
234
235                 g_error_free (poppler_error);
236         } else {
237                 g_propagate_error (error, poppler_error);
238         }
239 }
240
241
242 /* EvDocument */
243 static gboolean
244 pdf_document_save (EvDocument  *document,
245                    const char  *uri,
246                    GError     **error)
247 {
248         PdfDocument *pdf_document = PDF_DOCUMENT (document);
249         gboolean retval;
250         GError *poppler_error = NULL;
251
252         if (pdf_document->forms_modified || pdf_document->annots_modified) {
253                 retval = poppler_document_save (pdf_document->document,
254                                                 uri, &poppler_error);
255                 if (retval) {
256                         pdf_document->forms_modified = FALSE;
257                         pdf_document->annots_modified = FALSE;
258                 }
259         } else {
260                 retval = poppler_document_save_a_copy (pdf_document->document,
261                                                        uri, &poppler_error);
262         }
263                                                        
264         if (! retval)
265                 convert_error (poppler_error, error);
266
267         return retval;
268 }
269
270 static gboolean
271 pdf_document_load (EvDocument   *document,
272                    const char   *uri,
273                    GError      **error)
274 {
275         GError *poppler_error = NULL;
276         PdfDocument *pdf_document = PDF_DOCUMENT (document);
277
278         pdf_document->document =
279                 poppler_document_new_from_file (uri, pdf_document->password, &poppler_error);
280
281         if (pdf_document->document == NULL) {
282                 convert_error (poppler_error, error);
283                 return FALSE;
284         }
285
286         return TRUE;
287 }
288
289 static int
290 pdf_document_get_n_pages (EvDocument *document)
291 {
292         return poppler_document_get_n_pages (PDF_DOCUMENT (document)->document);
293 }
294
295 static EvPage *
296 pdf_document_get_page (EvDocument *document,
297                        gint        index)
298 {
299         PdfDocument *pdf_document = PDF_DOCUMENT (document);
300         PopplerPage *poppler_page;
301         EvPage      *page;
302
303         poppler_page = poppler_document_get_page (pdf_document->document, index);
304         page = ev_page_new (index);
305         page->backend_page = (EvBackendPage)g_object_ref (poppler_page);
306         page->backend_destroy_func = (EvBackendPageDestroyFunc)g_object_unref;
307         g_object_unref (poppler_page);
308
309         return page;
310 }
311
312 static void
313 pdf_document_get_page_size (EvDocument *document,
314                             EvPage     *page,
315                             double     *width,
316                             double     *height)
317 {
318         g_return_if_fail (POPPLER_IS_PAGE (page->backend_page));
319         
320         poppler_page_get_size (POPPLER_PAGE (page->backend_page), width, height);
321 }
322
323 static char *
324 pdf_document_get_page_label (EvDocument *document,
325                              EvPage     *page)
326 {
327         char *label = NULL;
328
329         g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
330
331         g_object_get (G_OBJECT (page->backend_page),
332                       "label", &label,
333                       NULL);
334         return label;
335 }
336
337 static cairo_surface_t *
338 pdf_page_render (PopplerPage     *page,
339                  gint             width,
340                  gint             height,
341                  EvRenderContext *rc)
342 {
343         cairo_surface_t *surface;
344         cairo_t *cr;
345
346         surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
347                                               width, height);
348         cr = cairo_create (surface);
349
350         switch (rc->rotation) {
351                 case 90:
352                         cairo_translate (cr, width, 0);
353                         break;
354                 case 180:
355                         cairo_translate (cr, width, height);
356                         break;
357                 case 270:
358                         cairo_translate (cr, 0, height);
359                         break;
360                 default:
361                         cairo_translate (cr, 0, 0);
362         }
363         cairo_scale (cr, rc->scale, rc->scale);
364         cairo_rotate (cr, rc->rotation * G_PI / 180.0);
365         poppler_page_render (page, cr);
366
367         cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
368         cairo_set_source_rgb (cr, 1., 1., 1.);
369         cairo_paint (cr);
370
371         cairo_destroy (cr);
372
373         return surface;
374 }
375
376 static cairo_surface_t *
377 pdf_document_render (EvDocument      *document,
378                      EvRenderContext *rc)
379 {
380         PdfDocument *pdf_document;
381         PopplerPage *poppler_page;
382         double width_points, height_points;
383         gint width, height;
384
385         poppler_page = POPPLER_PAGE (rc->page->backend_page);
386
387         poppler_page_get_size (poppler_page,
388                                &width_points, &height_points);
389         
390         if (rc->rotation == 90 || rc->rotation == 270) {
391                 width = (int) ((height_points * rc->scale) + 0.5);
392                 height = (int) ((width_points * rc->scale) + 0.5);
393         } else {
394                 width = (int) ((width_points * rc->scale) + 0.5);
395                 height = (int) ((height_points * rc->scale) + 0.5);
396         }
397         
398         return pdf_page_render (poppler_page,
399                                 width, height, rc);
400 }
401
402 static GdkPixbuf *
403 make_thumbnail_for_page (PopplerPage     *poppler_page,
404                          EvRenderContext *rc,
405                          gint             width,
406                          gint             height)
407 {
408         GdkPixbuf *pixbuf;
409
410 #ifdef POPPLER_WITH_GDK
411         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
412                                  width, height);
413         gdk_pixbuf_fill (pixbuf, 0xffffffff);
414
415         ev_document_fc_mutex_lock ();
416         poppler_page_render_to_pixbuf (poppler_page, 0, 0,
417                                        width, height,
418                                        rc->scale, rc->rotation, pixbuf);
419         ev_document_fc_mutex_unlock ();
420 #else
421         cairo_surface_t *surface;
422
423         ev_document_fc_mutex_lock ();
424         surface = pdf_page_render (poppler_page, width, height, rc);
425         ev_document_fc_mutex_unlock ();
426         
427         pixbuf = ev_document_misc_pixbuf_from_surface (surface);
428         cairo_surface_destroy (surface);
429 #endif /* POPPLER_WITH_GDK */
430
431         return pixbuf;
432 }
433
434 static GdkPixbuf *
435 pdf_document_get_thumbnail (EvDocument      *document,
436                             EvRenderContext *rc)
437 {
438         PdfDocument *pdf_document = PDF_DOCUMENT (document);
439         PopplerPage *poppler_page;
440         GdkPixbuf *pixbuf = NULL;
441         GdkPixbuf *border_pixbuf;
442         double page_width, page_height;
443         gint width, height;
444
445         poppler_page = POPPLER_PAGE (rc->page->backend_page);
446
447         poppler_page_get_size (poppler_page,
448                                &page_width, &page_height);
449
450         width = MAX ((gint)(page_width * rc->scale + 0.5), 1);
451         height = MAX ((gint)(page_height * rc->scale + 0.5), 1);
452
453         if (rc->rotation == 90 || rc->rotation == 270) {
454                 gint  temp;
455
456                 temp = width;
457                 width = height;
458                 height = temp;
459         }
460
461 #ifdef POPPLER_WITH_GDK
462         pixbuf = poppler_page_get_thumbnail_pixbuf (poppler_page);
463 #else
464         cairo_surface_t *surface;
465         
466         surface = poppler_page_get_thumbnail (poppler_page);
467         if (surface) {
468                 pixbuf = ev_document_misc_pixbuf_from_surface (surface);
469                 cairo_surface_destroy (surface);
470         }
471 #endif /* POPPLER_WITH_GDK */
472
473         if (pixbuf != NULL) {
474                 int thumb_width = (rc->rotation == 90 || rc->rotation == 270) ?
475                         gdk_pixbuf_get_height (pixbuf) :
476                         gdk_pixbuf_get_width (pixbuf);
477
478                 if (thumb_width == width) {
479                         GdkPixbuf *rotated_pixbuf;
480
481                         rotated_pixbuf = gdk_pixbuf_rotate_simple (pixbuf,
482                                                                    (GdkPixbufRotation) (360 - rc->rotation));
483                         g_object_unref (pixbuf);
484                         pixbuf = rotated_pixbuf;
485                 } else {
486                         /* The provided thumbnail has a different size */
487                         g_object_unref (pixbuf);
488                         pixbuf = make_thumbnail_for_page (poppler_page, rc, width, height);
489                 }
490         } else {
491                 /* There is no provided thumbnail. We need to make one. */
492                 pixbuf = make_thumbnail_for_page (poppler_page, rc, width, height);
493         }
494
495         return pixbuf;
496 }
497
498 /* reference:
499 http://www.pdfa.org/lib/exe/fetch.php?id=pdfa%3Aen%3Atechdoc&cache=cache&media=pdfa:techdoc:tn0001_pdfa-1_and_namespaces_2008-03-18.pdf */
500 static char *
501 pdf_document_get_format_from_metadata (xmlDocPtr          doc,
502                                        xmlXPathContextPtr xpathCtx)
503 {
504         xmlXPathObjectPtr xpathObj;
505         xmlChar *part = NULL;
506         xmlChar *conf = NULL;
507         char *result = NULL;
508         int i;
509
510         /* add pdf/a namespaces */
511         xmlXPathRegisterNs (xpathCtx, BAD_CAST "x", BAD_CAST "adobe:ns:meta/");
512         xmlXPathRegisterNs (xpathCtx, BAD_CAST "rdf", BAD_CAST "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
513         xmlXPathRegisterNs (xpathCtx, BAD_CAST "pdfaid", BAD_CAST "http://www.aiim.org/pdfa/ns/id/");
514
515         /* reads pdf/a part */
516         /* first syntax: child node */
517         xpathObj = xmlXPathEvalExpression (BAD_CAST "/x:xmpmeta/rdf:RDF/rdf:Description/pdfaid:part", xpathCtx);
518         if (xpathObj != NULL) {
519                 if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr != 0)
520                         part = xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
521
522                 xmlXPathFreeObject (xpathObj);
523         }
524         if (part == NULL) {
525                 /* second syntax: attribute */
526                 xpathObj = xmlXPathEvalExpression (BAD_CAST "/x:xmpmeta/rdf:RDF/rdf:Description/@pdfaid:part", xpathCtx);
527                 if (xpathObj != NULL) {
528                         if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr != 0)
529                                 part = xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
530
531                         xmlXPathFreeObject (xpathObj);
532                 }
533         }
534
535         /* reads pdf/a conformance */
536         /* first syntax: child node */
537         xpathObj = xmlXPathEvalExpression (BAD_CAST "/x:xmpmeta/rdf:RDF/rdf:Description/pdfaid:conformance", xpathCtx);
538         if (xpathObj != NULL) {
539                 if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr != 0)
540                         conf = xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
541
542                 xmlXPathFreeObject (xpathObj);
543         }
544         if (conf == NULL) {
545                 /* second syntax: attribute */
546                 xpathObj = xmlXPathEvalExpression (BAD_CAST "/x:xmpmeta/rdf:RDF/rdf:Description/@pdfaid:conformance", xpathCtx);
547                 if (xpathObj != NULL) {
548                         if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr != 0)
549                                 conf = xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
550
551                         xmlXPathFreeObject (xpathObj);
552                 }
553         }
554
555         if (part != NULL && conf != NULL) {
556                 /* makes conf lowercase */
557                 for (i = 0; conf[i]; i++)
558                         conf[i] = g_ascii_tolower (conf[i]);
559
560                 /* return buffer */
561                 result = g_strdup_printf ("PDF/A - %s%s", part, conf);
562         }
563
564         /* Cleanup */
565         xmlFree (part);
566         xmlFree (conf);
567
568         return result;
569 }
570
571 static EvDocumentLicense *
572 pdf_document_get_license_from_metadata (xmlDocPtr          doc,
573                                         xmlXPathContextPtr xpathCtx)
574 {
575         xmlXPathObjectPtr xpathObj;
576         xmlChar *marked = NULL;
577         const char *language_string;
578         char  *aux;
579         gchar **tags;
580         gchar *tag, *tag_aux;
581         int i, j;
582         EvDocumentLicense *license;
583
584         /* register namespaces */
585         xmlXPathRegisterNs (xpathCtx, BAD_CAST "x", BAD_CAST "adobe:ns:meta/");
586         xmlXPathRegisterNs (xpathCtx, BAD_CAST "rdf", BAD_CAST "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
587         xmlXPathRegisterNs (xpathCtx, BAD_CAST "dc", BAD_CAST "http://purl.org/dc/elements/1.1/");
588         /* XMP Rights Management Schema */
589         xmlXPathRegisterNs (xpathCtx, BAD_CAST "xmpRights", BAD_CAST "http://ns.adobe.com/xap/1.0/rights/");
590         /* Creative Commons Schema */
591         xmlXPathRegisterNs (xpathCtx, BAD_CAST "cc", BAD_CAST "http://creativecommons.org/ns#");
592
593         /* checking if the document has been marked as defined on the XMP Rights
594          * Management Schema */
595         xpathObj = xmlXPathEvalExpression (BAD_CAST LICENSE_MARKED, xpathCtx);
596         if (xpathObj != NULL) {
597                 if (xpathObj->nodesetval != NULL &&
598                     xpathObj->nodesetval->nodeNr != 0)
599                         marked = xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
600                 xmlXPathFreeObject (xpathObj);
601         }
602
603         /* a) Not marked => No XMP Rights information */
604         if (!marked) {
605                 xmlFree (marked);
606                 return NULL;
607         }
608
609         license = ev_document_license_new ();
610
611         /* b) Marked False => Public Domain, no copyrighted material and no
612          * license needed */
613         if (g_strrstr ((char *) marked, "False") != NULL) {
614                 license->text = g_strdup (_("This work is in the Public Domain"));
615         /* c) Marked True => Copyrighted material */
616         } else {
617                 /* Checking usage terms as defined by the XMP Rights Management
618                  * Schema. This field is recomended to be checked by Creative
619                  * Commons */
620                 /* 1) checking for a suitable localized string */
621                 language_string = pango_language_to_string (gtk_get_default_language ());
622                 tags = g_strsplit (language_string, "-", -1);
623                 i = g_strv_length (tags);
624                 while (i-- && !license->text) {
625                         tag = g_strdup (tags[0]);
626                         for (j = 1; j <= i; j++) {
627                                 tag_aux = g_strdup_printf ("%s-%s", tag, tags[j]);
628                                 g_free (tag);
629                                 tag = tag_aux;
630                         }
631                         aux = g_strdup_printf (LICENSE_TEXT, tag);
632                         xpathObj = xmlXPathEvalExpression (BAD_CAST aux, xpathCtx);
633                         if (xpathObj != NULL) {
634                                 if (xpathObj->nodesetval != NULL &&
635                                     xpathObj->nodesetval->nodeNr != 0)
636                                         license->text = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
637                                 xmlXPathFreeObject (xpathObj);
638                         }
639                         g_free (tag);
640                         g_free (aux);
641                 }
642                 g_strfreev(tags);
643
644                 /* 2) if not, use the default string */
645                 if (!license->text) {
646                         aux = g_strdup_printf (LICENSE_TEXT, "x-default");
647                         xpathObj = xmlXPathEvalExpression (BAD_CAST aux, xpathCtx);
648                         if (xpathObj != NULL) {
649                                 if (xpathObj->nodesetval != NULL &&
650                                     xpathObj->nodesetval->nodeNr != 0)
651                                         license->text = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
652                                 xmlXPathFreeObject (xpathObj);
653                         }
654                         g_free (aux);
655                 }
656
657                 /* Checking the license URI as defined by the Creative Commons
658                  * Schema. This field is recomended to be checked by Creative
659                  * Commons */
660                 xpathObj = xmlXPathEvalExpression (BAD_CAST LICENSE_URI, xpathCtx);
661                 if (xpathObj != NULL) {
662                         if (xpathObj->nodesetval != NULL &&
663                             xpathObj->nodesetval->nodeNr != 0)
664                                 license->uri = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
665                         xmlXPathFreeObject (xpathObj);
666                 }
667
668                 /* Checking the web statement as defined by the XMP Rights
669                  * Management Schema. Checking it out is a sort of above-and-beyond
670                  * the basic recommendations by Creative Commons. It can be
671                  * considered as a "reinforcement" approach to add certainty. */
672                 xpathObj = xmlXPathEvalExpression (BAD_CAST LICENSE_WEB_STATEMENT, xpathCtx);
673                 if (xpathObj != NULL) {
674                         if (xpathObj->nodesetval != NULL &&
675                             xpathObj->nodesetval->nodeNr != 0)
676                                 license->web_statement = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
677                         xmlXPathFreeObject (xpathObj);
678                 }
679         }
680         xmlFree (marked);
681
682         if (!license->text && !license->uri && !license->web_statement) {
683                 ev_document_license_free (license);
684                 return NULL;
685         }
686
687         return license;
688 }
689
690 static void
691 pdf_document_parse_metadata (const gchar    *metadata,
692                              EvDocumentInfo *info)
693 {
694         xmlDocPtr          doc;
695         xmlXPathContextPtr xpathCtx;
696         gchar             *fmt;
697
698         doc = xmlParseMemory (metadata, strlen (metadata));
699         if (doc == NULL)
700                 return;         /* invalid xml metadata */
701
702         xpathCtx = xmlXPathNewContext (doc);
703         if (xpathCtx == NULL) {
704                 xmlFreeDoc (doc);
705                 return;         /* invalid xpath context */
706         }
707
708         fmt = pdf_document_get_format_from_metadata (doc, xpathCtx);
709         if (fmt != NULL) {
710                 g_free (info->format);
711                 info->format = fmt;
712         }
713
714         info->license = pdf_document_get_license_from_metadata (doc, xpathCtx);
715
716         xmlXPathFreeContext (xpathCtx);
717         xmlFreeDoc (doc);
718 }
719
720
721 static EvDocumentInfo *
722 pdf_document_get_info (EvDocument *document)
723 {
724         EvDocumentInfo *info;
725         PopplerPageLayout layout;
726         PopplerPageMode mode;
727         PopplerViewerPreferences view_prefs;
728         PopplerPermissions permissions;
729         EvPage *page;
730         char *metadata;
731
732         info = g_new0 (EvDocumentInfo, 1);
733
734         info->fields_mask = EV_DOCUMENT_INFO_TITLE |
735                             EV_DOCUMENT_INFO_FORMAT |
736                             EV_DOCUMENT_INFO_AUTHOR |
737                             EV_DOCUMENT_INFO_SUBJECT |
738                             EV_DOCUMENT_INFO_KEYWORDS |
739                             EV_DOCUMENT_INFO_LAYOUT |
740                             EV_DOCUMENT_INFO_START_MODE |
741                             EV_DOCUMENT_INFO_PERMISSIONS |
742                             EV_DOCUMENT_INFO_UI_HINTS |
743                             EV_DOCUMENT_INFO_CREATOR |
744                             EV_DOCUMENT_INFO_PRODUCER |
745                             EV_DOCUMENT_INFO_CREATION_DATE |
746                             EV_DOCUMENT_INFO_MOD_DATE |
747                             EV_DOCUMENT_INFO_LINEARIZED |
748                             EV_DOCUMENT_INFO_N_PAGES |
749                             EV_DOCUMENT_INFO_SECURITY | 
750                             EV_DOCUMENT_INFO_PAPER_SIZE |
751                             EV_DOCUMENT_INFO_LICENSE;
752
753         g_object_get (PDF_DOCUMENT (document)->document,
754                       "title", &(info->title),
755                       "format", &(info->format),
756                       "author", &(info->author),
757                       "subject", &(info->subject),
758                       "keywords", &(info->keywords),
759                       "page-mode", &mode,
760                       "page-layout", &layout,
761                       "viewer-preferences", &view_prefs,
762                       "permissions", &permissions,
763                       "creator", &(info->creator),
764                       "producer", &(info->producer),
765                       "creation-date", &(info->creation_date),
766                       "mod-date", &(info->modified_date),
767                       "linearized", &(info->linearized),
768                       "metadata", &metadata,
769                       NULL);
770
771         if (metadata != NULL) {
772                 pdf_document_parse_metadata (metadata, info);
773                 g_free (metadata);
774         }
775
776         info->n_pages = ev_document_get_n_pages (document);
777
778         if (info->n_pages > 0) {
779                 ev_document_get_page_size (document, 0,
780                                            &(info->paper_width),
781                                            &(info->paper_height));
782                 // Convert to mm.
783                 info->paper_width = info->paper_width / 72.0f * 25.4f;
784                 info->paper_height = info->paper_height / 72.0f * 25.4f;
785         }
786
787         switch (layout) {
788                 case POPPLER_PAGE_LAYOUT_SINGLE_PAGE:
789                         info->layout = EV_DOCUMENT_LAYOUT_SINGLE_PAGE;
790                         break;
791                 case POPPLER_PAGE_LAYOUT_ONE_COLUMN:
792                         info->layout = EV_DOCUMENT_LAYOUT_ONE_COLUMN;
793                         break;
794                 case POPPLER_PAGE_LAYOUT_TWO_COLUMN_LEFT:
795                         info->layout = EV_DOCUMENT_LAYOUT_TWO_COLUMN_LEFT;
796                         break;
797                 case POPPLER_PAGE_LAYOUT_TWO_COLUMN_RIGHT:
798                         info->layout = EV_DOCUMENT_LAYOUT_TWO_COLUMN_RIGHT;
799                 case POPPLER_PAGE_LAYOUT_TWO_PAGE_LEFT:
800                         info->layout = EV_DOCUMENT_LAYOUT_TWO_PAGE_LEFT;
801                         break;
802                 case POPPLER_PAGE_LAYOUT_TWO_PAGE_RIGHT:
803                         info->layout = EV_DOCUMENT_LAYOUT_TWO_PAGE_RIGHT;
804                         break;
805                 default:
806                         break;
807         }
808
809         switch (mode) {
810                 case POPPLER_PAGE_MODE_NONE:
811                         info->mode = EV_DOCUMENT_MODE_NONE;
812                         break;
813                 case POPPLER_PAGE_MODE_USE_THUMBS:
814                         info->mode = EV_DOCUMENT_MODE_USE_THUMBS;
815                         break;
816                 case POPPLER_PAGE_MODE_USE_OC:
817                         info->mode = EV_DOCUMENT_MODE_USE_OC;
818                         break;
819                 case POPPLER_PAGE_MODE_FULL_SCREEN:
820                         info->mode = EV_DOCUMENT_MODE_FULL_SCREEN;
821                         break;
822                 case POPPLER_PAGE_MODE_USE_ATTACHMENTS:
823                         info->mode = EV_DOCUMENT_MODE_USE_ATTACHMENTS;
824                 default:
825                         break;
826         }
827
828         info->ui_hints = 0;
829         if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_TOOLBAR) {
830                 info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_TOOLBAR;
831         }
832         if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_MENUBAR) {
833                 info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_MENUBAR;
834         }
835         if (view_prefs & POPPLER_VIEWER_PREFERENCES_HIDE_WINDOWUI) {
836                 info->ui_hints |= EV_DOCUMENT_UI_HINT_HIDE_WINDOWUI;
837         }
838         if (view_prefs & POPPLER_VIEWER_PREFERENCES_FIT_WINDOW) {
839                 info->ui_hints |= EV_DOCUMENT_UI_HINT_FIT_WINDOW;
840         }
841         if (view_prefs & POPPLER_VIEWER_PREFERENCES_CENTER_WINDOW) {
842                 info->ui_hints |= EV_DOCUMENT_UI_HINT_CENTER_WINDOW;
843         }
844         if (view_prefs & POPPLER_VIEWER_PREFERENCES_DISPLAY_DOC_TITLE) {
845                 info->ui_hints |= EV_DOCUMENT_UI_HINT_DISPLAY_DOC_TITLE;
846         }
847         if (view_prefs & POPPLER_VIEWER_PREFERENCES_DIRECTION_RTL) {
848                 info->ui_hints |=  EV_DOCUMENT_UI_HINT_DIRECTION_RTL;
849         }
850
851         info->permissions = 0;
852         if (permissions & POPPLER_PERMISSIONS_OK_TO_PRINT) {
853                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_PRINT;
854         }
855         if (permissions & POPPLER_PERMISSIONS_OK_TO_MODIFY) {
856                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_MODIFY;
857         }
858         if (permissions & POPPLER_PERMISSIONS_OK_TO_COPY) {
859                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_COPY;
860         }
861         if (permissions & POPPLER_PERMISSIONS_OK_TO_ADD_NOTES) {
862                 info->permissions |= EV_DOCUMENT_PERMISSIONS_OK_TO_ADD_NOTES;
863         }
864
865         if (ev_document_security_has_document_security (EV_DOCUMENT_SECURITY (document))) {
866                 /* translators: this is the document security state */
867                 info->security = g_strdup (_("Yes"));
868         } else {
869                 /* translators: this is the document security state */
870                 info->security = g_strdup (_("No"));
871         }
872
873         return info;
874 }
875
876 static gboolean
877 pdf_document_get_backend_info (EvDocument *document, EvDocumentBackendInfo *info)
878 {
879         PopplerBackend backend;
880
881         backend = poppler_get_backend ();
882         switch (backend) {
883                 case POPPLER_BACKEND_CAIRO:
884                         info->name = "poppler/cairo";
885                         break;
886                 case POPPLER_BACKEND_SPLASH:
887                         info->name = "poppler/splash";
888                         break;
889                 default:
890                         info->name = "poppler/unknown";
891                         break;
892         }
893
894         info->version = poppler_get_version ();
895
896         return TRUE;
897 }
898
899 static gboolean
900 pdf_document_support_synctex (EvDocument *document)
901 {
902         return TRUE;
903 }
904
905 static void
906 pdf_document_class_init (PdfDocumentClass *klass)
907 {
908         GObjectClass    *g_object_class = G_OBJECT_CLASS (klass);
909         EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
910
911         g_object_class->dispose = pdf_document_dispose;
912
913         ev_document_class->save = pdf_document_save;
914         ev_document_class->load = pdf_document_load;
915         ev_document_class->get_n_pages = pdf_document_get_n_pages;
916         ev_document_class->get_page = pdf_document_get_page;
917         ev_document_class->get_page_size = pdf_document_get_page_size;
918         ev_document_class->get_page_label = pdf_document_get_page_label;
919         ev_document_class->render = pdf_document_render;
920         ev_document_class->get_thumbnail = pdf_document_get_thumbnail;
921         ev_document_class->get_info = pdf_document_get_info;
922         ev_document_class->get_backend_info = pdf_document_get_backend_info;
923         ev_document_class->support_synctex = pdf_document_support_synctex;
924 }
925
926 /* EvDocumentSecurity */
927 static gboolean
928 pdf_document_has_document_security (EvDocumentSecurity *document_security)
929 {
930         /* FIXME: do we really need to have this? */
931         return FALSE;
932 }
933
934 static void
935 pdf_document_set_password (EvDocumentSecurity *document_security,
936                            const char         *password)
937 {
938         PdfDocument *document = PDF_DOCUMENT (document_security);
939
940         if (document->password)
941                 g_free (document->password);
942
943         document->password = g_strdup (password);
944 }
945
946 static void
947 pdf_document_security_iface_init (EvDocumentSecurityInterface *iface)
948 {
949         iface->has_document_security = pdf_document_has_document_security;
950         iface->set_password = pdf_document_set_password;
951 }
952
953 static gdouble
954 pdf_document_fonts_get_progress (EvDocumentFonts *document_fonts)
955 {
956         PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
957         int n_pages;
958
959         n_pages = pdf_document_get_n_pages (EV_DOCUMENT (pdf_document));
960
961         return (double)pdf_document->fonts_scanned_pages / (double)n_pages;
962 }
963
964 static gboolean
965 pdf_document_fonts_scan (EvDocumentFonts *document_fonts,
966                          int              n_pages)
967 {
968         PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
969         gboolean result;
970
971         g_return_val_if_fail (PDF_IS_DOCUMENT (document_fonts), FALSE);
972
973         if (pdf_document->font_info == NULL) { 
974                 pdf_document->font_info = poppler_font_info_new (pdf_document->document);
975         }
976
977         if (pdf_document->fonts_iter) {
978                 poppler_fonts_iter_free (pdf_document->fonts_iter);
979         }
980
981         pdf_document->fonts_scanned_pages += n_pages;
982
983         result = poppler_font_info_scan (pdf_document->font_info, n_pages,
984                                          &pdf_document->fonts_iter);
985         if (!result) {
986                 pdf_document->fonts_scanned_pages = 0;
987                 poppler_font_info_free (pdf_document->font_info);
988                 pdf_document->font_info = NULL; 
989         }
990
991         return result;
992 }
993
994 static const char *
995 font_type_to_string (PopplerFontType type)
996 {
997         switch (type) {
998                 case POPPLER_FONT_TYPE_TYPE1:
999                         return _("Type 1");
1000                 case POPPLER_FONT_TYPE_TYPE1C:
1001                         return _("Type 1C");
1002                 case POPPLER_FONT_TYPE_TYPE3:
1003                         return _("Type 3");
1004                 case POPPLER_FONT_TYPE_TRUETYPE:
1005                         return _("TrueType");
1006                 case POPPLER_FONT_TYPE_CID_TYPE0:
1007                         return _("Type 1 (CID)");
1008                 case POPPLER_FONT_TYPE_CID_TYPE0C:
1009                         return _("Type 1C (CID)");
1010                 case POPPLER_FONT_TYPE_CID_TYPE2:
1011                         return _("TrueType (CID)");
1012                 default:
1013                         return _("Unknown font type");
1014         }
1015 }
1016
1017 static void
1018 pdf_document_fonts_fill_model (EvDocumentFonts *document_fonts,
1019                                GtkTreeModel    *model)
1020 {
1021         PdfDocument *pdf_document = PDF_DOCUMENT (document_fonts);
1022         PopplerFontsIter *iter = pdf_document->fonts_iter;
1023
1024         g_return_if_fail (PDF_IS_DOCUMENT (document_fonts));
1025
1026         if (!iter)
1027                 return;
1028
1029         do {
1030                 GtkTreeIter list_iter;
1031                 const char *name;
1032                 const char *type;
1033                 const char *embedded;
1034                 char *details;
1035                 
1036                 name = poppler_fonts_iter_get_name (iter);
1037
1038                 if (name == NULL) {
1039                         name = _("No name");
1040                 }
1041
1042                 type = font_type_to_string (
1043                         poppler_fonts_iter_get_font_type (iter));
1044
1045                 if (poppler_fonts_iter_is_embedded (iter)) {
1046                         if (poppler_fonts_iter_is_subset (iter))
1047                                 embedded = _("Embedded subset");
1048                         else
1049                                 embedded = _("Embedded");
1050                 } else {
1051                         embedded = _("Not embedded");
1052                 }
1053
1054                 details = g_markup_printf_escaped ("%s\n%s", type, embedded);
1055
1056                 gtk_list_store_append (GTK_LIST_STORE (model), &list_iter);
1057                 gtk_list_store_set (GTK_LIST_STORE (model), &list_iter,
1058                                     EV_DOCUMENT_FONTS_COLUMN_NAME, name,
1059                                     EV_DOCUMENT_FONTS_COLUMN_DETAILS, details,
1060                                     -1);
1061
1062                 g_free (details);
1063         } while (poppler_fonts_iter_next (iter));
1064 }
1065
1066 static void
1067 pdf_document_document_fonts_iface_init (EvDocumentFontsInterface *iface)
1068 {
1069         iface->fill_model = pdf_document_fonts_fill_model;
1070         iface->scan = pdf_document_fonts_scan;
1071         iface->get_progress = pdf_document_fonts_get_progress;
1072 }
1073
1074 static gboolean
1075 pdf_document_links_has_document_links (EvDocumentLinks *document_links)
1076 {
1077         PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
1078         PopplerIndexIter *iter;
1079
1080         g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
1081
1082         iter = poppler_index_iter_new (pdf_document->document);
1083         if (iter == NULL)
1084                 return FALSE;
1085         poppler_index_iter_free (iter);
1086
1087         return TRUE;
1088 }
1089
1090 static EvLinkDest *
1091 ev_link_dest_from_dest (PdfDocument *pdf_document,
1092                         PopplerDest *dest)
1093 {
1094         EvLinkDest *ev_dest = NULL;
1095         const char *unimplemented_dest = NULL;
1096
1097         g_assert (dest != NULL);
1098
1099         switch (dest->type) {
1100                 case POPPLER_DEST_XYZ: {
1101                         PopplerPage *poppler_page;
1102                         double height;
1103
1104                         poppler_page = poppler_document_get_page (pdf_document->document,
1105                                                                   MAX (0, dest->page_num - 1));
1106                         poppler_page_get_size (poppler_page, NULL, &height);
1107                         ev_dest = ev_link_dest_new_xyz (dest->page_num - 1,
1108                                                         dest->left,
1109                                                         height - MIN (height, dest->top),
1110                                                         dest->zoom,
1111                                                         dest->change_left,
1112                                                         dest->change_top,
1113                                                         dest->change_zoom);
1114                         g_object_unref (poppler_page);
1115                 }
1116                         break;
1117                 case POPPLER_DEST_FITB:
1118                 case POPPLER_DEST_FIT:
1119                         ev_dest = ev_link_dest_new_fit (dest->page_num - 1);
1120                         break;
1121                 case POPPLER_DEST_FITBH:
1122                 case POPPLER_DEST_FITH: {
1123                         PopplerPage *poppler_page;
1124                         double height;
1125
1126                         poppler_page = poppler_document_get_page (pdf_document->document,
1127                                                                   MAX (0, dest->page_num - 1));
1128                         poppler_page_get_size (poppler_page, NULL, &height);
1129                         ev_dest = ev_link_dest_new_fith (dest->page_num - 1,
1130                                                          height - MIN (height, dest->top),
1131                                                          dest->change_top);
1132                         g_object_unref (poppler_page);
1133                 }
1134                         break;
1135                 case POPPLER_DEST_FITBV:
1136                 case POPPLER_DEST_FITV:
1137                         ev_dest = ev_link_dest_new_fitv (dest->page_num - 1,
1138                                                          dest->left,
1139                                                          dest->change_left);
1140                         break;
1141                 case POPPLER_DEST_FITR: {
1142                         PopplerPage *poppler_page;
1143                         double height;
1144
1145                         poppler_page = poppler_document_get_page (pdf_document->document,
1146                                                                   MAX (0, dest->page_num - 1));
1147                         poppler_page_get_size (poppler_page, NULL, &height);
1148                         ev_dest = ev_link_dest_new_fitr (dest->page_num - 1,
1149                                                          dest->left,
1150                                                          height - MIN (height, dest->bottom),
1151                                                          dest->right,
1152                                                          height - MIN (height, dest->top));
1153                         g_object_unref (poppler_page);
1154                 }
1155                         break;
1156                 case POPPLER_DEST_NAMED:
1157                         ev_dest = ev_link_dest_new_named (dest->named_dest);
1158                         break;
1159                 case POPPLER_DEST_UNKNOWN:
1160                         unimplemented_dest = "POPPLER_DEST_UNKNOWN";
1161                         break;
1162         }
1163
1164         if (unimplemented_dest) {
1165                 g_warning ("Unimplemented destination: %s, please post a "
1166                            "bug report in Evince bugzilla "
1167                            "(http://bugzilla.gnome.org) with a testcase.",
1168                            unimplemented_dest);
1169         }
1170
1171         if (!ev_dest)
1172                 ev_dest = ev_link_dest_new_page (dest->page_num - 1);
1173         
1174         return ev_dest;
1175 }
1176
1177 static EvLink *
1178 ev_link_from_action (PdfDocument   *pdf_document,
1179                      PopplerAction *action)
1180 {
1181         EvLink       *link = NULL;
1182         EvLinkAction *ev_action = NULL;
1183         const char   *unimplemented_action = NULL;
1184
1185         switch (action->type) {
1186                 case POPPLER_ACTION_NONE:
1187                         break;
1188                 case POPPLER_ACTION_GOTO_DEST: {
1189                         EvLinkDest *dest;
1190                         
1191                         dest = ev_link_dest_from_dest (pdf_document, action->goto_dest.dest);
1192                         ev_action = ev_link_action_new_dest (dest);
1193                 }
1194                         break;
1195                 case POPPLER_ACTION_GOTO_REMOTE: {
1196                         EvLinkDest *dest;
1197                         
1198                         dest = ev_link_dest_from_dest (pdf_document, action->goto_remote.dest);
1199                         ev_action = ev_link_action_new_remote (dest, 
1200                                                                action->goto_remote.file_name);
1201                         
1202                 }
1203                         break;
1204                 case POPPLER_ACTION_LAUNCH:
1205                         ev_action = ev_link_action_new_launch (action->launch.file_name,
1206                                                                action->launch.params);
1207                         break;
1208                 case POPPLER_ACTION_URI:
1209                         ev_action = ev_link_action_new_external_uri (action->uri.uri);
1210                         break;
1211                 case POPPLER_ACTION_NAMED:
1212                         ev_action = ev_link_action_new_named (action->named.named_dest);
1213                         break;
1214                 case POPPLER_ACTION_MOVIE:
1215                         unimplemented_action = "POPPLER_ACTION_MOVIE";
1216                         break;
1217 #if POPPLER_CHECK_VERSION (0, 13, 2)
1218                 case POPPLER_ACTION_RENDITION:
1219                         unimplemented_action = "POPPLER_ACTION_RENDITION";
1220                         break;
1221                 case POPPLER_ACTION_OCG_STATE:
1222                         unimplemented_action = "POPPLER_ACTION_OCG_STATE";
1223                         break;
1224 #endif
1225                 case POPPLER_ACTION_UNKNOWN:
1226                         unimplemented_action = "POPPLER_ACTION_UNKNOWN";
1227         }
1228         
1229         if (unimplemented_action) {
1230                 g_warning ("Unimplemented action: %s, please post a bug report "
1231                            "in Evince bugzilla (http://bugzilla.gnome.org) "
1232                            "with a testcase.", unimplemented_action);
1233         }
1234         
1235         link = ev_link_new (action->any.title, ev_action);
1236         
1237         return link;    
1238 }
1239
1240 static void
1241 build_tree (PdfDocument      *pdf_document,
1242             GtkTreeModel     *model,
1243             GtkTreeIter      *parent,
1244             PopplerIndexIter *iter)
1245 {
1246         
1247         do {
1248                 GtkTreeIter tree_iter;
1249                 PopplerIndexIter *child;
1250                 PopplerAction *action;
1251                 EvLink *link = NULL;
1252                 gboolean expand;
1253                 char *title_markup;
1254                 
1255                 action = poppler_index_iter_get_action (iter);
1256                 expand = poppler_index_iter_is_open (iter);
1257
1258                 if (!action)
1259                         continue;
1260
1261                 link = ev_link_from_action (pdf_document, action);
1262                 if (!link || strlen (ev_link_get_title (link)) <= 0) {
1263                         poppler_action_free (action);
1264                         if (link)
1265                                 g_object_unref (link);
1266                         
1267                         continue;
1268                 }
1269
1270                 gtk_tree_store_append (GTK_TREE_STORE (model), &tree_iter, parent);
1271                 title_markup = g_markup_escape_text (ev_link_get_title (link), -1);
1272                 
1273                 gtk_tree_store_set (GTK_TREE_STORE (model), &tree_iter,
1274                                     EV_DOCUMENT_LINKS_COLUMN_MARKUP, title_markup,
1275                                     EV_DOCUMENT_LINKS_COLUMN_LINK, link,
1276                                     EV_DOCUMENT_LINKS_COLUMN_EXPAND, expand,
1277                                     -1);
1278                 
1279                 g_free (title_markup);
1280                 g_object_unref (link);
1281                 
1282                 child = poppler_index_iter_get_child (iter);
1283                 if (child)
1284                         build_tree (pdf_document, model, &tree_iter, child);
1285                 poppler_index_iter_free (child);
1286                 poppler_action_free (action);
1287                 
1288         } while (poppler_index_iter_next (iter));
1289 }
1290
1291 static GtkTreeModel *
1292 pdf_document_links_get_links_model (EvDocumentLinks *document_links)
1293 {
1294         PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
1295         GtkTreeModel *model = NULL;
1296         PopplerIndexIter *iter;
1297         
1298         g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), NULL);
1299
1300         iter = poppler_index_iter_new (pdf_document->document);
1301         /* Create the model if we have items*/
1302         if (iter != NULL) {
1303                 model = (GtkTreeModel *) gtk_tree_store_new (EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS,
1304                                                              G_TYPE_STRING,
1305                                                              G_TYPE_OBJECT,
1306                                                              G_TYPE_BOOLEAN,
1307                                                              G_TYPE_STRING);
1308                 build_tree (pdf_document, model, NULL, iter);
1309                 poppler_index_iter_free (iter);
1310         }
1311         
1312         return model;
1313 }
1314
1315 static EvMappingList *
1316 pdf_document_links_get_links (EvDocumentLinks *document_links,
1317                               EvPage          *page)
1318 {
1319         PdfDocument *pdf_document;
1320         PopplerPage *poppler_page;
1321         GList *retval = NULL;
1322         GList *mapping_list;
1323         GList *list;
1324         double height;
1325
1326         pdf_document = PDF_DOCUMENT (document_links);
1327         poppler_page = POPPLER_PAGE (page->backend_page);
1328         mapping_list = poppler_page_get_link_mapping (poppler_page);
1329         poppler_page_get_size (poppler_page, NULL, &height);
1330
1331         for (list = mapping_list; list; list = list->next) {
1332                 PopplerLinkMapping *link_mapping;
1333                 EvMapping *ev_link_mapping;
1334
1335                 link_mapping = (PopplerLinkMapping *)list->data;
1336                 ev_link_mapping = g_new (EvMapping, 1);
1337                 ev_link_mapping->data = ev_link_from_action (pdf_document,
1338                                                              link_mapping->action);
1339                 ev_link_mapping->area.x1 = link_mapping->area.x1;
1340                 ev_link_mapping->area.x2 = link_mapping->area.x2;
1341                 /* Invert this for X-style coordinates */
1342                 ev_link_mapping->area.y1 = height - link_mapping->area.y2;
1343                 ev_link_mapping->area.y2 = height - link_mapping->area.y1;
1344
1345                 retval = g_list_prepend (retval, ev_link_mapping);
1346         }
1347
1348         poppler_page_free_link_mapping (mapping_list);
1349
1350         return ev_mapping_list_new (page->index, g_list_reverse (retval), (GDestroyNotify)g_object_unref);
1351 }
1352
1353 static EvLinkDest *
1354 pdf_document_links_find_link_dest (EvDocumentLinks  *document_links,
1355                                    const gchar      *link_name)
1356 {
1357         PdfDocument *pdf_document;
1358         PopplerDest *dest;
1359         EvLinkDest *ev_dest = NULL;
1360
1361         pdf_document = PDF_DOCUMENT (document_links);
1362         dest = poppler_document_find_dest (pdf_document->document,
1363                                            link_name);
1364         if (dest) {
1365                 ev_dest = ev_link_dest_from_dest (pdf_document, dest);
1366                 poppler_dest_free (dest);
1367         }
1368
1369         return ev_dest;
1370 }
1371
1372 static gint
1373 pdf_document_links_find_link_page (EvDocumentLinks  *document_links,
1374                                    const gchar      *link_name)
1375 {
1376         PdfDocument *pdf_document;
1377         PopplerDest *dest;
1378         gint         retval = -1;
1379
1380         pdf_document = PDF_DOCUMENT (document_links);
1381         dest = poppler_document_find_dest (pdf_document->document,
1382                                            link_name);
1383         if (dest) {
1384                 retval = dest->page_num - 1;
1385                 poppler_dest_free (dest);
1386         }
1387
1388         return retval;
1389 }
1390
1391 static void
1392 pdf_document_document_links_iface_init (EvDocumentLinksInterface *iface)
1393 {
1394         iface->has_document_links = pdf_document_links_has_document_links;
1395         iface->get_links_model = pdf_document_links_get_links_model;
1396         iface->get_links = pdf_document_links_get_links;
1397         iface->find_link_dest = pdf_document_links_find_link_dest;
1398         iface->find_link_page = pdf_document_links_find_link_page;
1399 }
1400
1401 static EvMappingList *
1402 pdf_document_images_get_image_mapping (EvDocumentImages *document_images,
1403                                        EvPage           *page)
1404 {
1405         GList *retval = NULL;
1406         PdfDocument *pdf_document;
1407         PopplerPage *poppler_page;
1408         GList *mapping_list;
1409         GList *list;
1410
1411         pdf_document = PDF_DOCUMENT (document_images);
1412         poppler_page = POPPLER_PAGE (page->backend_page);
1413         mapping_list = poppler_page_get_image_mapping (poppler_page);
1414
1415         for (list = mapping_list; list; list = list->next) {
1416                 PopplerImageMapping *image_mapping;
1417                 EvMapping *ev_image_mapping;
1418
1419                 image_mapping = (PopplerImageMapping *)list->data;
1420
1421                 ev_image_mapping = g_new (EvMapping, 1);
1422                 
1423                 ev_image_mapping->data = ev_image_new (page->index, image_mapping->image_id);
1424                 ev_image_mapping->area.x1 = image_mapping->area.x1;
1425                 ev_image_mapping->area.y1 = image_mapping->area.y1;
1426                 ev_image_mapping->area.x2 = image_mapping->area.x2;
1427                 ev_image_mapping->area.y2 = image_mapping->area.y2;
1428
1429                 retval = g_list_prepend (retval, ev_image_mapping);
1430         }
1431
1432         poppler_page_free_image_mapping (mapping_list);
1433
1434         return ev_mapping_list_new (page->index, g_list_reverse (retval), (GDestroyNotify)g_object_unref);
1435 }
1436
1437 GdkPixbuf *
1438 pdf_document_images_get_image (EvDocumentImages *document_images,
1439                                EvImage          *image)
1440 {
1441         GdkPixbuf       *retval = NULL;
1442         PdfDocument     *pdf_document;
1443         PopplerPage     *poppler_page;
1444         cairo_surface_t *surface;
1445
1446         pdf_document = PDF_DOCUMENT (document_images);
1447         poppler_page = poppler_document_get_page (pdf_document->document,
1448                                                   ev_image_get_page (image));
1449
1450         surface = poppler_page_get_image (poppler_page, ev_image_get_id (image));
1451         if (surface) {
1452                 retval = ev_document_misc_pixbuf_from_surface (surface);
1453                 cairo_surface_destroy (surface);
1454         }
1455
1456         g_object_unref (poppler_page);
1457
1458         return retval;
1459 }
1460
1461 static void
1462 pdf_document_document_images_iface_init (EvDocumentImagesInterface *iface)
1463 {
1464         iface->get_image_mapping = pdf_document_images_get_image_mapping;
1465         iface->get_image = pdf_document_images_get_image;
1466 }
1467
1468 static GList *
1469 pdf_document_find_find_text (EvDocumentFind *document_find,
1470                              EvPage         *page,
1471                              const gchar    *text,
1472                              gboolean        case_sensitive)
1473 {
1474         GList *matches, *l;
1475         PopplerPage *poppler_page;
1476         gdouble height;
1477         GList *retval = NULL;
1478
1479         g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
1480         g_return_val_if_fail (text != NULL, NULL);
1481
1482         poppler_page = POPPLER_PAGE (page->backend_page);
1483         
1484         matches = poppler_page_find_text (poppler_page, text);
1485         if (!matches)
1486                 return NULL;
1487
1488         poppler_page_get_size (poppler_page, NULL, &height);
1489         for (l = matches; l && l->data; l = g_list_next (l)) {
1490                 PopplerRectangle *rect = (PopplerRectangle *)l->data;
1491                 EvRectangle      *ev_rect;
1492
1493                 ev_rect = ev_rectangle_new ();
1494                 ev_rect->x1 = rect->x1;
1495                 ev_rect->x2 = rect->x2;
1496                 /* Invert this for X-style coordinates */
1497                 ev_rect->y1 = height - rect->y2;
1498                 ev_rect->y2 = height - rect->y1;
1499
1500                 retval = g_list_prepend (retval, ev_rect);
1501         }
1502
1503         g_list_foreach (matches, (GFunc)poppler_rectangle_free, NULL);
1504         g_list_free (matches);
1505
1506         return g_list_reverse (retval);
1507 }
1508
1509 static void
1510 pdf_document_find_iface_init (EvDocumentFindInterface *iface)
1511 {
1512         iface->find_text = pdf_document_find_find_text;
1513 }
1514
1515 static void
1516 pdf_print_context_free (PdfPrintContext *ctx)
1517 {
1518         if (!ctx)
1519                 return;
1520
1521 #ifdef HAVE_CAIRO_PRINT
1522         if (ctx->cr) {
1523                 cairo_destroy (ctx->cr);
1524                 ctx->cr = NULL;
1525         }
1526 #else
1527         if (ctx->ps_file) {
1528                 poppler_ps_file_free (ctx->ps_file);
1529                 ctx->ps_file = NULL;
1530         }
1531 #endif
1532         g_free (ctx);
1533 }
1534
1535 static void
1536 pdf_document_file_exporter_begin (EvFileExporter        *exporter,
1537                                   EvFileExporterContext *fc)
1538 {
1539         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1540         PdfPrintContext *ctx;
1541 #ifdef HAVE_CAIRO_PRINT
1542         gdouble width, height;
1543         cairo_surface_t *surface = NULL;
1544 #endif
1545         
1546         if (pdf_document->print_ctx)
1547                 pdf_print_context_free (pdf_document->print_ctx);
1548         pdf_document->print_ctx = g_new0 (PdfPrintContext, 1);
1549         ctx = pdf_document->print_ctx;
1550         ctx->format = fc->format;
1551         
1552 #ifdef HAVE_CAIRO_PRINT
1553         ctx->pages_per_sheet = CLAMP (fc->pages_per_sheet, 1, 16);
1554
1555         ctx->paper_width = fc->paper_width;
1556         ctx->paper_height = fc->paper_height;
1557         
1558         switch (fc->pages_per_sheet) {
1559                 default:
1560                 case 1:
1561                         ctx->pages_x = 1;
1562                         ctx->pages_y = 1;
1563                         break;
1564                 case 2:
1565                         ctx->pages_x = 1;
1566                         ctx->pages_y = 2;
1567                         break;
1568                 case 4:
1569                         ctx->pages_x = 2;
1570                         ctx->pages_y = 2;
1571                         break;
1572                 case 6:
1573                         ctx->pages_x = 2;
1574                         ctx->pages_y = 3;
1575                         break;
1576                 case 9:
1577                         ctx->pages_x = 3;
1578                         ctx->pages_y = 3;
1579                         break;
1580                 case 16:
1581                         ctx->pages_x = 4;
1582                         ctx->pages_y = 4;
1583                         break;
1584         }
1585
1586         ctx->pages_printed = 0;
1587         
1588         switch (fc->format) {
1589                 case EV_FILE_FORMAT_PS:
1590 #ifdef HAVE_CAIRO_PS
1591                         surface = cairo_ps_surface_create (fc->filename, fc->paper_width, fc->paper_height);
1592 #endif
1593                         break;
1594                 case EV_FILE_FORMAT_PDF:
1595 #ifdef HAVE_CAIRO_PDF
1596                         surface = cairo_pdf_surface_create (fc->filename, fc->paper_width, fc->paper_height);
1597 #endif
1598                         break;
1599                 default:
1600                         g_assert_not_reached ();
1601         }
1602
1603         ctx->cr = cairo_create (surface);
1604         cairo_surface_destroy (surface);
1605
1606 #else /* HAVE_CAIRO_PRINT */
1607         if (ctx->format == EV_FILE_FORMAT_PS) {
1608                 ctx->ps_file = poppler_ps_file_new (pdf_document->document,
1609                                                     fc->filename, fc->first_page,
1610                                                     fc->last_page - fc->first_page + 1);
1611                 poppler_ps_file_set_paper_size (ctx->ps_file, fc->paper_width, fc->paper_height);
1612                 poppler_ps_file_set_duplex (ctx->ps_file, fc->duplex);
1613         }
1614 #endif /* HAVE_CAIRO_PRINT */
1615 }
1616
1617 static void
1618 pdf_document_file_exporter_begin_page (EvFileExporter *exporter)
1619 {
1620         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1621         PdfPrintContext *ctx = pdf_document->print_ctx;
1622         
1623         g_return_if_fail (pdf_document->print_ctx != NULL);
1624
1625         ctx->pages_printed = 0;
1626         
1627 #ifdef HAVE_CAIRO_PRINT
1628         if (ctx->paper_width > ctx->paper_height) {
1629                 if (ctx->format == EV_FILE_FORMAT_PS) {
1630                         cairo_ps_surface_set_size (cairo_get_target (ctx->cr),
1631                                                    ctx->paper_height,
1632                                                    ctx->paper_width);
1633                 } else if (ctx->format == EV_FILE_FORMAT_PDF) {
1634                         cairo_pdf_surface_set_size (cairo_get_target (ctx->cr),
1635                                                     ctx->paper_height,
1636                                                     ctx->paper_width);
1637                 }
1638         }
1639 #endif /* HAVE_CAIRO_PRINT */
1640 }
1641
1642 static void
1643 pdf_document_file_exporter_do_page (EvFileExporter  *exporter,
1644                                     EvRenderContext *rc)
1645 {
1646         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1647         PdfPrintContext *ctx = pdf_document->print_ctx;
1648         PopplerPage *poppler_page;
1649 #ifdef HAVE_CAIRO_PRINT
1650         gdouble  page_width, page_height;
1651         gint     x, y;
1652         gboolean rotate;
1653         gdouble  width, height;
1654         gdouble  pwidth, pheight;
1655         gdouble  xscale, yscale;
1656 #endif
1657
1658         g_return_if_fail (pdf_document->print_ctx != NULL);
1659
1660         poppler_page = POPPLER_PAGE (rc->page->backend_page);
1661         
1662 #ifdef HAVE_CAIRO_PRINT
1663         x = (ctx->pages_printed % ctx->pages_per_sheet) % ctx->pages_x;
1664         y = (ctx->pages_printed % ctx->pages_per_sheet) / ctx->pages_x;
1665         poppler_page_get_size (poppler_page, &page_width, &page_height);
1666
1667         if (page_width > page_height && page_width > ctx->paper_width) {
1668                 rotate = TRUE;
1669         } else {
1670                 rotate = FALSE;
1671         }
1672
1673         /* Use always portrait mode and rotate when necessary */
1674         if (ctx->paper_width > ctx->paper_height) {
1675                 width = ctx->paper_height;
1676                 height = ctx->paper_width;
1677                 rotate = !rotate;
1678         } else {
1679                 width = ctx->paper_width;
1680                 height = ctx->paper_height;
1681         }
1682
1683         if (ctx->pages_per_sheet == 2 || ctx->pages_per_sheet == 6) {
1684                 rotate = !rotate;
1685         }       
1686
1687         if (rotate) {
1688                 gint tmp1;
1689                 gdouble tmp2;
1690
1691                 tmp1 = x;
1692                 x = y;
1693                 y = tmp1;
1694
1695                 tmp2 = page_width;
1696                 page_width = page_height;
1697                 page_height = tmp2;
1698         }
1699
1700         pwidth = width / ctx->pages_x;
1701         pheight = height / ctx->pages_y;
1702
1703         if ((page_width > pwidth || page_height > pheight) ||
1704             (page_width < pwidth && page_height < pheight)) {
1705                 xscale = pwidth / page_width;
1706                 yscale = pheight / page_height;
1707                 
1708                 if (yscale < xscale) {
1709                         xscale = yscale;
1710                 } else {
1711                         yscale = xscale;
1712                 }
1713                 
1714         } else {        
1715                 xscale = yscale = 1;
1716         }
1717
1718         /* TODO: center */
1719
1720         cairo_save (ctx->cr);
1721         if (rotate) {
1722                 cairo_matrix_t matrix;
1723                 
1724                 cairo_translate (ctx->cr, (2 * y + 1) * pwidth, 0);
1725                 cairo_matrix_init (&matrix,
1726                                    0,  1,
1727                                    -1,  0,
1728                                    0,  0);
1729                 cairo_transform (ctx->cr, &matrix);
1730         }
1731         
1732         cairo_translate (ctx->cr,
1733                          x * (rotate ? pheight : pwidth),
1734                          y * (rotate ? pwidth : pheight));
1735         cairo_scale (ctx->cr, xscale, yscale);
1736
1737         poppler_page_render_for_printing (poppler_page, ctx->cr);
1738
1739         ctx->pages_printed++;
1740                         
1741         cairo_restore (ctx->cr);
1742 #else /* HAVE_CAIRO_PRINT */
1743         if (ctx->format == EV_FILE_FORMAT_PS)
1744                 poppler_page_render_to_ps (poppler_page, ctx->ps_file);
1745 #endif /* HAVE_CAIRO_PRINT */
1746 }
1747
1748 static void
1749 pdf_document_file_exporter_end_page (EvFileExporter *exporter)
1750 {
1751         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1752         PdfPrintContext *ctx = pdf_document->print_ctx;
1753         
1754         g_return_if_fail (pdf_document->print_ctx != NULL);
1755
1756 #ifdef HAVE_CAIRO_PRINT
1757         cairo_show_page (ctx->cr);
1758 #endif
1759 }
1760
1761 static void
1762 pdf_document_file_exporter_end (EvFileExporter *exporter)
1763 {
1764         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1765
1766         pdf_print_context_free (pdf_document->print_ctx);
1767         pdf_document->print_ctx = NULL;
1768 }
1769
1770 static EvFileExporterCapabilities
1771 pdf_document_file_exporter_get_capabilities (EvFileExporter *exporter)
1772 {
1773         return  (EvFileExporterCapabilities) (
1774                 EV_FILE_EXPORTER_CAN_PAGE_SET |
1775                 EV_FILE_EXPORTER_CAN_COPIES |
1776                 EV_FILE_EXPORTER_CAN_COLLATE |
1777                 EV_FILE_EXPORTER_CAN_REVERSE |
1778                 EV_FILE_EXPORTER_CAN_SCALE |
1779 #ifdef HAVE_CAIRO_PRINT
1780                 EV_FILE_EXPORTER_CAN_NUMBER_UP |
1781 #endif
1782                 
1783 #ifdef HAVE_CAIRO_PDF
1784                 EV_FILE_EXPORTER_CAN_GENERATE_PDF |
1785 #endif
1786                 EV_FILE_EXPORTER_CAN_GENERATE_PS);
1787 }
1788
1789 static void
1790 pdf_document_file_exporter_iface_init (EvFileExporterInterface *iface)
1791 {
1792         iface->begin = pdf_document_file_exporter_begin;
1793         iface->begin_page = pdf_document_file_exporter_begin_page;
1794         iface->do_page = pdf_document_file_exporter_do_page;
1795         iface->end_page = pdf_document_file_exporter_end_page;
1796         iface->end = pdf_document_file_exporter_end;
1797         iface->get_capabilities = pdf_document_file_exporter_get_capabilities;
1798 }
1799
1800 /* EvDocumentPrint */
1801 static void
1802 pdf_document_print_print_page (EvDocumentPrint *document,
1803                                EvPage          *page,
1804                                cairo_t         *cr)
1805 {
1806         PdfDocument *pdf_document = PDF_DOCUMENT (document);
1807
1808         poppler_page_render_for_printing (POPPLER_PAGE (page->backend_page), cr);
1809 }
1810
1811 static void
1812 pdf_document_document_print_iface_init (EvDocumentPrintInterface *iface)
1813 {
1814         iface->print_page = pdf_document_print_print_page;
1815 }
1816
1817 static void
1818 pdf_selection_render_selection (EvSelection      *selection,
1819                                 EvRenderContext  *rc,
1820                                 cairo_surface_t **surface,
1821                                 EvRectangle      *points,
1822                                 EvRectangle      *old_points,
1823                                 EvSelectionStyle  style,
1824                                 GdkColor         *text,
1825                                 GdkColor         *base)
1826 {
1827         PopplerPage *poppler_page;
1828         cairo_t *cr;
1829         PopplerColor text_color, base_color;
1830         double width_points, height_points;
1831         gint width, height;
1832
1833         poppler_page = POPPLER_PAGE (rc->page->backend_page);
1834
1835         poppler_page_get_size (poppler_page,
1836                                &width_points, &height_points);
1837         width = (int) ((width_points * rc->scale) + 0.5);
1838         height = (int) ((height_points * rc->scale) + 0.5);
1839
1840         text_color.red = text->red;
1841         text_color.green = text->green;
1842         text_color.blue = text->blue;
1843
1844         base_color.red = base->red;
1845         base_color.green = base->green;
1846         base_color.blue = base->blue;
1847
1848         if (*surface == NULL) {
1849                 *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
1850                                                        width, height);
1851                 
1852         }
1853
1854         cr = cairo_create (*surface);
1855         cairo_scale (cr, rc->scale, rc->scale);
1856         cairo_surface_set_device_offset (*surface, 0, 0);
1857         memset (cairo_image_surface_get_data (*surface), 0x00,
1858                 cairo_image_surface_get_height (*surface) *
1859                 cairo_image_surface_get_stride (*surface));
1860         poppler_page_render_selection (poppler_page,
1861                                        cr,
1862                                        (PopplerRectangle *)points,
1863                                        (PopplerRectangle *)old_points,
1864                                        (PopplerSelectionStyle)style,
1865                                        &text_color,
1866                                        &base_color);
1867         cairo_destroy (cr);
1868 }
1869
1870 static gchar *
1871 pdf_selection_get_selected_text (EvSelection     *selection,
1872                                  EvPage          *page,
1873                                  EvSelectionStyle style,
1874                                  EvRectangle     *points)
1875 {
1876         PopplerPage *poppler_page;
1877         char *retval;
1878
1879         poppler_page = POPPLER_PAGE (page->backend_page);
1880
1881 #ifdef HAVE_POPPLER_PAGE_GET_SELECTED_TEXT
1882         retval = poppler_page_get_selected_text (poppler_page,
1883                                                  (PopplerSelectionStyle)style,
1884                                                  (PopplerRectangle *)points);
1885 #else
1886         PopplerRectangle r;
1887         double height;
1888
1889         poppler_page_get_size (poppler_page, NULL, &height);
1890         r.x1 = points->x1;
1891         r.y1 = height - points->y2;
1892         r.x2 = points->x2;
1893         r.y2 = height - points->y1;
1894
1895         retval = poppler_page_get_text (poppler_page,
1896                                         (PopplerSelectionStyle)style,
1897                                         &r);
1898 #endif /* HAVE_POPPLER_PAGE_GET_SELECTED_TEXT */
1899
1900         return retval;
1901 }
1902
1903 static cairo_region_t *
1904 create_region_from_poppler_region (GList *region, gdouble scale)
1905 {
1906         GList *l;
1907         cairo_region_t *retval;
1908
1909         retval = cairo_region_create ();
1910
1911         for (l = region; l; l = g_list_next (l)) {
1912                 PopplerRectangle   *rectangle;
1913                 cairo_rectangle_int_t rect;
1914
1915                 rectangle = (PopplerRectangle *)l->data;
1916
1917                 rect.x = (gint) ((rectangle->x1 * scale) + 0.5);
1918                 rect.y = (gint) ((rectangle->y1 * scale) + 0.5);
1919                 rect.width  = (gint) (((rectangle->x2 - rectangle->x1) * scale) + 0.5);
1920                 rect.height = (gint) (((rectangle->y2 - rectangle->y1) * scale) + 0.5);
1921                 cairo_region_union_rectangle (retval, &rect);
1922
1923                 poppler_rectangle_free (rectangle);
1924         }
1925
1926         return retval;
1927 }
1928
1929 static cairo_region_t *
1930 pdf_selection_get_selection_region (EvSelection     *selection,
1931                                     EvRenderContext *rc,
1932                                     EvSelectionStyle style,
1933                                     EvRectangle     *points)
1934 {
1935         PopplerPage    *poppler_page;
1936         cairo_region_t *retval;
1937         GList          *region;
1938
1939         poppler_page = POPPLER_PAGE (rc->page->backend_page);
1940         region = poppler_page_get_selection_region (poppler_page,
1941                                                     1.0,
1942                                                     (PopplerSelectionStyle)style,
1943                                                     (PopplerRectangle *) points);
1944         retval = create_region_from_poppler_region (region, rc->scale);
1945         g_list_free (region);
1946         
1947         return retval;
1948 }
1949
1950 static void
1951 pdf_selection_iface_init (EvSelectionInterface *iface)
1952 {
1953         iface->render_selection = pdf_selection_render_selection;
1954         iface->get_selected_text = pdf_selection_get_selected_text;
1955         iface->get_selection_region = pdf_selection_get_selection_region;
1956 }
1957
1958
1959 /* EvDocumentText */
1960 static cairo_region_t *
1961 pdf_document_text_get_text_mapping (EvDocumentText *document_text,
1962                                     EvPage         *page)
1963 {
1964         PopplerPage *poppler_page;
1965         PopplerRectangle points;
1966         GList *region;
1967         cairo_region_t *retval;
1968
1969         g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
1970
1971         poppler_page = POPPLER_PAGE (page->backend_page);
1972
1973         points.x1 = 0.0;
1974         points.y1 = 0.0;
1975         poppler_page_get_size (poppler_page, &(points.x2), &(points.y2));
1976
1977         region = poppler_page_get_selection_region (poppler_page, 1.0,
1978                                                     POPPLER_SELECTION_GLYPH,
1979                                                     &points);
1980         retval = create_region_from_poppler_region (region, 1.0);
1981         g_list_free (region);
1982
1983         return retval;
1984 }
1985
1986 #ifdef HAVE_POPPLER_PAGE_GET_SELECTED_TEXT
1987 static gchar *
1988 pdf_document_text_get_text (EvDocumentText  *selection,
1989                             EvPage          *page)
1990 {
1991         PopplerPage *poppler_page;
1992
1993         g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
1994
1995         poppler_page = POPPLER_PAGE (page->backend_page);
1996
1997         return poppler_page_get_text (poppler_page);
1998 }
1999 #else
2000 static gchar *
2001 pdf_document_text_get_text (EvDocumentText  *selection,
2002                             EvPage          *page)
2003 {
2004         PopplerPage *poppler_page;
2005         PopplerRectangle r;
2006
2007         g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
2008
2009         poppler_page = POPPLER_PAGE (page->backend_page);
2010
2011         r.x1 = 0;
2012         r.y1 = 0;
2013         poppler_page_get_size (poppler_page, &(r.x2), &(r.y2));
2014
2015         return poppler_page_get_text (poppler_page,
2016                                       POPPLER_SELECTION_WORD,
2017                                       &r);
2018 }
2019 #endif /* HAVE_POPPLER_PAGE_GET_SELECTED_TEXT */
2020
2021 #ifdef HAVE_POPPLER_PAGE_GET_TEXT_LAYOUT
2022 static gboolean
2023 pdf_document_text_get_text_layout (EvDocumentText  *selection,
2024                                    EvPage          *page,
2025                                    EvRectangle    **areas,
2026                                    guint           *n_areas)
2027 {
2028         PopplerPage *poppler_page;
2029
2030         g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
2031
2032         poppler_page = POPPLER_PAGE (page->backend_page);
2033
2034         return poppler_page_get_text_layout (poppler_page, (PopplerRectangle **)areas, n_areas);
2035 }
2036 #endif
2037
2038 static void
2039 pdf_document_text_iface_init (EvDocumentTextInterface *iface)
2040 {
2041         iface->get_text_mapping = pdf_document_text_get_text_mapping;
2042         iface->get_text = pdf_document_text_get_text;
2043 #ifdef HAVE_POPPLER_PAGE_GET_TEXT_LAYOUT
2044         iface->get_text_layout = pdf_document_text_get_text_layout;
2045 #endif
2046 }
2047
2048 /* Page Transitions */
2049 static gdouble
2050 pdf_document_get_page_duration (EvDocumentTransition *trans,
2051                                 gint                  page)
2052 {
2053         PdfDocument *pdf_document;
2054         PopplerPage *poppler_page;
2055         gdouble      duration = -1;
2056
2057         pdf_document = PDF_DOCUMENT (trans);
2058         poppler_page = poppler_document_get_page (pdf_document->document, page);
2059         if (!poppler_page)
2060                 return -1;
2061
2062         duration = poppler_page_get_duration (poppler_page);
2063         g_object_unref (poppler_page);
2064
2065         return duration;
2066 }
2067
2068 static EvTransitionEffect *
2069 pdf_document_get_effect (EvDocumentTransition *trans,
2070                          gint                  page)
2071 {
2072         PdfDocument            *pdf_document;
2073         PopplerPage            *poppler_page;
2074         PopplerPageTransition  *page_transition;
2075         EvTransitionEffect     *effect;
2076
2077         pdf_document = PDF_DOCUMENT (trans);
2078         poppler_page = poppler_document_get_page (pdf_document->document, page);
2079
2080         if (!poppler_page)
2081                 return NULL;
2082
2083         page_transition = poppler_page_get_transition (poppler_page);
2084
2085         if (!page_transition) {
2086                 g_object_unref (poppler_page);
2087                 return NULL;
2088         }
2089
2090         /* enums in PopplerPageTransition match the EvTransitionEffect ones */
2091         effect = ev_transition_effect_new ((EvTransitionEffectType) page_transition->type,
2092                                            "alignment", page_transition->alignment,
2093                                            "direction", page_transition->direction,
2094                                            "duration", page_transition->duration,
2095                                            "angle", page_transition->angle,
2096                                            "scale", page_transition->scale,
2097                                            "rectangular", page_transition->rectangular,
2098                                            NULL);
2099
2100         poppler_page_transition_free (page_transition);
2101         g_object_unref (poppler_page);
2102
2103         return effect;
2104 }
2105
2106 static void
2107 pdf_document_page_transition_iface_init (EvDocumentTransitionInterface *iface)
2108 {
2109         iface->get_page_duration = pdf_document_get_page_duration;
2110         iface->get_effect = pdf_document_get_effect;
2111 }
2112
2113 /* Forms */
2114 static void
2115 pdf_document_get_crop_box (EvDocument  *document, 
2116                            int          page, 
2117                            EvRectangle *rect)
2118 {
2119         PdfDocument *pdf_document;
2120         PopplerPage *poppler_page;
2121         PopplerRectangle poppler_rect;
2122
2123         pdf_document = PDF_DOCUMENT (document);
2124         poppler_page = poppler_document_get_page (pdf_document->document, page);
2125         poppler_page_get_crop_box (poppler_page, &poppler_rect);
2126         rect->x1 = poppler_rect.x1;
2127         rect->x2 = poppler_rect.x2;
2128         rect->y1 = poppler_rect.y1;
2129         rect->y2 = poppler_rect.y2;
2130 }
2131
2132 static EvFormField *
2133 ev_form_field_from_poppler_field (PopplerFormField *poppler_field)
2134 {
2135         EvFormField *ev_field = NULL;
2136         gint         id;
2137         gdouble      font_size;
2138         gboolean     is_read_only;
2139
2140         id = poppler_form_field_get_id (poppler_field);
2141         font_size = poppler_form_field_get_font_size (poppler_field);
2142         is_read_only = poppler_form_field_is_read_only (poppler_field);
2143
2144         switch (poppler_form_field_get_field_type (poppler_field)) {
2145                 case POPPLER_FORM_FIELD_TEXT: {
2146                         EvFormFieldText    *field_text;
2147                         EvFormFieldTextType ev_text_type = EV_FORM_FIELD_TEXT_NORMAL;
2148
2149                         switch (poppler_form_field_text_get_text_type (poppler_field)) {
2150                                 case POPPLER_FORM_TEXT_NORMAL:
2151                                         ev_text_type = EV_FORM_FIELD_TEXT_NORMAL;
2152                                         break;
2153                                 case POPPLER_FORM_TEXT_MULTILINE:
2154                                         ev_text_type = EV_FORM_FIELD_TEXT_MULTILINE;
2155                                         break;
2156                                 case POPPLER_FORM_TEXT_FILE_SELECT:
2157                                         ev_text_type = EV_FORM_FIELD_TEXT_FILE_SELECT;
2158                                         break;
2159                         }
2160                         
2161                         ev_field = ev_form_field_text_new (id, ev_text_type);
2162                         field_text = EV_FORM_FIELD_TEXT (ev_field);
2163
2164                         field_text->do_spell_check = poppler_form_field_text_do_spell_check (poppler_field);
2165                         field_text->do_scroll = poppler_form_field_text_do_scroll (poppler_field);
2166                         field_text->is_rich_text = poppler_form_field_text_is_rich_text (poppler_field);
2167                         field_text->is_password = poppler_form_field_text_is_password (poppler_field);
2168                         field_text->max_len = poppler_form_field_text_get_max_len (poppler_field);
2169                         field_text->text = poppler_form_field_text_get_text (poppler_field);
2170
2171                 }
2172                         break;
2173                 case POPPLER_FORM_FIELD_BUTTON: {
2174                         EvFormFieldButton    *field_button;
2175                         EvFormFieldButtonType ev_button_type = EV_FORM_FIELD_BUTTON_PUSH;
2176
2177                         switch (poppler_form_field_button_get_button_type (poppler_field)) {
2178                                 case POPPLER_FORM_BUTTON_PUSH:
2179                                         ev_button_type = EV_FORM_FIELD_BUTTON_PUSH;
2180                                         break;
2181                                 case POPPLER_FORM_BUTTON_CHECK:
2182                                         ev_button_type = EV_FORM_FIELD_BUTTON_CHECK;
2183                                         break;
2184                                 case POPPLER_FORM_BUTTON_RADIO:
2185                                         ev_button_type = EV_FORM_FIELD_BUTTON_RADIO;
2186                                         break;
2187                         }
2188
2189                         ev_field = ev_form_field_button_new (id, ev_button_type);
2190                         field_button = EV_FORM_FIELD_BUTTON (ev_field);
2191                         
2192                         field_button->state = poppler_form_field_button_get_state (poppler_field);
2193                 }
2194                         break;
2195                 case POPPLER_FORM_FIELD_CHOICE: {
2196                         EvFormFieldChoice    *field_choice;
2197                         EvFormFieldChoiceType ev_choice_type = EV_FORM_FIELD_CHOICE_COMBO;
2198
2199                         switch (poppler_form_field_choice_get_choice_type (poppler_field)) {
2200                                 case POPPLER_FORM_CHOICE_COMBO:
2201                                         ev_choice_type = EV_FORM_FIELD_CHOICE_COMBO;
2202                                         break;
2203                                 case EV_FORM_FIELD_CHOICE_LIST:
2204                                         ev_choice_type = EV_FORM_FIELD_CHOICE_LIST;
2205                                         break;
2206                         }
2207
2208                         ev_field = ev_form_field_choice_new (id, ev_choice_type);
2209                         field_choice = EV_FORM_FIELD_CHOICE (ev_field);
2210
2211                         field_choice->is_editable = poppler_form_field_choice_is_editable (poppler_field);
2212                         field_choice->multi_select = poppler_form_field_choice_can_select_multiple (poppler_field);
2213                         field_choice->do_spell_check = poppler_form_field_choice_do_spell_check (poppler_field);
2214                         field_choice->commit_on_sel_change = poppler_form_field_choice_commit_on_change (poppler_field);
2215
2216                         /* TODO: we need poppler_form_field_choice_get_selected_items in poppler 
2217                         field_choice->selected_items = poppler_form_field_choice_get_selected_items (poppler_field);*/
2218                         if (field_choice->is_editable)
2219                                 field_choice->text = poppler_form_field_choice_get_text (poppler_field);
2220                 }
2221                         break;
2222                 case POPPLER_FORM_FIELD_SIGNATURE:
2223                         /* TODO */
2224                         ev_field = ev_form_field_signature_new (id);
2225                         break;
2226                 case POPPLER_FORM_FIELD_UNKNOWN:
2227                         return NULL;
2228         }
2229
2230         ev_field->font_size = font_size;
2231         ev_field->is_read_only = is_read_only;
2232
2233         return ev_field;
2234 }
2235
2236 static EvMappingList *
2237 pdf_document_forms_get_form_fields (EvDocumentForms *document, 
2238                                     EvPage          *page)
2239 {
2240         PopplerPage *poppler_page;
2241         GList *retval = NULL;
2242         GList *fields;
2243         GList *list;
2244         double height;
2245
2246         g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
2247         
2248         poppler_page = POPPLER_PAGE (page->backend_page);
2249         fields = poppler_page_get_form_field_mapping (poppler_page);
2250         poppler_page_get_size (poppler_page, NULL, &height);
2251
2252         for (list = fields; list; list = list->next) {
2253                 PopplerFormFieldMapping *mapping;
2254                 EvMapping *field_mapping;
2255                 EvFormField *ev_field;
2256
2257                 mapping = (PopplerFormFieldMapping *)list->data;
2258
2259                 ev_field = ev_form_field_from_poppler_field (mapping->field);
2260                 if (!ev_field)
2261                         continue;
2262
2263                 field_mapping = g_new0 (EvMapping, 1);
2264                 field_mapping->area.x1 = mapping->area.x1;
2265                 field_mapping->area.x2 = mapping->area.x2;
2266                 field_mapping->area.y1 = height - mapping->area.y2;
2267                 field_mapping->area.y2 = height - mapping->area.y1;
2268                 field_mapping->data = ev_field;
2269                 ev_field->page = EV_PAGE (g_object_ref (page));
2270
2271                 g_object_set_data_full (G_OBJECT (ev_field),
2272                                         "poppler-field",
2273                                         g_object_ref (mapping->field),
2274                                         (GDestroyNotify) g_object_unref);
2275                 
2276                 retval = g_list_prepend (retval, field_mapping);
2277         }
2278         
2279         poppler_page_free_form_field_mapping (fields);
2280
2281         return retval ? ev_mapping_list_new (page->index,
2282                                              g_list_reverse (retval),
2283                                              (GDestroyNotify)g_object_unref) : NULL;
2284 }
2285
2286 static gboolean
2287 pdf_document_forms_document_is_modified (EvDocumentForms *document)
2288 {
2289         return PDF_DOCUMENT (document)->forms_modified;
2290 }
2291
2292 static gchar *
2293 pdf_document_forms_form_field_text_get_text (EvDocumentForms *document,
2294                                              EvFormField     *field)
2295         
2296 {
2297         PopplerFormField *poppler_field;
2298         gchar *text;
2299
2300         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2301         if (!poppler_field)
2302                 return NULL;
2303         
2304         text = poppler_form_field_text_get_text (poppler_field);
2305
2306         return text;
2307 }
2308
2309 static void
2310 pdf_document_forms_form_field_text_set_text (EvDocumentForms *document, 
2311                                              EvFormField     *field,
2312                                              const gchar     *text)
2313 {
2314         PopplerFormField *poppler_field;
2315
2316         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2317         if (!poppler_field)
2318                 return;
2319         
2320         poppler_form_field_text_set_text (poppler_field, text);
2321         PDF_DOCUMENT (document)->forms_modified = TRUE;
2322 }
2323
2324 static void
2325 pdf_document_forms_form_field_button_set_state (EvDocumentForms *document, 
2326                                                 EvFormField     *field,
2327                                                 gboolean         state)
2328 {
2329         PopplerFormField *poppler_field;
2330
2331         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2332         if (!poppler_field)
2333                 return;
2334         
2335         poppler_form_field_button_set_state (poppler_field, state);
2336         PDF_DOCUMENT (document)->forms_modified = TRUE;
2337 }
2338
2339 static gboolean
2340 pdf_document_forms_form_field_button_get_state (EvDocumentForms *document, 
2341                                                 EvFormField     *field)
2342 {
2343         PopplerFormField *poppler_field;
2344         gboolean state;
2345
2346         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2347         if (!poppler_field)
2348                 return FALSE;
2349
2350         state = poppler_form_field_button_get_state (poppler_field);
2351
2352         return state;
2353 }
2354
2355 static gchar *
2356 pdf_document_forms_form_field_choice_get_item (EvDocumentForms *document, 
2357                                                EvFormField     *field,
2358                                                gint             index)
2359 {
2360         PopplerFormField *poppler_field;
2361         gchar *text;
2362
2363         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2364         if (!poppler_field)
2365                 return NULL;
2366
2367         text = poppler_form_field_choice_get_item (poppler_field, index);
2368
2369         return text;
2370 }
2371
2372 static int
2373 pdf_document_forms_form_field_choice_get_n_items (EvDocumentForms *document, 
2374                                                   EvFormField     *field)
2375 {
2376         PopplerFormField *poppler_field;
2377         gint n_items;
2378
2379         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2380         if (!poppler_field)
2381                 return -1;
2382         
2383         n_items = poppler_form_field_choice_get_n_items (poppler_field);
2384
2385         return n_items;
2386 }
2387
2388 static gboolean
2389 pdf_document_forms_form_field_choice_is_item_selected (EvDocumentForms *document, 
2390                                                        EvFormField     *field,
2391                                                        gint             index)
2392 {
2393         PopplerFormField *poppler_field;
2394         gboolean selected;
2395
2396         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2397         if (!poppler_field)
2398                 return FALSE;
2399
2400         selected = poppler_form_field_choice_is_item_selected (poppler_field, index);
2401
2402         return selected;
2403 }
2404
2405 static void
2406 pdf_document_forms_form_field_choice_select_item (EvDocumentForms *document, 
2407                                                   EvFormField     *field,
2408                                                   gint             index)
2409 {
2410         PopplerFormField *poppler_field;
2411
2412         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2413         if (!poppler_field)
2414                 return;
2415
2416         poppler_form_field_choice_select_item (poppler_field, index);
2417         PDF_DOCUMENT (document)->forms_modified = TRUE;
2418 }
2419
2420 static void
2421 pdf_document_forms_form_field_choice_toggle_item (EvDocumentForms *document, 
2422                                                   EvFormField     *field,
2423                                                   gint             index)
2424 {
2425         PopplerFormField *poppler_field;
2426
2427         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2428         if (!poppler_field)
2429                 return;
2430
2431         poppler_form_field_choice_toggle_item (poppler_field, index);
2432         PDF_DOCUMENT (document)->forms_modified = TRUE;
2433 }
2434
2435 static void
2436 pdf_document_forms_form_field_choice_unselect_all (EvDocumentForms *document, 
2437                                                    EvFormField     *field)
2438 {
2439         PopplerFormField *poppler_field;
2440
2441         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2442         if (!poppler_field)
2443                 return;
2444         
2445         poppler_form_field_choice_unselect_all (poppler_field);
2446         PDF_DOCUMENT (document)->forms_modified = TRUE;
2447 }
2448
2449 static void
2450 pdf_document_forms_form_field_choice_set_text (EvDocumentForms *document,
2451                                                EvFormField     *field,
2452                                                const gchar     *text)
2453 {
2454         PopplerFormField *poppler_field;
2455
2456         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2457         if (!poppler_field)
2458                 return;
2459         
2460         poppler_form_field_choice_set_text (poppler_field, text);
2461         PDF_DOCUMENT (document)->forms_modified = TRUE;
2462 }
2463
2464 static gchar *
2465 pdf_document_forms_form_field_choice_get_text (EvDocumentForms *document,
2466                                                EvFormField     *field)
2467 {
2468         PopplerFormField *poppler_field;
2469         gchar *text;
2470
2471         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2472         if (!poppler_field)
2473                 return NULL;
2474
2475         text = poppler_form_field_choice_get_text (poppler_field);
2476
2477         return text;
2478 }
2479
2480 static void
2481 pdf_document_document_forms_iface_init (EvDocumentFormsInterface *iface)
2482 {
2483         iface->get_form_fields = pdf_document_forms_get_form_fields;
2484         iface->document_is_modified = pdf_document_forms_document_is_modified;
2485         iface->form_field_text_get_text = pdf_document_forms_form_field_text_get_text;
2486         iface->form_field_text_set_text = pdf_document_forms_form_field_text_set_text;
2487         iface->form_field_button_set_state = pdf_document_forms_form_field_button_set_state;
2488         iface->form_field_button_get_state = pdf_document_forms_form_field_button_get_state;
2489         iface->form_field_choice_get_item = pdf_document_forms_form_field_choice_get_item;
2490         iface->form_field_choice_get_n_items = pdf_document_forms_form_field_choice_get_n_items;
2491         iface->form_field_choice_is_item_selected = pdf_document_forms_form_field_choice_is_item_selected;
2492         iface->form_field_choice_select_item = pdf_document_forms_form_field_choice_select_item;
2493         iface->form_field_choice_toggle_item = pdf_document_forms_form_field_choice_toggle_item;
2494         iface->form_field_choice_unselect_all = pdf_document_forms_form_field_choice_unselect_all;
2495         iface->form_field_choice_set_text = pdf_document_forms_form_field_choice_set_text;
2496         iface->form_field_choice_get_text = pdf_document_forms_form_field_choice_get_text;
2497 }
2498
2499 /* Annotations */
2500 static void
2501 poppler_annot_color_to_gdk_color (PopplerAnnot *poppler_annot,
2502                                   GdkColor     *color)
2503 {
2504         PopplerColor *poppler_color;
2505
2506         poppler_color = poppler_annot_get_color (poppler_annot);
2507         if (poppler_color) {
2508                 color->red = poppler_color->red;
2509                 color->green = poppler_color->green;
2510                 color->blue = poppler_color->blue;
2511
2512                 g_free (poppler_color);
2513         } /* TODO: else use a default color */
2514 }
2515
2516 static EvAnnotationTextIcon
2517 get_annot_text_icon (PopplerAnnotText *poppler_annot)
2518 {
2519 #ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
2520         gchar *icon = poppler_annot_text_get_icon (poppler_annot);
2521         EvAnnotationTextIcon retval;
2522
2523         if (!icon)
2524                 return EV_ANNOTATION_TEXT_ICON_UNKNOWN;
2525
2526         if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_NOTE) == 0)
2527                 retval = EV_ANNOTATION_TEXT_ICON_NOTE;
2528         else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_COMMENT) == 0)
2529                 retval = EV_ANNOTATION_TEXT_ICON_COMMENT;
2530         else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_KEY) == 0)
2531                 retval = EV_ANNOTATION_TEXT_ICON_KEY;
2532         else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_HELP) == 0)
2533                 retval = EV_ANNOTATION_TEXT_ICON_HELP;
2534         else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_NEW_PARAGRAPH) == 0)
2535                 retval = EV_ANNOTATION_TEXT_ICON_NEW_PARAGRAPH;
2536         else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_PARAGRAPH) == 0)
2537                 retval = EV_ANNOTATION_TEXT_ICON_PARAGRAPH;
2538         else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_INSERT) == 0)
2539                 retval = EV_ANNOTATION_TEXT_ICON_INSERT;
2540         else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_CROSS) == 0)
2541                 retval = EV_ANNOTATION_TEXT_ICON_CROSS;
2542         else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_CIRCLE) == 0)
2543                 retval = EV_ANNOTATION_TEXT_ICON_CIRCLE;
2544         else
2545                 retval = EV_ANNOTATION_TEXT_ICON_UNKNOWN;
2546
2547         g_free (icon);
2548
2549         return retval;
2550 #else
2551         return EV_ANNOTATION_TEXT_ICON_UNKNOWN;
2552 #endif
2553 }
2554
2555 static const gchar *
2556 get_poppler_annot_text_icon (EvAnnotationTextIcon icon)
2557 {
2558 #ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
2559         switch (icon) {
2560         case EV_ANNOTATION_TEXT_ICON_NOTE:
2561                 return POPPLER_ANNOT_TEXT_ICON_NOTE;
2562         case EV_ANNOTATION_TEXT_ICON_COMMENT:
2563                 return POPPLER_ANNOT_TEXT_ICON_COMMENT;
2564         case EV_ANNOTATION_TEXT_ICON_KEY:
2565                 return POPPLER_ANNOT_TEXT_ICON_KEY;
2566         case EV_ANNOTATION_TEXT_ICON_HELP:
2567                 return POPPLER_ANNOT_TEXT_ICON_HELP;
2568         case EV_ANNOTATION_TEXT_ICON_NEW_PARAGRAPH:
2569                 return POPPLER_ANNOT_TEXT_ICON_NEW_PARAGRAPH;
2570         case EV_ANNOTATION_TEXT_ICON_PARAGRAPH:
2571                 return POPPLER_ANNOT_TEXT_ICON_PARAGRAPH;
2572         case EV_ANNOTATION_TEXT_ICON_INSERT:
2573                 return POPPLER_ANNOT_TEXT_ICON_INSERT;
2574         case EV_ANNOTATION_TEXT_ICON_CROSS:
2575                 return POPPLER_ANNOT_TEXT_ICON_CROSS;
2576         case EV_ANNOTATION_TEXT_ICON_CIRCLE:
2577                 return POPPLER_ANNOT_TEXT_ICON_CIRCLE;
2578         case EV_ANNOTATION_TEXT_ICON_UNKNOWN:
2579         default:
2580                 return POPPLER_ANNOT_TEXT_ICON_NOTE;
2581         }
2582 #else
2583         return "Note";
2584 #endif
2585 }
2586
2587 static EvAnnotation *
2588 ev_annot_from_poppler_annot (PopplerAnnot *poppler_annot,
2589                              EvPage       *page)
2590 {
2591         EvAnnotation *ev_annot = NULL;
2592         const gchar  *unimplemented_annot = NULL;
2593
2594         switch (poppler_annot_get_annot_type (poppler_annot)) {
2595                 case POPPLER_ANNOT_TEXT: {
2596                         PopplerAnnotText *poppler_text;
2597                         EvAnnotationText *ev_annot_text;
2598
2599                         poppler_text = POPPLER_ANNOT_TEXT (poppler_annot);
2600
2601                         ev_annot = ev_annotation_text_new (page);
2602
2603                         ev_annot_text = EV_ANNOTATION_TEXT (ev_annot);
2604                         ev_annotation_text_set_is_open (ev_annot_text,
2605                                                         poppler_annot_text_get_is_open (poppler_text));
2606                         ev_annotation_text_set_icon (ev_annot_text, get_annot_text_icon (poppler_text));
2607                 }
2608                         break;
2609                 case POPPLER_ANNOT_FILE_ATTACHMENT: {
2610                         PopplerAnnotFileAttachment *poppler_annot_attachment;
2611                         EvAnnotationAttachment     *ev_annot_attachment;
2612                         PopplerAttachment          *poppler_attachment;
2613                         gchar                      *data = NULL;
2614                         gsize                       size;
2615                         GError                     *error = NULL;
2616
2617                         poppler_annot_attachment = POPPLER_ANNOT_FILE_ATTACHMENT (poppler_annot);
2618                         poppler_attachment = poppler_annot_file_attachment_get_attachment (poppler_annot_attachment);
2619
2620                         if (poppler_attachment &&
2621                             attachment_save_to_buffer (poppler_attachment, &data, &size, &error)) {
2622                                 EvAttachment *ev_attachment;
2623
2624                                 ev_attachment = ev_attachment_new (poppler_attachment->name,
2625                                                                    poppler_attachment->description,
2626                                                                    poppler_attachment->mtime,
2627                                                                    poppler_attachment->ctime,
2628                                                                    size, data);
2629                                 ev_annot = ev_annotation_attachment_new (page, ev_attachment);
2630                                 g_object_unref (ev_attachment);
2631                         } else if (error) {
2632                                 g_warning ("%s", error->message);
2633                                 g_error_free (error);
2634                         }
2635
2636                         if (poppler_attachment)
2637                                 g_object_unref (poppler_attachment);
2638                 }
2639                         break;
2640                 case POPPLER_ANNOT_LINK:
2641                 case POPPLER_ANNOT_WIDGET:
2642                         /* Ignore link and widgets annots since they are already handled */
2643                         break;
2644                 default: {
2645                         GEnumValue *enum_value;
2646
2647                         enum_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (POPPLER_TYPE_ANNOT_TYPE),
2648                                                        poppler_annot_get_annot_type (poppler_annot));
2649                         unimplemented_annot = enum_value ? enum_value->value_name : "Unknown annotation";
2650                 }
2651         }
2652
2653         if (unimplemented_annot) {
2654                 g_warning ("Unimplemented annotation: %s, please post a "
2655                            "bug report in Evince bugzilla "
2656                            "(http://bugzilla.gnome.org) with a testcase.",
2657                            unimplemented_annot);
2658         }
2659
2660         if (ev_annot) {
2661                 time_t   utime;
2662                 gchar   *modified;
2663                 gchar   *contents;
2664                 gchar   *name;
2665                 GdkColor color;
2666
2667                 contents = poppler_annot_get_contents (poppler_annot);
2668                 if (contents) {
2669                         ev_annotation_set_contents (ev_annot, contents);
2670                         g_free (contents);
2671                 }
2672
2673                 name = poppler_annot_get_name (poppler_annot);
2674                 if (name) {
2675                         ev_annotation_set_name (ev_annot, name);
2676                         g_free (name);
2677                 }
2678
2679                 modified = poppler_annot_get_modified (poppler_annot);
2680                 if (poppler_date_parse (modified, &utime)) {
2681                         ev_annotation_set_modified_from_time (ev_annot, utime);
2682                 } else {
2683                         ev_annotation_set_modified (ev_annot, modified);
2684                 }
2685                 g_free (modified);
2686
2687                 poppler_annot_color_to_gdk_color (poppler_annot, &color);
2688                 ev_annotation_set_color (ev_annot, &color);
2689
2690                 if (POPPLER_IS_ANNOT_MARKUP (poppler_annot)) {
2691                         PopplerAnnotMarkup *markup;
2692                         gchar *label;
2693                         gdouble opacity;
2694                         PopplerRectangle poppler_rect;
2695
2696                         markup = POPPLER_ANNOT_MARKUP (poppler_annot);
2697
2698                         if (poppler_annot_markup_get_popup_rectangle (markup, &poppler_rect)) {
2699                                 EvRectangle ev_rect;
2700                                 gboolean is_open;
2701                                 gdouble height;
2702
2703                                 poppler_page_get_size (POPPLER_PAGE (page->backend_page),
2704                                                        NULL, &height);
2705                                 ev_rect.x1 = poppler_rect.x1;
2706                                 ev_rect.x2 = poppler_rect.x2;
2707                                 ev_rect.y1 = height - poppler_rect.y2;
2708                                 ev_rect.y2 = height - poppler_rect.y1;
2709
2710                                 is_open = poppler_annot_markup_get_popup_is_open (markup);
2711
2712                                 g_object_set (ev_annot,
2713                                               "rectangle", &ev_rect,
2714                                               "popup_is_open", is_open,
2715                                               "has_popup", TRUE,
2716                                               NULL);
2717                         } else {
2718                                 g_object_set (ev_annot,
2719                                               "has_popup", FALSE,
2720                                               NULL);
2721                         }
2722
2723                         label = poppler_annot_markup_get_label (markup);
2724                         opacity = poppler_annot_markup_get_opacity (markup);
2725
2726                         g_object_set (ev_annot,
2727                                       "label", label,
2728                                       "opacity", opacity,
2729                                       NULL);
2730
2731                         g_free (label);
2732                 }
2733         }
2734
2735         return ev_annot;
2736 }
2737
2738 static EvMappingList *
2739 pdf_document_annotations_get_annotations (EvDocumentAnnotations *document_annotations,
2740                                           EvPage                *page)
2741 {
2742         GList *retval = NULL;
2743         PdfDocument *pdf_document;
2744         PopplerPage *poppler_page;
2745         EvMappingList *mapping_list;
2746         GList *annots;
2747         GList *list;
2748         gdouble height;
2749         gint i = 0;
2750
2751         pdf_document = PDF_DOCUMENT (document_annotations);
2752         poppler_page = POPPLER_PAGE (page->backend_page);
2753
2754         if (pdf_document->annots) {
2755                 mapping_list = (EvMappingList *)g_hash_table_lookup (pdf_document->annots,
2756                                                                      GINT_TO_POINTER (page->index));
2757                 if (mapping_list)
2758                         return ev_mapping_list_ref (mapping_list);
2759         }
2760
2761         annots = poppler_page_get_annot_mapping (poppler_page);
2762         poppler_page_get_size (poppler_page, NULL, &height);
2763
2764         for (list = annots; list; list = list->next) {
2765                 PopplerAnnotMapping *mapping;
2766                 EvMapping           *annot_mapping;
2767                 EvAnnotation        *ev_annot;
2768
2769                 mapping = (PopplerAnnotMapping *)list->data;
2770
2771                 ev_annot = ev_annot_from_poppler_annot (mapping->annot, page);
2772                 if (!ev_annot)
2773                         continue;
2774
2775                 i++;
2776
2777                 /* Make sure annot has a unique name */
2778                 if (!ev_annotation_get_name (ev_annot)) {
2779                         gchar *name = g_strdup_printf ("annot-%d-%d", page->index, i);
2780
2781                         ev_annotation_set_name (ev_annot, name);
2782                         g_free (name);
2783                 }
2784
2785                 annot_mapping = g_new (EvMapping, 1);
2786                 annot_mapping->area.x1 = mapping->area.x1;
2787                 annot_mapping->area.x2 = mapping->area.x2;
2788                 annot_mapping->area.y1 = height - mapping->area.y2;
2789                 annot_mapping->area.y2 = height - mapping->area.y1;
2790                 annot_mapping->data = ev_annot;
2791
2792                 g_object_set_data_full (G_OBJECT (ev_annot),
2793                                         "poppler-annot",
2794                                         g_object_ref (mapping->annot),
2795                                         (GDestroyNotify) g_object_unref);
2796
2797                 retval = g_list_prepend (retval, annot_mapping);
2798         }
2799
2800         poppler_page_free_annot_mapping (annots);
2801
2802         if (!retval)
2803                 return NULL;
2804
2805         if (!pdf_document->annots) {
2806                 pdf_document->annots = g_hash_table_new_full (g_direct_hash,
2807                                                               g_direct_equal,
2808                                                               (GDestroyNotify)NULL,
2809                                                               (GDestroyNotify)ev_mapping_list_unref);
2810         }
2811
2812         mapping_list = ev_mapping_list_new (page->index, g_list_reverse (retval), (GDestroyNotify)g_object_unref);
2813         g_hash_table_insert (pdf_document->annots,
2814                              GINT_TO_POINTER (page->index),
2815                              ev_mapping_list_ref (mapping_list));
2816
2817         return mapping_list;
2818 }
2819
2820 static gboolean
2821 pdf_document_annotations_document_is_modified (EvDocumentAnnotations *document_annotations)
2822 {
2823         return PDF_DOCUMENT (document_annotations)->annots_modified;
2824 }
2825
2826 #ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
2827 static void
2828 pdf_document_annotations_add_annotation (EvDocumentAnnotations *document_annotations,
2829                                          EvAnnotation          *annot,
2830                                          EvRectangle           *rect)
2831 {
2832         PopplerAnnot    *poppler_annot;
2833         PdfDocument     *pdf_document;
2834         EvPage          *page;
2835         PopplerPage     *poppler_page;
2836         GList           *list = NULL;
2837         EvMappingList   *mapping_list;
2838         EvMapping       *annot_mapping;
2839         PopplerRectangle poppler_rect;
2840         gdouble          height;
2841         PopplerColor     poppler_color;
2842         GdkColor         color;
2843         time_t           utime;
2844         gchar           *modified;
2845         gchar           *name;
2846
2847         pdf_document = PDF_DOCUMENT (document_annotations);
2848         page = ev_annotation_get_page (annot);
2849         poppler_page = POPPLER_PAGE (page->backend_page);
2850
2851         poppler_page_get_size (poppler_page, NULL, &height);
2852         poppler_rect.x1 = rect->x1;
2853         poppler_rect.x2 = rect->x2;
2854         poppler_rect.y1 = height - rect->y2;
2855         poppler_rect.y2 = height - rect->y1;
2856         poppler_annot = poppler_annot_text_new (pdf_document->document, &poppler_rect);
2857
2858         ev_annotation_get_color (annot, &color);
2859         poppler_color.red = color.red;
2860         poppler_color.green = color.green;
2861         poppler_color.blue = color.blue;
2862         poppler_annot_set_color (poppler_annot, &poppler_color);
2863
2864         if (EV_IS_ANNOTATION_MARKUP (annot)) {
2865                 EvAnnotationMarkup *markup = EV_ANNOTATION_MARKUP (annot);
2866                 const gchar *label;
2867
2868                 if (ev_annotation_markup_has_popup (markup)) {
2869                         EvRectangle popup_rect;
2870
2871                         ev_annotation_markup_get_rectangle (markup, &popup_rect);
2872                         poppler_rect.x1 = popup_rect.x1;
2873                         poppler_rect.x2 = popup_rect.x2;
2874                         poppler_rect.y1 = height - popup_rect.y2;
2875                         poppler_rect.y2 = height - popup_rect.y1;
2876                         poppler_annot_markup_set_popup (POPPLER_ANNOT_MARKUP (poppler_annot), &poppler_rect);
2877                         poppler_annot_markup_set_popup_is_open (POPPLER_ANNOT_MARKUP (poppler_annot),
2878                                                                 ev_annotation_markup_get_popup_is_open (markup));
2879                 }
2880
2881                 label = ev_annotation_markup_get_label (markup);
2882                 if (label)
2883                         poppler_annot_markup_set_label (POPPLER_ANNOT_MARKUP (poppler_annot), label);
2884         }
2885
2886         if (EV_IS_ANNOTATION_TEXT (annot)) {
2887                 EvAnnotationText    *text = EV_ANNOTATION_TEXT (annot);
2888                 EvAnnotationTextIcon icon;
2889
2890                 icon = ev_annotation_text_get_icon (text);
2891                 poppler_annot_text_set_icon (POPPLER_ANNOT_TEXT (poppler_annot),
2892                                              get_poppler_annot_text_icon (icon));
2893         }
2894         poppler_page_add_annot (poppler_page, poppler_annot);
2895
2896         annot_mapping = g_new (EvMapping, 1);
2897         annot_mapping->area = *rect;
2898         annot_mapping->data = annot;
2899         g_object_set_data_full (G_OBJECT (annot),
2900                                 "poppler-annot",
2901                                 g_object_ref (poppler_annot),
2902                                 (GDestroyNotify) g_object_unref);
2903
2904         if (pdf_document->annots) {
2905                 mapping_list = (EvMappingList *)g_hash_table_lookup (pdf_document->annots,
2906                                                                      GINT_TO_POINTER (page->index));
2907                 list = ev_mapping_list_get_list (mapping_list);
2908                 name = g_strdup_printf ("annot-%d-%d", page->index, g_list_length (list) + 1);
2909                 ev_annotation_set_name (annot, name);
2910                 g_free (name);
2911                 list = g_list_append (list, annot_mapping);
2912         } else {
2913                 pdf_document->annots = g_hash_table_new_full (g_direct_hash,
2914                                                               g_direct_equal,
2915                                                               (GDestroyNotify)NULL,
2916                                                               (GDestroyNotify)ev_mapping_list_unref);
2917                 name = g_strdup_printf ("annot-%d-0", page->index);
2918                 ev_annotation_set_name (annot, name);
2919                 g_free (name);
2920                 list = g_list_append (list, annot_mapping);
2921                 mapping_list = ev_mapping_list_new (page->index, list, (GDestroyNotify)g_object_unref);
2922                 g_hash_table_insert (pdf_document->annots,
2923                                      GINT_TO_POINTER (page->index),
2924                                      ev_mapping_list_ref (mapping_list));
2925         }
2926
2927         pdf_document->annots_modified = TRUE;
2928 }
2929 #endif /* HAVE_POPPLER_PAGE_ADD_ANNOT */
2930
2931 static void
2932 pdf_document_annotations_save_annotation (EvDocumentAnnotations *document_annotations,
2933                                           EvAnnotation          *annot,
2934                                           EvAnnotationsSaveMask  mask)
2935 {
2936         PopplerAnnot *poppler_annot;
2937
2938         poppler_annot = POPPLER_ANNOT (g_object_get_data (G_OBJECT (annot), "poppler-annot"));
2939         if (!poppler_annot)
2940                 return;
2941
2942         if (mask & EV_ANNOTATIONS_SAVE_CONTENTS)
2943                 poppler_annot_set_contents (poppler_annot,
2944                                             ev_annotation_get_contents (annot));
2945
2946 #ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
2947         if (mask & EV_ANNOTATIONS_SAVE_COLOR) {
2948                 PopplerColor color;
2949                 GdkColor     ev_color;
2950
2951                 ev_annotation_get_color (annot, &ev_color);
2952                 color.red = ev_color.red;
2953                 color.green = ev_color.green;
2954                 color.blue = ev_color.blue;
2955                 poppler_annot_set_color (poppler_annot, &color);
2956         }
2957
2958         if (EV_IS_ANNOTATION_MARKUP (annot)) {
2959                 EvAnnotationMarkup *ev_markup = EV_ANNOTATION_MARKUP (annot);
2960                 PopplerAnnotMarkup *markup = POPPLER_ANNOT_MARKUP (poppler_annot);
2961
2962                 if (mask & EV_ANNOTATIONS_SAVE_LABEL)
2963                         poppler_annot_markup_set_label (markup, ev_annotation_markup_get_label (ev_markup));
2964                 if (mask & EV_ANNOTATIONS_SAVE_OPACITY)
2965                         poppler_annot_markup_set_opacity (markup, ev_annotation_markup_get_opacity (ev_markup));
2966                 if (mask & EV_ANNOTATIONS_SAVE_POPUP_IS_OPEN)
2967                         poppler_annot_markup_set_popup_is_open (markup, ev_annotation_markup_get_popup_is_open (ev_markup));
2968         }
2969
2970         if (EV_IS_ANNOTATION_TEXT (annot)) {
2971                 EvAnnotationText *ev_text = EV_ANNOTATION_TEXT (annot);
2972                 PopplerAnnotText *text = POPPLER_ANNOT_TEXT (poppler_annot);
2973
2974                 if (mask & EV_ANNOTATIONS_SAVE_TEXT_IS_OPEN) {
2975                         poppler_annot_text_set_is_open (text,
2976                                                         ev_annotation_text_get_is_open (ev_text));
2977                 }
2978                 if (mask & EV_ANNOTATIONS_SAVE_TEXT_ICON) {
2979                         EvAnnotationTextIcon icon;
2980
2981                         icon = ev_annotation_text_get_icon (ev_text);
2982                         poppler_annot_text_set_icon (text, get_poppler_annot_text_icon (icon));
2983                 }
2984         }
2985 #endif /* HAVE_POPPLER_PAGE_ADD_ANNOT */
2986         PDF_DOCUMENT (document_annotations)->annots_modified = TRUE;
2987 }
2988
2989 static void
2990 pdf_document_document_annotations_iface_init (EvDocumentAnnotationsInterface *iface)
2991 {
2992         iface->get_annotations = pdf_document_annotations_get_annotations;
2993         iface->document_is_modified = pdf_document_annotations_document_is_modified;
2994 #ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
2995         iface->add_annotation = pdf_document_annotations_add_annotation;
2996 #endif
2997         iface->save_annotation = pdf_document_annotations_save_annotation;
2998 }
2999
3000 /* Attachments */
3001 struct SaveToBufferData {
3002         gchar *buffer;
3003         gsize len, max;
3004 };
3005
3006 static gboolean
3007 attachment_save_to_buffer_callback (const gchar  *buf,
3008                                     gsize         count,
3009                                     gpointer      user_data,
3010                                     GError      **error)
3011 {
3012         struct SaveToBufferData *sdata = (SaveToBufferData *)user_data;
3013         gchar *new_buffer;
3014         gsize new_max;
3015
3016         if (sdata->len + count > sdata->max) {
3017                 new_max = MAX (sdata->max * 2, sdata->len + count);
3018                 new_buffer = (gchar *)g_realloc (sdata->buffer, new_max);
3019
3020                 sdata->buffer = new_buffer;
3021                 sdata->max = new_max;
3022         }
3023
3024         memcpy (sdata->buffer + sdata->len, buf, count);
3025         sdata->len += count;
3026
3027         return TRUE;
3028 }
3029
3030 static gboolean
3031 attachment_save_to_buffer (PopplerAttachment  *attachment,
3032                            gchar             **buffer,
3033                            gsize              *buffer_size,
3034                            GError            **error)
3035 {
3036         static const gint initial_max = 1024;
3037         struct SaveToBufferData sdata;
3038
3039         *buffer = NULL;
3040         *buffer_size = 0;
3041
3042         sdata.buffer = (gchar *) g_malloc (initial_max);
3043         sdata.max = initial_max;
3044         sdata.len = 0;
3045
3046         if (! poppler_attachment_save_to_callback (attachment,
3047                                                    attachment_save_to_buffer_callback,
3048                                                    &sdata,
3049                                                    error)) {
3050                 g_free (sdata.buffer);
3051                 return FALSE;
3052         }
3053
3054         *buffer = sdata.buffer;
3055         *buffer_size = sdata.len;
3056
3057         return TRUE;
3058 }
3059
3060 static GList *
3061 pdf_document_attachments_get_attachments (EvDocumentAttachments *document)
3062 {
3063         PdfDocument *pdf_document = PDF_DOCUMENT (document);
3064         GList *attachments;
3065         GList *list;
3066         GList *retval = NULL;
3067
3068         attachments = poppler_document_get_attachments (pdf_document->document);
3069
3070         for (list = attachments; list; list = list->next) {
3071                 PopplerAttachment *attachment;
3072                 EvAttachment *ev_attachment;
3073                 gchar *data = NULL;
3074                 gsize size;
3075                 GError *error = NULL;
3076
3077                 attachment = (PopplerAttachment *) list->data;
3078
3079                 if (attachment_save_to_buffer (attachment, &data, &size, &error)) {
3080                         ev_attachment = ev_attachment_new (attachment->name,
3081                                                            attachment->description,
3082                                                            attachment->mtime,
3083                                                            attachment->ctime,
3084                                                            size, data);
3085
3086                         retval = g_list_prepend (retval, ev_attachment);
3087                 } else {
3088                         if (error) {
3089                                 g_warning ("%s", error->message);
3090                                 g_error_free (error);
3091
3092                                 g_free (data);
3093                         }
3094                 }
3095
3096                 g_object_unref (attachment);
3097         }
3098
3099         return g_list_reverse (retval);
3100 }
3101
3102 static gboolean
3103 pdf_document_attachments_has_attachments (EvDocumentAttachments *document)
3104 {
3105         PdfDocument *pdf_document = PDF_DOCUMENT (document);
3106
3107         return poppler_document_has_attachments (pdf_document->document);
3108 }
3109
3110 static void
3111 pdf_document_document_attachments_iface_init (EvDocumentAttachmentsInterface *iface)
3112 {
3113         iface->has_attachments = pdf_document_attachments_has_attachments;
3114         iface->get_attachments = pdf_document_attachments_get_attachments;
3115 }
3116
3117 /* Layers */
3118 static gboolean
3119 pdf_document_layers_has_layers (EvDocumentLayers *document)
3120 {
3121         PdfDocument *pdf_document = PDF_DOCUMENT (document);
3122         PopplerLayersIter *iter;
3123
3124         iter = poppler_layers_iter_new (pdf_document->document);
3125         if (!iter)
3126                 return FALSE;
3127         poppler_layers_iter_free (iter);
3128
3129         return TRUE;
3130 }
3131
3132 static void
3133 build_layers_tree (PdfDocument       *pdf_document,
3134                    GtkTreeModel      *model,
3135                    GtkTreeIter       *parent,
3136                    PopplerLayersIter *iter)
3137 {
3138         do {
3139                 GtkTreeIter        tree_iter;
3140                 PopplerLayersIter *child;
3141                 PopplerLayer      *layer;
3142                 EvLayer           *ev_layer = NULL;
3143                 gboolean           visible;
3144                 gchar             *markup;
3145                 gint               rb_group = 0;
3146
3147                 layer = poppler_layers_iter_get_layer (iter);
3148                 if (layer) {
3149                         markup = g_markup_escape_text (poppler_layer_get_title (layer), -1);
3150                         visible = poppler_layer_is_visible (layer);
3151                         rb_group = poppler_layer_get_radio_button_group_id (layer);
3152                         pdf_document->layers = g_list_append (pdf_document->layers,
3153                                                               g_object_ref (layer));
3154                         ev_layer = ev_layer_new (g_list_length (pdf_document->layers) - 1,
3155                                                  poppler_layer_is_parent (layer),
3156                                                  rb_group);
3157                 } else {
3158                         gchar *title;
3159
3160                         title = poppler_layers_iter_get_title (iter);
3161                         markup = g_markup_escape_text (title, -1);
3162                         g_free (title);
3163
3164                         visible = FALSE;
3165                         layer = NULL;
3166                 }
3167
3168                 gtk_tree_store_append (GTK_TREE_STORE (model), &tree_iter, parent);
3169                 gtk_tree_store_set (GTK_TREE_STORE (model), &tree_iter,
3170                                     EV_DOCUMENT_LAYERS_COLUMN_TITLE, markup,
3171                                     EV_DOCUMENT_LAYERS_COLUMN_VISIBLE, visible,
3172                                     EV_DOCUMENT_LAYERS_COLUMN_ENABLED, TRUE, /* FIXME */
3173                                     EV_DOCUMENT_LAYERS_COLUMN_SHOWTOGGLE, (layer != NULL),
3174                                     EV_DOCUMENT_LAYERS_COLUMN_RBGROUP, rb_group,
3175                                     EV_DOCUMENT_LAYERS_COLUMN_LAYER, ev_layer,
3176                                     -1);
3177                 if (ev_layer)
3178                         g_object_unref (ev_layer);
3179                 g_free (markup);
3180
3181                 child = poppler_layers_iter_get_child (iter);
3182                 if (child)
3183                         build_layers_tree (pdf_document, model, &tree_iter, child);
3184                 poppler_layers_iter_free (child);
3185         } while (poppler_layers_iter_next (iter));
3186 }
3187
3188 static GtkTreeModel *
3189 pdf_document_layers_get_layers (EvDocumentLayers *document)
3190 {
3191         GtkTreeModel *model = NULL;
3192         PdfDocument *pdf_document = PDF_DOCUMENT (document);
3193         PopplerLayersIter *iter;
3194
3195         iter = poppler_layers_iter_new (pdf_document->document);
3196         if (iter) {
3197                 model = (GtkTreeModel *) gtk_tree_store_new (EV_DOCUMENT_LAYERS_N_COLUMNS,
3198                                                              G_TYPE_STRING,  /* TITLE */
3199                                                              G_TYPE_OBJECT,  /* LAYER */
3200                                                              G_TYPE_BOOLEAN, /* VISIBLE */
3201                                                              G_TYPE_BOOLEAN, /* ENABLED */
3202                                                              G_TYPE_BOOLEAN, /* SHOWTOGGLE */
3203                                                              G_TYPE_INT);    /* RBGROUP */
3204                 build_layers_tree (pdf_document, model, NULL, iter);
3205                 poppler_layers_iter_free (iter);
3206         }
3207         return model;
3208 }
3209
3210 static void
3211 pdf_document_layers_show_layer (EvDocumentLayers *document,
3212                                 EvLayer          *layer)
3213 {
3214         PdfDocument *pdf_document = PDF_DOCUMENT (document);
3215         guint        layer_id = ev_layer_get_id (layer);
3216
3217         poppler_layer_show (POPPLER_LAYER (g_list_nth_data (pdf_document->layers, layer_id)));
3218 }
3219
3220 static void
3221 pdf_document_layers_hide_layer (EvDocumentLayers *document,
3222                                 EvLayer          *layer)
3223 {
3224         PdfDocument *pdf_document = PDF_DOCUMENT (document);
3225         guint        layer_id = ev_layer_get_id (layer);
3226
3227         poppler_layer_hide (POPPLER_LAYER (g_list_nth_data (pdf_document->layers, layer_id)));
3228 }
3229
3230 static gboolean
3231 pdf_document_layers_layer_is_visible (EvDocumentLayers *document,
3232                                       EvLayer          *layer)
3233 {
3234         PdfDocument *pdf_document = PDF_DOCUMENT (document);
3235         guint        layer_id = ev_layer_get_id (layer);
3236
3237         return poppler_layer_is_visible (POPPLER_LAYER (g_list_nth_data (pdf_document->layers, layer_id)));
3238 }
3239
3240 static void
3241 pdf_document_document_layers_iface_init (EvDocumentLayersInterface *iface)
3242 {
3243         iface->has_layers = pdf_document_layers_has_layers;
3244         iface->get_layers = pdf_document_layers_get_layers;
3245         iface->show_layer = pdf_document_layers_show_layer;
3246         iface->hide_layer = pdf_document_layers_hide_layer;
3247         iface->layer_is_visible = pdf_document_layers_layer_is_visible;
3248 }