emacs-diffs
[Top][All Lists]
Advanced

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

[Emacs-diffs] master c03c730 2/2: Merge branch 'cairo'.


From: Jan D.
Subject: [Emacs-diffs] master c03c730 2/2: Merge branch 'cairo'.
Date: Sat, 23 May 2015 10:38:58 +0000

branch: master
commit c03c730481bd2dc7bc857d9b4f1c41eea9bd495e
Merge: 7ac84a2 6aaa489
Author: Jan D <address@hidden>
Commit: Jan D <address@hidden>

    Merge branch 'cairo'.
    
    Main work done by YAMAMOTO Mitsuharu <address@hidden>.
    Small fixes and image work by Jan D. <address@hidden>.
---
 ChangeLog.1       |   21 ++
 configure.ac      |   30 ++-
 lisp/ChangeLog.17 |    6 +
 lisp/version.el   |    7 +-
 lwlib/ChangeLog.1 |    3 +
 lwlib/Makefile.in |    2 +
 src/ChangeLog.13  |  236 +++++++++++++
 src/Makefile.in   |    8 +-
 src/dispextern.h  |    7 +
 src/font.c        |    4 +
 src/font.h        |    4 +
 src/fringe.c      |   24 ++-
 src/ftcrfont.c    |  320 +++++++++++++++++
 src/ftfont.c      |   26 ++-
 src/ftfont.h      |    5 +
 src/gtkutil.c     |  128 +++++++-
 src/gtkutil.h     |    6 +
 src/image.c       |  379 +++++++++++++++++++--
 src/xfns.c        |  193 +++++++++++
 src/xterm.c       |  998 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 src/xterm.h       |   53 +++-
 21 files changed, 2320 insertions(+), 140 deletions(-)

diff --git a/ChangeLog.1 b/ChangeLog.1
index d1b8d0f..565c85b 100644
--- a/ChangeLog.1
+++ b/ChangeLog.1
@@ -1,9 +1,23 @@
+2015-04-11  Jan Djärv  <address@hidden>
+
+       * configure.ac: Allow jpeg with cairo.
+       Allow tiff and gif with cairo.
+
 2015-04-07  Paul Eggert  <address@hidden>
 
        Merge from gnulib
        * lib/stddef.in.h: Update from gnulib, incorporating:
        2015-04-02 stddef: port to pre-C11 GCC on x86
 
+2015-04-05  Jan Djärv  <address@hidden>
+
+       * configure.ac: Allow rsvg with cairo.  Move back HAVE_RSVG.
+
+2015-04-03  Jan Djärv  <address@hidden>
+
+       * configure.ac (HAVE_RSVG): Move after cairo.
+       (USE_CAIRO): Disable rsvg, don't disable Xpm.
+
 2015-04-03  Paul Eggert  <address@hidden>
 
        Port 'configure' to clang 3.5
@@ -108,6 +122,13 @@
        * configure.ac: Set locallisppath to empty for NS self contained,
        unless --enable-loadllisppath was given (Bug#19850).
 
+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 752204c..a9fe095 100644
--- a/configure.ac
+++ b/configure.ac
@@ -330,6 +330,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])
 
@@ -2407,6 +2408,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],
@@ -3075,6 +3077,25 @@ AC_SUBST(LIBOTF_LIBS)
 AC_SUBST(M17N_FLT_CFLAGS)
 AC_SUBST(M17N_FLT_LIBS)
 
+USE_CAIRO=no
+if test "${HAVE_X11}" = "yes"; then
+  if test "${with_cairo}" != "no"; then
+    CAIRO_REQUIRED=1.12.0
+    CAIRO_MODULE="cairo >= $CAIRO_REQUIRED"
+    PKG_CHECK_MODULES(CAIRO, $CAIRO_MODULE, USE_CAIRO=yes, :)
+    if test $USE_CAIRO = yes; then
+      AC_DEFINE(USE_CAIRO, 1, [Define to 1 if using cairo.])
+    else
+      AC_MSG_ERROR([cairo requested but not found.])
+    fi
+
+    CFLAGS="$CFLAGS $CAIRO_CFLAGS"
+    LIBS="$LIBS $CAIRO_LIBS"
+    AC_SUBST(CAIRO_CFLAGS)
+    AC_SUBST(CAIRO_LIBS)
+  fi
+fi
+
 ### Use -lXpm if available, unless '--with-xpm=no'.
 ### mingw32 doesn't use -lXpm, since it loads the library dynamically.
 ### In the Cygwin-w32 build, we need to use /usr/include/noX/X11/xpm.h
@@ -4009,8 +4030,8 @@ OLDCFLAGS="$CFLAGS"
 OLDLIBS="$LIBS"
 CFLAGS="$CFLAGS $GTK_CFLAGS $RSVG_CFLAGS $DBUS_CFLAGS $SETTINGS_CFLAGS"
 LIBS="$LIBS $GTK_LIBS $RSVG_LIBS $DBUS_LIBS $SETTINGS_LIBS"
-CFLAGS="$CFLAGS $GFILENOTIFY_CFLAGS"
-LIBS="$LIBS $GFILENOTIFY_LIBS"
+CFLAGS="$CFLAGS $GFILENOTIFY_CFLAGS $CAIRO_CFLAGS"
+LIBS="$LIBS $GFILENOTIFY_LIBS $CAIRO_LIBS"
 AC_MSG_CHECKING([whether GLib is linked in])
 AC_LINK_IFELSE([AC_LANG_PROGRAM(
        [[#include <glib.h>
@@ -4776,7 +4797,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"
@@ -5142,6 +5165,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.17 b/lisp/ChangeLog.17
index a40f8f3..2408ad2 100644
--- a/lisp/ChangeLog.17
+++ b/lisp/ChangeLog.17
@@ -1750,6 +1750,12 @@
 
 2015-02-11  Martin Rudalics  <address@hidden>
 
+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):
        Rename frame parameter `maximized' to `fullscreen-restore'.
        Restore fullwidth/-height after fullboth state.  Update doc-strings.
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/lwlib/ChangeLog.1 b/lwlib/ChangeLog.1
index e5dfed2..2e317dd 100644
--- a/lwlib/ChangeLog.1
+++ b/lwlib/ChangeLog.1
@@ -1,3 +1,6 @@
+2015-04-03  Jan Djärv  <address@hidden>
+
+       * Makefile.in (CAIRO_CFLAGS): Add.
 2015-03-18  Stefan Monnier  <address@hidden>
 
        * xlwmenu.c (pop_up_menu): Remove debugging code.
diff --git a/lwlib/Makefile.in b/lwlib/Makefile.in
index 2fd5959..cbc747c 100644
--- a/lwlib/Makefile.in
+++ b/lwlib/Makefile.in
@@ -33,6 +33,7 @@ address@hidden@
 PROFILING_CFLAGS = @PROFILING_CFLAGS@
 WARN_CFLAGS = `echo @WARN_CFLAGS@ | sed 's/ -Wwrite-strings//'`
 WERROR_CFLAGS = @WERROR_CFLAGS@
+CAIRO_CFLAGS= @CAIRO_CFLAGS@
 
 address@hidden@
 address@hidden@
@@ -88,6 +89,7 @@ endif
 ALL_CFLAGS= $(C_SWITCH_SYSTEM) $(C_SWITCH_X_SITE) \
   $(C_SWITCH_MACHINE) $(DEPFLAGS) \
   $(WARN_CFLAGS) $(WERROR_CFLAGS) $(PROFILING_CFLAGS) $(CFLAGS) \
+  $(CAIRO_CFLAGS) \
   -Demacs -I../src \
   -I$(srcdir) -I$(srcdir)/../src -I../lib -I$(srcdir)/../lib
 
diff --git a/src/ChangeLog.13 b/src/ChangeLog.13
index 328f798..8057b6e 100644
--- a/src/ChangeLog.13
+++ b/src/ChangeLog.13
@@ -1,9 +1,51 @@
+2015-04-26  Jan Djärv  <address@hidden>
+
+       * image.c (xcolor_to_argb32): New function.
+       (get_spec_bg_or_alpha_as_argb): Call xcolor_to_argb32.
+       (pbm_load, png_load_body, jpeg_load_body, gif_load): Only use
+       XImagePtr if ! USE_CAIRO.
+       (pbm_load): Add cairo support.
+
+2015-04-12  Jan Djärv  <address@hidden>
+
+       * xterm.c (x_draw_image_glyph_string): Added missing USE_CAIRO.
+       (x_free_cr_resources): Renamed from x_prepare_for_xlibdraw.
+       (x_cr_draw_frame, x_cr_export_frames, x_shift_glyphs_for_insert)
+       (x_free_frame_resources): Rename x_prepare_for_xlibdraw to
+       x_free_cr_resources.
+
+       * image.c (get_spec_bg_or_alpha_as_argb)
+       (create_cairo_image_surface): New functions when USE_CAIRO.
+       (xpm_load): Call the above functions.  Handle XPM without mask
+       when USE_CAIRO.
+       (png_load_body): Handle USE_CAIRO case.
+       (png_load): Remove USE_CAIRO specific fuction, modify png_load_body
+       instead.
+       (jpeg_load_body): Call create_cairo_image_surface.
+       (gif_load, svg_load_image): Handle specified background, call
+       create_cairo_image_surface.
+
+2015-04-11  Jan Djärv  <address@hidden>
+
+       * image.c (jpeg_load_body): Create cairo image surface if USE_CAIRO.
+       (tiff_load): Create cairo image surface if USE_CAIRO.
+       (gif_load): Ditto.
+
 2015-04-06  Koichi Arakawa  <address@hidden>  (tiny change)
 
        * w32proc.c (w32_executable_type): Look for the DLL name in the
        correct section.  This avoids segfaults with some executables.
        (Bug#20264)
 
+2015-04-05  Jan Djärv  <address@hidden>
+
+       * image.c: #undef COLOR_TABLE_SUPPORT when USE_CAIRO.
+       (x_clear_image): Free cr_data and cr_data2 if set.
+       (xpm_load): Assign data to cr_data2.
+       (svg_load_image): Convert from GdkPixbuf to CAIRO_FORMAT_ARGB32.
+
+       * dispextern.h (struct image): add cr_data2 if cairo.
+
 2015-04-04  Jan Djärv  <address@hidden>
 
        * xselect.c (x_reply_selection_request)
@@ -15,8 +57,17 @@
 
 2015-04-03  Jan Djärv  <address@hidden>
 
+       * image.c (prepare_image_for_display): Don't load if USE_CAIRO.
+       (x_clear_image): If USE_CAIRO, also free possible img->ximg->obdata and
+       don't return early.
+       (ALLOC_XPM_COLORS): Don't define when USE_CAIRO.
+       (xpm_load): Convert simple Xpms (32 bit ZPixmap) to CAIRO_FORMAT_ARGB32
+       and create a surface.
+
        * xterm.c (handle_one_xevent): Always redraw tool tips on
        MapNotify.  Update tool tip frame sizes on ConfigureNotify.
+       (x_update_begin): Don't create any surface for non-visible
+       tip frames, the geometry may be wrong.
 
 2015-03-31  Eli Zaretskii  <address@hidden>
 
@@ -559,6 +610,191 @@
        DEFINE_LISP_SYMBOL_BEGIN / DEFINE_LISP_SYMBOL_END.  All uses changed.
        (DEFINE_NONNIL_Q_SYMBOL_MACROS): New macro, defaulting to true.
 
+2015-02-19  YAMAMOTO Mitsuharu  <address@hidden>
+
+       * ftcrfont.c (ftcrfont_draw): Don't flush when drawing to screen.
+
+2015-02-17  YAMAMOTO Mitsuharu  <address@hidden>
+
+       * xterm.c [USE_CAIRO]: Include math.h.
+       (enum corners) [USE_CAIRO]: New enum.
+       (x_erase_corners_for_relief) [USE_CAIRO]: New function.
+       (x_draw_relief_rect) [USE_CAIRO]: Use it.  If box width is larger
+       than 1, draw the outermost line using the black relief.
+
+2015-02-16  YAMAMOTO Mitsuharu  <address@hidden>
+
+       * gtkutil.c (xg_page_setup_dialog, xg_get_page_setup, draw_page)
+       (xg_print_frames_dialog): Modernize k&r declarations.
+
+       * xfns.c (Fx_export_frames, Fx_page_setup_dialog, Fx_get_page_setup)
+       (Fx_print_frames_dialog): Modernize k&r declarations.
+
+       * xterm.c (x_draw_window_divider): Use x_fill_rectangle instead of
+       XFillRectangle.
+       (x_draw_horizontal_wave) [USE_CAIRO]: New function.
+       (x_draw_underwave) [USE_CAIRO]: Use it.
+       (x_gc_get_ext_data, x_extension_initialize, 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_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)
+       (x_clear_area): Modernize k&r declarations.
+       (x_cr_draw_image, x_fill_rectangle, x_draw_rectangle)
+       (x_fill_trapezoid_for_relief): Use int instead of unsigned int for
+       width and height args.
+       (x_draw_stretch_glyph_string): Call x_reset_clip_rectangles instead
+       of XSetClipMask.
+       (x_draw_relief_rect) [USE_CAIRO]: Reset clipping.
+       (x_fill_trapezoid_for_relief): Remove unnecessary cairo_close_path.
+
+2015-02-14  YAMAMOTO Mitsuharu  <address@hidden>
+
+       * fringe.c (init_fringe_bitmap) [USE_CAIRO]: Adjust bitmap data for
+       cairo image surface.
+
+       * xterm.c (x_cr_define_fringe_bitmap): Call cairo_surface_mark_dirty.
+
+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 57417fc..d0df326 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@
 
@@ -350,7 +354,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)
 
@@ -456,7 +460,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 329572e..d9d4d23 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -2941,6 +2941,10 @@ struct image
   /* Pixmaps of the image.  */
   Pixmap pixmap, mask;
 
+#ifdef USE_CAIRO
+  void *cr_data;
+  void *cr_data2;
+#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
@@ -3302,6 +3306,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 2ade45f..2ccfd15 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..fcc5207 100644
--- a/src/fringe.c
+++ b/src/fringe.c
@@ -1405,6 +1405,21 @@ init_fringe_bitmap (int which, struct fringe_bitmap *fb, 
int once_p)
       unsigned short *bits = fb->bits;
       int j;
 
+#ifdef USE_CAIRO
+      for (j = 0; j < fb->height; j++)
+       {
+         unsigned short b = *bits;
+#ifdef WORDS_BIGENDIAN
+         *bits++ = (b << (16 - fb->width));
+#else
+         b = (unsigned short)((swap_nibble[b & 0xf] << 12)
+                              | (swap_nibble[(b>>4) & 0xf] << 8)
+                              | (swap_nibble[(b>>8) & 0xf] << 4)
+                              | (swap_nibble[(b>>12) & 0xf]));
+         *bits++ = (b >> (16 - fb->width));
+#endif
+       }
+#else  /* not USE_CAIRO */
       if (fb->width <= 8)
        {
          unsigned char *cbits = (unsigned char *)fb->bits;
@@ -1433,6 +1448,7 @@ init_fringe_bitmap (int which, struct fringe_bitmap *fb, 
int once_p)
              *bits++ = b;
            }
        }
+#endif /* not USE_CAIRO */
 #endif /* HAVE_X_WINDOWS */
 
     }
@@ -1731,10 +1747,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 +1767,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..fc4e6da
--- /dev/null
+++ b/src/ftcrfont.c
@@ -0,0 +1,320 @@
+/* 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;
+  cairo_surface_type_t surface_type;
+  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);
+  /* XXX: It used to be necessary to flush when exporting.  It might
+     be the case that this is no longer necessary.  */
+  surface_type = cairo_surface_get_type (surface);
+  if (surface_type != CAIRO_SURFACE_TYPE_XLIB
+      && (surface_type != CAIRO_SURFACE_TYPE_IMAGE
+         || cairo_image_surface_get_format (surface) != CAIRO_FORMAT_ARGB32))
+    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 26740c2..f19933c 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 61bc5ee..a4b4331 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -847,22 +847,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));
     }
