emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] cairo dddcc0e: Add cairo drawing.


From: Jan D.
Subject: [Emacs-diffs] cairo dddcc0e: Add cairo drawing.
Date: Wed, 11 Feb 2015 15:15:16 +0000

branch: cairo
commit dddcc0e78452f2186c132823a33a174d2596ba33
Author: Jan D <address@hidden>
Commit: Jan D <address@hidden>

    Add cairo drawing.
    
    * configure.ac (with-cairo): New option.
    (USE_CAIRO): Default to yes for Gtk+ 3.  Add code to test for cairo,
    set CAIRO_CFLAGS, CAIRO_LIBS.  Add ftcrfonto to FONT_OBJ if cairo.
    Output "Does Emacs use cairo?".
    
    * lisp/version.el (emacs-version): Add cairo version.
    
    * src/Makefile.in (CAIRO_CFLAGS, CAIRO_LIBS): New variables.
    (FONT_OBJ): Add comment about ftcrfont.
    (ALL_CFLAGS): Add CAIRO_CFLAGS.
    (LIBES): Add CAIRO_LIBS.
    
    * src/dispextern.h (struct image): Add cr_data for cairo.
    (x_cr_init_fringe): Declare.
    
    * src/font.c (syms_of_font): Call syms_of_ftcrfont for cairo.
    
    * src/font.h (ftcrfont_driver, syms_of_ftcrfont): Declare
    
    * src/fringe.c (x_cr_init_fringe): New function name that shares code
    with w32_init_fringe.
    
    * src/ftcrfont.c: New font driver for cairo, based on the ftfont driver.
    
    * src/ftfont.c (ftfont_info_size); New global variable.
    (ftfont_open2): New extern function almost the same as old ftfont_open,
    but takes the font_object as argument.
    (ftfont_open): Build font object and call ftfont_open2.
    
    * src/ftfont.h (ftfont_open2, ftfont_info_size): Declare.
    
    * src/gtkutil.c (xg_clear_under_internal_border)
    (xg_update_scrollbar_pos, xg_update_horizontal_scrollbar_pos): Only
    queue_draw if not cairo.  Change args to x_clear_area.
    (xg_get_font): Use Qftcr when using cairo, Qxft otherwise.
    (xg_page_setup_dialog, xg_get_page_setup, draw_page)
    (xg_print_frames_dialog): New functions for printing.
    
    * src/gtkutil.h (xg_page_setup_dialog, xg_get_page_setup)
    (xg_print_frames_dialog): Declare.
    
    * src/image.c: Add defined (USE_CAIRO) for PNG.
    Add !defined USE_CAIRO for W32 PNG code.
    (x_clear_image): If cairo, destroy the surface in cr_data.
    (png_load): Add new cairo compatible implementation.
    (lookup_image_type): Add defined (USE_CAIRO) for define png_type.
    
    * src/xfns.c: New section Printing.
    (x-export-frames, x-page-setup-dialog, x-get-page-setup)
    (x-print-frames-dialog): New printing functions.
    (Fx_create_frame, x_create_tip_frame): Register ftcrfont if
    cairo.
    (syms_of_xfns): Defsym Qorientation, Qtop_margin, Qbottom_margin,
    Qportrait, Qlandscape, Qreverse_portrait, Qreverse_landscape).
    (syms_of_xfns): Provide cairo and defvar cairo-version-string.
    defsubr Sx_page_setup_dialog, Sx_get_page_setup, Sx_print_frames_dialog.
    
    * src/xterm.c (x_clear_area1, x_prepare_for_xlibdraw)
    (x_set_clip_rectangles, x_reset_clip_rectangles, x_fill_rectangle)
    (x_draw_rectangle, x_fill_trapezoid_for_relief, x_clear_window)
    (x_gc_get_ext_data, x_extension_initialize, x_cr_accumulate_data):
    Declare.
    (FRAME_CR_CONTEXT, FRAME_CR_SURFACE): New macros.
    (max_fringe_bmp, fringe_bmp): New variables.
    (x_gc_get_ext_data, x_extension_initialize)
    (x_cr_destroy_surface, x_begin_cr_clip, x_end_cr_clip)
    (x_set_cr_source_with_gc_foreground)
    (x_set_cr_source_with_gc_background, x_cr_define_fringe_bitmap)
    (x_cr_destroy_fringe_bitmap, x_cr_draw_image, x_cr_draw_frame)
    (x_cr_accumulate_data, x_cr_destroy, x_cr_export_frames)
    (x_prepare_for_xlibdraw, x_set_clip_rectangles)
    (x_reset_clip_rectangles, x_fill_rectangle, x_draw_rectangle)
    (x_clear_window, x_fill_trapezoid_for_relief): New functions.
    (x_update_begin): Create cairo surface if needed.
    (x_draw_vertical_window_border): Call x_fill_rectangle for cairo.
    (x_update_end): Paint cairo drawing surface to xlib surface.
    (x_clear_under_internal_border, x_after_update_window_line): Adjust
    arguments to x_clear_area.
    (x_draw_fringe_bitmap): Call x_fill_rectangle.  Get GC values and
    call x_cr_draw_image for cairo.  Call x_reset_clip_rectangles instead
    of XSetClipMask.
    (x_set_glyph_string_clipping)
    (x_set_glyph_string_clipping_exactly): Use x_set_clip_rectangles
    instead of XSetClipRectangles.
    (x_clear_glyph_string_rect, x_draw_glyph_string_background): Use
    x_fill_rectangle instead of XFillRectangle.
    (x_draw_glyph_string_foreground)
    (x_draw_composite_glyph_string_foreground)
    (x_draw_glyphless_glyph_string_foreground): Use x_draw_rectangle instead
    of XDrawRectangle.
    (x_draw_relief_rect): Add code for USE_CAIRO.
    Call x_reset_clip_rectangles instead of XSetClipMask.
    (x_draw_box_rect): x_set_clip_rectangles instead of XSetClipRectangles,
    x_fill_rectangle instead of XFillRectangle, x_reset_clip_rectangles
    instead of XSetClipMask.
    (x_draw_image_foreground, x_draw_image_foreground_1):
    x_draw_rectangle instead of XDrawRectangle.
    (x_draw_glyph_string_bg_rect): x_fill_rectangle instead of
    XFillRectangle.
    (x_draw_image_glyph_string): If img has cr_data, use it as
    a cairo surface.
    (x_draw_stretch_glyph_string): x_set_clip_rectangles instead of
    XSetClipRectangles, x_fill_rectangle instead of XFillRectangle.
    (x_draw_glyph_string): x_fill_rectangle instead of XFillRectangle.,
    x_reset_clip_rectangles instead of XSetClipMask.
    (x_shift_glyphs_for_insert): Call x_prepare_for_xlibdraw.
    (x_clear_area1): New function that calls XClearArea.
    (x_clear_area): Takes frame as parameter, calls x_clear_area1 for
    non-cairo.
    (x_clear_frame): x_clear_window instead of XClearWindow.
    (x_scroll_run): Set frame garbaged if cairo.
    (XTmouse_position): Initialize *part to 0.
    (x_scroll_bar_create): Adjust arguments to x_clear_area.
    (x_scroll_bar_set_handle): x_clear_area1 instead of x_clear_area,
    x_fill_rectangle instead of XFillRectangle.
    (XTset_vertical_scroll_bar, XTset_horizontal_scroll_bar): Adjust
    arguments to x_clear_area.
    (x_scroll_bar_expose): x_draw_rectangle instead of XDrawRectangle.
    (handle_one_xevent): Adjust arguments to x_clear_area.
    Destroy cairo surface for frame if ConfigureNotify.
    (x_clip_to_row): x_set_clip_rectangles instead of XSetClipRectangles.
    (x_draw_hollow_cursor): x_draw_rectangle instead of XDrawRectangle,
    x_reset_clip_rectangles instead of XSetClipMask.
    (x_draw_bar_cursor): x_fill_rectangle instead of XFillRectangle,
    x_reset_clip_rectangles instead of XSetClipMask.
    (x_clear_frame_area): Adjust arguments to x_clear_area.
    (x_free_frame_resources): Call x_prepare_for_xlibdraw.
    (x_term_init): Call x_extension_initialize if cairo.
    (x_redisplay_interface): Add x_cr_define_fringe_bitmap,
    x_cr_destroy_fringe_bitmap for cairo.
    (x_initialize): Call x_cr_init_fringe for cairo.
    
    * src/xterm.h: Add include of cairo header files.
    (x_bitmap_record): Add img if cairo.
    (x_gc_ext_data): New struct for cairo.
    (x_display_info): Add ext_codes for cairo.
    (x_output): Add cr_context and cr_surface for cairo.
    (x_clear_area): Change arguments from Display*/Window to frame pointer.
    (x_query_color, x_begin_cr_clip, x_end_cr_clip)
    (x_set_cr_source_with_gc_foreground, x_set_cr_source_with_gc_background)
    (x_cr_draw_frame, x_cr_export_frames): Declare.
