]> code.delx.au - gnu-emacs/blobdiff - src/image.c
Merge branch 'master' into cairo
[gnu-emacs] / src / image.c
index 83f9b38cfec48fce0f3cc3a6a51e0b83a6784c2b..87029bfa1b0ea9c3ef751c7945927611093f5450 100644 (file)
@@ -237,7 +237,7 @@ x_create_bitmap_from_data (struct frame *f, char *bits, unsigned int width, unsi
 #endif /* HAVE_NTGUI */
 
 #ifdef HAVE_NS
-  void *bitmap = ns_image_from_XBM (bits, width, height);
+  void *bitmap = ns_image_from_XBM (bits, width, height, 0, 0);
   if (!bitmap)
       return -1;
 #endif
@@ -518,7 +518,6 @@ x_create_bitmap_mask (struct frame *f, ptrdiff_t id)
 
 #endif /* HAVE_X_WINDOWS */
 
-
 /***********************************************************************
                            Image types
  ***********************************************************************/
@@ -1084,6 +1083,54 @@ image_ascent (struct image *img, struct face *face, struct glyph_slice *slice)
   return ascent;
 }
 
+#ifdef USE_CAIRO
+static uint32_t
+xcolor_to_argb32 (XColor xc)
+{
+  return (0xff << 24) | ((xc.red / 256) << 16)
+      | ((xc.green / 256) << 8) | (xc.blue / 256);
+}
+
+static uint32_t
+get_spec_bg_or_alpha_as_argb (struct image *img,
+                              struct frame *f)
+{
+  uint32_t bgcolor = 0;
+  XColor xbgcolor;
+  Lisp_Object bg = image_spec_value (img->spec, QCbackground, NULL);
+
+  if (STRINGP (bg) && XParseColor (FRAME_X_DISPLAY (f),
+                                   FRAME_X_COLORMAP (f),
+                                   SSDATA (bg),
+                                   &xbgcolor))
+    bgcolor = xcolor_to_argb32 (xbgcolor);
+
+  return bgcolor;
+}
+
+static void
+create_cairo_image_surface (struct image *img,
+                            unsigned char *data,
+                            int width,
+                            int height)
+{
+  cairo_surface_t *surface;
+  cairo_format_t format = CAIRO_FORMAT_ARGB32;
+  int stride = cairo_format_stride_for_width (format, width);
+  surface = cairo_image_surface_create_for_data (data,
+                                                 format,
+                                                 width,
+                                                 height,
+                                                 stride);
+  img->width = width;
+  img->height = height;
+  img->cr_data = surface;
+  img->cr_data2 = data;
+  img->pixmap = 0;
+}
+#endif
+
+
 \f
 /* Image background colors.  */
 
