]> code.delx.au - gnu-emacs/commitdiff
Merge branch 'master' into cairo
authorJan D <jan.h.d@swipnet.se>
Fri, 3 Apr 2015 10:32:13 +0000 (12:32 +0200)
committerJan D <jan.h.d@swipnet.se>
Fri, 3 Apr 2015 10:32:13 +0000 (12:32 +0200)
21 files changed:
ChangeLog
configure.ac
lisp/ChangeLog
lisp/version.el
lwlib/ChangeLog
lwlib/Makefile.in
src/ChangeLog
src/Makefile.in
src/dispextern.h
src/font.c
src/font.h
src/fringe.c
src/ftcrfont.c [new file with mode: 0644]
src/ftfont.c
src/ftfont.h
src/gtkutil.c
src/gtkutil.h
src/image.c
src/xfns.c
src/xterm.c
src/xterm.h

index 6df5a5a6344467391cac43065b9991600bb829f8..35e28ab9cc57e9099f9b2ab3c1576d061f6fa495 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
        * configure.ac: Set locallisppath to empty for NS self contained,
        unless --enable-loadllisppath was given (Bug#19850).
 
+2015-02-11  Jan Djärv  <jan.h.d@swipnet.se>
+
+       * 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  <eggert@cs.ucla.edu>
 
        * configure.ac (HAVE_LIBXML2): Add missing comma.
index 44709d47ab8bce8330298f2de0ed683cd9087639..1247f1349677739df765bfdfa8a6f2775768acef 100644 (file)
@@ -335,6 +335,7 @@ OPTION_DEFAULT_ON([tiff],[don't compile with TIFF image support])
 OPTION_DEFAULT_ON([gif],[don't compile with GIF image support])
 OPTION_DEFAULT_ON([png],[don't compile with PNG image support])
 OPTION_DEFAULT_ON([rsvg],[don't compile with SVG image support])
+OPTION_DEFAULT_OFF([cairo],[compile with Cairo drawing])
 OPTION_DEFAULT_ON([xml2],[don't compile with XML parsing support])
 OPTION_DEFAULT_ON([imagemagick],[don't compile with ImageMagick image support])
 
@@ -2427,6 +2428,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],
@@ -3098,6 +3100,30 @@ AC_SUBST(LIBOTF_LIBS)
 AC_SUBST(M17N_FLT_CFLAGS)
 AC_SUBST(M17N_FLT_LIBS)
 
+USE_CAIRO=no
+if test "${HAVE_X11}" = "yes"; then
+  if test "${with_cairo}" != "no"; then
+    CAIRO_REQUIRED=1.12.0
+    CAIRO_MODULE="cairo >= $CAIRO_REQUIRED"
+    PKG_CHECK_MODULES(CAIRO, $CAIRO_MODULE, USE_CAIRO=yes, :)
+    if test $USE_CAIRO = yes; then
+      AC_DEFINE(USE_CAIRO, 1, [Define to 1 if using cairo.])
+    else
+      AC_MSG_ERROR([cairo requested but not found.])
+    fi
+    with_xpm=no
+    with_jpeg=no
+    with_gif=no
+    with_tiff=no
+
+    CFLAGS="$CFLAGS $CAIRO_CFLAGS"
+    LIBS="$LIBS $CAIRO_LIBS"
+    AC_SUBST(CAIRO_CFLAGS)
+    AC_SUBST(CAIRO_LIBS)
+  fi
+fi
+
+
 ### Use -lXpm if available, unless `--with-xpm=no'.
 ### mingw32 doesn't use -lXpm, since it loads the library dynamically.
 ### In the Cygwin-w32 build, we need to use /usr/include/noX/X11/xpm.h
@@ -4037,8 +4063,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>
@@ -4804,7 +4830,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"
@@ -5151,6 +5179,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}"
index b004a2bba966b1012140cae27247f55081747947..d7abeac9ba6c71c65127df83019ed2c788520ebf 100644 (file)
        (package-menu--print-info, package-menu--status-predicate):
        Account for the "incompat" status.
 
+2015-02-11  Martin Rudalics  <rudalics@gmx.at>
+
+2015-02-11  Jan Djärv  <jan.h.d@swipnet.se>
+
+       * version.el (emacs-version): Add cairo version.
+
 2015-02-11  Martin Rudalics  <rudalics@gmx.at>
 
        * frame.el (toggle-frame-maximized, toggle-frame-fullscreen):
index 1837cbf0a85c3cbcdf1d0edfa89fcadb5fe21ee3..b8555cbb2f5d7e0c0b7f90c18ed5e3cbc11fb1c0 100644 (file)
@@ -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"
index e5dfed2342abc13135860ab3f87c6fd2fc895bdd..2e317dd2f667da20e07f878a228027e50f5cdd3d 100644 (file)
@@ -1,3 +1,6 @@
+2015-04-03  Jan Djärv  <jan.h.d@swipnet.se>
+
+       * Makefile.in (CAIRO_CFLAGS): Add.
 2015-03-18  Stefan Monnier  <monnier@iro.umontreal.ca>
 
        * xlwmenu.c (pop_up_menu): Remove debugging code.
index 1f332e92939d1de7f87c471fa6b7b5547aad32a4..7c91fb3a21c5856bef96beecc1d27bc6d5247d3f 100644 (file)
@@ -33,6 +33,7 @@ C_SWITCH_MACHINE=@C_SWITCH_MACHINE@
 PROFILING_CFLAGS = @PROFILING_CFLAGS@
 WARN_CFLAGS = `echo @WARN_CFLAGS@ | sed 's/ -Wwrite-strings//'`
 WERROR_CFLAGS = @WERROR_CFLAGS@
+CAIRO_CFLAGS= @CAIRO_CFLAGS@
 
 CC=@CC@
 CFLAGS=@CFLAGS@
@@ -83,6 +84,7 @@ MKDEPDIR = @MKDEPDIR@
 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
 
index 7c7892a3fe847d126c9dc189c805712d7ba46f05..8fe0e6f892a69af762500206992aa4e3cebccbf8 100644 (file)
        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  <mituharu@math.s.chiba-u.ac.jp>
+
+       * ftcrfont.c (ftcrfont_draw): Don't flush when drawing to screen.
+
+2015-02-17  YAMAMOTO Mitsuharu  <mituharu@math.s.chiba-u.ac.jp>
+
+       * 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  <mituharu@math.s.chiba-u.ac.jp>
+
+       * 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  <mituharu@math.s.chiba-u.ac.jp>
+
+       * 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  <mituharu@math.s.chiba-u.ac.jp>
+           Jan Djärv  <jan.h.d@swipnet.se>
+
+       * 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  <rudalics@gmx.at>
 
        * w32term.c (w32_read_socket): In SIZE_MAXIMIZED and
index 32615c848a73ecc01157ac87aef489ad5ee9c317..9e7a8a799150dbb2ce4e1f316a5bdcf9a7ccb720 100644 (file)
@@ -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 @@ W32_RES_LINK=@W32_RES_LINK@
 ## 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
 FONT_OBJ=@FONT_OBJ@
 
@@ -345,7 +349,7 @@ ALL_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \
   $(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) $(XFIXES_CFLAGS) \
   $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \
   $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
-  $(LIBGNUTLS_CFLAGS) $(GFILENOTIFY_CFLAGS) \
+  $(LIBGNUTLS_CFLAGS) $(GFILENOTIFY_CFLAGS) $(CAIRO_CFLAGS) \
   $(WARN_CFLAGS) $(WERROR_CFLAGS) $(CFLAGS)
 ALL_OBJC_CFLAGS=$(ALL_CFLAGS) $(GNU_OBJC_CFLAGS)
 
@@ -423,7 +427,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \
    $(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_ACL) $(LIB_CLOCK_GETTIME) \
    $(LIB_EACCESS) $(LIB_FDATASYNC) $(LIB_TIMER_TIME) $(DBUS_LIBS) \
    $(LIB_EXECINFO) $(XRANDR_LIBS) $(XINERAMA_LIBS) $(XFIXES_LIBS) \
-   $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
+   $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) $(CAIRO_LIBS) \
    $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \
    $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
    $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) \
index 329572eda229caf5e839f1d6c8051cb99447a6b3..addb43275bcc8231ce35362c76d3e3f8978a2534 100644 (file)
@@ -2941,6 +2941,9 @@ struct image
   /* Pixmaps of the image.  */
   Pixmap pixmap, mask;
 
+#ifdef USE_CAIRO
+  void *cr_data;
+#endif
 #ifdef HAVE_X_WINDOWS
   /* X images of the image, corresponding to the above Pixmaps.
      Non-NULL means it and its Pixmap counterpart may be out of sync
@@ -3302,6 +3305,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 *);
 
index b2b43c7971329125e173b631957809d60b361d47..603e998ed3f29fb953517056c5ef6e41e6ac43c6 100644 (file)
@@ -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
index efc184eef77bcb8e1f0afdf4aa595ecbac2ccb54..43e67e98c06c226638a2e801d60ac4462e6cddcb 100644 (file)
@@ -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
index 5e5ec60a48f63147fb45d974a91b35f17e4139f9..fcc5207b0629d93b8ba6ede747a8d1f1dfad78f9 100644 (file)
@@ -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 (file)
index 0000000..fc4e6da
--- /dev/null
@@ -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;
+}
+
+\f
+
+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);
+}
index 26740c263ce08128e0335d5207da61c03695a796..f19933c7ef2a23e4e719566d7a350fa7fe964d74 100644 (file)
@@ -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)
 {
index 210b634c0942befd5872cbcffca2cc9785c0594c..0cfa0ae3e3390f16b3bad6d43f757d367fcb596d 100644 (file)
@@ -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 */
 
index 41cc7a746643c2332974c740fd81c145ddfeebdc..c41bb4645a55abb16170360ed3e8dde98577351f 100644 (file)
@@ -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));
     }
@@ -2127,12 +2128,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);
@@ -3788,13 +3795,15 @@ xg_update_scrollbar_pos (struct frame *f,
           gtk_widget_show_all (wparent);
           gtk_widget_set_size_request (wscroll, width, height);
         }
+#ifndef USE_CAIRO
       gtk_widget_queue_draw (wfixed);
       gdk_window_process_all_updates ();
+#endif
       if (oldx != -1 && oldw > 0 && oldh > 0)
        /* Clear under old scroll bar position.  This must be done after
           the gtk_widget_queue_draw and gdk_window_process_all_updates
           above.  */
-       x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+       x_clear_area (f,
                      oldx, oldy, oldw, oldh);
 
       /* GTK does not redraw until the main loop is entered again, but
@@ -3860,7 +3869,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
@@ -4037,6 +4046,108 @@ xg_event_is_for_scrollbar (struct frame *f, const XEvent *event)
   return retval;
 }
 
+\f
+/***********************************************************************
+                              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 */
+
 
 \f
 /***********************************************************************
index 0ac49ca7db58bf9e46d0de082fd9fabae2823041..34338db58fb04400324023897aef829da818abf8 100644 (file)
@@ -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);
 
index df299bbd1646c4dd665f276122624432b7fb27d9..09d068725d7bcac5797d7799b8b9ecb0e0835d59 100644 (file)
@@ -1299,6 +1299,14 @@ static void
 x_clear_image (struct frame *f, struct image *img)
 {
   block_input ();
+#ifdef USE_CAIRO
+  if (img->cr_data)
+    {
+      cairo_surface_destroy ((cairo_surface_t *)img->cr_data);
+      unblock_input ();
+      return;
+    }
+#endif
   x_clear_image_1 (f, img,
                   CLEAR_IMAGE_PIXMAP | CLEAR_IMAGE_MASK | CLEAR_IMAGE_COLORS);
   unblock_input ();
@@ -5403,7 +5411,7 @@ pbm_load (struct frame *f, struct image *img)
                                 PNG
  ***********************************************************************/
 
-#if defined (HAVE_PNG) || defined (HAVE_NS)
+#if defined (HAVE_PNG) || defined (HAVE_NS) || defined (USE_CAIRO)
 
 /* Function prototypes.  */
 
@@ -5477,10 +5485,10 @@ png_image_p (Lisp_Object object)
   return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
 }
 
-#endif /* HAVE_PNG || HAVE_NS */
+#endif /* HAVE_PNG || HAVE_NS || USE_CAIRO */
 
 
-#if defined HAVE_PNG && !defined HAVE_NS
+#if defined HAVE_PNG && !defined HAVE_NS && !defined USE_CAIRO
 
 # ifdef WINDOWSNT
 /* PNG library details.  */
@@ -6049,7 +6057,44 @@ png_load (struct frame *f, struct image *img)
                         image_spec_value (img->spec, QCdata, NULL));
 }
 
-#endif /* HAVE_NS */
+#elif defined USE_CAIRO
+
+static bool
+png_load (struct frame *f, struct image *img)
+{
+  Lisp_Object file;
+  Lisp_Object specified_file = image_spec_value (img->spec, QCfile, NULL);
+  cairo_surface_t *surface;
+
+  if (! STRINGP (specified_file))
+    {
+      image_error ("Invalid image spec, file missing `%s'", img->spec, Qnil);
+      return false;
+    }
+
+  file = x_find_image_file (specified_file);
+  if (! STRINGP (file))
+    {
+      image_error ("Cannot find image file `%s'", specified_file, Qnil);
+      return false;
+    }
+
+  surface = cairo_image_surface_create_from_png (SSDATA (file));
+  if (! surface)
+    {
+      image_error ("Error creating surface from file `%s'",
+                   specified_file, Qnil);
+      return false;
+    }
+  img->width = cairo_image_surface_get_width (surface);
+  img->height = cairo_image_surface_get_height (surface);
+  img->cr_data = surface;
+  img->pixmap = 0;
+
+  return true;
+}
+
+#endif /* USE_CAIRO */
 
 
 \f
@@ -9353,7 +9398,7 @@ lookup_image_type (Lisp_Object type)
     return define_image_type (&gif_type);
 #endif
 
-#if defined (HAVE_PNG) || defined (HAVE_NS)
+#if defined (HAVE_PNG) || defined (HAVE_NS) || defined (USE_CAIRO)
   if (EQ (type, Qpng))
     return define_image_type (&png_type);
 #endif
index bd1db1013d0a9c03f8712c8d11f35c5f635755ba..80c214a7a566f1e0667c08f70a597a840f966fa0 100644 (file)
@@ -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);
@@ -6207,6 +6215,158 @@ present and mapped to the usual X keysyms.  */)
 }
 
 