---
 ChangeLog        |    7 +
 configure.ac     |   35 ++-
 lisp/ChangeLog   |    4 +
 lisp/version.el  |    7 +-
 src/ChangeLog    |  138 +++++++++
 src/Makefile.in  |    8 +-
 src/dispextern.h |    6 +
 src/font.c       |    4 +
 src/font.h       |    4 +
 src/fringe.c     |    8 +-
 src/ftcrfont.c   |  314 +++++++++++++++++++
 src/ftfont.c     |   26 ++-
 src/ftfont.h     |    5 +
 src/gtkutil.c    |  131 ++++++++-
 src/gtkutil.h    |    6 +
 src/image.c      |   55 +++-
 src/xfns.c       |  195 ++++++++++++
 src/xterm.c      |  895 +++++++++++++++++++++++++++++++++++++++++++++++++-----
 src/xterm.h      |   53 +++-
 19 files changed, 1794 insertions(+), 107 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index a574ac8..a48b305 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2015-02-11  Jan Djärv  <address@hidden>
+
+       * configure.ac (with-cairo): New option.
+       (USE_CAIRO): Default to yes for Gtk+ 3.  Add code to test for cairo,
+       set CAIRO_CFLAGS, CAIRO_LIBS.  Add ftcrfonto to FONT_OBJ if cairo.
+       Output "Does Emacs use cairo?".
+
 2015-02-09  Paul Eggert  <address@hidden>
 
        * configure.ac (HAVE_LIBXML2): Add missing comma.
diff --git a/configure.ac b/configure.ac
index 68291b8..261944f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -335,6 +335,7 @@ OPTION_DEFAULT_ON([tiff],[don't compile with TIFF image 
support])
 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])
 
@@ -2386,6 +2387,7 @@ if test "${opsys}" != "mingw32"; then
        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],
@@ -3052,6 +3054,30 @@ 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
+    with_xpm=no
+    with_jpeg=no
+    with_gif=no
+    with_tiff=no
+
+    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
@@ -3987,8 +4013,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>
@@ -4754,7 +4780,9 @@ if test "${HAVE_X_WINDOWS}" = "yes" ; then
   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"
@@ -5101,6 +5129,7 @@ echo "  Does Emacs use -ltiff?                            
      ${HAVE_TIFF}"
 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}"
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index a6e5f59..de2eb71 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,7 @@
+2015-02-11  Jan Djärv  <address@hidden>
+
+       * version.el (emacs-version): Add cairo version.
+
 2015-02-11  Martin Rudalics  <address@hidden>
 
        * frame.el (toggle-frame-maximized, toggle-frame-fullscreen):
diff --git a/lisp/version.el b/lisp/version.el
index 1837cbf..b8555cb 100644
--- a/lisp/version.el
+++ b/lisp/version.el
@@ -56,8 +56,8 @@ to the system configuration; look at `system-configuration' 
instead."
   (interactive "P")
   (let ((version-string
          (format (if (not (called-interactively-p 'interactive))
-                    "GNU Emacs %s (%s%s%s)\n of %s on %s"
-                  "GNU Emacs %s (%s%s%s) of %s on %s")
+                    "GNU Emacs %s (%s%s%s%s)\n of %s on %s"
+                  "GNU Emacs %s (%s%s%s%s) of %s on %s")
                  emacs-version
                 system-configuration
                 (cond ((featurep 'motif)
@@ -68,6 +68,9 @@ to the system configuration; look at `system-configuration' 
instead."
                       ((featurep 'ns)
                        (format ", NS %s" ns-version-string))
                       (t ""))
