]> www.fi.muni.cz Git - evince.git/blobdiff - backend/pdf/ev-poppler.cc
backends: Fix several security issues in the dvi-backend.
[evince.git] / backend / pdf / ev-poppler.cc
index dc253c70d142b80d7202c70e8cc86f96d78f7c79..ced3ef79fb9284149dd9eb08726fdda7ed2a378d 100644 (file)
@@ -43,7 +43,6 @@
 #include "ev-document-images.h"
 #include "ev-document-fonts.h"
 #include "ev-document-security.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-transition.h"
 #include "ev-document-forms.h"
 #include "ev-document-layers.h"
@@ -110,12 +109,10 @@ struct _PdfDocument
 
        PdfPrintContext *print_ctx;
 
 
        PdfPrintContext *print_ctx;
 
-       GList *layers;
        GHashTable *annots;
 };
 
 static void pdf_document_security_iface_init             (EvDocumentSecurityInterface    *iface);
        GHashTable *annots;
 };
 
 static void pdf_document_security_iface_init             (EvDocumentSecurityInterface    *iface);
-static void pdf_document_document_thumbnails_iface_init  (EvDocumentThumbnailsInterface  *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_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);
@@ -145,8 +142,6 @@ 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_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,
                                 EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_LINKS,
                                                                 pdf_document_document_links_iface_init);
                                 EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_IMAGES,
@@ -202,11 +197,6 @@ pdf_document_dispose (GObject *object)
                poppler_fonts_iter_free (pdf_document->fonts_iter);
        }
 
                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);
 }
 
        G_OBJECT_CLASS (pdf_document_parent_class)->dispose (object);
 }
 
@@ -403,6 +393,102 @@ pdf_document_render (EvDocument      *document,
                                width, height, rc);
 }
 
                                width, height, rc);
 }
 
+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_get_thumbnail (EvDocument      *document,
+                           EvRenderContext *rc)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+       PopplerPage *poppler_page;
+       GdkPixbuf *pixbuf = NULL;
+       GdkPixbuf *border_pixbuf;
+       double page_width, page_height;
+       gint width, height;
+
+       poppler_page = POPPLER_PAGE (rc->page->backend_page);
+
+       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 *
 /* 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 *
@@ -636,6 +722,9 @@ pdf_document_get_info (EvDocument *document)
        PopplerPermissions permissions;
        EvPage *page;
        char *metadata;
        PopplerPermissions permissions;
        EvPage *page;
        char *metadata;
+#ifdef HAVE_POPPLER_DOCUMENT_IS_LINEARIZED
+       gboolean linearized;
+#endif
 
        info = g_new0 (EvDocumentInfo, 1);
 
 
        info = g_new0 (EvDocumentInfo, 1);
 
@@ -672,7 +761,11 @@ pdf_document_get_info (EvDocument *document)
                      "producer", &(info->producer),
                      "creation-date", &(info->creation_date),
                      "mod-date", &(info->modified_date),
                      "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),
                      "linearized", &(info->linearized),
+#endif
                      "metadata", &metadata,
                      NULL);
 
                      "metadata", &metadata,
                      NULL);
 
@@ -778,6 +871,10 @@ pdf_document_get_info (EvDocument *document)
                info->security = g_strdup (_("No"));
        }
 
                info->security = g_strdup (_("No"));
        }
 
+#ifdef HAVE_POPPLER_DOCUMENT_IS_LINEARIZED
+       info->linearized = linearized ? g_strdup (_("Yes")) : g_strdup (_("No"));
+#endif
+
        return info;
 }
 
        return info;
 }
 
@@ -825,6 +922,7 @@ pdf_document_class_init (PdfDocumentClass *klass)
        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_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;
        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;
@@ -1125,8 +1223,47 @@ ev_link_from_action (PdfDocument   *pdf_document,
                case POPPLER_ACTION_RENDITION:
                        unimplemented_action = "POPPLER_ACTION_RENDITION";
                        break;
                case POPPLER_ACTION_RENDITION:
                        unimplemented_action = "POPPLER_ACTION_RENDITION";
                        break;
-               case POPPLER_ACTION_OCG_STATE:
-                       unimplemented_action = "POPPLER_ACTION_OCG_STATE";
+               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:
                        break;
 #endif
                case POPPLER_ACTION_UNKNOWN:
@@ -1165,36 +1302,7 @@ build_tree (PdfDocument      *pdf_document,
                if (!action)
                        continue;
 
                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)
                if (!link || strlen (ev_link_get_title (link)) <= 0) {
                        poppler_action_free (action);
                        if (link)
@@ -1305,6 +1413,25 @@ pdf_document_links_find_link_dest (EvDocumentLinks  *document_links,
        return ev_dest;
 }
 
        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 (EvDocumentLinksInterface *iface)
 {
 static void
 pdf_document_document_links_iface_init (EvDocumentLinksInterface *iface)
 {
@@ -1312,6 +1439,7 @@ pdf_document_document_links_iface_init (EvDocumentLinksInterface *iface)
        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->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 EvMappingList *
 }
 
 static EvMappingList *
@@ -1381,116 +1509,6 @@ pdf_document_document_images_iface_init (EvDocumentImagesInterface *iface)
        iface->get_image = pdf_document_images_get_image;
 }
 
        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;
-       double page_width, page_height;
-       gint width, height;
-
-       poppler_page = POPPLER_PAGE (rc->page->backend_page);
-
-       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);
-       }
-
-        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_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface)
-{
-       iface->get_thumbnail = pdf_document_thumbnails_get_thumbnail;
-}
-
-
 static GList *
 pdf_document_find_find_text (EvDocumentFind *document_find,
                             EvPage         *page,
 static GList *
 pdf_document_find_find_text (EvDocumentFind *document_find,
                             EvPage         *page,
@@ -3175,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);
                        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);
                                                 rb_group);
+                       g_object_set_data_full (G_OBJECT (ev_layer),
+                                               "poppler-layer",
+                                               g_object_ref (layer),
+                                               (GDestroyNotify) g_object_unref);
                } else {
                        gchar *title;
 
                } else {
                        gchar *title;
 
@@ -3237,30 +3256,33 @@ static void
 pdf_document_layers_show_layer (EvDocumentLayers *document,
                                EvLayer          *layer)
 {
 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)
 {
 }
 
 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)
 {
 }
 
 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
 }
 
 static void