+\f
+/***********************************************************************
+                              Printing
+ ***********************************************************************/
+
+#ifdef USE_CAIRO
+DEFUN ("x-export-frames", Fx_export_frames, Sx_export_frames, 0, 2, 0,
+       doc: /* XXX Experimental.  Return image data of FRAMES in TYPE format.
+FRAMES should be nil (the selected frame), a frame, or a list of
+frames (each of which corresponds to one page).  Optional arg TYPE
+should be either `pdf' (default), `png', `ps', or `svg'.  Supported
+types are determined by the compile-time configuration of cairo.  */)
+     (Lisp_Object frames, Lisp_Object type)
+{
+  Lisp_Object result, rest, tmp;
+  cairo_surface_type_t surface_type;
+
+  if (NILP (frames))
+    frames = selected_frame;
+  if (!CONSP (frames))
+    frames = list1 (frames);
+
+  tmp = Qnil;
+  for (rest = frames; CONSP (rest); rest = XCDR (rest))
+    {
+      struct frame *f = XFRAME (XCAR (rest));
+
+      if (! FRAME_LIVE_P (f) || ! FRAME_X_P (f) || ! FRAME_LIVE_P (f))
+        error ("Invalid frame");
+
+      Lisp_Object frame;
+
+      XSETFRAME (frame, f);
+      tmp = Fcons (frame, tmp);
+    }
+  frames = Fnreverse (tmp);
+
+#ifdef CAIRO_HAS_PDF_SURFACE
+  if (NILP (type) || EQ (type, intern ("pdf"))) /* XXX: Qpdf */
+    surface_type = CAIRO_SURFACE_TYPE_PDF;
+  else
+#endif
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+  if (EQ (type, intern ("png")))
+    {
+      if (!NILP (XCDR (frames)))
+       error ("PNG export cannot handle multiple frames.");
+      surface_type = CAIRO_SURFACE_TYPE_IMAGE;
+    }
+  else
+#endif
+#ifdef CAIRO_HAS_PS_SURFACE
+  if (EQ (type, intern ("ps")))
+    surface_type = CAIRO_SURFACE_TYPE_PS;
+  else
+#endif
+#ifdef CAIRO_HAS_SVG_SURFACE
+  if (EQ (type, intern ("svg")))
+    {
+      /* For now, we stick to SVG 1.1.  */
+      if (!NILP (XCDR (frames)))
+       error ("SVG export cannot handle multiple frames.");
+      surface_type = CAIRO_SURFACE_TYPE_SVG;
+    }
+  else
+#endif
+    error ("Unsupported export type");
+
+  result = x_cr_export_frames (frames, surface_type);
+
+  return result;
+}
+
+#ifdef USE_GTK
+DEFUN ("x-page-setup-dialog", Fx_page_setup_dialog, Sx_page_setup_dialog, 0, 0, 0,
+       doc: /* Pop up a page setup dialog.
+The current page setup can be obtained using `x-get-page-setup'.  */)
+     (void)
+{
+  block_input ();
+  xg_page_setup_dialog ();
+  unblock_input ();
+
+  return Qnil;
+}
+
+DEFUN ("x-get-page-setup", Fx_get_page_setup, Sx_get_page_setup, 0, 0, 0,
+       doc: /* Return the value of the current page setup.
+The return value is an alist containing the following keys:
+
+  orientation: page orientation (symbol `portrait', `landscape',
+       `reverse-portrait', or `reverse-landscape').
+  width, height: page width/height in points not including margins.
+  left-margin, right-margin, top-margin, bottom-margin: print margins,
+       which is the parts of the page that the printer cannot print
+       on, in points.
+
+The paper width can be obtained as the sum of width, left-margin, and
+right-margin values.  Likewise, the paper height is the sum of height,
+top-margin, and bottom-margin values.  */)
+     (void)
+{
+  Lisp_Object result;
+
+  block_input ();
+  result = xg_get_page_setup ();
+  unblock_input ();
+
+  return result;
+}
+
+DEFUN ("x-print-frames-dialog", Fx_print_frames_dialog, Sx_print_frames_dialog, 0, 1, "",
+       doc: /* Pop up a print dialog to print the current contents of FRAMES.
+FRAMES should be nil (the selected frame), a frame, or a list of
+frames (each of which corresponds to one page).  Each frame should be
+visible.  */)
+     (Lisp_Object frames)
+{
+  Lisp_Object rest, tmp;
+
+  if (NILP (frames))
+    frames = selected_frame;
+  if (!CONSP (frames))
+    frames = list1 (frames);
+
+  tmp = Qnil;
+  for (rest = frames; CONSP (rest); rest = XCDR (rest))
+    {
+      struct frame *f = XFRAME (XCAR (rest));
+      if (! FRAME_LIVE_P (f) || ! FRAME_X_P (f) || ! FRAME_LIVE_P (f))
+        error ("Invalid frame");
+      Lisp_Object frame;
+
+      XSETFRAME (frame, f);
+      if (!EQ (Fframe_visible_p (frame), Qt))
+       error ("Frames to be printed must be visible.");
+      tmp = Fcons (frame, tmp);
+    }
+  frames = Fnreverse (tmp);
+
+  /* Make sure the current matrices are up-to-date.  */
+  Fredisplay (Qt);
+
+  block_input ();
+  xg_print_frames_dialog (frames);
+  unblock_input ();
+
+  return Qnil;
+}
+#endif /* USE_GTK */
+#endif /* USE_CAIRO */
+
 \f
 /***********************************************************************
                            Initialization
@@ -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
 }
index bdc85ae71fc3417785f5ad34c058e6f9b0b29898..6bc79add21d9d21bb4f19185fe75dacbc797acfe 100644 (file)
@@ -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_prepare_for_xlibdraw (struct frame *);
+static void x_set_clip_rectangles (struct frame *, GC, XRectangle *, int);
+static void x_reset_clip_rectangles (struct frame *, GC);
+static void x_fill_rectangle (struct frame *, GC, int, int, 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_prepare_for_xlibdraw (f);
+  FRAME_CR_CONTEXT (f) = cr;
+  x_clear_area (f, 0, 0, width, height);
+  expose_frame (f, 0, 0, width, height);
+  FRAME_CR_CONTEXT (f) = NULL;
+}
+
+static cairo_status_t
+x_cr_accumulate_data (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_prepare_for_xlibdraw (f);
+      FRAME_CR_CONTEXT (f) = cr;
+      x_clear_area (f, 0, 0, width, height);
+      expose_frame (f, 0, 0, width, height);
+      FRAME_CR_CONTEXT (f) = NULL;
+      unblock_input ();
+
+      if (NILP (frames))
+       break;
+
+      block_input ();
+      cairo_surface_show_page (surface);
+      f = XFRAME (XCAR (frames));
+      frames = XCDR (frames);
+      width = FRAME_PIXEL_WIDTH (f);
+      height = FRAME_PIXEL_HEIGHT (f);
+      if (surface_set_size_func)
+       (*surface_set_size_func) (surface, width, height);
+      unblock_input ();
+    }
+
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+  if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
+    {
+      block_input ();
+      cairo_surface_flush (surface);
+      cairo_surface_write_to_png_stream (surface, x_cr_accumulate_data, &acc);
+      unblock_input ();
+    }
+#endif
+  unbind_to (count, Qnil);
+
+  args[0] = intern ("concat");
+  args[1] = Fnreverse (acc);
+  return Fapply (2, args);
+}
+
+#endif /* USE_CAIRO */
+
+static void
+x_prepare_for_xlibdraw (struct frame *f)
+{
+#ifdef USE_CAIRO
+  if (f == NULL)
+    {
+      Lisp_Object rest, frame;
+      FOR_EACH_FRAME (rest, frame)
+       if (FRAME_X_P (XFRAME (frame)))
+         x_prepare_for_xlibdraw (XFRAME (frame));
+    }
+  else
+    {
+      cairo_t *cr = FRAME_CR_CONTEXT (f);
+
+      if (cr)
+       {
+         cairo_surface_t *surface = cairo_get_target (cr);
+
+         if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB)
+           {
+             cairo_destroy (cr);
+             FRAME_CR_CONTEXT (f) = NULL;
+           }
+       }
+    }
+#endif
+}
+
+static void
+x_set_clip_rectangles (struct frame *f, GC gc, XRectangle *rectangles, int n)
+{
+  XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, rectangles, n, Unsorted);
+#ifdef USE_CAIRO
+  eassert (n >= 0 && n <= MAX_CLIP_RECTS);
+
+  {
+    struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 1);
+
+    gc_ext->n_clip_rects = n;
+    memcpy (gc_ext->clip_rects, rectangles, sizeof (XRectangle) * n);
+  }
+#endif
+}
+
+static void
+x_reset_clip_rectangles (struct frame *f, GC gc)
+{
+  XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
+#ifdef USE_CAIRO
+  {
+    struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
+
+    if (gc_ext)
+      gc_ext->n_clip_rects = 0;
+  }
+#endif
+}
+
+static void
+x_fill_rectangle (struct frame *f, GC gc, int x, int y, int width, int height)
+{
+#ifdef USE_CAIRO
+  cairo_t *cr;
+
+  cr = x_begin_cr_clip (f, gc);
+  x_set_cr_source_with_gc_foreground (f, gc);
+  cairo_rectangle (cr, x, y, width, height);
+  cairo_fill (cr);
+  x_end_cr_clip (f);
+#else
+  XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                 gc, x, y, width, height);
+#endif
+}
+
+static void
+x_draw_rectangle (struct frame *f, GC gc, int x, int y, int width, int height)
+{
+#ifdef USE_CAIRO
+  cairo_t *cr;
+
+  cr = x_begin_cr_clip (f, gc);
+  x_set_cr_source_with_gc_foreground (f, gc);
+  cairo_rectangle (cr, x + 0.5, y + 0.5, width, height);
+  cairo_set_line_width (cr, 1);
+  cairo_stroke (cr);
+  x_end_cr_clip (f);
+#else
+  XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                 gc, x, y, width, height);
+#endif
+}
+
+static void
+x_clear_window (struct frame *f)
+{
+#ifdef USE_CAIRO
+  cairo_t *cr;
+
+  cr = x_begin_cr_clip (f, NULL);
+  x_set_cr_source_with_gc_background (f, f->output_data.x->normal_gc);
+  cairo_paint (cr);
+  x_end_cr_clip (f);
+#else
+  XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+#endif
+}
+
+#ifdef USE_CAIRO
+static void
+x_fill_trapezoid_for_relief (struct frame *f, GC gc, int x, int y,
+                            int width, int height, int top_p)
+{
+  cairo_t *cr;
+
+  cr = x_begin_cr_clip (f, gc);
+  x_set_cr_source_with_gc_foreground (f, gc);
+  cairo_move_to (cr, top_p ? x : x + height, y);
+  cairo_line_to (cr, x, y + height);
+  cairo_line_to (cr, top_p ? x + width - height : x + width, y + height);
+  cairo_line_to (cr, x + width, y);
+  cairo_fill (cr);
+  x_end_cr_clip (f);
+}
+
+enum corners
+  {
+    CORNER_BOTTOM_RIGHT,       /* 0 -> pi/2 */
+    CORNER_BOTTOM_LEFT,                /* pi/2 -> pi */
+    CORNER_TOP_LEFT,           /* pi -> 3pi/2 */
+    CORNER_TOP_RIGHT,          /* 3pi/2 -> 2pi */
+    CORNER_LAST
+  };
+
+static void
+x_erase_corners_for_relief (struct frame *f, GC gc, int x, int y,
+                           int width, int height,
+                           double radius, double margin, int corners)
+{
+  cairo_t *cr;
+  int i;
+
+  cr = x_begin_cr_clip (f, gc);
+  x_set_cr_source_with_gc_background (f, gc);
+  for (i = 0; i < CORNER_LAST; i++)
+    if (corners & (1 << i))
+      {
+       double xm, ym, xc, yc;
+
+       if (i == CORNER_TOP_LEFT || i == CORNER_BOTTOM_LEFT)
+         xm = x - margin, xc = xm + radius;
+       else
+         xm = x + width + margin, xc = xm - radius;
+       if (i == CORNER_TOP_LEFT || i == CORNER_TOP_RIGHT)
+         ym = y - margin, yc = ym + radius;
+       else
+         ym = y + height + margin, yc = ym - radius;
+
+       cairo_move_to (cr, xm, ym);
+       cairo_arc (cr, xc, yc, radius, i * M_PI_2, (i + 1) * M_PI_2);
+      }
+  cairo_clip (cr);
+  cairo_rectangle (cr, x, y, width, height);
+  cairo_fill (cr);
+  x_end_cr_clip (f);
+}
+
+static void
+x_draw_horizontal_wave (struct frame *f, GC gc, int x, int y,
+                       int width, int height, int wave_length)
+{
+  cairo_t *cr;
+  double dx = wave_length, dy = height - 1;
+  int xoffset, n;
+
+  cr = x_begin_cr_clip (f, gc);
+  x_set_cr_source_with_gc_foreground (f, gc);
+  cairo_rectangle (cr, x, y, width, height);
+  cairo_clip (cr);
+
+  if (x >= 0)
+    {
+      xoffset = x % (wave_length * 2);
+      if (xoffset == 0)
+       xoffset = wave_length * 2;
+    }
+  else
+    xoffset = x % (wave_length * 2) + wave_length * 2;
+  n = (width + xoffset) / wave_length + 1;
+  if (xoffset > wave_length)
+    {
+      xoffset -= wave_length;
+      --n;
+      y += height - 1;
+      dy = -dy;
+    }
+
+  cairo_move_to (cr, x - xoffset + 0.5, y + 0.5);
+  while (--n >= 0)
+    {
+      cairo_rel_line_to (cr, dx, dy);
+      dy = -dy;
+    }
+  cairo_set_line_width (cr, 1);
+  cairo_stroke (cr);
+  x_end_cr_clip (f);
+}
+#endif
 
 \f
 /* Return the struct x_display_info corresponding to DPY.  */