+                (if (featurep 'cairo)
+                    (format ", cairo version %s" cairo-version-string)
+                  "")
                 (if (and (boundp 'x-toolkit-scroll-bars)
                          (memq x-toolkit-scroll-bars '(xaw xaw3d)))
                     (format ", %s scroll bars"
diff --git a/src/ChangeLog b/src/ChangeLog
index f8e65d5..e361fe2 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,141 @@
+2015-02-11  YAMAMOTO Mitsuharu  <address@hidden>
+           Jan Djärv  <address@hidden>
+
+       * xterm.h: Add include of cairo header files.
+       (x_bitmap_record): Add img if cairo.
+       (x_gc_ext_data): New struct for cairo.
+       (x_display_info): Add ext_codes for cairo.
+       (x_output): Add cr_context and cr_surface for cairo.
+       (x_clear_area): Change arguments from Display*/Window to frame pointer.
+       (x_query_color, x_begin_cr_clip, x_end_cr_clip)
+       (x_set_cr_source_with_gc_foreground, x_set_cr_source_with_gc_background)
+       (x_cr_draw_frame, x_cr_export_frames): Declare.
+
+       * xterm.c (x_clear_area1, x_prepare_for_xlibdraw)
+       (x_set_clip_rectangles, x_reset_clip_rectangles, x_fill_rectangle)
+       (x_draw_rectangle, x_fill_trapezoid_for_relief, x_clear_window)
+       (x_gc_get_ext_data, x_extension_initialize, x_cr_accumulate_data):
+       Declare.
+       (FRAME_CR_CONTEXT, FRAME_CR_SURFACE): New macros.
+       (max_fringe_bmp, fringe_bmp): New variables.
+       (x_gc_get_ext_data, x_extension_initialize)
+       (x_cr_destroy_surface, x_begin_cr_clip, x_end_cr_clip)
+       (x_set_cr_source_with_gc_foreground)
+       (x_set_cr_source_with_gc_background, x_cr_define_fringe_bitmap)
+       (x_cr_destroy_fringe_bitmap, x_cr_draw_image, x_cr_draw_frame)
+       (x_cr_accumulate_data, x_cr_destroy, x_cr_export_frames)
+       (x_prepare_for_xlibdraw, x_set_clip_rectangles)
+       (x_reset_clip_rectangles, x_fill_rectangle, x_draw_rectangle)
+       (x_clear_window, x_fill_trapezoid_for_relief): New functions.
+       (x_update_begin): Create cairo surface if needed.
+       (x_draw_vertical_window_border): Call x_fill_rectangle for cairo.
+       (x_update_end): Paint cairo drawing surface to xlib surface.
+       (x_clear_under_internal_border, x_after_update_window_line): Adjust
+       arguments to x_clear_area.
+       (x_draw_fringe_bitmap): Call x_fill_rectangle.  Get GC values and
+       call x_cr_draw_image for cairo.  Call x_reset_clip_rectangles instead
+       of XSetClipMask.
+       (x_set_glyph_string_clipping)
+       (x_set_glyph_string_clipping_exactly): Use x_set_clip_rectangles
+       instead of XSetClipRectangles.
+       (x_clear_glyph_string_rect, x_draw_glyph_string_background): Use
+       x_fill_rectangle instead of XFillRectangle.
+       (x_draw_glyph_string_foreground)
+       (x_draw_composite_glyph_string_foreground)
+       (x_draw_glyphless_glyph_string_foreground): Use x_draw_rectangle instead
+       of XDrawRectangle.
+       (x_draw_relief_rect): Add code for USE_CAIRO.
+       Call x_reset_clip_rectangles instead of XSetClipMask.
+       (x_draw_box_rect): x_set_clip_rectangles instead of XSetClipRectangles,
+       x_fill_rectangle instead of XFillRectangle, x_reset_clip_rectangles
+       instead of XSetClipMask.
+       (x_draw_image_foreground, x_draw_image_foreground_1):
+       x_draw_rectangle instead of XDrawRectangle.
+       (x_draw_glyph_string_bg_rect): x_fill_rectangle instead of
+       XFillRectangle.
+       (x_draw_image_glyph_string): If img has cr_data, use it as
+       a cairo surface.
+       (x_draw_stretch_glyph_string): x_set_clip_rectangles instead of
+       XSetClipRectangles, x_fill_rectangle instead of XFillRectangle.
+       (x_draw_glyph_string): x_fill_rectangle instead of XFillRectangle.,
+       x_reset_clip_rectangles instead of XSetClipMask.
+       (x_shift_glyphs_for_insert): Call x_prepare_for_xlibdraw.
+       (x_clear_area1): New function that calls XClearArea.
+       (x_clear_area): Takes frame as parameter, calls x_clear_area1 for
+       non-cairo.
+       (x_clear_frame): x_clear_window instead of XClearWindow.
+       (x_scroll_run): Set frame garbaged if cairo.
+       (XTmouse_position): Initialize *part to 0.
+       (x_scroll_bar_create): Adjust arguments to x_clear_area.
+       (x_scroll_bar_set_handle): x_clear_area1 instead of x_clear_area,
+       x_fill_rectangle instead of XFillRectangle.
+       (XTset_vertical_scroll_bar, XTset_horizontal_scroll_bar): Adjust
+       arguments to x_clear_area.
+       (x_scroll_bar_expose): x_draw_rectangle instead of XDrawRectangle.
+       (handle_one_xevent): Adjust arguments to x_clear_area.
+       Destroy cairo surface for frame if ConfigureNotify.
+       (x_clip_to_row): x_set_clip_rectangles instead of XSetClipRectangles.
+       (x_draw_hollow_cursor): x_draw_rectangle instead of XDrawRectangle,
+       x_reset_clip_rectangles instead of XSetClipMask.
+       (x_draw_bar_cursor): x_fill_rectangle instead of XFillRectangle,
+       x_reset_clip_rectangles instead of XSetClipMask.
+       (x_clear_frame_area): Adjust arguments to x_clear_area.
+       (x_free_frame_resources): Call x_prepare_for_xlibdraw.
+       (x_term_init): Call x_extension_initialize if cairo.
+       (x_redisplay_interface): Add x_cr_define_fringe_bitmap,
+       x_cr_destroy_fringe_bitmap for cairo.
+       (x_initialize): Call x_cr_init_fringe for cairo.
+
+       * xfns.c: New section Printing.
+       (x-export-frames, x-page-setup-dialog, x-get-page-setup)
+       (x-print-frames-dialog): New printing functions.
+       (Fx_create_frame, x_create_tip_frame): Register ftcrfont if
+       cairo.
+       (syms_of_xfns): Defsym Qorientation, Qtop_margin, Qbottom_margin,
+       Qportrait, Qlandscape, Qreverse_portrait, Qreverse_landscape).
+       (syms_of_xfns): Provide cairo and defvar cairo-version-string.
+       defsubr Sx_page_setup_dialog, Sx_get_page_setup, Sx_print_frames_dialog.
+
+       * image.c: Add defined (USE_CAIRO) for PNG.
+       Add !defined USE_CAIRO for W32 PNG code.
+       (x_clear_image): If cairo, destroy the surface in cr_data.
+       (png_load): Add new cairo compatible implementation.
+       (lookup_image_type): Add defined (USE_CAIRO) for define png_type.
+
+       * gtkutil.h (xg_page_setup_dialog, xg_get_page_setup)
+       (xg_print_frames_dialog): Declare.
+
+       * gtkutil.c (xg_clear_under_internal_border)
+       (xg_update_scrollbar_pos, xg_update_horizontal_scrollbar_pos): Only
+       queue_draw if not cairo.  Change args to x_clear_area.
+       (xg_get_font): Use Qftcr when using cairo, Qxft otherwise.
+       (xg_page_setup_dialog, xg_get_page_setup, draw_page)
+       (xg_print_frames_dialog): New functions for printing.
+
+       * ftfont.h (ftfont_open2, ftfont_info_size): Declare.
+
+       * ftfont.c (ftfont_info_size); New global variable.
+       (ftfont_open2): New extern function almost the same as old ftfont_open,
+       but takes the font_object as argument.
+       (ftfont_open): Build font object and call ftfont_open2.
+
+       * ftcrfont.c: New font driver for cairo, based on the ftfont driver.
+
+       * fringe.c (x_cr_init_fringe): New function name that shares code
+       with w32_init_fringe.
+
+       * font.h (ftcrfont_driver, syms_of_ftcrfont): Declare
+
+       * font.c (syms_of_font): Call syms_of_ftcrfont for cairo.
+
+       * dispextern.h (struct image): Add cr_data for cairo.
+       (x_cr_init_fringe): Declare.
+
+       * Makefile.in (CAIRO_CFLAGS, CAIRO_LIBS): New variables.
+       (FONT_OBJ): Add comment about ftcrfont.
+       (ALL_CFLAGS): Add CAIRO_CFLAGS.
+       (LIBES): Add CAIRO_LIBS.
+
 2015-02-11  Martin Rudalics  <address@hidden>
 
        * w32term.c (w32_read_socket): In SIZE_MAXIMIZED and
diff --git a/src/Makefile.in b/src/Makefile.in
index 32615c8..9e7a8a7 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -218,6 +218,9 @@ CFLAGS_SOUND= @CFLAGS_SOUND@
 RSVG_LIBS= @RSVG_LIBS@
 RSVG_CFLAGS= @RSVG_CFLAGS@
 
+CAIRO_LIBS= @CAIRO_LIBS@
+CAIRO_CFLAGS= @CAIRO_CFLAGS@
+
 IMAGEMAGICK_LIBS= @IMAGEMAGICK_LIBS@
 IMAGEMAGICK_CFLAGS= @IMAGEMAGICK_CFLAGS@
 
@@ -273,6 +276,7 @@ address@hidden@
 ## Empty if !HAVE_X_WINDOWS
 ## xfont.o ftfont.o xftfont.o ftxfont.o if HAVE_XFT
 ## xfont.o ftfont.o ftxfont.o if HAVE_FREETYPE
+## ftfont.o ftcrfont.o if USE_CAIRO
 ## else xfont.o
 address@hidden@
 
@@ -345,7 +349,7 @@ ALL_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \
   $(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) $(XFIXES_CFLAGS) \
   $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \
   $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
-  $(LIBGNUTLS_CFLAGS) $(GFILENOTIFY_CFLAGS) \
+  $(LIBGNUTLS_CFLAGS) $(GFILENOTIFY_CFLAGS) $(CAIRO_CFLAGS) \
   $(WARN_CFLAGS) $(WERROR_CFLAGS) $(CFLAGS)
 ALL_OBJC_CFLAGS=$(ALL_CFLAGS) $(GNU_OBJC_CFLAGS)
 
@@ -423,7 +427,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) 
$(LIBIMAGE) \
    $(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_ACL) $(LIB_CLOCK_GETTIME) \
    $(LIB_EACCESS) $(LIB_FDATASYNC) $(LIB_TIMER_TIME) $(DBUS_LIBS) \
    $(LIB_EXECINFO) $(XRANDR_LIBS) $(XINERAMA_LIBS) $(XFIXES_LIBS) \
-   $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
+   $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) $(CAIRO_LIBS) \
    $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \
    $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
    $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) \
diff --git a/src/dispextern.h b/src/dispextern.h
index 5f730df..b9db3f8 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -2939,6 +2939,9 @@ struct image
   /* Pixmaps of the image.  */
   Pixmap pixmap, mask;
 
+#ifdef USE_CAIRO
+  void *cr_data;
+#endif
 #ifdef HAVE_X_WINDOWS
   /* X images of the image, corresponding to the above Pixmaps.
      Non-NULL means it and its Pixmap counterpart may be out of sync
@@ -3300,6 +3303,9 @@ bool update_window_fringes (struct window *, bool);
 void w32_init_fringe (struct redisplay_interface *);
 void w32_reset_fringes (void);
 #endif
+#ifdef USE_CAIRO
+void x_cr_init_fringe (struct redisplay_interface *);
+#endif
 
 extern unsigned row_hash (struct glyph_row *);
 
diff --git a/src/font.c b/src/font.c
index b2b43c7..603e998 100644
--- a/src/font.c
+++ b/src/font.c
@@ -5280,11 +5280,15 @@ EMACS_FONT_LOG is set.  Otherwise, it is set to t.  */);
 #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 --git a/src/font.h b/src/font.h
index efc184e..43e67e9 100644
--- a/src/font.h
+++ b/src/font.h
@@ -844,6 +844,10 @@ extern struct font_driver nsfont_driver;
 extern void syms_of_nsfont (void);
 extern void syms_of_macfont (void);
 #endif /* HAVE_NS */
+#ifdef USE_CAIRO
+extern struct font_driver ftcrfont_driver;
+extern void syms_of_ftcrfont (void);
+#endif
 
 #ifndef FONT_DEBUG
 #define FONT_DEBUG
diff --git a/src/fringe.c b/src/fringe.c
index 5e5ec60..27b1003 100644
--- a/src/fringe.c
+++ b/src/fringe.c
@@ -1731,10 +1731,14 @@ init_fringe (void)
   fringe_faces = xzalloc (max_fringe_bitmaps * sizeof *fringe_faces);
 }
 
