]> www.fi.muni.cz Git - evince.git/blobdiff - backend/pdf/ev-poppler.cc
pdf: Support .pdf.xz files
[evince.git] / backend / pdf / ev-poppler.cc
index f6bce0988839031f2ef2aab81e4f3b9692fe45dd..ced3ef79fb9284149dd9eb08726fdda7ed2a378d 100644 (file)
@@ -1,5 +1,7 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
-/* pdfdocument.h: Implementation of EvDocument for PDF
+/* this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2009, Juanjo MarĂ­n <juanj.marin@juntadeandalucia.es>
  * Copyright (C) 2004, Red Hat, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -14,7 +16,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
 #include "config.h"
 #include "ev-document-images.h"
 #include "ev-document-fonts.h"
 #include "ev-document-security.h"
-#include "ev-document-thumbnails.h"
 #include "ev-document-transition.h"
 #include "ev-document-forms.h"
 #include "ev-document-layers.h"
 #include "ev-document-print.h"
 #include "ev-document-annotations.h"
+#include "ev-document-attachments.h"
+#include "ev-document-text.h"
 #include "ev-selection.h"
 #include "ev-transition-effect.h"
 #include "ev-attachment.h"
 #include <libxml/xpath.h>
 #include <libxml/xpathInternals.h>
 
-#if (defined (HAVE_POPPLER_PAGE_RENDER)) && (defined (HAVE_CAIRO_PDF) || defined (HAVE_CAIRO_PS))
+#if (defined (HAVE_CAIRO_PDF) || defined (HAVE_CAIRO_PS))
 #define HAVE_CAIRO_PRINT
 #endif
 
-typedef struct {
-       PdfDocument *document;
-       char *text;
-       GList **pages;
-       guint idle;
-       int start_page;
-       int search_page;
-} PdfDocumentSearch;
+/* fields from the XMP Rights Management Schema, XMP Specification Sept 2005, pag. 45 */
+#define LICENSE_MARKED "/x:xmpmeta/rdf:RDF/rdf:Description/xmpRights:Marked"
+#define LICENSE_TEXT "/x:xmpmeta/rdf:RDF/rdf:Description/dc:rights/rdf:Alt/rdf:li[lang('%s')]"
+#define LICENSE_WEB_STATEMENT "/x:xmpmeta/rdf:RDF/rdf:Description/xmpRights:WebStatement"
+/* license field from Creative Commons schema, http://creativecommons.org/ns */
+#define LICENSE_URI "/x:xmpmeta/rdf:RDF/rdf:Description/cc:license/@rdf:resource"
 
 typedef struct {
        EvFileExporterFormat format;
@@ -90,62 +91,57 @@ typedef struct {
 
 struct _PdfDocumentClass
 {
-       GObjectClass parent_class;
+       EvDocumentClass parent_class;
 };
 
 struct _PdfDocument
 {
-       GObject parent_instance;
+       EvDocument parent_instance;
 
        PopplerDocument *document;
        gchar *password;
-       gboolean modified;
+       gboolean forms_modified;
+       gboolean annots_modified;
 
        PopplerFontInfo *font_info;
        PopplerFontsIter *fonts_iter;
        int fonts_scanned_pages;
 
-       PdfDocumentSearch *search;
        PdfPrintContext *print_ctx;
 
-       GList *layers;
+       GHashTable *annots;
 };
 
-static void pdf_document_document_iface_init             (EvDocumentIface            *iface);
-static void pdf_document_security_iface_init             (EvDocumentSecurityIface    *iface);
-static void pdf_document_document_thumbnails_iface_init  (EvDocumentThumbnailsIface  *iface);
-static void pdf_document_document_links_iface_init       (EvDocumentLinksIface       *iface);
-static void pdf_document_document_images_iface_init      (EvDocumentImagesIface      *iface);
-static void pdf_document_document_forms_iface_init       (EvDocumentFormsIface       *iface);
-static void pdf_document_document_fonts_iface_init       (EvDocumentFontsIface       *iface);
-static void pdf_document_document_layers_iface_init      (EvDocumentLayersIface      *iface);
-#ifdef HAVE_POPPLER_PAGE_RENDER
-static void pdf_document_document_print_iface_init       (EvDocumentPrintIface       *iface);
-#endif
-static void pdf_document_document_annotations_iface_init (EvDocumentAnnotationsIface *iface);
-static void pdf_document_find_iface_init                 (EvDocumentFindIface        *iface);
-static void pdf_document_file_exporter_iface_init        (EvFileExporterIface        *iface);
-static void pdf_selection_iface_init                     (EvSelectionIface           *iface);
-static void pdf_document_page_transition_iface_init      (EvDocumentTransitionIface  *iface);
-static void pdf_document_thumbnails_get_dimensions       (EvDocumentThumbnails       *document_thumbnails,
-                                                         EvRenderContext            *rc,
-                                                         gint                       *width,
-                                                         gint                       *height);
-static int  pdf_document_get_n_pages                    (EvDocument                 *document);
-
-static EvLinkDest *ev_link_dest_from_dest   (PdfDocument       *pdf_document,
-                                            PopplerDest       *dest);
-static EvLink     *ev_link_from_action      (PdfDocument       *pdf_document,
-                                            PopplerAction     *action);
-static void        pdf_document_search_free (PdfDocumentSearch *search);
-static void        pdf_print_context_free   (PdfPrintContext   *ctx);
+static void pdf_document_security_iface_init             (EvDocumentSecurityInterface    *iface);
+static void pdf_document_document_links_iface_init       (EvDocumentLinksInterface       *iface);
+static void pdf_document_document_images_iface_init      (EvDocumentImagesInterface      *iface);
+static void pdf_document_document_forms_iface_init       (EvDocumentFormsInterface       *iface);
+static void pdf_document_document_fonts_iface_init       (EvDocumentFontsInterface       *iface);
+static void pdf_document_document_layers_iface_init      (EvDocumentLayersInterface      *iface);
+static void pdf_document_document_print_iface_init       (EvDocumentPrintInterface       *iface);
+static void pdf_document_document_annotations_iface_init (EvDocumentAnnotationsInterface *iface);
+static void pdf_document_document_attachments_iface_init (EvDocumentAttachmentsInterface *iface);
+static void pdf_document_find_iface_init                 (EvDocumentFindInterface        *iface);
+static void pdf_document_file_exporter_iface_init        (EvFileExporterInterface        *iface);
+static void pdf_selection_iface_init                     (EvSelectionInterface           *iface);
+static void pdf_document_page_transition_iface_init      (EvDocumentTransitionInterface  *iface);
+static void pdf_document_text_iface_init                 (EvDocumentTextInterface        *iface);
+static int  pdf_document_get_n_pages                    (EvDocument                     *document);
+
+static EvLinkDest *ev_link_dest_from_dest    (PdfDocument       *pdf_document,
+                                             PopplerDest       *dest);
+static EvLink     *ev_link_from_action       (PdfDocument       *pdf_document,
+                                             PopplerAction     *action);
+static void        pdf_print_context_free    (PdfPrintContext   *ctx);
+static gboolean    attachment_save_to_buffer (PopplerAttachment *attachment,
+                                             gchar            **buffer,
+                                             gsize             *buffer_size,
+                                             GError           **error);
 
 EV_BACKEND_REGISTER_WITH_CODE (PdfDocument, pdf_document,
                         {
                                 EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_SECURITY,
                                                                 pdf_document_security_iface_init);
-                                EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
-                                                                pdf_document_document_thumbnails_iface_init);
                                 EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_LINKS,
                                                                 pdf_document_document_links_iface_init);
                                 EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_IMAGES,
@@ -156,12 +152,12 @@ EV_BACKEND_REGISTER_WITH_CODE (PdfDocument, pdf_document,
                                                                 pdf_document_document_fonts_iface_init);
                                 EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_LAYERS,
                                                                 pdf_document_document_layers_iface_init);
-#ifdef HAVE_POPPLER_PAGE_RENDER
                                 EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_PRINT,
                                                                 pdf_document_document_print_iface_init);
-#endif
                                 EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_ANNOTATIONS,
                                                                 pdf_document_document_annotations_iface_init);
+                                EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_ATTACHMENTS,
+                                                                pdf_document_document_attachments_iface_init);
                                 EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FIND,
                                                                 pdf_document_find_iface_init);
                                 EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_FILE_EXPORTER,
@@ -170,29 +166,10 @@ EV_BACKEND_REGISTER_WITH_CODE (PdfDocument, pdf_document,
                                                                 pdf_selection_iface_init);
                                 EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_TRANSITION,
                                                                 pdf_document_page_transition_iface_init);
+                                EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_TEXT,
+                                                                pdf_document_text_iface_init);
                         });
 
-static void
-pdf_document_search_free (PdfDocumentSearch   *search)
-{
-        PdfDocument *pdf_document = search->document;
-       int n_pages;
-       int i;
-
-        if (search->idle != 0)
-                g_source_remove (search->idle);
-
-       n_pages = pdf_document_get_n_pages (EV_DOCUMENT (pdf_document));
-       for (i = 0; i < n_pages; i++) {
-               g_list_foreach (search->pages[i], (GFunc) g_free, NULL);
-               g_list_free (search->pages[i]);
-       }
-       g_free (search->pages);
-       
-       g_free (search->text);
-       g_free (search);
-}
-
 static void
 pdf_document_dispose (GObject *object)
 {
@@ -202,10 +179,10 @@ pdf_document_dispose (GObject *object)
                pdf_print_context_free (pdf_document->print_ctx);
                pdf_document->print_ctx = NULL;
        }
-       
-       if (pdf_document->search) {
-               pdf_document_search_free (pdf_document->search);
-               pdf_document->search = NULL;
+
+       if (pdf_document->annots) {
+               g_hash_table_destroy (pdf_document->annots);
+               pdf_document->annots = NULL;
        }
 
        if (pdf_document->document) {
@@ -220,22 +197,9 @@ pdf_document_dispose (GObject *object)
                poppler_fonts_iter_free (pdf_document->fonts_iter);
        }
 
-       if (pdf_document->layers) {
-               g_list_foreach (pdf_document->layers, (GFunc)g_object_unref, NULL);
-               g_list_free (pdf_document->layers);
-       }
-
        G_OBJECT_CLASS (pdf_document_parent_class)->dispose (object);
 }
 