@@ -452,9 +1037,38 @@ x_set_frame_alpha (struct frame *f)
 static void
 x_update_begin (struct frame *f)
 {
-  /* Nothing to do.  */
-}
+#ifdef USE_CAIRO
+  if (! FRAME_CR_SURFACE (f))
+    {
+      int width, height;
+#ifdef USE_GTK
+      if (FRAME_GTK_WIDGET (f))
+        {
+          GdkWindow *w = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
+          width = gdk_window_get_width (w);
+          height = gdk_window_get_height (w);
+        }
+      else
+#endif
+        {
+          width = FRAME_PIXEL_WIDTH (f);
+          height = FRAME_PIXEL_HEIGHT (f);
+          if (! FRAME_EXTERNAL_TOOL_BAR (f))
+            height += FRAME_TOOL_BAR_HEIGHT (f);
+          if (! FRAME_EXTERNAL_MENU_BAR (f))
+            height += FRAME_MENU_BAR_HEIGHT (f);
+        }
 
+      if (width > 0 && height > 0)
+        {
+          block_input();
+          FRAME_CR_SURFACE (f) = cairo_image_surface_create
+            (CAIRO_FORMAT_ARGB32, width, height);
+          unblock_input();
+        }
+    }
+#endif /* USE_CAIRO */
+}
 
 /* Start update of window W.  */
 