-#ifdef HAVE_NTGUI
+#if defined (HAVE_NTGUI) || defined (USE_CAIRO)
 
 void
+#ifdef HAVE_NTGUI
 w32_init_fringe (struct redisplay_interface *rif)
+#else
+x_cr_init_fringe (struct redisplay_interface *rif)
+#endif
 {
   int bt;
 
@@ -1747,7 +1751,9 @@ w32_init_fringe (struct redisplay_interface *rif)
       rif->define_fringe_bitmap (bt, fb->bits, fb->height, fb->width);
     }
 }
+#endif
 
+#ifdef HAVE_NTGUI
 void
 w32_reset_fringes (void)
 {
diff --git a/src/ftcrfont.c b/src/ftcrfont.c
new file mode 100644
index 0000000..d60c120
--- /dev/null
+++ b/src/ftcrfont.c
@@ -0,0 +1,314 @@
+/* ftcrfont.c -- FreeType font driver on cairo.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+#include <config.h>
+#include <stdio.h>
+#include <cairo-ft.h>
+
+#include "lisp.h"
+#include "dispextern.h"
+#include "xterm.h"
+#include "frame.h"
+#include "blockinput.h"
+#include "character.h"
+#include "charset.h"
+#include "fontset.h"
+#include "font.h"
+#include "ftfont.h"
+
+/* FTCR font driver.  */
+
+/* The actual structure for ftcr font that can be casted to struct
+   font.  */
+
+struct ftcrfont_info
+{
+  struct font font;
+  /* The following six members must be here in this order to be
+     compatible with struct ftfont_info (in ftfont.c).  */
+#ifdef HAVE_LIBOTF
+  bool maybe_otf;        /* Flag to tell if this may be OTF or not.  */
+  OTF *otf;
+#endif /* HAVE_LIBOTF */
+  FT_Size ft_size;
+  int index;
+  FT_Matrix matrix;
+
+  cairo_font_face_t *cr_font_face;
+  /* To prevent cairo from cluttering the activated FT_Size maintained
+     in ftfont.c, we activate this special FT_Size before drawing.  */
+  FT_Size ft_size_draw;
+  /* Font metrics cache.  */
+  struct font_metrics **metrics;
+  short metrics_nrows;
+};
+
+#define METRICS_NCOLS_PER_ROW  (128)
+
+enum metrics_status
+  {
+    METRICS_INVALID = -1,    /* metrics entry is invalid */
+  };
+
+#define METRICS_STATUS(metrics)        ((metrics)->ascent + (metrics)->descent)
+#define METRICS_SET_STATUS(metrics, status) \
+  ((metrics)->ascent = 0, (metrics)->descent = (status))
+
+/* Prototypes for helper function.  */
+static int ftcrfont_glyph_extents (struct font *, unsigned,
+                                      struct font_metrics *);
+
+/* Prototypes for font-driver methods.  */
+static Lisp_Object ftcrfont_list (struct frame*, Lisp_Object);
+static Lisp_Object ftcrfont_match (struct frame*, Lisp_Object);
+static Lisp_Object ftcrfont_open (struct frame*, Lisp_Object, int);
+static void ftcrfont_close (struct font *);
+static void ftcrfont_text_extents (struct font *, unsigned *, int,
+                                   struct font_metrics *);
+static int ftcrfont_draw (struct glyph_string *, int, int, int, int, bool);
+
+struct font_driver ftcrfont_driver;
+
+static int
+ftcrfont_glyph_extents (struct font *font,
+                        unsigned glyph,
+                        struct font_metrics *metrics)
+{
+  struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) font;
+  int row, col;
+  struct font_metrics *cache;
+
+  row = glyph / METRICS_NCOLS_PER_ROW;
+  col = glyph % METRICS_NCOLS_PER_ROW;
+  if (row >= ftcrfont_info->metrics_nrows)
+    {
+      ftcrfont_info->metrics =
+       xrealloc (ftcrfont_info->metrics,
+                 sizeof (struct font_metrics *) * (row + 1));
+      bzero (ftcrfont_info->metrics + ftcrfont_info->metrics_nrows,
+            (sizeof (struct font_metrics *)
+             * (row + 1 - ftcrfont_info->metrics_nrows)));
+      ftcrfont_info->metrics_nrows = row + 1;
+    }
+  if (ftcrfont_info->metrics[row] == NULL)
+    {
+      struct font_metrics *new;
+      int i;
+
+      new = xmalloc (sizeof (struct font_metrics) * METRICS_NCOLS_PER_ROW);
+      for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
+       METRICS_SET_STATUS (new + i, METRICS_INVALID);
+      ftcrfont_info->metrics[row] = new;
+    }
+  cache = ftcrfont_info->metrics[row] + col;
+
+  if (METRICS_STATUS (cache) == METRICS_INVALID)
+    ftfont_driver.text_extents (font, &glyph, 1, cache);
+
+  if (metrics)
+    *metrics = *cache;
+
+  return cache->width;
+}
+
+static Lisp_Object
+ftcrfont_list (struct frame *f, Lisp_Object spec)
+{
+  Lisp_Object list = ftfont_driver.list (f, spec), tail;
+
+  for (tail = list; CONSP (tail); tail = XCDR (tail))
+    ASET (XCAR (tail), FONT_TYPE_INDEX, Qftcr);
+  return list;
+}
+
+static Lisp_Object
+ftcrfont_match (struct frame *f, Lisp_Object spec)
+{
+  Lisp_Object entity = ftfont_driver.match (f, spec);
+
+  if (VECTORP (entity))
+    ASET (entity, FONT_TYPE_INDEX, Qftcr);
+  return entity;
+}
+
+extern FT_Face ftfont_get_ft_face (Lisp_Object);
+
+static Lisp_Object
+ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
+{
+  Lisp_Object font_object;
+  struct font *font;
+  struct ftcrfont_info *ftcrfont_info;
+  FT_Face ft_face;
+  FT_UInt size;
+
+  block_input ();
+  size = XINT (AREF (entity, FONT_SIZE_INDEX));
+  if (size == 0)
+    size = pixel_size;
+  font_object = font_build_object (VECSIZE (struct ftcrfont_info),
+                                  Qftcr, entity, size);
+  font_object = ftfont_open2 (f, entity, pixel_size, font_object);
+  if (NILP (font_object)) return Qnil;
+
+  font = XFONT_OBJECT (font_object);
+  font->driver = &ftcrfont_driver;
+  ftcrfont_info = (struct ftcrfont_info *) font;
+  ft_face = ftcrfont_info->ft_size->face;
+  FT_New_Size (ft_face, &ftcrfont_info->ft_size_draw);
+  FT_Activate_Size (ftcrfont_info->ft_size_draw);
+  FT_Set_Pixel_Sizes (ft_face, 0, font->pixel_size);
+  ftcrfont_info->cr_font_face =
+    cairo_ft_font_face_create_for_ft_face (ft_face, 0);
+  ftcrfont_info->metrics = NULL;
+  ftcrfont_info->metrics_nrows = 0;
+  unblock_input ();
+
+  return font_object;
+}
+
+static void
+ftcrfont_close (struct font *font)
+{
+  struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) font;
+  int i;
+
+  block_input ();
+  for (i = 0; i < ftcrfont_info->metrics_nrows; i++)
+    if (ftcrfont_info->metrics[i])
+      xfree (ftcrfont_info->metrics[i]);
+  if (ftcrfont_info->metrics)
+    xfree (ftcrfont_info->metrics);
+  FT_Done_Size (ftcrfont_info->ft_size_draw);
+  cairo_font_face_destroy (ftcrfont_info->cr_font_face);
+  unblock_input ();
+
+  ftfont_driver.close (font);
+}
+
+static void
+ftcrfont_text_extents (struct font *font,
+                       unsigned *code,
+                       int nglyphs,
+                       struct font_metrics *metrics)
+{
+  int width, i;
+
+  block_input ();
+  width = ftcrfont_glyph_extents (font, code[0], metrics);
+  for (i = 1; i < nglyphs; i++)
+    {
+      struct font_metrics m;
+      int w = ftcrfont_glyph_extents (font, code[i], metrics ? &m : NULL);
+
+      if (metrics)
+       {
+         if (width + m.lbearing < metrics->lbearing)
+           metrics->lbearing = width + m.lbearing;
+         if (width + m.rbearing > metrics->rbearing)
+           metrics->rbearing = width + m.rbearing;
+         if (m.ascent > metrics->ascent)
+           metrics->ascent = m.ascent;
+         if (m.descent > metrics->descent)
+           metrics->descent = m.descent;
+       }
+      width += w;
+    }
+  unblock_input ();
+
+  if (metrics)
+    metrics->width = width;
+}
+
+static int
+ftcrfont_draw (struct glyph_string *s,
+               int from, int to, int x, int y, bool with_background)
+{
+  struct frame *f = s->f;
+  struct face *face = s->face;
+  struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) s->font;
+  cairo_t *cr;
+  cairo_glyph_t *glyphs;
+  cairo_surface_t *surface;
+  int len = to - from;
+  int i;
+
+  block_input ();
+
+  cr = x_begin_cr_clip (f, s->gc);
+
+  if (with_background)
+    {
+      x_set_cr_source_with_gc_background (f, s->gc);
+      cairo_rectangle (cr, x, y - FONT_BASE (face->font),
+                      s->width, FONT_HEIGHT (face->font));
+      cairo_fill (cr);
+    }
+
+  glyphs = alloca (sizeof (cairo_glyph_t) * len);
+  for (i = 0; i < len; i++)
+    {
+      unsigned code = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
+                      | XCHAR2B_BYTE2 (s->char2b + from + i));
+
+      glyphs[i].index = code;
+      glyphs[i].x = x;
+      glyphs[i].y = y;
+      x += (s->padding_p ? 1 : ftcrfont_glyph_extents (s->font, code, NULL));
+    }
+
+  x_set_cr_source_with_gc_foreground (f, s->gc);
+  cairo_set_font_face (cr, ftcrfont_info->cr_font_face);
+  cairo_set_font_size (cr, s->font->pixel_size);
+  /* cairo_set_font_matrix */
+  /* cairo_set_font_options */
+
+  FT_Activate_Size (ftcrfont_info->ft_size_draw);
+  cairo_show_glyphs (cr, glyphs, len);
+  surface = cairo_get_target (cr);
+  if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_XLIB)
+    cairo_surface_flush (surface);
+
+  x_end_cr_clip (f);
+
+  unblock_input ();
+
+  return len;
+}
+
+
+
+void
+syms_of_ftcrfont (void)
+{
+  if (ftfont_info_size != offsetof (struct ftcrfont_info, cr_font_face))
+    abort ();
+
+  DEFSYM (Qftcr, "ftcr");
+
+  ftcrfont_driver = ftfont_driver;
+  ftcrfont_driver.type = Qftcr;
+  ftcrfont_driver.list = ftcrfont_list;
+  ftcrfont_driver.match = ftcrfont_match;
+  ftcrfont_driver.open = ftcrfont_open;
+  ftcrfont_driver.close = ftcrfont_close;
+  ftcrfont_driver.text_extents = ftcrfont_text_extents;
+  ftcrfont_driver.draw = ftcrfont_draw;
+  register_font_driver (&ftcrfont_driver, NULL);
+}
diff --git a/src/ftfont.c b/src/ftfont.c
index adf1888..75d59c1 100644
--- a/src/ftfont.c
+++ b/src/ftfont.c
@@ -67,6 +67,8 @@ struct ftfont_info
   FT_Matrix matrix;
 };
 
