unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#35871: 27.0.50; [PATCH] Fix SVG transparency with Cairo
@ 2019-05-23 20:05 Kévin Le Gouguec
  2019-05-24  0:02 ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 10+ messages in thread
From: Kévin Le Gouguec @ 2019-05-23 20:05 UTC (permalink / raw)
  To: 35871

[-- Attachment #1: Type: text/plain, Size: 368 bytes --]

Hello,

While trying out the Cairo build, I noticed that some SVG images did
not look as smooth as in the "regular" build.  More specifically,
semi-transparent parts of SVG images (when the alpha value is neither
0% nor 100%) did not seem to be displayed properly.

This is especially noticeable on the splash screen (see attached
screenshot) and when starting Gnus.


[-- Attachment #2: cairo-svg.png --]
[-- Type: image/png, Size: 154308 bytes --]

[-- Attachment #3: Type: text/plain, Size: 1624 bytes --]


Each window in the screenshot was obtained with:

- ./src/emacs -Q -rv,
- C-h C-a (for some reason the splash screen wasn't displayed at
  startup)
- C-x 2, moving to the *scratch* buffer, and displaying
  - system-configuration-options,
  - system-configuration-features,
  - emacs-repository-version.

I could reproduce this on OpenSUSE Tumbleweed, Debian stretch and
Xubuntu 16.04.

I looked at the SVG section in src/image.c, in particular at any
USE_CAIRO section; I stumbled on this bit:

> if (iconptr[3] == 0)
>   *dataptr = bgcolor;
> else
>   *dataptr = (iconptr[0] << 16)
>     | (iconptr[1] << 8)
>     | iconptr[2]
>     | (iconptr[3] << 24);

Looking at create_cairo_image_surface, I saw that we use
CAIRO_FORMAT_ARGB32, which according to the documentation works with
"premultiplied alpha" values.

Quoting <https://www.cairographics.org/manual/cairo-Image-Surfaces.html#cairo-format-t>:

> CAIRO_FORMAT_ARGB32      each pixel is a 32-bit quantity, with alpha
>                          in the upper 8 bits, then red, then green,
>                          then blue. The 32-bit quantities are stored
>                          native-endian. Pre-multiplied alpha is
>                          used. (That is, 50% transparent red is
>                          0x80800000, not 0x80ff0000.) (Since 1.0)

AFAICU, this means that Cairo expects the RGB values to be scaled down
according to the alpha value.  Having no idea whether this was the issue
(I had no idea whether gdk-pixbuf gave us premultiplied alpha or not), I
added that multiplication and AFAICT, this does solve the issue (see
other screenshot).


[-- Attachment #4: cairo-svg-fixed.png --]
[-- Type: image/png, Size: 161037 bytes --]

[-- Attachment #5: Type: text/plain, Size: 140 bytes --]


NB: the commit named "a7c9365f7956d9d7a089a2f161d2b9d06fc91d58" in the
left screenshot is the one which contains my patch, attached here:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: 0001-Fix-transparency-handling-in-SVG-images-with-Cairo.patch --]
[-- Type: text/x-patch, Size: 1842 bytes --]

From a7c9365f7956d9d7a089a2f161d2b9d06fc91d58 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?K=C3=A9vin=20Le=20Gouguec?= <kevin.legouguec@gmail.com>
Date: Thu, 23 May 2019 20:48:35 +0200
Subject: [PATCH] Fix transparency handling in SVG images with Cairo

We create cairo_surface_t objects with CAIRO_FORMAT_ARGB32, which is
meant to be used with "premultiplied alpha" values, i.e. RGB values
must be scaled down according to the alpha value.

Some references:

https://www.cairographics.org/manual/cairo-Image-Surfaces.html#cairo-format-t
https://wiki.gnome.org/Attic/GtkCairoIntegration

* src/image.c (gdk_pixbuf_to_argb32): New function to convert
GdkPixbuf to Cairo ARGB.
(svg_load_image): Use it.
---
 src/image.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/src/image.c b/src/image.c
index 57b405f6db..7d9aea6f3e 100644
--- a/src/image.c
+++ b/src/image.c
@@ -1084,6 +1084,17 @@ emacs_color_to_argb32 (Emacs_Color *ec)
 	  | ((ec->green / 256) << 8) | (ec->blue / 256));
 }
 
+static uint32_t
+gdk_pixbuf_to_argb32 (const guchar iconptr[4])
+{
+  /* Convert to pre-multiplied alpha. */
+  guchar a = iconptr[3];
+  return a<<24
+    | ((iconptr[0]*a / 256) << 16)
+    | ((iconptr[1]*a / 256) << 8)
+    | (iconptr[2]*a / 256);
+}
+
 static uint32_t
 get_spec_bg_or_alpha_as_argb (struct image *img,
                               struct frame *f)
@@ -9271,10 +9282,7 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
             if (iconptr[3] == 0)
               *dataptr = bgcolor;
             else
-              *dataptr = (iconptr[0] << 16)
-                | (iconptr[1] << 8)
-                | iconptr[2]
-                | (iconptr[3] << 24);
+              *dataptr = gdk_pixbuf_to_argb32 (iconptr);
 
             iconptr += 4;
             ++dataptr;
-- 
2.21.0


[-- Attachment #7: Type: text/plain, Size: 114 bytes --]


Here is a before-after-patch screenshot with a grey background, which I
find makes the problem more noticeable:


[-- Attachment #8: cairo-svg-fixed-personal-config.png --]
[-- Type: image/png, Size: 229017 bytes --]

[-- Attachment #9: Type: text/plain, Size: 8587 bytes --]



Looking for references afterward, I found this bit about Cairo
integration in GTK+ in the er… GNOME Wiki Attic?

https://wiki.gnome.org/Attic/GtkCairoIntegration

> gdk-pixbuf only handles the pixel formats packed RGB and RGBA. Both of
> these formats are inefficient memory and performance wise.
>
> […]
>
> 2. Most Xservers uses the color format ARGB so to blit a GdkPixbuf you
>    need to convert each pixel from RGBA to ARGB which means that you are
>    taking an unnecessary performance hit. It is even worse if you are
>    blitting pixbufs using Cairo because then you have to convert from
>    premultiplied to non-premultiplied alpha.

See also the note on "Pixel formats" from a GNOME developer:

https://people.gnome.org/~federico/blog/my-gdk-pixbuf-braindump.html

> Every time we paint a GdkPixbuf to a cairo_t, there is a conversion
> from unpremultiplied RGBA to premultiplied, platform-endian ARGB.

(I find the GNOME Wiki Attic page a bit perplexing; they talk about
converting *from* premultiplied *to* non-premultiplied when working with
Cairo, which contradicts the Cairo manual, the GNOME developer's blog,
and my observations.)


Some questions I have about my patch:

- Is it OK to have array sizes in argument lists?  I know they are
  mostly decorative (e.g. sizeof still returns the size of a pointer),
  but I find the practice useful as a way to document intent (no idea
  if static analyzers are smart enough to use them nowadays).
  
  I can't say off the top of my head whether they come from C99 or
  later, but I found a few other functions using them
  (prepare_standard_handles in src/w32.h,
  get_lface_attributes_no_remap in src/xfaces.c), so I figured we
  already support the feature in practice.

- I originally divided by 255, since I figured that would be the
  maximal value for any given component and we want x*a / max to yield
  x when a is 255; however I later noticed that emacs_color_to_argb32
  divides by 256, so I went for that instead.  I am still not sure
  whether it's correct, or whether it matters much.

- I added my static function to the "Image type independent image
  structures" section so that it ends up close to emacs_color_to_argb32,
  but maybe I should move it down to the "SVG" section?  In which case I
  will probably need to add a new #ifdef USE_CAIRO block.

  (Alternately, should I just inline the function?)

- I haven't thought really hard about that "if (iconptr[3] == 0)"
  branch.  Is it still relevant?


Thank you for your time.



In GNU Emacs 27.0.50 (build 2, x86_64-pc-linux-gnu, GTK+ Version 3.24.8, cairo version 1.16.0)
 of 2019-05-15 built on my-little-tumbleweed
Repository revision: 4fa6029f7ee30aa3316d6d73db61462730042908
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12004000
System Description: openSUSE Tumbleweed

Configured using:
 'configure --with-xwidgets --with-cairo'

Configured features:
XPM JPEG TIFF GIF PNG RSVG CAIRO SOUND GPM DBUS GSETTINGS GLIB NOTIFY
INOTIFY ACL LIBSELINUX GNUTLS LIBXML2 FREETYPE M17N_FLT LIBOTF ZLIB
TOOLKIT_SCROLL_BARS GTK3 X11 XDBE XIM THREADS XWIDGETS JSON PDUMPER
LCMS2 GMP

Important settings:
  value of $LC_CTYPE: en_US.UTF-8
  value of $LANG: en_US.UTF-8
  value of $XMODIFIERS: @im=local
  locale-coding-system: utf-8-unix

Major mode: Magit Process

Minor modes in effect:
  global-magit-file-mode: t
  magit-auto-revert-mode: t
  global-git-commit-mode: t
  async-bytecomp-package-mode: t
  shell-dirtrack-mode: t
  show-paren-mode: t
  minibuffer-depth-indicate-mode: t
  icomplete-mode: t
  global-page-break-lines-mode: t
  page-break-lines-mode: t
  electric-pair-mode: t
  diff-hl-flydiff-mode: t
  global-diff-hl-mode: t
  delete-selection-mode: t
  tooltip-mode: t
  global-eldoc-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  buffer-read-only: t
  column-number-mode: t
  line-number-mode: t
  transient-mark-mode: t

Load-path shadows:
None found.

Features:
(shadow emacsbug rect help-fns radix-tree ffap log-view misearch
multi-isearch browse-url cus-edit whitespace magit-patch cc-mode
cc-fonts cc-guess cc-menus cc-cmds cc-styles cc-align cc-engine cc-vars
cc-defs diff-hl-dired notifications dbus xml org-indent org-rmail
org-mhe org-irc org-info org-gnus org-docview doc-view image-mode
org-bibtex bibtex org-bbdb org-w3m org-element avl-tree generator org
org-macro org-footnote org-pcomplete org-list org-faces org-entities
org-version ob-emacs-lisp ob ob-tangle org-src ob-ref ob-lob ob-table
ob-keys ob-exp ob-comint ob-core ob-eval org-compat org-macs
org-loaddefs find-func cal-menu calendar cal-loaddefs find-dired xref
vc-bzr vc-src vc-sccs vc-svn vc-cvs vc-rcs project magit-ediff
ediff-merg ediff-wind ediff-diff ediff-mult ediff-help ediff-init
ediff-util ediff bug-reference flyspell ispell view markdown-mode rx
color thingatpt noutline outline magit-extras sh-script smie
magit-submodule magit-obsolete magit-popup magit-blame magit-stash
magit-reflog magit-bisect magit-push magit-pull magit-fetch magit-clone
magit-remote magit-commit magit-sequence magit-notes magit-worktree
magit-tag magit-merge magit-branch magit-reset magit-files magit-refs
magit-status magit magit-repos magit-apply magit-wip magit-log
which-func imenu magit-diff magit-core magit-autorevert autorevert
filenotify magit-margin magit-transient magit-process magit-mode
transient git-commit magit-git magit-section magit-utils crm log-edit
pcvs-util add-log with-editor async-bytecomp async shell pcomplete
server dash smerge-mode jka-compr mm-archive executable vc-git mailalias
smtpmail sendmail iso-transl nnir sort gnus-cite mail-extr gnus-async
gnus-bcklg qp gnus-ml nndraft nnmh nnfolder utf-7 epa-file gnutls
network-stream nsm gnus-agent gnus-srvr gnus-score score-mode nnvirtual
gnus-msg gnus-art mm-uu mml2015 mm-view mml-smime smime dig mailcap nntp
gnus-cache gnus-sum gnus-group gnus-undo gnus-start gnus-cloud nnimap
nnmail mail-source utf7 netrc nnoo parse-time gnus-spec gnus-int
gnus-range message rmc puny dired dired-loaddefs format-spec rfc822 mml
mml-sec epa derived epg mm-decode mm-bodies mm-encode mail-parse rfc2231
mailabbrev gmm-utils mailheader gnus-win gnus nnheader gnus-util rmail
rmail-loaddefs rfc2047 rfc2045 ietf-drums text-property-search time-date
mail-utils mm-util mail-prsvr wid-edit delight advice eighters-theme
quail cl-extra help-mode rg rg-ibuffer rg-result wgrep-rg wgrep s
rg-history rg-header rg-compat ibuf-ext ibuffer ibuffer-loaddefs grep
compile comint ansi-color ring edmacro kmacro disp-table paren mb-depth
icomplete page-break-lines elec-pair diff-hl-flydiff diff diff-hl vc-dir
ewoc vc vc-dispatcher diff-mode easy-mmode delsel cus-start cus-load
mule-util info package easymenu epg-config url-handlers url-parse
auth-source cl-seq eieio eieio-core cl-macs eieio-loaddefs
password-cache json subr-x map url-vars seq byte-opt gv bytecomp
byte-compile cconv cl-loaddefs cl-lib tooltip eldoc electric uniquify
ediff-hook vc-hooks lisp-float-type mwheel term/x-win x-win
term/common-win x-dnd tool-bar dnd fontset image regexp-opt fringe
tabulated-list replace newcomment text-mode elisp-mode lisp-mode
prog-mode register page menu-bar rfn-eshadow isearch timer select
scroll-bar mouse jit-lock font-lock syntax facemenu font-core
term/tty-colors frame cl-generic cham georgian utf-8-lang misc-lang
vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms cp51932
hebrew greek romanian slovak czech european ethiopic indian cyrillic
chinese composite charscript charprop case-table epa-hook jka-cmpr-hook
help simple abbrev obarray minibuffer cl-preloaded nadvice loaddefs
button faces cus-face macroexp files text-properties overlay sha1 md5
base64 format env code-pages mule custom widget hashtable-print-readable
backquote threads dbusbind inotify lcms2 dynamic-setting
system-font-setting font-render-setting xwidget-internal cairo
move-toolbar gtk x-toolkit x multi-tty make-network-process emacs)

Memory information:
((conses 16 444631 125454)
 (symbols 48 47237 83)
 (strings 32 176476 9183)
 (string-bytes 1 5274843)
 (vectors 16 64009)
 (vector-slots 8 2012096 107118)
 (floats 8 522 596)
 (intervals 56 17166 2584)
 (buffers 992 85))

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* bug#35871: 27.0.50; [PATCH] Fix SVG transparency with Cairo
  2019-05-23 20:05 bug#35871: 27.0.50; [PATCH] Fix SVG transparency with Cairo Kévin Le Gouguec
@ 2019-05-24  0:02 ` YAMAMOTO Mitsuharu
  2019-05-24 21:19   ` Kévin Le Gouguec
  2019-05-28  0:52   ` YAMAMOTO Mitsuharu
  0 siblings, 2 replies; 10+ messages in thread
From: YAMAMOTO Mitsuharu @ 2019-05-24  0:02 UTC (permalink / raw)
  To: Kévin Le Gouguec; +Cc: 35871

On Fri, 24 May 2019 05:05:31 +0900,
Kévin Le Gouguec wrote:
> While trying out the Cairo build, I noticed that some SVG images did
> not look as smooth as in the "regular" build.  More specifically,
> semi-transparent parts of SVG images (when the alpha value is neither
> 0% nor 100%) did not seem to be displayed properly.

As I mentioned in (*), the current image support on cairo has several
problems including this one.  I'm thinking about porting the core part
of the image support code on the Mac port, to cairo.

(*): https://lists.gnu.org/r/bug-gnu-emacs/2019-05/msg00205.html 

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp





^ permalink raw reply	[flat|nested] 10+ messages in thread

* bug#35871: 27.0.50; [PATCH] Fix SVG transparency with Cairo
  2019-05-24  0:02 ` YAMAMOTO Mitsuharu
@ 2019-05-24 21:19   ` Kévin Le Gouguec
  2019-05-28  0:52   ` YAMAMOTO Mitsuharu
  1 sibling, 0 replies; 10+ messages in thread
From: Kévin Le Gouguec @ 2019-05-24 21:19 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: 35871

YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> writes:

> As I mentioned in (*), the current image support on cairo has several
> problems including this one.  I'm thinking about porting the core part
> of the image support code on the Mac port, to cairo.
>
> (*): https://lists.gnu.org/r/bug-gnu-emacs/2019-05/msg00205.html 

I see!  Thanks for the pointer; I did try searching the bug tracker for
anything mentioning both "cairo" and "SVG", but this particular report
slipped under my radar (maybe because there is no explicit mention of
"SVG"?  Or maybe my search-fu is just too weak).

I guess the incentives to apply small, specific patches like mine are
not very compelling if a more systemic fix is around the corner.





^ permalink raw reply	[flat|nested] 10+ messages in thread

* bug#35871: 27.0.50; [PATCH] Fix SVG transparency with Cairo
  2019-05-24  0:02 ` YAMAMOTO Mitsuharu
  2019-05-24 21:19   ` Kévin Le Gouguec
@ 2019-05-28  0:52   ` YAMAMOTO Mitsuharu
  2019-05-28 10:02     ` Kévin Le Gouguec
  1 sibling, 1 reply; 10+ messages in thread
From: YAMAMOTO Mitsuharu @ 2019-05-28  0:52 UTC (permalink / raw)
  To: Kévin Le Gouguec; +Cc: 35871

[-- Attachment #1: Type: text/plain, Size: 904 bytes --]

On Fri, 24 May 2019 09:02:32 +0900,
YAMAMOTO Mitsuharu wrote:
> 
> As I mentioned in (*), the current image support on cairo has several
> problems including this one.  I'm thinking about porting the core part
> of the image support code on the Mac port, to cairo.
> 
> (*): https://lists.gnu.org/r/bug-gnu-emacs/2019-05/msg00205.html 

Patch attached.

It makes cairo image support more consistent with the Xlib one.  It
supports postprocessing (:conversion ALGORITHM), mask removal (:mask
nil), and image-mask-p.  SVG images should look similar on both
builds.  Postscript support, which is marked obsolete, is dropped.

Alpha channel (not the tRNS chunk in PNG) support for PNG and SVG is
now easy on cairo, but not added in this patch, because it introduces
some inconsistency with the Xlib one.  It could be added as a separate
change.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp

[-- Attachment #2: mac-like-cairo-image.diff --]
[-- Type: application/octet-stream, Size: 64997 bytes --]

diff --git a/src/dispextern.h b/src/dispextern.h
index aa80fa653db..70ae96b8243 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -38,7 +38,9 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 typedef XColor Emacs_Color;
 typedef Cursor Emacs_Cursor;
 #define No_Cursor (None)
+#ifndef USE_CAIRO
 typedef Pixmap Emacs_Pixmap;
+#endif
 typedef XRectangle Emacs_Rectangle;
 typedef XGCValues Emacs_GC;
 #else /* !HAVE_X_WINDOWS */
@@ -92,11 +94,26 @@ xstrcasecmp (char const *a, char const *b)
 #ifdef HAVE_X_WINDOWS
 #include <X11/Xresource.h> /* for XrmDatabase */
 typedef struct x_display_info Display_Info;
+#ifndef USE_CAIRO
 typedef XImage *Emacs_Pix_Container;
 typedef XImage *Emacs_Pix_Context;
+#endif	/* !USE_CAIRO */
 #define NativeRectangle XRectangle
 #endif
 
+#ifdef USE_CAIRO
+/* Mininal version of XImage.  */
+typedef struct
+{
+  int width, height;		/* size of image */
+  char *data;			/* pointer to image data */
+  int bytes_per_line;		/* accelarator to next line */
+  int bits_per_pixel;		/* bits per pixel (ZPixmap) */
+} *Emacs_Pix_Container;
+typedef Emacs_Pix_Container Emacs_Pixmap;
+typedef Emacs_Pix_Container Emacs_Pix_Context;
+#endif
+
 #ifdef HAVE_NTGUI
 #include "w32gui.h"
 typedef struct w32_display_info Display_Info;
@@ -3396,7 +3413,9 @@ extern void image_destroy_bitmap (struct frame *, ptrdiff_t);
 extern void image_destroy_all_bitmaps (Display_Info *);
 #ifdef HAVE_X_WINDOWS
 extern void x_create_bitmap_mask (struct frame *, ptrdiff_t);
+#ifndef USE_CAIRO
 extern void x_kill_gs_process (Pixmap, struct frame *);
+#endif	/* !USE_CAIRO */
 #endif
 extern Lisp_Object image_find_image_file (Lisp_Object);
 
@@ -3408,7 +3427,7 @@ bool valid_image_p (Lisp_Object);
 void prepare_image_for_display (struct frame *, struct image *);
 ptrdiff_t lookup_image (struct frame *, Lisp_Object);
 
-#if defined (HAVE_X_WINDOWS) ||  defined (HAVE_NS)
+#if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_NS
 #define RGB_PIXEL_COLOR unsigned long
 #endif
 
diff --git a/src/image.c b/src/image.c
index 699bdfd4fa1..e847195b2b7 100644
--- a/src/image.c
+++ b/src/image.c
@@ -30,6 +30,7 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <setjmp.h>
 
+#include <stdint.h>
 #include <c-ctype.h>
 #include <flexmember.h>
 
@@ -67,13 +68,37 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifdef HAVE_X_WINDOWS
 typedef struct x_bitmap_record Bitmap_Record;
+#ifndef USE_CAIRO
 #define GET_PIXEL(ximg, x, y) XGetPixel (ximg, x, y)
+#define PUT_PIXEL XPutPixel
 #define NO_PIXMAP None
 
 #define PIX_MASK_RETAIN	0
 #define PIX_MASK_DRAW	1
+#endif	/* !USE_CAIRO */
 #endif /* HAVE_X_WINDOWS */
 
+#ifdef USE_CAIRO
+#define GET_PIXEL image_pix_context_get_pixel
+#define PUT_PIXEL image_pix_container_put_pixel
+#define NO_PIXMAP 0
+
+#define PIX_MASK_RETAIN	0
+#define PIX_MASK_DRAW	255
+
+#define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b))
+#define ARGB_TO_ULONG(a, r, g, b) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+#define RED_FROM_ULONG(color)	(((color) >> 16) & 0xff)
+#define GREEN_FROM_ULONG(color)	(((color) >> 8) & 0xff)
+#define BLUE_FROM_ULONG(color)	((color) & 0xff)
+#define RED16_FROM_ULONG(color)		(RED_FROM_ULONG (color) * 0x101)
+#define GREEN16_FROM_ULONG(color)	(GREEN_FROM_ULONG (color) * 0x101)
+#define BLUE16_FROM_ULONG(color)	(BLUE_FROM_ULONG (color) * 0x101)
+
+static unsigned long image_alloc_image_color (struct frame *, struct image *,
+					      Lisp_Object, unsigned long);
+#endif	/* USE_CAIRO */
+
 #ifdef HAVE_NTGUI
 
 /* We need (or want) w32.h only when we're _not_ compiling for Cygwin.  */
@@ -84,6 +109,7 @@ typedef struct x_bitmap_record Bitmap_Record;
 
 typedef struct w32_bitmap_record Bitmap_Record;
 #define GET_PIXEL(ximg, x, y) GetPixel (ximg, x, y)
+#define PUT_PIXEL XPutPixel
 #define NO_PIXMAP 0
 
 #define PIX_MASK_RETAIN	0
@@ -95,6 +121,7 @@ typedef struct w32_bitmap_record Bitmap_Record;
 typedef struct ns_bitmap_record Bitmap_Record;
 
 #define GET_PIXEL(ximg, x, y) XGetPixel (ximg, x, y)
+#define PUT_PIXEL XPutPixel
 #define NO_PIXMAP 0
 
 #define PIX_MASK_RETAIN	0
@@ -118,16 +145,109 @@ static void free_color_table (void);
 static unsigned long *colors_in_color_table (int *n);
 #endif
 
-/* Code to deal with bitmaps.  Bitmaps are referenced by their bitmap
-   id, which is just an int that this section returns.  Bitmaps are
-   reference counted so they can be shared among frames.
+#ifdef USE_CAIRO
 
-   Bitmap indices are guaranteed to be > 0, so a negative number can
-   be used to indicate no bitmap.
+static Emacs_Pix_Container
+image_create_pix_container (struct frame *f, unsigned int width,
+			    unsigned int height, unsigned int depth)
+{
+  Emacs_Pix_Container pimg;
 
-   If you use image_create_bitmap_from_data, then you must keep track
-   of the bitmaps yourself.  That is, creating a bitmap from the same
-   data more than once will not be caught.  */
+  pimg = xmalloc (sizeof (*pimg));
+  pimg->width = width;
+  pimg->height = height;
+  pimg->bits_per_pixel = depth == 1 ? 8 : 32;
+  pimg->bytes_per_line = cairo_format_stride_for_width ((depth == 1
+							 ? CAIRO_FORMAT_A8
+							 : CAIRO_FORMAT_RGB24),
+							width);
+  pimg->data = xmalloc (pimg->bytes_per_line * height);
+
+  return pimg;
+}
+
+static void
+image_pix_container_put_pixel (Emacs_Pix_Container image,
+			       int x, int y, unsigned long pixel)
+{
+  if (image->bits_per_pixel == 32)
+    ((uint32_t *)(image->data + y * image->bytes_per_line))[x] = pixel;
+  else
+    ((uint8_t *)(image->data + y * image->bytes_per_line))[x] = pixel;
+}
+
+static unsigned long
+image_pix_context_get_pixel (Emacs_Pix_Context image, int x, int y)
+{
+  if (image->bits_per_pixel == 32)
+    return ((uint32_t *)(image->data + y * image->bytes_per_line))[x];
+  else
+    return ((uint8_t *)(image->data + y * image->bytes_per_line))[x];
+}
+
+static Emacs_Pix_Container
+image_pix_container_create_from_bitmap_data (struct frame *f,
+					     char *data, unsigned int width,
+					     unsigned int height,
+					     unsigned long fg,
+					     unsigned long bg)
+{
+  Emacs_Pix_Container pimg = image_create_pix_container (f, width, height, 0);
+  int bytes_per_line = (width + (CHAR_BIT - 1)) / CHAR_BIT;
+
+  for (int y = 0; y < height; y++)
+    {
+      for (int x = 0; x < width; x++)
+	PUT_PIXEL (pimg, x, y,
+		   (data[x / CHAR_BIT] >> (x % CHAR_BIT)) & 1 ? fg : bg);
+      data += bytes_per_line;
+    }
+
+  return pimg;
+}
+
+static cairo_surface_t *
+cr_create_cr_surface_from_image (struct frame *f, struct image *img)
+{
+  Emacs_Pix_Container pimg = img->pixmap;
+  cairo_surface_t *surface;
+
+  if (img->mask)
+    {
+      int x, y;
+
+      for (y = 0; y < pimg->height; y++)
+	for (x = 0; x < pimg->width; x++)
+	  {
+	    unsigned long color, alpha;
+	    int r, g, b;
+
+	    color = GET_PIXEL (pimg, x, y);
+	    alpha = GET_PIXEL (img->mask, x, y);
+	    r = (RED_FROM_ULONG (color) * alpha + 0x7f) / 0xff;
+	    g = (GREEN_FROM_ULONG (color) * alpha + 0x7f) / 0xff;
+	    b = (BLUE_FROM_ULONG (color) * alpha + 0x7f) / 0xff;
+	    PUT_PIXEL (pimg, x, y, ARGB_TO_ULONG (alpha, r, g, b));
+	  }
+      xfree (img->mask->data);
+      img->mask->data = NULL;
+    }
+  block_input ();
+  surface = cairo_image_surface_create_for_data ((unsigned char *) pimg->data,
+						 (img->mask
+						  ? CAIRO_FORMAT_ARGB32
+						  : CAIRO_FORMAT_RGB24),
+						 pimg->width, pimg->height,
+						 pimg->bytes_per_line);
+  static cairo_user_data_key_t key;
+  cairo_surface_set_user_data (surface, &key, pimg->data, xfree);
+  unblock_input ();
+  pimg->data = NULL;
+
+  return surface;
+}
+
+#endif	/* USE_CAIRO */
 
 #ifdef HAVE_NS
 /* Use with images created by ns_image_for_XPM.  */
@@ -146,6 +266,16 @@ XPutPixel (Emacs_Pix_Container image, int x, int y, unsigned long pixel)
 }
 #endif /* HAVE_NS */
 
+/* Code to deal with bitmaps.  Bitmaps are referenced by their bitmap
+   id, which is just an int that this section returns.  Bitmaps are
+   reference counted so they can be shared among frames.
+
+   Bitmap indices are guaranteed to be > 0, so a negative number can
+   be used to indicate no bitmap.
+
+   If you use image_create_bitmap_from_data, then you must keep track
+   of the bitmaps yourself.  That is, creating a bitmap from the same
+   data more than once will not be caught.  */
 
 /* Functions to access the contents of a bitmap, given an id.  */
 
@@ -433,16 +563,17 @@ static void image_unget_x_image (struct image *, bool, Emacs_Pix_Container);
 
 #ifdef HAVE_X_WINDOWS
 
+#ifndef USE_CAIRO
 static void image_sync_to_pixmaps (struct frame *, struct image *);
+#endif	/* !USE_CAIRO */
 
-/* Useful functions defined in the section
-   `Image type independent image structures' below. */
-
-static unsigned long four_corners_best (XImage *ximg,
-                                        int *corners,
-                                        unsigned long width,
-                                        unsigned long height);
+/* We are working on X-specific data structures here even with cairo.
+   So we use X-specific versions of image construction/destruction
+   functions and inline the specific case of four_corners_best.  */
 
+static bool x_create_x_image_and_pixmap (struct frame *, int, int, int,
+					 XImage **, Pixmap *);
+static void x_destroy_x_image (XImage *);
 
 /* Create a mask of a bitmap. Note is this not a perfect mask.
    It's nicer with some borders in this context */
@@ -454,7 +585,7 @@ x_create_bitmap_mask (struct frame *f, ptrdiff_t id)
   XImage *ximg, *mask_img;
   unsigned long width, height;
   bool result;
-  unsigned long bg;
+  unsigned long bg UNINIT;
   unsigned long x, y, xp, xm, yp, ym;
   GC gc;
 
@@ -477,8 +608,7 @@ x_create_bitmap_mask (struct frame *f, ptrdiff_t id)
       return;
     }
 
-  result = image_create_x_image_and_pixmap_1 (f, width, height, 1,
-                                              &mask_img, &mask, NULL);
+  result = x_create_x_image_and_pixmap (f, width, height, 1, &mask_img, &mask);
 
   unblock_input ();
   if (!result)
@@ -487,7 +617,23 @@ x_create_bitmap_mask (struct frame *f, ptrdiff_t id)
       return;
     }
 
-  bg = four_corners_best (ximg, NULL, width, height);
+  unsigned long corner_pixels[4];
+  corner_pixels[0] = XGetPixel (ximg, 0, 0);
+  corner_pixels[1] = XGetPixel (ximg, width - 1, 0);
+  corner_pixels[2] = XGetPixel (ximg, width - 1, height - 1);
+  corner_pixels[3] = XGetPixel (ximg, 0, height - 1);
+  int i, best_count;
+  for (i = best_count = 0; i < 4; ++i)
+    {
+      int j, n;
+
+      for (j = n = 0; j < 4; ++j)
+	if (corner_pixels[i] == corner_pixels[j])
+	  ++n;
+
+      if (n > best_count)
+	bg = corner_pixels[i], best_count = n;
+    }
 
   for (y = 0; y < ximg->height; ++y)
     {
@@ -522,7 +668,7 @@ x_create_bitmap_mask (struct frame *f, ptrdiff_t id)
   dpyinfo->bitmaps[id - 1].mask = mask;
 
   XDestroyImage (ximg);
-  image_destroy_x_image (mask_img);
+  x_destroy_x_image (mask_img);
 }
 
 #endif /* HAVE_X_WINDOWS */
@@ -1015,13 +1161,22 @@ prepare_image_for_display (struct frame *f, struct image *img)
   /* We're about to display IMG, so set its timestamp to `now'.  */
   img->timestamp = current_timespec ();
 
-#ifndef USE_CAIRO
   /* If IMG doesn't have a pixmap yet, load it now, using the image
      type dependent loader function.  */
   if (img->pixmap == NO_PIXMAP && !img->load_failed_p)
     img->load_failed_p = ! img->type->load (f, img);
 
-#ifdef HAVE_X_WINDOWS
+#ifdef USE_CAIRO
+  if (!img->load_failed_p && img->cr_data == NULL)
+    {
+      img->cr_data = cr_create_cr_surface_from_image (f, img);
+      if (img->cr_data == NULL)
+	{
+	  img->load_failed_p = 1;
+	  img->type->free (f, img);
+	}
+    }
+#elif defined HAVE_X_WINDOWS
   if (!img->load_failed_p)
     {
       block_input ();
@@ -1029,7 +1184,6 @@ prepare_image_for_display (struct frame *f, struct image *img)
       unblock_input ();
     }
 #endif
-#endif
 }
 
 
@@ -1076,48 +1230,6 @@ image_ascent (struct image *img, struct face *face, struct glyph_slice *slice)
   return ascent;
 }
 
-#ifdef USE_CAIRO
-static uint32_t
-emacs_color_to_argb32 (Emacs_Color *ec)
-{
-  return ((0xffu << 24) | ((ec->red / 256) << 16)
-	  | ((ec->green / 256) << 8) | (ec->blue / 256));
-}
-
-static uint32_t
-get_spec_bg_or_alpha_as_argb (struct image *img,
-                              struct frame *f)
-{
-  uint32_t bgcolor = 0;
-  Emacs_Color xbgcolor;
-  Lisp_Object bg = image_spec_value (img->spec, QCbackground, NULL);
-
-  if (STRINGP (bg) && x_parse_color (f, SSDATA (bg), &xbgcolor))
-    bgcolor = emacs_color_to_argb32 (&xbgcolor);
-
-  return bgcolor;
-}
-
-static cairo_surface_t *
-create_cairo_image_surface (int width, int height)
-{
-  cairo_format_t format = CAIRO_FORMAT_ARGB32;
-  eassert (cairo_format_stride_for_width (format, width) == width * 4);
-
-  return cairo_image_surface_create (format, width, height);
-}
-
-static void
-set_cairo_image_surface (struct image *img, cairo_surface_t *surface)
-{
-  cairo_surface_mark_dirty (surface);
-  img->width = cairo_image_surface_get_width (surface);
-  img->height = cairo_image_surface_get_height (surface);
-  img->cr_data = surface;
-  img->pixmap = 0;
-}
-#endif
-
 
 \f
 /* Image background colors.  */
@@ -1184,7 +1296,19 @@ image_background (struct image *img, struct frame *f, Emacs_Pix_Context pimg)
       if (free_pimg)
 	pimg = image_get_x_image_or_dc (f, img, 0, &prev);
 
-      img->background = four_corners_best (pimg, img->corners, img->width, img->height);
+      RGB_PIXEL_COLOR bg
+	= four_corners_best (pimg, img->corners, img->width, img->height);
+#ifdef USE_CAIRO
+      {
+	char color_name[30];
+	sprintf (color_name, "#%04x%04x%04x",
+		 (unsigned int) RED16_FROM_ULONG (bg),
+		 (unsigned int) GREEN16_FROM_ULONG (bg),
+		 (unsigned int) BLUE16_FROM_ULONG (bg));
+	bg = image_alloc_image_color (f, img, build_string (color_name), 0);
+      }
+#endif
+      img->background = bg;
 
       if (free_pimg)
 	image_unget_x_image_or_dc (img, 0, pimg, prev);
@@ -1259,7 +1383,7 @@ image_clear_image_1 (struct frame *f, struct image *img, int flags)
 	  /* NOTE (HAVE_NS): background color is NOT an indexed color! */
 	  img->background_valid = 0;
 	}