@@ -2141,12 +2142,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);
@@ -3806,8 +3813,10 @@ 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
@@ -3815,8 +3824,7 @@ xg_update_scrollbar_pos (struct frame *f,
              above.  */
          oldw += (scale - 1) * oldw;
          oldx -= (scale - 1) * oldw;
-          x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                        oldx, oldy, oldw, oldh);
+          x_clear_area (f, oldx, oldy, oldw, oldh);
         }
 
       /* GTK does not redraw until the main loop is entered again, but
@@ -3882,7 +3890,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
@@ -4059,6 +4067,108 @@ 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 (void)
+{
+  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 (void)
+{
+  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 (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 (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 d7f48bd..87029bf 100644
--- a/src/image.c
+++ b/src/image.c
@@ -88,6 +88,10 @@ typedef struct w32_bitmap_record Bitmap_Record;
 
 #endif /* HAVE_NTGUI */
 
+#ifdef USE_CAIRO
+#undef COLOR_TABLE_SUPPORT
+#endif
+
 #ifdef HAVE_NS
 #undef COLOR_TABLE_SUPPORT
 
@@ -514,7 +518,6 @@ x_create_bitmap_mask (struct frame *f, ptrdiff_t id)
 
 #endif /* HAVE_X_WINDOWS */
 
-
 /***********************************************************************
                            Image types
  ***********************************************************************/
@@ -1019,6 +1022,7 @@ prepare_image_for_display (struct frame *f, struct image 
*img)
   /* We're about to display IMG, so set its timestamp to `now'.  */
   img->timestamp = current_timespec ();
 
+#ifndef USE_CAIRO
   /* If IMG doesn't have a pixmap yet, load it now, using the image
      type dependent loader function.  */
   if (img->pixmap == NO_PIXMAP && !img->load_failed_p)
@@ -1032,6 +1036,7 @@ prepare_image_for_display (struct frame *f, struct image 
*img)
       unblock_input ();
     }
 #endif
+#endif
 }
 
 
@@ -1078,6 +1083,54 @@ image_ascent (struct image *img, struct face *face, 
struct glyph_slice *slice)
   return ascent;
 }
 
+#ifdef USE_CAIRO
+static uint32_t
+xcolor_to_argb32 (XColor xc)
+{
+  return (0xff << 24) | ((xc.red / 256) << 16)
+      | ((xc.green / 256) << 8) | (xc.blue / 256);
+}
+
+static uint32_t
+get_spec_bg_or_alpha_as_argb (struct image *img,
+                              struct frame *f)
+{
+  uint32_t bgcolor = 0;
+  XColor xbgcolor;
+  Lisp_Object bg = image_spec_value (img->spec, QCbackground, NULL);
+
+  if (STRINGP (bg) && XParseColor (FRAME_X_DISPLAY (f),
+                                   FRAME_X_COLORMAP (f),
+                                   SSDATA (bg),
+                                   &xbgcolor))
+    bgcolor = xcolor_to_argb32 (xbgcolor);
+
+  return bgcolor;
+}
+
+static void
+create_cairo_image_surface (struct image *img,
+                            unsigned char *data,
+                            int width,
+                            int height)
+{
+  cairo_surface_t *surface;
+  cairo_format_t format = CAIRO_FORMAT_ARGB32;
+  int stride = cairo_format_stride_for_width (format, width);
+  surface = cairo_image_surface_create_for_data (data,
+                                                 format,
+                                                 width,
+                                                 height,
+                                                 stride);
+  img->width = width;
+  img->height = height;
+  img->cr_data = surface;
+  img->cr_data2 = data;
+  img->pixmap = 0;
+}
+#endif
+
+
 
 /* Image background colors.  */
 
@@ -1299,6 +1352,11 @@ 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);
+  if (img->cr_data2) xfree (img->cr_data2);
+#endif
   x_clear_image_1 (f, img,
                   CLEAR_IMAGE_PIXMAP | CLEAR_IMAGE_MASK | CLEAR_IMAGE_COLORS);
   unblock_input ();
@@ -3154,9 +3212,11 @@ static struct image_type xpm_type =
    color allocation failures more gracefully than the ones on the XPM
    lib.  */
 
+#ifndef USE_CAIRO
 #if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
 #define ALLOC_XPM_COLORS
 #endif
+#endif /* USE_CAIRO */
 #endif /* HAVE_X_WINDOWS */
 
 #ifdef ALLOC_XPM_COLORS
@@ -3617,6 +3677,44 @@ xpm_load (struct frame *f, struct image *img)
 #endif /* HAVE_NTGUI */
     }
 
+#ifdef USE_CAIRO
+  // Load very specific Xpm:s.
+  if (rc == XpmSuccess
+      && img->ximg->format == ZPixmap
+      && img->ximg->bits_per_pixel == 32
+      && (! img->mask_img || img->mask_img->bits_per_pixel == 1))
+    {
+      int width = img->ximg->width;
+      int height = img->ximg->height;
+      unsigned char *data = (unsigned char *) xmalloc (width*height*4);
+      int i;
+      uint32_t *od = (uint32_t *)data;
+      uint32_t *id = (uint32_t *)img->ximg->data;
+      unsigned char *mid = img->mask_img ? img->mask_img->data : 0;
+      uint32_t bgcolor = get_spec_bg_or_alpha_as_argb (img, f);
+
+      for (i = 0; i < height; ++i)
+        {
+          int k;
+          for (k = 0; k < width; ++k)
+            {
+              int idx = i * img->ximg->bytes_per_line/4 + k;
+              int maskidx = mid ? i * img->mask_img->bytes_per_line + k/8 : 0;
+              int mask = mid ? mid[maskidx] & (1 << (k % 8)) : 1;
+
+              if (mask) od[idx] = id[idx] + 0xff000000; // ff => full alpha
+              else od[idx] = bgcolor;
+            }
+        }
+
+      create_cairo_image_surface (img, data, width, height);
+    }
+  else
+    {
+      rc = XpmFileInvalid;
+      x_clear_image (f, img);
+    }
+#else
 #ifdef HAVE_X_WINDOWS
   if (rc == XpmSuccess)
     {
@@ -3642,6 +3740,7 @@ xpm_load (struct frame *f, struct image *img)
        }
     }
 #endif