@@ -2659,7 +2706,7 @@ Create_Pixmap_From_Bitmap_Data (struct frame *f, struct image *img, char *data,
     convert_mono_to_color_image (f, img, fg, bg);
 
 #elif defined (HAVE_NS)
-  img->pixmap = ns_image_from_XBM (data, img->width, img->height);
+  img->pixmap = ns_image_from_XBM (data, img->width, img->height, fg, bg);
 
 #else
   img->pixmap =
@@ -3635,19 +3682,16 @@ xpm_load (struct frame *f, struct image *img)
   if (rc == XpmSuccess
       && img->ximg->format == ZPixmap
       && img->ximg->bits_per_pixel == 32
-      && img->mask_img->bits_per_pixel == 1)
+      && (! img->mask_img || img->mask_img->bits_per_pixel == 1))
     {
-      cairo_surface_t *surface;
       int width = img->ximg->width;
       int height = img->ximg->height;
-      cairo_format_t format = CAIRO_FORMAT_ARGB32;
-      int stride = cairo_format_stride_for_width (format, width);
-      unsigned char *data = (unsigned char *)
-        xmalloc (width*height*4);
+      unsigned char *data = (unsigned char *) xmalloc (width*height*4);
       int i;
       uint32_t *od = (uint32_t *)data;
       uint32_t *id = (uint32_t *)img->ximg->data;
-      unsigned char *mid = img->mask_img->data;
+      unsigned char *mid = img->mask_img ? img->mask_img->data : 0;
+      uint32_t bgcolor = get_spec_bg_or_alpha_as_argb (img, f);
 
       for (i = 0; i < height; ++i)
         {
@@ -3655,24 +3699,15 @@ xpm_load (struct frame *f, struct image *img)
           for (k = 0; k < width; ++k)
             {
               int idx = i * img->ximg->bytes_per_line/4 + k;
-              int maskidx = i * img->mask_img->bytes_per_line + k/8;
-              int mask = mid[maskidx] & (1 << (k % 8));
+              int maskidx = mid ? i * img->mask_img->bytes_per_line + k/8 : 0;
+              int mask = mid ? mid[maskidx] & (1 << (k % 8)) : 1;
 
               if (mask) od[idx] = id[idx] + 0xff000000; // ff => full alpha
-              else od[idx] = 0;
+              else od[idx] = bgcolor;
             }
         }
 
-      surface = cairo_image_surface_create_for_data (data,
-                                                     format,
-                                                     width,
-                                                     height,
-                                                     stride);
-      img->width = cairo_image_surface_get_width (surface);
-      img->height = cairo_image_surface_get_height (surface);
-      img->cr_data = surface;
-      img->pixmap = 0;
-      img->cr_data2 = data;
+      create_cairo_image_surface (img, data, width, height);
     }
   else
     {
@@ -5028,7 +5063,8 @@ x_build_heuristic_mask (struct frame *f, struct image *img, Lisp_Object how)
       if (i == 3 && NILP (how))
        {
          char color_name[30];
-         sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
+         sprintf (color_name, "#%04x%04x%04x",
+                  rgb[0] + 0u, rgb[1] + 0u, rgb[2] + 0u);
          bg = (
 #ifdef HAVE_NTGUI
                0x00ffffff & /* Filter out palette info.  */
@@ -5211,12 +5247,17 @@ pbm_load (struct frame *f, struct image *img)
   bool raw_p;
   int x, y;
   int width, height, max_color_idx = 0;
-  XImagePtr ximg;
   Lisp_Object file, specified_file;
   enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
   unsigned char *contents = NULL;
   unsigned char *end, *p;
   ptrdiff_t size;
+#ifdef USE_CAIRO
+  unsigned char *data = 0;
+  uint32_t *dataptr;
+#else
+  XImagePtr ximg;
+#endif
 
   specified_file = image_spec_value (img->spec, QCfile, NULL);
 
@@ -5298,6 +5339,11 @@ pbm_load (struct frame *f, struct image *img)
   width = pbm_scan_number (&p, end);
   height = pbm_scan_number (&p, end);
 
+#ifdef USE_CAIRO
+  data = (unsigned char *) xmalloc (width * height * 4);
+  dataptr = (uint32_t *) data;
+#endif
+
   if (type != PBM_MONO)
     {
       max_color_idx = pbm_scan_number (&p, end);
@@ -5314,8 +5360,10 @@ pbm_load (struct frame *f, struct image *img)
       goto error;
     }
 
+#ifndef USE_CAIRO
   if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
     goto error;
+#endif
 
   /* Initialize the color hash table.  */
   init_color_table ();
@@ -5326,12 +5374,34 @@ pbm_load (struct frame *f, struct image *img)
       struct image_keyword fmt[PBM_LAST];
       unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
       unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
-
+#ifdef USE_CAIRO
+      XColor xfg, xbg;
+      int fga32, bga32;
+#endif
       /* Parse the image specification.  */
       memcpy (fmt, pbm_format, sizeof fmt);
       parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
 
       /* Get foreground and background colors, maybe allocate colors.  */
+#ifdef USE_CAIRO
+      if (! fmt[PBM_FOREGROUND].count
+          || ! STRINGP (fmt[PBM_FOREGROUND].value)
+          || ! x_defined_color (f, SSDATA (fmt[PBM_FOREGROUND].value), &xfg, 0))
+        {
+          xfg.pixel = fg;
+          x_query_color (f, &xfg);
+        }
+      fga32 = xcolor_to_argb32 (xfg);
+
+      if (! fmt[PBM_BACKGROUND].count
+          || ! STRINGP (fmt[PBM_BACKGROUND].value)
+          || ! x_defined_color (f, SSDATA (fmt[PBM_BACKGROUND].value), &xbg, 0))
+       {
+          xbg.pixel = bg;
+          x_query_color (f, &xbg);
+       }
+      bga32 = xcolor_to_argb32 (xbg);
+#else
       if (fmt[PBM_FOREGROUND].count
          && STRINGP (fmt[PBM_FOREGROUND].value))
        fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
@@ -5342,6 +5412,7 @@ pbm_load (struct frame *f, struct image *img)
          img->background = bg;
          img->background_valid = 1;
        }
+#endif
 
       for (y = 0; y < height; ++y)
        for (x = 0; x < width; ++x)
@@ -5352,7 +5423,11 @@ pbm_load (struct frame *f, struct image *img)
                  {
                    if (p >= end)
                      {
+#ifdef USE_CAIRO
+                        xfree (data);
+#else
                        x_destroy_x_image (ximg);
+#endif
                        x_clear_image (f, img);
                        image_error ("Invalid image size in image `%s'",
                                     img->spec, Qnil);
@@ -5366,7 +5441,11 @@ pbm_load (struct frame *f, struct image *img)
            else
              g = pbm_scan_number (&p, end);
 
+#ifdef USE_CAIRO
+            *dataptr++ = g ? fga32 : bga32;
+#else
            XPutPixel (ximg, x, y, g ? fg : bg);
+#endif
          }
     }
   else
@@ -5379,7 +5458,11 @@ pbm_load (struct frame *f, struct image *img)
 
       if (raw_p && p + expected_size > end)
        {
+#ifdef USE_CAIRO
+          xfree (data);
+#else
          x_destroy_x_image (ximg);
+#endif
          x_clear_image (f, img);
          image_error ("Invalid image size in image `%s'",
                       img->spec, Qnil);
@@ -5420,18 +5503,29 @@ pbm_load (struct frame *f, struct image *img)
 
            if (r < 0 || g < 0 || b < 0)
              {
+#ifdef USE_CAIRO
+                xfree (data);
+#else
                x_destroy_x_image (ximg);
+#endif
                image_error ("Invalid pixel value in image `%s'",
                             img->spec, Qnil);
                goto error;
              }
 
+#ifdef USE_CAIRO
+           r = (double) r * 255 / max_color_idx;
+           g = (double) g * 255 / max_color_idx;
+           b = (double) b * 255 / max_color_idx;
+            *dataptr++ = (0xff << 24) | (r << 16) | (g << 8) | b;
+#else
            /* RGB values are now in the range 0..max_color_idx.
               Scale this to the range 0..0xffff supported by X.  */
            r = (double) r * 65535 / max_color_idx;
            g = (double) g * 65535 / max_color_idx;
            b = (double) b * 65535 / max_color_idx;
            XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
+#endif
          }
     }
 
@@ -5447,12 +5541,16 @@ pbm_load (struct frame *f, struct image *img)
 
   /* Maybe fill in the background field while we have ximg handy.  */
 
+#ifdef USE_CAIRO
+  create_cairo_image_surface (img, data, width, height);
+#else
   if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
     /* Casting avoids a GCC warning.  */
     IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
 
   /* Put ximg into the image.  */
   image_put_x_image (f, img, ximg, 0);
+#endif
 
   /* X and W32 versions did it here, MAC version above.  ++kfs
      img->width = width;
@@ -5544,7 +5642,7 @@ png_image_p (Lisp_Object object)
 #endif /* HAVE_PNG || HAVE_NS || USE_CAIRO */
 
 
-#if defined HAVE_PNG && !defined HAVE_NS && !defined USE_CAIRO
+#if defined HAVE_PNG && !defined HAVE_NS
 
 # ifdef WINDOWSNT
 /* PNG library details.  */
@@ -5776,7 +5874,6 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
   Lisp_Object specified_data;
   int x, y;
   ptrdiff_t i;
-  XImagePtr ximg, mask_img = NULL;
   png_struct *png_ptr;
   png_info *info_ptr = NULL, *end_info = NULL;
   FILE *fp = NULL;
@@ -5790,9 +5887,17 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
   bool transparent_p;
   struct png_memory_storage tbr;  /* Data to be read */
 
+#ifdef USE_CAIRO
+  unsigned char *data = 0;
+  uint32_t *dataptr;
+#else
+  XImagePtr ximg, mask_img = NULL;
+#endif
+
   /* Find out what file to load.  */
   specified_file = image_spec_value (img->spec, QCfile, NULL);
   specified_data = image_spec_value (img->spec, QCdata, NULL);
+  IF_LINT (Lisp_Object volatile specified_data_volatile = specified_data);
 
   if (NILP (specified_data))
     {
@@ -5889,6 +5994,7 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
 
   /* Silence a bogus diagnostic; see GCC bug 54561.  */
   IF_LINT (fp = c->fp);
+  IF_LINT (specified_data = specified_data_volatile);
 
   /* Read image info.  */
   if (!NILP (specified_data))
@@ -5908,10 +6014,12 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
       goto error;
     }
 
+#ifndef USE_CAIRO
   /* Create the X image and pixmap now, so that the work below can be
      omitted if the image is too large for X.  */
   if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
     goto error;
+#endif
 
   /* If image contains simply transparency data, we prefer to
      construct a clipping mask.  */
@@ -5998,6 +6106,10 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
       c->fp = NULL;
     }
 