-#ifdef HAVE_X_WINDOWS
+#if defined HAVE_X_WINDOWS && !defined USE_CAIRO
       if (img->ximg)
 	{
 	  image_destroy_x_image (img->ximg);
@@ -1277,7 +1401,7 @@ image_clear_image_1 (struct frame *f, struct image *img, int flags)
 	  img->mask = NO_PIXMAP;
 	  img->background_transparent_valid = 0;
 	}
-#ifdef HAVE_X_WINDOWS
+#if defined HAVE_X_WINDOWS && !defined USE_CAIRO
       if (img->mask_img)
 	{
 	  image_destroy_x_image (img->mask_img);
@@ -1290,14 +1414,21 @@ image_clear_image_1 (struct frame *f, struct image *img, int flags)
   if ((flags & CLEAR_IMAGE_COLORS) && img->ncolors)
     {
       /* W32_TODO: color table support.  */
-#ifdef HAVE_X_WINDOWS
+#if defined HAVE_X_WINDOWS && !defined USE_CAIRO
       x_free_colors (f, img->colors, img->ncolors);
-#endif /* HAVE_X_WINDOWS */
+#endif /* HAVE_X_WINDOWS && !USE_CAIRO */
       xfree (img->colors);
       img->colors = NULL;
       img->ncolors = 0;
     }
 
+#ifdef USE_CAIRO
+  if (img->cr_data)
+    {
+      cairo_surface_destroy ((cairo_surface_t *) img->cr_data);
+      img->cr_data = NULL;
+    }
+#endif	/* USE_CAIRO */
 }
 
 /* Free X resources of image IMG which is used on frame F.  */