+#endif /* ! USE_CAIRO */
 
   if (rc == XpmSuccess)
     {
@@ -5148,12 +5247,17 @@ pbm_load (struct frame *f, struct image *img)
   bool raw_p;
   int x, y;
   int width, height, max_color_idx = 0;
-  XImagePtr ximg;
   Lisp_Object file, specified_file;
   enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
   unsigned char *contents = NULL;
   unsigned char *end, *p;
   ptrdiff_t size;
+#ifdef USE_CAIRO
+  unsigned char *data = 0;
+  uint32_t *dataptr;
+#else
+  XImagePtr ximg;
+#endif
 
   specified_file = image_spec_value (img->spec, QCfile, NULL);
 
@@ -5235,6 +5339,11 @@ pbm_load (struct frame *f, struct image *img)
   width = pbm_scan_number (&p, end);
   height = pbm_scan_number (&p, end);
 
+#ifdef USE_CAIRO
+  data = (unsigned char *) xmalloc (width * height * 4);
+  dataptr = (uint32_t *) data;
+#endif
+
   if (type != PBM_MONO)
     {
       max_color_idx = pbm_scan_number (&p, end);
@@ -5251,8 +5360,10 @@ pbm_load (struct frame *f, struct image *img)
       goto error;
     }
 
+#ifndef USE_CAIRO
   if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
     goto error;
+#endif
 
   /* Initialize the color hash table.  */
   init_color_table ();
@@ -5263,12 +5374,34 @@ pbm_load (struct frame *f, struct image *img)
       struct image_keyword fmt[PBM_LAST];
       unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
       unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
-
+#ifdef USE_CAIRO
+      XColor xfg, xbg;
+      int fga32, bga32;
+#endif
       /* Parse the image specification.  */
       memcpy (fmt, pbm_format, sizeof fmt);
       parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
 
       /* Get foreground and background colors, maybe allocate colors.  */
+#ifdef USE_CAIRO
+      if (! fmt[PBM_FOREGROUND].count
+          || ! STRINGP (fmt[PBM_FOREGROUND].value)
+          || ! x_defined_color (f, SSDATA (fmt[PBM_FOREGROUND].value), &xfg, 
0))
+        {
+          xfg.pixel = fg;
+          x_query_color (f, &xfg);
+        }
+      fga32 = xcolor_to_argb32 (xfg);
+
+      if (! fmt[PBM_BACKGROUND].count
+          || ! STRINGP (fmt[PBM_BACKGROUND].value)
+          || ! x_defined_color (f, SSDATA (fmt[PBM_BACKGROUND].value), &xbg, 
0))
+       {
+          xbg.pixel = bg;
+          x_query_color (f, &xbg);
+       }
+      bga32 = xcolor_to_argb32 (xbg);
+#else
       if (fmt[PBM_FOREGROUND].count
          && STRINGP (fmt[PBM_FOREGROUND].value))
        fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
@@ -5279,6 +5412,7 @@ pbm_load (struct frame *f, struct image *img)
          img->background = bg;
          img->background_valid = 1;
        }
+#endif
 
       for (y = 0; y < height; ++y)
        for (x = 0; x < width; ++x)
@@ -5289,7 +5423,11 @@ pbm_load (struct frame *f, struct image *img)
                  {
                    if (p >= end)
                      {
+#ifdef USE_CAIRO
+                        xfree (data);
+#else
                        x_destroy_x_image (ximg);
+#endif
                        x_clear_image (f, img);
                        image_error ("Invalid image size in image `%s'",
                                     img->spec, Qnil);
@@ -5303,7 +5441,11 @@ pbm_load (struct frame *f, struct image *img)
            else
              g = pbm_scan_number (&p, end);
 
+#ifdef USE_CAIRO
+            *dataptr++ = g ? fga32 : bga32;
+#else
            XPutPixel (ximg, x, y, g ? fg : bg);
+#endif
          }
     }
   else
@@ -5316,7 +5458,11 @@ pbm_load (struct frame *f, struct image *img)
 
       if (raw_p && p + expected_size > end)
        {
+#ifdef USE_CAIRO
+          xfree (data);
+#else
          x_destroy_x_image (ximg);
+#endif
          x_clear_image (f, img);
          image_error ("Invalid image size in image `%s'",
                       img->spec, Qnil);
@@ -5357,18 +5503,29 @@ pbm_load (struct frame *f, struct image *img)
 
            if (r < 0 || g < 0 || b < 0)
              {
+#ifdef USE_CAIRO
+                xfree (data);
+#else
                x_destroy_x_image (ximg);
+#endif
                image_error ("Invalid pixel value in image `%s'",
                             img->spec, Qnil);
                goto error;
              }
 
+#ifdef USE_CAIRO
+           r = (double) r * 255 / max_color_idx;
+           g = (double) g * 255 / max_color_idx;
+           b = (double) b * 255 / max_color_idx;
+            *dataptr++ = (0xff << 24) | (r << 16) | (g << 8) | b;
+#else
            /* RGB values are now in the range 0..max_color_idx.
               Scale this to the range 0..0xffff supported by X.  */
            r = (double) r * 65535 / max_color_idx;
            g = (double) g * 65535 / max_color_idx;
            b = (double) b * 65535 / max_color_idx;
            XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
+#endif
          }
     }
 
@@ -5384,12 +5541,16 @@ pbm_load (struct frame *f, struct image *img)
 
   /* Maybe fill in the background field while we have ximg handy.  */
 
+#ifdef USE_CAIRO
+  create_cairo_image_surface (img, data, width, height);
+#else
   if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
     /* Casting avoids a GCC warning.  */
     IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
 
   /* Put ximg into the image.  */
   image_put_x_image (f, img, ximg, 0);
+#endif
 
   /* X and W32 versions did it here, MAC version above.  ++kfs
      img->width = width;
@@ -5404,7 +5565,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.  */
 
@@ -5478,7 +5639,7 @@ 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
@@ -5713,7 +5874,6 @@ png_load_body (struct frame *f, struct image *img, struct 
png_load_context *c)
   Lisp_Object specified_data;
   int x, y;
   ptrdiff_t i;
-  XImagePtr ximg, mask_img = NULL;
   png_struct *png_ptr;
   png_info *info_ptr = NULL, *end_info = NULL;
   FILE *fp = NULL;
@@ -5727,6 +5887,13 @@ png_load_body (struct frame *f, struct image *img, 
struct png_load_context *c)
   bool transparent_p;
   struct png_memory_storage tbr;  /* Data to be read */
 
+#ifdef USE_CAIRO
+  unsigned char *data = 0;
+  uint32_t *dataptr;
+#else
+  XImagePtr ximg, mask_img = NULL;
+#endif
+
   /* Find out what file to load.  */
   specified_file = image_spec_value (img->spec, QCfile, NULL);
   specified_data = image_spec_value (img->spec, QCdata, NULL);
@@ -5847,10 +6014,12 @@ png_load_body (struct frame *f, struct image *img, 
struct png_load_context *c)
       goto error;
     }
 
+#ifndef USE_CAIRO
   /* Create the X image and pixmap now, so that the work below can be
      omitted if the image is too large for X.  */
   if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
     goto error;
+#endif
 
   /* If image contains simply transparency data, we prefer to
      construct a clipping mask.  */
@@ -5937,6 +6106,10 @@ png_load_body (struct frame *f, struct image *img, 
struct png_load_context *c)
       c->fp = NULL;
     }
 
+#ifdef USE_CAIRO
+  data = (unsigned char *) xmalloc (width * height * 4);
+  dataptr = (uint32_t *) data;
+#else
   /* Create an image and pixmap serving as mask if the PNG image
      contains an alpha channel.  */
   if (channels == 4
@@ -5948,6 +6121,7 @@ png_load_body (struct frame *f, struct image *img, struct 
png_load_context *c)
       x_clear_image_1 (f, img, CLEAR_IMAGE_PIXMAP);
       goto error;
     }
+#endif
 
   /* Fill the X image and mask from PNG data.  */
   init_color_table ();
@@ -5960,6 +6134,14 @@ png_load_body (struct frame *f, struct image *img, 
struct png_load_context *c)
        {
          int r, g, b;
 
+#ifdef USE_CAIRO
+          int a = 0xff;
+         r = *p++;
+         g = *p++;
+         b = *p++;
+          if (channels == 4) a = *p++;
+          *dataptr++ = (a << 24) | (r << 16) | (g << 8) | b;
+#else
          r = *p++ << 8;
          g = *p++ << 8;
          b = *p++ << 8;
@@ -5986,6 +6168,7 @@ png_load_body (struct frame *f, struct image *img, struct 
png_load_context *c)
                XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : 
PIX_MASK_RETAIN);
              ++p;
            }
+#endif
        }
     }
 
@@ -6015,6 +6198,9 @@ png_load_body (struct frame *f, struct image *img, struct 
png_load_context *c)
   img->width = width;
   img->height = height;
 
+#ifdef USE_CAIRO
+  create_cairo_image_surface (img, data, width, height);
+#else
   /* Maybe fill in the background field while we have ximg handy.
      Casting avoids a GCC warning.  */
   IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
@@ -6031,6 +6217,7 @@ png_load_body (struct frame *f, struct image *img, struct 
png_load_context *c)
 
       image_put_x_image (f, img, mask_img, 1);
     }
+#endif
 
   return 1;
 }
@@ -6052,6 +6239,7 @@ png_load (struct frame *f, struct image *img)
                         image_spec_value (img->spec, QCdata, NULL));
 }
 
+
 #endif /* HAVE_NS */
 
 