+size_t ftfont_info_size = sizeof (struct ftfont_info);
+
 enum ftfont_cache_for
   {
     FTFONT_CACHE_FOR_FACE,
@@ -1161,8 +1163,11 @@ ftfont_list_family (struct frame *f)
 }
 
 
-static Lisp_Object
-ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
+Lisp_Object
+ftfont_open2 (struct frame *f,
+              Lisp_Object entity,
+              int pixel_size,
+              Lisp_Object font_object)
 {
   struct ftfont_info *ftfont_info;
   struct font *font;
@@ -1170,7 +1175,7 @@ ftfont_open (struct frame *f, Lisp_Object entity, int 
pixel_size)
   FT_Face ft_face;
   FT_Size ft_size;
   FT_UInt size;
-  Lisp_Object val, filename, idx, cache, font_object;
+  Lisp_Object val, filename, idx, cache;
   bool scalable;
   int spacing;
   int i;
@@ -1210,8 +1215,6 @@ ftfont_open (struct frame *f, Lisp_Object entity, int 
pixel_size)
       return Qnil;
     }
 
-  font_object = font_build_object (VECSIZE (struct ftfont_info),
-                                  Qfreetype, entity, size);
   ASET (font_object, FONT_FILE_INDEX, filename);
   font = XFONT_OBJECT (font_object);
   ftfont_info = (struct ftfont_info *) font;
@@ -1294,6 +1297,19 @@ ftfont_open (struct frame *f, Lisp_Object entity, int 
pixel_size)
   return font_object;
 }
 
+static Lisp_Object
+ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
+{
+  Lisp_Object font_object;
+  FT_UInt size;
+  size = XINT (AREF (entity, FONT_SIZE_INDEX));
+  if (size == 0)
+    size = pixel_size;
+  font_object = font_build_object (VECSIZE (struct ftfont_info),
+                                  Qfreetype, entity, size);
+  return ftfont_open2 (f, entity, pixel_size, font_object);
+}
+
 static void
 ftfont_close (struct font *font)
 {
diff --git a/src/ftfont.h b/src/ftfont.h
index 210b634..0cfa0ae 100644
--- a/src/ftfont.h
+++ b/src/ftfont.h
@@ -37,6 +37,11 @@ along with GNU Emacs.  If not, see 
<http://www.gnu.org/licenses/>.  */
 #endif /* HAVE_LIBOTF */
 
 extern FcCharSet *ftfont_get_fc_charset (Lisp_Object);
+extern Lisp_Object ftfont_open2 (struct frame *f,
+                                 Lisp_Object entity,
+                                 int pixel_size,
+                                 Lisp_Object font_object);
+extern size_t ftfont_info_size;
 
 #endif /* EMACS_FTFONT_H */
 
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 6f17078..f111ea8 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -845,22 +845,23 @@ xg_clear_under_internal_border (struct frame *f)
 {
   if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
     {
+#ifndef USE_CAIRO
       GtkWidget *wfixed = f->output_data.x->edit_widget;
 
       gtk_widget_queue_draw (wfixed);
       gdk_window_process_all_updates ();
-
-      x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0, 0,
+#endif
+      x_clear_area (f, 0, 0,
                    FRAME_PIXEL_WIDTH (f), FRAME_INTERNAL_BORDER_WIDTH (f));
 
-      x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0, 0,
+      x_clear_area (f, 0, 0,
                    FRAME_INTERNAL_BORDER_WIDTH (f), FRAME_PIXEL_HEIGHT (f));
 
-      x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0,
+      x_clear_area (f, 0,
                    FRAME_PIXEL_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f),
                    FRAME_PIXEL_WIDTH (f), FRAME_INTERNAL_BORDER_WIDTH (f));
 
-      x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+      x_clear_area (f,
                    FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f),
                    0, FRAME_INTERNAL_BORDER_WIDTH (f), FRAME_PIXEL_HEIGHT (f));
     }
@@ -2125,12 +2126,18 @@ xg_get_font (struct frame *f, const char *default_name)
          PangoWeight weight = pango_font_description_get_weight (desc);
          PangoStyle  style  = pango_font_description_get_style (desc);
 
+#ifdef USE_CAIRO
+#define FONT_TYPE_WANTED (Qftcr)
+#else
+#define FONT_TYPE_WANTED (Qxft)
+#endif
          font = CALLN (Ffont_spec,
                        QCname, build_string (name),
                        QCsize, make_float (pango_units_to_double (size)),
                        QCweight, XG_WEIGHT_TO_SYMBOL (weight),
                        QCslant, XG_STYLE_TO_SYMBOL (style),
-                       QCtype, Qxft);
+                       QCtype,
+                        FONT_TYPE_WANTED);
 
          pango_font_description_free (desc);
          dupstring (&x_last_font_name, name);
@@ -3784,13 +3791,15 @@ xg_update_scrollbar_pos (struct frame *f,
           gtk_widget_show_all (wparent);
           gtk_widget_set_size_request (wscroll, width, height);
         }
+#ifndef USE_CAIRO
       gtk_widget_queue_draw (wfixed);
       gdk_window_process_all_updates ();