@@ -496,8 +1110,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 +1135,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 +1229,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 +1292,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 +1343,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 +1374,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 +1441,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 +1651,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 +1671,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 +1723,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 +1747,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 +1790,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 +1842,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 +1976,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 +2548,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 +2709,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 +2731,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 +2883,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 +2892,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 +3031,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 +3039,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 +3054,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 +3163,22 @@ x_draw_image_glyph_string (struct glyph_string *s)
     }
 
   /* Draw the foreground.  */
-  if (pixmap != None)
+  if (s->img->cr_data)
+    {
+      cairo_t *cr = x_begin_cr_clip (s->f, s->gc);
+
+      int x = s->x + s->img->hmargin;
+      int y = s->y + s->img->vmargin;
+      int width = s->background_width;
+
+      cairo_set_source_surface (cr, s->img->cr_data,
+                                x - s->slice.x,
+                                y - s->slice.y);
+      cairo_rectangle (cr, x, y, width, height);
+      cairo_fill (cr);
+      x_end_cr_clip (s->f);
+    }
+  else if (pixmap != None)
     {
       x_draw_image_foreground_1 (s, pixmap);
       x_set_glyph_string_clipping (s);
@@ -2505,13 +3261,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 +3275,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 +3316,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 +3369,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 +3539,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 +3558,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 +3578,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 +3614,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 +3639,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 +3648,7 @@ x_draw_glyph_string (struct glyph_string *s)
     }
 
   /* Reset clipping.  */
