diff --git a/configure.ac b/configure.ac
index 0f1fd5d26ef..90f13b99fc3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5229,7 +5229,7 @@ AC_DEFUN
   XOBJ="xterm.o xfns.o xselect.o xrdb.o xsmfns.o xsettings.o"
   FONT_OBJ=xfont.o
   if test "$HAVE_CAIRO" = "yes"; then
-    FONT_OBJ="ftfont.o ftcrfont.o"
+    FONT_OBJ="$FONT_OBJ ftfont.o ftcrfont.o"
   elif test "$HAVE_XFT" = "yes"; then
     FONT_OBJ="$FONT_OBJ ftfont.o xftfont.o ftxfont.o"
   elif test "$HAVE_FREETYPE" = "yes"; then
diff --git a/src/font.c b/src/font.c
index 5ca89c97dcf..52bf5dae95b 100644
--- a/src/font.c
+++ b/src/font.c
@@ -5489,10 +5489,10 @@ cause Xft crashes.  Only has an effect in Xft builds.  */);
 #ifdef HAVE_FREETYPE
   syms_of_ftfont ();
 #ifdef HAVE_X_WINDOWS
+  syms_of_xfont ();
 #ifdef USE_CAIRO
   syms_of_ftcrfont ();
 #else
-  syms_of_xfont ();
   syms_of_ftxfont ();
 #ifdef HAVE_XFT
   syms_of_xftfont ();