@@ -6463,9 +6651,12 @@ jpeg_load_body (struct frame *f, struct image *img,
   FILE * IF_LINT (volatile) fp = NULL;
   JSAMPARRAY buffer;
   int row_stride, x, y;
-  XImagePtr ximg = NULL;
   unsigned long *colors;
   int width, height;
+  int i, ir, ig, ib;
+#ifndef USE_CAIRO
+  XImagePtr ximg = NULL;
+#endif
 
   /* Open the JPEG file.  */
   specified_file = image_spec_value (img->spec, QCfile, NULL);
@@ -6525,8 +6716,9 @@ jpeg_load_body (struct frame *f, struct image *img,
       jpeg_destroy_decompress (&mgr->cinfo);
 
       /* If we already have an XImage, free that.  */
+#ifndef USE_CAIRO
       x_destroy_x_image (ximg);
-
+#endif
       /* Free pixmap and colors.  */
       x_clear_image (f, img);
       return 0;
@@ -6560,12 +6752,14 @@ jpeg_load_body (struct frame *f, struct image *img,
       sys_longjmp (mgr->setjmp_buffer, 1);
     }
 
+#ifndef USE_CAIRO
   /* Create X image and pixmap.  */
   if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
     {
       mgr->failure_code = MY_JPEG_CANNOT_CREATE_X;
       sys_longjmp (mgr->setjmp_buffer, 1);
     }
+#endif
 
   /* Allocate colors.  When color quantization is used,
      mgr->cinfo.actual_number_of_colors has been set with the number of
@@ -6574,8 +6768,6 @@ jpeg_load_body (struct frame *f, struct image *img,
      No more than 255 colors will be generated.  */
   USE_SAFE_ALLOCA;
   {
-    int i, ir, ig, ib;
-
     if (mgr->cinfo.out_color_components > 2)
       ir = 0, ig = 1, ib = 2;
     else if (mgr->cinfo.out_color_components > 1)
@@ -6583,6 +6775,7 @@ jpeg_load_body (struct frame *f, struct image *img,
     else
       ir = 0, ig = 0, ib = 0;
 
+#ifndef CAIRO
     /* Use the color table mechanism because it handles colors that
        cannot be allocated nicely.  Such colors will be replaced with
        a default color, and we don't have to care about which colors
@@ -6599,6 +6792,7 @@ jpeg_load_body (struct frame *f, struct image *img,
        int b = mgr->cinfo.colormap[ib][i] << 8;
        colors[i] = lookup_rgb_color (f, r, g, b);
       }
+#endif
 
 #ifdef COLOR_TABLE_SUPPORT
     /* Remember those colors actually allocated.  */
@@ -6611,12 +6805,36 @@ jpeg_load_body (struct frame *f, struct image *img,
   row_stride = width * mgr->cinfo.output_components;
   buffer = mgr->cinfo.mem->alloc_sarray ((j_common_ptr) &mgr->cinfo,
                                         JPOOL_IMAGE, row_stride, 1);
+#ifdef USE_CAIRO
+  {
+    unsigned char *data = (unsigned char *) xmalloc (width*height*4);
+    uint32_t *dataptr = (uint32_t *) data;
+    int r, g, b;
+
+    for (y = 0; y < height; ++y)
+      {
+        jpeg_read_scanlines (&mgr->cinfo, buffer, 1);
+
+        for (x = 0; x < width; ++x)
+          {
+            i = buffer[0][x];
+            r = mgr->cinfo.colormap[ir][i];
+            g = mgr->cinfo.colormap[ig][i];
+            b = mgr->cinfo.colormap[ib][i];
+            *dataptr++ = (0xff << 24) | (r << 16) | (g << 8) | b;
+          }
+      }
+
+    create_cairo_image_surface (img, data, width, height);
+  }
+#else
   for (y = 0; y < height; ++y)
     {
       jpeg_read_scanlines (&mgr->cinfo, buffer, 1);
       for (x = 0; x < mgr->cinfo.output_width; ++x)
        XPutPixel (ximg, x, y, colors[buffer[0][x]]);
     }
+#endif
 
   /* Clean up.  */
   jpeg_finish_decompress (&mgr->cinfo);
@@ -6624,6 +6842,7 @@ jpeg_load_body (struct frame *f, struct image *img,
   if (fp)
     fclose (fp);
 
+#ifndef USE_CAIRO
   /* Maybe fill in the background field while we have ximg handy. */
   if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
     /* Casting avoids a GCC warning.  */
@@ -6631,6 +6850,7 @@ jpeg_load_body (struct frame *f, struct image *img,
 
   /* Put ximg into the image.  */
   image_put_x_image (f, img, ximg, 0);
+#endif
   SAFE_FREE ();
   return 1;
 }
@@ -7063,6 +7283,29 @@ tiff_load (struct frame *f, struct image *img)
       return 0;
     }
 
+#ifdef USE_CAIRO
+  {
+    unsigned char *data = (unsigned char *) xmalloc (width*height*4);
+    uint32_t *dataptr = (uint32_t *) data;
+    int r, g, b, a;
+
+    for (y = 0; y < height; ++y)
+      {
+        uint32 *row = buf + (height - 1 - y) * width;
+        for (x = 0; x < width; ++x)
+          {
+            uint32 abgr = row[x];
+            int r = TIFFGetR (abgr);
+            int g = TIFFGetG (abgr);
+            int b = TIFFGetB (abgr);
+            int a = TIFFGetA (abgr);
+            *dataptr++ = (a << 24) | (r << 16) | (g << 8) | b;
+          }
+      }
+
+    create_cairo_image_surface (img, data, width, height);
+  }
+#else
   /* Initialize the color table.  */
   init_color_table ();
 
@@ -7097,8 +7340,10 @@ tiff_load (struct frame *f, struct image *img)
 
   /* Put ximg into the image.  */
   image_put_x_image (f, img, ximg, 0);
-  xfree (buf);
 
+#endif /* ! USE_CAIRO */
+
+  xfree (buf);
   return 1;
 }
 
@@ -7348,7 +7593,6 @@ gif_load (struct frame *f, struct image *img)
 {
   Lisp_Object file;
   int rc, width, height, x, y, i, j;
-  XImagePtr ximg;
   ColorMapObject *gif_color_map;
   unsigned long pixel_colors[256];
   GifFileType *gif;
@@ -7360,6 +7604,12 @@ gif_load (struct frame *f, struct image *img)
   EMACS_INT idx;
   int gif_err;
 
+#ifdef USE_CAIRO
+  unsigned char *data = 0;
+#else
+  XImagePtr ximg;
+#endif
+
   if (NILP (specified_data))
     {
       file = x_find_image_file (specified_file);
@@ -7488,6 +7738,25 @@ gif_load (struct frame *f, struct image *img)
        }
     }
 
+#ifdef USE_CAIRO
+  /* xzalloc so data is zero => transparent */
+  data = (unsigned char *) xzalloc (width * height * 4);
+  if (STRINGP (specified_bg))
+    {
+      XColor color;
+      if (x_defined_color (f, SSDATA (specified_bg), &color, 0))
+        {
+          uint32_t *dataptr = (uint32_t *)data;
+          int r = color.red/256;
+          int g = color.green/256;
+          int b = color.blue/256;
+
+          for (y = 0; y < height; ++y)
+            for (x = 0; x < width; ++x)
+              *dataptr++ = (0xff << 24) | (r << 16) | (g << 8) | b;
+        }
+    }
+#else
   /* Create the X image and pixmap.  */
   if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
     {
@@ -7514,6 +7783,7 @@ gif_load (struct frame *f, struct image *img)
       for (x = img->corners[RIGHT_CORNER]; x < width; ++x)
        XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
     }
+#endif
 
   /* Read the GIF image into the X image.   */
 
@@ -7568,12 +7838,14 @@ gif_load (struct frame *f, struct image *img)
       if (disposal == 0)
        disposal = 1;
 
-      /* Allocate subimage colors.  */
-      memset (pixel_colors, 0, sizeof pixel_colors);
       gif_color_map = subimage->ImageDesc.ColorMap;
       if (!gif_color_map)
        gif_color_map = gif->SColorMap;
 
+#ifndef USE_CAIRO
+      /* Allocate subimage colors.  */
+      memset (pixel_colors, 0, sizeof pixel_colors);
+
       if (gif_color_map)
        for (i = 0; i < gif_color_map->ColorCount; ++i)
          {
@@ -7588,6 +7860,7 @@ gif_load (struct frame *f, struct image *img)
                pixel_colors[i] = lookup_rgb_color (f, r, g, b);
              }
          }
+#endif
 
       /* Apply the pixel values.  */
       if (GIFLIB_MAJOR < 5 && gif->SavedImages[j].ImageDesc.Interlace)
@@ -7605,20 +7878,47 @@ gif_load (struct frame *f, struct image *img)
                {
                  int c = raster[y * subimg_width + x];
                  if (transparency_color_index != c || disposal != 1)
-                   XPutPixel (ximg, x + subimg_left, row + subimg_top,
-                              pixel_colors[c]);
+                    {
+#ifdef USE_CAIRO
+                      uint32_t *dataptr =
+                        ((uint32_t*)data + ((row + subimg_top) * subimg_width
+                                            + x + subimg_left));
+                      int r = gif_color_map->Colors[c].Red;
+                      int g = gif_color_map->Colors[c].Green;
+                      int b = gif_color_map->Colors[c].Blue;
+
+                      if (transparency_color_index != c)
+                        *dataptr = (0xff << 24) | (r << 16) | (g << 8) | b;
+#else
+                      XPutPixel (ximg, x + subimg_left, row + subimg_top,
+                                 pixel_colors[c]);
+#endif
+                    }
                }
            }
        }
       else
        {
-         for (y = 0; y < subimg_height; ++y)
+          for (y = 0; y < subimg_height; ++y)
            for (x = 0; x < subimg_width; ++x)
              {
                int c = raster[y * subimg_width + x];
                if (transparency_color_index != c || disposal != 1)
-                 XPutPixel (ximg, x + subimg_left, y + subimg_top,
-                            pixel_colors[c]);
+                  {
+#ifdef USE_CAIRO
+                    uint32_t *dataptr =
+                      ((uint32_t*)data + ((y + subimg_top) * subimg_width
+                                          + x + subimg_left));
+                    int r = gif_color_map->Colors[c].Red;
+                    int g = gif_color_map->Colors[c].Green;
+                    int b = gif_color_map->Colors[c].Blue;
+                    if (transparency_color_index != c)
+                      *dataptr = (0xff << 24) | (r << 16) | (g << 8) | b;
+#else
+                    XPutPixel (ximg, x + subimg_left, y + subimg_top,
+                               pixel_colors[c]);
+#endif
+                  }
              }
        }
     }
@@ -7675,6 +7975,9 @@ gif_load (struct frame *f, struct image *img)
 #endif
     }
 
+#ifdef USE_CAIRO
+  create_cairo_image_surface (img, data, width, height);
+#else
   /* Maybe fill in the background field while we have ximg handy. */
   if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
     /* Casting avoids a GCC warning.  */
@@ -7682,6 +7985,7 @@ gif_load (struct frame *f, struct image *img)
 
   /* Put ximg into the image.  */
   image_put_x_image (f, img, ximg, 0);
+#endif
 
   return 1;
 }
