]> code.delx.au - gnu-emacs/commitdiff
Merge branch 'master' into cairo
authorJan D <jan.h.d@swipnet.se>
Sat, 23 May 2015 10:28:54 +0000 (12:28 +0200)
committerJan D <jan.h.d@swipnet.se>
Sat, 23 May 2015 10:28:54 +0000 (12:28 +0200)
1  2 
configure.ac
src/font.c
src/xfns.c
src/xterm.c

diff --combined configure.ac
index fff3db90e50bd621e1f347354534741e5c4a1f8e,752204c3a8ca86837266ecc8dd09a3afba61b6e0..a9fe0952b164892017e3c4369f99016bde9cee9e
@@@ -330,7 -330,6 +330,7 @@@ OPTION_DEFAULT_ON([tiff],[don't compil
  OPTION_DEFAULT_ON([gif],[don't compile with GIF image support])
  OPTION_DEFAULT_ON([png],[don't compile with PNG image support])
  OPTION_DEFAULT_ON([rsvg],[don't compile with SVG image support])
 +OPTION_DEFAULT_OFF([cairo],[compile with Cairo drawing])
  OPTION_DEFAULT_ON([xml2],[don't compile with XML parsing support])
  OPTION_DEFAULT_ON([imagemagick],[don't compile with ImageMagick image support])
  
@@@ -2408,7 -2407,6 +2408,7 @@@ if test "${opsys}" != "mingw32"; the
         AC_DEFINE(HAVE_GTK3, 1, [Define to 1 if using GTK 3 or later.])
         GTK_OBJ=emacsgtkfixed.o
         gtk_term_header=gtkutil.h
 +       USE_CAIRO=yes
         USE_GTK_TOOLKIT="GTK3"
         if test "x$ac_enable_gtk_deprecation_warnings" = x; then
         AC_DEFINE([GDK_DISABLE_DEPRECATION_WARNINGS], [1],
@@@ -3077,25 -3075,6 +3077,25 @@@ AC_SUBST(LIBOTF_LIBS
  AC_SUBST(M17N_FLT_CFLAGS)
  AC_SUBST(M17N_FLT_LIBS)
  
 +USE_CAIRO=no
 +if test "${HAVE_X11}" = "yes"; then
 +  if test "${with_cairo}" != "no"; then
 +    CAIRO_REQUIRED=1.12.0
 +    CAIRO_MODULE="cairo >= $CAIRO_REQUIRED"
 +    PKG_CHECK_MODULES(CAIRO, $CAIRO_MODULE, USE_CAIRO=yes, :)
 +    if test $USE_CAIRO = yes; then
 +      AC_DEFINE(USE_CAIRO, 1, [Define to 1 if using cairo.])
 +    else
 +      AC_MSG_ERROR([cairo requested but not found.])
 +    fi
 +
 +    CFLAGS="$CFLAGS $CAIRO_CFLAGS"
 +    LIBS="$LIBS $CAIRO_LIBS"
 +    AC_SUBST(CAIRO_CFLAGS)
 +    AC_SUBST(CAIRO_LIBS)
 +  fi
 +fi
 +
  ### Use -lXpm if available, unless '--with-xpm=no'.
  ### mingw32 doesn't use -lXpm, since it loads the library dynamically.
  ### In the Cygwin-w32 build, we need to use /usr/include/noX/X11/xpm.h
@@@ -4030,8 -4009,8 +4030,8 @@@ OLDCFLAGS="$CFLAGS
  OLDLIBS="$LIBS"
  CFLAGS="$CFLAGS $GTK_CFLAGS $RSVG_CFLAGS $DBUS_CFLAGS $SETTINGS_CFLAGS"
  LIBS="$LIBS $GTK_LIBS $RSVG_LIBS $DBUS_LIBS $SETTINGS_LIBS"
 -CFLAGS="$CFLAGS $GFILENOTIFY_CFLAGS"
 -LIBS="$LIBS $GFILENOTIFY_LIBS"
 +CFLAGS="$CFLAGS $GFILENOTIFY_CFLAGS $CAIRO_CFLAGS"
 +LIBS="$LIBS $GFILENOTIFY_LIBS $CAIRO_LIBS"
  AC_MSG_CHECKING([whether GLib is linked in])
  AC_LINK_IFELSE([AC_LANG_PROGRAM(
        [[#include <glib.h>
@@@ -4797,9 -4776,7 +4797,9 @@@ if test "${HAVE_X_WINDOWS}" = "yes" ; t
    XMENU_OBJ=xmenu.o
    XOBJ="xterm.o xfns.o xselect.o xrdb.o xsmfns.o xsettings.o"
    FONT_OBJ=xfont.o
 -  if test "$HAVE_XFT" = "yes"; then
 +  if test "$USE_CAIRO" = "yes"; then
 +    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
      FONT_OBJ="$FONT_OBJ ftfont.o ftxfont.o"
@@@ -5165,7 -5142,6 +5165,7 @@@ echo "  Does Emacs use -ltiff
  echo "  Does Emacs use a gif library?                           ${HAVE_GIF} $LIBGIF"
  echo "  Does Emacs use a png library?                           ${HAVE_PNG} $LIBPNG"
  echo "  Does Emacs use -lrsvg-2?                                ${HAVE_RSVG}"
 +echo "  Does Emacs use cairo?                                   ${USE_CAIRO}"
  echo "  Does Emacs use imagemagick?                             ${HAVE_IMAGEMAGICK}"
  
  echo "  Does Emacs support sound?                               ${HAVE_SOUND}"
  
  dnl The admin/ directory used to be excluded from tarfiles.
  if test -d $srcdir/admin; then
-   SUBDIR_MAKEFILES="$SUBDIR_MAKEFILES admin/unidata/Makefile admin/grammars/Makefile"
+   SUBDIR_MAKEFILES="$SUBDIR_MAKEFILES admin/charsets/Makefile admin/unidata/Makefile admin/grammars/Makefile"
+   AC_CONFIG_FILES([admin/charsets/Makefile])
    AC_CONFIG_FILES([admin/unidata/Makefile])
    AC_CONFIG_FILES([admin/grammars/Makefile])
  fi                              dnl -d admin
diff --combined src/font.c
index 603e998ed3f29fb953517056c5ef6e41e6ac43c6,2ade45fd73a730f240e85bd296e8e4d55c45c2b3..2ccfd15d43691e07327995a541fc53386893bec2
@@@ -3822,17 -3822,17 +3822,17 @@@ They are the same as face attributes o
  
  `:foundry'
  
- VALUE must be a string or a symbol specifying the font foundry, e.g. ``misc''.
+ VALUE must be a string or a symbol specifying the font foundry, e.g. `misc'.
  
  `:adstyle'
  
  VALUE must be a string or a symbol specifying the additional
- typographic style information of a font, e.g. ``sans''.
+ typographic style information of a font, e.g. `sans'.
  
  `:registry'
  
  VALUE must be a string or a symbol specifying the charset registry and
- encoding of a font, e.g. ``iso8859-1''.
+ encoding of a font, e.g. `iso8859-1'.
  
  `:size'
  
@@@ -3866,7 -3866,7 +3866,7 @@@ required OpenType features
    GSUB: List of OpenType GSUB feature tag symbols, or nil if none required.
    GPOS: List of OpenType GPOS feature tag symbols, or nil if none required.
  
- GSUB and GPOS may contain `nil' element.  In such a case, the font
+ GSUB and GPOS may contain nil elements.  In such a case, the font
  must not have any of the remaining elements.
  
  For instance, if the VALUE is `(thai nil nil (mark))', the font must
@@@ -5011,7 -5011,7 +5011,7 @@@ build_style_table (const struct table_e
  static Lisp_Object Vfont_log_deferred;
  
  /* Prepend the font-related logging data in Vfont_log if it is not
-    `t'.  ACTION describes a kind of font-related action (e.g. listing,
+    t.  ACTION describes a kind of font-related action (e.g. listing,
     opening), ARG is the argument for the action, and RESULT is the
     result of the action.  */
  void
@@@ -5280,15 -5280,11 +5280,15 @@@ EMACS_FONT_LOG is set.  Otherwise, it i
  #ifdef HAVE_FREETYPE
    syms_of_ftfont ();
  #ifdef HAVE_X_WINDOWS
 +#ifdef USE_CAIRO
 +  syms_of_ftcrfont ();
 +#else
    syms_of_xfont ();
    syms_of_ftxfont ();
  #ifdef HAVE_XFT
    syms_of_xftfont ();
  #endif  /* HAVE_XFT */
 +#endif  /* not USE_CAIRO */
  #endif        /* HAVE_X_WINDOWS */
  #else /* not HAVE_FREETYPE */
  #ifdef HAVE_X_WINDOWS
diff --combined src/xfns.c
index 80c214a7a566f1e0667c08f70a597a840f966fa0,03ef8136ae25517bcfb0cf1d8529b94a172973e7..5ac58e9c7e0919bf93550e5fa30619ad32aa9a95
@@@ -3116,9 -3116,6 +3116,9 @@@ This function is an internal primitive-
        specbind (Qx_resource_name, name);
      }
  
 +#ifdef USE_CAIRO
 +  register_font_driver (&ftcrfont_driver, f);
 +#else
  #ifdef HAVE_FREETYPE
  #ifdef HAVE_XFT
    register_font_driver (&xftfont_driver, f);
  #endif        /* not HAVE_XFT */
  #endif        /* HAVE_FREETYPE */
    register_font_driver (&xfont_driver, f);
 +#endif        /* not USE_CAIRO */
  
    x_default_parameter (f, parms, Qfont_backend, Qnil,
                       "fontBackend", "FontBackend", RES_TYPE_STRING);
@@@ -4320,13 -4316,13 +4320,13 @@@ elements (all size values are in pixels
  
  - `title-bar-height' is the height of the title bar of FRAME.
  
- - `menu-bar-external' if `t' means the menu bar is external (not
+ - `menu-bar-external' if t means the menu bar is external (not
    included in the inner edges of FRAME).
  
  - `menu-bar-size' is a cons of the width and height of the menu bar of
    FRAME.
  
- - `tool-bar-external' if `t' means the tool bar is external (not
+ - `tool-bar-external' if t means the tool bar is external (not
    included in the inner edges of FRAME).
  
  - `tool-bar-side' tells tells on which side the tool bar on FRAME is and
@@@ -5122,9 -5118,6 +5122,9 @@@ x_create_tip_frame (struct x_display_in
        specbind (Qx_resource_name, name);
      }
  
 +#ifdef USE_CAIRO
 +  register_font_driver (&ftcrfont_driver, f);
 +#else
    register_font_driver (&xfont_driver, f);
  #ifdef HAVE_FREETYPE
  #ifdef HAVE_XFT
    register_font_driver (&ftxfont_driver, f);
  #endif        /* not HAVE_XFT */
  #endif        /* HAVE_FREETYPE */
 +#endif        /* not USE_CAIRO */
  
    x_default_parameter (f, parms, Qfont_backend, Qnil,
                       "fontBackend", "FontBackend", RES_TYPE_STRING);
@@@ -6215,158 -6207,6 +6215,158 @@@ present and mapped to the usual X keysy
  }
  
  
 +\f
 +/***********************************************************************
 +                             Printing
 + ***********************************************************************/
 +
 +#ifdef USE_CAIRO
 +DEFUN ("x-export-frames", Fx_export_frames, Sx_export_frames, 0, 2, 0,
 +       doc: /* XXX Experimental.  Return image data of FRAMES in TYPE format.
 +FRAMES should be nil (the selected frame), a frame, or a list of
 +frames (each of which corresponds to one page).  Optional arg TYPE
 +should be either `pdf' (default), `png', `ps', or `svg'.  Supported
 +types are determined by the compile-time configuration of cairo.  */)
 +     (Lisp_Object frames, Lisp_Object type)
 +{
 +  Lisp_Object result, rest, tmp;
 +  cairo_surface_type_t surface_type;
 +
 +  if (NILP (frames))
 +    frames = selected_frame;
 +  if (!CONSP (frames))
 +    frames = list1 (frames);
 +
 +  tmp = Qnil;
 +  for (rest = frames; CONSP (rest); rest = XCDR (rest))
 +    {
 +      struct frame *f = XFRAME (XCAR (rest));
 +
 +      if (! FRAME_LIVE_P (f) || ! FRAME_X_P (f) || ! FRAME_LIVE_P (f))
 +        error ("Invalid frame");
 +
 +      Lisp_Object frame;
 +
 +      XSETFRAME (frame, f);
 +      tmp = Fcons (frame, tmp);
 +    }
 +  frames = Fnreverse (tmp);
 +
 +#ifdef CAIRO_HAS_PDF_SURFACE
 +  if (NILP (type) || EQ (type, intern ("pdf"))) /* XXX: Qpdf */
 +    surface_type = CAIRO_SURFACE_TYPE_PDF;
 +  else
 +#endif
 +#ifdef CAIRO_HAS_PNG_FUNCTIONS
 +  if (EQ (type, intern ("png")))
 +    {
 +      if (!NILP (XCDR (frames)))
 +      error ("PNG export cannot handle multiple frames.");
 +      surface_type = CAIRO_SURFACE_TYPE_IMAGE;
 +    }
 +  else
 +#endif
 +#ifdef CAIRO_HAS_PS_SURFACE
 +  if (EQ (type, intern ("ps")))
 +    surface_type = CAIRO_SURFACE_TYPE_PS;
 +  else
 +#endif
 +#ifdef CAIRO_HAS_SVG_SURFACE
 +  if (EQ (type, intern ("svg")))
 +    {
 +      /* For now, we stick to SVG 1.1.  */
 +      if (!NILP (XCDR (frames)))
 +      error ("SVG export cannot handle multiple frames.");
 +      surface_type = CAIRO_SURFACE_TYPE_SVG;
 +    }
 +  else
 +#endif
 +    error ("Unsupported export type");
 +
 +  result = x_cr_export_frames (frames, surface_type);
 +
 +  return result;
 +}
 +
 +#ifdef USE_GTK
 +DEFUN ("x-page-setup-dialog", Fx_page_setup_dialog, Sx_page_setup_dialog, 0, 0, 0,
 +       doc: /* Pop up a page setup dialog.
 +The current page setup can be obtained using `x-get-page-setup'.  */)
 +     (void)
 +{
 +  block_input ();
 +  xg_page_setup_dialog ();
 +  unblock_input ();
 +
 +  return Qnil;
 +}
 +
 +DEFUN ("x-get-page-setup", Fx_get_page_setup, Sx_get_page_setup, 0, 0, 0,
 +       doc: /* Return the value of the current page setup.
 +The return value is an alist containing the following keys:
 +
 +  orientation: page orientation (symbol `portrait', `landscape',
 +      `reverse-portrait', or `reverse-landscape').
 +  width, height: page width/height in points not including margins.
 +  left-margin, right-margin, top-margin, bottom-margin: print margins,
 +      which is the parts of the page that the printer cannot print
 +      on, in points.
 +
 +The paper width can be obtained as the sum of width, left-margin, and
 +right-margin values.  Likewise, the paper height is the sum of height,
 +top-margin, and bottom-margin values.  */)
 +     (void)
 +{
 +  Lisp_Object result;
 +
 +  block_input ();
 +  result = xg_get_page_setup ();
 +  unblock_input ();
 +
 +  return result;
 +}
 +
 +DEFUN ("x-print-frames-dialog", Fx_print_frames_dialog, Sx_print_frames_dialog, 0, 1, "",
 +       doc: /* Pop up a print dialog to print the current contents of FRAMES.
 +FRAMES should be nil (the selected frame), a frame, or a list of
 +frames (each of which corresponds to one page).  Each frame should be
 +visible.  */)
 +     (Lisp_Object frames)
 +{
 +  Lisp_Object rest, tmp;
 +
 +  if (NILP (frames))
 +    frames = selected_frame;
 +  if (!CONSP (frames))
 +    frames = list1 (frames);
 +
 +  tmp = Qnil;
 +  for (rest = frames; CONSP (rest); rest = XCDR (rest))
 +    {
 +      struct frame *f = XFRAME (XCAR (rest));
 +      if (! FRAME_LIVE_P (f) || ! FRAME_X_P (f) || ! FRAME_LIVE_P (f))
 +        error ("Invalid frame");
 +      Lisp_Object frame;
 +
 +      XSETFRAME (frame, f);
 +      if (!EQ (Fframe_visible_p (frame), Qt))
 +      error ("Frames to be printed must be visible.");
 +      tmp = Fcons (frame, tmp);
 +    }
 +  frames = Fnreverse (tmp);
 +
 +  /* Make sure the current matrices are up-to-date.  */
 +  Fredisplay (Qt);
 +
 +  block_input ();
 +  xg_print_frames_dialog (frames);
 +  unblock_input ();
 +
 +  return Qnil;
 +}
 +#endif        /* USE_GTK */
 +#endif        /* USE_CAIRO */
 +
  \f
  /***********************************************************************
                            Initialization
@@@ -6425,16 -6265,6 +6425,16 @@@ syms_of_xfns (void
    DEFSYM (Qfont_param, "font-parameter");
    DEFSYM (Qmono, "mono");
  
 +#ifdef USE_CAIRO
 +  DEFSYM (Qorientation, "orientation");
 +  DEFSYM (Qtop_margin, "top-margin");
 +  DEFSYM (Qbottom_margin, "bottom-margin");
 +  DEFSYM (Qportrait, "portrait");
 +  DEFSYM (Qlandscape, "landscape");
 +  DEFSYM (Qreverse_portrait, "reverse-portrait");
 +  DEFSYM (Qreverse_landscape, "reverse-landscape");
 +#endif
 +
    Fput (Qundefined_color, Qerror_conditions,
        listn (CONSTYPE_PURE, 2, Qundefined_color, Qerror));
    Fput (Qundefined_color, Qerror_message,
@@@ -6575,20 -6405,6 +6575,20 @@@ When using Gtk+ tooltips, the tooltip f
    }
  #endif /* USE_GTK */
  
 +#ifdef USE_CAIRO
 +  Fprovide (intern_c_string ("cairo"), Qnil);
 +
 +  DEFVAR_LISP ("cairo-version-string", Vcairo_version_string,
 +               doc: /* Version info for cairo.  */);
 +  {
 +    char cairo_version[sizeof ".." + 3 * INT_STRLEN_BOUND (int)];
 +    int len = sprintf (cairo_version, "%d.%d.%d",
 +                     CAIRO_VERSION_MAJOR, CAIRO_VERSION_MINOR,
 +                       CAIRO_VERSION_MICRO);
 +    Vcairo_version_string = make_pure_string (cairo_version, len, len, false);
 +  }
 +#endif
 +
    /* X window properties.  */
    defsubr (&Sx_change_window_property);
    defsubr (&Sx_delete_window_property);
  #if defined (USE_GTK) && defined (HAVE_FREETYPE)
    defsubr (&Sx_select_font);
  #endif
 +
 +#ifdef USE_CAIRO
 +  defsubr (&Sx_export_frames);
 +#ifdef USE_GTK
 +  defsubr (&Sx_page_setup_dialog);
 +  defsubr (&Sx_get_page_setup);
 +  defsubr (&Sx_print_frames_dialog);
 +#endif
 +#endif
  }
diff --combined src/xterm.c
index 4590e34fe8b313ce3859e648617c57462e87cc2c,06ce7070bcac163fa28cabe1c65aea2b333c100b..3734fbfee92a0b251efefc080fe09c7dbe2e94e8
@@@ -22,9 -22,6 +22,9 @@@ along with GNU Emacs.  If not, see <htt
  
  #include <config.h>
  #include <stdio.h>
 +#ifdef USE_CAIRO
 +#include <math.h>
 +#endif
  
  #include "lisp.h"
  #include "blockinput.h"
@@@ -223,7 -220,6 +223,7 @@@ static int x_io_error_quitter (Display 
  static struct terminal *x_create_terminal (struct x_display_info *);
  static void x_update_end (struct frame *);
  static void XTframe_up_to_date (struct frame *);
 +static void x_clear_area1 (Display *, Window, int, int, int, int, int);
  static void x_clear_frame (struct frame *);
  static _Noreturn void x_ins_del_lines (struct frame *, int, int);
  static void frame_highlight (struct frame *);
@@@ -329,587 -325,6 +329,587 @@@ record_event (char *locus, int type
  
  #endif
  
 +static void x_free_cr_resources (struct frame *);
 +static void x_set_clip_rectangles (struct frame *, GC, XRectangle *, int);
 +static void x_reset_clip_rectangles (struct frame *, GC);
 +static void x_fill_rectangle (struct frame *, GC, int, int, int, int);
 +static void x_draw_rectangle (struct frame *, GC, int, int, int, int);
 +static void x_fill_trapezoid_for_relief (struct frame *, GC, int, int,
 +                                       int, int, int);
 +static void x_clear_window (struct frame *);
 +
 +#ifdef USE_CAIRO
 +static struct x_gc_ext_data *x_gc_get_ext_data (struct frame *, GC, int);
 +static void x_extension_initialize (struct x_display_info *);
 +static cairo_status_t x_cr_accumulate_data (void *,
 +                                            const unsigned char *,
 +                                            unsigned int);
 +
 +#define FRAME_CR_CONTEXT(f)   ((f)->output_data.x->cr_context)
 +#define FRAME_CR_SURFACE(f)   ((f)->output_data.x->cr_surface)
 +
 +static struct x_gc_ext_data *
 +x_gc_get_ext_data (struct frame *f, GC gc, int create_if_not_found_p)
 +{
 +  struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
 +  XEDataObject object;
 +  XExtData **head, *ext_data;
 +
 +  object.gc = gc;
 +  head = XEHeadOfExtensionList (object);
 +  ext_data = XFindOnExtensionList (head, dpyinfo->ext_codes->extension);
 +  if (ext_data == NULL)
 +    {
 +      if (!create_if_not_found_p)
 +      return NULL;
 +      else
 +      {
 +        ext_data = xzalloc (sizeof (*ext_data));
 +        ext_data->number = dpyinfo->ext_codes->extension;
 +        ext_data->private_data = xzalloc (sizeof (struct x_gc_ext_data));
 +        XAddToExtensionList (head, ext_data);
 +      }
 +    }
 +  return (struct x_gc_ext_data *) ext_data->private_data;
 +}
 +
 +static void
 +x_extension_initialize (struct x_display_info *dpyinfo)
 +{
 +  XExtCodes *ext_codes = XAddExtension (dpyinfo->display);
 +
 +  dpyinfo->ext_codes = ext_codes;
 +}
 +
 +static void
 +x_cr_destroy_surface (struct frame *f)
 +{
 +  if (FRAME_CR_SURFACE (f))
 +    {
 +      cairo_t *cr = FRAME_CR_CONTEXT (f);
 +      cairo_surface_destroy (FRAME_CR_SURFACE (f));
 +      FRAME_CR_SURFACE (f) = 0;
 +      if (cr) cairo_destroy (cr);
 +      FRAME_CR_CONTEXT (f) = NULL;
 +    }
 +}
 +
 +cairo_t *
 +x_begin_cr_clip (struct frame *f, GC gc)
 +{
 +  cairo_t *cr = FRAME_CR_CONTEXT (f);
 +
 +  if (!cr)
 +    {
 +
 +      if (! FRAME_CR_SURFACE (f))
 +        {
 +          cairo_surface_t *surface;
 +          surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
 +                                               FRAME_X_WINDOW (f),
 +                                               FRAME_DISPLAY_INFO (f)->visual,
 +                                               FRAME_PIXEL_WIDTH (f),
 +                                               FRAME_PIXEL_HEIGHT (f));
 +          cr = cairo_create (surface);
 +          cairo_surface_destroy (surface);
 +        }
 +      else
 +        cr = cairo_create (FRAME_CR_SURFACE (f));
 +      FRAME_CR_CONTEXT (f) = cr;
 +    }
 +  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);
 +      }
 +    }
 +
 +  return cr;
 +}
 +
 +void
 +x_end_cr_clip (struct frame *f)
 +{
 +  cairo_restore (FRAME_CR_CONTEXT (f));
 +}
 +
 +void
 +x_set_cr_source_with_gc_foreground (struct frame *f, GC gc)
 +{
 +  XGCValues xgcv;
 +  XColor color;
 +
 +  XGetGCValues (FRAME_X_DISPLAY (f), gc, GCForeground, &xgcv);
 +  color.pixel = xgcv.foreground;
 +  x_query_color (f, &color);
 +  cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0,
 +                      color.green / 65535.0, color.blue / 65535.0);
 +}
 +
 +void
 +x_set_cr_source_with_gc_background (struct frame *f, GC gc)
 +{
 +  XGCValues xgcv;
 +  XColor color;
 +
 +  XGetGCValues (FRAME_X_DISPLAY (f), gc, GCBackground, &xgcv);
 +  color.pixel = xgcv.background;
 +  x_query_color (f, &color);
 +  cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0,
 +                      color.green / 65535.0, color.blue / 65535.0);
 +}
 +
 +/* Fringe bitmaps.  */
 +
 +static int max_fringe_bmp = 0;
 +static cairo_pattern_t **fringe_bmp = 0;
 +
 +static void
 +x_cr_define_fringe_bitmap (int which, unsigned short *bits, int h, int wd)
 +{
 +  int i, stride;
 +  cairo_surface_t *surface;
 +  unsigned char *data;
 +  cairo_pattern_t *pattern;
 +
 +  if (which >= max_fringe_bmp)
 +    {
 +      i = max_fringe_bmp;
 +      max_fringe_bmp = which + 20;
 +      fringe_bmp = (cairo_pattern_t **) xrealloc (fringe_bmp, max_fringe_bmp * sizeof (cairo_pattern_t *));
 +      while (i < max_fringe_bmp)
 +      fringe_bmp[i++] = 0;
 +    }
 +
 +  block_input ();
 +
 +  surface = cairo_image_surface_create (CAIRO_FORMAT_A1, wd, h);
 +  stride = cairo_image_surface_get_stride (surface);
 +  data = cairo_image_surface_get_data (surface);
 +
 +  for (i = 0; i < h; i++)
 +    {
 +      *((unsigned short *) data) = bits[i];
 +      data += stride;
 +    }
 +
 +  cairo_surface_mark_dirty (surface);
 +  pattern = cairo_pattern_create_for_surface (surface);
 +  cairo_surface_destroy (surface);
 +
 +  unblock_input ();
 +
 +  fringe_bmp[which] = pattern;
 +}
 +
 +static void
 +x_cr_destroy_fringe_bitmap (int which)
 +{
 +  if (which >= max_fringe_bmp)
 +    return;
 +
 +  if (fringe_bmp[which])
 +    {
 +      block_input ();
 +      cairo_pattern_destroy (fringe_bmp[which]);
 +      unblock_input ();
 +    }
 +  fringe_bmp[which] = 0;
 +}
 +
 +static void
 +x_cr_draw_image (struct frame *f, GC gc, cairo_pattern_t *image,
 +               int src_x, int src_y, int width, int height,
 +               int dest_x, int dest_y, bool overlay_p)
 +{
 +  cairo_t *cr;
 +  cairo_matrix_t matrix;
 +  cairo_surface_t *surface;
 +  cairo_format_t format;
 +
 +  cr = x_begin_cr_clip (f, gc);
 +  if (overlay_p)
 +    cairo_rectangle (cr, dest_x, dest_y, width, height);
 +  else
 +    {
 +      x_set_cr_source_with_gc_background (f, gc);
 +      cairo_rectangle (cr, dest_x, dest_y, width, height);
 +      cairo_fill_preserve (cr);
 +    }
 +  cairo_clip (cr);
 +  cairo_matrix_init_translate (&matrix, src_x - dest_x, src_y - dest_y);
 +  cairo_pattern_set_matrix (image, &matrix);
 +  cairo_pattern_get_surface (image, &surface);
 +  format = cairo_image_surface_get_format (surface);
 +  if (format != CAIRO_FORMAT_A8 && format != CAIRO_FORMAT_A1)
 +    {
 +      cairo_set_source (cr, image);
 +      cairo_fill (cr);
 +    }
 +  else
 +    {
 +      x_set_cr_source_with_gc_foreground (f, gc);
 +      cairo_mask (cr, image);
 +    }
 +  x_end_cr_clip (f);
 +}
 +
 +void
 +x_cr_draw_frame (cairo_t *cr, struct frame *f)
 +{
 +  int width, height;
 +
 +  width = FRAME_PIXEL_WIDTH (f);
 +  height = FRAME_PIXEL_HEIGHT (f);
 +
 +  x_free_cr_resources (f);
 +  FRAME_CR_CONTEXT (f) = cr;
 +  x_clear_area (f, 0, 0, width, height);
 +  expose_frame (f, 0, 0, width, height);
 +  FRAME_CR_CONTEXT (f) = NULL;
 +}
 +
 +static cairo_status_t
 +x_cr_accumulate_data (void *closure, const unsigned char *data,
 +                    unsigned int length)
 +{
 +  Lisp_Object *acc = (Lisp_Object *) closure;
 +
 +  *acc = Fcons (make_unibyte_string (data, length), *acc);
 +
 +  return CAIRO_STATUS_SUCCESS;
 +}
 +
 +static void
 +x_cr_destroy (Lisp_Object arg)
 +{
 +  cairo_t *cr = (cairo_t *) XSAVE_POINTER (arg, 0);
 +
 +  block_input ();
 +  cairo_destroy (cr);
 +  unblock_input ();
 +}
 +
 +Lisp_Object
 +x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type)
 +{
 +  struct frame *f;
 +  cairo_surface_t *surface;
 +  cairo_t *cr;
 +  int width, height;
 +  void (*surface_set_size_func) (cairo_surface_t *, double, double) = NULL;
 +  Lisp_Object acc = Qnil, args[2];
 +  int count = SPECPDL_INDEX ();
 +
 +  Fredisplay (Qt);
 +
 +  f = XFRAME (XCAR (frames));
 +  frames = XCDR (frames);
 +  width = FRAME_PIXEL_WIDTH (f);
 +  height = FRAME_PIXEL_HEIGHT (f);
 +
 +  block_input ();
 +#ifdef CAIRO_HAS_PDF_SURFACE
 +  if (surface_type == CAIRO_SURFACE_TYPE_PDF)
 +    {
 +      surface = cairo_pdf_surface_create_for_stream (x_cr_accumulate_data, &acc,
 +                                                   width, height);
 +      surface_set_size_func = cairo_pdf_surface_set_size;
 +    }
 +  else
 +#endif
 +#ifdef CAIRO_HAS_PNG_FUNCTIONS
 +  if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
 +    surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
 +  else
 +#endif
 +#ifdef CAIRO_HAS_PS_SURFACE
 +  if (surface_type == CAIRO_SURFACE_TYPE_PS)
 +    {
 +      surface = cairo_ps_surface_create_for_stream (x_cr_accumulate_data, &acc,
 +                                                  width, height);
 +      surface_set_size_func = cairo_ps_surface_set_size;
 +    }
 +  else
 +#endif
 +#ifdef CAIRO_HAS_SVG_SURFACE
 +  if (surface_type == CAIRO_SURFACE_TYPE_SVG)
 +    surface = cairo_svg_surface_create_for_stream (x_cr_accumulate_data, &acc,
 +                                                 width, height);
 +  else
 +#endif
 +    abort ();
 +
 +  cr = cairo_create (surface);
 +  cairo_surface_destroy (surface);
 +  record_unwind_protect (x_cr_destroy, make_save_ptr (cr));
 +  unblock_input ();
 +
 +  while (1)
 +    {
 +      QUIT;
 +
 +      block_input ();
 +      x_free_cr_resources (f);
 +      FRAME_CR_CONTEXT (f) = cr;
 +      x_clear_area (f, 0, 0, width, height);
 +      expose_frame (f, 0, 0, width, height);
 +      FRAME_CR_CONTEXT (f) = NULL;
 +      unblock_input ();
 +
 +      if (NILP (frames))
 +      break;
 +
 +      block_input ();
 +      cairo_surface_show_page (surface);
 +      f = XFRAME (XCAR (frames));
 +      frames = XCDR (frames);
 +      width = FRAME_PIXEL_WIDTH (f);
 +      height = FRAME_PIXEL_HEIGHT (f);
 +      if (surface_set_size_func)
 +      (*surface_set_size_func) (surface, width, height);
 +      unblock_input ();
 +    }
 +
 +#ifdef CAIRO_HAS_PNG_FUNCTIONS
 +  if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
 +    {
 +      block_input ();
 +      cairo_surface_flush (surface);
 +      cairo_surface_write_to_png_stream (surface, x_cr_accumulate_data, &acc);
 +      unblock_input ();
 +    }
 +#endif
 +  unbind_to (count, Qnil);
 +
 +  args[0] = intern ("concat");
 +  args[1] = Fnreverse (acc);
 +  return Fapply (2, args);
 +}
 +
 +#endif        /* USE_CAIRO */
 +
 +static void
 +x_free_cr_resources (struct frame *f)
 +{
 +#ifdef USE_CAIRO
 +  if (f == NULL)
 +    {
 +      Lisp_Object rest, frame;
 +      FOR_EACH_FRAME (rest, frame)
 +      if (FRAME_X_P (XFRAME (frame)))
 +        x_free_cr_resources (XFRAME (frame));
 +    }
 +  else
 +    {
 +      cairo_t *cr = FRAME_CR_CONTEXT (f);
 +
 +      if (cr)
 +      {
 +        cairo_surface_t *surface = cairo_get_target (cr);
 +
 +        if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB)
 +          {
 +            cairo_destroy (cr);
 +            FRAME_CR_CONTEXT (f) = NULL;
 +          }
 +      }
 +    }
 +#endif
 +}
 +
 +static void
 +x_set_clip_rectangles (struct frame *f, GC gc, XRectangle *rectangles, int n)
 +{
 +  XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, rectangles, n, Unsorted);
 +#ifdef USE_CAIRO
 +  eassert (n >= 0 && n <= MAX_CLIP_RECTS);
 +
 +  {
 +    struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 1);
 +
 +    gc_ext->n_clip_rects = n;
 +    memcpy (gc_ext->clip_rects, rectangles, sizeof (XRectangle) * n);
 +  }
 +#endif
 +}
 +
 +static void
 +x_reset_clip_rectangles (struct frame *f, GC gc)
 +{
 +  XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
 +#ifdef USE_CAIRO
 +  {
 +    struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
 +
 +    if (gc_ext)
 +      gc_ext->n_clip_rects = 0;
 +  }
 +#endif
 +}
 +
 +static void
 +x_fill_rectangle (struct frame *f, GC gc, int x, int y, int width, int height)
 +{
 +#ifdef USE_CAIRO
 +  cairo_t *cr;
 +
 +  cr = x_begin_cr_clip (f, gc);
 +  x_set_cr_source_with_gc_foreground (f, gc);
 +  cairo_rectangle (cr, x, y, width, height);
 +  cairo_fill (cr);
 +  x_end_cr_clip (f);
 +#else
 +  XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
 +                gc, x, y, width, height);
 +#endif
 +}
 +
 +static void
 +x_draw_rectangle (struct frame *f, GC gc, int x, int y, int width, int height)
 +{
 +#ifdef USE_CAIRO
 +  cairo_t *cr;
 +
 +  cr = x_begin_cr_clip (f, gc);
 +  x_set_cr_source_with_gc_foreground (f, gc);
 +  cairo_rectangle (cr, x + 0.5, y + 0.5, width, height);
 +  cairo_set_line_width (cr, 1);
 +  cairo_stroke (cr);
 +  x_end_cr_clip (f);
 +#else
 +  XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
 +                gc, x, y, width, height);
 +#endif
 +}
 +
 +static void
 +x_clear_window (struct frame *f)
 +{
 +#ifdef USE_CAIRO
 +  cairo_t *cr;
 +
 +  cr = x_begin_cr_clip (f, NULL);
 +  x_set_cr_source_with_gc_background (f, f->output_data.x->normal_gc);
 +  cairo_paint (cr);
 +  x_end_cr_clip (f);
 +#else
 +  XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
 +#endif
 +}
 +
 +#ifdef USE_CAIRO
 +static void
 +x_fill_trapezoid_for_relief (struct frame *f, GC gc, int x, int y,
 +                           int width, int height, int top_p)
 +{
 +  cairo_t *cr;
 +
 +  cr = x_begin_cr_clip (f, gc);
 +  x_set_cr_source_with_gc_foreground (f, gc);
 +  cairo_move_to (cr, top_p ? x : x + height, y);
 +  cairo_line_to (cr, x, y + height);
 +  cairo_line_to (cr, top_p ? x + width - height : x + width, y + height);
 +  cairo_line_to (cr, x + width, y);
 +  cairo_fill (cr);
 +  x_end_cr_clip (f);
 +}
 +
 +enum corners
 +  {
 +    CORNER_BOTTOM_RIGHT,      /* 0 -> pi/2 */
 +    CORNER_BOTTOM_LEFT,               /* pi/2 -> pi */
 +    CORNER_TOP_LEFT,          /* pi -> 3pi/2 */
 +    CORNER_TOP_RIGHT,         /* 3pi/2 -> 2pi */
 +    CORNER_LAST
 +  };
 +
 +static void
 +x_erase_corners_for_relief (struct frame *f, GC gc, int x, int y,
 +                          int width, int height,
 +                          double radius, double margin, int corners)
 +{
 +  cairo_t *cr;
 +  int i;
 +
 +  cr = x_begin_cr_clip (f, gc);
 +  x_set_cr_source_with_gc_background (f, gc);
 +  for (i = 0; i < CORNER_LAST; i++)
 +    if (corners & (1 << i))
 +      {
 +      double xm, ym, xc, yc;
 +
 +      if (i == CORNER_TOP_LEFT || i == CORNER_BOTTOM_LEFT)
 +        xm = x - margin, xc = xm + radius;
 +      else
 +        xm = x + width + margin, xc = xm - radius;
 +      if (i == CORNER_TOP_LEFT || i == CORNER_TOP_RIGHT)
 +        ym = y - margin, yc = ym + radius;
 +      else
 +        ym = y + height + margin, yc = ym - radius;
 +
 +      cairo_move_to (cr, xm, ym);
 +      cairo_arc (cr, xc, yc, radius, i * M_PI_2, (i + 1) * M_PI_2);
 +      }
 +  cairo_clip (cr);
 +  cairo_rectangle (cr, x, y, width, height);
 +  cairo_fill (cr);
 +  x_end_cr_clip (f);
 +}
 +
 +static void
 +x_draw_horizontal_wave (struct frame *f, GC gc, int x, int y,
 +                      int width, int height, int wave_length)
 +{
 +  cairo_t *cr;
 +  double dx = wave_length, dy = height - 1;
 +  int xoffset, n;
 +
 +  cr = x_begin_cr_clip (f, gc);
 +  x_set_cr_source_with_gc_foreground (f, gc);
 +  cairo_rectangle (cr, x, y, width, height);
 +  cairo_clip (cr);
 +
 +  if (x >= 0)
 +    {
 +      xoffset = x % (wave_length * 2);
 +      if (xoffset == 0)
 +      xoffset = wave_length * 2;
 +    }
 +  else
 +    xoffset = x % (wave_length * 2) + wave_length * 2;
 +  n = (width + xoffset) / wave_length + 1;
 +  if (xoffset > wave_length)
 +    {
 +      xoffset -= wave_length;
 +      --n;
 +      y += height - 1;
 +      dy = -dy;
 +    }
 +
 +  cairo_move_to (cr, x - xoffset + 0.5, y + 0.5);
 +  while (--n >= 0)
 +    {
 +      cairo_rel_line_to (cr, dx, dy);
 +      dy = -dy;
 +    }
 +  cairo_set_line_width (cr, 1);
 +  cairo_stroke (cr);
 +  x_end_cr_clip (f);
 +}
 +#endif
  
  \f
  /* Return the struct x_display_info corresponding to DPY.  */
@@@ -1037,42 -452,9 +1037,42 @@@ x_set_frame_alpha (struct frame *f
  static void
  x_update_begin (struct frame *f)
  {
 -  /* Nothing to do.  */
 -}
 +#ifdef USE_CAIRO
 +  if (! NILP (tip_frame) && XFRAME (tip_frame) == f
 +      && ! FRAME_VISIBLE_P (f))
 +    return;
 +
 +  if (! FRAME_CR_SURFACE (f))
 +    {
 +      int width, height;
 +#ifdef USE_GTK
 +      if (FRAME_GTK_WIDGET (f))
 +        {
 +          GdkWindow *w = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
 +          width = gdk_window_get_width (w);
 +          height = gdk_window_get_height (w);
 +        }
 +      else
 +#endif
 +        {
 +          width = FRAME_PIXEL_WIDTH (f);
 +          height = FRAME_PIXEL_HEIGHT (f);
 +          if (! FRAME_EXTERNAL_TOOL_BAR (f))
 +            height += FRAME_TOOL_BAR_HEIGHT (f);
 +          if (! FRAME_EXTERNAL_MENU_BAR (f))
 +            height += FRAME_MENU_BAR_HEIGHT (f);
 +        }
  
 +      if (width > 0 && height > 0)
 +        {
 +          block_input();
 +          FRAME_CR_SURFACE (f) = cairo_image_surface_create
 +            (CAIRO_FORMAT_ARGB32, width, height);
 +          unblock_input();
 +        }
 +    }
 +#endif /* USE_CAIRO */
 +}
  
  /* Start update of window W.  */
  
@@@ -1114,12 -496,8 +1114,12 @@@ x_draw_vertical_window_border (struct w
      XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
                    face->foreground);
  
 +#ifdef USE_CAIRO
 +  x_fill_rectangle (f, f->output_data.x->normal_gc, x, y0, 1, y1 - y0);
 +#else
    XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
             f->output_data.x->normal_gc, x, y0, x, y1);
 +#endif
  }
  
  /* Draw a window divider from (x0,y0) to (x1,y1)  */
@@@ -1139,38 -517,39 +1139,38 @@@ x_draw_window_divider (struct window *w
                              ? face_last->foreground
                              : FRAME_FOREGROUND_PIXEL (f));
    Display *display = FRAME_X_DISPLAY (f);
 -  Window window = FRAME_X_WINDOW (f);
  
    if (y1 - y0 > x1 - x0 && x1 - x0 > 2)
      /* Vertical.  */
      {
        XSetForeground (display, f->output_data.x->normal_gc, color_first);
 -      XFillRectangle (display, window, f->output_data.x->normal_gc,
 -                    x0, y0, 1, y1 - y0);
 +      x_fill_rectangle (f, f->output_data.x->normal_gc,
 +                      x0, y0, 1, y1 - y0);
        XSetForeground (display, f->output_data.x->normal_gc, color);
 -      XFillRectangle (display, window, f->output_data.x->normal_gc,
 -                    x0 + 1, y0, x1 - x0 - 2, y1 - y0);
 +      x_fill_rectangle (f, f->output_data.x->normal_gc,
 +                      x0 + 1, y0, x1 - x0 - 2, y1 - y0);
        XSetForeground (display, f->output_data.x->normal_gc, color_last);
 -      XFillRectangle (display, window, f->output_data.x->normal_gc,
 -                    x1 - 1, y0, 1, y1 - y0);
 +      x_fill_rectangle (f, f->output_data.x->normal_gc,
 +                      x1 - 1, y0, 1, y1 - y0);
      }
    else if (x1 - x0 > y1 - y0 && y1 - y0 > 3)
      /* Horizontal.  */
      {
        XSetForeground (display, f->output_data.x->normal_gc, color_first);
 -      XFillRectangle (display, window, f->output_data.x->normal_gc,
 -                    x0, y0, x1 - x0, 1);
 +      x_fill_rectangle (f, f->output_data.x->normal_gc,
 +                      x0, y0, x1 - x0, 1);
        XSetForeground (display, f->output_data.x->normal_gc, color);
 -      XFillRectangle (display, window, f->output_data.x->normal_gc,
 -                    x0, y0 + 1, x1 - x0, y1 - y0 - 2);
 +      x_fill_rectangle (f, f->output_data.x->normal_gc,
 +                      x0, y0 + 1, x1 - x0, y1 - y0 - 2);
        XSetForeground (display, f->output_data.x->normal_gc, color_last);
 -      XFillRectangle (display, window, f->output_data.x->normal_gc,
 -                    x0, y1 - 1, x1 - x0, 1);
 +      x_fill_rectangle (f, f->output_data.x->normal_gc,
 +                      x0, y1 - 1, x1 - x0, 1);
      }
    else
      {
        XSetForeground (display, f->output_data.x->normal_gc, color);
 -      XFillRectangle (display, window, f->output_data.x->normal_gc,
 -                    x0, y0, x1 - x0, y1 - y0);
 +      x_fill_rectangle (f, f->output_data.x->normal_gc,
 +                      x0, y0, x1 - x0, y1 - y0);
      }
  }
  
@@@ -1233,43 -612,6 +1233,43 @@@ x_update_end (struct frame *f
    /* Mouse highlight may be displayed again.  */
    MOUSE_HL_INFO (f)->mouse_face_defer = false;
  
 +#ifdef USE_CAIRO
 +  if (FRAME_CR_SURFACE (f))
 +    {
 +      cairo_t *cr = 0;
 +      block_input();
 +#if defined (USE_GTK) && defined (HAVE_GTK3)
 +      if (FRAME_GTK_WIDGET (f))
 +        {
 +          GdkWindow *w = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
 +          cr = gdk_cairo_create (w);
 +        }
 +      else
 +#endif
 +        {
 +          cairo_surface_t *surface;
 +          int width = FRAME_PIXEL_WIDTH (f);
 +          int height = FRAME_PIXEL_HEIGHT (f);
 +          if (! FRAME_EXTERNAL_TOOL_BAR (f))
 +            height += FRAME_TOOL_BAR_HEIGHT (f);
 +          if (! FRAME_EXTERNAL_MENU_BAR (f))
 +            height += FRAME_MENU_BAR_HEIGHT (f);
 +          surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
 +                                               FRAME_X_WINDOW (f),
 +                                               FRAME_DISPLAY_INFO (f)->visual,
 +                                               width,
 +                                               height);
 +          cr = cairo_create (surface);
 +          cairo_surface_destroy (surface);
 +        }
 +
 +      cairo_set_source_surface (cr, FRAME_CR_SURFACE (f), 0, 0);
 +      cairo_paint (cr);
 +      cairo_destroy (cr);
 +      unblock_input ();
 +    }
 +#endif /* USE_CAIRO */
 +
  #ifndef XFlush
    block_input ();
    XFlush (FRAME_X_DISPLAY (f));
@@@ -1296,16 -638,18 +1296,16 @@@ x_clear_under_internal_border (struct f
  {
    if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
      {
 -      Display *display = FRAME_X_DISPLAY (f);
 -      Window window = FRAME_X_WINDOW (f);
        int border = FRAME_INTERNAL_BORDER_WIDTH (f);
        int width = FRAME_PIXEL_WIDTH (f);
        int height = FRAME_PIXEL_HEIGHT (f);
        int margin = FRAME_TOP_MARGIN_HEIGHT (f);
  
        block_input ();
 -      x_clear_area (display, window, 0, 0, border, height);
 -      x_clear_area (display, window, 0, margin, width, border);
 -      x_clear_area (display, window, width - border, 0, border, height);
 -      x_clear_area (display, window, 0, height - border, width, border);
 +      x_clear_area (f, 0, 0, border, height);
 +      x_clear_area (f, 0, margin, width, border);
 +      x_clear_area (f, width - border, 0, border, height);
 +      x_clear_area (f, 0, height - border, width, border);
        unblock_input ();
      }
  }
@@@ -1347,8 -691,11 +1347,8 @@@ x_after_update_window_line (struct wind
        int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
  
        block_input ();
 -      x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
 -                    0, y, width, height);
 -      x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
 -                    FRAME_PIXEL_WIDTH (f) - width,
 -                    y, width, height);
 +      x_clear_area (f, 0, y, width, height);
 +      x_clear_area (f, FRAME_PIXEL_WIDTH (f) - width, y, width, height);
        unblock_input ();
        }
    }
@@@ -1378,29 -725,13 +1378,29 @@@ x_draw_fringe_bitmap (struct window *w
        else
        XSetForeground (display, face->gc, face->background);
  
 -      XFillRectangle (display, window, face->gc,
 -                    p->bx, p->by, p->nx, p->ny);
 +      x_fill_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny);
  
        if (!face->stipple)
        XSetForeground (display, face->gc, face->foreground);
      }
  
 +#ifdef USE_CAIRO
 +  if (p->which && p->which < max_fringe_bmp)
 +    {
 +      XGCValues gcv;
 +
 +      XGetGCValues (display, gc, GCForeground | GCBackground, &gcv);
 +      XSetForeground (display, gc, (p->cursor_p
 +                                  ? (p->overlay_p ? face->background
 +                                     : f->output_data.x->cursor_pixel)
 +                                  : face->foreground));
 +      XSetBackground (display, gc, face->background);
 +      x_cr_draw_image (f, gc, fringe_bmp[p->which], 0, p->dh,
 +                     p->wd, p->h, p->x, p->y, p->overlay_p);
 +      XSetForeground (display, gc, gcv.foreground);
 +      XSetBackground (display, gc, gcv.background);
 +    }
 +#else  /* not USE_CAIRO */
    if (p->which)
      {
        char *bits;
          XFreePixmap (display, clipmask);
        }
      }
 +#endif  /* not USE_CAIRO */
  
 -  XSetClipMask (display, gc, None);
 +  x_reset_clip_rectangles (f, gc);
  }
  
  /***********************************************************************
@@@ -1655,7 -985,7 +1655,7 @@@ x_set_glyph_string_clipping (struct gly
    int n = get_glyph_string_clip_rects (s, r, 2);
  
    if (n > 0)
 -    XSetClipRectangles (s->display, s->gc, 0, 0, r, n, Unsorted);
 +    x_set_clip_rectangles (s->f, s->gc, r, n);
    s->num_clips = n;
  }
  
@@@ -1675,7 -1005,7 +1675,7 @@@ x_set_glyph_string_clipping_exactly (st
    r.height = src->height;
    dst->clip[0] = r;
    dst->num_clips = 1;
 -  XSetClipRectangles (dst->display, dst->gc, 0, 0, &r, 1, Unsorted);
 +  x_set_clip_rectangles (dst->f, dst->gc, &r, 1);
  }
  
  
@@@ -1727,7 -1057,7 +1727,7 @@@ x_clear_glyph_string_rect (struct glyph
    XGCValues xgcv;
    XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
    XSetForeground (s->display, s->gc, xgcv.background);
 -  XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
 +  x_fill_rectangle (s->f, s->gc, x, y, w, h);
    XSetForeground (s->display, s->gc, xgcv.foreground);
  }
  
@@@ -1751,7 -1081,7 +1751,7 @@@ x_draw_glyph_string_background (struct 
        {
          /* Fill background with a stipple pattern.  */
          XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
 -        XFillRectangle (s->display, s->window, s->gc, s->x,
 +        x_fill_rectangle (s->f, s->gc, s->x,
                          s->y + box_line_width,
                          s->background_width,
                          s->height - 2 * box_line_width);
@@@ -1794,7 -1124,7 +1794,7 @@@ x_draw_glyph_string_foreground (struct 
        for (i = 0; i < s->nchars; ++i)
        {
          struct glyph *g = s->first_glyph + i;
 -        XDrawRectangle (s->display, s->window,
 +        x_draw_rectangle (s->f,
                          s->gc, x, s->y, g->pixel_width - 1,
                          s->height - 1);
          x += g->pixel_width;
@@@ -1846,7 -1176,7 +1846,7 @@@ x_draw_composite_glyph_string_foregroun
    if (s->font_not_found_p)
      {
        if (s->cmp_from == 0)
 -      XDrawRectangle (s->display, s->window, s->gc, x, s->y,
 +      x_draw_rectangle (s->f, s->gc, x, s->y,
                        s->width - 1, s->height - 1);
      }
    else if (! s->first_glyph->u.cmp.automatic)
@@@ -1980,7 -1310,7 +1980,7 @@@ x_draw_glyphless_glyph_string_foregroun
                                 false);
        }
        if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
 -      XDrawRectangle (s->display, s->window, s->gc,
 +      x_draw_rectangle (s->f, s->gc,
                        x, s->ybase - glyph->ascent,
                        glyph->pixel_width - 1,
                        glyph->ascent + glyph->descent - 1);
@@@ -2552,79 -1882,6 +2552,79 @@@ x_draw_relief_rect (struct frame *f
                    bool left_p, bool right_p,
                    XRectangle *clip_rect)
  {
 +#ifdef USE_CAIRO
 +  GC top_left_gc, bottom_right_gc;
 +  int corners = 0;
 +
 +  if (raised_p)
 +    {
 +      top_left_gc = f->output_data.x->white_relief.gc;
 +      bottom_right_gc = f->output_data.x->black_relief.gc;
 +    }
 +  else
 +    {
 +      top_left_gc = f->output_data.x->black_relief.gc;
 +      bottom_right_gc = f->output_data.x->white_relief.gc;
 +    }
 +
 +  x_set_clip_rectangles (f, top_left_gc, clip_rect, 1);
 +  x_set_clip_rectangles (f, bottom_right_gc, clip_rect, 1);
 +
 +  if (left_p)
 +    {
 +      x_fill_rectangle (f, top_left_gc, left_x, top_y,
 +                      width, bottom_y + 1 - top_y);
 +      if (top_p)
 +      corners |= 1 << CORNER_TOP_LEFT;
 +      if (bot_p)
 +      corners |= 1 << CORNER_BOTTOM_LEFT;
 +    }
 +  if (right_p)
 +    {
 +      x_fill_rectangle (f, bottom_right_gc, right_x + 1 - width, top_y,
 +                      width, bottom_y + 1 - top_y);
 +      if (top_p)
 +      corners |= 1 << CORNER_TOP_RIGHT;
 +      if (bot_p)
 +      corners |= 1 << CORNER_BOTTOM_RIGHT;
 +    }
 +  if (top_p)
 +    {
 +      if (!right_p)
 +      x_fill_rectangle (f, top_left_gc, left_x, top_y,
 +                        right_x + 1 - left_x, width);
 +      else
 +      x_fill_trapezoid_for_relief (f, top_left_gc, left_x, top_y,
 +                                   right_x + 1 - left_x, width, 1);
 +    }
 +  if (bot_p)
 +    {
 +      if (!left_p)
 +      x_fill_rectangle (f, bottom_right_gc, left_x, bottom_y + 1 - width,
 +                        right_x + 1 - left_x, width);
 +      else
 +      x_fill_trapezoid_for_relief (f, bottom_right_gc,
 +                                   left_x, bottom_y + 1 - width,
 +                                   right_x + 1 - left_x, width, 0);
 +    }
 +  if (left_p && width != 1)
 +    x_fill_rectangle (f, bottom_right_gc, left_x, top_y,
 +                    1, bottom_y + 1 - top_y);
 +  if (top_p && width != 1)
 +    x_fill_rectangle (f, bottom_right_gc, left_x, top_y,
 +                    right_x + 1 - left_x, 1);
 +  if (corners)
 +    {
 +      XSetBackground (FRAME_X_DISPLAY (f), top_left_gc,
 +                    FRAME_BACKGROUND_PIXEL (f));
 +      x_erase_corners_for_relief (f, top_left_gc, left_x, top_y,
 +                                right_x - left_x + 1, bottom_y - top_y + 1,
 +                                6, 1, corners);
 +    }
 +
 +  x_reset_clip_rectangles (f, top_left_gc);
 +  x_reset_clip_rectangles (f, bottom_right_gc);
 +#else
    Display *dpy = FRAME_X_DISPLAY (f);
    Window window = FRAME_X_WINDOW (f);
    int i;
                   right_x - i, bottom_y + 1 - (i + 1) * bot_p);
      }
  
 -  XSetClipMask (dpy, gc, None);
 +  x_reset_clip_rectangles (f, gc);
 +
 +#endif
  }
  
  
@@@ -2735,28 -1990,28 +2735,28 @@@ x_draw_box_rect (struct glyph_string *s
  
    XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
    XSetForeground (s->display, s->gc, s->face->box_color);
 -  XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
 +  x_set_clip_rectangles (s->f, s->gc, clip_rect, 1);
  
    /* Top.  */
 -  XFillRectangle (s->display, s->window, s->gc,
 +  x_fill_rectangle (s->f, s->gc,
                  left_x, top_y, right_x - left_x + 1, width);
  
    /* Left.  */
    if (left_p)
 -    XFillRectangle (s->display, s->window, s->gc,
 +    x_fill_rectangle (s->f, s->gc,
                    left_x, top_y, width, bottom_y - top_y + 1);
  
    /* Bottom.  */
 -  XFillRectangle (s->display, s->window, s->gc,
 +  x_fill_rectangle (s->f, s->gc,
                  left_x, bottom_y - width + 1, right_x - left_x + 1, width);
  
    /* Right.  */
    if (right_p)
 -    XFillRectangle (s->display, s->window, s->gc,
 +    x_fill_rectangle (s->f, s->gc,
                    right_x - width + 1, top_y, width, bottom_y - top_y + 1);
  
    XSetForeground (s->display, s->gc, xgcv.foreground);
 -  XSetClipMask (s->display, s->gc, None);
 +  x_reset_clip_rectangles (s->f, s->gc);
  }
  
  
@@@ -2887,7 -2142,7 +2887,7 @@@ x_draw_image_foreground (struct glyph_s
          if (s->hl == DRAW_CURSOR)
            {
              int relief = eabs (s->img->relief);
 -            XDrawRectangle (s->display, s->window, s->gc,
 +            x_draw_rectangle (s->f, s->gc,
                              x - relief, y - relief,
                              s->slice.width + relief*2 - 1,
                              s->slice.height + relief*2 - 1);
      }
    else
      /* Draw a rectangle if image could not be loaded.  */
 -    XDrawRectangle (s->display, s->window, s->gc, x, y,
 +    x_draw_rectangle (s->f, s->gc, x, y,
                    s->slice.width - 1, s->slice.height - 1);
  }
  
@@@ -3035,7 -2290,7 +3035,7 @@@ x_draw_image_foreground_1 (struct glyph
          if (s->hl == DRAW_CURSOR)
            {
              int r = eabs (s->img->relief);
 -            XDrawRectangle (s->display, s->window, s->gc, x - r, y - r,
 +            x_draw_rectangle (s->f, s->gc, x - r, y - r,
                              s->slice.width + r*2 - 1,
                              s->slice.height + r*2 - 1);
            }
      }
    else
      /* Draw a rectangle if image could not be loaded.  */
 -    XDrawRectangle (s->display, pixmap, s->gc, x, y,
 +    x_draw_rectangle (s->f, s->gc, x, y,
                    s->slice.width - 1, s->slice.height - 1);
  }
  
@@@ -3058,7 -2313,7 +3058,7 @@@ x_draw_glyph_string_bg_rect (struct gly
      {
        /* Fill background with a stipple pattern.  */
        XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
 -      XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
 +      x_fill_rectangle (s->f, s->gc, x, y, w, h);
        XSetFillStyle (s->display, s->gc, FillSolid);
      }
    else
@@@ -3167,25 -2422,7 +3167,25 @@@ x_draw_image_glyph_string (struct glyph
      }
  
    /* Draw the foreground.  */
 -  if (pixmap != None)
 +#ifdef USE_CAIRO
 +  if (s->img->cr_data)
 +    {
 +      cairo_t *cr = x_begin_cr_clip (s->f, s->gc);
 +
 +      int x = s->x + s->img->hmargin;
 +      int y = s->y + s->img->vmargin;
 +      int width = s->background_width;
 +
 +      cairo_set_source_surface (cr, s->img->cr_data,
 +                                x - s->slice.x,
 +                                y - s->slice.y);
 +      cairo_rectangle (cr, x, y, width, height);
 +      cairo_fill (cr);
 +      x_end_cr_clip (s->f);
 +    }
 +  else
 +#endif
 +    if (pixmap != None)
      {
        x_draw_image_foreground_1 (s, pixmap);
        x_set_glyph_string_clipping (s);
@@@ -3268,13 -2505,13 +3268,13 @@@ x_draw_stretch_glyph_string (struct gly
            gc = s->face->gc;
  
          get_glyph_string_clip_rect (s, &r);
 -        XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
 +        x_set_clip_rectangles (s->f, gc, &r, 1);
  
          if (s->face->stipple)
            {
              /* Fill background with a stipple pattern.  */
              XSetFillStyle (s->display, gc, FillOpaqueStippled);
 -            XFillRectangle (s->display, s->window, gc, x, y, w, h);
 +            x_fill_rectangle (s->f, gc, x, y, w, h);
              XSetFillStyle (s->display, gc, FillSolid);
            }
          else
              XGCValues xgcv;
              XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
              XSetForeground (s->display, gc, xgcv.background);
 -            XFillRectangle (s->display, s->window, gc, x, y, w, h);
 +            x_fill_rectangle (s->f, gc, x, y, w, h);
              XSetForeground (s->display, gc, xgcv.foreground);
            }
  
 -        XSetClipMask (s->display, gc, None);
 +        x_reset_clip_rectangles (s->f, gc);
        }
      }
    else if (!s->background_filled_p)
@@@ -3323,10 -2560,6 +3323,10 @@@ static voi
  x_draw_underwave (struct glyph_string *s)
  {
    int wave_height = 3, wave_length = 2;
 +#ifdef USE_CAIRO
 +  x_draw_horizontal_wave (s->f, s->gc, s->x, s->ybase - wave_height + 3,
 +                        s->width, wave_height, wave_length);
 +#else  /* not USE_CAIRO */
    int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax;
    bool odd;
    XRectangle wave_clip, string_clip, final_clip;
  
    /* Restore previous clipping rectangle(s) */
    XSetClipRectangles (s->display, s->gc, 0, 0, s->clip, s->num_clips, Unsorted);
 +#endif        /* not USE_CAIRO */
  }
  
  
@@@ -3546,14 -2778,14 +3546,14 @@@ x_draw_glyph_string (struct glyph_strin
                s->underline_position = position;
                y = s->ybase + position;
                if (s->face->underline_defaulted_p)
 -                XFillRectangle (s->display, s->window, s->gc,
 +                x_fill_rectangle (s->f, s->gc,
                                  s->x, y, s->width, thickness);
                else
                  {
                    XGCValues xgcv;
                    XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
                    XSetForeground (s->display, s->gc, s->face->underline_color);
 -                  XFillRectangle (s->display, s->window, s->gc,
 +                  x_fill_rectangle (s->f, s->gc,
                                    s->x, y, s->width, thickness);
                    XSetForeground (s->display, s->gc, xgcv.foreground);
                  }
          unsigned long dy = 0, h = 1;
  
          if (s->face->overline_color_defaulted_p)
 -          XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
 +          x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
                            s->width, h);
          else
            {
              XGCValues xgcv;
              XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
              XSetForeground (s->display, s->gc, s->face->overline_color);
 -            XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
 +            x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
                              s->width, h);
              XSetForeground (s->display, s->gc, xgcv.foreground);
            }
          unsigned long dy = (s->height - h) / 2;
  
          if (s->face->strike_through_color_defaulted_p)
 -          XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
 +          x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
                            s->width, h);
          else
            {
              XGCValues xgcv;
              XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
              XSetForeground (s->display, s->gc, s->face->strike_through_color);
 -            XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
 +            x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
                              s->width, h);
              XSetForeground (s->display, s->gc, xgcv.foreground);
            }
                  x_draw_glyph_string_foreground (prev);
                else
                  x_draw_composite_glyph_string_foreground (prev);
 -              XSetClipMask (prev->display, prev->gc, None);
 +              x_reset_clip_rectangles (prev->f, prev->gc);
                prev->hl = save;
                prev->num_clips = 0;
              }
                  x_draw_glyph_string_foreground (next);
                else
                  x_draw_composite_glyph_string_foreground (next);
 -              XSetClipMask (next->display, next->gc, None);
 +              x_reset_clip_rectangles (next->f, next->gc);
                next->hl = save;
                next->num_clips = 0;
                next->clip_head = s->next;
      }
  
    /* Reset clipping.  */
 -  XSetClipMask (s->display, s->gc, None);
 +  x_reset_clip_rectangles (s->f, s->gc);
    s->num_clips = 0;
  }
  
@@@ -3686,32 -2918,11 +3686,32 @@@ x_delete_glyphs (struct frame *f, regis
  /* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
     If they are <= 0, this is probably an error.  */
  
 +static void
 +x_clear_area1 (Display *dpy, Window window,
 +               int x, int y, int width, int height, int exposures)
 +{
 +  eassert (width > 0 && height > 0);
 +  XClearArea (dpy, window, x, y, width, height, exposures);
 +}
 +
 +
  void
 -x_clear_area (Display *dpy, Window window, int x, int y, int width, int height)
 +x_clear_area (struct frame *f, int x, int y, int width, int height)
  {
 +#ifdef USE_CAIRO
 +  cairo_t *cr;
 +
    eassert (width > 0 && height > 0);
 -  XClearArea (dpy, window, x, y, width, height, False);
 +
 +  cr = x_begin_cr_clip (f, NULL);
 +  x_set_cr_source_with_gc_background (f, f->output_data.x->normal_gc);
 +  cairo_rectangle (cr, x, y, width, height);
 +  cairo_fill (cr);
 +  x_end_cr_clip (f);
 +#else
 +  x_clear_area1 (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
 +               x, y, width, height, False);
 +#endif
  }
  
  
@@@ -3726,7 -2937,7 +3726,7 @@@ x_clear_frame (struct frame *f
  
    block_input ();
  
 -  XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
 +  x_clear_window (f);
  
    /* We have to clear the scroll bars.  If we have changed colors or
       something like that, then they should be notified.  */
@@@ -4032,16 -3243,12 +4032,16 @@@ x_scroll_run (struct window *w, struct 
    /* Cursor off.  Will be switched on again in x_update_window_end.  */
    x_clear_cursor (w);
  
 +#ifdef USE_CAIRO
 +  SET_FRAME_GARBAGED (f);
 +#else
    XCopyArea (FRAME_X_DISPLAY (f),
             FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
             f->output_data.x->normal_gc,
             x, from_y,
             width, height,
             x, to_y);
 +#endif
  
    unblock_input ();
  }
@@@ -4950,7 -4157,7 +4950,7 @@@ XTmouse_position (struct frame **fp, in
            dpyinfo->last_mouse_glyph_frame = f1;
  
            *bar_window = Qnil;
 -          *part = scroll_bar_above_handle;
 +          *part = 0;
            *fp = f1;
            XSETINT (*x, win_x);
            XSETINT (*y, win_y);
@@@ -5044,7 -4251,7 +5044,7 @@@ x_window_to_menu_bar (Window window
  #ifdef USE_TOOLKIT_SCROLL_BARS
  
  static void x_send_scroll_bar_event (Lisp_Object, enum scroll_bar_part,
 -                                   int, int, bool);
 +                                     int, int, bool);
  
  /* Lisp window being scrolled.  Set when starting to interact with
     a toolkit scroll bar, reset to nil when ending the interaction.  */
@@@ -6301,7 -5508,8 +6301,7 @@@ x_scroll_bar_create (struct window *w, 
         for the case that a window has been split horizontally.  In
         this case, no clear_frame is generated to reduce flickering.  */
      if (width > 0 && window_box_height (w) > 0)
 -      x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
 -                  left, top, width, window_box_height (w));
 +      x_clear_area (f, left, top, width, window_box_height (w));
  
      window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
                            /* Position and size of scroll bar.  */
@@@ -6433,7 -5641,7 +6433,7 @@@ x_scroll_bar_set_handle (struct scroll_
      /* Draw the empty space above the handle.  Note that we can't clear
         zero-height areas; that means "clear to end of window."  */
      if ((inside_width > 0) && (start > 0))
 -      x_clear_area (FRAME_X_DISPLAY (f), w,
 +      x_clear_area1 (FRAME_X_DISPLAY (f), w,
                    VERTICAL_SCROLL_BAR_LEFT_BORDER,
                    VERTICAL_SCROLL_BAR_TOP_BORDER,
                    inside_width, start);
                      f->output_data.x->scroll_bar_foreground_pixel);
  
      /* Draw the handle itself.  */
 -    XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
 +    x_fill_rectangle (f, gc,
                    /* x, y, width, height */
                    VERTICAL_SCROLL_BAR_LEFT_BORDER,
                    VERTICAL_SCROLL_BAR_TOP_BORDER + start,
      /* Draw the empty space below the handle.  Note that we can't
         clear zero-height areas; that means "clear to end of window." */
      if ((inside_width > 0) && (end < inside_height))
 -      x_clear_area (FRAME_X_DISPLAY (f), w,
 +      x_clear_area1 (FRAME_X_DISPLAY (f), w,
                    VERTICAL_SCROLL_BAR_LEFT_BORDER,
                    VERTICAL_SCROLL_BAR_TOP_BORDER + end,
                    inside_width, inside_height - end);
@@@ -6525,7 -5733,8 +6525,7 @@@ XTset_vertical_scroll_bar (struct windo
        if (width > 0 && height > 0)
        {
          block_input ();
 -        x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
 -                      left, top, width, height);
 +          x_clear_area (f, left, top, width, height);
          unblock_input ();
        }
  
          /* Since toolkit scroll bars are smaller than the space reserved
             for them on the frame, we have to clear "under" them.  */
          if (width > 0 && height > 0)
 -          x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
 -                        left, top, width, height);
 +          x_clear_area (f, left, top, width, height);
  #ifdef USE_GTK
            xg_update_scrollbar_pos (f, bar->x_window, top,
                                   left, width, max (height, 1));
@@@ -6643,7 -5853,8 +6643,7 @@@ XTset_horizontal_scroll_bar (struct win
  
          /* Clear also part between window_width and
             WINDOW_PIXEL_WIDTH.  */
 -        x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
 -                      left, top, pixel_width, height);
 +        x_clear_area (f, left, top, pixel_width, height);
          unblock_input ();
        }
  
          /* Since toolkit scroll bars are smaller than the space reserved
             for them on the frame, we have to clear "under" them.  */
          if (width > 0 && height > 0)
 -          x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
 +          x_clear_area (f,
                          WINDOW_LEFT_EDGE_X (w), top,
                          pixel_width - WINDOW_RIGHT_DIVIDER_WIDTH (w), height);
  #ifdef USE_GTK
@@@ -6920,7 -6131,7 +6920,7 @@@ x_scroll_bar_expose (struct scroll_bar 
                    f->output_data.x->scroll_bar_foreground_pixel);
  
    /* Draw a one-pixel border just inside the edges of the scroll bar.  */
 -  XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
 +  x_draw_rectangle (f, gc,
                  /* x, y, width, height */
                  0, 0, bar->width - 1, bar->height - 1);
  
@@@ -7704,10 -6915,11 +7704,10 @@@ handle_one_xevent (struct x_display_inf
              }
            else
            {
 -#ifdef USE_GTK
 +#if defined (USE_GTK) && ! defined (HAVE_GTK3) && ! defined (USE_CAIRO)
              /* This seems to be needed for GTK 2.6 and later, see
                 http://debbugs.gnu.org/cgi/bugreport.cgi?bug=15398.  */
 -            x_clear_area (event->xexpose.display,
 -                          event->xexpose.window,
 +            x_clear_area (f,
                            event->xexpose.x, event->xexpose.y,
                            event->xexpose.width, event->xexpose.height);
  #endif
  
        f = any;
  
- #if ! defined (USE_GTK)
        /* If mouse-highlight is an integer, input clears out
         mouse highlighting.  */
        if (!hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
+ #if ! defined (USE_GTK)
          && (f == 0
-             || !EQ (f->tool_bar_window, hlinfo->mouse_face_window)))
+             || !EQ (f->tool_bar_window, hlinfo->mouse_face_window))
+ #endif
+         )
          {
            clear_mouse_face (hlinfo);
            hlinfo->mouse_face_hidden = true;
          }
- #endif
  
  #if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
        if (f == 0)
  
      case ConfigureNotify:
        f = x_top_window_to_frame (dpyinfo, event->xconfigure.window);
 +#ifdef USE_CAIRO
 +      if (f) x_cr_destroy_surface (f);
 +#endif
  #ifdef USE_GTK
        if (!f
            && (f = any)
          {
            xg_frame_resized (f, event->xconfigure.width,
                              event->xconfigure.height);
 +#ifdef USE_CAIRO
 +          x_cr_destroy_surface (f);
 +#endif
            f = 0;
          }
  #endif
@@@ -8750,7 -7957,7 +8751,7 @@@ x_clip_to_row (struct window *w, struc
    clip_rect.width = window_width;
    clip_rect.height = row->visible_height;
  
 -  XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
 +  x_set_clip_rectangles (f, gc, &clip_rect, 1);
  }
  
  
@@@ -8799,8 -8006,8 +8800,8 @@@ x_draw_hollow_cursor (struct window *w
      }
    /* Set clipping, draw the rectangle, and reset clipping again.  */
    x_clip_to_row (w, row, TEXT_AREA, gc);
 -  XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h - 1);
 -  XSetClipMask (dpy, gc, None);
 +  x_draw_rectangle (f, gc, x, y, wd, h - 1);
 +  x_reset_clip_rectangles (f, gc);
  }
  
  
@@@ -8878,7 -8085,7 +8879,7 @@@ x_draw_bar_cursor (struct window *w, st
          if ((cursor_glyph->resolved_level & 1) != 0)
            x += cursor_glyph->pixel_width - width;
  
 -        XFillRectangle (dpy, window, gc, x,
 +        x_fill_rectangle (f, gc, x,
                          WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
                          width, row->height);
        }
          if ((cursor_glyph->resolved_level & 1) != 0
              && cursor_glyph->pixel_width > w->phys_cursor_width - 1)
            x += cursor_glyph->pixel_width - w->phys_cursor_width + 1;
 -        XFillRectangle (dpy, window, gc, x,
 -                        WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
 -                                                 row->height - width),
 -                        w->phys_cursor_width - 1, width);
 +        x_fill_rectangle (f, gc, x,
 +                          WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
 +                                                     row->height - width),
 +                            w->phys_cursor_width - 1, width);
        }
  
 -      XSetClipMask (dpy, gc, None);
 +      x_reset_clip_rectangles (f, gc);
      }
  }
  
@@@ -8926,7 -8133,7 +8927,7 @@@ x_define_frame_cursor (struct frame *f
  static void
  x_clear_frame_area (struct frame *f, int x, int y, int width, int height)
  {
 -  x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), x, y, width, height);
 +  x_clear_area (f, x, y, width, height);
  #ifdef USE_GTK
    /* Must queue a redraw, because scroll bars might have been cleared.  */
    if (FRAME_GTK_WIDGET (f))
@@@ -11040,7 -10247,6 +11041,7 @@@ x_free_frame_resources (struct frame *f
        free_frame_xic (f);
  #endif
  
 +      x_free_cr_resources (f);
  #ifdef USE_X_TOOLKIT
        if (f->output_data.x->widget)
        {
@@@ -12127,10 -11333,6 +12128,10 @@@ x_term_init (Lisp_Object display_name, 
      x_session_initialize (dpyinfo);
  #endif
  
 +#ifdef USE_CAIRO
 +  x_extension_initialize (dpyinfo);
 +#endif
 +
    unblock_input ();
  
    return dpyinfo;
@@@ -12242,13 -11444,8 +12243,13 @@@ static struct redisplay_interface x_red
      x_get_glyph_overhangs,
      x_fix_overlapping_area,
      x_draw_fringe_bitmap,
 +#ifdef USE_CAIRO
 +    x_cr_define_fringe_bitmap,
 +    x_cr_destroy_fringe_bitmap,
 +#else
      0, /* define_fringe_bitmap */
      0, /* destroy_fringe_bitmap */
 +#endif
      x_compute_glyph_string_overhangs,
      x_draw_glyph_string,
      x_define_frame_cursor,
      x_draw_window_cursor,
      x_draw_vertical_window_border,
      x_draw_window_divider,
-     x_shift_glyphs_for_insert, /* Never called, se comment in function.  */
+     x_shift_glyphs_for_insert, /* Never called; see comment in function.  */
      x_show_hourglass,
      x_hide_hourglass
    };
@@@ -12426,10 -11623,6 +12427,10 @@@ x_initialize (void
  #endif
  #endif
  
 +#ifdef USE_CAIRO
 +  x_cr_init_fringe (&x_redisplay_interface);
 +#endif
 +
    /* Note that there is no real way portable across R3/R4 to get the
       original error handler.  */
    XSetErrorHandler (x_error_handler);