]> www.fi.muni.cz Git - evince.git/blob - backend/pdf/ev-poppler.cc
[pdf] Do not resolve named destinations in the backend
[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 void
1373 pdf_document_document_links_iface_init (EvDocumentLinksInterface *iface)
1374 {
1375         iface->has_document_links = pdf_document_links_has_document_links;
1376         iface->get_links_model = pdf_document_links_get_links_model;
1377         iface->get_links = pdf_document_links_get_links;
1378         iface->find_link_dest = pdf_document_links_find_link_dest;
1379 }
1380
1381 static EvMappingList *
1382 pdf_document_images_get_image_mapping (EvDocumentImages *document_images,
1383                                        EvPage           *page)
1384 {
1385         GList *retval = NULL;
1386         PdfDocument *pdf_document;
1387         PopplerPage *poppler_page;
1388         GList *mapping_list;
1389         GList *list;
1390
1391         pdf_document = PDF_DOCUMENT (document_images);
1392         poppler_page = POPPLER_PAGE (page->backend_page);
1393         mapping_list = poppler_page_get_image_mapping (poppler_page);
1394
1395         for (list = mapping_list; list; list = list->next) {
1396                 PopplerImageMapping *image_mapping;
1397                 EvMapping *ev_image_mapping;
1398
1399                 image_mapping = (PopplerImageMapping *)list->data;
1400
1401                 ev_image_mapping = g_new (EvMapping, 1);
1402                 
1403                 ev_image_mapping->data = ev_image_new (page->index, image_mapping->image_id);
1404                 ev_image_mapping->area.x1 = image_mapping->area.x1;
1405                 ev_image_mapping->area.y1 = image_mapping->area.y1;
1406                 ev_image_mapping->area.x2 = image_mapping->area.x2;
1407                 ev_image_mapping->area.y2 = image_mapping->area.y2;
1408
1409                 retval = g_list_prepend (retval, ev_image_mapping);
1410         }
1411
1412         poppler_page_free_image_mapping (mapping_list);
1413
1414         return ev_mapping_list_new (page->index, g_list_reverse (retval), (GDestroyNotify)g_object_unref);
1415 }
1416
1417 GdkPixbuf *
1418 pdf_document_images_get_image (EvDocumentImages *document_images,
1419                                EvImage          *image)
1420 {
1421         GdkPixbuf       *retval = NULL;
1422         PdfDocument     *pdf_document;
1423         PopplerPage     *poppler_page;
1424         cairo_surface_t *surface;
1425
1426         pdf_document = PDF_DOCUMENT (document_images);
1427         poppler_page = poppler_document_get_page (pdf_document->document,
1428                                                   ev_image_get_page (image));
1429
1430         surface = poppler_page_get_image (poppler_page, ev_image_get_id (image));
1431         if (surface) {
1432                 retval = ev_document_misc_pixbuf_from_surface (surface);
1433                 cairo_surface_destroy (surface);
1434         }
1435
1436         g_object_unref (poppler_page);
1437
1438         return retval;
1439 }
1440
1441 static void
1442 pdf_document_document_images_iface_init (EvDocumentImagesInterface *iface)
1443 {
1444         iface->get_image_mapping = pdf_document_images_get_image_mapping;
1445         iface->get_image = pdf_document_images_get_image;
1446 }
1447
1448 static GList *
1449 pdf_document_find_find_text (EvDocumentFind *document_find,
1450                              EvPage         *page,
1451                              const gchar    *text,
1452                              gboolean        case_sensitive)
1453 {
1454         GList *matches, *l;
1455         PopplerPage *poppler_page;
1456         gdouble height;
1457         GList *retval = NULL;
1458
1459         g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
1460         g_return_val_if_fail (text != NULL, NULL);
1461
1462         poppler_page = POPPLER_PAGE (page->backend_page);
1463         
1464         matches = poppler_page_find_text (poppler_page, text);
1465         if (!matches)
1466                 return NULL;
1467
1468         poppler_page_get_size (poppler_page, NULL, &height);
1469         for (l = matches; l && l->data; l = g_list_next (l)) {
1470                 PopplerRectangle *rect = (PopplerRectangle *)l->data;
1471                 EvRectangle      *ev_rect;
1472
1473                 ev_rect = ev_rectangle_new ();
1474                 ev_rect->x1 = rect->x1;
1475                 ev_rect->x2 = rect->x2;
1476                 /* Invert this for X-style coordinates */
1477                 ev_rect->y1 = height - rect->y2;
1478                 ev_rect->y2 = height - rect->y1;
1479
1480                 retval = g_list_prepend (retval, ev_rect);
1481         }
1482
1483         g_list_foreach (matches, (GFunc)poppler_rectangle_free, NULL);
1484         g_list_free (matches);
1485
1486         return g_list_reverse (retval);
1487 }
1488
1489 static void
1490 pdf_document_find_iface_init (EvDocumentFindInterface *iface)
1491 {
1492         iface->find_text = pdf_document_find_find_text;
1493 }
1494
1495 static void
1496 pdf_print_context_free (PdfPrintContext *ctx)
1497 {
1498         if (!ctx)
1499                 return;
1500
1501 #ifdef HAVE_CAIRO_PRINT
1502         if (ctx->cr) {
1503                 cairo_destroy (ctx->cr);
1504                 ctx->cr = NULL;
1505         }
1506 #else
1507         if (ctx->ps_file) {
1508                 poppler_ps_file_free (ctx->ps_file);
1509                 ctx->ps_file = NULL;
1510         }
1511 #endif
1512         g_free (ctx);
1513 }
1514
1515 static void
1516 pdf_document_file_exporter_begin (EvFileExporter        *exporter,
1517                                   EvFileExporterContext *fc)
1518 {
1519         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1520         PdfPrintContext *ctx;
1521 #ifdef HAVE_CAIRO_PRINT
1522         gdouble width, height;
1523         cairo_surface_t *surface = NULL;
1524 #endif
1525         
1526         if (pdf_document->print_ctx)
1527                 pdf_print_context_free (pdf_document->print_ctx);
1528         pdf_document->print_ctx = g_new0 (PdfPrintContext, 1);
1529         ctx = pdf_document->print_ctx;
1530         ctx->format = fc->format;
1531         
1532 #ifdef HAVE_CAIRO_PRINT
1533         ctx->pages_per_sheet = CLAMP (fc->pages_per_sheet, 1, 16);
1534
1535         ctx->paper_width = fc->paper_width;
1536         ctx->paper_height = fc->paper_height;
1537         
1538         switch (fc->pages_per_sheet) {
1539                 default:
1540                 case 1:
1541                         ctx->pages_x = 1;
1542                         ctx->pages_y = 1;
1543                         break;
1544                 case 2:
1545                         ctx->pages_x = 1;
1546                         ctx->pages_y = 2;
1547                         break;
1548                 case 4:
1549                         ctx->pages_x = 2;
1550                         ctx->pages_y = 2;
1551                         break;
1552                 case 6:
1553                         ctx->pages_x = 2;
1554                         ctx->pages_y = 3;
1555                         break;
1556                 case 9:
1557                         ctx->pages_x = 3;
1558                         ctx->pages_y = 3;
1559                         break;
1560                 case 16:
1561                         ctx->pages_x = 4;
1562                         ctx->pages_y = 4;
1563                         break;
1564         }
1565
1566         ctx->pages_printed = 0;
1567         
1568         switch (fc->format) {
1569                 case EV_FILE_FORMAT_PS:
1570 #ifdef HAVE_CAIRO_PS
1571                         surface = cairo_ps_surface_create (fc->filename, fc->paper_width, fc->paper_height);
1572 #endif
1573                         break;
1574                 case EV_FILE_FORMAT_PDF:
1575 #ifdef HAVE_CAIRO_PDF
1576                         surface = cairo_pdf_surface_create (fc->filename, fc->paper_width, fc->paper_height);
1577 #endif
1578                         break;
1579                 default:
1580                         g_assert_not_reached ();
1581         }
1582
1583         ctx->cr = cairo_create (surface);
1584         cairo_surface_destroy (surface);
1585
1586 #else /* HAVE_CAIRO_PRINT */
1587         if (ctx->format == EV_FILE_FORMAT_PS) {
1588                 ctx->ps_file = poppler_ps_file_new (pdf_document->document,
1589                                                     fc->filename, fc->first_page,
1590                                                     fc->last_page - fc->first_page + 1);
1591                 poppler_ps_file_set_paper_size (ctx->ps_file, fc->paper_width, fc->paper_height);
1592                 poppler_ps_file_set_duplex (ctx->ps_file, fc->duplex);
1593         }
1594 #endif /* HAVE_CAIRO_PRINT */
1595 }
1596
1597 static void
1598 pdf_document_file_exporter_begin_page (EvFileExporter *exporter)
1599 {
1600         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1601         PdfPrintContext *ctx = pdf_document->print_ctx;
1602         
1603         g_return_if_fail (pdf_document->print_ctx != NULL);
1604
1605         ctx->pages_printed = 0;
1606         
1607 #ifdef HAVE_CAIRO_PRINT
1608         if (ctx->paper_width > ctx->paper_height) {
1609                 if (ctx->format == EV_FILE_FORMAT_PS) {
1610                         cairo_ps_surface_set_size (cairo_get_target (ctx->cr),
1611                                                    ctx->paper_height,
1612                                                    ctx->paper_width);
1613                 } else if (ctx->format == EV_FILE_FORMAT_PDF) {
1614                         cairo_pdf_surface_set_size (cairo_get_target (ctx->cr),
1615                                                     ctx->paper_height,
1616                                                     ctx->paper_width);
1617                 }
1618         }
1619 #endif /* HAVE_CAIRO_PRINT */
1620 }
1621
1622 static void
1623 pdf_document_file_exporter_do_page (EvFileExporter  *exporter,
1624                                     EvRenderContext *rc)
1625 {
1626         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1627         PdfPrintContext *ctx = pdf_document->print_ctx;
1628         PopplerPage *poppler_page;
1629 #ifdef HAVE_CAIRO_PRINT
1630         gdouble  page_width, page_height;
1631         gint     x, y;
1632         gboolean rotate;
1633         gdouble  width, height;
1634         gdouble  pwidth, pheight;
1635         gdouble  xscale, yscale;
1636 #endif
1637
1638         g_return_if_fail (pdf_document->print_ctx != NULL);
1639
1640         poppler_page = POPPLER_PAGE (rc->page->backend_page);
1641         
1642 #ifdef HAVE_CAIRO_PRINT
1643         x = (ctx->pages_printed % ctx->pages_per_sheet) % ctx->pages_x;
1644         y = (ctx->pages_printed % ctx->pages_per_sheet) / ctx->pages_x;
1645         poppler_page_get_size (poppler_page, &page_width, &page_height);
1646
1647         if (page_width > page_height && page_width > ctx->paper_width) {
1648                 rotate = TRUE;
1649         } else {
1650                 rotate = FALSE;
1651         }
1652
1653         /* Use always portrait mode and rotate when necessary */
1654         if (ctx->paper_width > ctx->paper_height) {
1655                 width = ctx->paper_height;
1656                 height = ctx->paper_width;
1657                 rotate = !rotate;
1658         } else {
1659                 width = ctx->paper_width;
1660                 height = ctx->paper_height;
1661         }
1662
1663         if (ctx->pages_per_sheet == 2 || ctx->pages_per_sheet == 6) {
1664                 rotate = !rotate;
1665         }       
1666
1667         if (rotate) {
1668                 gint tmp1;
1669                 gdouble tmp2;
1670
1671                 tmp1 = x;
1672                 x = y;
1673                 y = tmp1;
1674
1675                 tmp2 = page_width;
1676                 page_width = page_height;
1677                 page_height = tmp2;
1678         }
1679
1680         pwidth = width / ctx->pages_x;
1681         pheight = height / ctx->pages_y;
1682
1683         if ((page_width > pwidth || page_height > pheight) ||
1684             (page_width < pwidth && page_height < pheight)) {
1685                 xscale = pwidth / page_width;
1686                 yscale = pheight / page_height;
1687                 
1688                 if (yscale < xscale) {
1689                         xscale = yscale;
1690                 } else {
1691                         yscale = xscale;
1692                 }
1693                 
1694         } else {        
1695                 xscale = yscale = 1;
1696         }
1697
1698         /* TODO: center */
1699
1700         cairo_save (ctx->cr);
1701         if (rotate) {
1702                 cairo_matrix_t matrix;
1703                 
1704                 cairo_translate (ctx->cr, (2 * y + 1) * pwidth, 0);
1705                 cairo_matrix_init (&matrix,
1706                                    0,  1,
1707                                    -1,  0,
1708                                    0,  0);
1709                 cairo_transform (ctx->cr, &matrix);
1710         }
1711         
1712         cairo_translate (ctx->cr,
1713                          x * (rotate ? pheight : pwidth),
1714                          y * (rotate ? pwidth : pheight));
1715         cairo_scale (ctx->cr, xscale, yscale);
1716
1717         poppler_page_render_for_printing (poppler_page, ctx->cr);
1718
1719         ctx->pages_printed++;
1720                         
1721         cairo_restore (ctx->cr);
1722 #else /* HAVE_CAIRO_PRINT */
1723         if (ctx->format == EV_FILE_FORMAT_PS)
1724                 poppler_page_render_to_ps (poppler_page, ctx->ps_file);
1725 #endif /* HAVE_CAIRO_PRINT */
1726 }
1727
1728 static void
1729 pdf_document_file_exporter_end_page (EvFileExporter *exporter)
1730 {
1731         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1732         PdfPrintContext *ctx = pdf_document->print_ctx;
1733         
1734         g_return_if_fail (pdf_document->print_ctx != NULL);
1735
1736 #ifdef HAVE_CAIRO_PRINT
1737         cairo_show_page (ctx->cr);
1738 #endif
1739 }
1740
1741 static void
1742 pdf_document_file_exporter_end (EvFileExporter *exporter)
1743 {
1744         PdfDocument *pdf_document = PDF_DOCUMENT (exporter);
1745
1746         pdf_print_context_free (pdf_document->print_ctx);
1747         pdf_document->print_ctx = NULL;
1748 }
1749
1750 static EvFileExporterCapabilities
1751 pdf_document_file_exporter_get_capabilities (EvFileExporter *exporter)
1752 {
1753         return  (EvFileExporterCapabilities) (
1754                 EV_FILE_EXPORTER_CAN_PAGE_SET |
1755                 EV_FILE_EXPORTER_CAN_COPIES |
1756                 EV_FILE_EXPORTER_CAN_COLLATE |
1757                 EV_FILE_EXPORTER_CAN_REVERSE |
1758                 EV_FILE_EXPORTER_CAN_SCALE |
1759 #ifdef HAVE_CAIRO_PRINT
1760                 EV_FILE_EXPORTER_CAN_NUMBER_UP |
1761 #endif
1762                 
1763 #ifdef HAVE_CAIRO_PDF
1764                 EV_FILE_EXPORTER_CAN_GENERATE_PDF |
1765 #endif
1766                 EV_FILE_EXPORTER_CAN_GENERATE_PS);
1767 }
1768
1769 static void
1770 pdf_document_file_exporter_iface_init (EvFileExporterInterface *iface)
1771 {
1772         iface->begin = pdf_document_file_exporter_begin;
1773         iface->begin_page = pdf_document_file_exporter_begin_page;
1774         iface->do_page = pdf_document_file_exporter_do_page;
1775         iface->end_page = pdf_document_file_exporter_end_page;
1776         iface->end = pdf_document_file_exporter_end;
1777         iface->get_capabilities = pdf_document_file_exporter_get_capabilities;
1778 }
1779
1780 /* EvDocumentPrint */
1781 static void
1782 pdf_document_print_print_page (EvDocumentPrint *document,
1783                                EvPage          *page,
1784                                cairo_t         *cr)
1785 {
1786         PdfDocument *pdf_document = PDF_DOCUMENT (document);
1787
1788         poppler_page_render_for_printing (POPPLER_PAGE (page->backend_page), cr);
1789 }
1790
1791 static void
1792 pdf_document_document_print_iface_init (EvDocumentPrintInterface *iface)
1793 {
1794         iface->print_page = pdf_document_print_print_page;
1795 }
1796
1797 static void
1798 pdf_selection_render_selection (EvSelection      *selection,
1799                                 EvRenderContext  *rc,
1800                                 cairo_surface_t **surface,
1801                                 EvRectangle      *points,
1802                                 EvRectangle      *old_points,
1803                                 EvSelectionStyle  style,
1804                                 GdkColor         *text,
1805                                 GdkColor         *base)
1806 {
1807         PopplerPage *poppler_page;
1808         cairo_t *cr;
1809         PopplerColor text_color, base_color;
1810         double width_points, height_points;
1811         gint width, height;
1812
1813         poppler_page = POPPLER_PAGE (rc->page->backend_page);
1814
1815         poppler_page_get_size (poppler_page,
1816                                &width_points, &height_points);
1817         width = (int) ((width_points * rc->scale) + 0.5);
1818         height = (int) ((height_points * rc->scale) + 0.5);
1819
1820         text_color.red = text->red;
1821         text_color.green = text->green;
1822         text_color.blue = text->blue;
1823
1824         base_color.red = base->red;
1825         base_color.green = base->green;
1826         base_color.blue = base->blue;
1827
1828         if (*surface == NULL) {
1829                 *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
1830                                                        width, height);
1831                 
1832         }
1833
1834         cr = cairo_create (*surface);
1835         cairo_scale (cr, rc->scale, rc->scale);
1836         cairo_surface_set_device_offset (*surface, 0, 0);
1837         memset (cairo_image_surface_get_data (*surface), 0x00,
1838                 cairo_image_surface_get_height (*surface) *
1839                 cairo_image_surface_get_stride (*surface));
1840         poppler_page_render_selection (poppler_page,
1841                                        cr,
1842                                        (PopplerRectangle *)points,
1843                                        (PopplerRectangle *)old_points,
1844                                        (PopplerSelectionStyle)style,
1845                                        &text_color,
1846                                        &base_color);
1847         cairo_destroy (cr);
1848 }
1849
1850 static gchar *
1851 pdf_selection_get_selected_text (EvSelection     *selection,
1852                                  EvPage          *page,
1853                                  EvSelectionStyle style,
1854                                  EvRectangle     *points)
1855 {
1856         PopplerPage *poppler_page;
1857         char *retval;
1858
1859         poppler_page = POPPLER_PAGE (page->backend_page);
1860
1861 #ifdef HAVE_POPPLER_PAGE_GET_SELECTED_TEXT
1862         retval = poppler_page_get_selected_text (poppler_page,
1863                                                  (PopplerSelectionStyle)style,
1864                                                  (PopplerRectangle *)points);
1865 #else
1866         PopplerRectangle r;
1867         double height;
1868
1869         poppler_page_get_size (poppler_page, NULL, &height);
1870         r.x1 = points->x1;
1871         r.y1 = height - points->y2;
1872         r.x2 = points->x2;
1873         r.y2 = height - points->y1;
1874
1875         retval = poppler_page_get_text (poppler_page,
1876                                         (PopplerSelectionStyle)style,
1877                                         &r);
1878 #endif /* HAVE_POPPLER_PAGE_GET_SELECTED_TEXT */
1879
1880         return retval;
1881 }
1882
1883 static cairo_region_t *
1884 create_region_from_poppler_region (GList *region, gdouble scale)
1885 {
1886         GList *l;
1887         cairo_region_t *retval;
1888
1889         retval = cairo_region_create ();
1890
1891         for (l = region; l; l = g_list_next (l)) {
1892                 PopplerRectangle   *rectangle;
1893                 cairo_rectangle_int_t rect;
1894
1895                 rectangle = (PopplerRectangle *)l->data;
1896
1897                 rect.x = (gint) ((rectangle->x1 * scale) + 0.5);
1898                 rect.y = (gint) ((rectangle->y1 * scale) + 0.5);
1899                 rect.width  = (gint) (((rectangle->x2 - rectangle->x1) * scale) + 0.5);
1900                 rect.height = (gint) (((rectangle->y2 - rectangle->y1) * scale) + 0.5);
1901                 cairo_region_union_rectangle (retval, &rect);
1902
1903                 poppler_rectangle_free (rectangle);
1904         }
1905
1906         return retval;
1907 }
1908
1909 static cairo_region_t *
1910 pdf_selection_get_selection_region (EvSelection     *selection,
1911                                     EvRenderContext *rc,
1912                                     EvSelectionStyle style,
1913                                     EvRectangle     *points)
1914 {
1915         PopplerPage    *poppler_page;
1916         cairo_region_t *retval;
1917         GList          *region;
1918
1919         poppler_page = POPPLER_PAGE (rc->page->backend_page);
1920         region = poppler_page_get_selection_region (poppler_page,
1921                                                     1.0,
1922                                                     (PopplerSelectionStyle)style,
1923                                                     (PopplerRectangle *) points);
1924         retval = create_region_from_poppler_region (region, rc->scale);
1925         g_list_free (region);
1926         
1927         return retval;
1928 }
1929
1930 static void
1931 pdf_selection_iface_init (EvSelectionInterface *iface)
1932 {
1933         iface->render_selection = pdf_selection_render_selection;
1934         iface->get_selected_text = pdf_selection_get_selected_text;
1935         iface->get_selection_region = pdf_selection_get_selection_region;
1936 }
1937
1938
1939 /* EvDocumentText */
1940 static cairo_region_t *
1941 pdf_document_text_get_text_mapping (EvDocumentText *document_text,
1942                                     EvPage         *page)
1943 {
1944         PopplerPage *poppler_page;
1945         PopplerRectangle points;
1946         GList *region;
1947         cairo_region_t *retval;
1948
1949         g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
1950
1951         poppler_page = POPPLER_PAGE (page->backend_page);
1952
1953         points.x1 = 0.0;
1954         points.y1 = 0.0;
1955         poppler_page_get_size (poppler_page, &(points.x2), &(points.y2));
1956
1957         region = poppler_page_get_selection_region (poppler_page, 1.0,
1958                                                     POPPLER_SELECTION_GLYPH,
1959                                                     &points);
1960         retval = create_region_from_poppler_region (region, 1.0);
1961         g_list_free (region);
1962
1963         return retval;
1964 }
1965
1966 #ifdef HAVE_POPPLER_PAGE_GET_SELECTED_TEXT
1967 static gchar *
1968 pdf_document_text_get_text (EvDocumentText  *selection,
1969                             EvPage          *page)
1970 {
1971         PopplerPage *poppler_page;
1972
1973         g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
1974
1975         poppler_page = POPPLER_PAGE (page->backend_page);
1976
1977         return poppler_page_get_text (poppler_page);
1978 }
1979 #else
1980 static gchar *
1981 pdf_document_text_get_text (EvDocumentText  *selection,
1982                             EvPage          *page)
1983 {
1984         PopplerPage *poppler_page;
1985         PopplerRectangle r;
1986
1987         g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
1988
1989         poppler_page = POPPLER_PAGE (page->backend_page);
1990
1991         r.x1 = 0;
1992         r.y1 = 0;
1993         poppler_page_get_size (poppler_page, &(r.x2), &(r.y2));
1994
1995         return poppler_page_get_text (poppler_page,
1996                                       POPPLER_SELECTION_WORD,
1997                                       &r);
1998 }
1999 #endif /* HAVE_POPPLER_PAGE_GET_SELECTED_TEXT */
2000
2001 #ifdef HAVE_POPPLER_PAGE_GET_TEXT_LAYOUT
2002 static gboolean
2003 pdf_document_text_get_text_layout (EvDocumentText  *selection,
2004                                    EvPage          *page,
2005                                    EvRectangle    **areas,
2006                                    guint           *n_areas)
2007 {
2008         PopplerPage *poppler_page;
2009
2010         g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
2011
2012         poppler_page = POPPLER_PAGE (page->backend_page);
2013
2014         return poppler_page_get_text_layout (poppler_page, (PopplerRectangle **)areas, n_areas);
2015 }
2016 #endif
2017
2018 static void
2019 pdf_document_text_iface_init (EvDocumentTextInterface *iface)
2020 {
2021         iface->get_text_mapping = pdf_document_text_get_text_mapping;
2022         iface->get_text = pdf_document_text_get_text;
2023 #ifdef HAVE_POPPLER_PAGE_GET_TEXT_LAYOUT
2024         iface->get_text_layout = pdf_document_text_get_text_layout;
2025 #endif
2026 }
2027
2028 /* Page Transitions */
2029 static gdouble
2030 pdf_document_get_page_duration (EvDocumentTransition *trans,
2031                                 gint                  page)
2032 {
2033         PdfDocument *pdf_document;
2034         PopplerPage *poppler_page;
2035         gdouble      duration = -1;
2036
2037         pdf_document = PDF_DOCUMENT (trans);
2038         poppler_page = poppler_document_get_page (pdf_document->document, page);
2039         if (!poppler_page)
2040                 return -1;
2041
2042         duration = poppler_page_get_duration (poppler_page);
2043         g_object_unref (poppler_page);
2044
2045         return duration;
2046 }
2047
2048 static EvTransitionEffect *
2049 pdf_document_get_effect (EvDocumentTransition *trans,
2050                          gint                  page)
2051 {
2052         PdfDocument            *pdf_document;
2053         PopplerPage            *poppler_page;
2054         PopplerPageTransition  *page_transition;
2055         EvTransitionEffect     *effect;
2056
2057         pdf_document = PDF_DOCUMENT (trans);
2058         poppler_page = poppler_document_get_page (pdf_document->document, page);
2059
2060         if (!poppler_page)
2061                 return NULL;
2062
2063         page_transition = poppler_page_get_transition (poppler_page);
2064
2065         if (!page_transition) {
2066                 g_object_unref (poppler_page);
2067                 return NULL;
2068         }
2069
2070         /* enums in PopplerPageTransition match the EvTransitionEffect ones */
2071         effect = ev_transition_effect_new ((EvTransitionEffectType) page_transition->type,
2072                                            "alignment", page_transition->alignment,
2073                                            "direction", page_transition->direction,
2074                                            "duration", page_transition->duration,
2075                                            "angle", page_transition->angle,
2076                                            "scale", page_transition->scale,
2077                                            "rectangular", page_transition->rectangular,
2078                                            NULL);
2079
2080         poppler_page_transition_free (page_transition);
2081         g_object_unref (poppler_page);
2082
2083         return effect;
2084 }
2085
2086 static void
2087 pdf_document_page_transition_iface_init (EvDocumentTransitionInterface *iface)
2088 {
2089         iface->get_page_duration = pdf_document_get_page_duration;
2090         iface->get_effect = pdf_document_get_effect;
2091 }
2092
2093 /* Forms */
2094 static void
2095 pdf_document_get_crop_box (EvDocument  *document, 
2096                            int          page, 
2097                            EvRectangle *rect)
2098 {
2099         PdfDocument *pdf_document;
2100         PopplerPage *poppler_page;
2101         PopplerRectangle poppler_rect;
2102
2103         pdf_document = PDF_DOCUMENT (document);
2104         poppler_page = poppler_document_get_page (pdf_document->document, page);
2105         poppler_page_get_crop_box (poppler_page, &poppler_rect);
2106         rect->x1 = poppler_rect.x1;
2107         rect->x2 = poppler_rect.x2;
2108         rect->y1 = poppler_rect.y1;
2109         rect->y2 = poppler_rect.y2;
2110 }
2111
2112 static EvFormField *
2113 ev_form_field_from_poppler_field (PopplerFormField *poppler_field)
2114 {
2115         EvFormField *ev_field = NULL;
2116         gint         id;
2117         gdouble      font_size;
2118         gboolean     is_read_only;
2119
2120         id = poppler_form_field_get_id (poppler_field);
2121         font_size = poppler_form_field_get_font_size (poppler_field);
2122         is_read_only = poppler_form_field_is_read_only (poppler_field);
2123
2124         switch (poppler_form_field_get_field_type (poppler_field)) {
2125                 case POPPLER_FORM_FIELD_TEXT: {
2126                         EvFormFieldText    *field_text;
2127                         EvFormFieldTextType ev_text_type = EV_FORM_FIELD_TEXT_NORMAL;
2128
2129                         switch (poppler_form_field_text_get_text_type (poppler_field)) {
2130                                 case POPPLER_FORM_TEXT_NORMAL:
2131                                         ev_text_type = EV_FORM_FIELD_TEXT_NORMAL;
2132                                         break;
2133                                 case POPPLER_FORM_TEXT_MULTILINE:
2134                                         ev_text_type = EV_FORM_FIELD_TEXT_MULTILINE;
2135                                         break;
2136                                 case POPPLER_FORM_TEXT_FILE_SELECT:
2137                                         ev_text_type = EV_FORM_FIELD_TEXT_FILE_SELECT;
2138                                         break;
2139                         }
2140                         
2141                         ev_field = ev_form_field_text_new (id, ev_text_type);
2142                         field_text = EV_FORM_FIELD_TEXT (ev_field);
2143
2144                         field_text->do_spell_check = poppler_form_field_text_do_spell_check (poppler_field);
2145                         field_text->do_scroll = poppler_form_field_text_do_scroll (poppler_field);
2146                         field_text->is_rich_text = poppler_form_field_text_is_rich_text (poppler_field);
2147                         field_text->is_password = poppler_form_field_text_is_password (poppler_field);
2148                         field_text->max_len = poppler_form_field_text_get_max_len (poppler_field);
2149                         field_text->text = poppler_form_field_text_get_text (poppler_field);
2150
2151                 }
2152                         break;
2153                 case POPPLER_FORM_FIELD_BUTTON: {
2154                         EvFormFieldButton    *field_button;
2155                         EvFormFieldButtonType ev_button_type = EV_FORM_FIELD_BUTTON_PUSH;
2156
2157                         switch (poppler_form_field_button_get_button_type (poppler_field)) {
2158                                 case POPPLER_FORM_BUTTON_PUSH:
2159                                         ev_button_type = EV_FORM_FIELD_BUTTON_PUSH;
2160                                         break;
2161                                 case POPPLER_FORM_BUTTON_CHECK:
2162                                         ev_button_type = EV_FORM_FIELD_BUTTON_CHECK;
2163                                         break;
2164                                 case POPPLER_FORM_BUTTON_RADIO:
2165                                         ev_button_type = EV_FORM_FIELD_BUTTON_RADIO;
2166                                         break;
2167                         }
2168
2169                         ev_field = ev_form_field_button_new (id, ev_button_type);
2170                         field_button = EV_FORM_FIELD_BUTTON (ev_field);
2171                         
2172                         field_button->state = poppler_form_field_button_get_state (poppler_field);
2173                 }
2174                         break;
2175                 case POPPLER_FORM_FIELD_CHOICE: {
2176                         EvFormFieldChoice    *field_choice;
2177                         EvFormFieldChoiceType ev_choice_type = EV_FORM_FIELD_CHOICE_COMBO;
2178
2179                         switch (poppler_form_field_choice_get_choice_type (poppler_field)) {
2180                                 case POPPLER_FORM_CHOICE_COMBO:
2181                                         ev_choice_type = EV_FORM_FIELD_CHOICE_COMBO;
2182                                         break;
2183                                 case EV_FORM_FIELD_CHOICE_LIST:
2184                                         ev_choice_type = EV_FORM_FIELD_CHOICE_LIST;
2185                                         break;
2186                         }
2187
2188                         ev_field = ev_form_field_choice_new (id, ev_choice_type);
2189                         field_choice = EV_FORM_FIELD_CHOICE (ev_field);
2190
2191                         field_choice->is_editable = poppler_form_field_choice_is_editable (poppler_field);
2192                         field_choice->multi_select = poppler_form_field_choice_can_select_multiple (poppler_field);
2193                         field_choice->do_spell_check = poppler_form_field_choice_do_spell_check (poppler_field);
2194                         field_choice->commit_on_sel_change = poppler_form_field_choice_commit_on_change (poppler_field);
2195
2196                         /* TODO: we need poppler_form_field_choice_get_selected_items in poppler 
2197                         field_choice->selected_items = poppler_form_field_choice_get_selected_items (poppler_field);*/
2198                         if (field_choice->is_editable)
2199                                 field_choice->text = poppler_form_field_choice_get_text (poppler_field);
2200                 }
2201                         break;
2202                 case POPPLER_FORM_FIELD_SIGNATURE:
2203                         /* TODO */
2204                         ev_field = ev_form_field_signature_new (id);
2205                         break;
2206                 case POPPLER_FORM_FIELD_UNKNOWN:
2207                         return NULL;
2208         }
2209
2210         ev_field->font_size = font_size;
2211         ev_field->is_read_only = is_read_only;
2212
2213         return ev_field;
2214 }
2215
2216 static EvMappingList *
2217 pdf_document_forms_get_form_fields (EvDocumentForms *document, 
2218                                     EvPage          *page)
2219 {
2220         PopplerPage *poppler_page;
2221         GList *retval = NULL;
2222         GList *fields;
2223         GList *list;
2224         double height;
2225
2226         g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
2227         
2228         poppler_page = POPPLER_PAGE (page->backend_page);
2229         fields = poppler_page_get_form_field_mapping (poppler_page);
2230         poppler_page_get_size (poppler_page, NULL, &height);
2231
2232         for (list = fields; list; list = list->next) {
2233                 PopplerFormFieldMapping *mapping;
2234                 EvMapping *field_mapping;
2235                 EvFormField *ev_field;
2236
2237                 mapping = (PopplerFormFieldMapping *)list->data;
2238
2239                 ev_field = ev_form_field_from_poppler_field (mapping->field);
2240                 if (!ev_field)
2241                         continue;
2242
2243                 field_mapping = g_new0 (EvMapping, 1);
2244                 field_mapping->area.x1 = mapping->area.x1;
2245                 field_mapping->area.x2 = mapping->area.x2;
2246                 field_mapping->area.y1 = height - mapping->area.y2;
2247                 field_mapping->area.y2 = height - mapping->area.y1;
2248                 field_mapping->data = ev_field;
2249                 ev_field->page = EV_PAGE (g_object_ref (page));
2250
2251                 g_object_set_data_full (G_OBJECT (ev_field),
2252                                         "poppler-field",
2253                                         g_object_ref (mapping->field),
2254                                         (GDestroyNotify) g_object_unref);
2255                 
2256                 retval = g_list_prepend (retval, field_mapping);
2257         }
2258         
2259         poppler_page_free_form_field_mapping (fields);
2260
2261         return retval ? ev_mapping_list_new (page->index,
2262                                              g_list_reverse (retval),
2263                                              (GDestroyNotify)g_object_unref) : NULL;
2264 }
2265
2266 static gboolean
2267 pdf_document_forms_document_is_modified (EvDocumentForms *document)
2268 {
2269         return PDF_DOCUMENT (document)->forms_modified;
2270 }
2271
2272 static gchar *
2273 pdf_document_forms_form_field_text_get_text (EvDocumentForms *document,
2274                                              EvFormField     *field)
2275         
2276 {
2277         PopplerFormField *poppler_field;
2278         gchar *text;
2279
2280         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2281         if (!poppler_field)
2282                 return NULL;
2283         
2284         text = poppler_form_field_text_get_text (poppler_field);
2285
2286         return text;
2287 }
2288
2289 static void
2290 pdf_document_forms_form_field_text_set_text (EvDocumentForms *document, 
2291                                              EvFormField     *field,
2292                                              const gchar     *text)
2293 {
2294         PopplerFormField *poppler_field;
2295
2296         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2297         if (!poppler_field)
2298                 return;
2299         
2300         poppler_form_field_text_set_text (poppler_field, text);
2301         PDF_DOCUMENT (document)->forms_modified = TRUE;
2302 }
2303
2304 static void
2305 pdf_document_forms_form_field_button_set_state (EvDocumentForms *document, 
2306                                                 EvFormField     *field,
2307                                                 gboolean         state)
2308 {
2309         PopplerFormField *poppler_field;
2310
2311         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2312         if (!poppler_field)
2313                 return;
2314         
2315         poppler_form_field_button_set_state (poppler_field, state);
2316         PDF_DOCUMENT (document)->forms_modified = TRUE;
2317 }
2318
2319 static gboolean
2320 pdf_document_forms_form_field_button_get_state (EvDocumentForms *document, 
2321                                                 EvFormField     *field)
2322 {
2323         PopplerFormField *poppler_field;
2324         gboolean state;
2325
2326         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2327         if (!poppler_field)
2328                 return FALSE;
2329
2330         state = poppler_form_field_button_get_state (poppler_field);
2331
2332         return state;
2333 }
2334
2335 static gchar *
2336 pdf_document_forms_form_field_choice_get_item (EvDocumentForms *document, 
2337                                                EvFormField     *field,
2338                                                gint             index)
2339 {
2340         PopplerFormField *poppler_field;
2341         gchar *text;
2342
2343         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2344         if (!poppler_field)
2345                 return NULL;
2346
2347         text = poppler_form_field_choice_get_item (poppler_field, index);
2348
2349         return text;
2350 }
2351
2352 static int
2353 pdf_document_forms_form_field_choice_get_n_items (EvDocumentForms *document, 
2354                                                   EvFormField     *field)
2355 {
2356         PopplerFormField *poppler_field;
2357         gint n_items;
2358
2359         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2360         if (!poppler_field)
2361                 return -1;
2362         
2363         n_items = poppler_form_field_choice_get_n_items (poppler_field);
2364
2365         return n_items;
2366 }
2367
2368 static gboolean
2369 pdf_document_forms_form_field_choice_is_item_selected (EvDocumentForms *document, 
2370                                                        EvFormField     *field,
2371                                                        gint             index)
2372 {
2373         PopplerFormField *poppler_field;
2374         gboolean selected;
2375
2376         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2377         if (!poppler_field)
2378                 return FALSE;
2379
2380         selected = poppler_form_field_choice_is_item_selected (poppler_field, index);
2381
2382         return selected;
2383 }
2384
2385 static void
2386 pdf_document_forms_form_field_choice_select_item (EvDocumentForms *document, 
2387                                                   EvFormField     *field,
2388                                                   gint             index)
2389 {
2390         PopplerFormField *poppler_field;
2391
2392         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2393         if (!poppler_field)
2394                 return;
2395
2396         poppler_form_field_choice_select_item (poppler_field, index);
2397         PDF_DOCUMENT (document)->forms_modified = TRUE;
2398 }
2399
2400 static void
2401 pdf_document_forms_form_field_choice_toggle_item (EvDocumentForms *document, 
2402                                                   EvFormField     *field,
2403                                                   gint             index)
2404 {
2405         PopplerFormField *poppler_field;
2406
2407         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2408         if (!poppler_field)
2409                 return;
2410
2411         poppler_form_field_choice_toggle_item (poppler_field, index);
2412         PDF_DOCUMENT (document)->forms_modified = TRUE;
2413 }
2414
2415 static void
2416 pdf_document_forms_form_field_choice_unselect_all (EvDocumentForms *document, 
2417                                                    EvFormField     *field)
2418 {
2419         PopplerFormField *poppler_field;
2420
2421         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2422         if (!poppler_field)
2423                 return;
2424         
2425         poppler_form_field_choice_unselect_all (poppler_field);
2426         PDF_DOCUMENT (document)->forms_modified = TRUE;
2427 }
2428
2429 static void
2430 pdf_document_forms_form_field_choice_set_text (EvDocumentForms *document,
2431                                                EvFormField     *field,
2432                                                const gchar     *text)
2433 {
2434         PopplerFormField *poppler_field;
2435
2436         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2437         if (!poppler_field)
2438                 return;
2439         
2440         poppler_form_field_choice_set_text (poppler_field, text);
2441         PDF_DOCUMENT (document)->forms_modified = TRUE;
2442 }
2443
2444 static gchar *
2445 pdf_document_forms_form_field_choice_get_text (EvDocumentForms *document,
2446                                                EvFormField     *field)
2447 {
2448         PopplerFormField *poppler_field;
2449         gchar *text;
2450
2451         poppler_field = POPPLER_FORM_FIELD (g_object_get_data (G_OBJECT (field), "poppler-field"));
2452         if (!poppler_field)
2453                 return NULL;
2454
2455         text = poppler_form_field_choice_get_text (poppler_field);
2456
2457         return text;
2458 }
2459
2460 static void
2461 pdf_document_document_forms_iface_init (EvDocumentFormsInterface *iface)
2462 {
2463         iface->get_form_fields = pdf_document_forms_get_form_fields;
2464         iface->document_is_modified = pdf_document_forms_document_is_modified;
2465         iface->form_field_text_get_text = pdf_document_forms_form_field_text_get_text;
2466         iface->form_field_text_set_text = pdf_document_forms_form_field_text_set_text;
2467         iface->form_field_button_set_state = pdf_document_forms_form_field_button_set_state;
2468         iface->form_field_button_get_state = pdf_document_forms_form_field_button_get_state;
2469         iface->form_field_choice_get_item = pdf_document_forms_form_field_choice_get_item;
2470         iface->form_field_choice_get_n_items = pdf_document_forms_form_field_choice_get_n_items;
2471         iface->form_field_choice_is_item_selected = pdf_document_forms_form_field_choice_is_item_selected;
2472         iface->form_field_choice_select_item = pdf_document_forms_form_field_choice_select_item;
2473         iface->form_field_choice_toggle_item = pdf_document_forms_form_field_choice_toggle_item;
2474         iface->form_field_choice_unselect_all = pdf_document_forms_form_field_choice_unselect_all;
2475         iface->form_field_choice_set_text = pdf_document_forms_form_field_choice_set_text;
2476         iface->form_field_choice_get_text = pdf_document_forms_form_field_choice_get_text;
2477 }
2478
2479 /* Annotations */
2480 static void
2481 poppler_annot_color_to_gdk_color (PopplerAnnot *poppler_annot,
2482                                   GdkColor     *color)
2483 {
2484         PopplerColor *poppler_color;
2485
2486         poppler_color = poppler_annot_get_color (poppler_annot);
2487         if (poppler_color) {
2488                 color->red = poppler_color->red;
2489                 color->green = poppler_color->green;
2490                 color->blue = poppler_color->blue;
2491
2492                 g_free (poppler_color);
2493         } /* TODO: else use a default color */
2494 }
2495
2496 static EvAnnotationTextIcon
2497 get_annot_text_icon (PopplerAnnotText *poppler_annot)
2498 {
2499 #ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
2500         gchar *icon = poppler_annot_text_get_icon (poppler_annot);
2501         EvAnnotationTextIcon retval;
2502
2503         if (!icon)
2504                 return EV_ANNOTATION_TEXT_ICON_UNKNOWN;
2505
2506         if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_NOTE) == 0)
2507                 retval = EV_ANNOTATION_TEXT_ICON_NOTE;
2508         else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_COMMENT) == 0)
2509                 retval = EV_ANNOTATION_TEXT_ICON_COMMENT;
2510         else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_KEY) == 0)
2511                 retval = EV_ANNOTATION_TEXT_ICON_KEY;
2512         else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_HELP) == 0)
2513                 retval = EV_ANNOTATION_TEXT_ICON_HELP;
2514         else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_NEW_PARAGRAPH) == 0)
2515                 retval = EV_ANNOTATION_TEXT_ICON_NEW_PARAGRAPH;
2516         else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_PARAGRAPH) == 0)
2517                 retval = EV_ANNOTATION_TEXT_ICON_PARAGRAPH;
2518         else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_INSERT) == 0)
2519                 retval = EV_ANNOTATION_TEXT_ICON_INSERT;
2520         else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_CROSS) == 0)
2521                 retval = EV_ANNOTATION_TEXT_ICON_CROSS;
2522         else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_CIRCLE) == 0)
2523                 retval = EV_ANNOTATION_TEXT_ICON_CIRCLE;
2524         else
2525                 retval = EV_ANNOTATION_TEXT_ICON_UNKNOWN;
2526
2527         g_free (icon);
2528
2529         return retval;
2530 #else
2531         return EV_ANNOTATION_TEXT_ICON_UNKNOWN;
2532 #endif
2533 }
2534
2535 static const gchar *
2536 get_poppler_annot_text_icon (EvAnnotationTextIcon icon)
2537 {
2538 #ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
2539         switch (icon) {
2540         case EV_ANNOTATION_TEXT_ICON_NOTE:
2541                 return POPPLER_ANNOT_TEXT_ICON_NOTE;
2542         case EV_ANNOTATION_TEXT_ICON_COMMENT:
2543                 return POPPLER_ANNOT_TEXT_ICON_COMMENT;
2544         case EV_ANNOTATION_TEXT_ICON_KEY:
2545                 return POPPLER_ANNOT_TEXT_ICON_KEY;
2546         case EV_ANNOTATION_TEXT_ICON_HELP:
2547                 return POPPLER_ANNOT_TEXT_ICON_HELP;
2548         case EV_ANNOTATION_TEXT_ICON_NEW_PARAGRAPH:
2549                 return POPPLER_ANNOT_TEXT_ICON_NEW_PARAGRAPH;
2550         case EV_ANNOTATION_TEXT_ICON_PARAGRAPH:
2551                 return POPPLER_ANNOT_TEXT_ICON_PARAGRAPH;
2552         case EV_ANNOTATION_TEXT_ICON_INSERT:
2553                 return POPPLER_ANNOT_TEXT_ICON_INSERT;
2554         case EV_ANNOTATION_TEXT_ICON_CROSS:
2555                 return POPPLER_ANNOT_TEXT_ICON_CROSS;
2556         case EV_ANNOTATION_TEXT_ICON_CIRCLE:
2557                 return POPPLER_ANNOT_TEXT_ICON_CIRCLE;
2558         case EV_ANNOTATION_TEXT_ICON_UNKNOWN:
2559         default:
2560                 return POPPLER_ANNOT_TEXT_ICON_NOTE;
2561         }
2562 #else
2563         return "Note";
2564 #endif
2565 }
2566
2567 static EvAnnotation *
2568 ev_annot_from_poppler_annot (PopplerAnnot *poppler_annot,
2569                              EvPage       *page)
2570 {
2571         EvAnnotation *ev_annot = NULL;
2572         const gchar  *unimplemented_annot = NULL;
2573
2574         switch (poppler_annot_get_annot_type (poppler_annot)) {
2575                 case POPPLER_ANNOT_TEXT: {
2576                         PopplerAnnotText *poppler_text;
2577                         EvAnnotationText *ev_annot_text;
2578
2579                         poppler_text = POPPLER_ANNOT_TEXT (poppler_annot);
2580
2581                         ev_annot = ev_annotation_text_new (page);
2582
2583                         ev_annot_text = EV_ANNOTATION_TEXT (ev_annot);
2584                         ev_annotation_text_set_is_open (ev_annot_text,
2585                                                         poppler_annot_text_get_is_open (poppler_text));
2586                         ev_annotation_text_set_icon (ev_annot_text, get_annot_text_icon (poppler_text));
2587                 }
2588                         break;
2589                 case POPPLER_ANNOT_FILE_ATTACHMENT: {
2590                         PopplerAnnotFileAttachment *poppler_annot_attachment;
2591                         EvAnnotationAttachment     *ev_annot_attachment;
2592                         PopplerAttachment          *poppler_attachment;
2593                         gchar                      *data = NULL;
2594                         gsize                       size;
2595                         GError                     *error = NULL;
2596
2597                         poppler_annot_attachment = POPPLER_ANNOT_FILE_ATTACHMENT (poppler_annot);
2598                         poppler_attachment = poppler_annot_file_attachment_get_attachment (poppler_annot_attachment);
2599
2600                         if (poppler_attachment &&
2601                             attachment_save_to_buffer (poppler_attachment, &data, &size, &error)) {
2602                                 EvAttachment *ev_attachment;
2603
2604                                 ev_attachment = ev_attachment_new (poppler_attachment->name,
2605                                                                    poppler_attachment->description,
2606                                                                    poppler_attachment->mtime,
2607                                                                    poppler_attachment->ctime,
2608                                                                    size, data);
2609                                 ev_annot = ev_annotation_attachment_new (page, ev_attachment);
2610                                 g_object_unref (ev_attachment);
2611                         } else if (error) {
2612                                 g_warning ("%s", error->message);
2613                                 g_error_free (error);
2614                         }
2615
2616                         if (poppler_attachment)
2617                                 g_object_unref (poppler_attachment);
2618                 }
2619                         break;
2620                 case POPPLER_ANNOT_LINK:
2621                 case POPPLER_ANNOT_WIDGET:
2622                         /* Ignore link and widgets annots since they are already handled */
2623                         break;
2624                 default: {
2625                         GEnumValue *enum_value;
2626
2627                         enum_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (POPPLER_TYPE_ANNOT_TYPE),
2628                                                        poppler_annot_get_annot_type (poppler_annot));
2629                         unimplemented_annot = enum_value ? enum_value->value_name : "Unknown annotation";
2630                 }
2631         }
2632
2633         if (unimplemented_annot) {
2634                 g_warning ("Unimplemented annotation: %s, please post a "
2635                            "bug report in Evince bugzilla "
2636                            "(http://bugzilla.gnome.org) with a testcase.",
2637                            unimplemented_annot);
2638         }
2639
2640         if (ev_annot) {
2641                 time_t   utime;
2642                 gchar   *modified;
2643                 gchar   *contents;
2644                 gchar   *name;
2645                 GdkColor color;
2646
2647                 contents = poppler_annot_get_contents (poppler_annot);
2648                 if (contents) {
2649                         ev_annotation_set_contents (ev_annot, contents);
2650                         g_free (contents);
2651                 }
2652
2653                 name = poppler_annot_get_name (poppler_annot);
2654                 if (name) {
2655                         ev_annotation_set_name (ev_annot, name);
2656                         g_free (name);
2657                 }
2658
2659                 modified = poppler_annot_get_modified (poppler_annot);
2660                 if (poppler_date_parse (modified, &utime)) {
2661                         ev_annotation_set_modified_from_time (ev_annot, utime);
2662                 } else {
2663                         ev_annotation_set_modified (ev_annot, modified);
2664                 }
2665                 g_free (modified);
2666
2667                 poppler_annot_color_to_gdk_color (poppler_annot, &color);
2668                 ev_annotation_set_color (ev_annot, &color);
2669
2670                 if (POPPLER_IS_ANNOT_MARKUP (poppler_annot)) {
2671                         PopplerAnnotMarkup *markup;
2672                         gchar *label;
2673                         gdouble opacity;
2674                         PopplerRectangle poppler_rect;
2675
2676                         markup = POPPLER_ANNOT_MARKUP (poppler_annot);
2677
2678                         if (poppler_annot_markup_get_popup_rectangle (markup, &poppler_rect)) {
2679                                 EvRectangle ev_rect;
2680                                 gboolean is_open;
2681                                 gdouble height;
2682
2683                                 poppler_page_get_size (POPPLER_PAGE (page->backend_page),
2684                                                        NULL, &height);
2685                                 ev_rect.x1 = poppler_rect.x1;
2686                                 ev_rect.x2 = poppler_rect.x2;
2687                                 ev_rect.y1 = height - poppler_rect.y2;
2688                                 ev_rect.y2 = height - poppler_rect.y1;
2689
2690                                 is_open = poppler_annot_markup_get_popup_is_open (markup);
2691
2692                                 g_object_set (ev_annot,
2693                                               "rectangle", &ev_rect,
2694                                               "popup_is_open", is_open,
2695                                               "has_popup", TRUE,
2696                                               NULL);
2697                         } else {
2698                                 g_object_set (ev_annot,
2699                                               "has_popup", FALSE,
2700                                               NULL);
2701                         }
2702
2703                         label = poppler_annot_markup_get_label (markup);
2704                         opacity = poppler_annot_markup_get_opacity (markup);
2705
2706                         g_object_set (ev_annot,
2707                                       "label", label,
2708                                       "opacity", opacity,
2709                                       NULL);
2710
2711                         g_free (label);
2712                 }
2713         }
2714
2715         return ev_annot;
2716 }
2717
2718 static EvMappingList *
2719 pdf_document_annotations_get_annotations (EvDocumentAnnotations *document_annotations,
2720                                           EvPage                *page)
2721 {
2722         GList *retval = NULL;
2723         PdfDocument *pdf_document;
2724         PopplerPage *poppler_page;
2725         EvMappingList *mapping_list;
2726         GList *annots;
2727         GList *list;
2728         gdouble height;
2729         gint i = 0;
2730
2731         pdf_document = PDF_DOCUMENT (document_annotations);
2732         poppler_page = POPPLER_PAGE (page->backend_page);
2733
2734         if (pdf_document->annots) {
2735                 mapping_list = (EvMappingList *)g_hash_table_lookup (pdf_document->annots,
2736                                                                      GINT_TO_POINTER (page->index));
2737                 if (mapping_list)
2738                         return ev_mapping_list_ref (mapping_list);
2739         }
2740
2741         annots = poppler_page_get_annot_mapping (poppler_page);
2742         poppler_page_get_size (poppler_page, NULL, &height);
2743
2744         for (list = annots; list; list = list->next) {
2745                 PopplerAnnotMapping *mapping;
2746                 EvMapping           *annot_mapping;
2747                 EvAnnotation        *ev_annot;
2748
2749                 mapping = (PopplerAnnotMapping *)list->data;
2750
2751                 ev_annot = ev_annot_from_poppler_annot (mapping->annot, page);
2752                 if (!ev_annot)
2753                         continue;
2754
2755                 i++;
2756
2757                 /* Make sure annot has a unique name */
2758                 if (!ev_annotation_get_name (ev_annot)) {
2759                         gchar *name = g_strdup_printf ("annot-%d-%d", page->index, i);
2760
2761                         ev_annotation_set_name (ev_annot, name);
2762                         g_free (name);
2763                 }
2764
2765                 annot_mapping = g_new (EvMapping, 1);
2766                 annot_mapping->area.x1 = mapping->area.x1;
2767                 annot_mapping->area.x2 = mapping->area.x2;
2768                 annot_mapping->area.y1 = height - mapping->area.y2;
2769                 annot_mapping->area.y2 = height - mapping->area.y1;
2770                 annot_mapping->data = ev_annot;
2771
2772                 g_object_set_data_full (G_OBJECT (ev_annot),
2773                                         "poppler-annot",
2774                                         g_object_ref (mapping->annot),
2775                                         (GDestroyNotify) g_object_unref);
2776
2777                 retval = g_list_prepend (retval, annot_mapping);
2778         }
2779
2780         poppler_page_free_annot_mapping (annots);
2781
2782         if (!retval)
2783                 return NULL;
2784
2785         if (!pdf_document->annots) {
2786                 pdf_document->annots = g_hash_table_new_full (g_direct_hash,
2787                                                               g_direct_equal,
2788                                                               (GDestroyNotify)NULL,
2789                                                               (GDestroyNotify)ev_mapping_list_unref);
2790         }
2791
2792         mapping_list = ev_mapping_list_new (page->index, g_list_reverse (retval), (GDestroyNotify)g_object_unref);
2793         g_hash_table_insert (pdf_document->annots,
2794                              GINT_TO_POINTER (page->index),
2795                              ev_mapping_list_ref (mapping_list));
2796
2797         return mapping_list;
2798 }
2799
2800 static gboolean
2801 pdf_document_annotations_document_is_modified (EvDocumentAnnotations *document_annotations)
2802 {
2803         return PDF_DOCUMENT (document_annotations)->annots_modified;
2804 }
2805
2806 #ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
2807 static void
2808 pdf_document_annotations_add_annotation (EvDocumentAnnotations *document_annotations,
2809                                          EvAnnotation          *annot,
2810                                          EvRectangle           *rect)
2811 {
2812         PopplerAnnot    *poppler_annot;
2813         PdfDocument     *pdf_document;
2814         EvPage          *page;
2815         PopplerPage     *poppler_page;
2816         GList           *list = NULL;
2817         EvMappingList   *mapping_list;
2818         EvMapping       *annot_mapping;
2819         PopplerRectangle poppler_rect;
2820         gdouble          height;
2821         PopplerColor     poppler_color;
2822         GdkColor         color;
2823         time_t           utime;
2824         gchar           *modified;
2825         gchar           *name;
2826
2827         pdf_document = PDF_DOCUMENT (document_annotations);
2828         page = ev_annotation_get_page (annot);
2829         poppler_page = POPPLER_PAGE (page->backend_page);
2830
2831         poppler_page_get_size (poppler_page, NULL, &height);
2832         poppler_rect.x1 = rect->x1;
2833         poppler_rect.x2 = rect->x2;
2834         poppler_rect.y1 = height - rect->y2;
2835         poppler_rect.y2 = height - rect->y1;
2836         poppler_annot = poppler_annot_text_new (pdf_document->document, &poppler_rect);
2837
2838         ev_annotation_get_color (annot, &color);
2839         poppler_color.red = color.red;
2840         poppler_color.green = color.green;
2841         poppler_color.blue = color.blue;
2842         poppler_annot_set_color (poppler_annot, &poppler_color);
2843
2844         if (EV_IS_ANNOTATION_MARKUP (annot)) {
2845                 EvAnnotationMarkup *markup = EV_ANNOTATION_MARKUP (annot);
2846                 const gchar *label;
2847
2848                 if (ev_annotation_markup_has_popup (markup)) {
2849                         EvRectangle popup_rect;
2850
2851                         ev_annotation_markup_get_rectangle (markup, &popup_rect);
2852                         poppler_rect.x1 = popup_rect.x1;
2853                         poppler_rect.x2 = popup_rect.x2;
2854                         poppler_rect.y1 = height - popup_rect.y2;
2855                         poppler_rect.y2 = height - popup_rect.y1;
2856                         poppler_annot_markup_set_popup (POPPLER_ANNOT_MARKUP (poppler_annot), &poppler_rect);
2857                         poppler_annot_markup_set_popup_is_open (POPPLER_ANNOT_MARKUP (poppler_annot),
2858                                                                 ev_annotation_markup_get_popup_is_open (markup));
2859                 }
2860
2861                 label = ev_annotation_markup_get_label (markup);
2862                 if (label)
2863                         poppler_annot_markup_set_label (POPPLER_ANNOT_MARKUP (poppler_annot), label);
2864         }
2865
2866         if (EV_IS_ANNOTATION_TEXT (annot)) {
2867                 EvAnnotationText    *text = EV_ANNOTATION_TEXT (annot);
2868                 EvAnnotationTextIcon icon;
2869
2870                 icon = ev_annotation_text_get_icon (text);
2871                 poppler_annot_text_set_icon (POPPLER_ANNOT_TEXT (poppler_annot),
2872                                              get_poppler_annot_text_icon (icon));
2873         }
2874         poppler_page_add_annot (poppler_page, poppler_annot);
2875
2876         annot_mapping = g_new (EvMapping, 1);
2877         annot_mapping->area = *rect;
2878         annot_mapping->data = annot;
2879         g_object_set_data_full (G_OBJECT (annot),
2880                                 "poppler-annot",
2881                                 g_object_ref (poppler_annot),
2882                                 (GDestroyNotify) g_object_unref);
2883
2884         if (pdf_document->annots) {
2885                 mapping_list = (EvMappingList *)g_hash_table_lookup (pdf_document->annots,
2886                                                                      GINT_TO_POINTER (page->index));
2887                 list = ev_mapping_list_get_list (mapping_list);
2888                 name = g_strdup_printf ("annot-%d-%d", page->index, g_list_length (list) + 1);
2889                 ev_annotation_set_name (annot, name);
2890                 g_free (name);
2891                 list = g_list_append (list, annot_mapping);
2892         } else {
2893                 pdf_document->annots = g_hash_table_new_full (g_direct_hash,
2894                                                               g_direct_equal,
2895                                                               (GDestroyNotify)NULL,
2896                                                               (GDestroyNotify)ev_mapping_list_unref);
2897                 name = g_strdup_printf ("annot-%d-0", page->index);
2898                 ev_annotation_set_name (annot, name);
2899                 g_free (name);
2900                 list = g_list_append (list, annot_mapping);
2901                 mapping_list = ev_mapping_list_new (page->index, list, (GDestroyNotify)g_object_unref);
2902                 g_hash_table_insert (pdf_document->annots,
2903                                      GINT_TO_POINTER (page->index),
2904                                      ev_mapping_list_ref (mapping_list));
2905         }
2906
2907         pdf_document->annots_modified = TRUE;
2908 }
2909 #endif /* HAVE_POPPLER_PAGE_ADD_ANNOT */
2910
2911 static void
2912 pdf_document_annotations_save_annotation (EvDocumentAnnotations *document_annotations,
2913                                           EvAnnotation          *annot,
2914                                           EvAnnotationsSaveMask  mask)
2915 {
2916         PopplerAnnot *poppler_annot;
2917
2918         poppler_annot = POPPLER_ANNOT (g_object_get_data (G_OBJECT (annot), "poppler-annot"));
2919         if (!poppler_annot)
2920                 return;
2921
2922         if (mask & EV_ANNOTATIONS_SAVE_CONTENTS)
2923                 poppler_annot_set_contents (poppler_annot,
2924                                             ev_annotation_get_contents (annot));
2925
2926 #ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
2927         if (mask & EV_ANNOTATIONS_SAVE_COLOR) {
2928                 PopplerColor color;
2929                 GdkColor     ev_color;
2930
2931                 ev_annotation_get_color (annot, &ev_color);
2932                 color.red = ev_color.red;
2933                 color.green = ev_color.green;
2934                 color.blue = ev_color.blue;
2935                 poppler_annot_set_color (poppler_annot, &color);
2936         }
2937
2938         if (EV_IS_ANNOTATION_MARKUP (annot)) {
2939                 EvAnnotationMarkup *ev_markup = EV_ANNOTATION_MARKUP (annot);
2940                 PopplerAnnotMarkup *markup = POPPLER_ANNOT_MARKUP (poppler_annot);
2941
2942                 if (mask & EV_ANNOTATIONS_SAVE_LABEL)
2943                         poppler_annot_markup_set_label (markup, ev_annotation_markup_get_label (ev_markup));
2944                 if (mask & EV_ANNOTATIONS_SAVE_OPACITY)
2945                         poppler_annot_markup_set_opacity (markup, ev_annotation_markup_get_opacity (ev_markup));
2946                 if (mask & EV_ANNOTATIONS_SAVE_POPUP_IS_OPEN)
2947                         poppler_annot_markup_set_popup_is_open (markup, ev_annotation_markup_get_popup_is_open (ev_markup));
2948         }
2949
2950         if (EV_IS_ANNOTATION_TEXT (annot)) {
2951                 EvAnnotationText *ev_text = EV_ANNOTATION_TEXT (annot);
2952                 PopplerAnnotText *text = POPPLER_ANNOT_TEXT (poppler_annot);
2953
2954                 if (mask & EV_ANNOTATIONS_SAVE_TEXT_IS_OPEN) {
2955                         poppler_annot_text_set_is_open (text,
2956                                                         ev_annotation_text_get_is_open (ev_text));
2957                 }
2958                 if (mask & EV_ANNOTATIONS_SAVE_TEXT_ICON) {
2959                         EvAnnotationTextIcon icon;
2960
2961                         icon = ev_annotation_text_get_icon (ev_text);
2962                         poppler_annot_text_set_icon (text, get_poppler_annot_text_icon (icon));
2963                 }
2964         }
2965 #endif /* HAVE_POPPLER_PAGE_ADD_ANNOT */
2966         PDF_DOCUMENT (document_annotations)->annots_modified = TRUE;
2967 }
2968
2969 static void
2970 pdf_document_document_annotations_iface_init (EvDocumentAnnotationsInterface *iface)
2971 {
2972         iface->get_annotations = pdf_document_annotations_get_annotations;
2973         iface->document_is_modified = pdf_document_annotations_document_is_modified;
2974 #ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
2975         iface->add_annotation = pdf_document_annotations_add_annotation;
2976 #endif
2977         iface->save_annotation = pdf_document_annotations_save_annotation;
2978 }
2979
2980 /* Attachments */
2981 struct SaveToBufferData {
2982         gchar *buffer;
2983         gsize len, max;
2984 };
2985
2986 static gboolean
2987 attachment_save_to_buffer_callback (const gchar  *buf,
2988                                     gsize         count,
2989                                     gpointer      user_data,
2990                                     GError      **error)
2991 {
2992         struct SaveToBufferData *sdata = (SaveToBufferData *)user_data;
2993         gchar *new_buffer;
2994         gsize new_max;
2995
2996         if (sdata->len + count > sdata->max) {
2997                 new_max = MAX (sdata->max * 2, sdata->len + count);
2998                 new_buffer = (gchar *)g_realloc (sdata->buffer, new_max);
2999
3000                 sdata->buffer = new_buffer;
3001                 sdata->max = new_max;
3002         }
3003
3004         memcpy (sdata->buffer + sdata->len, buf, count);
3005         sdata->len += count;
3006
3007         return TRUE;
3008 }
3009
3010 static gboolean
3011 attachment_save_to_buffer (PopplerAttachment  *attachment,
3012                            gchar             **buffer,
3013                            gsize              *buffer_size,
3014                            GError            **error)
3015 {
3016         static const gint initial_max = 1024;
3017         struct SaveToBufferData sdata;
3018
3019         *buffer = NULL;
3020         *buffer_size = 0;
3021
3022         sdata.buffer = (gchar *) g_malloc (initial_max);
3023         sdata.max = initial_max;
3024         sdata.len = 0;
3025
3026         if (! poppler_attachment_save_to_callback (attachment,
3027                                                    attachment_save_to_buffer_callback,
3028                                                    &sdata,
3029                                                    error)) {
3030                 g_free (sdata.buffer);
3031                 return FALSE;
3032         }
3033
3034         *buffer = sdata.buffer;
3035         *buffer_size = sdata.len;
3036
3037         return TRUE;
3038 }
3039
3040 static GList *
3041 pdf_document_attachments_get_attachments (EvDocumentAttachments *document)
3042 {
3043         PdfDocument *pdf_document = PDF_DOCUMENT (document);
3044         GList *attachments;
3045         GList *list;
3046         GList *retval = NULL;
3047
3048         attachments = poppler_document_get_attachments (pdf_document->document);
3049
3050         for (list = attachments; list; list = list->next) {
3051                 PopplerAttachment *attachment;
3052                 EvAttachment *ev_attachment;
3053                 gchar *data = NULL;
3054                 gsize size;
3055                 GError *error = NULL;
3056
3057                 attachment = (PopplerAttachment *) list->data;
3058
3059                 if (attachment_save_to_buffer (attachment, &data, &size, &error)) {
3060                         ev_attachment = ev_attachment_new (attachment->name,
3061                                                            attachment->description,
3062                                                            attachment->mtime,
3063                                                            attachment->ctime,
3064                                                            size, data);
3065
3066                         retval = g_list_prepend (retval, ev_attachment);
3067                 } else {
3068                         if (error) {
3069                                 g_warning ("%s", error->message);
3070                                 g_error_free (error);
3071
3072                                 g_free (data);
3073                         }
3074                 }
3075
3076                 g_object_unref (attachment);
3077         }
3078
3079         return g_list_reverse (retval);
3080 }
3081
3082 static gboolean
3083 pdf_document_attachments_has_attachments (EvDocumentAttachments *document)
3084 {
3085         PdfDocument *pdf_document = PDF_DOCUMENT (document);
3086
3087         return poppler_document_has_attachments (pdf_document->document);
3088 }
3089
3090 static void
3091 pdf_document_document_attachments_iface_init (EvDocumentAttachmentsInterface *iface)
3092 {
3093         iface->has_attachments = pdf_document_attachments_has_attachments;
3094         iface->get_attachments = pdf_document_attachments_get_attachments;
3095 }
3096
3097 /* Layers */
3098 static gboolean
3099 pdf_document_layers_has_layers (EvDocumentLayers *document)
3100 {
3101         PdfDocument *pdf_document = PDF_DOCUMENT (document);
3102         PopplerLayersIter *iter;
3103
3104         iter = poppler_layers_iter_new (pdf_document->document);
3105         if (!iter)
3106                 return FALSE;
3107         poppler_layers_iter_free (iter);
3108
3109         return TRUE;
3110 }
3111
3112 static void
3113 build_layers_tree (PdfDocument       *pdf_document,
3114                    GtkTreeModel      *model,
3115                    GtkTreeIter       *parent,
3116                    PopplerLayersIter *iter)
3117 {
3118         do {
3119                 GtkTreeIter        tree_iter;
3120                 PopplerLayersIter *child;
3121                 PopplerLayer      *layer;
3122                 EvLayer           *ev_layer = NULL;
3123                 gboolean           visible;
3124                 gchar             *markup;
3125                 gint               rb_group = 0;
3126
3127                 layer = poppler_layers_iter_get_layer (iter);
3128                 if (layer) {
3129                         markup = g_markup_escape_text (poppler_layer_get_title (layer), -1);
3130                         visible = poppler_layer_is_visible (layer);
3131                         rb_group = poppler_layer_get_radio_button_group_id (layer);
3132                         pdf_document->layers = g_list_append (pdf_document->layers,
3133                                                               g_object_ref (layer));
3134                         ev_layer = ev_layer_new (g_list_length (pdf_document->layers) - 1,
3135                                                  poppler_layer_is_parent (layer),
3136                                                  rb_group);
3137                 } else {
3138                         gchar *title;
3139
3140                         title = poppler_layers_iter_get_title (iter);
3141                         markup = g_markup_escape_text (title, -1);
3142                         g_free (title);
3143
3144                         visible = FALSE;
3145                         layer = NULL;
3146                 }
3147
3148                 gtk_tree_store_append (GTK_TREE_STORE (model), &tree_iter, parent);
3149                 gtk_tree_store_set (GTK_TREE_STORE (model), &tree_iter,
3150                                     EV_DOCUMENT_LAYERS_COLUMN_TITLE, markup,
3151                                     EV_DOCUMENT_LAYERS_COLUMN_VISIBLE, visible,
3152                                     EV_DOCUMENT_LAYERS_COLUMN_ENABLED, TRUE, /* FIXME */
3153                                     EV_DOCUMENT_LAYERS_COLUMN_SHOWTOGGLE, (layer != NULL),
3154                                     EV_DOCUMENT_LAYERS_COLUMN_RBGROUP, rb_group,
3155                                     EV_DOCUMENT_LAYERS_COLUMN_LAYER, ev_layer,
3156                                     -1);
3157                 if (ev_layer)
3158                         g_object_unref (ev_layer);
3159                 g_free (markup);
3160
3161                 child = poppler_layers_iter_get_child (iter);
3162                 if (child)
3163                         build_layers_tree (pdf_document, model, &tree_iter, child);
3164                 poppler_layers_iter_free (child);
3165         } while (poppler_layers_iter_next (iter));
3166 }
3167
3168 static GtkTreeModel *
3169 pdf_document_layers_get_layers (EvDocumentLayers *document)
3170 {
3171         GtkTreeModel *model = NULL;
3172         PdfDocument *pdf_document = PDF_DOCUMENT (document);
3173         PopplerLayersIter *iter;
3174
3175         iter = poppler_layers_iter_new (pdf_document->document);
3176         if (iter) {
3177                 model = (GtkTreeModel *) gtk_tree_store_new (EV_DOCUMENT_LAYERS_N_COLUMNS,
3178                                                              G_TYPE_STRING,  /* TITLE */
3179                                                              G_TYPE_OBJECT,  /* LAYER */
3180                                                              G_TYPE_BOOLEAN, /* VISIBLE */
3181                                                              G_TYPE_BOOLEAN, /* ENABLED */
3182                                                              G_TYPE_BOOLEAN, /* SHOWTOGGLE */
3183                                                              G_TYPE_INT);    /* RBGROUP */
3184                 build_layers_tree (pdf_document, model, NULL, iter);
3185                 poppler_layers_iter_free (iter);
3186         }
3187         return model;
3188 }
3189
3190 static void
3191 pdf_document_layers_show_layer (EvDocumentLayers *document,
3192                                 EvLayer          *layer)
3193 {
3194         PdfDocument *pdf_document = PDF_DOCUMENT (document);
3195         guint        layer_id = ev_layer_get_id (layer);
3196
3197         poppler_layer_show (POPPLER_LAYER (g_list_nth_data (pdf_document->layers, layer_id)));
3198 }
3199
3200 static void
3201 pdf_document_layers_hide_layer (EvDocumentLayers *document,
3202                                 EvLayer          *layer)
3203 {
3204         PdfDocument *pdf_document = PDF_DOCUMENT (document);
3205         guint        layer_id = ev_layer_get_id (layer);
3206
3207         poppler_layer_hide (POPPLER_LAYER (g_list_nth_data (pdf_document->layers, layer_id)));
3208 }
3209
3210 static gboolean
3211 pdf_document_layers_layer_is_visible (EvDocumentLayers *document,
3212                                       EvLayer          *layer)
3213 {
3214         PdfDocument *pdf_document = PDF_DOCUMENT (document);
3215         guint        layer_id = ev_layer_get_id (layer);
3216
3217         return poppler_layer_is_visible (POPPLER_LAYER (g_list_nth_data (pdf_document->layers, layer_id)));
3218 }
3219
3220 static void
3221 pdf_document_document_layers_iface_init (EvDocumentLayersInterface *iface)
3222 {
3223         iface->has_layers = pdf_document_layers_has_layers;
3224         iface->get_layers = pdf_document_layers_get_layers;
3225         iface->show_layer = pdf_document_layers_show_layer;
3226         iface->hide_layer = pdf_document_layers_hide_layer;
3227         iface->layer_is_visible = pdf_document_layers_layer_is_visible;
3228 }