@@ -8901,6 +9205,37 @@ svg_load_image (struct frame *f,         /* Pointer to 
emacs frame structure.  *
   eassert (gdk_pixbuf_get_has_alpha (pixbuf));
   eassert (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);
 
+#ifdef USE_CAIRO
+  {
+    unsigned char *data = (unsigned char *) xmalloc (width*height*4);
+    int y;
+    uint32_t bgcolor = get_spec_bg_or_alpha_as_argb (img, f);
+
+    for (y = 0; y < height; ++y)
+      {
+        const guchar *iconptr = pixels + y * rowstride;
+        uint32_t *dataptr = (uint32_t *) (data + y * rowstride);
+        int x;
+
+        for (x = 0; x < width; ++x)
+          {
+            if (iconptr[3] == 0)
+              *dataptr = bgcolor;
+            else
+              *dataptr = (iconptr[0] << 16)
+                | (iconptr[1] << 8)
+                | iconptr[2]
+                | (iconptr[3] << 24);
+
+            iconptr += 4;
+            ++dataptr;
+          }
+      }
+
+    create_cairo_image_surface (img, data, width, height);
+    g_object_unref (pixbuf);
+  }
+#else
   /* Try to create a x pixmap to hold the svg pixmap.  */
   if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
     {
@@ -8972,6 +9307,7 @@ svg_load_image (struct frame *f,         /* Pointer to 
emacs frame structure.  *
 
   /* Put ximg into the image.  */
   image_put_x_image (f, img, ximg, 0);
+#endif /* ! USE_CAIRO */
 
   return 1;
 
@@ -9239,15 +9575,16 @@ x_kill_gs_process (Pixmap pixmap, struct frame *f)
          /* For each pixel of the image, look its color up in the
             color table.  After having done so, the color table will
             contain an entry for each color used by the image.  */
+#ifdef COLOR_TABLE_SUPPORT
          for (y = 0; y < img->height; ++y)
            for (x = 0; x < img->width; ++x)
              {
                unsigned long pixel = XGetPixel (ximg, x, y);
+
                lookup_pixel_color (f, pixel);
              }
 
          /* Record colors in the image.  Free color table and XImage.  */
-#ifdef COLOR_TABLE_SUPPORT
          img->colors = colors_in_color_table (&img->ncolors);
          free_color_table ();
 #endif
@@ -9360,7 +9697,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 03ef813..5ac58e9 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -3116,6 +3116,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);
@@ -3124,6 +3127,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);
@@ -5118,6 +5122,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
@@ -5126,6 +5133,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);
@@ -6209,6 +6217,158 @@ 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.  */)
+     (Lisp_Object frames, Lisp_Object type)
+{
+  Lisp_Object result, rest, tmp;
+  cairo_surface_type_t surface_type;
+
+  if (NILP (frames))
+    frames = selected_frame;
+  if (!CONSP (frames))
+    frames = list1 (frames);
+
+  tmp = Qnil;
+  for (rest = frames; CONSP (rest); rest = XCDR (rest))
+    {
+      struct frame *f = XFRAME (XCAR (rest));
+
+      if (! FRAME_LIVE_P (f) || ! FRAME_X_P (f) || ! FRAME_LIVE_P (f))
+        error ("Invalid frame");
+
+      Lisp_Object frame;
+
+      XSETFRAME (frame, f);
+      tmp = Fcons (frame, tmp);
+    }
+  frames = Fnreverse (tmp);
+
+#ifdef CAIRO_HAS_PDF_SURFACE
+  if (NILP (type) || EQ (type, intern ("pdf"))) /* XXX: Qpdf */
+    surface_type = CAIRO_SURFACE_TYPE_PDF;
+  else
+#endif
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+  if (EQ (type, intern ("png")))
+    {
+      if (!NILP (XCDR (frames)))
+       error ("PNG export cannot handle multiple frames.");
+      surface_type = CAIRO_SURFACE_TYPE_IMAGE;
+    }
+  else
+#endif
+#ifdef CAIRO_HAS_PS_SURFACE
+  if (EQ (type, intern ("ps")))
+    surface_type = CAIRO_SURFACE_TYPE_PS;
+  else
+#endif
+#ifdef CAIRO_HAS_SVG_SURFACE
+  if (EQ (type, intern ("svg")))
+    {
+      /* For now, we stick to SVG 1.1.  */
+      if (!NILP (XCDR (frames)))
+       error ("SVG export cannot handle multiple frames.");
+      surface_type = CAIRO_SURFACE_TYPE_SVG;
+    }
+  else
+#endif
+    error ("Unsupported export type");
+
+  result = x_cr_export_frames (frames, surface_type);
+
+  return result;
+}
+
+#ifdef USE_GTK
+DEFUN ("x-page-setup-dialog", Fx_page_setup_dialog, Sx_page_setup_dialog, 0, 
0, 0,
+       doc: /* Pop up a page setup dialog.
+The current page setup can be obtained using `x-get-page-setup'.  */)
+     (void)
+{
+  block_input ();
+  xg_page_setup_dialog ();
+  unblock_input ();
+
+  return Qnil;
+}
+
+DEFUN ("x-get-page-setup", Fx_get_page_setup, Sx_get_page_setup, 0, 0, 0,
+       doc: /* Return the value of the current page setup.
+The return value is an alist containing the following keys:
+
+  orientation: page orientation (symbol `portrait', `landscape',
+       `reverse-portrait', or `reverse-landscape').
+  width, height: page width/height in points not including margins.
+  left-margin, right-margin, top-margin, bottom-margin: print margins,
+       which is the parts of the page that the printer cannot print
+       on, in points.
+
+The paper width can be obtained as the sum of width, left-margin, and
+right-margin values.  Likewise, the paper height is the sum of height,
+top-margin, and bottom-margin values.  */)
+     (void)
+{
+  Lisp_Object result;
+
+  block_input ();
+  result = xg_get_page_setup ();
+  unblock_input ();
+
+  return result;
+}
+
+DEFUN ("x-print-frames-dialog", Fx_print_frames_dialog, 
Sx_print_frames_dialog, 0, 1, "",
+       doc: /* Pop up a print dialog to print the current contents of FRAMES.
+FRAMES should be nil (the selected frame), a frame, or a list of
+frames (each of which corresponds to one page).  Each frame should be
+visible.  */)
+     (Lisp_Object frames)
+{
+  Lisp_Object rest, tmp;
+
+  if (NILP (frames))
+    frames = selected_frame;
+  if (!CONSP (frames))
+    frames = list1 (frames);
+
+  tmp = Qnil;
+  for (rest = frames; CONSP (rest); rest = XCDR (rest))
+    {
+      struct frame *f = XFRAME (XCAR (rest));
+      if (! FRAME_LIVE_P (f) || ! FRAME_X_P (f) || ! FRAME_LIVE_P (f))
+        error ("Invalid frame");
+      Lisp_Object frame;
+
+      XSETFRAME (frame, f);
+      if (!EQ (Fframe_visible_p (frame), Qt))
+       error ("Frames to be printed must be visible.");
+      tmp = Fcons (frame, tmp);
+    }
+  frames = Fnreverse (tmp);
+
+  /* Make sure the current matrices are up-to-date.  */
+  Fredisplay (Qt);
+
+  block_input ();
+  xg_print_frames_dialog (frames);
+  unblock_input ();
+
+  return Qnil;
+}
+#endif /* USE_GTK */
+#endif /* USE_CAIRO */
+
+
+/***********************************************************************
                            Initialization
  ***********************************************************************/
 
@@ -6265,6 +6425,16 @@ syms_of_xfns (void)
   DEFSYM (Qfont_param, "font-parameter");
   DEFSYM (Qmono, "mono");
 
+#ifdef USE_CAIRO
+  DEFSYM (Qorientation, "orientation");
+  DEFSYM (Qtop_margin, "top-margin");
+  DEFSYM (Qbottom_margin, "bottom-margin");
+  DEFSYM (Qportrait, "portrait");
+  DEFSYM (Qlandscape, "landscape");
+  DEFSYM (Qreverse_portrait, "reverse-portrait");
+  DEFSYM (Qreverse_landscape, "reverse-landscape");
+#endif
+
   Fput (Qundefined_color, Qerror_conditions,
        listn (CONSTYPE_PURE, 2, Qundefined_color, Qerror));
   Fput (Qundefined_color, Qerror_message,
@@ -6405,6 +6575,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);
@@ -6455,4 +6639,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 06ce707..3734fbf 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -22,6 +22,9 @@ along with GNU Emacs.  If not, see 
<http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 #include <stdio.h>
+#ifdef USE_CAIRO
+#include <math.h>
+#endif
 
 #include "lisp.h"
 #include "blockinput.h"
@@ -220,6 +223,7 @@ static int x_io_error_quitter (Display *);
 static struct terminal *x_create_terminal (struct x_display_info *);
 static void x_update_end (struct frame *);
 static void XTframe_up_to_date (struct frame *);
+static void x_clear_area1 (Display *, Window, int, int, int, int, int);
 static void x_clear_frame (struct frame *);
 static _Noreturn void x_ins_del_lines (struct frame *, int, int);
 static void frame_highlight (struct frame *);
@@ -325,6 +329,587 @@ record_event (char *locus, int type)
 
 #endif
 