+#ifdef USE_CAIRO
+  data = (unsigned char *) xmalloc (width * height * 4);
+  dataptr = (uint32_t *) data;
+#else
   /* Create an image and pixmap serving as mask if the PNG image
      contains an alpha channel.  */
   if (channels == 4
@@ -6009,6 +6121,7 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
       x_clear_image_1 (f, img, CLEAR_IMAGE_PIXMAP);
       goto error;
     }
+#endif
 
   /* Fill the X image and mask from PNG data.  */
   init_color_table ();
@@ -6021,6 +6134,14 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
        {
          int r, g, b;
 
+#ifdef USE_CAIRO
+          int a = 0xff;
+         r = *p++;
+         g = *p++;
+         b = *p++;
+          if (channels == 4) a = *p++;
+          *dataptr++ = (a << 24) | (r << 16) | (g << 8) | b;
+#else
          r = *p++ << 8;
          g = *p++ << 8;
          b = *p++ << 8;
@@ -6047,6 +6168,7 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
                XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : PIX_MASK_RETAIN);
              ++p;
            }
+#endif
        }
     }
 
@@ -6076,6 +6198,9 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
   img->width = width;
   img->height = height;
 
+#ifdef USE_CAIRO
+  create_cairo_image_surface (img, data, width, height);
+#else
   /* Maybe fill in the background field while we have ximg handy.
      Casting avoids a GCC warning.  */
   IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