-  XSetClipMask (s->display, s->gc, None);
+  x_reset_clip_rectangles (s->f, s->gc);
   s->num_clips = 0;
 }
 
@@ -2896,6 +3657,7 @@ x_draw_glyph_string (struct glyph_string *s)
 static void
 x_shift_glyphs_for_insert (struct frame *f, int x, int y, int width, int height, int shift_by)
 {
+  x_prepare_for_xlibdraw (f);
   XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
             f->output_data.x->normal_gc,
             x, y, width, height,
@@ -2915,11 +3677,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
 }
 
 
@@ -2934,7 +3717,7 @@ x_clear_frame (struct frame *f)
 
   block_input ();
 
-  XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+  x_clear_window (f);
 
   /* We have to clear the scroll bars.  If we have changed colors or
      something like that, then they should be notified.  */
@@ -3240,12 +4023,16 @@ x_scroll_run (struct window *w, struct run *run)
   /* Cursor off.  Will be switched on again in x_update_window_end.  */
   x_clear_cursor (w);
 
+#ifdef USE_CAIRO
+  SET_FRAME_GARBAGED (f);
+#else
   XCopyArea (FRAME_X_DISPLAY (f),
             FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
             f->output_data.x->normal_gc,
             x, from_y,
             width, height,
             x, to_y);