+static void x_free_cr_resources (struct frame *);
+static void x_set_clip_rectangles (struct frame *, GC, XRectangle *, int);
+static void x_reset_clip_rectangles (struct frame *, GC);
+static void x_fill_rectangle (struct frame *, GC, int, int, int, int);
+static void x_draw_rectangle (struct frame *, GC, int, int, int, int);
+static void x_fill_trapezoid_for_relief (struct frame *, GC, int, int,
+                                        int, int, int);
+static void x_clear_window (struct frame *);
+
+#ifdef USE_CAIRO
+static struct x_gc_ext_data *x_gc_get_ext_data (struct frame *, GC, int);
+static void x_extension_initialize (struct x_display_info *);
+static cairo_status_t x_cr_accumulate_data (void *,
+                                            const unsigned char *,
+                                            unsigned int);
+
+#define FRAME_CR_CONTEXT(f)    ((f)->output_data.x->cr_context)
+#define FRAME_CR_SURFACE(f)    ((f)->output_data.x->cr_surface)
+
+static struct x_gc_ext_data *
+x_gc_get_ext_data (struct frame *f, GC gc, int create_if_not_found_p)
+{
+  struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+  XEDataObject object;
+  XExtData **head, *ext_data;
+
+  object.gc = gc;
+  head = XEHeadOfExtensionList (object);
+  ext_data = XFindOnExtensionList (head, dpyinfo->ext_codes->extension);
+  if (ext_data == NULL)
+    {
+      if (!create_if_not_found_p)
+       return NULL;
+      else
+       {
+         ext_data = xzalloc (sizeof (*ext_data));
+         ext_data->number = dpyinfo->ext_codes->extension;
+         ext_data->private_data = xzalloc (sizeof (struct x_gc_ext_data));
+         XAddToExtensionList (head, ext_data);
+       }
+    }
+  return (struct x_gc_ext_data *) ext_data->private_data;
+}
+
+static void
+x_extension_initialize (struct x_display_info *dpyinfo)
+{
+  XExtCodes *ext_codes = XAddExtension (dpyinfo->display);
+
+  dpyinfo->ext_codes = ext_codes;
+}
+
+static void
+x_cr_destroy_surface (struct frame *f)
+{
+  if (FRAME_CR_SURFACE (f))
+    {
+      cairo_t *cr = FRAME_CR_CONTEXT (f);
+      cairo_surface_destroy (FRAME_CR_SURFACE (f));
+      FRAME_CR_SURFACE (f) = 0;
+      if (cr) cairo_destroy (cr);
+      FRAME_CR_CONTEXT (f) = NULL;
+    }
+}
+
+cairo_t *
+x_begin_cr_clip (struct frame *f, GC gc)
+{
+  cairo_t *cr = FRAME_CR_CONTEXT (f);
+
+  if (!cr)
+    {
+
+      if (! FRAME_CR_SURFACE (f))
+        {
+          cairo_surface_t *surface;
+          surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
+                                               FRAME_X_WINDOW (f),
+                                               FRAME_DISPLAY_INFO (f)->visual,
+                                               FRAME_PIXEL_WIDTH (f),
+                                               FRAME_PIXEL_HEIGHT (f));
+          cr = cairo_create (surface);
+          cairo_surface_destroy (surface);
+        }
+      else
+        cr = cairo_create (FRAME_CR_SURFACE (f));
+      FRAME_CR_CONTEXT (f) = cr;
+    }
+  cairo_save (cr);
+
+  if (gc)
+    {
+      struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
+
+      if (gc_ext && gc_ext->n_clip_rects)
+       {
+         int i;
+
+         for (i = 0; i < gc_ext->n_clip_rects; i++)
+           cairo_rectangle (cr, gc_ext->clip_rects[i].x,
+                            gc_ext->clip_rects[i].y,
+                            gc_ext->clip_rects[i].width,
+                            gc_ext->clip_rects[i].height);
+         cairo_clip (cr);
+       }
+    }
+
+  return cr;
+}
+
+void
+x_end_cr_clip (struct frame *f)
+{
+  cairo_restore (FRAME_CR_CONTEXT (f));
+}
+
+void
+x_set_cr_source_with_gc_foreground (struct frame *f, GC gc)
+{
+  XGCValues xgcv;
+  XColor color;
+
+  XGetGCValues (FRAME_X_DISPLAY (f), gc, GCForeground, &xgcv);
+  color.pixel = xgcv.foreground;
+  x_query_color (f, &color);
+  cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0,
+                       color.green / 65535.0, color.blue / 65535.0);
+}
+
+void
+x_set_cr_source_with_gc_background (struct frame *f, GC gc)
+{
+  XGCValues xgcv;
+  XColor color;
+
+  XGetGCValues (FRAME_X_DISPLAY (f), gc, GCBackground, &xgcv);
+  color.pixel = xgcv.background;
+  x_query_color (f, &color);
+  cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0,
+                       color.green / 65535.0, color.blue / 65535.0);
+}
+
+/* Fringe bitmaps.  */
+
+static int max_fringe_bmp = 0;
+static cairo_pattern_t **fringe_bmp = 0;
+
+static void
+x_cr_define_fringe_bitmap (int which, unsigned short *bits, int h, int wd)
+{
+  int i, stride;
+  cairo_surface_t *surface;
+  unsigned char *data;
+  cairo_pattern_t *pattern;
+
+  if (which >= max_fringe_bmp)
+    {
+      i = max_fringe_bmp;
+      max_fringe_bmp = which + 20;
+      fringe_bmp = (cairo_pattern_t **) xrealloc (fringe_bmp, max_fringe_bmp * 
sizeof (cairo_pattern_t *));
+      while (i < max_fringe_bmp)
+       fringe_bmp[i++] = 0;
+    }
+
+  block_input ();
+
+  surface = cairo_image_surface_create (CAIRO_FORMAT_A1, wd, h);
+  stride = cairo_image_surface_get_stride (surface);
+  data = cairo_image_surface_get_data (surface);
+
+  for (i = 0; i < h; i++)
+    {
+      *((unsigned short *) data) = bits[i];
+      data += stride;
+    }
+
+  cairo_surface_mark_dirty (surface);
+  pattern = cairo_pattern_create_for_surface (surface);
+  cairo_surface_destroy (surface);
+
+  unblock_input ();
+
+  fringe_bmp[which] = pattern;
+}
+
+static void
+x_cr_destroy_fringe_bitmap (int which)
+{
+  if (which >= max_fringe_bmp)
+    return;
+
+  if (fringe_bmp[which])
+    {
+      block_input ();
+      cairo_pattern_destroy (fringe_bmp[which]);
+      unblock_input ();
+    }
+  fringe_bmp[which] = 0;
+}
+
+static void
+x_cr_draw_image (struct frame *f, GC gc, cairo_pattern_t *image,
+                int src_x, int src_y, int width, int height,
+                int dest_x, int dest_y, bool overlay_p)
+{
+  cairo_t *cr;
+  cairo_matrix_t matrix;
+  cairo_surface_t *surface;
+  cairo_format_t format;
+
+  cr = x_begin_cr_clip (f, gc);
+  if (overlay_p)
+    cairo_rectangle (cr, dest_x, dest_y, width, height);
+  else
+    {
+      x_set_cr_source_with_gc_background (f, gc);
+      cairo_rectangle (cr, dest_x, dest_y, width, height);
+      cairo_fill_preserve (cr);
+    }
+  cairo_clip (cr);
+  cairo_matrix_init_translate (&matrix, src_x - dest_x, src_y - dest_y);
+  cairo_pattern_set_matrix (image, &matrix);
+  cairo_pattern_get_surface (image, &surface);
+  format = cairo_image_surface_get_format (surface);
+  if (format != CAIRO_FORMAT_A8 && format != CAIRO_FORMAT_A1)
+    {
+      cairo_set_source (cr, image);
+      cairo_fill (cr);
+    }
+  else
+    {
+      x_set_cr_source_with_gc_foreground (f, gc);
+      cairo_mask (cr, image);
+    }
+  x_end_cr_clip (f);
+}
+
+void
+x_cr_draw_frame (cairo_t *cr, struct frame *f)
+{
+  int width, height;
+
+  width = FRAME_PIXEL_WIDTH (f);
+  height = FRAME_PIXEL_HEIGHT (f);
+
+  x_free_cr_resources (f);
+  FRAME_CR_CONTEXT (f) = cr;
+  x_clear_area (f, 0, 0, width, height);
+  expose_frame (f, 0, 0, width, height);
+  FRAME_CR_CONTEXT (f) = NULL;
+}
+
+static cairo_status_t
+x_cr_accumulate_data (void *closure, const unsigned char *data,
+                     unsigned int length)
+{
+  Lisp_Object *acc = (Lisp_Object *) closure;
+
+  *acc = Fcons (make_unibyte_string (data, length), *acc);
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+x_cr_destroy (Lisp_Object arg)
+{
+  cairo_t *cr = (cairo_t *) XSAVE_POINTER (arg, 0);
+
+  block_input ();
+  cairo_destroy (cr);
+  unblock_input ();
+}
+
+Lisp_Object
+x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type)
+{
+  struct frame *f;
+  cairo_surface_t *surface;
+  cairo_t *cr;
+  int width, height;
+  void (*surface_set_size_func) (cairo_surface_t *, double, double) = NULL;
+  Lisp_Object acc = Qnil, args[2];
+  int count = SPECPDL_INDEX ();
+
+  Fredisplay (Qt);
+
+  f = XFRAME (XCAR (frames));
+  frames = XCDR (frames);
+  width = FRAME_PIXEL_WIDTH (f);
+  height = FRAME_PIXEL_HEIGHT (f);
+
+  block_input ();
+#ifdef CAIRO_HAS_PDF_SURFACE
+  if (surface_type == CAIRO_SURFACE_TYPE_PDF)
+    {
+      surface = cairo_pdf_surface_create_for_stream (x_cr_accumulate_data, 
&acc,
+                                                    width, height);
+      surface_set_size_func = cairo_pdf_surface_set_size;
+    }
+  else
+#endif
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+  if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
+    surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
+  else
+#endif
+#ifdef CAIRO_HAS_PS_SURFACE
+  if (surface_type == CAIRO_SURFACE_TYPE_PS)
+    {
+      surface = cairo_ps_surface_create_for_stream (x_cr_accumulate_data, &acc,
+                                                   width, height);
+      surface_set_size_func = cairo_ps_surface_set_size;
+    }
+  else
+#endif
+#ifdef CAIRO_HAS_SVG_SURFACE
+  if (surface_type == CAIRO_SURFACE_TYPE_SVG)
+    surface = cairo_svg_surface_create_for_stream (x_cr_accumulate_data, &acc,
+                                                  width, height);
+  else
+#endif
+    abort ();
+
+  cr = cairo_create (surface);
+  cairo_surface_destroy (surface);
+  record_unwind_protect (x_cr_destroy, make_save_ptr (cr));
+  unblock_input ();
+
+  while (1)
+    {
+      QUIT;
+
+      block_input ();
+      x_free_cr_resources (f);
+      FRAME_CR_CONTEXT (f) = cr;
+      x_clear_area (f, 0, 0, width, height);
+      expose_frame (f, 0, 0, width, height);
+      FRAME_CR_CONTEXT (f) = NULL;
+      unblock_input ();
+
+      if (NILP (frames))
+       break;
+
+      block_input ();
+      cairo_surface_show_page (surface);
+      f = XFRAME (XCAR (frames));
+      frames = XCDR (frames);
+      width = FRAME_PIXEL_WIDTH (f);
+      height = FRAME_PIXEL_HEIGHT (f);
+      if (surface_set_size_func)
+       (*surface_set_size_func) (surface, width, height);
+      unblock_input ();
+    }
+
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+  if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
+    {
+      block_input ();
+      cairo_surface_flush (surface);
+      cairo_surface_write_to_png_stream (surface, x_cr_accumulate_data, &acc);
+      unblock_input ();
+    }
+#endif
+  unbind_to (count, Qnil);
+
+  args[0] = intern ("concat");
+  args[1] = Fnreverse (acc);
+  return Fapply (2, args);
+}
+
+#endif /* USE_CAIRO */
+
+static void
+x_free_cr_resources (struct frame *f)
+{
+#ifdef USE_CAIRO
+  if (f == NULL)
+    {
+      Lisp_Object rest, frame;
+      FOR_EACH_FRAME (rest, frame)
+       if (FRAME_X_P (XFRAME (frame)))
+         x_free_cr_resources (XFRAME (frame));
+    }
+  else
+    {
+      cairo_t *cr = FRAME_CR_CONTEXT (f);
+
+      if (cr)
+       {
+         cairo_surface_t *surface = cairo_get_target (cr);
+
+         if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB)
+           {
+             cairo_destroy (cr);
+             FRAME_CR_CONTEXT (f) = NULL;
+           }
+       }
+    }
+#endif
+}
+
+static void
+x_set_clip_rectangles (struct frame *f, GC gc, XRectangle *rectangles, int n)
+{
+  XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, rectangles, n, Unsorted);
+#ifdef USE_CAIRO
+  eassert (n >= 0 && n <= MAX_CLIP_RECTS);
+
+  {
+    struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 1);
+
+    gc_ext->n_clip_rects = n;
+    memcpy (gc_ext->clip_rects, rectangles, sizeof (XRectangle) * n);
+  }
+#endif
+}
+
+static void
+x_reset_clip_rectangles (struct frame *f, GC gc)
+{
+  XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
+#ifdef USE_CAIRO
+  {
+    struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
+
+    if (gc_ext)
+      gc_ext->n_clip_rects = 0;
+  }
+#endif
+}
+
+static void
+x_fill_rectangle (struct frame *f, GC gc, int x, int y, int width, int height)
+{
+#ifdef USE_CAIRO
+  cairo_t *cr;
+
+  cr = x_begin_cr_clip (f, gc);
+  x_set_cr_source_with_gc_foreground (f, gc);
+  cairo_rectangle (cr, x, y, width, height);
+  cairo_fill (cr);
+  x_end_cr_clip (f);
+#else
+  XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                 gc, x, y, width, height);
+#endif
+}
+
+static void
+x_draw_rectangle (struct frame *f, GC gc, int x, int y, int width, int height)
+{
+#ifdef USE_CAIRO
+  cairo_t *cr;
+
+  cr = x_begin_cr_clip (f, gc);
+  x_set_cr_source_with_gc_foreground (f, gc);
+  cairo_rectangle (cr, x + 0.5, y + 0.5, width, height);
+  cairo_set_line_width (cr, 1);
+  cairo_stroke (cr);
+  x_end_cr_clip (f);
+#else
+  XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                 gc, x, y, width, height);
+#endif
+}
+
+static void
+x_clear_window (struct frame *f)
+{
+#ifdef USE_CAIRO
+  cairo_t *cr;
+
+  cr = x_begin_cr_clip (f, NULL);
+  x_set_cr_source_with_gc_background (f, f->output_data.x->normal_gc);
+  cairo_paint (cr);
+  x_end_cr_clip (f);
+#else
+  XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+#endif
+}
+
+#ifdef USE_CAIRO
+static void
+x_fill_trapezoid_for_relief (struct frame *f, GC gc, int x, int y,
+                            int width, int height, int top_p)
+{
+  cairo_t *cr;
+
+  cr = x_begin_cr_clip (f, gc);
+  x_set_cr_source_with_gc_foreground (f, gc);
+  cairo_move_to (cr, top_p ? x : x + height, y);
+  cairo_line_to (cr, x, y + height);
+  cairo_line_to (cr, top_p ? x + width - height : x + width, y + height);
+  cairo_line_to (cr, x + width, y);
+  cairo_fill (cr);
+  x_end_cr_clip (f);
+}
+
+enum corners
+  {
+    CORNER_BOTTOM_RIGHT,       /* 0 -> pi/2 */
+    CORNER_BOTTOM_LEFT,                /* pi/2 -> pi */
+    CORNER_TOP_LEFT,           /* pi -> 3pi/2 */
+    CORNER_TOP_RIGHT,          /* 3pi/2 -> 2pi */
+    CORNER_LAST
+  };
+
+static void
+x_erase_corners_for_relief (struct frame *f, GC gc, int x, int y,
+                           int width, int height,
+                           double radius, double margin, int corners)
+{
+  cairo_t *cr;
+  int i;
+
+  cr = x_begin_cr_clip (f, gc);
+  x_set_cr_source_with_gc_background (f, gc);
+  for (i = 0; i < CORNER_LAST; i++)
+    if (corners & (1 << i))
+      {
+       double xm, ym, xc, yc;
+
+       if (i == CORNER_TOP_LEFT || i == CORNER_BOTTOM_LEFT)
+         xm = x - margin, xc = xm + radius;
+       else
+         xm = x + width + margin, xc = xm - radius;
+       if (i == CORNER_TOP_LEFT || i == CORNER_TOP_RIGHT)
+         ym = y - margin, yc = ym + radius;
+       else
+         ym = y + height + margin, yc = ym - radius;
+
+       cairo_move_to (cr, xm, ym);
+       cairo_arc (cr, xc, yc, radius, i * M_PI_2, (i + 1) * M_PI_2);
+      }
+  cairo_clip (cr);
+  cairo_rectangle (cr, x, y, width, height);
+  cairo_fill (cr);
+  x_end_cr_clip (f);
+}
+
+static void
+x_draw_horizontal_wave (struct frame *f, GC gc, int x, int y,
+                       int width, int height, int wave_length)
+{
+  cairo_t *cr;
+  double dx = wave_length, dy = height - 1;
+  int xoffset, n;
+
+  cr = x_begin_cr_clip (f, gc);
+  x_set_cr_source_with_gc_foreground (f, gc);
+  cairo_rectangle (cr, x, y, width, height);
+  cairo_clip (cr);
+
+  if (x >= 0)
+    {
+      xoffset = x % (wave_length * 2);
+      if (xoffset == 0)
+       xoffset = wave_length * 2;
+    }
+  else
+    xoffset = x % (wave_length * 2) + wave_length * 2;
+  n = (width + xoffset) / wave_length + 1;
+  if (xoffset > wave_length)
+    {
+      xoffset -= wave_length;
+      --n;
+      y += height - 1;
+      dy = -dy;
+    }
+
+  cairo_move_to (cr, x - xoffset + 0.5, y + 0.5);
+  while (--n >= 0)
+    {
+      cairo_rel_line_to (cr, dx, dy);
+      dy = -dy;
+    }
+  cairo_set_line_width (cr, 1);
+  cairo_stroke (cr);
+  x_end_cr_clip (f);
+}
+#endif
 
 
 /* Return the struct x_display_info corresponding to DPY.  */