@@ -1306,10 +1437,6 @@ static void
 image_clear_image (struct frame *f, struct image *img)
 {
   block_input ();
-#ifdef USE_CAIRO
-  if (img->cr_data)
-    cairo_surface_destroy ((cairo_surface_t *)img->cr_data);
-#endif
   image_clear_image_1 (f, img,
 		   CLEAR_IMAGE_PIXMAP | CLEAR_IMAGE_MASK | CLEAR_IMAGE_COLORS);
   unblock_input ();
@@ -2000,14 +2127,10 @@ mark_image_cache (struct image_cache *c)
 			  X / NS / W32 support code
  ***********************************************************************/
 
-/* Return true if XIMG's size WIDTH x HEIGHT doesn't break the
-   windowing system.
-   WIDTH and HEIGHT must both be positive.
-   If XIMG is null, assume it is a bitmap.  */
+#ifdef HAVE_X_WINDOWS
 static bool
-image_check_image_size (Emacs_Pix_Container ximg, int width, int height)
+x_check_image_size (XImage *ximg, int width, int height)
 {
-#ifdef HAVE_X_WINDOWS
   /* Respect Xlib's limits: it cannot deal with images that have more
      than INT_MAX (and/or UINT_MAX) bytes.  And respect Emacs's limits
      of PTRDIFF_MAX (and/or SIZE_MAX) bytes for any object.  */
@@ -2032,29 +2155,12 @@ image_check_image_size (Emacs_Pix_Container ximg, int width, int height)
     }
   return (width <= (INT_MAX - (bitmap_pad - 1)) / depth
 	  && height <= X_IMAGE_BYTES_MAX / bytes_per_line);
-#else
-  /* FIXME: Implement this check for the HAVE_NS and HAVE_NTGUI cases.
-     For now, assume that every image size is allowed on these systems.  */
-  return 1;
-#endif
 }
 