diff --git a/src/xfns.c b/src/xfns.c
index 4195980d33e..1dcad6f3db1 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -3788,8 +3788,8 @@ This function is an internal primitive--use `make-frame' instead.  */)
   register_font_driver (&ftxfont_driver, f);
 #endif	/* not HAVE_XFT */
 #endif	/* HAVE_FREETYPE */
-  register_font_driver (&xfont_driver, f);
 #endif	/* not USE_CAIRO */
+  register_font_driver (&xfont_driver, f);
 
   image_cache_refcount =
     FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
diff --git a/src/xterm.c b/src/xterm.c
index ccc84dcc716..8c4df4efb01 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -357,6 +357,25 @@ x_cr_update_surface_desired_size (struct frame *f, int width, int height)
     }
 }
 
+static void
+x_cr_gc_clip (cairo_t *cr, struct frame *f, GC gc)
+{
+  if (gc)
+    {
+      struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
+
+      if (gc_ext && gc_ext->n_clip_rects)
+	{
+	  for (int i = 0; i < gc_ext->n_clip_rects; i++)
+	    cairo_rectangle (cr, gc_ext->clip_rects[i].x,
+			     gc_ext->clip_rects[i].y,
+			     gc_ext->clip_rects[i].width,
+			     gc_ext->clip_rects[i].height);
+	  cairo_clip (cr);
+	}
+    }
+}
+
 cairo_t *
 x_begin_cr_clip (struct frame *f, GC gc)
 {
@@ -379,23 +398,7 @@ x_begin_cr_clip (struct frame *f, GC gc)
       cairo_surface_destroy (surface);
     }
   cairo_save (cr);
-
-  if (gc)
-    {
-      struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
-
-      if (gc_ext && gc_ext->n_clip_rects)
-	{
-	  int i;
-
-	  for (i = 0; i < gc_ext->n_clip_rects; i++)
-	    cairo_rectangle (cr, gc_ext->clip_rects[i].x,
-			     gc_ext->clip_rects[i].y,
-			     gc_ext->clip_rects[i].width,
-			     gc_ext->clip_rects[i].height);
-	  cairo_clip (cr);
-	}
-    }
+  x_cr_gc_clip (cr, f, gc);
 
   return cr;
 }
@@ -434,6 +437,126 @@ x_set_cr_source_with_gc_background (struct frame *f, GC gc)
 			color.green / 65535.0, color.blue / 65535.0);
 }
 
+static const cairo_user_data_key_t xlib_surface_key, saved_drawable_key;
+
+static void
+x_cr_destroy_xlib_surface (cairo_surface_t *xlib_surface)
+{
+  if (xlib_surface)
+    {
+      XFreePixmap (cairo_xlib_surface_get_display (xlib_surface),
+		   cairo_xlib_surface_get_drawable (xlib_surface));
+      cairo_surface_destroy (xlib_surface);
+    }
+}
+
+static bool
+x_try_cr_xlib_drawable (struct frame *f, GC gc)
+{
+  cairo_t *cr = FRAME_CR_CONTEXT (f);
+  if (!cr)
+    return true;
+
+  cairo_surface_t *surface = cairo_get_target (cr);
+  switch (cairo_surface_get_type (surface))
+    {
+    case CAIRO_SURFACE_TYPE_XLIB:
+      cairo_surface_flush (surface);
+      return true;
+
+    case CAIRO_SURFACE_TYPE_IMAGE:
+      break;
+
+    default:
+      return false;
+    }
+
+  /* FRAME_CR_CONTEXT (f) is an image surface we can not draw directly
+     with Xlib.  Set up a Pixmap so we can copy back the result later
+     in x_end_cr_xlib_drawable.  */
+  cairo_surface_t *xlib_surface = cairo_get_user_data (cr, &xlib_surface_key);
+  int width = FRAME_CR_SURFACE_DESIRED_WIDTH (f);
+  int height = FRAME_CR_SURFACE_DESIRED_HEIGHT (f);
+  Pixmap pixmap;
+  if (xlib_surface
+      && cairo_xlib_surface_get_width (xlib_surface) == width
+      && cairo_xlib_surface_get_height (xlib_surface) == height)
+    pixmap = cairo_xlib_surface_get_drawable (xlib_surface);
+  else
+    {
+      pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_RAW_DRAWABLE (f),
+			      width, height,
+			      DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
+      xlib_surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
+						pixmap, FRAME_X_VISUAL (f),
+						width, height);
+      cairo_set_user_data (cr, &xlib_surface_key, xlib_surface,
+			   (cairo_destroy_func_t) x_cr_destroy_xlib_surface);
+    }
+
+#if 0				/* This seems to be unnecessary.  */
+  if (cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32)
+    {
+      cairo_surface_flush (xlib_surface);
+      XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_RAW_DRAWABLE (f), pixmap, gc,
+		 0, 0, width, height, 0, 0);
+      cairo_surface_mark_dirty (xlib_surface);
+    }
+#endif
+
+  cairo_t *buf = cairo_create (xlib_surface);
+  cairo_set_source_surface (buf, surface, 0, 0);
+  cairo_matrix_t matrix;
+  cairo_get_matrix (cr, &matrix);
+  cairo_pattern_set_matrix (cairo_get_source (cr), &matrix);
+  cairo_set_operator (buf, CAIRO_OPERATOR_SOURCE);
+  x_cr_gc_clip (buf, f, gc);
+  cairo_paint (buf);
+  cairo_destroy (buf);
+
+  cairo_set_user_data (cr, &saved_drawable_key,
+		       (void *) (uintptr_t) FRAME_X_RAW_DRAWABLE (f), NULL);
+  FRAME_X_RAW_DRAWABLE (f) = pixmap;
+  cairo_surface_flush (xlib_surface);
+
+  return true;
+}
+
+static void
+x_end_cr_xlib_drawable (struct frame *f, GC gc)
+{
+  cairo_t *cr = FRAME_CR_CONTEXT (f);
+  if (!cr)
+    return;
+
+  Drawable saved_drawable
+    = (uintptr_t) cairo_get_user_data (cr, &saved_drawable_key);
+  cairo_surface_t *surface = (saved_drawable
+			      ? cairo_get_user_data (cr, &xlib_surface_key)
+			      : cairo_get_target (cr));
+  struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
+  if (gc_ext && gc_ext->n_clip_rects)
+    for (int i = 0; i < gc_ext->n_clip_rects; i++)
+      cairo_surface_mark_dirty_rectangle (surface, gc_ext->clip_rects[i].x,
+					  gc_ext->clip_rects[i].y,
+					  gc_ext->clip_rects[i].width,
+					  gc_ext->clip_rects[i].height);
+  else
+    cairo_surface_mark_dirty (surface);
+  if (!saved_drawable)
+    return;
+
+  cairo_save (cr);
+  cairo_set_source_surface (cr, surface, 0, 0);
+  cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+  x_cr_gc_clip (cr, f, gc);
+  cairo_paint (cr);
+  cairo_restore (cr);
+
+  FRAME_X_RAW_DRAWABLE (f) = saved_drawable;
+  cairo_set_user_data (cr, &saved_drawable_key, NULL, NULL);
+}
+
 /* Fringe bitmaps.  */
 
 static int max_fringe_bmp = 0;
@@ -1739,6 +1862,33 @@ x_draw_glyph_string_foreground (struct glyph_string *s)
   else
     {
       struct font *font = s->font;
+#ifdef USE_CAIRO
+      if (EQ (font->driver->type, Qx)
+	  && !x_try_cr_xlib_drawable (s->f, s->gc))
+	{
+	  /* Fallback for the case that no Xlib Drawable is available
+	     for drawing text with X core fonts.  */
+	  if (!(s->for_overlaps
+		|| (s->background_filled_p && s->hl != DRAW_CURSOR)))
+	    {
+	      int box_line_width = max (s->face->box_line_width, 0);
+
+	      x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
+					 s->background_width,
+					 s->height - 2 * box_line_width);
+	    }
+	  for (i = 0; i < s->nchars; ++i)
+	    {
+	      struct glyph *g = s->first_glyph + i;
+	      x_draw_rectangle (s->f,
+				s->gc, x, s->y, g->pixel_width - 1,
+				s->height - 1);
+	      x += g->pixel_width;
+	    }
+	}
+      else
+	{
+#endif	/* USE_CAIRO */
       int boff = font->baseline_offset;
       int y;
 
@@ -1753,6 +1903,11 @@ x_draw_glyph_string_foreground (struct glyph_string *s)
 	font->driver->draw (s, 0, s->nchars, x, y, true);
       if (s->face->overstrike)
 	font->driver->draw (s, 0, s->nchars, x + 1, y, false);
+#ifdef USE_CAIRO
+	  if (EQ (font->driver->type, Qx))
+	    x_end_cr_xlib_drawable (s->f, s->gc);
+	}
+#endif	/* USE_CAIRO */
     }
 }
 
@@ -1785,7 +1940,21 @@ x_draw_composite_glyph_string_foreground (struct glyph_string *s)
 	x_draw_rectangle (s->f, s->gc, x, s->y,
 			s->width - 1, s->height - 1);
     }
-  else if (! s->first_glyph->u.cmp.automatic)
+  else
+#ifdef USE_CAIRO
+    if (EQ (font->driver->type, Qx)
+	&& !x_try_cr_xlib_drawable (s->f, s->gc))
+      {
+	/* Fallback for the case that no Xlib Drawable is available
+	   for drawing text with X core fonts.  */
+	if (s->cmp_from == 0)
+	  x_draw_rectangle (s->f, s->gc, x, s->y,
+			    s->width - 1, s->height - 1);
+      }
+    else
+      {
+#endif	/* USE_CAIRO */
+  if (! s->first_glyph->u.cmp.automatic)
     {
       int y = s->ybase;
 
@@ -1844,6 +2013,11 @@ x_draw_composite_glyph_string_foreground (struct glyph_string *s)
 	    font->driver->draw (s, j, i, x + 1, y, false);
 	}
     }
+#ifdef USE_CAIRO
+	if (EQ (font->driver->type, Qx))
+	  x_end_cr_xlib_drawable (s->f, s->gc);
+      }
+#endif	/* USE_CAIRO */
 }
 
 