@@ -6092,6 +6217,7 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
 
       image_put_x_image (f, img, mask_img, 1);
     }
+#endif
 
   return 1;
 }
@@ -6113,44 +6239,8 @@ png_load (struct frame *f, struct image *img)
                         image_spec_value (img->spec, QCdata, NULL));
 }
 
-#elif defined USE_CAIRO
 
-static bool
-png_load (struct frame *f, struct image *img)
-{
-  Lisp_Object file;
-  Lisp_Object specified_file = image_spec_value (img->spec, QCfile, NULL);
-  cairo_surface_t *surface;
-
-  if (! STRINGP (specified_file))
-    {
-      image_error ("Invalid image spec, file missing `%s'", img->spec, Qnil);
-      return false;
-    }
-
-  file = x_find_image_file (specified_file);
-  if (! STRINGP (file))
-    {
-      image_error ("Cannot find image file `%s'", specified_file, Qnil);
-      return false;
-    }
-
-  surface = cairo_image_surface_create_from_png (SSDATA (file));
-  if (! surface)
-    {
-      image_error ("Error creating surface from file `%s'",
-                   specified_file, Qnil);
-      return false;
-    }
-  img->width = cairo_image_surface_get_width (surface);
-  img->height = cairo_image_surface_get_height (surface);
-  img->cr_data = surface;
-  img->pixmap = 0;
-
-  return true;
-}
-
-#endif /* USE_CAIRO */
+#endif /* HAVE_NS */
 
 
 \f