-/* Create an Emacs_Pix_Container and a pixmap of size WIDTH x
-   HEIGHT for use on frame F.  Set *PIMG and *PIXMAP to the
-   Emacs_Pix_Container and Emacs_Pixmap created.  Set (*PIMG)->data
-   to a raster of WIDTH x HEIGHT pixels allocated via xmalloc.  Print
-   error messages via image_error if an error occurs.  Value is true
-   if successful.
-
-   On W32, a DEPTH of zero signifies a 24 bit image, otherwise DEPTH
-   should indicate the bit depth of the image.  */
-
 static bool
-image_create_x_image_and_pixmap_1 (struct frame *f, int width, int height, int depth,
-                                   Emacs_Pix_Container *pimg,
-                                   Emacs_Pixmap *pixmap, Picture *picture)
+x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth,
+			     XImage **ximg, Pixmap *pixmap)
 {
-#ifdef HAVE_X_WINDOWS
   Display *display = FRAME_X_DISPLAY (f);
   Drawable drawable = FRAME_X_DRAWABLE (f);
   Screen *screen = FRAME_X_SCREEN (f);
@@ -2063,38 +2169,104 @@ image_create_x_image_and_pixmap_1 (struct frame *f, int width, int height, int d
 
   if (depth <= 0)
     depth = DefaultDepthOfScreen (screen);
-  *pimg = XCreateImage (display, DefaultVisualOfScreen (screen),
+  *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
 			depth, ZPixmap, 0, NULL, width, height,
 			depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
-  if (*pimg == NULL)
+  if (*ximg == NULL)
     {
       image_error ("Unable to allocate X image");
       return 0;
     }
 
-  if (! image_check_image_size (*pimg, width, height))
+  if (! x_check_image_size (*ximg, width, height))
     {
-      image_destroy_x_image (*pimg);
-      *pimg = NULL;
+      x_destroy_x_image (*ximg);
+      *ximg = NULL;
       image_error ("Image too large (%dx%d)",
 		   make_fixnum (width), make_fixnum (height));
       return 0;
     }
 
   /* Allocate image raster.  */
-  (*pimg)->data = xmalloc ((*pimg)->bytes_per_line * height);
+  (*ximg)->data = xmalloc ((*ximg)->bytes_per_line * height);
 
   /* Allocate a pixmap of the same size.  */
   *pixmap = XCreatePixmap (display, drawable, width, height, depth);
   if (*pixmap == NO_PIXMAP)
     {
-      image_destroy_x_image (*pimg);
-      *pimg = NULL;
+      x_destroy_x_image (*ximg);
+      *ximg = NULL;
       image_error ("Unable to create X pixmap");
       return 0;
     }
 
+  return 1;
+}
+
+static void
+x_destroy_x_image (XImage *ximg)
+{
+  eassert (input_blocked_p ());
+  if (ximg)
+    {
+      xfree (ximg->data);
+      ximg->data = NULL;
+    }
+}
+
+#endif	/* HAVE_X_WINDOWS */
+
+/* Return true if XIMG's size WIDTH x HEIGHT doesn't break the
+   windowing system.
+   WIDTH and HEIGHT must both be positive.
+   If XIMG is null, assume it is a bitmap.  */
+
+static bool
+image_check_image_size (Emacs_Pix_Container ximg, int width, int height)
+{
+#if defined HAVE_X_WINDOWS && !defined USE_CAIRO
+  return x_check_image_size (ximg, width, height);
+#else
+  /* FIXME: Implement this check for the HAVE_NS and HAVE_NTGUI cases.
+     For now, assume that every image size is allowed on these systems.  */
+  return 1;
+#endif
+}
+
+/* Create an Emacs_Pix_Container and a pixmap of size WIDTH x
+   HEIGHT for use on frame F.  Set *PIMG and *PIXMAP to the
+   Emacs_Pix_Container and Emacs_Pixmap created.  Set (*PIMG)->data
+   to a raster of WIDTH x HEIGHT pixels allocated via xmalloc.  Print
+   error messages via image_error if an error occurs.  Value is true
+   if successful.
+
+   On W32, a DEPTH of zero signifies a 24 bit image, otherwise DEPTH
+   should indicate the bit depth of the image.  */
+
+static bool
+image_create_x_image_and_pixmap_1 (struct frame *f, int width, int height, int depth,
+                                   Emacs_Pix_Container *pimg,
+                                   Emacs_Pixmap *pixmap, Picture *picture)
+{
+#ifdef USE_CAIRO
+  eassert (input_blocked_p ());
+
+  /* Allocate a pixmap of the same size.  */
+  *pixmap = image_create_pix_container (f, width, height, depth);
+  if (*pixmap == NO_PIXMAP)
+    {
+      *pimg = NULL;
+      image_error ("Unable to create X pixmap", Qnil, Qnil);
+      return 0;
+    }
+
+  *pimg = *pixmap;
+  return 1;
+#elif defined HAVE_X_WINDOWS
+  if (!x_create_x_image_and_pixmap (f, width, height, depth, pimg, pixmap))
+    return 0;
 # ifdef HAVE_XRENDER
+  Display *display = FRAME_X_DISPLAY (f);
   int event_basep, error_basep;
   if (picture && XRenderQueryExtension (display, &event_basep, &error_basep))
     {
@@ -2238,14 +2410,14 @@ image_create_x_image_and_pixmap_1 (struct frame *f, int width, int height, int d
 static void
 image_destroy_x_image (Emacs_Pix_Container pimg)
 {
+#if defined HAVE_X_WINDOWS && !defined USE_CAIRO
+  x_destroy_x_image (pimg);
+#else
   eassert (input_blocked_p ());
   if (pimg)
     {
-#ifdef HAVE_X_WINDOWS
-      xfree (pimg->data);
-      pimg->data = NULL;
-      XDestroyImage (pimg);
-#endif /* HAVE_X_WINDOWS */
+#ifdef USE_CAIRO
+#endif	/* USE_CAIRO */
 #ifdef HAVE_NTGUI
       /* Data will be freed by DestroyObject.  */
       pimg->data = NULL;
@@ -2255,6 +2427,7 @@ image_destroy_x_image (Emacs_Pix_Container pimg)
       ns_release_object (pimg);
 #endif /* HAVE_NS */
     }
+#endif
 }
 
 
@@ -2266,7 +2439,9 @@ static void
 gui_put_x_image (struct frame *f, Emacs_Pix_Container pimg,
                  Emacs_Pixmap pixmap, int width, int height)
 {
-#ifdef HAVE_X_WINDOWS
+#ifdef USE_CAIRO
+  eassert (pimg == pixmap);
+#elif defined HAVE_X_WINDOWS
   GC gc;
 
   eassert (input_blocked_p ());
@@ -2319,7 +2494,7 @@ static void
 image_put_x_image (struct frame *f, struct image *img, Emacs_Pix_Container ximg,
 		   bool mask_p)
 {
-#ifdef HAVE_X_WINDOWS
+#if defined HAVE_X_WINDOWS && !defined USE_CAIRO
   if (!mask_p)
     {
       eassert (img->ximg == NULL);
@@ -2337,7 +2512,7 @@ image_put_x_image (struct frame *f, struct image *img, Emacs_Pix_Container ximg,
 #endif
 }
 
-#ifdef HAVE_X_WINDOWS
+#if defined HAVE_X_WINDOWS && !defined USE_CAIRO
 /* Put the X images recorded in IMG on frame F into pixmaps, then free
    the X images and their buffers.  */
 
@@ -2391,7 +2566,9 @@ image_unget_x_image_or_dc (struct image *img, bool mask_p,
 static Emacs_Pix_Container
 image_get_x_image (struct frame *f, struct image *img, bool mask_p)
 {
-#ifdef HAVE_X_WINDOWS
+#ifdef USE_CAIRO
+  return !mask_p ? img->pixmap : img->mask;
+#elif defined HAVE_X_WINDOWS
   XImage *ximg_in_img = !mask_p ? img->ximg : img->mask_img;
 
   if (ximg_in_img)
@@ -2410,7 +2587,8 @@ image_get_x_image (struct frame *f, struct image *img, bool mask_p)
 static void
 image_unget_x_image (struct image *img, bool mask_p, Emacs_Pix_Container ximg)
 {
-#ifdef HAVE_X_WINDOWS
+#ifdef USE_CAIRO
+#elif defined HAVE_X_WINDOWS
   XImage *ximg_in_img = !mask_p ? img->ximg : img->mask_img;
 
   if (ximg_in_img)
@@ -2869,28 +3047,32 @@ Create_Pixmap_From_Bitmap_Data (struct frame *f, struct image *img, char *data,
 				RGB_PIXEL_COLOR fg, RGB_PIXEL_COLOR bg,
 				bool non_default_colors)
 {
-#ifdef HAVE_NTGUI
+#ifdef USE_CAIRO
+  Emacs_Color fgbg[] = {{.pixel = fg}, {.pixel = bg}};
+  FRAME_TERMINAL (f)->query_colors (f, fgbg, ARRAYELTS (fgbg));
+  fg = lookup_rgb_color (f, fgbg[0].red, fgbg[0].green, fgbg[0].blue);
+  bg = lookup_rgb_color (f, fgbg[1].red, fgbg[1].green, fgbg[1].blue);
+  img->pixmap
+    = image_pix_container_create_from_bitmap_data (f, data, img->width,
+						   img->height, fg, bg);
+#elif defined HAVE_X_WINDOWS
+  img->pixmap
+    = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
+				   FRAME_X_DRAWABLE (f),
+				   data,
+				   img->width, img->height,
+				   fg, bg,
+				   DefaultDepthOfScreen (FRAME_X_SCREEN (f)))
+#elif defined HAVE_NTGUI
   img->pixmap
     = w32_create_pixmap_from_bitmap_data (img->width, img->height, data);
 
   /* If colors were specified, transfer the bitmap to a color one.  */
   if (non_default_colors)
     convert_mono_to_color_image (f, img, fg, bg);
-
-#elif defined (HAVE_NS)
+#elif defined HAVE_NS
   img->pixmap = ns_image_from_XBM (data, img->width, img->height, fg, bg);
-
-#else
-  img->pixmap =
-   (image_check_image_size (0, img->width, img->height)
-    ? XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
-                                   FRAME_X_DRAWABLE (f),
-				   data,
-				   img->width, img->height,
-				   fg, bg,
-				   DefaultDepthOfScreen (FRAME_X_SCREEN (f)))
-    : NO_PIXMAP);
-#endif /* !HAVE_NTGUI && !HAVE_NS */
+#endif
 }
 
 
@@ -3099,9 +3281,12 @@ xbm_load_image (struct frame *f, struct image *img, char *contents, char *end)
 	  non_default_colors = 1;
 	}
 
-      Create_Pixmap_From_Bitmap_Data (f, img, data,
-				      foreground, background,
-				      non_default_colors);
+      if (image_check_image_size (0, img->width, img->height))
+	Create_Pixmap_From_Bitmap_Data (f, img, data,
+					foreground, background,
+					non_default_colors);
+      else
+	img->pixmap = NO_PIXMAP;
       xfree (data);
 
       if (img->pixmap == NO_PIXMAP)
@@ -3315,7 +3500,7 @@ xbm_load (struct frame *f, struct image *img)
 #endif /* not HAVE_NTGUI */
 #endif /* HAVE_XPM */
 
-#if defined (HAVE_XPM) || defined (HAVE_NS)
+#if defined HAVE_XPM || defined USE_CAIRO || defined HAVE_NS
 
 /* Indices of image specification fields in xpm_format, below.  */
 
@@ -3353,19 +3538,17 @@ static const struct image_keyword xpm_format[XPM_LAST] =
   {":background",	IMAGE_STRING_OR_NIL_VALUE,		0}
 };
 
-#ifdef HAVE_X_WINDOWS
+#if defined HAVE_X_WINDOWS && !defined USE_CAIRO
 
 /* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation
    functions for allocating image colors.  Our own functions handle
    color allocation failures more gracefully than the ones on the XPM
    lib.  */
 
-#ifndef USE_CAIRO
 #if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
 #define ALLOC_XPM_COLORS
 #endif
-#endif /* USE_CAIRO */
-#endif /* HAVE_X_WINDOWS */
+#endif /* HAVE_X_WINDOWS && !USE_CAIRO */
 
 #ifdef ALLOC_XPM_COLORS
 
@@ -3614,7 +3797,7 @@ xpm_image_p (Lisp_Object object)
 	      || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
 }
 
-#endif /* HAVE_XPM || HAVE_NS */
+#endif /* HAVE_XPM || USE_CAIRO || HAVE_NS */
 
 #if defined HAVE_XPM && defined HAVE_X_WINDOWS && !defined USE_GTK
 ptrdiff_t
@@ -3670,7 +3853,7 @@ x_create_bitmap_from_xpm_data (struct frame *f, const char **bits)
 /* Load image IMG which will be displayed on frame F.  Value is
    true if successful.  */
 
-#ifdef HAVE_XPM
+#if defined HAVE_XPM && !defined USE_CAIRO
 
 static bool
 xpm_load (struct frame *f, struct image *img)
@@ -3838,44 +4021,6 @@ xpm_load (struct frame *f, struct image *img)
 #endif /* HAVE_NTGUI */
     }
 
-#ifdef USE_CAIRO
-  /* Load very specific Xpm:s.  */
-  if (rc == XpmSuccess
-      && img->ximg->format == ZPixmap
-      && img->ximg->bits_per_pixel == 32
-      && (! img->mask_img || img->mask_img->bits_per_pixel == 1))
-    {
-      int width = img->ximg->width;
-      int height = img->ximg->height;
-      cairo_surface_t *surface = create_cairo_image_surface (width, height);
-      int i;
-      uint32_t *od = (uint32_t *) cairo_image_surface_get_data (surface);
-      uint32_t *id = (uint32_t *) img->ximg->data;
-      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)
-        {
-          int k;
-          for (k = 0; k < width; ++k)
-            {
-              int idx = i * img->ximg->bytes_per_line/4 + k;
-              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] = bgcolor;
-            }
-        }
-
-      set_cairo_image_surface (img, surface);
-    }
-  else
-    {
-      rc = XpmFileInvalid;
-      image_clear_image (f, img);
-    }
-#else
 #ifdef HAVE_X_WINDOWS
   if (rc == XpmSuccess)
     {
@@ -3901,7 +4046,6 @@ xpm_load (struct frame *f, struct image *img)
 	}
     }
 #endif
-#endif /* ! USE_CAIRO */
 
   if (rc == XpmSuccess)
     {
@@ -4004,9 +4148,9 @@ xpm_load (struct frame *f, struct image *img)
   return rc == XpmSuccess;
 }
 
-#endif /* HAVE_XPM */
+#endif /* HAVE_XPM && !USE_CAIRO */
 
-#if defined (HAVE_NS) && !defined (HAVE_XPM)
+#if defined USE_CAIRO || (defined HAVE_NS && !defined HAVE_XPM)
 
 /* XPM support functions for NS where libxpm is not available.
    Only XPM version 3 (without any extensions) is supported.  */
@@ -4346,7 +4490,9 @@ xpm_load_image (struct frame *f,
 		color_val = Qt;
 	      else if (FRAME_TERMINAL (f)->defined_color_hook
                        (f, SSDATA (XCDR (specified_color)), &cdef, false, false))
-		color_val = make_fixnum (cdef.pixel);
+		color_val
+		  = make_fixnum (lookup_rgb_color (f, cdef.red, cdef.green,
+						   cdef.blue));
 	    }
 	}
       if (NILP (color_val) && max_key > 0)
@@ -4355,7 +4501,8 @@ xpm_load_image (struct frame *f,
 	    color_val = Qt;
 	  else if (FRAME_TERMINAL (f)->defined_color_hook
                    (f, max_color, &cdef, false, false))
-	    color_val = make_fixnum (cdef.pixel);
+	    color_val = make_fixnum (lookup_rgb_color (f, cdef.red, cdef.green,
+						       cdef.blue));
 	}
       if (!NILP (color_val))
 	(*put_color_table) (color_table, beg, chars_per_pixel, color_val);
@@ -4363,6 +4510,14 @@ xpm_load_image (struct frame *f,
       expect (',');
     }
 
+  unsigned long frame_fg = FRAME_FOREGROUND_PIXEL (f);
+#ifdef USE_CAIRO
+  {
+    Emacs_Color color = {.pixel = frame_fg};
+    FRAME_TERMINAL (f)->query_colors (f, &color, 1);
+    frame_fg = lookup_rgb_color (f, color.red, color.green, color.blue);
+  }
+#endif
   for (y = 0; y < height; y++)
     {
       expect (XPM_TK_STRING);
@@ -4374,11 +4529,10 @@ xpm_load_image (struct frame *f,
 	  Lisp_Object color_val =
 	    (*get_color_table) (color_table, str, chars_per_pixel);
 
-	  XPutPixel (ximg, x, y,
-		     (FIXNUMP (color_val) ? XFIXNUM (color_val)
-		      : FRAME_FOREGROUND_PIXEL (f)));
+	  PUT_PIXEL (ximg, x, y,
+		     FIXNUMP (color_val) ? XFIXNUM (color_val) : frame_fg);
 #ifndef HAVE_NS
-	  XPutPixel (mask_img, x, y,
+	  PUT_PIXEL (mask_img, x, y,
 		     (!EQ (color_val, Qt) ? PIX_MASK_DRAW
 		      : (have_mask = true, PIX_MASK_RETAIN)));
 #else
@@ -4735,10 +4889,8 @@ lookup_rgb_color (struct frame *f, int r, int g, int b)
 {
 #ifdef HAVE_NTGUI
   return PALETTERGB (r >> 8, g >> 8, b >> 8);
-#elif defined HAVE_NS
+#elif defined USE_CAIRO || defined HAVE_NS
   return RGB_TO_ULONG (r >> 8, g >> 8, b >> 8);
-#elif defined USE_CAIRO
-  return (0xffu << 24) | (r << 16) | (g << 8) | b;
 #else
   xsignal1 (Qfile_error,
 	    build_string ("This Emacs mishandles this image file type"));
@@ -4810,7 +4962,7 @@ image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p)
   p = colors;
   for (y = 0; y < img->height; ++y)
     {
-#if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
+#if !defined USE_CAIRO && !defined HAVE_NS
       Emacs_Color *row = p;
       for (x = 0; x < img->width; ++x, ++p)
 	p->pixel = GET_PIXEL (ximg, x, y);
@@ -4818,11 +4970,9 @@ image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p)
         {
           FRAME_TERMINAL (f)->query_colors (f, row, img->width);
         }
-#else
-
+#else  /* USE_CAIRO || HAVE_NS */
       for (x = 0; x < img->width; ++x, ++p)
 	{
-	  /* W32_TODO: palette support needed here?  */
 	  p->pixel = GET_PIXEL (ximg, x, y);
 	  if (rgb_p)
 	    {
@@ -4831,7 +4981,7 @@ image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p)
 	      p->blue = BLUE16_FROM_ULONG (p->pixel);
 	    }
 	}
-#endif /* HAVE_X_WINDOWS */
+#endif	/* USE_CAIRO || HAVE_NS */
     }
 
   image_unget_x_image_or_dc (img, 0, ximg, prev);
@@ -4907,7 +5057,7 @@ image_from_emacs_colors (struct frame *f, struct image *img, Emacs_Color *colors
       {
 	unsigned long pixel;
 	pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
-	XPutPixel (oimg, x, y, pixel);
+	PUT_PIXEL (oimg, x, y, pixel);
       }
 
   xfree (colors);
@@ -5056,6 +5206,44 @@ image_edge_detection (struct frame *f, struct image *img,
 }
 
 
+#if defined HAVE_X_WINDOWS || defined USE_CAIRO
+static void
+image_pixmap_draw_cross (struct frame *f, Emacs_Pixmap pixmap,
+			 int x, int y, unsigned int width, unsigned int height,
+			 unsigned long color)
+{
+#ifdef USE_CAIRO
+  cairo_surface_t *surface
+    = cairo_image_surface_create_for_data ((unsigned char *) pixmap->data,
+					   (pixmap->bits_per_pixel == 32
+					    ? CAIRO_FORMAT_RGB24
+					    : CAIRO_FORMAT_A8),
+					   pixmap->width, pixmap->height,
+					   pixmap->bytes_per_line);
+  cairo_t *cr = cairo_create (surface);
+  cairo_surface_destroy (surface);
+  cairo_set_source_rgb (cr, RED_FROM_ULONG (color) / 255.0,
+			GREEN_FROM_ULONG (color) / 255.0,
+			BLUE_FROM_ULONG (color) / 255.0);
+  cairo_move_to (cr, x + 0.5, y + 0.5);
+  cairo_rel_line_to (cr, width - 1, height - 1);
+  cairo_rel_move_to (cr, 0, - (height - 1));
+  cairo_rel_line_to (cr, - (width - 1), height - 1);
+  cairo_set_line_width (cr, 1);
+  cairo_stroke (cr);
+  cairo_destroy (cr);
+#elif HAVE_X_WINDOWS
+  Display *dpy = FRAME_X_DISPLAY (f);
+  GC gc = XCreateGC (dpy, pixmap, 0, NULL);
+
+  XSetForeground (dpy, gc, color);
+  XDrawLine (dpy, pixmap, gc, x, y, x + width - 1, y + height - 1);
+  XDrawLine (dpy, pixmap, gc, x, y + height - 1, x + width - 1, y);
+  XFreeGC (dpy, gc);
+#endif	/* HAVE_X_WINDOWS */
+}
+#endif	/* HAVE_X_WINDOWS || USE_CAIRO */
+
 /* Transform image IMG on frame F so that it looks disabled.  */
 
 static void
@@ -5097,30 +5285,22 @@ image_disable_image (struct frame *f, struct image *img)
 #ifndef HAVE_NTGUI
 #ifndef HAVE_NS  /* TODO: NS support, however this not needed for toolbars */
 
+#ifndef USE_CAIRO
+#define CrossForeground(f) BLACK_PIX_DEFAULT (f)
 #define MaskForeground(f)  WHITE_PIX_DEFAULT (f)
+#else  /* USE_CAIRO */
+#define CrossForeground(f) 0
+#define MaskForeground(f)  PIX_MASK_DRAW
+#endif	/* USE_CAIRO */
 
-      Display *dpy = FRAME_X_DISPLAY (f);
-      GC gc;
-
+#ifndef USE_CAIRO
       image_sync_to_pixmaps (f, img);
-      gc = XCreateGC (dpy, img->pixmap, 0, NULL);
-      XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
-      XDrawLine (dpy, img->pixmap, gc, 0, 0,
-		 img->width - 1, img->height - 1);
-      XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
-		 img->width - 1, 0);
-      XFreeGC (dpy, gc);
-
+#endif	/* !USE_CAIRO */
+      image_pixmap_draw_cross (f, img->pixmap, 0, 0, img->width, img->height,
+			       CrossForeground (f));
       if (img->mask)
-	{
-	  gc = XCreateGC (dpy, img->mask, 0, NULL);
-	  XSetForeground (dpy, gc, MaskForeground (f));
-	  XDrawLine (dpy, img->mask, gc, 0, 0,
-		     img->width - 1, img->height - 1);
-	  XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
-		     img->width - 1, 0);
-	  XFreeGC (dpy, gc);
-	}
+	image_pixmap_draw_cross (f, img->mask, 0, 0, img->width, img->height,
+				 MaskForeground (f));
 #endif /* !HAVE_NS */
 #else
       HDC hdc, bmpdc;
@@ -5212,6 +5392,7 @@ image_build_heuristic_mask (struct frame *f, struct image *img,
 
       if (i == 3 && NILP (how))
 	{
+#ifndef USE_CAIRO
 	  char color_name[30];
 	  sprintf (color_name, "#%04x%04x%04x",
 		   rgb[0] + 0u, rgb[1] + 0u, rgb[2] + 0u);
@@ -5220,6 +5401,9 @@ image_build_heuristic_mask (struct frame *f, struct image *img,
 		0x00ffffff & /* Filter out palette info.  */
 #endif /* HAVE_NTGUI */
 		image_alloc_image_color (f, img, build_string (color_name), 0));
+#else  /* USE_CAIRO */
+	  bg = lookup_rgb_color (f, rgb[0], rgb[1], rgb[2]);
+#endif	/* USE_CAIRO */
 	  use_img_background = 0;
 	}
     }
@@ -5233,7 +5417,7 @@ image_build_heuristic_mask (struct frame *f, struct image *img,
   for (y = 0; y < img->height; ++y)
     for (x = 0; x < img->width; ++x)
 #ifndef HAVE_NS
-      XPutPixel (mask_img, x, y, (XGetPixel (ximg, x, y) != bg
+      PUT_PIXEL (mask_img, x, y, (GET_PIXEL (ximg, x, y) != bg
 				  ? PIX_MASK_DRAW : PIX_MASK_RETAIN));
 #else
       if (XGetPixel (ximg, x, y) == bg)
@@ -5406,9 +5590,7 @@ pbm_load (struct frame *f, struct image *img)
   enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
   char *contents = NULL;
   char *end, *p;
-#ifndef USE_CAIRO
   Emacs_Pix_Container ximg;
-#endif
 
   specified_file = image_spec_value (img->spec, QCfile, NULL);
 
@@ -5492,11 +5674,6 @@ pbm_load (struct frame *f, struct image *img)
   width = pbm_scan_number (&p, end);
   height = pbm_scan_number (&p, end);
 
-#ifdef USE_CAIRO
-  cairo_surface_t *surface = create_cairo_image_surface (width, height);
-  uint32_t *dataptr = (uint32_t *) cairo_image_surface_get_data (surface);
-#endif
-
   if (type != PBM_MONO)
     {
       max_color_idx = pbm_scan_number (&p, end);
@@ -5513,10 +5690,8 @@ 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 ();
@@ -5528,42 +5703,11 @@ 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
-      Emacs_Color 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)
-          || ! FRAME_TERMINAL (f)->defined_color_hook (f,
-                                                       SSDATA (fmt[PBM_FOREGROUND].value),
-                                                       &xfg,
-                                                       false,
-                                                       false))
-        {
-          xfg.pixel = fg;
-          x_query_colors (f, &xfg, 1);
-        }
-      fga32 = emacs_color_to_argb32 (&xfg);
-
-      if (! fmt[PBM_BACKGROUND].count
-          || ! STRINGP (fmt[PBM_BACKGROUND].value)
-          || ! FRAME_TERMINAL (f)->defined_color_hook (f,
-                                                       SSDATA (fmt[PBM_BACKGROUND].value),
-                                                       &xbg,
-                                                       false,
-                                                       false))
-	{
-          xbg.pixel = bg;
-          x_query_colors (f, &xbg, 1);
-	}
-      bga32 = emacs_color_to_argb32 (&xbg);
-#else
       if (fmt[PBM_FOREGROUND].count
 	  && STRINGP (fmt[PBM_FOREGROUND].value))
 	fg = image_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
@@ -5574,8 +5718,15 @@ pbm_load (struct frame *f, struct image *img)
 	  img->background = bg;
 	  img->background_valid = 1;
 	}
-#endif
 
+#ifdef USE_CAIRO
+      {
+	Emacs_Color fgbg[] = {{.pixel = fg}, {.pixel = bg}};
+	FRAME_TERMINAL (f)->query_colors (f, fgbg, ARRAYELTS (fgbg));
+	fg = lookup_rgb_color (f, fgbg[0].red, fgbg[0].green, fgbg[0].blue);
+	bg = lookup_rgb_color (f, fgbg[1].red, fgbg[1].green, fgbg[1].blue);
+      }
+#endif
       for (y = 0; y < height; ++y)
 	for (x = 0; x < width; ++x)
 	  {
@@ -5585,11 +5736,7 @@ pbm_load (struct frame *f, struct image *img)
 		  {
 		    if (p >= end)
 		      {
-#ifdef USE_CAIRO
-                        cairo_surface_destroy (surface);
-#else
 			image_destroy_x_image (ximg);
-#endif
 			image_clear_image (f, img);
 			image_error ("Invalid image size in image `%s'",
 				     img->spec);
@@ -5613,11 +5760,7 @@ pbm_load (struct frame *f, struct image *img)
 		  g = 0;
 	      }
 
-#ifdef USE_CAIRO
-            *dataptr++ = g ? fga32 : bga32;
-#else
-	    XPutPixel (ximg, x, y, g ? fg : bg);
-#endif
+	    PUT_PIXEL (ximg, x, y, g ? fg : bg);
 	  }
     }
   else
@@ -5631,11 +5774,7 @@ pbm_load (struct frame *f, struct image *img)
 
       if (raw_p && p + expected_size > end)
 	{
-#ifdef USE_CAIRO
-          cairo_surface_destroy (surface);
-#else
 	  image_destroy_x_image (ximg);
-#endif
 	  image_clear_image (f, img);
 	  image_error ("Invalid image size in image `%s'", img->spec);
 	  goto error;
@@ -5665,28 +5804,17 @@ pbm_load (struct frame *f, struct image *img)
 
 	    if (r < 0 || g < 0 || b < 0)
 	      {
-#ifdef USE_CAIRO
-                cairo_surface_destroy (surface);
-#else
 		image_destroy_x_image (ximg);
-#endif
 		image_error ("Invalid pixel value in image `%s'", img->spec);
 		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++ = (0xffu << 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
+	    PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, r, g, b));
 	  }
     }
 
@@ -5702,16 +5830,12 @@ pbm_load (struct frame *f, struct image *img)
 
   /* Maybe fill in the background field while we have ximg handy.  */
 
-#ifdef USE_CAIRO
-  set_cairo_image_surface (img, surface);
-#else
   if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
     /* Casting avoids a GCC warning.  */
     IMAGE_BACKGROUND (img, f, (Emacs_Pix_Context)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;
@@ -6028,13 +6152,7 @@ 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 */
   ptrdiff_t nbytes;
-
-#ifdef USE_CAIRO
-  cairo_surface_t *surface;
-  uint32_t *dataptr;
-#else
   Emacs_Pix_Container ximg, mask_img = NULL;
-#endif
 
   /* Find out what file to load.  */
   specified_file = image_spec_value (img->spec, QCfile, NULL);
@@ -6152,12 +6270,10 @@ 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.  */
@@ -6249,10 +6365,6 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
       c->fp = NULL;
     }
 
-#ifdef USE_CAIRO
-  surface = create_cairo_image_surface (width, height);
-  dataptr = (uint32_t *) cairo_image_surface_get_data (surface);
-#else
   /* Create an image and pixmap serving as mask if the PNG image
      contains an alpha channel.  */
   if (channels == 4
@@ -6264,7 +6376,6 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
       image_clear_image_1 (f, img, CLEAR_IMAGE_PIXMAP);
       goto error;
     }
-#endif
 
   /* Fill the X image and mask from PNG data.  */
   init_color_table ();
@@ -6277,18 +6388,10 @@ 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;
-	  XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
+	  PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, r, g, b));
 	  /* An alpha channel, aka mask channel, associates variable
 	     transparency with an image.  Where other image formats
 	     support binary transparency---fully transparent or fully
@@ -6308,10 +6411,9 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
 	  if (channels == 4)
 	    {
 	      if (mask_img)
-		XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : PIX_MASK_RETAIN);
+		PUT_PIXEL (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : PIX_MASK_RETAIN);
 	      ++p;
 	    }
-#endif
 	}
     }
 
@@ -6322,7 +6424,14 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
       png_color_16 *bg;
       if (png_get_bKGD (png_ptr, info_ptr, &bg))
 	{
+#ifndef USE_CAIRO
 	  img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
+#else  /* USE_CAIRO */
+	  char color_name[30];
+	  sprintf (color_name, "#%04x%04x%04x", bg->red, bg->green, bg->blue);
+	  img->background
+	    = image_alloc_image_color (f, img, build_string (color_name), 0);
+#endif /* USE_CAIRO */
 	  img->background_valid = 1;
 	}
     }