+#endif
       if (oldx != -1 && oldw > 0 && oldh > 0)
        /* Clear under old scroll bar position.  This must be done after
           the gtk_widget_queue_draw and gdk_window_process_all_updates
           above.  */
-       x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+       x_clear_area (f,
                      oldx, oldy, oldw, oldh);
 
       /* GTK does not redraw until the main loop is entered again, but
@@ -3856,7 +3865,7 @@ xg_update_horizontal_scrollbar_pos (struct frame *f,
        /* Clear under old scroll bar position.  This must be done after
           the gtk_widget_queue_draw and gdk_window_process_all_updates
           above.  */
-       x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+       x_clear_area (f,
                      oldx, oldy, oldw, oldh);
 
       /* GTK does not redraw until the main loop is entered again, but
@@ -4033,6 +4042,112 @@ xg_event_is_for_scrollbar (struct frame *f, const 
XEvent *event)
   return retval;
 }
 
+
+/***********************************************************************
+                              Printing
+ ***********************************************************************/
+#ifdef USE_CAIRO
+static GtkPrintSettings *print_settings = NULL;
+static GtkPageSetup *page_setup = NULL;
+
+void
+xg_page_setup_dialog ()
+{
+  GtkPageSetup *new_page_setup = NULL;
+
+  if (print_settings == NULL)
+    print_settings = gtk_print_settings_new ();
+  new_page_setup = gtk_print_run_page_setup_dialog (NULL, page_setup,
+                                                   print_settings);
+  if (page_setup)
+    g_object_unref (page_setup);
+  page_setup = new_page_setup;
+}
+
+Lisp_Object
+xg_get_page_setup ()
+{
+  Lisp_Object result, orientation_symbol;
+  GtkPageOrientation orientation;
+
+  if (page_setup == NULL)
+    page_setup = gtk_page_setup_new ();
+  result = list4 (Fcons (Qleft_margin,
+                        make_float (gtk_page_setup_get_left_margin (page_setup,
+                                                                    
GTK_UNIT_POINTS))),
+                 Fcons (Qright_margin,
+                        make_float (gtk_page_setup_get_right_margin 
(page_setup,
+                                                                     
GTK_UNIT_POINTS))),
+                 Fcons (Qtop_margin,
+                        make_float (gtk_page_setup_get_top_margin (page_setup,
+                                                                   
GTK_UNIT_POINTS))),
+                 Fcons (Qbottom_margin,
+                        make_float (gtk_page_setup_get_bottom_margin 
(page_setup,
+                                                                      
GTK_UNIT_POINTS))));
+  result = Fcons (Fcons (Qheight,
+                        make_float (gtk_page_setup_get_page_height (page_setup,
+                                                                    
GTK_UNIT_POINTS))),
+                 result);
+  result = Fcons (Fcons (Qwidth,
+                        make_float (gtk_page_setup_get_page_width (page_setup,
+                                                                   
GTK_UNIT_POINTS))),
+                 result);
+  orientation = gtk_page_setup_get_orientation (page_setup);
+  if (orientation == GTK_PAGE_ORIENTATION_PORTRAIT)
+    orientation_symbol = Qportrait;
+  else if (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE)
+    orientation_symbol = Qlandscape;
+  else if (orientation == GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT)
+    orientation_symbol = Qreverse_portrait;
+  else if (orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE)
+    orientation_symbol = Qreverse_landscape;
+  result = Fcons (Fcons (Qorientation, orientation_symbol), result);
+
+  return result;
+}
+
+static void
+draw_page (operation, context, page_nr, user_data)
+     GtkPrintOperation *operation;
+     GtkPrintContext *context;
+     gint page_nr;
+     gpointer user_data;
+{
+  Lisp_Object frames = *((Lisp_Object *) user_data);
+  struct frame *f = XFRAME (Fnth (make_number (page_nr), frames));
+  cairo_t *cr = gtk_print_context_get_cairo_context (context);
+
+  x_cr_draw_frame (cr, f);
+}
+
+void
+xg_print_frames_dialog (frames)
+     Lisp_Object frames;
+{
+  GtkPrintOperation *print;
+  GtkPrintOperationResult res;
+
+  print = gtk_print_operation_new ();
+  if (print_settings != NULL)
+    gtk_print_operation_set_print_settings (print, print_settings);
+  if (page_setup != NULL)
+    gtk_print_operation_set_default_page_setup (print, page_setup);
+  gtk_print_operation_set_n_pages (print, XINT (Flength (frames)));
+  g_signal_connect (print, "draw-page", G_CALLBACK (draw_page), &frames);
+  res = gtk_print_operation_run (print, 
GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
+                                 NULL, NULL);
+  if (res == GTK_PRINT_OPERATION_RESULT_APPLY)
+    {
+      if (print_settings != NULL)
+        g_object_unref (print_settings);
+      print_settings =
+       g_object_ref (gtk_print_operation_get_print_settings (print));
+    }
+  g_object_unref (print);
+}
+
+#endif /* USE_CAIRO */
+
 
 
 /***********************************************************************
diff --git a/src/gtkutil.h b/src/gtkutil.h
index 0ac49ca..34338db 100644
--- a/src/gtkutil.h
+++ b/src/gtkutil.h
@@ -180,6 +180,12 @@ extern bool xg_prepare_tooltip (struct frame *f,
 extern void xg_show_tooltip (struct frame *f, int root_x, int root_y);
 extern bool xg_hide_tooltip (struct frame *f);
 
+#ifdef USE_CAIRO
+extern void xg_page_setup_dialog (void);
+extern Lisp_Object xg_get_page_setup (void);
+extern void xg_print_frames_dialog (Lisp_Object);
+#endif
+
 /* Mark all callback data that are Lisp_object:s during GC.  */
 extern void xg_mark_data (void);
 
diff --git a/src/image.c b/src/image.c
index df299bb..09d0687 100644
--- a/src/image.c
+++ b/src/image.c
@@ -1299,6 +1299,14 @@ static void
 x_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);
+      unblock_input ();
+      return;
+    }
+#endif
   x_clear_image_1 (f, img,
                   CLEAR_IMAGE_PIXMAP | CLEAR_IMAGE_MASK | CLEAR_IMAGE_COLORS);
   unblock_input ();
@@ -5403,7 +5411,7 @@ pbm_load (struct frame *f, struct image *img)
                                 PNG
  ***********************************************************************/
 
-#if defined (HAVE_PNG) || defined (HAVE_NS)
+#if defined (HAVE_PNG) || defined (HAVE_NS) || defined (USE_CAIRO)
 
 /* Function prototypes.  */
 
@@ -5477,10 +5485,10 @@ png_image_p (Lisp_Object object)
   return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
 }
 
-#endif /* HAVE_PNG || HAVE_NS */
+#endif /* HAVE_PNG || HAVE_NS || USE_CAIRO */
 
 
-#if defined HAVE_PNG && !defined HAVE_NS
+#if defined HAVE_PNG && !defined HAVE_NS && !defined USE_CAIRO
 
 # ifdef WINDOWSNT
 /* PNG library details.  */
@@ -6049,7 +6057,44 @@ png_load (struct frame *f, struct image *img)
                         image_spec_value (img->spec, QCdata, NULL));
 }
 
-#endif /* HAVE_NS */
+#elif defined USE_CAIRO
+
+static bool
+png_load (struct frame *f, struct image *img)
+{
+  Lisp_Object file;
+  Lisp_Object specified_file = image_spec_value (img->spec, QCfile, NULL);
+  cairo_surface_t *surface;
+
+  if (! STRINGP (specified_file))
+    {
+      image_error ("Invalid image spec, file missing `%s'", img->spec, Qnil);
+      return false;
+    }
+
+  file = x_find_image_file (specified_file);
+  if (! STRINGP (file))
+    {
+      image_error ("Cannot find image file `%s'", specified_file, Qnil);
+      return false;
+    }
+
+  surface = cairo_image_surface_create_from_png (SSDATA (file));
+  if (! surface)
+    {
+      image_error ("Error creating surface from file `%s'",
+                   specified_file, Qnil);
+      return false;
+    }
+  img->width = cairo_image_surface_get_width (surface);
+  img->height = cairo_image_surface_get_height (surface);
+  img->cr_data = surface;
+  img->pixmap = 0;
+
+  return true;
+}
+
+#endif /* USE_CAIRO */
 
 
 
@@ -9353,7 +9398,7 @@ lookup_image_type (Lisp_Object type)
     return define_image_type (&gif_type);
 #endif
 
-#if defined (HAVE_PNG) || defined (HAVE_NS)
+#if defined (HAVE_PNG) || defined (HAVE_NS) || defined (USE_CAIRO)
   if (EQ (type, Qpng))
     return define_image_type (&png_type);
 #endif
