Submitted By: Ken Moffat <ken at linuxfromscratch dot org>
Date: 2011-12-05
Initial Package Version: 2.6.11
Upstream Status: Applied
Origin: Upstream
Description: Fixes compilation with poppler-0.1{7,8}

 Found at PLD.

From 69f69eed816b89be9a01a48a1f0643d1fd496118 Mon Sep 17 00:00:00 2001
From: Nils Philippsen <nils@redhat.com>
Date: Fri, 6 May 2011 11:58:44 +0200
Subject: [PATCH] patch: poppler-0.17

Squashed commit of the following:

commit 529d940222dfc352d41fbf72de29134421aa4002
Author: Nils Philippsen <nils@redhat.com>
Date:   Fri May 6 11:50:30 2011 +0200

    use code based on pixbufs instead of cairo surfaces

    this is done to avoid adding to libgimp, thanks to Mukund Sivaraman for
    hints how to do this

commit f8671d8767d4cdab830dc06310e96c63a88ec0fd
Author: Mukund Sivaraman <muks@banu.com>
Date:   Thu Apr 21 13:57:13 2011 +0530

    file-pdf-load: Update attribution, removing bogus copyright
    (cherry picked from commit e999122e0b20b6ccd6bde3ce039bb64068fc0019)

commit 89a78f2590d298dac2f42e6d9a3016fc5d672c70
Author: Nils Philippsen <nils@redhat.com>
Date:   Thu Apr 21 13:52:18 2011 +0200

    file-pdf-load: Use better API + cleanups

    * fixes issues with poppler 0.17 completely
    * uses new libgimp API to pass surfaces instead of pixbufs
    * uses GTK+ 3 API to convert surfaces to pixbufs where available
    (backported from commit 7bdadd80ba479d6ff904e276d805e16f6b940ee2)

commit 4e92302c4a14a961f112587a0ad86696c88da2f8
Author: Nils Philippsen <nils@redhat.com>
Date:   Thu Apr 21 13:38:08 2011 +0200

    file-pdf-load: Don't use deprecated API (bug #646947)

    (cherry picked from commit 9b3e1c91fd2eac69da6947ec9c7fbf10096ba237)

    Conflicts:

    	plug-ins/common/file-pdf.c
---
 plug-ins/common/file-pdf.c |  323 ++++++++++++++++++++++++++++++++++++++------
 1 files changed, 283 insertions(+), 40 deletions(-)

diff --git a/plug-ins/common/file-pdf.c b/plug-ins/common/file-pdf.c
index a43b459..43c2b7d 100644
--- a/plug-ins/common/file-pdf.c
+++ b/plug-ins/common/file-pdf.c
@@ -4,6 +4,9 @@
  *
  * Copyright (C) 2005 Nathan Summers
  *
+ * Some code in render_page_to_surface() borrowed from
+ * poppler.git/glib/poppler-page.cc.
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -80,16 +83,20 @@ static gboolean          load_dialog       (PopplerDocument        *doc,
 static PopplerDocument * open_document     (const gchar            *filename,
                                             GError                **error);
 
-static GdkPixbuf *       get_thumbnail     (PopplerDocument        *doc,
+static cairo_surface_t * get_thumb_surface (PopplerDocument        *doc,
+                                            gint                    page,
+                                            gint                    preferred_size);
+
+static GdkPixbuf *       get_thumb_pixbuf  (PopplerDocument        *doc,
                                             gint                    page,
                                             gint                    preferred_size);
 
 static gint32            layer_from_pixbuf (gint32                  image,
-                                            const gchar            *layer_name,
-                                            gint                    position,
-                                            GdkPixbuf              *buf,
-                                            gdouble                 progress_start,
-                                            gdouble                 progress_scale);
+					                        const gchar            *layer_name,
+					                        gint                    position,
+					                        GdkPixbuf              *pixbuf,
+					                        gdouble                 progress_start,
+					                        gdouble                 progress_scale);
 
 /**
  ** the following was formerly part of
@@ -433,11 +440,12 @@ run (const gchar      *name,
         }
       else
         {
-          gdouble      width  = 0;
-          gdouble      height = 0;
-          gdouble      scale;
-          gint32       image  = -1;
-          GdkPixbuf   *pixbuf = NULL;
+          gdouble    width     = 0;
+          gdouble    height    = 0;
+          gdouble    scale;
+          gint32     image     = -1;
+          gint       num_pages = 0;
+          GdkPixbuf *pixbuf    = NULL;
 
           /* Possibly retrieve last settings */
           gimp_get_data (LOAD_PROC, &loadvals);
@@ -455,7 +463,10 @@ run (const gchar      *name,
                   g_object_unref (page);
                 }
 
-              pixbuf = get_thumbnail (doc, 0, param[1].data.d_int32);
+              num_pages = poppler_document_get_n_pages (doc);
+
+              pixbuf = get_thumb_pixbuf (doc, 0, param[1].data.d_int32);
+
               g_object_unref (doc);
             }
 