@@ -6341,9 +6450,6 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
   img->width = width;
   img->height = height;
 
-#ifdef USE_CAIRO
-  set_cairo_image_surface (img, surface);
-#else
   /* Maybe fill in the background field while we have ximg handy.
      Casting avoids a GCC warning.  */
   IMAGE_BACKGROUND (img, f, (Emacs_Pix_Context)ximg);
@@ -6360,7 +6466,6 @@ 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;
 }
@@ -6774,10 +6879,8 @@ jpeg_load_body (struct frame *f, struct image *img,
   int row_stride, x, y;
   int width, height;
   int i, ir, ig, ib;
-#ifndef USE_CAIRO
   unsigned long *colors;
   Emacs_Pix_Container ximg = NULL;
-#endif
 
   /* Open the JPEG file.  */
   specified_file = image_spec_value (img->spec, QCfile, NULL);
@@ -6837,9 +6940,7 @@ 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
       image_destroy_x_image (ximg);
-#endif
       /* Free pixmap and colors.  */
       image_clear_image (f, img);
       return 0;
@@ -6870,23 +6971,19 @@ 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
      colors generated, and mgr->cinfo.colormap is a two-dimensional array
      of color indices in the range 0..mgr->cinfo.actual_number_of_colors.
      No more than 255 colors will be generated.  */
-#ifndef USE_CAIRO
   USE_SAFE_ALLOCA;
-#endif
   {
     if (mgr->cinfo.out_color_components > 2)
       ir = 0, ig = 1, ib = 2;
@@ -6895,7 +6992,6 @@ jpeg_load_body (struct frame *f, struct image *img,
     else
       ir = 0, ig = 0, ib = 0;
 
-#ifndef USE_CAIRO
     /* Use the color table mechanism because it handles colors that
        cannot be allocated nicely.  Such colors will be replaced with
        a default color, and we don't have to care about which colors
@@ -6912,7 +7008,6 @@ jpeg_load_body (struct frame *f, struct image *img,
 	int b = mgr->cinfo.colormap[ib][i] << 8;
 	colors[i] = lookup_rgb_color (f, r, g, b);
       }
-#endif
 
 #ifdef COLOR_TABLE_SUPPORT
     /* Remember those colors actually allocated.  */
@@ -6925,36 +7020,12 @@ jpeg_load_body (struct frame *f, struct image *img,
   row_stride = width * mgr->cinfo.output_components;
   buffer = mgr->cinfo.mem->alloc_sarray ((j_common_ptr) &mgr->cinfo,
 					 JPOOL_IMAGE, row_stride, 1);
-#ifdef USE_CAIRO
-  {
-    cairo_surface_t *surface = create_cairo_image_surface (width, height);
-    uint32_t *dataptr = (uint32_t *) cairo_image_surface_get_data (surface);
-    int r, g, b;
-
-    for (y = 0; y < height; ++y)
-      {
-        jpeg_read_scanlines (&mgr->cinfo, buffer, 1);
-
-        for (x = 0; x < width; ++x)
-          {
-            i = buffer[0][x];
-            r = mgr->cinfo.colormap[ir][i];
-            g = mgr->cinfo.colormap[ig][i];
-            b = mgr->cinfo.colormap[ib][i];
-            *dataptr++ = (0xffu << 24) | (r << 16) | (g << 8) | b;
-          }
-      }
-
-    set_cairo_image_surface (img, surface);
-  }
-#else
   for (y = 0; y < height; ++y)
     {
       jpeg_read_scanlines (&mgr->cinfo, buffer, 1);
       for (x = 0; x < mgr->cinfo.output_width; ++x)
-	XPutPixel (ximg, x, y, colors[buffer[0][x]]);
+	PUT_PIXEL (ximg, x, y, colors[buffer[0][x]]);
     }
-#endif
 
   /* Clean up.  */
   jpeg_finish_decompress (&mgr->cinfo);
@@ -6962,7 +7033,6 @@ jpeg_load_body (struct frame *f, struct image *img,
   if (fp)
     fclose (fp);
 
-#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.  */
@@ -6971,7 +7041,6 @@ jpeg_load_body (struct frame *f, struct image *img,
   /* Put ximg into the image.  */
   image_put_x_image (f, img, ximg, 0);
   SAFE_FREE ();
-#endif
   return 1;
 }
 
@@ -7384,28 +7453,6 @@ tiff_load (struct frame *f, struct image *img)
       return 0;
     }
 
-#ifdef USE_CAIRO
-  {
-    cairo_surface_t *surface = create_cairo_image_surface (width, height);
-    uint32_t *dataptr = (uint32_t *) cairo_image_surface_get_data (surface);
-
-    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;
-          }
-      }
-
-    set_cairo_image_surface (img, surface);
-  }
-#else
   /* Initialize the color table.  */
   init_color_table ();
 
@@ -7420,7 +7467,7 @@ tiff_load (struct frame *f, struct image *img)
 	  int r = TIFFGetR (abgr) << 8;
 	  int g = TIFFGetG (abgr) << 8;
 	  int b = TIFFGetB (abgr) << 8;
-	  XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
+	  PUT_PIXEL (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
 	}
     }
 
@@ -7441,8 +7488,6 @@ tiff_load (struct frame *f, struct image *img)
   /* Put ximg into the image.  */
   image_put_x_image (f, img, ximg, 0);
 
-#endif /* ! USE_CAIRO */
-
   xfree (buf);
   return 1;
 }