+#endif
 
   unblock_input ();
 }
@@ -4154,7 +4941,7 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
            dpyinfo->last_mouse_glyph_frame = f1;
 
            *bar_window = Qnil;
-           *part = scroll_bar_above_handle;
+           *part = 0;
            *fp = f1;
            XSETINT (*x, win_x);
            XSETINT (*y, win_y);
@@ -4248,7 +5035,7 @@ x_window_to_menu_bar (Window window)
 #ifdef USE_TOOLKIT_SCROLL_BARS
 
 static void x_send_scroll_bar_event (Lisp_Object, enum scroll_bar_part,
-                                    int, int, bool);
+                                     int, int, bool);
 
 /* Lisp window being scrolled.  Set when starting to interact with
    a toolkit scroll bar, reset to nil when ending the interaction.  */
@@ -5505,8 +6292,7 @@ x_scroll_bar_create (struct window *w, int top, int left,
        for the case that a window has been split horizontally.  In
        this case, no clear_frame is generated to reduce flickering.  */
     if (width > 0 && window_box_height (w) > 0)
-      x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                   left, top, width, window_box_height (w));
+      x_clear_area (f, left, top, width, window_box_height (w));
 
     window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
                            /* Position and size of scroll bar.  */
@@ -5638,7 +6424,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end,
     /* Draw the empty space above the handle.  Note that we can't clear
        zero-height areas; that means "clear to end of window."  */
     if ((inside_width > 0) && (start > 0))