@@ -548,6 +559,187 @@ open_document (const gchar  *filename,
   return doc;
 }
 
+/* FIXME: Remove this someday when we depend fully on GTK+ >= 3 */
+
+#if (!GTK_CHECK_VERSION (3, 0, 0))
+
+static cairo_format_t
+gdk_cairo_format_for_content (cairo_content_t content)
+{
+  switch (content)
+    {
+    case CAIRO_CONTENT_COLOR:
+      return CAIRO_FORMAT_RGB24;
+    case CAIRO_CONTENT_ALPHA:
+      return CAIRO_FORMAT_A8;
+    case CAIRO_CONTENT_COLOR_ALPHA:
+    default:
+      return CAIRO_FORMAT_ARGB32;
+    }
+}
+
+static cairo_surface_t *
+gdk_cairo_surface_coerce_to_image (cairo_surface_t *surface,
+                                   cairo_content_t  content,
+                                   int              src_x,
+                                   int              src_y,
+                                   int              width,
+                                   int              height)
+{
+  cairo_surface_t *copy;
+  cairo_t *cr;
+
+  copy = cairo_image_surface_create (gdk_cairo_format_for_content (content),
+                                     width,
+                                     height);
+
+  cr = cairo_create (copy);
+  cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+  cairo_set_source_surface (cr, surface, -src_x, -src_y);
+  cairo_paint (cr);
+  cairo_destroy (cr);
+
+  return copy;
+}
+
+static void
+convert_alpha (guchar *dest_data,
+               int     dest_stride,
+               guchar *src_data,
+               int     src_stride,
+               int     src_x,
+               int     src_y,
+               int     width,
+               int     height)
+{
+  int x, y;
+
+  src_data += src_stride * src_y + src_x * 4;
+
+  for (y = 0; y < height; y++) {
+    guint32 *src = (guint32 *) src_data;
+
+    for (x = 0; x < width; x++) {
+      guint alpha = src[x] >> 24;
+
+      if (alpha == 0)
+        {
+          dest_data[x * 4 + 0] = 0;
+          dest_data[x * 4 + 1] = 0;
+          dest_data[x * 4 + 2] = 0;
+        }
+      else
+        {
+          dest_data[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
+          dest_data[x * 4 + 1] = (((src[x] & 0x00ff00) >>  8) * 255 + alpha / 2) / alpha;
+          dest_data[x * 4 + 2] = (((src[x] & 0x0000ff) >>  0) * 255 + alpha / 2) / alpha;
+        }
+      dest_data[x * 4 + 3] = alpha;
+    }
+
+    src_data += src_stride;
+    dest_data += dest_stride;
+  }
+}
+
+static void
+convert_no_alpha (guchar *dest_data,
+                  int     dest_stride,
+                  guchar *src_data,
+                  int     src_stride,
+                  int     src_x,
+                  int     src_y,
+                  int     width,
+                  int     height)
+{
+  int x, y;
+
+  src_data += src_stride * src_y + src_x * 4;
+
+  for (y = 0; y < height; y++) {
+    guint32 *src = (guint32 *) src_data;
+
+    for (x = 0; x < width; x++) {
+      dest_data[x * 3 + 0] = src[x] >> 16;
+      dest_data[x * 3 + 1] = src[x] >>  8;
+      dest_data[x * 3 + 2] = src[x];
+    }
+
+    src_data += src_stride;
+    dest_data += dest_stride;
+  }
+}
+
+/**
+ * gdk_pixbuf_get_from_surface:
+ * @surface: surface to copy from
+ * @src_x: Source X coordinate within @surface
+ * @src_y: Source Y coordinate within @surface
+ * @width: Width in pixels of region to get
+ * @height: Height in pixels of region to get
+ *
+ * Transfers image data from a #cairo_surface_t and converts it to an RGB(A)
+ * representation inside a #GdkPixbuf. This allows you to efficiently read
+ * individual pixels from cairo surfaces. For #GdkWindows, use
+ * gdk_pixbuf_get_from_window() instead.
+ *
+ * This function will create an RGB pixbuf with 8 bits per channel.
+ * The pixbuf will contain an alpha channel if the @surface contains one.
+ *
+ * Return value: (transfer full): A newly-created pixbuf with a reference
+ *     count of 1, or %NULL on error
+ */
+static GdkPixbuf *
+gdk_pixbuf_get_from_surface  (cairo_surface_t *surface,
+                              gint             src_x,
+                              gint             src_y,
+                              gint             width,
+                              gint             height)
+{
+  cairo_content_t content;
+  GdkPixbuf *dest;
+
+  /* General sanity checks */
+  g_return_val_if_fail (surface != NULL, NULL);
+  g_return_val_if_fail (width > 0 && height > 0, NULL);
+
+  content = cairo_surface_get_content (surface) | CAIRO_CONTENT_COLOR;
+  dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                         !!(content & CAIRO_CONTENT_ALPHA),
+                         8,
+                         width, height);
+
+  surface = gdk_cairo_surface_coerce_to_image (surface, content,
+                                               src_x, src_y,
+                                               width, height);
+  cairo_surface_flush (surface);
+  if (cairo_surface_status (surface) || dest == NULL)
+    {
+      cairo_surface_destroy (surface);
+      return NULL;
+    }
+
+  if (gdk_pixbuf_get_has_alpha (dest))
+    convert_alpha (gdk_pixbuf_get_pixels (dest),
+                   gdk_pixbuf_get_rowstride (dest),
+                   cairo_image_surface_get_data (surface),
+                   cairo_image_surface_get_stride (surface),
+                   0, 0,
+                   width, height);
+  else
+    convert_no_alpha (gdk_pixbuf_get_pixels (dest),
+                      gdk_pixbuf_get_rowstride (dest),
+                      cairo_image_surface_get_data (surface),
+                      cairo_image_surface_get_stride (surface),
+                      0, 0,
+                      width, height);
+
+  cairo_surface_destroy (surface);
+  return dest;
+}
+
+#endif
+
 static gint32
 layer_from_pixbuf (gint32        image,
                    const gchar  *layer_name,
@@ -566,6 +758,54 @@ layer_from_pixbuf (gint32        image,
   return layer;
 }
 
+static cairo_surface_t *
+render_page_to_surface (PopplerPage *page,
+                        int          width,
+                        int          height,
+                        double       scale)
+{
+  cairo_surface_t *surface;
+  cairo_t *cr;
+
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+  cr = cairo_create (surface);
+
+  cairo_save (cr);
+  cairo_translate (cr, 0.0, 0.0);
+
+  if (scale != 1.0)
+    cairo_scale (cr, scale, scale);
+
+  poppler_page_render (page, cr);
+  cairo_restore (cr);
+
+  cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
+  cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+  cairo_paint (cr);
+
+  cairo_destroy (cr);
+
+  return surface;
+}
+
+static GdkPixbuf *
+render_page_to_pixbuf (PopplerPage *page,
+                       int          width,
+                       int          height,
+                       double       scale)
+{
+  GdkPixbuf *pixbuf;
+  cairo_surface_t *surface;
+
+  surface = render_page_to_surface (page, width, height, scale);
+  pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0,
+                                        cairo_image_surface_get_width (surface),
+                                        cairo_image_surface_get_height (surface));
+  cairo_surface_destroy (surface);
+
+  return pixbuf;
+}
+
 static gint32
 load_image (PopplerDocument        *doc,
             const gchar            *filename,
@@ -597,7 +837,7 @@ load_image (PopplerDocument        *doc,
       gdouble      page_width;
       gdouble      page_height;
 
-      GdkPixbuf   *buf;
+      GdkPixbuf   *pixbuf;
       gint         width;
       gint         height;
 
@@ -627,15 +867,13 @@ load_image (PopplerDocument        *doc,
           gimp_image_set_resolution (image_ID, resolution, resolution);
         }
 
-      buf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
-
-      poppler_page_render_to_pixbuf (page, 0, 0, width, height, scale, 0, buf);
+      pixbuf = render_page_to_pixbuf (page, width, height, scale);
 
-      layer_from_pixbuf (image_ID, page_label, i, buf,
+      layer_from_pixbuf (image_ID, page_label, i, pixbuf,
                          doc_progress, 1.0 / pages->n_pages);
 
       g_free (page_label);
-      g_object_unref (buf);
+      g_object_unref(pixbuf);
 
       doc_progress = (double) (i + 1) / pages->n_pages;
       gimp_progress_update (doc_progress);
@@ -676,30 +914,22 @@ load_image (PopplerDocument        *doc,
   return image_ID;
 }
 
-static GdkPixbuf *
-get_thumbnail (PopplerDocument *doc,
-               gint             page_num,
-               gint             preferred_size)
+static cairo_surface_t *
+get_thumb_surface (PopplerDocument *doc,
+                   gint             page_num,
+                   gint             preferred_size)
 {
   PopplerPage *page;
-  GdkPixbuf   *pixbuf;
+  cairo_surface_t *surface;
 
   page = poppler_document_get_page (doc, page_num);
 
   if (! page)
     return NULL;
 
-  /* XXX: Remove conditional when we depend on poppler 0.8.0, but also
-   * add configure check to make sure POPPLER_WITH_GDK is enabled!
-   */
-#ifdef POPPLER_WITH_GDK
-  pixbuf = poppler_page_get_thumbnail_pixbuf (page);
-#else
-  pixbuf = poppler_page_get_thumbnail (page);
-#endif
-
+  surface = poppler_page_get_thumbnail (page);
 
-  if (! pixbuf)
+  if (! surface)
     {
       gdouble width;
       gdouble height;
@@ -712,15 +942,28 @@ get_thumbnail (PopplerDocument *doc,
       width  *= scale;
       height *= scale;
 
-      pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
-                               width, height);
-
-      poppler_page_render_to_pixbuf (page,
-                                     0, 0, width, height, scale, 0, pixbuf);
+      surface = render_page_to_surface (page, width, height, scale);
     }
 
   g_object_unref (page);
 
+  return surface;
+}
+
+static GdkPixbuf *
+get_thumb_pixbuf (PopplerDocument *doc,
+                  gint             page_num,
+                  gint             preferred_size)
+{
+  cairo_surface_t *surface;
+  GdkPixbuf *pixbuf;
+
+  surface = get_thumb_surface (doc, page_num, preferred_size);
+  pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0,
+                                        cairo_image_surface_get_width (surface),
+                                        cairo_image_surface_get_height (surface));
+  cairo_surface_destroy (surface);
+
   return pixbuf;
 }
 
@@ -769,8 +1012,8 @@ thumbnail_thread (gpointer data)
       idle_data->page_no  = i;
 
       /* FIXME get preferred size from somewhere? */
-      idle_data->pixbuf = get_thumbnail (thread_data->document, i,
-                                         THUMBNAIL_SIZE);
+      idle_data->pixbuf = get_thumb_pixbuf (thread_data->document, i,
+                                            THUMBNAIL_SIZE);
 
       g_idle_add (idle_set_thumbnail, idle_data);
 
-- 
1.7.5