@@ -7819,26 +7864,6 @@ gif_load (struct frame *f, struct image *img)
 	}
     }
 
-#ifdef USE_CAIRO
-  cairo_surface_t *surface = create_cairo_image_surface (width, height);
-  uint32_t *data32 = (uint32_t *) cairo_image_surface_get_data (surface);
-  if (STRINGP (specified_bg))
-    {
-      Emacs_Color color;
-      if (FRAME_TERMINAL (f)->defined_color_hook
-          (f, SSDATA (specified_bg), &color, false, false))
-        {
-          uint32_t *dataptr = data32;
-          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++ = (0xffu << 24) | (r << 16) | (g << 8) | b;
-        }
-    }
-#else
   /* Create the X image and pixmap.  */
   Emacs_Pix_Container ximg;
   if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
@@ -7851,22 +7876,31 @@ gif_load (struct frame *f, struct image *img)
      Full animated GIF support requires more here (see the gif89 spec,
      disposal methods).  Let's simply assume that the part not covered
      by a sub-image is in the frame's background color.  */
+  unsigned long frame_bg;
+#ifndef USE_CAIRO
+  frame_bg = FRAME_BACKGROUND_PIXEL (f);
+#else  /* USE_CAIRO */
+  {
+    Emacs_Color color;
+    FRAME_TERMINAL (f)->query_frame_background_color (f, &color);
+    frame_bg = lookup_rgb_color (f, color.red, color.green, color.blue);
+  }
+#endif	/* USE_CAIRO */
   for (y = 0; y < img->corners[TOP_CORNER]; ++y)
     for (x = 0; x < width; ++x)