-      x_clear_area (FRAME_X_DISPLAY (f), w,
+      x_clear_area1 (FRAME_X_DISPLAY (f), w,
                    VERTICAL_SCROLL_BAR_LEFT_BORDER,
                    VERTICAL_SCROLL_BAR_TOP_BORDER,
                    inside_width, start);
@@ -5649,7 +6435,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end,
                      f->output_data.x->scroll_bar_foreground_pixel);
 
     /* Draw the handle itself.  */
-    XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
+    x_fill_rectangle (f, gc,
                    /* x, y, width, height */
                    VERTICAL_SCROLL_BAR_LEFT_BORDER,
                    VERTICAL_SCROLL_BAR_TOP_BORDER + start,
@@ -5663,7 +6449,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end,
     /* Draw the empty space below the handle.  Note that we can't
        clear zero-height areas; that means "clear to end of window." */
     if ((inside_width > 0) && (end < inside_height))
-      x_clear_area (FRAME_X_DISPLAY (f), w,
+      x_clear_area1 (FRAME_X_DISPLAY (f), w,
                    VERTICAL_SCROLL_BAR_LEFT_BORDER,
                    VERTICAL_SCROLL_BAR_TOP_BORDER + end,
                    inside_width, inside_height - end);
@@ -5730,8 +6516,7 @@ XTset_vertical_scroll_bar (struct window *w, int portion, int whole, int positio
       if (width > 0 && height > 0)
        {
          block_input ();
-         x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                       left, top, width, height);
+          x_clear_area (f, left, top, width, height);
          unblock_input ();
        }
 
@@ -5763,8 +6548,7 @@ XTset_vertical_scroll_bar (struct window *w, int portion, int whole, int positio
          /* Since toolkit scroll bars are smaller than the space reserved
             for them on the frame, we have to clear "under" them.  */
          if (width > 0 && height > 0)
-           x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                         left, top, width, height);
+           x_clear_area (f, left, top, width, height);
 #ifdef USE_GTK
           xg_update_scrollbar_pos (f, bar->x_window, top,
                                   left, width, max (height, 1));
@@ -5850,8 +6634,7 @@ XTset_horizontal_scroll_bar (struct window *w, int portion, int whole, int posit
 
          /* Clear also part between window_width and
             WINDOW_PIXEL_WIDTH.  */
-         x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                       left, top, pixel_width, height);
+         x_clear_area (f, left, top, pixel_width, height);
          unblock_input ();
        }
 
@@ -5882,7 +6665,7 @@ XTset_horizontal_scroll_bar (struct window *w, int portion, int whole, int posit
          /* Since toolkit scroll bars are smaller than the space reserved
             for them on the frame, we have to clear "under" them.  */
          if (width > 0 && height > 0)
-           x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+           x_clear_area (f,
                          WINDOW_LEFT_EDGE_X (w), top,
                          pixel_width - WINDOW_RIGHT_DIVIDER_WIDTH (w), height);
 #ifdef USE_GTK
@@ -6128,7 +6911,7 @@ x_scroll_bar_expose (struct scroll_bar *bar, const XEvent *event)
                    f->output_data.x->scroll_bar_foreground_pixel);
 
   /* Draw a one-pixel border just inside the edges of the scroll bar.  */
-  XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
+  x_draw_rectangle (f, gc,
                  /* x, y, width, height */
                  0, 0, bar->width - 1, bar->height - 1);
 
@@ -6912,11 +7695,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
             }
           else
            {
-#ifdef USE_GTK
+#if defined (USE_GTK) && ! defined (HAVE_GTK3) && ! defined (USE_CAIRO)
              /* This seems to be needed for GTK 2.6 and later, see
                 http://debbugs.gnu.org/cgi/bugreport.cgi?bug=15398.  */
-             x_clear_area (event->xexpose.display,
-                           event->xexpose.window,
+             x_clear_area (f,
                            event->xexpose.x, event->xexpose.y,
                            event->xexpose.width, event->xexpose.height);
 #endif
@@ -7530,6 +8312,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
     case ConfigureNotify:
       f = x_top_window_to_frame (dpyinfo, event->xconfigure.window);
+#ifdef USE_CAIRO
+      if (f) x_cr_destroy_surface (f);
+#endif
 #ifdef USE_GTK
       if (!f
           && (f = any)
@@ -7537,6 +8322,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
         {
           xg_frame_resized (f, event->xconfigure.width,
                             event->xconfigure.height);
+          x_cr_destroy_surface (f);
           f = 0;
         }
 #endif
@@ -7946,7 +8732,7 @@ x_clip_to_row (struct window *w, struct glyph_row *row,
   clip_rect.width = window_width;
   clip_rect.height = row->visible_height;
 
-  XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
+  x_set_clip_rectangles (f, gc, &clip_rect, 1);
 }
 
 
@@ -7995,8 +8781,8 @@ x_draw_hollow_cursor (struct window *w, struct glyph_row *row)
     }
   /* Set clipping, draw the rectangle, and reset clipping again.  */
   x_clip_to_row (w, row, TEXT_AREA, gc);
-  XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h - 1);
-  XSetClipMask (dpy, gc, None);
+  x_draw_rectangle (f, gc, x, y, wd, h - 1);
+  x_reset_clip_rectangles (f, gc);
 }
 
 