-static void
-pdf_document_class_init (PdfDocumentClass *klass)
-{
-       GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
-
-       g_object_class->dispose = pdf_document_dispose;
-}
-
 static void
 pdf_document_init (PdfDocument *pdf_document)
 {
@@ -279,9 +243,13 @@ pdf_document_save (EvDocument  *document,
        gboolean retval;
        GError *poppler_error = NULL;
 
-       if (pdf_document->modified) {
+       if (pdf_document->forms_modified || pdf_document->annots_modified) {
                retval = poppler_document_save (pdf_document->document,
                                                uri, &poppler_error);
+               if (retval) {
+                       pdf_document->forms_modified = FALSE;
+                       pdf_document->annots_modified = FALSE;
+               }
        } else {
                retval = poppler_document_save_a_copy (pdf_document->document,
                                                       uri, &poppler_error);
@@ -360,122 +328,6 @@ pdf_document_get_page_label (EvDocument *document,
        return label;
 }
 
-static gboolean
-pdf_document_has_attachments (EvDocument *document)
-{
-       PdfDocument *pdf_document;
-
-       pdf_document = PDF_DOCUMENT (document);
-
-       return poppler_document_has_attachments (pdf_document->document);
-}
-
-struct SaveToBufferData {
-       gchar *buffer;
-       gsize len, max;
-};
-
-static gboolean
-attachment_save_to_buffer_callback (const gchar  *buf,
-                                   gsize         count,
-                                   gpointer      user_data,
-                                   GError      **error)
-{
-       struct SaveToBufferData *sdata = (SaveToBufferData *)user_data;
-       gchar *new_buffer;
-       gsize new_max;
-
-       if (sdata->len + count > sdata->max) {
-               new_max = MAX (sdata->max * 2, sdata->len + count);
-               new_buffer = (gchar *)g_realloc (sdata->buffer, new_max);
-
-               sdata->buffer = new_buffer;
-               sdata->max = new_max;
-       }
-       
-       memcpy (sdata->buffer + sdata->len, buf, count);
-       sdata->len += count;
-       
-       return TRUE;
-}
-
-static gboolean
-attachment_save_to_buffer (PopplerAttachment  *attachment,
-                          gchar             **buffer,
-                          gsize              *buffer_size,
-                          GError            **error)
-{
-       static const gint initial_max = 1024;
-       struct SaveToBufferData sdata;
-
-       *buffer = NULL;
-       *buffer_size = 0;
-
-       sdata.buffer = (gchar *) g_malloc (initial_max);
-       sdata.max = initial_max;
-       sdata.len = 0;
-
-       if (! poppler_attachment_save_to_callback (attachment,
-                                                  attachment_save_to_buffer_callback,
-                                                  &sdata,
-                                                  error)) {
-               g_free (sdata.buffer);
-               return FALSE;
-       }
-
-       *buffer = sdata.buffer;
-       *buffer_size = sdata.len;
-       
-       return TRUE;
-}
-
-static GList *
-pdf_document_get_attachments (EvDocument *document)
-{
-       PdfDocument *pdf_document;
-       GList *attachments;
-       GList *list;
-       GList *retval = NULL;
-
-       pdf_document = PDF_DOCUMENT (document);
-
-       if (!pdf_document_has_attachments (document))
-               return NULL;
-
-       attachments = poppler_document_get_attachments (pdf_document->document);
-       
-       for (list = attachments; list; list = list->next) {
-               PopplerAttachment *attachment;
-               EvAttachment *ev_attachment;
-               gchar *data = NULL;
-               gsize size;
-               GError *error = NULL;
-
-               attachment = (PopplerAttachment *) list->data;
-
-               if (attachment_save_to_buffer (attachment, &data, &size, &error)) {
-                       ev_attachment = ev_attachment_new (attachment->name,
-                                                          attachment->description,
-                                                          attachment->mtime,
-                                                          attachment->ctime,
-                                                          size, data);
-                       
-                       retval = g_list_prepend (retval, ev_attachment);
-               } else {
-                       if (error) {
-                               g_warning ("%s", error->message);
-                               g_error_free (error);
-
-                               g_free (data);
-                       }
-               }
-
-               g_object_unref (attachment);
-       }
-
-       return g_list_reverse (retval);
-}
-
 static cairo_surface_t *
 pdf_page_render (PopplerPage     *page,
                 gint             width,
@@ -483,17 +335,12 @@ pdf_page_render (PopplerPage     *page,
                 EvRenderContext *rc)
 {
        cairo_surface_t *surface;
-
-#ifdef HAVE_POPPLER_PAGE_RENDER
        cairo_t *cr;
-       
-       surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+
+       surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
                                              width, height);
-       memset (cairo_image_surface_get_data (surface), 0xff,
-               cairo_image_surface_get_height (surface) *
-               cairo_image_surface_get_stride (surface));
-       
        cr = cairo_create (surface);
+
        switch (rc->rotation) {
                case 90:
                        cairo_translate (cr, width, 0);
@@ -510,25 +357,14 @@ pdf_page_render (PopplerPage     *page,
        cairo_scale (cr, rc->scale, rc->scale);
        cairo_rotate (cr, rc->rotation * G_PI / 180.0);
        poppler_page_render (page, cr);
-       cairo_destroy (cr);
-#else /* HAVE_POPPLER_PAGE_RENDER */
-       GdkPixbuf *pixbuf;
-       
-       pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
-                                FALSE, 8,
-                                width, height);
 
-       poppler_page_render_to_pixbuf (page,
-                                      0, 0,
-                                      width, height,
-                                      rc->scale,
-                                      rc->rotation,
-                                      pixbuf);
-       surface = ev_document_misc_surface_from_pixbuf (pixbuf);
-       g_object_unref (pixbuf);
-#endif /* HAVE_POPPLER_PAGE_RENDER */
+       cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
+       cairo_set_source_rgb (cr, 1., 1., 1.);
+       cairo_paint (cr);
 
-       return surface; 
+       cairo_destroy (cr);
+
+       return surface;
 }
 
 static cairo_surface_t *
@@ -557,51 +393,114 @@ pdf_document_render (EvDocument      *document,
                                width, height, rc);
 }
 
-/* EvDocumentSecurity */
-
-static gboolean
-pdf_document_has_document_security (EvDocumentSecurity *document_security)
+static GdkPixbuf *
+make_thumbnail_for_page (PopplerPage     *poppler_page,
+                        EvRenderContext *rc,
+                        gint             width,
+                        gint             height)
 {
-       /* FIXME: do we really need to have this? */
-       return FALSE;
+       GdkPixbuf *pixbuf;
+
+#ifdef POPPLER_WITH_GDK
+       pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
+                                width, height);
+       gdk_pixbuf_fill (pixbuf, 0xffffffff);
+
+       ev_document_fc_mutex_lock ();
+       poppler_page_render_to_pixbuf (poppler_page, 0, 0,
+                                      width, height,
+                                      rc->scale, rc->rotation, pixbuf);
+       ev_document_fc_mutex_unlock ();
+#else
+       cairo_surface_t *surface;
+
+       ev_document_fc_mutex_lock ();
+       surface = pdf_page_render (poppler_page, width, height, rc);
+       ev_document_fc_mutex_unlock ();
+       
+       pixbuf = ev_document_misc_pixbuf_from_surface (surface);
+       cairo_surface_destroy (surface);
+#endif /* POPPLER_WITH_GDK */
+
+       return pixbuf;
 }
 
-static void
-pdf_document_set_password (EvDocumentSecurity *document_security,
-                          const char         *password)
+static GdkPixbuf *
+pdf_document_get_thumbnail (EvDocument      *document,
+                           EvRenderContext *rc)
 {
-       PdfDocument *document = PDF_DOCUMENT (document_security);
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+       PopplerPage *poppler_page;
+       GdkPixbuf *pixbuf = NULL;
+       GdkPixbuf *border_pixbuf;
+       double page_width, page_height;
+       gint width, height;
 
-       if (document->password)
-               g_free (document->password);
+       poppler_page = POPPLER_PAGE (rc->page->backend_page);
 
-       document->password = g_strdup (password);
-}
+       poppler_page_get_size (poppler_page,
+                              &page_width, &page_height);
+
+       width = MAX ((gint)(page_width * rc->scale + 0.5), 1);
+       height = MAX ((gint)(page_height * rc->scale + 0.5), 1);
 
+       if (rc->rotation == 90 || rc->rotation == 270) {
+               gint  temp;
+
+               temp = width;
+               width = height;
+               height = temp;
+       }
+
+#ifdef POPPLER_WITH_GDK
+       pixbuf = poppler_page_get_thumbnail_pixbuf (poppler_page);
+#else
+       cairo_surface_t *surface;
+       
+       surface = poppler_page_get_thumbnail (poppler_page);
+       if (surface) {
+               pixbuf = ev_document_misc_pixbuf_from_surface (surface);
+               cairo_surface_destroy (surface);
+       }
+#endif /* POPPLER_WITH_GDK */
+
+       if (pixbuf != NULL) {
+               int thumb_width = (rc->rotation == 90 || rc->rotation == 270) ?
+                       gdk_pixbuf_get_height (pixbuf) :
+                       gdk_pixbuf_get_width (pixbuf);
+
+               if (thumb_width == width) {
+                       GdkPixbuf *rotated_pixbuf;
+
+                       rotated_pixbuf = gdk_pixbuf_rotate_simple (pixbuf,
+                                                                  (GdkPixbufRotation) (360 - rc->rotation));
+                       g_object_unref (pixbuf);
+                       pixbuf = rotated_pixbuf;
+               } else {
+                       /* The provided thumbnail has a different size */
+                       g_object_unref (pixbuf);
+                       pixbuf = make_thumbnail_for_page (poppler_page, rc, width, height);
+               }
+       } else {
+               /* There is no provided thumbnail. We need to make one. */
+               pixbuf = make_thumbnail_for_page (poppler_page, rc, width, height);
+       }
+
+       return pixbuf;
+}
 
 /* reference:
 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 */
 static char *
-pdf_document_get_format_from_metadata (const char *metadata)
+pdf_document_get_format_from_metadata (xmlDocPtr          doc,
+                                      xmlXPathContextPtr xpathCtx)
 {
-       xmlDocPtr doc;
-       xmlXPathContextPtr xpathCtx;
        xmlXPathObjectPtr xpathObj;
        xmlChar *part = NULL;
        xmlChar *conf = NULL;
        char *result = NULL;
        int i;
 
-       doc = xmlParseMemory (metadata, strlen (metadata));
-       if (doc == NULL)
-               return NULL;      /* invalid xml metadata */
-
-       xpathCtx = xmlXPathNewContext (doc);
-       if (xpathCtx == NULL) {
-               xmlFreeDoc (doc);
-               return NULL;      /* invalid xpath context */
-       }
-
        /* add pdf/a namespaces */
        xmlXPathRegisterNs (xpathCtx, BAD_CAST "x", BAD_CAST "adobe:ns:meta/");
        xmlXPathRegisterNs (xpathCtx, BAD_CAST "rdf", BAD_CAST "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
@@ -647,22 +546,169 @@ pdf_document_get_format_from_metadata (const char *metadata)
                }
        }
 
-       if (part != NULL && conf != NULL) {
-               /* makes conf lowercase */
-               for (i = 0; conf[i]; i++)
-                       conf[i] = g_ascii_tolower (conf[i]);
+       if (part != NULL && conf != NULL) {
+               /* makes conf lowercase */
+               for (i = 0; conf[i]; i++)
+                       conf[i] = g_ascii_tolower (conf[i]);
+
+               /* return buffer */
+               result = g_strdup_printf ("PDF/A - %s%s", part, conf);
+       }
+
+       /* Cleanup */
+       xmlFree (part);
+       xmlFree (conf);
+
+       return result;
+}
+
+static EvDocumentLicense *
+pdf_document_get_license_from_metadata (xmlDocPtr          doc,
+                                       xmlXPathContextPtr xpathCtx)
+{
+       xmlXPathObjectPtr xpathObj;
+       xmlChar *marked = NULL;
+       const char *language_string;
+       char  *aux;
+       gchar **tags;
+       gchar *tag, *tag_aux;
+       int i, j;
+       EvDocumentLicense *license;
+
+       /* register namespaces */
+       xmlXPathRegisterNs (xpathCtx, BAD_CAST "x", BAD_CAST "adobe:ns:meta/");
+       xmlXPathRegisterNs (xpathCtx, BAD_CAST "rdf", BAD_CAST "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
+       xmlXPathRegisterNs (xpathCtx, BAD_CAST "dc", BAD_CAST "http://purl.org/dc/elements/1.1/");
+       /* XMP Rights Management Schema */
+       xmlXPathRegisterNs (xpathCtx, BAD_CAST "xmpRights", BAD_CAST "http://ns.adobe.com/xap/1.0/rights/");
+       /* Creative Commons Schema */
+       xmlXPathRegisterNs (xpathCtx, BAD_CAST "cc", BAD_CAST "http://creativecommons.org/ns#");
+
+       /* checking if the document has been marked as defined on the XMP Rights
+        * Management Schema */
+       xpathObj = xmlXPathEvalExpression (BAD_CAST LICENSE_MARKED, xpathCtx);
+       if (xpathObj != NULL) {
+               if (xpathObj->nodesetval != NULL &&
+                   xpathObj->nodesetval->nodeNr != 0)
+                       marked = xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
+               xmlXPathFreeObject (xpathObj);
+       }
+
+       /* a) Not marked => No XMP Rights information */
+       if (!marked) {
+               xmlFree (marked);
+               return NULL;
+       }
+
+       license = ev_document_license_new ();
+
+       /* b) Marked False => Public Domain, no copyrighted material and no
+        * license needed */
+       if (g_strrstr ((char *) marked, "False") != NULL) {
+               license->text = g_strdup (_("This work is in the Public Domain"));
+       /* c) Marked True => Copyrighted material */
+       } else {
+               /* Checking usage terms as defined by the XMP Rights Management
+                * Schema. This field is recomended to be checked by Creative
+                * Commons */
+               /* 1) checking for a suitable localized string */
+               language_string = pango_language_to_string (gtk_get_default_language ());
+               tags = g_strsplit (language_string, "-", -1);
+               i = g_strv_length (tags);
+               while (i-- && !license->text) {
+                       tag = g_strdup (tags[0]);
+                       for (j = 1; j <= i; j++) {
+                               tag_aux = g_strdup_printf ("%s-%s", tag, tags[j]);
+                               g_free (tag);
+                               tag = tag_aux;
+                       }
+                       aux = g_strdup_printf (LICENSE_TEXT, tag);
+                       xpathObj = xmlXPathEvalExpression (BAD_CAST aux, xpathCtx);
+                       if (xpathObj != NULL) {
+                               if (xpathObj->nodesetval != NULL &&
+                                   xpathObj->nodesetval->nodeNr != 0)
+                                       license->text = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
+                               xmlXPathFreeObject (xpathObj);
+                       }
+                       g_free (tag);
+                       g_free (aux);
+               }
+               g_strfreev(tags);
+
+               /* 2) if not, use the default string */
+               if (!license->text) {
+                       aux = g_strdup_printf (LICENSE_TEXT, "x-default");
+                       xpathObj = xmlXPathEvalExpression (BAD_CAST aux, xpathCtx);
+                       if (xpathObj != NULL) {
+                               if (xpathObj->nodesetval != NULL &&
+                                   xpathObj->nodesetval->nodeNr != 0)
+                                       license->text = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
+                               xmlXPathFreeObject (xpathObj);
+                       }
+                       g_free (aux);
+               }
+
+               /* Checking the license URI as defined by the Creative Commons
+                * Schema. This field is recomended to be checked by Creative
+                * Commons */
+               xpathObj = xmlXPathEvalExpression (BAD_CAST LICENSE_URI, xpathCtx);
+               if (xpathObj != NULL) {
+                       if (xpathObj->nodesetval != NULL &&
+                           xpathObj->nodesetval->nodeNr != 0)
+                               license->uri = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
+                       xmlXPathFreeObject (xpathObj);
+               }
+
+               /* Checking the web statement as defined by the XMP Rights
+                * Management Schema. Checking it out is a sort of above-and-beyond
+                * the basic recommendations by Creative Commons. It can be
+                * considered as a "reinforcement" approach to add certainty. */
+               xpathObj = xmlXPathEvalExpression (BAD_CAST LICENSE_WEB_STATEMENT, xpathCtx);
+               if (xpathObj != NULL) {
+                       if (xpathObj->nodesetval != NULL &&
+                           xpathObj->nodesetval->nodeNr != 0)
+                               license->web_statement = (gchar *)xmlNodeGetContent (xpathObj->nodesetval->nodeTab[0]);
+                       xmlXPathFreeObject (xpathObj);
+               }
+       }
+       xmlFree (marked);
+
+       if (!license->text && !license->uri && !license->web_statement) {
+               ev_document_license_free (license);
+               return NULL;
+       }
 
-               /* return buffer */
-               result = g_strdup_printf ("PDF/A - %s%s", part, conf);
+       return license;
+}
+
+static void
+pdf_document_parse_metadata (const gchar    *metadata,
+                            EvDocumentInfo *info)
+{
+       xmlDocPtr          doc;
+       xmlXPathContextPtr xpathCtx;
+       gchar             *fmt;
+
+       doc = xmlParseMemory (metadata, strlen (metadata));
+       if (doc == NULL)
+               return;         /* invalid xml metadata */
+
+       xpathCtx = xmlXPathNewContext (doc);
+       if (xpathCtx == NULL) {
+               xmlFreeDoc (doc);
+               return;         /* invalid xpath context */
        }
 
-       /* Cleanup */
-       xmlFree (part);
-       xmlFree (conf);
+       fmt = pdf_document_get_format_from_metadata (doc, xpathCtx);
+       if (fmt != NULL) {
+               g_free (info->format);
+               info->format = fmt;
+       }
+
+       info->license = pdf_document_get_license_from_metadata (doc, xpathCtx);
+
        xmlXPathFreeContext (xpathCtx);
        xmlFreeDoc (doc);
-
-       return result;
 }
 
 
@@ -676,7 +722,9 @@ pdf_document_get_info (EvDocument *document)
        PopplerPermissions permissions;
        EvPage *page;
        char *metadata;
-       char *fmt;
+#ifdef HAVE_POPPLER_DOCUMENT_IS_LINEARIZED
+       gboolean linearized;
+#endif
 
        info = g_new0 (EvDocumentInfo, 1);
 
@@ -696,7 +744,8 @@ pdf_document_get_info (EvDocument *document)
                            EV_DOCUMENT_INFO_LINEARIZED |
                            EV_DOCUMENT_INFO_N_PAGES |
                            EV_DOCUMENT_INFO_SECURITY | 
-                           EV_DOCUMENT_INFO_PAPER_SIZE;
+                           EV_DOCUMENT_INFO_PAPER_SIZE |
+                           EV_DOCUMENT_INFO_LICENSE;
 
        g_object_get (PDF_DOCUMENT (document)->document,
                      "title", &(info->title),
@@ -712,29 +761,25 @@ pdf_document_get_info (EvDocument *document)
                      "producer", &(info->producer),
                      "creation-date", &(info->creation_date),
                      "mod-date", &(info->modified_date),
+#ifdef HAVE_POPPLER_DOCUMENT_IS_LINEARIZED
+                     "linearized", &linearized,
+#else
                      "linearized", &(info->linearized),
+#endif
                      "metadata", &metadata,
                      NULL);
 
        if (metadata != NULL) {
-               fmt = pdf_document_get_format_from_metadata(metadata);
-               if (fmt != NULL) {
-                       g_free (info->format);
-                       info->format = fmt;
-               }
+               pdf_document_parse_metadata (metadata, info);
                g_free (metadata);
        }
 
        info->n_pages = ev_document_get_n_pages (document);
 
        if (info->n_pages > 0) {
-               page = ev_document_get_page (document, 0);
-               ev_document_get_page_size (document, page,
+               ev_document_get_page_size (document, 0,
                                           &(info->paper_width),
                                           &(info->paper_height));
-               g_object_unref (page);
-               
-
                // Convert to mm.
                info->paper_width = info->paper_width / 72.0f * 25.4f;
                info->paper_height = info->paper_height / 72.0f * 25.4f;
@@ -826,26 +871,85 @@ pdf_document_get_info (EvDocument *document)
                info->security = g_strdup (_("No"));
        }
 
+#ifdef HAVE_POPPLER_DOCUMENT_IS_LINEARIZED
+       info->linearized = linearized ? g_strdup (_("Yes")) : g_strdup (_("No"));
+#endif
+
        return info;
 }
 
+static gboolean
+pdf_document_get_backend_info (EvDocument *document, EvDocumentBackendInfo *info)
+{
+       PopplerBackend backend;
+
+       backend = poppler_get_backend ();
+       switch (backend) {
+               case POPPLER_BACKEND_CAIRO:
+                       info->name = "poppler/cairo";
+                       break;
+               case POPPLER_BACKEND_SPLASH:
+                       info->name = "poppler/splash";
+                       break;
+               default:
+                       info->name = "poppler/unknown";
+                       break;
+       }
+
+       info->version = poppler_get_version ();
+
+       return TRUE;
+}
+
+static gboolean
+pdf_document_support_synctex (EvDocument *document)
+{
+       return TRUE;
+}
+
 static void
-pdf_document_document_iface_init (EvDocumentIface *iface)
-{
-       iface->save = pdf_document_save;
-       iface->load = pdf_document_load;
-       iface->get_n_pages = pdf_document_get_n_pages;
-       iface->get_page = pdf_document_get_page;
-       iface->get_page_size = pdf_document_get_page_size;
-       iface->get_page_label = pdf_document_get_page_label;
-       iface->has_attachments = pdf_document_has_attachments;
-       iface->get_attachments = pdf_document_get_attachments;
-       iface->render = pdf_document_render;
-       iface->get_info = pdf_document_get_info;
-};
+pdf_document_class_init (PdfDocumentClass *klass)
+{
+       GObjectClass    *g_object_class = G_OBJECT_CLASS (klass);
+       EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
+
+       g_object_class->dispose = pdf_document_dispose;
+
+       ev_document_class->save = pdf_document_save;
+       ev_document_class->load = pdf_document_load;
+       ev_document_class->get_n_pages = pdf_document_get_n_pages;
+       ev_document_class->get_page = pdf_document_get_page;
+       ev_document_class->get_page_size = pdf_document_get_page_size;
+       ev_document_class->get_page_label = pdf_document_get_page_label;
+       ev_document_class->render = pdf_document_render;
+       ev_document_class->get_thumbnail = pdf_document_get_thumbnail;
+       ev_document_class->get_info = pdf_document_get_info;
+       ev_document_class->get_backend_info = pdf_document_get_backend_info;
+       ev_document_class->support_synctex = pdf_document_support_synctex;
+}
+
+/* EvDocumentSecurity */
+static gboolean
+pdf_document_has_document_security (EvDocumentSecurity *document_security)
+{
+       /* FIXME: do we really need to have this? */
+       return FALSE;
+}
+
+static void
+pdf_document_set_password (EvDocumentSecurity *document_security,
+                          const char         *password)
+{
+       PdfDocument *document = PDF_DOCUMENT (document_security);
+
+       if (document->password)
+               g_free (document->password);
+
+       document->password = g_strdup (password);
+}
 
 static void
-pdf_document_security_iface_init (EvDocumentSecurityIface *iface)
+pdf_document_security_iface_init (EvDocumentSecurityInterface *iface)
 {
        iface->has_document_security = pdf_document_has_document_security;
        iface->set_password = pdf_document_set_password;
@@ -965,7 +1069,7 @@ pdf_document_fonts_fill_model (EvDocumentFonts *document_fonts,
 }
 
 static void
-pdf_document_document_fonts_iface_init (EvDocumentFontsIface *iface)
+pdf_document_document_fonts_iface_init (EvDocumentFontsInterface *iface)
 {
        iface->fill_model = pdf_document_fonts_fill_model;
        iface->scan = pdf_document_fonts_scan;
@@ -1015,9 +1119,11 @@ ev_link_dest_from_dest (PdfDocument *pdf_document,
                        g_object_unref (poppler_page);
                }
                        break;
-               case POPPLER_DEST_FIT:
+               case POPPLER_DEST_FITB:
+               case POPPLER_DEST_FIT:
                        ev_dest = ev_link_dest_new_fit (dest->page_num - 1);
                        break;
+               case POPPLER_DEST_FITBH:
                case POPPLER_DEST_FITH: {
                        PopplerPage *poppler_page;
                        double height;
@@ -1031,6 +1137,7 @@ ev_link_dest_from_dest (PdfDocument *pdf_document,
                        g_object_unref (poppler_page);
                }
                        break;
+               case POPPLER_DEST_FITBV:
                case POPPLER_DEST_FITV:
                        ev_dest = ev_link_dest_new_fitv (dest->page_num - 1,
                                                         dest->left,
@@ -1051,15 +1158,6 @@ ev_link_dest_from_dest (PdfDocument *pdf_document,
                        g_object_unref (poppler_page);
                }
                        break;
-               case POPPLER_DEST_FITB:
-                       unimplemented_dest = "POPPLER_DEST_FITB";
-                       break;
-               case POPPLER_DEST_FITBH:
-                       unimplemented_dest = "POPPLER_DEST_FITBH";
-                       break;
-               case POPPLER_DEST_FITBV:
-                       unimplemented_dest = "POPPLER_DEST_FITBV";
-                       break;
                case POPPLER_DEST_NAMED:
                        ev_dest = ev_link_dest_new_named (dest->named_dest);
                        break;
@@ -1121,6 +1219,53 @@ ev_link_from_action (PdfDocument   *pdf_document,
                case POPPLER_ACTION_MOVIE:
                        unimplemented_action = "POPPLER_ACTION_MOVIE";
                        break;
+#if POPPLER_CHECK_VERSION (0, 13, 2)
+               case POPPLER_ACTION_RENDITION:
+                       unimplemented_action = "POPPLER_ACTION_RENDITION";
+                       break;
+               case POPPLER_ACTION_OCG_STATE: {
+                       GList *on_list = NULL;
+                       GList *off_list = NULL;
+                       GList *toggle_list = NULL;
+                       GList *l, *m;
+
+                       for (l = action->ocg_state.state_list; l; l = g_list_next (l)) {
+                               PopplerActionLayer *action_layer = (PopplerActionLayer *)l->data;
+
+                               for (m = action_layer->layers; m; m = g_list_next (m)) {
+                                       PopplerLayer *layer = (PopplerLayer *)m->data;
+                                       EvLayer      *ev_layer;
+
+                                       ev_layer = ev_layer_new (poppler_layer_is_parent (layer),
+                                                                poppler_layer_get_radio_button_group_id (layer));
+                                       g_object_set_data_full (G_OBJECT (ev_layer),
+                                                               "poppler-layer",
+                                                               g_object_ref (layer),
+                                                               (GDestroyNotify)g_object_unref);
+
+                                       switch (action_layer->action) {
+                                       case POPPLER_ACTION_LAYER_ON:
+                                               on_list = g_list_prepend (on_list, ev_layer);
+                                               break;
+                                       case POPPLER_ACTION_LAYER_OFF:
+                                               off_list = g_list_prepend (off_list, ev_layer);
+                                               break;
+                                       case POPPLER_ACTION_LAYER_TOGGLE:
+                                               toggle_list = g_list_prepend (toggle_list, ev_layer);
+                                               break;
+                                       }
+                               }
+                       }
+
+                       /* The action takes the ownership of the lists */
+                       ev_action = ev_link_action_new_layers_state (g_list_reverse (on_list),
+                                                                    g_list_reverse (off_list),
+                                                                    g_list_reverse (toggle_list));
+
+
+               }
+                       break;
+#endif
                case POPPLER_ACTION_UNKNOWN:
                        unimplemented_action = "POPPLER_ACTION_UNKNOWN";
        }
@@ -1157,36 +1302,7 @@ build_tree (PdfDocument      *pdf_document,
                if (!action)
                        continue;
 
-               switch (action->type) {
-                       case POPPLER_ACTION_GOTO_DEST: {
-                               /* For bookmarks, solve named destinations */
-                               if (action->goto_dest.dest->type == POPPLER_DEST_NAMED) {
-                                       PopplerDest *dest;
-                                       EvLinkDest *ev_dest = NULL;
-                                       EvLinkAction *ev_action;
-                                       
-                                       dest = poppler_document_find_dest (pdf_document->document,
-                                                                          action->goto_dest.dest->named_dest);
-                                       if (!dest) {
-                                               link = ev_link_from_action (pdf_document, action);
-                                               break;
-                                       }
-                                       
-                                       ev_dest = ev_link_dest_from_dest (pdf_document, dest);
-                                       poppler_dest_free (dest);
-                                       
-                                       ev_action = ev_link_action_new_dest (ev_dest);
-                                       link = ev_link_new (action->any.title, ev_action);
-                               } else {
-                                       link = ev_link_from_action (pdf_document, action);
-                               }
-                       }
-                               break;
-                       default:
-                               link = ev_link_from_action (pdf_document, action);
-                               break;
-               }
-               
+               link = ev_link_from_action (pdf_document, action);
                if (!link || strlen (ev_link_get_title (link)) <= 0) {
                        poppler_action_free (action);
                        if (link)
@@ -1240,9 +1356,9 @@ pdf_document_links_get_links_model (EvDocumentLinks *document_links)
        return model;
 }
 
-static GList *
+static EvMappingList *
 pdf_document_links_get_links (EvDocumentLinks *document_links,
-                             gint             page)
+                             EvPage          *page)
 {
        PdfDocument *pdf_document;
        PopplerPage *poppler_page;
@@ -1252,32 +1368,30 @@ pdf_document_links_get_links (EvDocumentLinks *document_links,
        double height;
 
        pdf_document = PDF_DOCUMENT (document_links);
-       poppler_page = poppler_document_get_page (pdf_document->document,
-                                                 page);
+       poppler_page = POPPLER_PAGE (page->backend_page);
        mapping_list = poppler_page_get_link_mapping (poppler_page);
        poppler_page_get_size (poppler_page, NULL, &height);
 
        for (list = mapping_list; list; list = list->next) {
                PopplerLinkMapping *link_mapping;
-               EvLinkMapping *ev_link_mapping;
+               EvMapping *ev_link_mapping;
 
                link_mapping = (PopplerLinkMapping *)list->data;
-               ev_link_mapping = g_new (EvLinkMapping, 1);
-               ev_link_mapping->link = ev_link_from_action (pdf_document,
+               ev_link_mapping = g_new (EvMapping, 1);
+               ev_link_mapping->data = ev_link_from_action (pdf_document,
                                                             link_mapping->action);
-               ev_link_mapping->x1 = link_mapping->area.x1;
-               ev_link_mapping->x2 = link_mapping->area.x2;
+               ev_link_mapping->area.x1 = link_mapping->area.x1;
+               ev_link_mapping->area.x2 = link_mapping->area.x2;
                /* Invert this for X-style coordinates */
-               ev_link_mapping->y1 = height - link_mapping->area.y2;
-               ev_link_mapping->y2 = height - link_mapping->area.y1;
+               ev_link_mapping->area.y1 = height - link_mapping->area.y2;
+               ev_link_mapping->area.y2 = height - link_mapping->area.y1;
 
                retval = g_list_prepend (retval, ev_link_mapping);
        }
 
        poppler_page_free_link_mapping (mapping_list);
-       g_object_unref (poppler_page);
 
-       return g_list_reverse (retval);
+       return ev_mapping_list_new (page->index, g_list_reverse (retval), (GDestroyNotify)g_object_unref);
 }
 
 static EvLinkDest *
@@ -1299,18 +1413,38 @@ pdf_document_links_find_link_dest (EvDocumentLinks  *document_links,
        return ev_dest;
 }
 
+static gint
+pdf_document_links_find_link_page (EvDocumentLinks  *document_links,
+                                  const gchar      *link_name)
+{
+       PdfDocument *pdf_document;
+       PopplerDest *dest;
+       gint         retval = -1;
+
+       pdf_document = PDF_DOCUMENT (document_links);
+       dest = poppler_document_find_dest (pdf_document->document,
+                                          link_name);
+       if (dest) {
+               retval = dest->page_num - 1;
+               poppler_dest_free (dest);
+       }
+
+       return retval;
+}
+
 static void
-pdf_document_document_links_iface_init (EvDocumentLinksIface *iface)
+pdf_document_document_links_iface_init (EvDocumentLinksInterface *iface)
 {
        iface->has_document_links = pdf_document_links_has_document_links;
        iface->get_links_model = pdf_document_links_get_links_model;
        iface->get_links = pdf_document_links_get_links;
        iface->find_link_dest = pdf_document_links_find_link_dest;
+       iface->find_link_page = pdf_document_links_find_link_page;
 }
 
-static GList *
+static EvMappingList *
 pdf_document_images_get_image_mapping (EvDocumentImages *document_images,
-                                      gint              page)
+                                      EvPage           *page)
 {
        GList *retval = NULL;
        PdfDocument *pdf_document;
@@ -1319,30 +1453,29 @@ pdf_document_images_get_image_mapping (EvDocumentImages *document_images,
        GList *list;
 
        pdf_document = PDF_DOCUMENT (document_images);
-       poppler_page = poppler_document_get_page (pdf_document->document, page);
+       poppler_page = POPPLER_PAGE (page->backend_page);
        mapping_list = poppler_page_get_image_mapping (poppler_page);
 
        for (list = mapping_list; list; list = list->next) {
                PopplerImageMapping *image_mapping;
-               EvImageMapping *ev_image_mapping;
+               EvMapping *ev_image_mapping;
 
                image_mapping = (PopplerImageMapping *)list->data;
 
-               ev_image_mapping = g_new (EvImageMapping, 1);
+               ev_image_mapping = g_new (EvMapping, 1);
                
-               ev_image_mapping->image = ev_image_new (page, image_mapping->image_id);
-               ev_image_mapping->x1 = image_mapping->area.x1;
-               ev_image_mapping->x2 = image_mapping->area.x2;
-               ev_image_mapping->y1 = image_mapping->area.y1;
-               ev_image_mapping->y2 = image_mapping->area.y2;
+               ev_image_mapping->data = ev_image_new (page->index, image_mapping->image_id);
+               ev_image_mapping->area.x1 = image_mapping->area.x1;
+               ev_image_mapping->area.y1 = image_mapping->area.y1;
+               ev_image_mapping->area.x2 = image_mapping->area.x2;
+               ev_image_mapping->area.y2 = image_mapping->area.y2;
 
                retval = g_list_prepend (retval, ev_image_mapping);
        }
 
        poppler_page_free_image_mapping (mapping_list);
-       g_object_unref (poppler_page);
 
-       return g_list_reverse (retval);
+       return ev_mapping_list_new (page->index, g_list_reverse (retval), (GDestroyNotify)g_object_unref);
 }
 
 GdkPixbuf *
@@ -1350,7 +1483,6 @@ pdf_document_images_get_image (EvDocumentImages *document_images,
                               EvImage          *image)
 {
        GdkPixbuf       *retval = NULL;
-#ifdef HAVE_POPPLER_PAGE_GET_IMAGE
        PdfDocument     *pdf_document;
        PopplerPage     *poppler_page;
        cairo_surface_t *surface;
@@ -1366,139 +1498,17 @@ pdf_document_images_get_image (EvDocumentImages *document_images,
        }
 
        g_object_unref (poppler_page);
-#endif
+
        return retval;
 }
 
 static void
-pdf_document_document_images_iface_init (EvDocumentImagesIface *iface)
+pdf_document_document_images_iface_init (EvDocumentImagesInterface *iface)
 {
        iface->get_image_mapping = pdf_document_images_get_image_mapping;
        iface->get_image = pdf_document_images_get_image;
 }
 
-static GdkPixbuf *
-make_thumbnail_for_page (PopplerPage     *poppler_page,
-                        EvRenderContext *rc,
-                        gint             width,
-                        gint             height)
-{
-       GdkPixbuf *pixbuf;
-
-#ifdef POPPLER_WITH_GDK
-       pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
-                                width, height);
-       gdk_pixbuf_fill (pixbuf, 0xffffffff);
-
-       ev_document_fc_mutex_lock ();
-       poppler_page_render_to_pixbuf (poppler_page, 0, 0,
-                                      width, height,
-                                      rc->scale, rc->rotation, pixbuf);
-       ev_document_fc_mutex_unlock ();
-#else
-       cairo_surface_t *surface;
-
-       ev_document_fc_mutex_lock ();
-       surface = pdf_page_render (poppler_page, width, height, rc);
-       ev_document_fc_mutex_unlock ();
-       
-       pixbuf = ev_document_misc_pixbuf_from_surface (surface);
-       cairo_surface_destroy (surface);
-#endif /* POPPLER_WITH_GDK */
-
-       return pixbuf;
-}
-
-static GdkPixbuf *
-pdf_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document_thumbnails,
-                                      EvRenderContext      *rc, 
-                                      gboolean              border)
-{
-       PdfDocument *pdf_document = PDF_DOCUMENT (document_thumbnails);
-       PopplerPage *poppler_page;
-       GdkPixbuf *pixbuf = NULL;
-       GdkPixbuf *border_pixbuf;
-       gint width, height;
-
-       poppler_page = POPPLER_PAGE (rc->page->backend_page);
-
-       pdf_document_thumbnails_get_dimensions (EV_DOCUMENT_THUMBNAILS (pdf_document),
-                                               rc, &width, &height);
-       
-#ifdef POPPLER_WITH_GDK
-       pixbuf = poppler_page_get_thumbnail_pixbuf (poppler_page);
-#else
-       cairo_surface_t *surface;
-       
-       surface = poppler_page_get_thumbnail (poppler_page);
-       if (surface) {
-               pixbuf = ev_document_misc_pixbuf_from_surface (surface);
-               cairo_surface_destroy (surface);
-       }
-#endif /* POPPLER_WITH_GDK */
-
-       if (pixbuf != NULL) {
-               int thumb_width = (rc->rotation == 90 || rc->rotation == 270) ?
-                       gdk_pixbuf_get_height (pixbuf) :
-                       gdk_pixbuf_get_width (pixbuf);
-
-               if (thumb_width == width) {
-                       GdkPixbuf *rotated_pixbuf;
-
-                       rotated_pixbuf = gdk_pixbuf_rotate_simple (pixbuf,
-                                                                  (GdkPixbufRotation) (360 - rc->rotation));
-                       g_object_unref (pixbuf);
-                       pixbuf = rotated_pixbuf;
-               } else {
-                       /* The provided thumbnail has a different size */
-                       g_object_unref (pixbuf);
-                       pixbuf = make_thumbnail_for_page (poppler_page, rc, width, height);
-               }
-       } else {
-               /* There is no provided thumbnail. We need to make one. */
-               pixbuf = make_thumbnail_for_page (poppler_page, rc, width, height);
-       }
-
-        if (border && pixbuf) {
-               border_pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, pixbuf);
-               g_object_unref (pixbuf);
-               pixbuf = border_pixbuf;
-       }               
-
-       return pixbuf;
-}
-
-static void
-pdf_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnails,
-                                       EvRenderContext      *rc,
-                                       gint                 *width,
-                                       gint                 *height)
-{
-       double page_width, page_height;
-       
-       poppler_page_get_size (POPPLER_PAGE (rc->page->backend_page),
-                              &page_width, &page_height);
-       
-       *width = MAX ((gint)(page_width * rc->scale + 0.5), 1);
-       *height = MAX ((gint)(page_height * rc->scale + 0.5), 1);
-
-       if (rc->rotation == 90 || rc->rotation == 270) {
-               gint  temp;
-
-               temp = *width;
-               *width = *height;
-               *height = temp;
-       }
-}
-
-static void
-pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
-{
-       iface->get_thumbnail = pdf_document_thumbnails_get_thumbnail;
-       iface->get_dimensions = pdf_document_thumbnails_get_dimensions;
-}
-
-
 static GList *
 pdf_document_find_find_text (EvDocumentFind *document_find,
                             EvPage         *page,
@@ -1508,7 +1518,8 @@ pdf_document_find_find_text (EvDocumentFind *document_find,
        GList *matches, *l;
        PopplerPage *poppler_page;
        gdouble height;
-       
+       GList *retval = NULL;
+
        g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
        g_return_val_if_fail (text != NULL, NULL);
 
@@ -1521,18 +1532,26 @@ pdf_document_find_find_text (EvDocumentFind *document_find,
        poppler_page_get_size (poppler_page, NULL, &height);
        for (l = matches; l && l->data; l = g_list_next (l)) {
                PopplerRectangle *rect = (PopplerRectangle *)l->data;
-               gdouble           tmp;
+               EvRectangle      *ev_rect;
 
-               tmp = rect->y1;
-               rect->y1 = height - rect->y2;
-               rect->y2 = height - tmp;
+               ev_rect = ev_rectangle_new ();
+               ev_rect->x1 = rect->x1;
+               ev_rect->x2 = rect->x2;
+               /* Invert this for X-style coordinates */
+               ev_rect->y1 = height - rect->y2;
+               ev_rect->y2 = height - rect->y1;
+
+               retval = g_list_prepend (retval, ev_rect);
        }
-       
-       return matches;
+
+       g_list_foreach (matches, (GFunc)poppler_rectangle_free, NULL);
+       g_list_free (matches);
+
+       return g_list_reverse (retval);
 }
 
 static void
-pdf_document_find_iface_init (EvDocumentFindIface *iface)
+pdf_document_find_iface_init (EvDocumentFindInterface *iface)
 {
         iface->find_text = pdf_document_find_find_text;
 }
@@ -1802,21 +1821,17 @@ pdf_document_file_exporter_get_capabilities (EvFileExporter *exporter)
                EV_FILE_EXPORTER_CAN_REVERSE |
                EV_FILE_EXPORTER_CAN_SCALE |
 #ifdef HAVE_CAIRO_PRINT
-#ifdef HAVE_POPPLER_PAGE_RENDER
                EV_FILE_EXPORTER_CAN_NUMBER_UP |
 #endif
-#endif
                
 #ifdef HAVE_CAIRO_PDF
-#ifdef HAVE_POPPLER_PAGE_RENDER
                EV_FILE_EXPORTER_CAN_GENERATE_PDF |
-#endif
 #endif
                EV_FILE_EXPORTER_CAN_GENERATE_PS);
 }
 
 static void
-pdf_document_file_exporter_iface_init (EvFileExporterIface *iface)
+pdf_document_file_exporter_iface_init (EvFileExporterInterface *iface)
 {
         iface->begin = pdf_document_file_exporter_begin;
        iface->begin_page = pdf_document_file_exporter_begin_page;
@@ -1826,7 +1841,6 @@ pdf_document_file_exporter_iface_init (EvFileExporterIface *iface)
        iface->get_capabilities = pdf_document_file_exporter_get_capabilities;
 }
 
-#ifdef HAVE_POPPLER_PAGE_RENDER
 /* EvDocumentPrint */
 static void
 pdf_document_print_print_page (EvDocumentPrint *document,
@@ -1839,11 +1853,10 @@ pdf_document_print_print_page (EvDocumentPrint *document,
 }
 
 static void
-pdf_document_document_print_iface_init (EvDocumentPrintIface *iface)
+pdf_document_document_print_iface_init (EvDocumentPrintInterface *iface)
 {
        iface->print_page = pdf_document_print_print_page;
 }
-#endif /* HAVE_POPPLER_PAGE_RENDER */
 
 static void
 pdf_selection_render_selection (EvSelection      *selection,
@@ -1856,6 +1869,8 @@ pdf_selection_render_selection (EvSelection      *selection,
                                GdkColor         *base)
 {
        PopplerPage *poppler_page;
+       cairo_t *cr;
+       PopplerColor text_color, base_color;
        double width_points, height_points;
        gint width, height;
 
@@ -1866,10 +1881,6 @@ pdf_selection_render_selection (EvSelection      *selection,
        width = (int) ((width_points * rc->scale) + 0.5);
        height = (int) ((height_points * rc->scale) + 0.5);
 
-#ifdef HAVE_POPPLER_PAGE_RENDER
-       cairo_t *cr;
-       PopplerColor text_color, base_color;
-       
        text_color.red = text->red;
        text_color.green = text->green;
        text_color.blue = text->blue;
@@ -1898,39 +1909,26 @@ pdf_selection_render_selection (EvSelection      *selection,
                                       &text_color,
                                       &base_color);
        cairo_destroy (cr);
-#else /* HAVE_POPPLER_PAGE_RENDER */
-       GdkPixbuf *pixbuf;
-       
-       pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
-                                TRUE, 8,
-                                width, height);
-
-       poppler_page_render_selection_to_pixbuf (poppler_page,
-                                                rc->scale, rc->rotation, pixbuf,
-                                                (PopplerRectangle *)points,
-                                                (PopplerRectangle *)old_points,
-                                                (PopplerSelectionStyle)style,
-                                                text,
-                                                base);
-       if (*surface)
-               cairo_surface_destroy (*surface);
-       *surface = ev_document_misc_surface_from_pixbuf (pixbuf);
-       g_object_unref (pixbuf);
-#endif /* HAVE_POPPLER_PAGE_RENDER */
 }
 
 static gchar *
 pdf_selection_get_selected_text (EvSelection     *selection,
-                                EvRenderContext *rc,
+                                EvPage          *page,
                                 EvSelectionStyle style,
                                 EvRectangle     *points)
 {
        PopplerPage *poppler_page;
+       char *retval;
+
+       poppler_page = POPPLER_PAGE (page->backend_page);
+
+#ifdef HAVE_POPPLER_PAGE_GET_SELECTED_TEXT
+       retval = poppler_page_get_selected_text (poppler_page,
+                                                (PopplerSelectionStyle)style,
+                                                (PopplerRectangle *)points);
+#else
        PopplerRectangle r;
        double height;
-       char *retval;
-       
-       poppler_page = POPPLER_PAGE (rc->page->backend_page);
 
        poppler_page_get_size (poppler_page, NULL, &height);
        r.x1 = points->x1;
@@ -1941,89 +1939,154 @@ pdf_selection_get_selected_text (EvSelection     *selection,
        retval = poppler_page_get_text (poppler_page,
                                        (PopplerSelectionStyle)style,
                                        &r);
+#endif /* HAVE_POPPLER_PAGE_GET_SELECTED_TEXT */
 
        return retval;
 }
 
-static GdkRegion *
-create_gdk_region_from_poppler_region (GList *region)
+static cairo_region_t *
+create_region_from_poppler_region (GList *region, gdouble scale)
 {
        GList *l;
-       GdkRegion *retval;
-       
-       retval = gdk_region_new ();
-       
+       cairo_region_t *retval;
+
+       retval = cairo_region_create ();
+
        for (l = region; l; l = g_list_next (l)) {
-               PopplerRectangle *rectangle;
-               GdkRectangle      rect;
-               
+               PopplerRectangle   *rectangle;
+               cairo_rectangle_int_t rect;
+
                rectangle = (PopplerRectangle *)l->data;
-               
-               rect.x = (gint) rectangle->x1;
-               rect.y = (gint) rectangle->y1;
-               rect.width  = (gint) (rectangle->x2 - rectangle->x1);
-               rect.height = (gint) (rectangle->y2 - rectangle->y1);
-               gdk_region_union_with_rect (retval, &rect);
-               
+
+               rect.x = (gint) ((rectangle->x1 * scale) + 0.5);
+               rect.y = (gint) ((rectangle->y1 * scale) + 0.5);
+               rect.width  = (gint) (((rectangle->x2 - rectangle->x1) * scale) + 0.5);
+               rect.height = (gint) (((rectangle->y2 - rectangle->y1) * scale) + 0.5);
+               cairo_region_union_rectangle (retval, &rect);
+
                poppler_rectangle_free (rectangle);
        }
 
        return retval;
 }
 
-static GdkRegion *
+static cairo_region_t *
 pdf_selection_get_selection_region (EvSelection     *selection,
                                    EvRenderContext *rc,
                                    EvSelectionStyle style,
                                    EvRectangle     *points)
 {
-       PopplerPage *poppler_page;
-       GdkRegion   *retval;
-       GList       *region;
+       PopplerPage    *poppler_page;
+       cairo_region_t *retval;
+       GList          *region;
 
        poppler_page = POPPLER_PAGE (rc->page->backend_page);
-       
        region = poppler_page_get_selection_region (poppler_page,
-                                                   rc->scale,
+                                                   1.0,
                                                    (PopplerSelectionStyle)style,
                                                    (PopplerRectangle *) points);
-       retval = create_gdk_region_from_poppler_region (region);
+       retval = create_region_from_poppler_region (region, rc->scale);
        g_list_free (region);
        
        return retval;
 }
 
-static GdkRegion *
-pdf_selection_get_selection_map (EvSelection     *selection,
-                                EvRenderContext *rc)
+static void
+pdf_selection_iface_init (EvSelectionInterface *iface)
+{
+        iface->render_selection = pdf_selection_render_selection;
+       iface->get_selected_text = pdf_selection_get_selected_text;
+        iface->get_selection_region = pdf_selection_get_selection_region;
+}
+
+
+/* EvDocumentText */
+static cairo_region_t *
+pdf_document_text_get_text_mapping (EvDocumentText *document_text,
+                                   EvPage         *page)
 {
        PopplerPage *poppler_page;
        PopplerRectangle points;
        GList *region;
-       GdkRegion *retval;
+       cairo_region_t *retval;
 
-       poppler_page = POPPLER_PAGE (rc->page->backend_page);
+       g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
+
+       poppler_page = POPPLER_PAGE (page->backend_page);
 
        points.x1 = 0.0;
        points.y1 = 0.0;
        poppler_page_get_size (poppler_page, &(points.x2), &(points.y2));
-       
+
        region = poppler_page_get_selection_region (poppler_page, 1.0,
                                                    POPPLER_SELECTION_GLYPH,
                                                    &points);
-       retval = create_gdk_region_from_poppler_region (region);
+       retval = create_region_from_poppler_region (region, 1.0);
        g_list_free (region);
 
        return retval;
 }
 
+#ifdef HAVE_POPPLER_PAGE_GET_SELECTED_TEXT
+static gchar *
+pdf_document_text_get_text (EvDocumentText  *selection,
+                           EvPage          *page)
+{
+       PopplerPage *poppler_page;
+
+       g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
+
+       poppler_page = POPPLER_PAGE (page->backend_page);
+
+       return poppler_page_get_text (poppler_page);
+}
+#else
+static gchar *
+pdf_document_text_get_text (EvDocumentText  *selection,
+                           EvPage          *page)
+{
+       PopplerPage *poppler_page;
+       PopplerRectangle r;
+
+       g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
+
+       poppler_page = POPPLER_PAGE (page->backend_page);
+
+       r.x1 = 0;
+       r.y1 = 0;
+       poppler_page_get_size (poppler_page, &(r.x2), &(r.y2));
+
+       return poppler_page_get_text (poppler_page,
+                                     POPPLER_SELECTION_WORD,
+                                     &r);
+}
+#endif /* HAVE_POPPLER_PAGE_GET_SELECTED_TEXT */
+
+#ifdef HAVE_POPPLER_PAGE_GET_TEXT_LAYOUT
+static gboolean
+pdf_document_text_get_text_layout (EvDocumentText  *selection,
+                                  EvPage          *page,
+                                  EvRectangle    **areas,
+                                  guint           *n_areas)
+{
+       PopplerPage *poppler_page;
+
+       g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
+
+       poppler_page = POPPLER_PAGE (page->backend_page);
+
+       return poppler_page_get_text_layout (poppler_page, (PopplerRectangle **)areas, n_areas);
+}
+#endif
+
 static void
-pdf_selection_iface_init (EvSelectionIface *iface)
+pdf_document_text_iface_init (EvDocumentTextInterface *iface)
 {
-        iface->render_selection = pdf_selection_render_selection;
-       iface->get_selected_text = pdf_selection_get_selected_text;
-        iface->get_selection_region = pdf_selection_get_selection_region;
-        iface->get_selection_map = pdf_selection_get_selection_map;
+        iface->get_text_mapping = pdf_document_text_get_text_mapping;
+        iface->get_text = pdf_document_text_get_text;
+#ifdef HAVE_POPPLER_PAGE_GET_TEXT_LAYOUT
+        iface->get_text_layout = pdf_document_text_get_text_layout;
+#endif
 }
 
 /* Page Transitions */
@@ -2085,7 +2148,7 @@ pdf_document_get_effect (EvDocumentTransition *trans,
 }
 
 static void
-pdf_document_page_transition_iface_init (EvDocumentTransitionIface *iface)
+pdf_document_page_transition_iface_init (EvDocumentTransitionInterface *iface)
 {
        iface->get_page_duration = pdf_document_get_page_duration;
        iface->get_effect = pdf_document_get_effect;
@@ -2214,7 +2277,7 @@ ev_form_field_from_poppler_field (PopplerFormField *poppler_field)
        return ev_field;
 }
 
-static GList *
+static EvMappingList *
 pdf_document_forms_get_form_fields (EvDocumentForms *document, 
                                    EvPage          *page)
 {
@@ -2232,7 +2295,7 @@ pdf_document_forms_get_form_fields (EvDocumentForms *document,
 
        for (list = fields; list; list = list->next) {
                PopplerFormFieldMapping *mapping;
-               EvFormFieldMapping *field_mapping;
+               EvMapping *field_mapping;
                EvFormField *ev_field;
 
                mapping = (PopplerFormFieldMapping *)list->data;
@@ -2241,13 +2304,13 @@ pdf_document_forms_get_form_fields (EvDocumentForms *document,
                if (!ev_field)
                        continue;
 
-               field_mapping = g_new0 (EvFormFieldMapping, 1);
-               field_mapping->x1 = mapping->area.x1;
-               field_mapping->x2 = mapping->area.x2;
-               field_mapping->y1 = height - mapping->area.y2;
-               field_mapping->y2 = height - mapping->area.y1;
-               field_mapping->field = ev_field;
-               field_mapping->field->page = EV_PAGE (g_object_ref (page));
+               field_mapping = g_new0 (EvMapping, 1);
+               field_mapping->area.x1 = mapping->area.x1;
+               field_mapping->area.x2 = mapping->area.x2;
+               field_mapping->area.y1 = height - mapping->area.y2;
+               field_mapping->area.y2 = height - mapping->area.y1;
+               field_mapping->data = ev_field;
+               ev_field->page = EV_PAGE (g_object_ref (page));
 
                g_object_set_data_full (G_OBJECT (ev_field),
                                        "poppler-field",
@@ -2259,7 +2322,15 @@ pdf_document_forms_get_form_fields (EvDocumentForms *document,
        
        poppler_page_free_form_field_mapping (fields);
 
-       return g_list_reverse (retval);
+       return retval ? ev_mapping_list_new (page->index,
+                                            g_list_reverse (retval),
+                                            (GDestroyNotify)g_object_unref) : NULL;
+}
+
+static gboolean
+pdf_document_forms_document_is_modified (EvDocumentForms *document)
+{
+       return PDF_DOCUMENT (document)->forms_modified;
 }
 
 static gchar *
@@ -2291,7 +2362,7 @@ pdf_document_forms_form_field_text_set_text (EvDocumentForms *document,
                return;
        
        poppler_form_field_text_set_text (poppler_field, text);
-       PDF_DOCUMENT (document)->modified = TRUE;
+       PDF_DOCUMENT (document)->forms_modified = TRUE;
 }
 
 static void
@@ -2306,7 +2377,7 @@ pdf_document_forms_form_field_button_set_state (EvDocumentForms *document,
                return;
        
        poppler_form_field_button_set_state (poppler_field, state);
-       PDF_DOCUMENT (document)->modified = TRUE;
+       PDF_DOCUMENT (document)->forms_modified = TRUE;
 }
 
 static gboolean
@@ -2387,7 +2458,7 @@ pdf_document_forms_form_field_choice_select_item (EvDocumentForms *document,
                return;
 
        poppler_form_field_choice_select_item (poppler_field, index);
-       PDF_DOCUMENT (document)->modified = TRUE;
+       PDF_DOCUMENT (document)->forms_modified = TRUE;
 }
 
 static void
@@ -2402,7 +2473,7 @@ pdf_document_forms_form_field_choice_toggle_item (EvDocumentForms *document,
                return;
 
        poppler_form_field_choice_toggle_item (poppler_field, index);
-       PDF_DOCUMENT (document)->modified = TRUE;
+       PDF_DOCUMENT (document)->forms_modified = TRUE;
 }
 
 static void
@@ -2416,7 +2487,7 @@ pdf_document_forms_form_field_choice_unselect_all (EvDocumentForms *document,
                return;
        
        poppler_form_field_choice_unselect_all (poppler_field);
-       PDF_DOCUMENT (document)->modified = TRUE;
+       PDF_DOCUMENT (document)->forms_modified = TRUE;
 }
 
 static void
@@ -2431,7 +2502,7 @@ pdf_document_forms_form_field_choice_set_text (EvDocumentForms *document,
                return;
        
        poppler_form_field_choice_set_text (poppler_field, text);
-       PDF_DOCUMENT (document)->modified = TRUE;
+       PDF_DOCUMENT (document)->forms_modified = TRUE;
 }
 
 static gchar *
@@ -2451,9 +2522,10 @@ pdf_document_forms_form_field_choice_get_text (EvDocumentForms *document,
 }
 
 static void
-pdf_document_document_forms_iface_init (EvDocumentFormsIface *iface)
+pdf_document_document_forms_iface_init (EvDocumentFormsInterface *iface)
 {
        iface->get_form_fields = pdf_document_forms_get_form_fields;
+       iface->document_is_modified = pdf_document_forms_document_is_modified;
        iface->form_field_text_get_text = pdf_document_forms_form_field_text_get_text;
        iface->form_field_text_set_text = pdf_document_forms_form_field_text_set_text;
        iface->form_field_button_set_state = pdf_document_forms_form_field_button_set_state;
@@ -2485,6 +2557,77 @@ poppler_annot_color_to_gdk_color (PopplerAnnot *poppler_annot,
        } /* TODO: else use a default color */
 }
 
+static EvAnnotationTextIcon
+get_annot_text_icon (PopplerAnnotText *poppler_annot)
+{
+#ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
+       gchar *icon = poppler_annot_text_get_icon (poppler_annot);
+       EvAnnotationTextIcon retval;
+
+       if (!icon)
+               return EV_ANNOTATION_TEXT_ICON_UNKNOWN;
+
+       if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_NOTE) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_NOTE;
+       else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_COMMENT) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_COMMENT;
+       else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_KEY) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_KEY;
+       else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_HELP) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_HELP;
+       else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_NEW_PARAGRAPH) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_NEW_PARAGRAPH;
+       else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_PARAGRAPH) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_PARAGRAPH;
+       else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_INSERT) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_INSERT;
+       else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_CROSS) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_CROSS;
+       else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_CIRCLE) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_CIRCLE;
+       else
+               retval = EV_ANNOTATION_TEXT_ICON_UNKNOWN;
+
+       g_free (icon);
+
+       return retval;
+#else
+       return EV_ANNOTATION_TEXT_ICON_UNKNOWN;
+#endif
+}
+
+static const gchar *
+get_poppler_annot_text_icon (EvAnnotationTextIcon icon)
+{
+#ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
+       switch (icon) {
+       case EV_ANNOTATION_TEXT_ICON_NOTE:
+               return POPPLER_ANNOT_TEXT_ICON_NOTE;
+       case EV_ANNOTATION_TEXT_ICON_COMMENT:
+               return POPPLER_ANNOT_TEXT_ICON_COMMENT;
+       case EV_ANNOTATION_TEXT_ICON_KEY:
+               return POPPLER_ANNOT_TEXT_ICON_KEY;
+       case EV_ANNOTATION_TEXT_ICON_HELP:
+               return POPPLER_ANNOT_TEXT_ICON_HELP;
+       case EV_ANNOTATION_TEXT_ICON_NEW_PARAGRAPH:
+               return POPPLER_ANNOT_TEXT_ICON_NEW_PARAGRAPH;
+       case EV_ANNOTATION_TEXT_ICON_PARAGRAPH:
+               return POPPLER_ANNOT_TEXT_ICON_PARAGRAPH;
+       case EV_ANNOTATION_TEXT_ICON_INSERT:
+               return POPPLER_ANNOT_TEXT_ICON_INSERT;
+       case EV_ANNOTATION_TEXT_ICON_CROSS:
+               return POPPLER_ANNOT_TEXT_ICON_CROSS;
+       case EV_ANNOTATION_TEXT_ICON_CIRCLE:
+               return POPPLER_ANNOT_TEXT_ICON_CIRCLE;
+       case EV_ANNOTATION_TEXT_ICON_UNKNOWN:
+       default:
+               return POPPLER_ANNOT_TEXT_ICON_NOTE;
+       }
+#else
+       return "Note";
+#endif
+}
+
 static EvAnnotation *
 ev_annot_from_poppler_annot (PopplerAnnot *poppler_annot,
                             EvPage       *page)
@@ -2493,7 +2636,7 @@ ev_annot_from_poppler_annot (PopplerAnnot *poppler_annot,
        const gchar  *unimplemented_annot = NULL;
 
        switch (poppler_annot_get_annot_type (poppler_annot)) {
-               case POPPLER_ANNOT_TEXT:
+               case POPPLER_ANNOT_TEXT: {
                        PopplerAnnotText *poppler_text;
                        EvAnnotationText *ev_annot_text;
 
@@ -2502,8 +2645,41 @@ ev_annot_from_poppler_annot (PopplerAnnot *poppler_annot,
                        ev_annot = ev_annotation_text_new (page);
 
                        ev_annot_text = EV_ANNOTATION_TEXT (ev_annot);
-                       ev_annot_text->is_open = poppler_annot_text_get_is_open (poppler_text);
+                       ev_annotation_text_set_is_open (ev_annot_text,
+                                                       poppler_annot_text_get_is_open (poppler_text));
+                       ev_annotation_text_set_icon (ev_annot_text, get_annot_text_icon (poppler_text));
+               }
+                       break;
+               case POPPLER_ANNOT_FILE_ATTACHMENT: {
+                       PopplerAnnotFileAttachment *poppler_annot_attachment;
+                       EvAnnotationAttachment     *ev_annot_attachment;
+                       PopplerAttachment          *poppler_attachment;
+                       gchar                      *data = NULL;
+                       gsize                       size;
+                       GError                     *error = NULL;
+
+                       poppler_annot_attachment = POPPLER_ANNOT_FILE_ATTACHMENT (poppler_annot);
+                       poppler_attachment = poppler_annot_file_attachment_get_attachment (poppler_annot_attachment);
+
+                       if (poppler_attachment &&
+                           attachment_save_to_buffer (poppler_attachment, &data, &size, &error)) {
+                               EvAttachment *ev_attachment;
+
+                               ev_attachment = ev_attachment_new (poppler_attachment->name,
+                                                                  poppler_attachment->description,
+                                                                  poppler_attachment->mtime,
+                                                                  poppler_attachment->ctime,
+                                                                  size, data);
+                               ev_annot = ev_annotation_attachment_new (page, ev_attachment);
+                               g_object_unref (ev_attachment);
+                       } else if (error) {
+                               g_warning ("%s", error->message);
+                               g_error_free (error);
+                       }
 
+                       if (poppler_attachment)
+                               g_object_unref (poppler_attachment);
+               }
                        break;
                case POPPLER_ANNOT_LINK:
                case POPPLER_ANNOT_WIDGET:
@@ -2526,22 +2702,46 @@ ev_annot_from_poppler_annot (PopplerAnnot *poppler_annot,
        }
 
        if (ev_annot) {
-               ev_annot->contents = poppler_annot_get_contents (poppler_annot);
-               ev_annot->name = poppler_annot_get_name (poppler_annot);
-               ev_annot->modified = poppler_annot_get_modified (poppler_annot);
-               poppler_annot_color_to_gdk_color (poppler_annot, &ev_annot->color);
+               time_t   utime;
+               gchar   *modified;
+               gchar   *contents;
+               gchar   *name;
+               GdkColor color;
+
+               contents = poppler_annot_get_contents (poppler_annot);
+               if (contents) {
+                       ev_annotation_set_contents (ev_annot, contents);
+                       g_free (contents);
+               }
+
+               name = poppler_annot_get_name (poppler_annot);
+               if (name) {
+                       ev_annotation_set_name (ev_annot, name);
+                       g_free (name);
+               }
+
+               modified = poppler_annot_get_modified (poppler_annot);
+               if (poppler_date_parse (modified, &utime)) {
+                       ev_annotation_set_modified_from_time (ev_annot, utime);
+               } else {
+                       ev_annotation_set_modified (ev_annot, modified);
+               }
+               g_free (modified);
+
+               poppler_annot_color_to_gdk_color (poppler_annot, &color);
+               ev_annotation_set_color (ev_annot, &color);
 
                if (POPPLER_IS_ANNOT_MARKUP (poppler_annot)) {
                        PopplerAnnotMarkup *markup;
                        gchar *label;
                        gdouble opacity;
-                       gboolean is_open;
                        PopplerRectangle poppler_rect;
 
                        markup = POPPLER_ANNOT_MARKUP (poppler_annot);
 
                        if (poppler_annot_markup_get_popup_rectangle (markup, &poppler_rect)) {
                                EvRectangle ev_rect;
+                               gboolean is_open;
                                gdouble height;
 
                                poppler_page_get_size (POPPLER_PAGE (page->backend_page),
@@ -2551,17 +2751,25 @@ ev_annot_from_poppler_annot (PopplerAnnot *poppler_annot,
                                ev_rect.y1 = height - poppler_rect.y2;
                                ev_rect.y2 = height - poppler_rect.y1;
 
-                               g_object_set (ev_annot, "rectangle", &ev_rect, NULL);
+                               is_open = poppler_annot_markup_get_popup_is_open (markup);
+
+                               g_object_set (ev_annot,
+                                             "rectangle", &ev_rect,
+                                             "popup_is_open", is_open,
+                                             "has_popup", TRUE,
+                                             NULL);
+                       } else {
+                               g_object_set (ev_annot,
+                                             "has_popup", FALSE,
+                                             NULL);
                        }
 
                        label = poppler_annot_markup_get_label (markup);
                        opacity = poppler_annot_markup_get_opacity (markup);
-                       is_open = poppler_annot_markup_get_popup_is_open (markup);
 
                        g_object_set (ev_annot,
                                      "label", label,
                                      "opacity", opacity,
-                                     "is_open", is_open,
                                      NULL);
 
                        g_free (label);
@@ -2571,13 +2779,14 @@ ev_annot_from_poppler_annot (PopplerAnnot *poppler_annot,
        return ev_annot;
 }
 
-static GList *
+static EvMappingList *
 pdf_document_annotations_get_annotations (EvDocumentAnnotations *document_annotations,
                                          EvPage                *page)
 {
        GList *retval = NULL;
        PdfDocument *pdf_document;
        PopplerPage *poppler_page;
+       EvMappingList *mapping_list;
        GList *annots;
        GList *list;
        gdouble height;
@@ -2585,12 +2794,20 @@ pdf_document_annotations_get_annotations (EvDocumentAnnotations *document_annota
 
        pdf_document = PDF_DOCUMENT (document_annotations);
        poppler_page = POPPLER_PAGE (page->backend_page);
+
+       if (pdf_document->annots) {
+               mapping_list = (EvMappingList *)g_hash_table_lookup (pdf_document->annots,
+                                                                    GINT_TO_POINTER (page->index));
+               if (mapping_list)
+                       return ev_mapping_list_ref (mapping_list);
+       }
+
        annots = poppler_page_get_annot_mapping (poppler_page);
        poppler_page_get_size (poppler_page, NULL, &height);
 
        for (list = annots; list; list = list->next) {
                PopplerAnnotMapping *mapping;
-               EvAnnotationMapping *annot_mapping;
+               EvMapping           *annot_mapping;
                EvAnnotation        *ev_annot;
 
                mapping = (PopplerAnnotMapping *)list->data;
@@ -2602,15 +2819,19 @@ pdf_document_annotations_get_annotations (EvDocumentAnnotations *document_annota
                i++;
 
                /* Make sure annot has a unique name */
-               if (!ev_annot->name)
-                       ev_annot->name = g_strdup_printf ("annot-%d-%d", page->index, i);
+               if (!ev_annotation_get_name (ev_annot)) {
+                       gchar *name = g_strdup_printf ("annot-%d-%d", page->index, i);
 
-               annot_mapping = g_new0 (EvAnnotationMapping, 1);
-               annot_mapping->x1 = mapping->area.x1;
-               annot_mapping->x2 = mapping->area.x2;
-               annot_mapping->y1 = height - mapping->area.y2;
-               annot_mapping->y2 = height - mapping->area.y1;
-               annot_mapping->annotation = ev_annot;
+                       ev_annotation_set_name (ev_annot, name);
+                       g_free (name);
+               }
+
+               annot_mapping = g_new (EvMapping, 1);
+               annot_mapping->area.x1 = mapping->area.x1;
+               annot_mapping->area.x2 = mapping->area.x2;
+               annot_mapping->area.y1 = height - mapping->area.y2;
+               annot_mapping->area.y2 = height - mapping->area.y1;
+               annot_mapping->data = ev_annot;
 
                g_object_set_data_full (G_OBJECT (ev_annot),
                                        "poppler-annot",
@@ -2622,13 +2843,139 @@ pdf_document_annotations_get_annotations (EvDocumentAnnotations *document_annota
 
        poppler_page_free_annot_mapping (annots);
 
-       return g_list_reverse (retval);
+       if (!retval)
+               return NULL;
+
+       if (!pdf_document->annots) {
+               pdf_document->annots = g_hash_table_new_full (g_direct_hash,
+                                                             g_direct_equal,
+                                                             (GDestroyNotify)NULL,
+                                                             (GDestroyNotify)ev_mapping_list_unref);
+       }
+
+       mapping_list = ev_mapping_list_new (page->index, g_list_reverse (retval), (GDestroyNotify)g_object_unref);
+       g_hash_table_insert (pdf_document->annots,
+                            GINT_TO_POINTER (page->index),
+                            ev_mapping_list_ref (mapping_list));
+
+       return mapping_list;
+}
+
+static gboolean
+pdf_document_annotations_document_is_modified (EvDocumentAnnotations *document_annotations)
+{
+       return PDF_DOCUMENT (document_annotations)->annots_modified;
+}
+
+#ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
+static void
+pdf_document_annotations_add_annotation (EvDocumentAnnotations *document_annotations,
+                                        EvAnnotation          *annot,
+                                        EvRectangle           *rect)
+{
+       PopplerAnnot    *poppler_annot;
+       PdfDocument     *pdf_document;
+       EvPage          *page;
+       PopplerPage     *poppler_page;
+       GList           *list = NULL;
+       EvMappingList   *mapping_list;
+       EvMapping       *annot_mapping;
+       PopplerRectangle poppler_rect;
+       gdouble          height;
+       PopplerColor     poppler_color;
+       GdkColor         color;
+       time_t           utime;
+       gchar           *modified;
+       gchar           *name;
+
+       pdf_document = PDF_DOCUMENT (document_annotations);
+       page = ev_annotation_get_page (annot);
+       poppler_page = POPPLER_PAGE (page->backend_page);
+
+       poppler_page_get_size (poppler_page, NULL, &height);
+       poppler_rect.x1 = rect->x1;
+       poppler_rect.x2 = rect->x2;
+       poppler_rect.y1 = height - rect->y2;
+       poppler_rect.y2 = height - rect->y1;
+       poppler_annot = poppler_annot_text_new (pdf_document->document, &poppler_rect);
+
+       ev_annotation_get_color (annot, &color);
+       poppler_color.red = color.red;
+       poppler_color.green = color.green;
+       poppler_color.blue = color.blue;
+       poppler_annot_set_color (poppler_annot, &poppler_color);
+
+       if (EV_IS_ANNOTATION_MARKUP (annot)) {
+               EvAnnotationMarkup *markup = EV_ANNOTATION_MARKUP (annot);
+               const gchar *label;
+
+               if (ev_annotation_markup_has_popup (markup)) {
+                       EvRectangle popup_rect;
+
+                       ev_annotation_markup_get_rectangle (markup, &popup_rect);
+                       poppler_rect.x1 = popup_rect.x1;
+                       poppler_rect.x2 = popup_rect.x2;
+                       poppler_rect.y1 = height - popup_rect.y2;
+                       poppler_rect.y2 = height - popup_rect.y1;
+                       poppler_annot_markup_set_popup (POPPLER_ANNOT_MARKUP (poppler_annot), &poppler_rect);
+                       poppler_annot_markup_set_popup_is_open (POPPLER_ANNOT_MARKUP (poppler_annot),
+                                                               ev_annotation_markup_get_popup_is_open (markup));
+               }
+
+               label = ev_annotation_markup_get_label (markup);
+               if (label)
+                       poppler_annot_markup_set_label (POPPLER_ANNOT_MARKUP (poppler_annot), label);
+       }
+
+       if (EV_IS_ANNOTATION_TEXT (annot)) {
+               EvAnnotationText    *text = EV_ANNOTATION_TEXT (annot);
+               EvAnnotationTextIcon icon;
+
+               icon = ev_annotation_text_get_icon (text);
+               poppler_annot_text_set_icon (POPPLER_ANNOT_TEXT (poppler_annot),
+                                            get_poppler_annot_text_icon (icon));
+       }
+       poppler_page_add_annot (poppler_page, poppler_annot);
+
+       annot_mapping = g_new (EvMapping, 1);
+       annot_mapping->area = *rect;
+       annot_mapping->data = annot;
+       g_object_set_data_full (G_OBJECT (annot),
+                               "poppler-annot",
+                               g_object_ref (poppler_annot),
+                               (GDestroyNotify) g_object_unref);
+
+       if (pdf_document->annots) {
+               mapping_list = (EvMappingList *)g_hash_table_lookup (pdf_document->annots,
+                                                                    GINT_TO_POINTER (page->index));
+               list = ev_mapping_list_get_list (mapping_list);
+               name = g_strdup_printf ("annot-%d-%d", page->index, g_list_length (list) + 1);
+               ev_annotation_set_name (annot, name);
+               g_free (name);
+               list = g_list_append (list, annot_mapping);
+       } else {
+               pdf_document->annots = g_hash_table_new_full (g_direct_hash,
+                                                             g_direct_equal,
+                                                             (GDestroyNotify)NULL,
+                                                             (GDestroyNotify)ev_mapping_list_unref);
+               name = g_strdup_printf ("annot-%d-0", page->index);
+               ev_annotation_set_name (annot, name);
+               g_free (name);
+               list = g_list_append (list, annot_mapping);
+               mapping_list = ev_mapping_list_new (page->index, list, (GDestroyNotify)g_object_unref);
+               g_hash_table_insert (pdf_document->annots,
+                                    GINT_TO_POINTER (page->index),
+                                    ev_mapping_list_ref (mapping_list));
+       }
+
+       pdf_document->annots_modified = TRUE;
 }
+#endif /* HAVE_POPPLER_PAGE_ADD_ANNOT */
 
 static void
-pdf_document_annotations_annotation_set_contents (EvDocumentAnnotations *document,
-                                                 EvAnnotation          *annot,
-                                                 const gchar           *contents)
+pdf_document_annotations_save_annotation (EvDocumentAnnotations *document_annotations,
+                                         EvAnnotation          *annot,
+                                         EvAnnotationsSaveMask  mask)
 {
        PopplerAnnot *poppler_annot;
 
@@ -2636,15 +2983,179 @@ pdf_document_annotations_annotation_set_contents (EvDocumentAnnotations *documen
        if (!poppler_annot)
                return;
 
-       poppler_annot_set_contents (poppler_annot, contents);
-       PDF_DOCUMENT (document)->modified = TRUE;
+       if (mask & EV_ANNOTATIONS_SAVE_CONTENTS)
+               poppler_annot_set_contents (poppler_annot,
+                                           ev_annotation_get_contents (annot));
+
+#ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
+       if (mask & EV_ANNOTATIONS_SAVE_COLOR) {
+               PopplerColor color;
+               GdkColor     ev_color;
+
+               ev_annotation_get_color (annot, &ev_color);
+               color.red = ev_color.red;
+               color.green = ev_color.green;
+               color.blue = ev_color.blue;
+               poppler_annot_set_color (poppler_annot, &color);
+       }
+
+       if (EV_IS_ANNOTATION_MARKUP (annot)) {
+               EvAnnotationMarkup *ev_markup = EV_ANNOTATION_MARKUP (annot);
+               PopplerAnnotMarkup *markup = POPPLER_ANNOT_MARKUP (poppler_annot);
+
+               if (mask & EV_ANNOTATIONS_SAVE_LABEL)
+                       poppler_annot_markup_set_label (markup, ev_annotation_markup_get_label (ev_markup));
+               if (mask & EV_ANNOTATIONS_SAVE_OPACITY)
+                       poppler_annot_markup_set_opacity (markup, ev_annotation_markup_get_opacity (ev_markup));
+               if (mask & EV_ANNOTATIONS_SAVE_POPUP_IS_OPEN)
+                       poppler_annot_markup_set_popup_is_open (markup, ev_annotation_markup_get_popup_is_open (ev_markup));
+       }
+
+       if (EV_IS_ANNOTATION_TEXT (annot)) {
+               EvAnnotationText *ev_text = EV_ANNOTATION_TEXT (annot);
+               PopplerAnnotText *text = POPPLER_ANNOT_TEXT (poppler_annot);
+
+               if (mask & EV_ANNOTATIONS_SAVE_TEXT_IS_OPEN) {
+                       poppler_annot_text_set_is_open (text,
+                                                       ev_annotation_text_get_is_open (ev_text));
+               }
+               if (mask & EV_ANNOTATIONS_SAVE_TEXT_ICON) {
+                       EvAnnotationTextIcon icon;
+
+                       icon = ev_annotation_text_get_icon (ev_text);
+                       poppler_annot_text_set_icon (text, get_poppler_annot_text_icon (icon));
+               }
+       }
+#endif /* HAVE_POPPLER_PAGE_ADD_ANNOT */
+       PDF_DOCUMENT (document_annotations)->annots_modified = TRUE;
 }
 
 static void
-pdf_document_document_annotations_iface_init (EvDocumentAnnotationsIface *iface)
+pdf_document_document_annotations_iface_init (EvDocumentAnnotationsInterface *iface)
 {
        iface->get_annotations = pdf_document_annotations_get_annotations;
-       iface->annotation_set_contents = pdf_document_annotations_annotation_set_contents;
+       iface->document_is_modified = pdf_document_annotations_document_is_modified;
+#ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
+       iface->add_annotation = pdf_document_annotations_add_annotation;
+#endif
+       iface->save_annotation = pdf_document_annotations_save_annotation;
+}
+
+/* Attachments */
+struct SaveToBufferData {
+       gchar *buffer;
+       gsize len, max;
+};
+
+static gboolean
+attachment_save_to_buffer_callback (const gchar  *buf,
+                                   gsize         count,
+                                   gpointer      user_data,
+                                   GError      **error)
+{
+       struct SaveToBufferData *sdata = (SaveToBufferData *)user_data;
+       gchar *new_buffer;
+       gsize new_max;
+
+       if (sdata->len + count > sdata->max) {
+               new_max = MAX (sdata->max * 2, sdata->len + count);
+               new_buffer = (gchar *)g_realloc (sdata->buffer, new_max);
+
+               sdata->buffer = new_buffer;
+               sdata->max = new_max;
+       }
+
+       memcpy (sdata->buffer + sdata->len, buf, count);
+       sdata->len += count;
+
+       return TRUE;
+}
+
+static gboolean
+attachment_save_to_buffer (PopplerAttachment  *attachment,
+                          gchar             **buffer,
+                          gsize              *buffer_size,
+                          GError            **error)
+{
+       static const gint initial_max = 1024;
+       struct SaveToBufferData sdata;
+
+       *buffer = NULL;
+       *buffer_size = 0;
+
+       sdata.buffer = (gchar *) g_malloc (initial_max);
+       sdata.max = initial_max;
+       sdata.len = 0;
+
+       if (! poppler_attachment_save_to_callback (attachment,
+                                                  attachment_save_to_buffer_callback,
+                                                  &sdata,
+                                                  error)) {
+               g_free (sdata.buffer);
+               return FALSE;
+       }
+
+       *buffer = sdata.buffer;
+       *buffer_size = sdata.len;
+
+       return TRUE;
+}
+
+static GList *
+pdf_document_attachments_get_attachments (EvDocumentAttachments *document)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+       GList *attachments;
+       GList *list;
+       GList *retval = NULL;
+
+       attachments = poppler_document_get_attachments (pdf_document->document);
+
+       for (list = attachments; list; list = list->next) {
+               PopplerAttachment *attachment;
+               EvAttachment *ev_attachment;
+               gchar *data = NULL;
+               gsize size;
+               GError *error = NULL;
+
+               attachment = (PopplerAttachment *) list->data;
+
+               if (attachment_save_to_buffer (attachment, &data, &size, &error)) {
+                       ev_attachment = ev_attachment_new (attachment->name,
+                                                          attachment->description,
+                                                          attachment->mtime,
+                                                          attachment->ctime,
+                                                          size, data);
+
+                       retval = g_list_prepend (retval, ev_attachment);
+               } else {
+                       if (error) {
+                               g_warning ("%s", error->message);
+                               g_error_free (error);
+
+                               g_free (data);
+                       }
+               }
+
+               g_object_unref (attachment);
+       }
+
+       return g_list_reverse (retval);
+}
+
+static gboolean
+pdf_document_attachments_has_attachments (EvDocumentAttachments *document)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+
+       return poppler_document_has_attachments (pdf_document->document);
+}
+
+static void
+pdf_document_document_attachments_iface_init (EvDocumentAttachmentsInterface *iface)
+{
+       iface->has_attachments = pdf_document_attachments_has_attachments;
+       iface->get_attachments = pdf_document_attachments_get_attachments;
 }
 
 /* Layers */
@@ -2682,11 +3193,12 @@ build_layers_tree (PdfDocument       *pdf_document,
                        markup = g_markup_escape_text (poppler_layer_get_title (layer), -1);
                        visible = poppler_layer_is_visible (layer);
                        rb_group = poppler_layer_get_radio_button_group_id (layer);
-                       pdf_document->layers = g_list_append (pdf_document->layers,
-                                                             g_object_ref (layer));
-                       ev_layer = ev_layer_new (g_list_length (pdf_document->layers) - 1,
-                                                poppler_layer_is_parent (layer),
+                       ev_layer = ev_layer_new (poppler_layer_is_parent (layer),
                                                 rb_group);
+                       g_object_set_data_full (G_OBJECT (ev_layer),
+                                               "poppler-layer",
+                                               g_object_ref (layer),
+                                               (GDestroyNotify) g_object_unref);
                } else {
                        gchar *title;
 
@@ -2744,34 +3256,37 @@ static void
 pdf_document_layers_show_layer (EvDocumentLayers *document,
                                EvLayer          *layer)
 {
-       PdfDocument *pdf_document = PDF_DOCUMENT (document);
-       guint        layer_id = ev_layer_get_id (layer);
+       PdfDocument  *pdf_document = PDF_DOCUMENT (document);
+       PopplerLayer *poppler_layer;
 
-       poppler_layer_show (POPPLER_LAYER (g_list_nth_data (pdf_document->layers, layer_id)));
+       poppler_layer = POPPLER_LAYER (g_object_get_data (G_OBJECT (layer), "poppler-layer"));
+       poppler_layer_show (poppler_layer);
 }
 
 static void
 pdf_document_layers_hide_layer (EvDocumentLayers *document,
                                EvLayer          *layer)
 {
-       PdfDocument *pdf_document = PDF_DOCUMENT (document);
-       guint        layer_id = ev_layer_get_id (layer);
+       PdfDocument  *pdf_document = PDF_DOCUMENT (document);
+       PopplerLayer *poppler_layer;
 
-       poppler_layer_hide (POPPLER_LAYER (g_list_nth_data (pdf_document->layers, layer_id)));
+       poppler_layer = POPPLER_LAYER (g_object_get_data (G_OBJECT (layer), "poppler-layer"));
+       poppler_layer_hide (poppler_layer);
 }
 
 static gboolean
 pdf_document_layers_layer_is_visible (EvDocumentLayers *document,
                                      EvLayer          *layer)
 {
-       PdfDocument *pdf_document = PDF_DOCUMENT (document);
-       guint        layer_id = ev_layer_get_id (layer);
+       PdfDocument  *pdf_document = PDF_DOCUMENT (document);
+       PopplerLayer *poppler_layer;
 
-       return poppler_layer_is_visible (POPPLER_LAYER (g_list_nth_data (pdf_document->layers, layer_id)));
+       poppler_layer = POPPLER_LAYER (g_object_get_data (G_OBJECT (layer), "poppler-layer"));
+       return poppler_layer_is_visible (poppler_layer);
 }
 
 static void
-pdf_document_document_layers_iface_init (EvDocumentLayersIface *iface)
+pdf_document_document_layers_iface_init (EvDocumentLayersInterface *iface)
 {
        iface->has_layers = pdf_document_layers_has_layers;
        iface->get_layers = pdf_document_layers_get_layers;