-      XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
+      PUT_PIXEL (ximg, x, y, frame_bg);
 
   for (y = img->corners[BOT_CORNER]; y < height; ++y)
     for (x = 0; x < width; ++x)
-      XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
+      PUT_PIXEL (ximg, x, y, frame_bg);
 
   for (y = img->corners[TOP_CORNER]; y < img->corners[BOT_CORNER]; ++y)
     {
       for (x = 0; x < img->corners[LEFT_CORNER]; ++x)
-	XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
+	PUT_PIXEL (ximg, x, y, frame_bg);
       for (x = img->corners[RIGHT_CORNER]; x < width; ++x)
-	XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
+	PUT_PIXEL (ximg, x, y, frame_bg);
     }
-#endif
 
   /* Read the GIF image into the X image.   */
 
@@ -7877,12 +7911,17 @@ gif_load (struct frame *f, struct image *img)
 
   init_color_table ();
 
-#ifndef USE_CAIRO
   unsigned long bgcolor UNINIT;
   if (STRINGP (specified_bg))
-    bgcolor = image_alloc_image_color (f, img, specified_bg,
-                                       FRAME_BACKGROUND_PIXEL (f));
+    {
+      bgcolor = image_alloc_image_color (f, img, specified_bg,
+					 FRAME_BACKGROUND_PIXEL (f));
+#ifdef USE_CAIRO
+      Emacs_Color color = {.pixel = bgcolor};
+      FRAME_TERMINAL (f)->query_colors (f, &color, 1);
+      bgcolor = lookup_rgb_color (f, color.red, color.green, color.blue);
 #endif
+    }
 
   for (j = 0; j <= idx; ++j)
     {
@@ -7930,7 +7969,6 @@ gif_load (struct frame *f, struct image *img)
       if (!gif_color_map)
 	gif_color_map = gif->SColorMap;
 
-#ifndef USE_CAIRO
       /* Allocate subimage colors.  */
       unsigned long pixel_colors[256] = { 0, };
 
@@ -7939,7 +7977,7 @@ gif_load (struct frame *f, struct image *img)
 	  {
 	    if (transparency_color_index == i)
 	      pixel_colors[i] = STRINGP (specified_bg)
-		? bgcolor : FRAME_BACKGROUND_PIXEL (f);
+		? bgcolor : frame_bg;
 	    else
 	      {
 		int r = gif_color_map->Colors[i].Red << 8;
@@ -7948,7 +7986,6 @@ 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)
@@ -7967,21 +8004,9 @@ gif_load (struct frame *f, struct image *img)
 		  int c = raster[y * subimg_width + x];
 		  if (transparency_color_index != c || disposal != 1)
                     {
-#ifdef USE_CAIRO
-                      uint32_t *dataptr =
-                        (data32 + ((row + subimg_top) * 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 = (0xffu << 24) | (r << 16) | (g << 8) | b;
-#else
-                      XPutPixel (ximg, x + subimg_left, row + subimg_top,
+                      PUT_PIXEL (ximg, x + subimg_left, row + subimg_top,
                                  pixel_colors[c]);
-#endif
-                   }
+		    }
 		}
 	    }
 	}
@@ -7993,19 +8018,8 @@ gif_load (struct frame *f, struct image *img)
 		int c = raster[y * subimg_width + x];
 		if (transparency_color_index != c || disposal != 1)
                   {
-#ifdef USE_CAIRO
-                    uint32_t *dataptr =
-                      (data32 + ((y + subimg_top) * 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 = (0xffu << 24) | (r << 16) | (g << 8) | b;
-#else
-                    XPutPixel (ximg, x + subimg_left, y + subimg_top,
+                    PUT_PIXEL (ximg, x + subimg_left, y + subimg_top,
                                pixel_colors[c]);
-#endif
                   }
 	      }
 	}
@@ -8064,9 +8078,6 @@ gif_load (struct frame *f, struct image *img)
 #endif
     }
 
-#ifdef USE_CAIRO
-  set_cairo_image_surface (img, surface);
-#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.  */
@@ -8074,7 +8085,6 @@ gif_load (struct frame *f, struct image *img)
 
   /* Put ximg into the image.  */
   image_put_x_image (f, img, ximg, 0);
-#endif
 
   return 1;
 }