@@ -8074,7 +8860,7 @@ x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text
          if ((cursor_glyph->resolved_level & 1) != 0)
            x += cursor_glyph->pixel_width - width;
 
-         XFillRectangle (dpy, window, gc, x,
+         x_fill_rectangle (f, gc, x,
                          WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
                          width, row->height);
        }
@@ -8094,13 +8880,13 @@ x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text
          if ((cursor_glyph->resolved_level & 1) != 0
              && cursor_glyph->pixel_width > w->phys_cursor_width - 1)
            x += cursor_glyph->pixel_width - w->phys_cursor_width + 1;
-         XFillRectangle (dpy, window, gc, x,
-                         WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
-                                                  row->height - width),
-                         w->phys_cursor_width - 1, width);
+         x_fill_rectangle (f, gc, x,
+                           WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
+                                                     row->height - width),
+                            w->phys_cursor_width - 1, width);
        }
 
-      XSetClipMask (dpy, gc, None);
+      x_reset_clip_rectangles (f, gc);
     }
 }
 
@@ -8122,7 +8908,7 @@ x_define_frame_cursor (struct frame *f, Cursor cursor)
 static void
 x_clear_frame_area (struct frame *f, int x, int y, int width, int height)
 {
-  x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), x, y, width, height);
+  x_clear_area (f, x, y, width, height);
 #ifdef USE_GTK
   /* Must queue a redraw, because scroll bars might have been cleared.  */
   if (FRAME_GTK_WIDGET (f))
@@ -10235,6 +11021,7 @@ x_free_frame_resources (struct frame *f)
        free_frame_xic (f);
 #endif
 
+      x_prepare_for_xlibdraw (f);
 #ifdef USE_X_TOOLKIT
       if (f->output_data.x->widget)
        {
@@ -11321,6 +12108,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;
@@ -11432,8 +12223,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,
@@ -11611,6 +12407,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);
index 0366261b2f4d1da6bc647f6141fe5b09d7128973..3081c1653e37cf15ac22f2ebba348b202c2df90c 100644 (file)
@@ -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;
@@ -123,6 +139,19 @@ struct x_bitmap_record
   /* Record some info about this pixmap.  */
   int height, width, depth;
 };
+\f
+#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
+
 \f
 /* 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)