@@ -452,9 +1037,42 @@ x_set_frame_alpha (struct frame *f)
 static void
 x_update_begin (struct frame *f)
 {
-  /* Nothing to do.  */
-}
+#ifdef USE_CAIRO
+  if (! NILP (tip_frame) && XFRAME (tip_frame) == f
+      && ! FRAME_VISIBLE_P (f))
+    return;
+
+  if (! FRAME_CR_SURFACE (f))
+    {
+      int width, height;
+#ifdef USE_GTK
+      if (FRAME_GTK_WIDGET (f))
+        {
+          GdkWindow *w = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
+          width = gdk_window_get_width (w);
+          height = gdk_window_get_height (w);
+        }
+      else
+#endif
+        {
+          width = FRAME_PIXEL_WIDTH (f);
+          height = FRAME_PIXEL_HEIGHT (f);
+          if (! FRAME_EXTERNAL_TOOL_BAR (f))
+            height += FRAME_TOOL_BAR_HEIGHT (f);
+          if (! FRAME_EXTERNAL_MENU_BAR (f))
+            height += FRAME_MENU_BAR_HEIGHT (f);
+        }
 
+      if (width > 0 && height > 0)
+        {
+          block_input();
+          FRAME_CR_SURFACE (f) = cairo_image_surface_create
+            (CAIRO_FORMAT_ARGB32, width, height);
+          unblock_input();
+        }
+    }
+#endif /* USE_CAIRO */
+}
 
 /* Start update of window W.  */
 
@@ -496,8 +1114,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)  */
@@ -517,39 +1139,38 @@ x_draw_window_divider (struct window *w, int x0, int x1, 
int y0, int y1)
                              ? face_last->foreground
                              : FRAME_FOREGROUND_PIXEL (f));
   Display *display = FRAME_X_DISPLAY (f);
-  Window window = FRAME_X_WINDOW (f);
 
   if (y1 - y0 > x1 - x0 && x1 - x0 > 2)
     /* Vertical.  */
     {
       XSetForeground (display, f->output_data.x->normal_gc, color_first);
-      XFillRectangle (display, window, f->output_data.x->normal_gc,
-                     x0, y0, 1, y1 - y0);
+      x_fill_rectangle (f, f->output_data.x->normal_gc,
+                       x0, y0, 1, y1 - y0);
       XSetForeground (display, f->output_data.x->normal_gc, color);
-      XFillRectangle (display, window, f->output_data.x->normal_gc,
-                     x0 + 1, y0, x1 - x0 - 2, y1 - y0);
+      x_fill_rectangle (f, f->output_data.x->normal_gc,
+                       x0 + 1, y0, x1 - x0 - 2, y1 - y0);
       XSetForeground (display, f->output_data.x->normal_gc, color_last);
-      XFillRectangle (display, window, f->output_data.x->normal_gc,
-                     x1 - 1, y0, 1, y1 - y0);
+      x_fill_rectangle (f, f->output_data.x->normal_gc,
+                       x1 - 1, y0, 1, y1 - y0);
     }
   else if (x1 - x0 > y1 - y0 && y1 - y0 > 3)
     /* Horizontal.  */
     {
       XSetForeground (display, f->output_data.x->normal_gc, color_first);
-      XFillRectangle (display, window, f->output_data.x->normal_gc,
-                     x0, y0, x1 - x0, 1);
+      x_fill_rectangle (f, f->output_data.x->normal_gc,
+                       x0, y0, x1 - x0, 1);
       XSetForeground (display, f->output_data.x->normal_gc, color);
-      XFillRectangle (display, window, f->output_data.x->normal_gc,
-                     x0, y0 + 1, x1 - x0, y1 - y0 - 2);
+      x_fill_rectangle (f, f->output_data.x->normal_gc,
+                       x0, y0 + 1, x1 - x0, y1 - y0 - 2);
       XSetForeground (display, f->output_data.x->normal_gc, color_last);
-      XFillRectangle (display, window, f->output_data.x->normal_gc,
-                     x0, y1 - 1, x1 - x0, 1);
+      x_fill_rectangle (f, f->output_data.x->normal_gc,
+                       x0, y1 - 1, x1 - x0, 1);
     }
   else
     {
       XSetForeground (display, f->output_data.x->normal_gc, color);
-      XFillRectangle (display, window, f->output_data.x->normal_gc,
-                     x0, y0, x1 - x0, y1 - y0);
+      x_fill_rectangle (f, f->output_data.x->normal_gc,
+                       x0, y0, x1 - x0, y1 - y0);
     }
 }
 
@@ -612,6 +1233,43 @@ x_update_end (struct frame *f)
   /* Mouse highlight may be displayed again.  */
   MOUSE_HL_INFO (f)->mouse_face_defer = false;
 
+#ifdef USE_CAIRO
+  if (FRAME_CR_SURFACE (f))
+    {
+      cairo_t *cr = 0;
+      block_input();
+#if defined (USE_GTK) && defined (HAVE_GTK3)
+      if (FRAME_GTK_WIDGET (f))
+        {
+          GdkWindow *w = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
+          cr = gdk_cairo_create (w);
+        }
+      else
+#endif
+        {
+          cairo_surface_t *surface;
+          int width = FRAME_PIXEL_WIDTH (f);
+          int height = FRAME_PIXEL_HEIGHT (f);
+          if (! FRAME_EXTERNAL_TOOL_BAR (f))
+            height += FRAME_TOOL_BAR_HEIGHT (f);
+          if (! FRAME_EXTERNAL_MENU_BAR (f))
+            height += FRAME_MENU_BAR_HEIGHT (f);
+          surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
+                                               FRAME_X_WINDOW (f),
+                                               FRAME_DISPLAY_INFO (f)->visual,
+                                               width,
+                                               height);
+          cr = cairo_create (surface);
+          cairo_surface_destroy (surface);
+        }
+
+      cairo_set_source_surface (cr, FRAME_CR_SURFACE (f), 0, 0);
+      cairo_paint (cr);
+      cairo_destroy (cr);
+      unblock_input ();
+    }
+#endif /* USE_CAIRO */
+
 #ifndef XFlush
   block_input ();
   XFlush (FRAME_X_DISPLAY (f));