@@ -8453,9 +8463,7 @@ imagemagick_load_image (struct frame *f, struct image *img,
   int width, height;
   size_t image_width, image_height;
   MagickBooleanType status;
-#ifndef USE_CAIRO
   Emacs_Pix_Container ximg;
-#endif
   int x, y;
   MagickWand *image_wand;
   PixelIterator *iterator;
@@ -8469,9 +8477,6 @@ imagemagick_load_image (struct frame *f, struct image *img,
   double rotation;
   char hint_buffer[MaxTextExtent];
   char *filename_hint = NULL;
-#ifdef USE_CAIRO
-  cairo_surface_t *surface;
-#endif
 
   /* Initialize the ImageMagick environment.  */
   static bool imagemagick_initialized;
@@ -8685,11 +8690,6 @@ imagemagick_load_image (struct frame *f, struct image *img,
          method is also well tested.  Some aspects of this method are
          ad-hoc and needs to be more researched. */
       void *dataptr;
-#ifdef USE_CAIRO
-      surface = create_cairo_image_surface (width, height);
-      const char *exportdepth = "BGRA";
-      dataptr = cairo_image_surface_get_data (surface);
-#else
       int imagedepth = 24; /*MagickGetImageDepth(image_wand);*/
       const char *exportdepth = imagedepth <= 8 ? "I" : "BGRP"; /*"RGBP";*/
       /* Try to create a x pixmap to hold the imagemagick pixmap.  */
@@ -8703,7 +8703,6 @@ imagemagick_load_image (struct frame *f, struct image *img,
 	  goto imagemagick_error;
 	}
       dataptr = ximg->data;
-#endif /* not USE_CAIRO */
 
       /* Oddly, the below code doesn't seem to work:*/
       /* switch(ximg->bitmap_unit){ */
@@ -8734,11 +8733,6 @@ imagemagick_load_image (struct frame *f, struct image *img,
       size_t image_height;
       double quantum_range = QuantumRange;
       MagickRealType color_scale = 65535.0 / quantum_range;
-#ifdef USE_CAIRO
-      surface = create_cairo_image_surface (width, height);
-      uint32_t *dataptr = (uint32_t *) cairo_image_surface_get_data (surface);
-      color_scale /= 256;
-#else
       /* Try to create a x pixmap to hold the imagemagick pixmap.  */
       if (!image_create_x_image_and_pixmap (f, img, width, height, 0,
 					    &ximg, 0))
@@ -8749,7 +8743,6 @@ imagemagick_load_image (struct frame *f, struct image *img,
           image_error ("Imagemagick X bitmap allocation failure");
           goto imagemagick_error;
         }
-#endif
 
       /* Copy imagemagick image to x with primitive yet robust pixel
          pusher loop.  This has been tested a lot with many different
@@ -8762,9 +8755,7 @@ imagemagick_load_image (struct frame *f, struct image *img,
 #ifdef COLOR_TABLE_SUPPORT
 	  free_color_table ();
 #endif
-#ifndef USE_CAIRO
 	  image_destroy_x_image (ximg);
-#endif
           image_error ("Imagemagick pixel iterator creation failed");
           goto imagemagick_error;
         }
@@ -8780,27 +8771,16 @@ imagemagick_load_image (struct frame *f, struct image *img,
 	  for (x = 0; x < xlim; x++)
             {
               PixelGetMagickColor (pixels[x], &pixel);
-#ifdef USE_CAIRO
-	      dataptr[width * y + x] =
-		lookup_rgb_color (f,
-				  color_scale * pixel.red,
-				  color_scale * pixel.green,
-				  color_scale * pixel.blue);
-#else
-              XPutPixel (ximg, x, y,
+              PUT_PIXEL (ximg, x, y,
                          lookup_rgb_color (f,
 					   color_scale * pixel.red,
 					   color_scale * pixel.green,
 					   color_scale * pixel.blue));
-#endif
             }
         }
       DestroyPixelIterator (iterator);
     }
 
-#ifdef USE_CAIRO
-  set_cairo_image_surface (img, surface);
-#else
 #ifdef COLOR_TABLE_SUPPORT
   /* Remember colors allocated for this image.  */
   img->colors = colors_in_color_table (&img->ncolors);
@@ -8812,7 +8792,6 @@ imagemagick_load_image (struct frame *f, struct image *img,
 
   /* Put ximg into the image.  */
   image_put_x_image (f, img, ximg, 0);
-#endif
 
   /* Final cleanup. image_wand should be the only resource left. */
   DestroyMagickWand (image_wand);
@@ -9257,33 +9236,6 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
   eassert (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);
 
   {
-#ifdef USE_CAIRO
-    cairo_surface_t *surface = create_cairo_image_surface (width, height);
-    uint32_t *dataptr = (uint32_t *) cairo_image_surface_get_data (surface);
-    uint32_t bgcolor = get_spec_bg_or_alpha_as_argb (img, f);
-
-    for (int y = 0; y < height; ++y)
-      {
-        const guchar *iconptr = pixels + y * rowstride;
-
-        for (int x = 0; x < width; ++x)
-          {
-            if (iconptr[3] == 0)
-              *dataptr = bgcolor;
-            else
-              *dataptr = (iconptr[0] << 16)
-                | (iconptr[1] << 8)
-                | iconptr[2]
-                | (iconptr[3] << 24);
-
-            iconptr += 4;
-            ++dataptr;
-          }
-      }
-
-    set_cairo_image_surface (img, surface);
-    g_object_unref (pixbuf);
-#else
     /* Try to create a x pixmap to hold the svg pixmap.  */
     Emacs_Pix_Container ximg;
     if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
@@ -9333,7 +9285,7 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
 	    blue  = ((blue * opacity)
 		     + (background.blue * ((1 << 8) - opacity)));
 
-	    XPutPixel (ximg, x, y, lookup_rgb_color (f, red, green, blue));
+	    PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, red, green, blue));
 	  }
 
 	pixels += rowstride - 4 * width;
@@ -9356,7 +9308,6 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
 
     /* Put ximg into the image.  */
     image_put_x_image (f, img, ximg, 0);
-#endif /* ! USE_CAIRO */
   }
 
   return 1;
@@ -9379,9 +9330,9 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
 				Ghostscript
  ***********************************************************************/
 
-#ifdef HAVE_X_WINDOWS
+#if defined HAVE_X_WINDOWS && !defined USE_CAIRO
 #define HAVE_GHOSTSCRIPT 1
-#endif /* HAVE_X_WINDOWS */
+#endif /* HAVE_X_WINDOWS && !USE_CAIRO */
 
 #ifdef HAVE_GHOSTSCRIPT
 
diff --git a/src/xterm.c b/src/xterm.c
index 559d1b48924..03458cb03f6 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -7794,12 +7794,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                reply with "Next" if we received "Page", but we
                currently never do because we are interested in
                images, only, which should have 1 page.  */
-            Pixmap pixmap = (Pixmap) event->xclient.data.l[1];
 	    f = x_window_to_frame (dpyinfo, event->xclient.window);
 	    if (!f)
 	      goto OTHER;
+#ifndef USE_CAIRO
+            Pixmap pixmap = (Pixmap) event->xclient.data.l[1];
             x_kill_gs_process (pixmap, f);
             expose_frame (f, 0, 0, 0, 0);
+#endif	/* !USE_CAIRO */
 	    goto done;
           }
 
@@ -12154,7 +12156,15 @@ x_check_font (struct frame *f, struct font *font)
 static void
 x_free_pixmap (struct frame *f, Emacs_Pixmap pixmap)
 {
+#ifdef USE_CAIRO
+  if (pixmap)
+    {
+      xfree (pixmap->data);
+      xfree (pixmap);
+    }
+#else
   XFreePixmap (FRAME_X_DISPLAY (f), pixmap);
+#endif
 }
 
 \f

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* bug#35871: 27.0.50; [PATCH] Fix SVG transparency with Cairo
  2019-05-28  0:52   ` YAMAMOTO Mitsuharu
@ 2019-05-28 10:02     ` Kévin Le Gouguec
  2019-05-29  9:07       ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 10+ messages in thread
From: Kévin Le Gouguec @ 2019-05-28 10:02 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: 35871

[-- Attachment #1: Type: text/plain, Size: 376 bytes --]

YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> writes:

> Patch attached.
>
> It makes cairo image support more consistent with the Xlib one.  […]
> SVG images should look similar on both builds.

Just compiled master (c617b4bf1e50bf33f0016bbcd5f502cc88150f26)
--with-cairo and your patch on top; SVG images do seem to look the same
from where I'm standing:


[-- Attachment #2: cairo-svg-fixed.png --]
[-- Type: image/png, Size: 93090 bytes --]

[-- Attachment #3: Type: text/plain, Size: 323 bytes --]


> Alpha channel (not the tRNS chunk in PNG) support for PNG and SVG is
> now easy on cairo, but not added in this patch, because it introduces
> some inconsistency with the Xlib one.  It could be added as a separate
> change.

As far as this bug is concerned, I am fine with closing it when/if this
patch lands on master.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* bug#35871: 27.0.50; [PATCH] Fix SVG transparency with Cairo
  2019-05-28 10:02     ` Kévin Le Gouguec
@ 2019-05-29  9:07       ` YAMAMOTO Mitsuharu
  2019-05-30  0:18         ` Basil L. Contovounesios
  2019-05-30 16:42         ` Kévin Le Gouguec
  0 siblings, 2 replies; 10+ messages in thread
From: YAMAMOTO Mitsuharu @ 2019-05-29  9:07 UTC (permalink / raw)
  To: Kévin Le Gouguec; +Cc: 35871-done

On Tue, 28 May 2019 19:02:34 +0900,
Kévin Le Gouguec wrote:
> 
> YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> writes:
> 
> > Patch attached.
> >
> > It makes cairo image support more consistent with the Xlib one.  […]
> > SVG images should look similar on both builds.
> 
> Just compiled master (c617b4bf1e50bf33f0016bbcd5f502cc88150f26)
> --with-cairo and your patch on top; SVG images do seem to look the same
> from where I'm standing:

Thanks for testing.  Pushed to master as c89900ebd79.  Closing.

			     YAMAMOTO Mitsuharu
			mituharu@math.s.chiba-u.ac.jp

^ permalink raw reply	[flat|nested] 10+ messages in thread

* bug#35871: 27.0.50; [PATCH] Fix SVG transparency with Cairo
  2019-05-29  9:07       ` YAMAMOTO Mitsuharu
@ 2019-05-30  0:18         ` Basil L. Contovounesios
  2019-05-30  1:09           ` YAMAMOTO Mitsuharu
  2019-05-30 16:42         ` Kévin Le Gouguec
  1 sibling, 1 reply; 10+ messages in thread
From: Basil L. Contovounesios @ 2019-05-30  0:18 UTC (permalink / raw)
  To: 35871; +Cc: kevin.legouguec

YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> writes:

> On Tue, 28 May 2019 19:02:34 +0900,
> Kévin Le Gouguec wrote:
>> 
>> YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> writes:
>> 
>> > Patch attached.
>> >
>> > It makes cairo image support more consistent with the Xlib one.  […]
>> > SVG images should look similar on both builds.
>> 
>> Just compiled master (c617b4bf1e50bf33f0016bbcd5f502cc88150f26)
>> --with-cairo and your patch on top; SVG images do seem to look the same
>> from where I'm standing:
>
> Thanks for testing.  Pushed to master as c89900ebd79.  Closing.

Thanks for working on this!  Unfortunately this commit seems to have
broken native image scaling, at least on X:

0. emacs -Q
1. C-x C-f /path/to/image.png RET
   [Notice the image isn't scaled to the window size.]
2. Any combination of + and -
   [Notice the image is not scaled.]

Reverting c89900ebd79 brings back scaling for me.
Here is my build info:

In GNU Emacs 27.0.50 (build 4, x86_64-pc-linux-gnu, X toolkit, Xaw3d scroll bars)
 of 2019-05-29 built on thunk
Repository revision: 7f3b0d1c0003f3b883a6df3d2fae7f847f6d3070
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12003000
System Description: Debian GNU/Linux 10 (buster)

Configured using:
 'configure 'CC=ccache gcc' 'CFLAGS=-O2 -march=native' --config-cache
 --prefix=/home/blc/.local --with-mailutils --with-x-toolkit=lucid
 --with-modules --with-file-notification=yes --with-x'

Configured features:
XAW3D XPM JPEG TIFF GIF PNG RSVG SOUND GPM DBUS GSETTINGS GLIB NOTIFY
INOTIFY ACL LIBSELINUX GNUTLS LIBXML2 FREETYPE M17N_FLT LIBOTF XFT ZLIB
TOOLKIT_SCROLL_BARS LUCID X11 XDBE XIM MODULES THREADS LIBSYSTEMD JSON
PDUMPER LCMS2 GMP

Should I file a new bug report for this?

Thanks,

-- 
Basil





^ permalink raw reply	[flat|nested] 10+ messages in thread

* bug#35871: 27.0.50; [PATCH] Fix SVG transparency with Cairo
  2019-05-30  0:18         ` Basil L. Contovounesios
@ 2019-05-30  1:09           ` YAMAMOTO Mitsuharu
  2019-05-30  1:55             ` Basil L. Contovounesios
  0 siblings, 1 reply; 10+ messages in thread
From: YAMAMOTO Mitsuharu @ 2019-05-30  1:09 UTC (permalink / raw)
  To: Basil L. Contovounesios; +Cc: 35871, kevin.legouguec

On Thu, 30 May 2019 09:18:59 +0900,
Basil L. Contovounesios wrote:
> 
> YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> writes:
> 
> > On Tue, 28 May 2019 19:02:34 +0900,
> > Kévin Le Gouguec wrote:
> >> 
> >> YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> writes:
> >> 
> >> > Patch attached.
> >> >
> >> > It makes cairo image support more consistent with the Xlib one.  […]
> >> > SVG images should look similar on both builds.
> >> 
> >> Just compiled master (c617b4bf1e50bf33f0016bbcd5f502cc88150f26)
> >> --with-cairo and your patch on top; SVG images do seem to look the same
> >> from where I'm standing:
> >
> > Thanks for testing.  Pushed to master as c89900ebd79.  Closing.
> 
> Thanks for working on this!  Unfortunately this commit seems to have
> broken native image scaling, at least on X:

Thanks for reporting this.  Should be fixed at 46a176169b9.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp

^ permalink raw reply	[flat|nested] 10+ messages in thread

* bug#35871: 27.0.50; [PATCH] Fix SVG transparency with Cairo
  2019-05-30  1:09           ` YAMAMOTO Mitsuharu
@ 2019-05-30  1:55             ` Basil L. Contovounesios
  0 siblings, 0 replies; 10+ messages in thread
From: Basil L. Contovounesios @ 2019-05-30  1:55 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: 35871, kevin.legouguec

YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> writes:

> On Thu, 30 May 2019 09:18:59 +0900,
> Basil L. Contovounesios wrote:
>> 
>> YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> writes:
>> 
>> > On Tue, 28 May 2019 19:02:34 +0900,
>> > Kévin Le Gouguec wrote:
>> >> 
>> >> YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> writes:
>> >> 
>> >> > Patch attached.
>> >> >
>> >> > It makes cairo image support more consistent with the Xlib one.  […]
>> >> > SVG images should look similar on both builds.
>> >> 
>> >> Just compiled master (c617b4bf1e50bf33f0016bbcd5f502cc88150f26)
>> >> --with-cairo and your patch on top; SVG images do seem to look the same
>> >> from where I'm standing:
>> >
>> > Thanks for testing.  Pushed to master as c89900ebd79.  Closing.
>> 
>> Thanks for working on this!  Unfortunately this commit seems to have
>> broken native image scaling, at least on X:
>
> Thanks for reporting this.  Should be fixed at 46a176169b9.

It is indeed, thanks for fixing this so quickly!

-- 
Basil





^ permalink raw reply	[flat|nested] 10+ messages in thread

* bug#35871: 27.0.50; [PATCH] Fix SVG transparency with Cairo
  2019-05-29  9:07       ` YAMAMOTO Mitsuharu
  2019-05-30  0:18         ` Basil L. Contovounesios
@ 2019-05-30 16:42         ` Kévin Le Gouguec
  1 sibling, 0 replies; 10+ messages in thread
From: Kévin Le Gouguec @ 2019-05-30 16:42 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: 35871-done

YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> writes:

> Thanks for testing.  Pushed to master as c89900ebd79.  Closing.

Thank you for the patch, for closing, and for dealing with the fallout
;)





^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2019-05-30 16:42 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-23 20:05 bug#35871: 27.0.50; [PATCH] Fix SVG transparency with Cairo Kévin Le Gouguec
2019-05-24  0:02 ` YAMAMOTO Mitsuharu
2019-05-24 21:19   ` Kévin Le Gouguec
2019-05-28  0:52   ` YAMAMOTO Mitsuharu
2019-05-28 10:02     ` Kévin Le Gouguec
2019-05-29  9:07       ` YAMAMOTO Mitsuharu
2019-05-30  0:18         ` Basil L. Contovounesios
2019-05-30  1:09           ` YAMAMOTO Mitsuharu
2019-05-30  1:55             ` Basil L. Contovounesios
2019-05-30 16:42         ` Kévin Le Gouguec

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).