@@ -6561,14 +6651,17 @@ jpeg_load_body (struct frame *f, struct image *img,
   FILE * IF_LINT (volatile) fp = NULL;
   JSAMPARRAY buffer;
   int row_stride, x, y;
-  XImagePtr ximg = NULL;
   unsigned long *colors;
   int width, height;
   int i, ir, ig, ib;
+#ifndef USE_CAIRO
+  XImagePtr ximg = NULL;
+#endif
 
   /* Open the JPEG file.  */
   specified_file = image_spec_value (img->spec, QCfile, NULL);
   specified_data = image_spec_value (img->spec, QCdata, NULL);
+  IF_LINT (Lisp_Object volatile specified_data_volatile = specified_data);
 
   if (NILP (specified_data))
     {
@@ -6623,13 +6716,17 @@ jpeg_load_body (struct frame *f, struct image *img,
       jpeg_destroy_decompress (&mgr->cinfo);
 
       /* If we already have an XImage, free that.  */
+#ifndef USE_CAIRO
       x_destroy_x_image (ximg);
-
+#endif
       /* Free pixmap and colors.  */
       x_clear_image (f, img);
       return 0;
     }
 
+  /* Silence a bogus diagnostic; see GCC bug 54561.  */
+  IF_LINT (specified_data = specified_data_volatile);
+
   /* Create the JPEG decompression object.  Let it read from fp.
         Read the JPEG image header.  */
   jpeg_CreateDecompress (&mgr->cinfo, JPEG_LIB_VERSION, sizeof *&mgr->cinfo);
@@ -6655,12 +6752,14 @@ jpeg_load_body (struct frame *f, struct image *img,
       sys_longjmp (mgr->setjmp_buffer, 1);
     }
 
+#ifndef USE_CAIRO
   /* Create X image and pixmap.  */
   if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
     {
       mgr->failure_code = MY_JPEG_CANNOT_CREATE_X;
       sys_longjmp (mgr->setjmp_buffer, 1);
     }
+#endif
 
   /* Allocate colors.  When color quantization is used,
      mgr->cinfo.actual_number_of_colors has been set with the number of
@@ -6708,9 +6807,6 @@ jpeg_load_body (struct frame *f, struct image *img,
                                         JPOOL_IMAGE, row_stride, 1);
 #ifdef USE_CAIRO
   {
-    cairo_surface_t *surface;
-    cairo_format_t format = CAIRO_FORMAT_ARGB32;
-    int stride = cairo_format_stride_for_width (format, width);
     unsigned char *data = (unsigned char *) xmalloc (width*height*4);
     uint32_t *dataptr = (uint32_t *) data;
     int r, g, b;
@@ -6729,17 +6825,7 @@ jpeg_load_body (struct frame *f, struct image *img,
           }
       }
 
-    surface = cairo_image_surface_create_for_data (data,
-                                                   format,
-                                                   width,
-                                                   height,
-                                                   stride);
-
-    img->width  = width;
-    img->height = height;
-    img->cr_data = surface;
-    img->cr_data2 = data;
-    img->pixmap = 0;
+    create_cairo_image_surface (img, data, width, height);
   }
 #else
   for (y = 0; y < height; ++y)
@@ -6756,7 +6842,7 @@ jpeg_load_body (struct frame *f, struct image *img,
   if (fp)
     fclose (fp);
 
-#ifndef CAIRO
+#ifndef USE_CAIRO
   /* Maybe fill in the background field while we have ximg handy. */
   if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
     /* Casting avoids a GCC warning.  */
@@ -7197,6 +7283,29 @@ tiff_load (struct frame *f, struct image *img)
       return 0;
     }
 
+#ifdef USE_CAIRO
+  {
+    unsigned char *data = (unsigned char *) xmalloc (width*height*4);
+    uint32_t *dataptr = (uint32_t *) data;
+    int r, g, b, a;
+
+    for (y = 0; y < height; ++y)
+      {
+        uint32 *row = buf + (height - 1 - y) * width;
+        for (x = 0; x < width; ++x)
+          {
+            uint32 abgr = row[x];
+            int r = TIFFGetR (abgr);
+            int g = TIFFGetG (abgr);
+            int b = TIFFGetB (abgr);
+            int a = TIFFGetA (abgr);
+            *dataptr++ = (a << 24) | (r << 16) | (g << 8) | b;
+          }
+      }
+
+    create_cairo_image_surface (img, data, width, height);
+  }
+#else
   /* Initialize the color table.  */
   init_color_table ();
 
@@ -7231,8 +7340,10 @@ tiff_load (struct frame *f, struct image *img)
 
   /* Put ximg into the image.  */
   image_put_x_image (f, img, ximg, 0);
-  xfree (buf);
 
+#endif /* ! USE_CAIRO */
+
+  xfree (buf);
   return 1;
 }
 