diff --git a/src/xfns.c b/src/xfns.c
index 629ac4b..23af438 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -3052,6 +3052,9 @@ This function is an internal primitive--use `make-frame' 
instead.  */)
       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);
@@ -3060,6 +3063,7 @@ This function is an internal primitive--use `make-frame' 
instead.  */)
 #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);
@@ -5049,6 +5053,9 @@ x_create_tip_frame (struct x_display_info *dpyinfo,
       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
@@ -5057,6 +5064,7 @@ x_create_tip_frame (struct x_display_info *dpyinfo,
   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);
@@ -6140,6 +6148,160 @@ present and mapped to the usual X keysyms.  */)
 
 
 /***********************************************************************
+                              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.  */)
+     (frames, type)
+     Lisp_Object frames, 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'.  */)
+     ()
+{
+  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.  */)
+     ()
+{
+  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.  */)
+     (frames)
+     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 */
+
+
+/***********************************************************************
                            Initialization
  ***********************************************************************/
 
@@ -6195,6 +6357,16 @@ syms_of_xfns (void)
   DEFSYM (Qcancel_timer, "cancel-timer");
   DEFSYM (Qfont_param, "font-parameter");
 
+#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,
@@ -6335,6 +6507,20 @@ When using Gtk+ tooltips, the tooltip face is not used.  
*/);
   }
 #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);
@@ -6385,4 +6571,13 @@ When using Gtk+ tooltips, the tooltip face is not used.  
*/);
 #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 --git a/src/xterm.c b/src/xterm.c
index 0b3efe7..1074862 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -220,6 +220,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 *);
@@ -325,6 +326,555 @@ record_event (char *locus, int type)
 
 #endif
 
+static void x_prepare_for_xlibdraw (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,
+                              unsigned int, unsigned int);
+static void x_draw_rectangle (struct frame *, GC, int, int,
+                              unsigned int, unsigned int);
+static void x_fill_trapezoid_for_relief (struct frame *, GC, int, int,
+                                         unsigned int, unsigned 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 (f, gc, create_if_not_found_p)
+     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 (dpyinfo)
+     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 (f, gc)
+     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 (f)
+     struct frame *f;
+{
+  cairo_restore (FRAME_CR_CONTEXT (f));
+}
+
+void
+x_set_cr_source_with_gc_foreground (f, gc)
+     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 (f, gc)
+     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 (which, bits, h, wd)
+     int which;
+     unsigned short *bits;
+     int h, 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;
+    }
+
+  pattern = cairo_pattern_create_for_surface (surface);
+  cairo_surface_destroy (surface);
+
+  unblock_input ();
+
+  fringe_bmp[which] = pattern;
+}
+
+static void
+x_cr_destroy_fringe_bitmap (which)
+     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,
+                 unsigned int width,
+                 unsigned 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 (cr, f)
+     cairo_t *cr;
+     struct frame *f;
+{
+  int width, height;
+
+  width = FRAME_PIXEL_WIDTH (f);
+  height = FRAME_PIXEL_HEIGHT (f);
+
+  x_prepare_for_xlibdraw (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 (closure, data, length)
+     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 (arg)
+     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 (frames, surface_type)
+     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_prepare_for_xlibdraw (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_prepare_for_xlibdraw (f)
+     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_prepare_for_xlibdraw (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 (f, gc, rectangles, n)
+     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 (f, gc)
+     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 (f, gc, x, y, width, height)
+     struct frame *f;
+     GC gc;
+     int x, y;
+     unsigned int width, 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 (f, gc, x, y, width, height)
+     struct frame *f;
+     GC gc;
+     int x, y;
+     unsigned int width, 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 (f)
+     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 (f, gc, x, y, width, height, top_p)
+     struct frame *f;
+     GC gc;
+     int x, y;
+     unsigned int width, 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_close_path (cr);
+  cairo_fill (cr);
+  x_end_cr_clip (f);
+}
+#endif
 
 
 /* Return the struct x_display_info corresponding to DPY.  */
@@ -452,9 +1002,38 @@ x_set_frame_alpha (struct frame *f)
 static void
 x_update_begin (struct frame *f)
 {
-  /* Nothing to do.  */
-}
+#ifdef USE_CAIRO
+  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.  */
 
@@ -496,8 +1075,12 @@ x_draw_vertical_window_border (struct window *w, int x, 
int y0, int y1)
     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)  */
@@ -612,6 +1195,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));
@@ -638,18 +1258,16 @@ x_clear_under_internal_border (struct frame *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 ();
     }
 }
@@ -691,11 +1309,8 @@ x_after_update_window_line (struct window *w, struct 
glyph_row *desired_row)
        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 ();
       }
   }
@@ -725,13 +1340,29 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row 
*row, struct draw_fring
       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;
@@ -776,8 +1407,9 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row 
*row, struct draw_fring
          XFreePixmap (display, clipmask);
        }
     }
+#endif  /* not USE_CAIRO */
 
-  XSetClipMask (display, gc, None);
+  x_reset_clip_rectangles (f, gc);
 }
 
 /***********************************************************************
@@ -985,7 +1617,7 @@ x_set_glyph_string_clipping (struct glyph_string *s)
   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;
 }
 
@@ -1005,7 +1637,7 @@ x_set_glyph_string_clipping_exactly (struct glyph_string 
*src, struct glyph_stri
   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);
 }
 
 
@@ -1057,7 +1689,7 @@ x_clear_glyph_string_rect (struct glyph_string *s, int x, 
int y, int w, int h)
   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);
 }
 
@@ -1081,7 +1713,7 @@ x_draw_glyph_string_background (struct glyph_string *s, 
bool force_p)
        {
          /* 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);
@@ -1124,7 +1756,7 @@ x_draw_glyph_string_foreground (struct glyph_string *s)
       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;
@@ -1176,7 +1808,7 @@ x_draw_composite_glyph_string_foreground (struct 
glyph_string *s)
   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)
@@ -1310,7 +1942,7 @@ x_draw_glyphless_glyph_string_foreground (struct 
glyph_string *s)
                                 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);
@@ -1882,6 +2514,52 @@ 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;
+
+  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 (right_p)
+    x_fill_rectangle (f, bottom_right_gc, right_x + 1 - width, top_y,
+                     width, bottom_y + 1 - top_y);
+  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);
+    }
+
+  x_set_clip_rectangles (f, top_left_gc, clip_rect, 1);
+  x_set_clip_rectangles (f, bottom_right_gc, clip_rect, 1);
+#else
   Display *dpy = FRAME_X_DISPLAY (f);
   Window window = FRAME_X_WINDOW (f);
   int i;
@@ -1970,7 +2648,9 @@ x_draw_relief_rect (struct frame *f,
                   right_x - i, bottom_y + 1 - (i + 1) * bot_p);
     }
 
-  XSetClipMask (dpy, gc, None);
+  x_reset_clip_rectangles (f, gc);
+
+#endif
 }
 
 
@@ -1990,28 +2670,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);
 }
 
 
@@ -2142,7 +2822,7 @@ x_draw_image_foreground (struct glyph_string *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);
@@ -2151,7 +2831,7 @@ x_draw_image_foreground (struct glyph_string *s)
     }
   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);
 }
 
@@ -2290,7 +2970,7 @@ x_draw_image_foreground_1 (struct glyph_string *s, Pixmap 
pixmap)
          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);
            }
@@ -2298,7 +2978,7 @@ x_draw_image_foreground_1 (struct glyph_string *s, Pixmap 
pixmap)
     }
   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);
 }
 
@@ -2313,7 +2993,7 @@ x_draw_glyph_string_bg_rect (struct glyph_string *s, int 
x, int y, int w, int h)
     {
       /* 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
@@ -2422,7 +3102,22 @@ x_draw_image_glyph_string (struct glyph_string *s)
     }
 
   /* Draw the foreground.  */
-  if (pixmap != None)
+  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 if (pixmap != None)
     {
       x_draw_image_foreground_1 (s, pixmap);
       x_set_glyph_string_clipping (s);
@@ -2505,13 +3200,13 @@ x_draw_stretch_glyph_string (struct glyph_string *s)
            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
@@ -2519,7 +3214,7 @@ x_draw_stretch_glyph_string (struct glyph_string *s)
              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);
            }
 
@@ -2778,14 +3473,14 @@ x_draw_glyph_string (struct glyph_string *s)
               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);
                 }