@@ -638,18 +1296,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 +1347,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 +1378,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 +1445,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 +1655,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 +1675,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 +1727,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 +1751,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 +1794,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 +1846,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 +1980,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 +2552,79 @@ x_draw_relief_rect (struct frame *f,
                    bool left_p, bool right_p,
                    XRectangle *clip_rect)
 {
+#ifdef USE_CAIRO
+  GC top_left_gc, bottom_right_gc;
+  int corners = 0;
+
+  if (raised_p)
+    {
+      top_left_gc = f->output_data.x->white_relief.gc;
+      bottom_right_gc = f->output_data.x->black_relief.gc;
+    }
+  else
+    {
+      top_left_gc = f->output_data.x->black_relief.gc;
+      bottom_right_gc = f->output_data.x->white_relief.gc;
+    }
+
+  x_set_clip_rectangles (f, top_left_gc, clip_rect, 1);
+  x_set_clip_rectangles (f, bottom_right_gc, clip_rect, 1);
+
+  if (left_p)
+    {
+      x_fill_rectangle (f, top_left_gc, left_x, top_y,
+                       width, bottom_y + 1 - top_y);
+      if (top_p)
+       corners |= 1 << CORNER_TOP_LEFT;
+      if (bot_p)
+       corners |= 1 << CORNER_BOTTOM_LEFT;
+    }
+  if (right_p)
+    {
+      x_fill_rectangle (f, bottom_right_gc, right_x + 1 - width, top_y,
+                       width, bottom_y + 1 - top_y);
+      if (top_p)
+       corners |= 1 << CORNER_TOP_RIGHT;
+      if (bot_p)
+       corners |= 1 << CORNER_BOTTOM_RIGHT;
+    }
+  if (top_p)
+    {
+      if (!right_p)
+       x_fill_rectangle (f, top_left_gc, left_x, top_y,
+                         right_x + 1 - left_x, width);
+      else
+       x_fill_trapezoid_for_relief (f, top_left_gc, left_x, top_y,
+                                    right_x + 1 - left_x, width, 1);
+    }
+  if (bot_p)
+    {
+      if (!left_p)
+       x_fill_rectangle (f, bottom_right_gc, left_x, bottom_y + 1 - width,
+                         right_x + 1 - left_x, width);
+      else
+       x_fill_trapezoid_for_relief (f, bottom_right_gc,
+                                    left_x, bottom_y + 1 - width,
+                                    right_x + 1 - left_x, width, 0);
+    }
+  if (left_p && width != 1)
+    x_fill_rectangle (f, bottom_right_gc, left_x, top_y,
+                     1, bottom_y + 1 - top_y);
+  if (top_p && width != 1)
+    x_fill_rectangle (f, bottom_right_gc, left_x, top_y,
+                     right_x + 1 - left_x, 1);
+  if (corners)
+    {
+      XSetBackground (FRAME_X_DISPLAY (f), top_left_gc,
+                     FRAME_BACKGROUND_PIXEL (f));
+      x_erase_corners_for_relief (f, top_left_gc, left_x, top_y,
+                                 right_x - left_x + 1, bottom_y - top_y + 1,
+                                 6, 1, corners);
+    }
+
+  x_reset_clip_rectangles (f, top_left_gc);
+  x_reset_clip_rectangles (f, bottom_right_gc);
+#else
   Display *dpy = FRAME_X_DISPLAY (f);
   Window window = FRAME_X_WINDOW (f);
   int i;
@@ -1970,7 +2713,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 +2735,28 @@ x_draw_box_rect (struct glyph_string *s,
 
   XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
   XSetForeground (s->display, s->gc, s->face->box_color);
-  XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
+  x_set_clip_rectangles (s->f, s->gc, clip_rect, 1);
 
   /* Top.  */
-  XFillRectangle (s->display, s->window, s->gc,
+  x_fill_rectangle (s->f, s->gc,
                  left_x, top_y, right_x - left_x + 1, width);
 
   /* Left.  */
   if (left_p)
-    XFillRectangle (s->display, s->window, s->gc,
+    x_fill_rectangle (s->f, s->gc,
                    left_x, top_y, width, bottom_y - top_y + 1);
 
   /* Bottom.  */
-  XFillRectangle (s->display, s->window, s->gc,
+  x_fill_rectangle (s->f, s->gc,
                  left_x, bottom_y - width + 1, right_x - left_x + 1, width);
 
   /* Right.  */
   if (right_p)
-    XFillRectangle (s->display, s->window, s->gc,
+    x_fill_rectangle (s->f, s->gc,
                    right_x - width + 1, top_y, width, bottom_y - top_y + 1);
 
   XSetForeground (s->display, s->gc, xgcv.foreground);
-  XSetClipMask (s->display, s->gc, None);
+  x_reset_clip_rectangles (s->f, s->gc);
 }
 
 
@@ -2142,7 +2887,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 +2896,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 +3035,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 +3043,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 +3058,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 +3167,25 @@ x_draw_image_glyph_string (struct glyph_string *s)
     }
 
   /* Draw the foreground.  */
-  if (pixmap != None)
+#ifdef USE_CAIRO
+  if (s->img->cr_data)
+    {
+      cairo_t *cr = x_begin_cr_clip (s->f, s->gc);
+
+      int x = s->x + s->img->hmargin;
+      int y = s->y + s->img->vmargin;
+      int width = s->background_width;
+
+      cairo_set_source_surface (cr, s->img->cr_data,
+                                x - s->slice.x,
+                                y - s->slice.y);
+      cairo_rectangle (cr, x, y, width, height);
+      cairo_fill (cr);
+      x_end_cr_clip (s->f);
+    }
+  else
+#endif
+    if (pixmap != None)
     {
       x_draw_image_foreground_1 (s, pixmap);
       x_set_glyph_string_clipping (s);
@@ -2505,13 +3268,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,11 +3282,11 @@ 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);
            }
 
-         XSetClipMask (s->display, gc, None);
+         x_reset_clip_rectangles (s->f, gc);
        }
     }
   else if (!s->background_filled_p)
@@ -2560,6 +3323,10 @@ static void
 x_draw_underwave (struct glyph_string *s)
 {
   int wave_height = 3, wave_length = 2;
+#ifdef USE_CAIRO
+  x_draw_horizontal_wave (s->f, s->gc, s->x, s->ybase - wave_height + 3,
+                         s->width, wave_height, wave_length);
+#else  /* not USE_CAIRO */
   int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax;
   bool odd;
   XRectangle wave_clip, string_clip, final_clip;
@@ -2609,6 +3376,7 @@ x_draw_underwave (struct glyph_string *s)
 
   /* Restore previous clipping rectangle(s) */
   XSetClipRectangles (s->display, s->gc, 0, 0, s->clip, s->num_clips, 
Unsorted);
+#endif /* not USE_CAIRO */
 }
 
 
@@ -2778,14 +3546,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 +3565,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 +3585,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 +3621,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 +3646,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 +3655,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;
 }
 
@@ -2918,11 +3686,32 @@ 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 (struct frame *f, int x, int y, int width, int height)
 {
+#ifdef USE_CAIRO
+  cairo_t *cr;
+
   eassert (width > 0 && height > 0);
-  XClearArea (dpy, window, x, y, width, height, False);
+
+  cr = x_begin_cr_clip (f, NULL);
+  x_set_cr_source_with_gc_background (f, f->output_data.x->normal_gc);
+  cairo_rectangle (cr, x, y, width, height);
+  cairo_fill (cr);
+  x_end_cr_clip (f);
+#else
+  x_clear_area1 (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                x, y, width, height, False);
+#endif
 }
 
 
@@ -2937,7 +3726,7 @@ x_clear_frame (struct frame *f)
 
   block_input ();
 
-  XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+  x_clear_window (f);
 
   /* We have to clear the scroll bars.  If we have changed colors or
      something like that, then they should be notified.  */
@@ -3243,12 +4032,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 ();
 }
@@ -4157,7 +4950,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);
@@ -4251,7 +5044,7 @@ x_window_to_menu_bar (Window window)
 #ifdef USE_TOOLKIT_SCROLL_BARS
 
 static void x_send_scroll_bar_event (Lisp_Object, enum scroll_bar_part,
-                                    int, int, bool);
+                                     int, int, bool);
 
 /* Lisp window being scrolled.  Set when starting to interact with
    a toolkit scroll bar, reset to nil when ending the interaction.  */
@@ -5508,8 +6301,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.  */
@@ -5641,7 +6433,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);
@@ -5652,7 +6444,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,
@@ -5666,7 +6458,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);
@@ -5733,8 +6525,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 ();
        }
 
@@ -5766,8 +6557,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));
@@ -5853,8 +6643,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 ();
        }
 
@@ -5885,7 +6674,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
@@ -6131,7 +6920,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);
 
@@ -6915,11 +7704,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
@@ -7529,6 +8317,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)
@@ -7536,6 +8327,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
         {
           xg_frame_resized (f, event->xconfigure.width,
                             event->xconfigure.height);
+#ifdef USE_CAIRO
+          x_cr_destroy_surface (f);
+#endif
           f = 0;
         }
 #endif
@@ -7957,7 +8751,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);
 }
 
 
@@ -8006,8 +8800,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);
 }
 
 
@@ -8085,7 +8879,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);
        }
@@ -8105,13 +8899,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);
     }
 }
 
@@ -8133,7 +8927,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))
@@ -10247,6 +11041,7 @@ x_free_frame_resources (struct frame *f)
        free_frame_xic (f);
 #endif
 
+      x_free_cr_resources (f);
 #ifdef USE_X_TOOLKIT
       if (f->output_data.x->widget)
        {
@@ -11333,6 +12128,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;
@@ -11444,8 +12243,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,
@@ -11623,6 +12427,10 @@ x_initialize (void)
 #endif
 #endif
 
+#ifdef USE_CAIRO
+  x_cr_init_fringe (&x_redisplay_interface);
+#endif
+
   /* Note that there is no real way portable across R3/R4 to get the
      original error handler.  */
   XSetErrorHandler (x_error_handler);
diff --git a/src/xterm.h b/src/xterm.h
index 0366261..3081c16 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
@@ -636,7 +669,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
@@ -645,6 +677,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
@@ -991,7 +1031,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
@@ -1000,6 +1041,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]