@@ -7482,7 +7593,6 @@ gif_load (struct frame *f, struct image *img)
 {
   Lisp_Object file;
   int rc, width, height, x, y, i, j;
-  XImagePtr ximg;
   ColorMapObject *gif_color_map;
   unsigned long pixel_colors[256];
   GifFileType *gif;
@@ -7494,6 +7604,12 @@ gif_load (struct frame *f, struct image *img)
   EMACS_INT idx;
   int gif_err;
 
+#ifdef USE_CAIRO
+  unsigned char *data = 0;
+#else
+  XImagePtr ximg;
+#endif
+
   if (NILP (specified_data))
     {
       file = x_find_image_file (specified_file);
@@ -7622,6 +7738,25 @@ gif_load (struct frame *f, struct image *img)
        }
     }
 
+#ifdef USE_CAIRO
+  /* xzalloc so data is zero => transparent */
+  data = (unsigned char *) xzalloc (width * height * 4);
+  if (STRINGP (specified_bg))
+    {
+      XColor color;
+      if (x_defined_color (f, SSDATA (specified_bg), &color, 0))
+        {
+          uint32_t *dataptr = (uint32_t *)data;
+          int r = color.red/256;
+          int g = color.green/256;
+          int b = color.blue/256;
+
+          for (y = 0; y < height; ++y)
+            for (x = 0; x < width; ++x)
+              *dataptr++ = (0xff << 24) | (r << 16) | (g << 8) | b;
+        }
+    }
+#else
   /* Create the X image and pixmap.  */
   if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
     {
@@ -7648,6 +7783,7 @@ gif_load (struct frame *f, struct image *img)
       for (x = img->corners[RIGHT_CORNER]; x < width; ++x)
        XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
     }
+#endif
 
   /* Read the GIF image into the X image.   */
 
@@ -7702,12 +7838,14 @@ gif_load (struct frame *f, struct image *img)
       if (disposal == 0)
        disposal = 1;
 
-      /* Allocate subimage colors.  */
-      memset (pixel_colors, 0, sizeof pixel_colors);
       gif_color_map = subimage->ImageDesc.ColorMap;
       if (!gif_color_map)
        gif_color_map = gif->SColorMap;
 
+#ifndef USE_CAIRO
+      /* Allocate subimage colors.  */
+      memset (pixel_colors, 0, sizeof pixel_colors);
+
       if (gif_color_map)
        for (i = 0; i < gif_color_map->ColorCount; ++i)
          {
@@ -7722,6 +7860,7 @@ gif_load (struct frame *f, struct image *img)
                pixel_colors[i] = lookup_rgb_color (f, r, g, b);
              }
          }
+#endif
 
       /* Apply the pixel values.  */
       if (GIFLIB_MAJOR < 5 && gif->SavedImages[j].ImageDesc.Interlace)