@@ -2797,14 +3492,14 @@ x_draw_glyph_string (struct glyph_string *s)
          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);
            }
@@ -2817,14 +3512,14 @@ x_draw_glyph_string (struct glyph_string *s)
          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);
            }
@@ -2853,7 +3548,7 @@ x_draw_glyph_string (struct glyph_string *s)
                  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;
              }
@@ -2878,7 +3573,7 @@ x_draw_glyph_string (struct glyph_string *s)
                  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;
@@ -2887,7 +3582,7 @@ x_draw_glyph_string (struct glyph_string *s)
     }
 
   /* Reset clipping.  */
-  XSetClipMask (s->display, s->gc, None);
+  x_reset_clip_rectangles (s->f, s->gc);
   s->num_clips = 0;
 }
 
@@ -2896,6 +3591,7 @@ x_draw_glyph_string (struct glyph_string *s)
 static void
 x_shift_glyphs_for_insert (struct frame *f, int x, int y, int width, int 
height, int shift_by)
 {
+  x_prepare_for_xlibdraw (f);
   XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
             f->output_data.x->normal_gc,
             x, y, width, height,
@@ -2915,11 +3611,35 @@ x_delete_glyphs (struct frame *f, register int n)
 /* 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 (f, x, y, width, height)
+     struct frame *f;
+     int x, y;
+     int width, 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
 }
 
 
@@ -2934,7 +3654,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.  */
@@ -3240,12 +3960,16 @@ x_scroll_run (struct window *w, struct run *run)
   /* 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 ();
 }
@@ -4154,7 +4878,7 @@ XTmouse_position (struct frame **fp, int insist, 
Lisp_Object *bar_window,
            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);
@@ -4248,7 +4972,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.  */
@@ -5505,8 +6229,7 @@ x_scroll_bar_create (struct window *w, int top, int left,
        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.  */
@@ -5638,7 +6361,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int 
start, int end,
     /* 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);
@@ -5649,7 +6372,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int 
start, int end,
                      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,
@@ -5663,7 +6386,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int 
start, int end,
     /* 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);
@@ -5730,8 +6453,7 @@ XTset_vertical_scroll_bar (struct window *w, int portion, 
int whole, int positio
       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 ();
        }
 
@@ -5763,8 +6485,7 @@ XTset_vertical_scroll_bar (struct window *w, int portion, 
int whole, int positio
          /* 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));
@@ -5850,8 +6571,7 @@ XTset_horizontal_scroll_bar (struct window *w, int 
portion, int whole, int posit
 
          /* 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 ();
        }
 
@@ -5882,7 +6602,7 @@ XTset_horizontal_scroll_bar (struct window *w, int 
portion, int whole, int posit
          /* 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
@@ -6128,7 +6848,7 @@ x_scroll_bar_expose (struct scroll_bar *bar, const XEvent 
*event)
                    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);
 
@@ -6912,11 +7632,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
             }
           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
@@ -7530,6 +8249,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
     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)
@@ -7537,6 +8259,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
         {
           xg_frame_resized (f, event->xconfigure.width,
                             event->xconfigure.height);
+          x_cr_destroy_surface (f);
           f = 0;
         }
 #endif
@@ -7946,7 +8669,7 @@ x_clip_to_row (struct window *w, struct glyph_row *row,
   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);
 }
 
 
@@ -7995,8 +8718,8 @@ x_draw_hollow_cursor (struct window *w, struct glyph_row 
*row)
     }
   /* 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);
 }
 
 
@@ -8074,7 +8797,7 @@ x_draw_bar_cursor (struct window *w, struct glyph_row 
*row, int width, enum text
          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);
        }
@@ -8094,13 +8817,13 @@ x_draw_bar_cursor (struct window *w, struct glyph_row 
*row, int width, enum text
          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);
     }
 }
 
@@ -8122,7 +8845,7 @@ x_define_frame_cursor (struct frame *f, Cursor cursor)
 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))
@@ -10235,6 +10958,7 @@ x_free_frame_resources (struct frame *f)
        free_frame_xic (f);
 #endif
 
+      x_prepare_for_xlibdraw (f);
 #ifdef USE_X_TOOLKIT
       if (f->output_data.x->widget)
        {
@@ -11312,6 +12036,10 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
     x_session_initialize (dpyinfo);
 #endif
 
+#ifdef USE_CAIRO
+  x_extension_initialize (dpyinfo);
+#endif
+
   unblock_input ();
 
   return dpyinfo;
@@ -11423,8 +12151,13 @@ static struct redisplay_interface 
x_redisplay_interface =
     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,
@@ -11602,6 +12335,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);
diff --git a/src/xterm.h b/src/xterm.h
index e597227..eb8eaae 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -70,6 +70,19 @@ typedef GtkWidget *xt_or_gtk_widget;
 #define USE_GTK_TOOLTIP
 #endif
 
+#ifdef USE_CAIRO
+#include <cairo-xlib.h>
+#ifdef CAIRO_HAS_PDF_SURFACE
+#include <cairo-pdf.h>
+#endif
+#ifdef CAIRO_HAS_PS_SURFACE
+#include <cairo-ps.h>
+#endif
+#ifdef CAIRO_HAS_SVG_SURFACE
+#include <cairo-svg.h>
+#endif
+#endif
+
 #ifdef HAVE_X_I18N
 #include <X11/Xlocale.h>
 #endif
@@ -115,6 +128,9 @@ struct xim_inst_t
 
 struct x_bitmap_record
 {
+#ifdef USE_CAIRO
+  void *img;
+#endif
   Pixmap pixmap;
   bool have_mask;
   Pixmap mask;
@@ -124,6 +140,19 @@ struct x_bitmap_record
   int height, width, depth;
 };
 
+#ifdef USE_CAIRO
+struct x_gc_ext_data
+{
+#define MAX_CLIP_RECTS 2
+  /* Number of clipping rectangles.  */
+  int n_clip_rects;
+
+  /* Clipping rectangles.  */
+  XRectangle clip_rects[MAX_CLIP_RECTS];
+};
+#endif
+
+
 /* For each X display, we have a structure that records
    information about it.  */
 
@@ -411,6 +440,10 @@ struct x_display_info
 
   /* SM */
   Atom Xatom_SM_CLIENT_ID;
+
+#ifdef USE_CAIRO
+  XExtCodes *ext_codes;
+#endif
 };
 
 #ifdef HAVE_X_I18N
@@ -645,7 +678,6 @@ struct x_output
   /* The offset we need to add to compensate for type A WMs.  */
   int move_offset_top;
   int move_offset_left;
-};
 
 /* Extreme 'short' and 'long' values suitable for libX11.  */
 #define X_SHRT_MAX 0x7fff
@@ -654,6 +686,14 @@ struct x_output
 #define X_LONG_MIN (-1 - X_LONG_MAX)
 #define X_ULONG_MAX 0xffffffffUL
 
+#ifdef USE_CAIRO
+  /* Cairo drawing context.  */
+  cairo_t *cr_context;
+  /* Cairo surface for double buffering */
+  cairo_surface_t *cr_surface;
+#endif
+};
+
 #define No_Cursor (None)
 
 enum
@@ -1000,7 +1040,8 @@ extern bool x_alloc_lighter_color_for_widget (Widget, 
Display *, Colormap,
                                              double, int);
 #endif
 extern bool x_alloc_nearest_color (struct frame *, Colormap, XColor *);
-extern void x_clear_area (Display *, Window, int, int, int, int);
+extern void x_query_color (struct frame *f, XColor *);
+extern void x_clear_area (struct frame *f, int, int, int, int);
 #if !defined USE_X_TOOLKIT && !defined USE_GTK
 extern void x_mouse_leave (struct x_display_info *);
 #endif
@@ -1009,6 +1050,14 @@ extern void x_mouse_leave (struct x_display_info *);
 extern int x_dispatch_event (XEvent *, Display *);
 #endif
 extern int x_x_to_emacs_modifiers (struct x_display_info *, int);
+#ifdef USE_CAIRO
+extern cairo_t *x_begin_cr_clip (struct frame *, GC);
+extern void x_end_cr_clip (struct frame *);
+extern void x_set_cr_source_with_gc_foreground (struct frame *, GC);
+extern void x_set_cr_source_with_gc_background (struct frame *, GC);
+extern void x_cr_draw_frame (cairo_t *, struct frame *);
+extern Lisp_Object x_cr_export_frames (Lisp_Object, cairo_surface_type_t);
+#endif
 
 INLINE int
 x_display_pixel_height (struct x_display_info *dpyinfo)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]