@@ -7739,20 +7878,47 @@ gif_load (struct frame *f, struct image *img)
                {
                  int c = raster[y * subimg_width + x];
                  if (transparency_color_index != c || disposal != 1)
-                   XPutPixel (ximg, x + subimg_left, row + subimg_top,
-                              pixel_colors[c]);
+                    {
+#ifdef USE_CAIRO
+                      uint32_t *dataptr =
+                        ((uint32_t*)data + ((row + subimg_top) * subimg_width
+                                            + x + subimg_left));
+                      int r = gif_color_map->Colors[c].Red;
+                      int g = gif_color_map->Colors[c].Green;
+                      int b = gif_color_map->Colors[c].Blue;
+
+                      if (transparency_color_index != c)
+                        *dataptr = (0xff << 24) | (r << 16) | (g << 8) | b;
+#else
+                      XPutPixel (ximg, x + subimg_left, row + subimg_top,
+                                 pixel_colors[c]);
+#endif
+                    }
                }
            }
        }
       else
        {
-         for (y = 0; y < subimg_height; ++y)
+          for (y = 0; y < subimg_height; ++y)
            for (x = 0; x < subimg_width; ++x)
              {
                int c = raster[y * subimg_width + x];
                if (transparency_color_index != c || disposal != 1)
-                 XPutPixel (ximg, x + subimg_left, y + subimg_top,
-                            pixel_colors[c]);
+                  {
+#ifdef USE_CAIRO
+                    uint32_t *dataptr =
+                      ((uint32_t*)data + ((y + subimg_top) * subimg_width
+                                          + x + subimg_left));
+                    int r = gif_color_map->Colors[c].Red;
+                    int g = gif_color_map->Colors[c].Green;
+                    int b = gif_color_map->Colors[c].Blue;
+                    if (transparency_color_index != c)
+                      *dataptr = (0xff << 24) | (r << 16) | (g << 8) | b;
+#else
+                    XPutPixel (ximg, x + subimg_left, y + subimg_top,
+                               pixel_colors[c]);
+#endif
+                  }
              }
        }
     }
@@ -7809,6 +7975,9 @@ gif_load (struct frame *f, struct image *img)
 #endif
     }
 
+#ifdef USE_CAIRO
+  create_cairo_image_surface (img, data, width, height);
+#else
   /* Maybe fill in the background field while we have ximg handy. */
   if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
     /* Casting avoids a GCC warning.  */
@@ -7816,6 +7985,7 @@ gif_load (struct frame *f, struct image *img)
 
   /* Put ximg into the image.  */
   image_put_x_image (f, img, ximg, 0);
+#endif
 
   return 1;
 }
@@ -9037,11 +9207,9 @@ svg_load_image (struct frame *f,         /* Pointer to emacs frame structure.  *
 
 #ifdef USE_CAIRO
   {
-    cairo_surface_t *surface;
-    cairo_format_t format = CAIRO_FORMAT_ARGB32;
-    int stride = cairo_format_stride_for_width (format, width);
     unsigned char *data = (unsigned char *) xmalloc (width*height*4);
     int y;
+    uint32_t bgcolor = get_spec_bg_or_alpha_as_argb (img, f);
 
     for (y = 0; y < height; ++y)
       {
@@ -9051,27 +9219,21 @@ svg_load_image (struct frame *f,         /* Pointer to emacs frame structure.  *
 
         for (x = 0; x < width; ++x)
           {
-            *dataptr = (iconptr[0] << 16)
-              | (iconptr[1] << 8)
-              | iconptr[2]
-              | (iconptr[3] << 24);
+            if (iconptr[3] == 0)
+              *dataptr = bgcolor;
+            else
+              *dataptr = (iconptr[0] << 16)
+                | (iconptr[1] << 8)
+                | iconptr[2]
+                | (iconptr[3] << 24);
+
             iconptr += 4;
             ++dataptr;
           }
       }
 
-    surface = cairo_image_surface_create_for_data (data,
-                                                   format,
-                                                   width,
-                                                   height,
-                                                   stride);
-
+    create_cairo_image_surface (img, data, width, height);
     g_object_unref (pixbuf);
-    img->width  = width;
-    img->height = height;
-    img->cr_data = surface;
-    img->cr_data2 = data;
-    img->pixmap = 0;
   }
 #else
   /* Try to create a x pixmap to hold the svg pixmap.  */