diff options
author | Jan D <jan.h.d@swipnet.se> | 2015-02-11 16:14:35 +0100 |
---|---|---|
committer | Jan D <jan.h.d@swipnet.se> | 2015-02-11 16:14:35 +0100 |
commit | dddcc0e78452f2186c132823a33a174d2596ba33 (patch) | |
tree | 8369d54925d9ea4b60ecf6a53c6a321dffd194f9 /src | |
parent | 061c7e2b5a5a5854b2b85f2ace5b1d9222dd7f11 (diff) | |
download | emacs-dddcc0e78452f2186c132823a33a174d2596ba33.tar.gz |
Add cairo drawing.
* configure.ac (with-cairo): New option.
(USE_CAIRO): Default to yes for Gtk+ 3. Add code to test for cairo,
set CAIRO_CFLAGS, CAIRO_LIBS. Add ftcrfonto to FONT_OBJ if cairo.
Output "Does Emacs use cairo?".
* lisp/version.el (emacs-version): Add cairo version.
* src/Makefile.in (CAIRO_CFLAGS, CAIRO_LIBS): New variables.
(FONT_OBJ): Add comment about ftcrfont.
(ALL_CFLAGS): Add CAIRO_CFLAGS.
(LIBES): Add CAIRO_LIBS.
* src/dispextern.h (struct image): Add cr_data for cairo.
(x_cr_init_fringe): Declare.
* src/font.c (syms_of_font): Call syms_of_ftcrfont for cairo.
* src/font.h (ftcrfont_driver, syms_of_ftcrfont): Declare
* src/fringe.c (x_cr_init_fringe): New function name that shares code
with w32_init_fringe.
* src/ftcrfont.c: New font driver for cairo, based on the ftfont driver.
* src/ftfont.c (ftfont_info_size); New global variable.
(ftfont_open2): New extern function almost the same as old ftfont_open,
but takes the font_object as argument.
(ftfont_open): Build font object and call ftfont_open2.
* src/ftfont.h (ftfont_open2, ftfont_info_size): Declare.
* src/gtkutil.c (xg_clear_under_internal_border)
(xg_update_scrollbar_pos, xg_update_horizontal_scrollbar_pos): Only
queue_draw if not cairo. Change args to x_clear_area.
(xg_get_font): Use Qftcr when using cairo, Qxft otherwise.
(xg_page_setup_dialog, xg_get_page_setup, draw_page)
(xg_print_frames_dialog): New functions for printing.
* src/gtkutil.h (xg_page_setup_dialog, xg_get_page_setup)
(xg_print_frames_dialog): Declare.
* src/image.c: Add defined (USE_CAIRO) for PNG.
Add !defined USE_CAIRO for W32 PNG code.
(x_clear_image): If cairo, destroy the surface in cr_data.
(png_load): Add new cairo compatible implementation.
(lookup_image_type): Add defined (USE_CAIRO) for define png_type.
* src/xfns.c: New section Printing.
(x-export-frames, x-page-setup-dialog, x-get-page-setup)
(x-print-frames-dialog): New printing functions.
(Fx_create_frame, x_create_tip_frame): Register ftcrfont if
cairo.
(syms_of_xfns): Defsym Qorientation, Qtop_margin, Qbottom_margin,
Qportrait, Qlandscape, Qreverse_portrait, Qreverse_landscape).
(syms_of_xfns): Provide cairo and defvar cairo-version-string.
defsubr Sx_page_setup_dialog, Sx_get_page_setup, Sx_print_frames_dialog.
* src/xterm.c (x_clear_area1, x_prepare_for_xlibdraw)
(x_set_clip_rectangles, x_reset_clip_rectangles, x_fill_rectangle)
(x_draw_rectangle, x_fill_trapezoid_for_relief, x_clear_window)
(x_gc_get_ext_data, x_extension_initialize, x_cr_accumulate_data):
Declare.
(FRAME_CR_CONTEXT, FRAME_CR_SURFACE): New macros.
(max_fringe_bmp, fringe_bmp): New variables.
(x_gc_get_ext_data, x_extension_initialize)
(x_cr_destroy_surface, x_begin_cr_clip, x_end_cr_clip)
(x_set_cr_source_with_gc_foreground)
(x_set_cr_source_with_gc_background, x_cr_define_fringe_bitmap)
(x_cr_destroy_fringe_bitmap, x_cr_draw_image, x_cr_draw_frame)
(x_cr_accumulate_data, x_cr_destroy, x_cr_export_frames)
(x_prepare_for_xlibdraw, x_set_clip_rectangles)
(x_reset_clip_rectangles, x_fill_rectangle, x_draw_rectangle)
(x_clear_window, x_fill_trapezoid_for_relief): New functions.
(x_update_begin): Create cairo surface if needed.
(x_draw_vertical_window_border): Call x_fill_rectangle for cairo.
(x_update_end): Paint cairo drawing surface to xlib surface.
(x_clear_under_internal_border, x_after_update_window_line): Adjust
arguments to x_clear_area.
(x_draw_fringe_bitmap): Call x_fill_rectangle. Get GC values and
call x_cr_draw_image for cairo. Call x_reset_clip_rectangles instead
of XSetClipMask.
(x_set_glyph_string_clipping)
(x_set_glyph_string_clipping_exactly): Use x_set_clip_rectangles
instead of XSetClipRectangles.
(x_clear_glyph_string_rect, x_draw_glyph_string_background): Use
x_fill_rectangle instead of XFillRectangle.
(x_draw_glyph_string_foreground)
(x_draw_composite_glyph_string_foreground)
(x_draw_glyphless_glyph_string_foreground): Use x_draw_rectangle instead
of XDrawRectangle.
(x_draw_relief_rect): Add code for USE_CAIRO.
Call x_reset_clip_rectangles instead of XSetClipMask.
(x_draw_box_rect): x_set_clip_rectangles instead of XSetClipRectangles,
x_fill_rectangle instead of XFillRectangle, x_reset_clip_rectangles
instead of XSetClipMask.
(x_draw_image_foreground, x_draw_image_foreground_1):
x_draw_rectangle instead of XDrawRectangle.
(x_draw_glyph_string_bg_rect): x_fill_rectangle instead of
XFillRectangle.
(x_draw_image_glyph_string): If img has cr_data, use it as
a cairo surface.
(x_draw_stretch_glyph_string): x_set_clip_rectangles instead of
XSetClipRectangles, x_fill_rectangle instead of XFillRectangle.
(x_draw_glyph_string): x_fill_rectangle instead of XFillRectangle.,
x_reset_clip_rectangles instead of XSetClipMask.
(x_shift_glyphs_for_insert): Call x_prepare_for_xlibdraw.
(x_clear_area1): New function that calls XClearArea.
(x_clear_area): Takes frame as parameter, calls x_clear_area1 for
non-cairo.
(x_clear_frame): x_clear_window instead of XClearWindow.
(x_scroll_run): Set frame garbaged if cairo.
(XTmouse_position): Initialize *part to 0.
(x_scroll_bar_create): Adjust arguments to x_clear_area.
(x_scroll_bar_set_handle): x_clear_area1 instead of x_clear_area,
x_fill_rectangle instead of XFillRectangle.
(XTset_vertical_scroll_bar, XTset_horizontal_scroll_bar): Adjust
arguments to x_clear_area.
(x_scroll_bar_expose): x_draw_rectangle instead of XDrawRectangle.
(handle_one_xevent): Adjust arguments to x_clear_area.
Destroy cairo surface for frame if ConfigureNotify.
(x_clip_to_row): x_set_clip_rectangles instead of XSetClipRectangles.
(x_draw_hollow_cursor): x_draw_rectangle instead of XDrawRectangle,
x_reset_clip_rectangles instead of XSetClipMask.
(x_draw_bar_cursor): x_fill_rectangle instead of XFillRectangle,
x_reset_clip_rectangles instead of XSetClipMask.
(x_clear_frame_area): Adjust arguments to x_clear_area.
(x_free_frame_resources): Call x_prepare_for_xlibdraw.
(x_term_init): Call x_extension_initialize if cairo.
(x_redisplay_interface): Add x_cr_define_fringe_bitmap,
x_cr_destroy_fringe_bitmap for cairo.
(x_initialize): Call x_cr_init_fringe for cairo.
* src/xterm.h: Add include of cairo header files.
(x_bitmap_record): Add img if cairo.
(x_gc_ext_data): New struct for cairo.
(x_display_info): Add ext_codes for cairo.
(x_output): Add cr_context and cr_surface for cairo.
(x_clear_area): Change arguments from Display*/Window to frame pointer.
(x_query_color, x_begin_cr_clip, x_end_cr_clip)
(x_set_cr_source_with_gc_foreground, x_set_cr_source_with_gc_background)
(x_cr_draw_frame, x_cr_export_frames): Declare.
Diffstat (limited to 'src')
-rw-r--r-- | src/ChangeLog | 138 | ||||
-rw-r--r-- | src/Makefile.in | 8 | ||||
-rw-r--r-- | src/dispextern.h | 6 | ||||
-rw-r--r-- | src/font.c | 4 | ||||
-rw-r--r-- | src/font.h | 4 | ||||
-rw-r--r-- | src/fringe.c | 8 | ||||
-rw-r--r-- | src/ftcrfont.c | 314 | ||||
-rw-r--r-- | src/ftfont.c | 26 | ||||
-rw-r--r-- | src/ftfont.h | 5 | ||||
-rw-r--r-- | src/gtkutil.c | 131 | ||||
-rw-r--r-- | src/gtkutil.h | 6 | ||||
-rw-r--r-- | src/image.c | 55 | ||||
-rw-r--r-- | src/xfns.c | 195 | ||||
-rw-r--r-- | src/xterm.c | 895 | ||||
-rw-r--r-- | src/xterm.h | 53 |
15 files changed, 1746 insertions, 102 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index f8e65d5d91d..e361fe286e4 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,141 @@ +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 diff --git a/src/Makefile.in b/src/Makefile.in index 32615c848a7..9e7a8a79915 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -218,6 +218,9 @@ CFLAGS_SOUND= @CFLAGS_SOUND@ RSVG_LIBS= @RSVG_LIBS@ RSVG_CFLAGS= @RSVG_CFLAGS@ +CAIRO_LIBS= @CAIRO_LIBS@ +CAIRO_CFLAGS= @CAIRO_CFLAGS@ + IMAGEMAGICK_LIBS= @IMAGEMAGICK_LIBS@ IMAGEMAGICK_CFLAGS= @IMAGEMAGICK_CFLAGS@ @@ -273,6 +276,7 @@ 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) \ diff --git a/src/dispextern.h b/src/dispextern.h index 5f730df514b..b9db3f808b5 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -2939,6 +2939,9 @@ struct image /* Pixmaps of the image. */ Pixmap pixmap, mask; +#ifdef USE_CAIRO + void *cr_data; +#endif #ifdef HAVE_X_WINDOWS /* X images of the image, corresponding to the above Pixmaps. Non-NULL means it and its Pixmap counterpart may be out of sync @@ -3300,6 +3303,9 @@ bool update_window_fringes (struct window *, bool); void w32_init_fringe (struct redisplay_interface *); void w32_reset_fringes (void); #endif +#ifdef USE_CAIRO +void x_cr_init_fringe (struct redisplay_interface *); +#endif extern unsigned row_hash (struct glyph_row *); diff --git a/src/font.c b/src/font.c index b2b43c79713..603e998ed3f 100644 --- a/src/font.c +++ b/src/font.c @@ -5280,11 +5280,15 @@ EMACS_FONT_LOG is set. Otherwise, it is set to t. */); #ifdef HAVE_FREETYPE syms_of_ftfont (); #ifdef HAVE_X_WINDOWS +#ifdef USE_CAIRO + syms_of_ftcrfont (); +#else syms_of_xfont (); syms_of_ftxfont (); #ifdef HAVE_XFT syms_of_xftfont (); #endif /* HAVE_XFT */ +#endif /* not USE_CAIRO */ #endif /* HAVE_X_WINDOWS */ #else /* not HAVE_FREETYPE */ #ifdef HAVE_X_WINDOWS diff --git a/src/font.h b/src/font.h index efc184eef77..43e67e98c06 100644 --- a/src/font.h +++ b/src/font.h @@ -844,6 +844,10 @@ extern struct font_driver nsfont_driver; extern void syms_of_nsfont (void); extern void syms_of_macfont (void); #endif /* HAVE_NS */ +#ifdef USE_CAIRO +extern struct font_driver ftcrfont_driver; +extern void syms_of_ftcrfont (void); +#endif #ifndef FONT_DEBUG #define FONT_DEBUG diff --git a/src/fringe.c b/src/fringe.c index 5e5ec60a48f..27b10035556 100644 --- a/src/fringe.c +++ b/src/fringe.c @@ -1731,10 +1731,14 @@ init_fringe (void) fringe_faces = xzalloc (max_fringe_bitmaps * sizeof *fringe_faces); } -#ifdef HAVE_NTGUI +#if defined (HAVE_NTGUI) || defined (USE_CAIRO) void +#ifdef HAVE_NTGUI w32_init_fringe (struct redisplay_interface *rif) +#else +x_cr_init_fringe (struct redisplay_interface *rif) +#endif { int bt; @@ -1747,7 +1751,9 @@ w32_init_fringe (struct redisplay_interface *rif) rif->define_fringe_bitmap (bt, fb->bits, fb->height, fb->width); } } +#endif +#ifdef HAVE_NTGUI void w32_reset_fringes (void) { diff --git a/src/ftcrfont.c b/src/ftcrfont.c new file mode 100644 index 00000000000..d60c1202b9d --- /dev/null +++ b/src/ftcrfont.c @@ -0,0 +1,314 @@ +/* ftcrfont.c -- FreeType font driver on cairo. + Copyright (C) 2015 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ + + +#include <config.h> +#include <stdio.h> +#include <cairo-ft.h> + +#include "lisp.h" +#include "dispextern.h" +#include "xterm.h" +#include "frame.h" +#include "blockinput.h" +#include "character.h" +#include "charset.h" +#include "fontset.h" +#include "font.h" +#include "ftfont.h" + +/* FTCR font driver. */ + +/* The actual structure for ftcr font that can be casted to struct + font. */ + +struct ftcrfont_info +{ + struct font font; + /* The following six members must be here in this order to be + compatible with struct ftfont_info (in ftfont.c). */ +#ifdef HAVE_LIBOTF + bool maybe_otf; /* Flag to tell if this may be OTF or not. */ + OTF *otf; +#endif /* HAVE_LIBOTF */ + FT_Size ft_size; + int index; + FT_Matrix matrix; + + cairo_font_face_t *cr_font_face; + /* To prevent cairo from cluttering the activated FT_Size maintained + in ftfont.c, we activate this special FT_Size before drawing. */ + FT_Size ft_size_draw; + /* Font metrics cache. */ + struct font_metrics **metrics; + short metrics_nrows; +}; + +#define METRICS_NCOLS_PER_ROW (128) + +enum metrics_status + { + METRICS_INVALID = -1, /* metrics entry is invalid */ + }; + +#define METRICS_STATUS(metrics) ((metrics)->ascent + (metrics)->descent) +#define METRICS_SET_STATUS(metrics, status) \ + ((metrics)->ascent = 0, (metrics)->descent = (status)) + +/* Prototypes for helper function. */ +static int ftcrfont_glyph_extents (struct font *, unsigned, + struct font_metrics *); + +/* Prototypes for font-driver methods. */ +static Lisp_Object ftcrfont_list (struct frame*, Lisp_Object); +static Lisp_Object ftcrfont_match (struct frame*, Lisp_Object); +static Lisp_Object ftcrfont_open (struct frame*, Lisp_Object, int); +static void ftcrfont_close (struct font *); +static void ftcrfont_text_extents (struct font *, unsigned *, int, + struct font_metrics *); +static int ftcrfont_draw (struct glyph_string *, int, int, int, int, bool); + +struct font_driver ftcrfont_driver; + +static int +ftcrfont_glyph_extents (struct font *font, + unsigned glyph, + struct font_metrics *metrics) +{ + struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) font; + int row, col; + struct font_metrics *cache; + + row = glyph / METRICS_NCOLS_PER_ROW; + col = glyph % METRICS_NCOLS_PER_ROW; + if (row >= ftcrfont_info->metrics_nrows) + { + ftcrfont_info->metrics = + xrealloc (ftcrfont_info->metrics, + sizeof (struct font_metrics *) * (row + 1)); + bzero (ftcrfont_info->metrics + ftcrfont_info->metrics_nrows, + (sizeof (struct font_metrics *) + * (row + 1 - ftcrfont_info->metrics_nrows))); + ftcrfont_info->metrics_nrows = row + 1; + } + if (ftcrfont_info->metrics[row] == NULL) + { + struct font_metrics *new; + int i; + + new = xmalloc (sizeof (struct font_metrics) * METRICS_NCOLS_PER_ROW); + for (i = 0; i < METRICS_NCOLS_PER_ROW; i++) + METRICS_SET_STATUS (new + i, METRICS_INVALID); + ftcrfont_info->metrics[row] = new; + } + cache = ftcrfont_info->metrics[row] + col; + + if (METRICS_STATUS (cache) == METRICS_INVALID) + ftfont_driver.text_extents (font, &glyph, 1, cache); + + if (metrics) + *metrics = *cache; + + return cache->width; +} + +static Lisp_Object +ftcrfont_list (struct frame *f, Lisp_Object spec) +{ + Lisp_Object list = ftfont_driver.list (f, spec), tail; + + for (tail = list; CONSP (tail); tail = XCDR (tail)) + ASET (XCAR (tail), FONT_TYPE_INDEX, Qftcr); + return list; +} + +static Lisp_Object +ftcrfont_match (struct frame *f, Lisp_Object spec) +{ + Lisp_Object entity = ftfont_driver.match (f, spec); + + if (VECTORP (entity)) + ASET (entity, FONT_TYPE_INDEX, Qftcr); + return entity; +} + +extern FT_Face ftfont_get_ft_face (Lisp_Object); + +static Lisp_Object +ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size) +{ + Lisp_Object font_object; + struct font *font; + struct ftcrfont_info *ftcrfont_info; + FT_Face ft_face; + FT_UInt size; + + block_input (); + size = XINT (AREF (entity, FONT_SIZE_INDEX)); + if (size == 0) + size = pixel_size; + font_object = font_build_object (VECSIZE (struct ftcrfont_info), + Qftcr, entity, size); + font_object = ftfont_open2 (f, entity, pixel_size, font_object); + if (NILP (font_object)) return Qnil; + + font = XFONT_OBJECT (font_object); + font->driver = &ftcrfont_driver; + ftcrfont_info = (struct ftcrfont_info *) font; + ft_face = ftcrfont_info->ft_size->face; + FT_New_Size (ft_face, &ftcrfont_info->ft_size_draw); + FT_Activate_Size (ftcrfont_info->ft_size_draw); + FT_Set_Pixel_Sizes (ft_face, 0, font->pixel_size); + ftcrfont_info->cr_font_face = + cairo_ft_font_face_create_for_ft_face (ft_face, 0); + ftcrfont_info->metrics = NULL; + ftcrfont_info->metrics_nrows = 0; + unblock_input (); + + return font_object; +} + +static void +ftcrfont_close (struct font *font) +{ + struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) font; + int i; + + block_input (); + for (i = 0; i < ftcrfont_info->metrics_nrows; i++) + if (ftcrfont_info->metrics[i]) + xfree (ftcrfont_info->metrics[i]); + if (ftcrfont_info->metrics) + xfree (ftcrfont_info->metrics); + FT_Done_Size (ftcrfont_info->ft_size_draw); + cairo_font_face_destroy (ftcrfont_info->cr_font_face); + unblock_input (); + + ftfont_driver.close (font); +} + +static void +ftcrfont_text_extents (struct font *font, + unsigned *code, + int nglyphs, + struct font_metrics *metrics) +{ + int width, i; + + block_input (); + width = ftcrfont_glyph_extents (font, code[0], metrics); + for (i = 1; i < nglyphs; i++) + { + struct font_metrics m; + int w = ftcrfont_glyph_extents (font, code[i], metrics ? &m : NULL); + + if (metrics) + { + if (width + m.lbearing < metrics->lbearing) + metrics->lbearing = width + m.lbearing; + if (width + m.rbearing > metrics->rbearing) + metrics->rbearing = width + m.rbearing; + if (m.ascent > metrics->ascent) + metrics->ascent = m.ascent; + if (m.descent > metrics->descent) + metrics->descent = m.descent; + } + width += w; + } + unblock_input (); + + if (metrics) + metrics->width = width; +} + +static int +ftcrfont_draw (struct glyph_string *s, + int from, int to, int x, int y, bool with_background) +{ + struct frame *f = s->f; + struct face *face = s->face; + struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) s->font; + cairo_t *cr; + cairo_glyph_t *glyphs; + cairo_surface_t *surface; + int len = to - from; + int i; + + block_input (); + + cr = x_begin_cr_clip (f, s->gc); + + if (with_background) + { + x_set_cr_source_with_gc_background (f, s->gc); + cairo_rectangle (cr, x, y - FONT_BASE (face->font), + s->width, FONT_HEIGHT (face->font)); + cairo_fill (cr); + } + + glyphs = alloca (sizeof (cairo_glyph_t) * len); + for (i = 0; i < len; i++) + { + unsigned code = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8) + | XCHAR2B_BYTE2 (s->char2b + from + i)); + + glyphs[i].index = code; + glyphs[i].x = x; + glyphs[i].y = y; + x += (s->padding_p ? 1 : ftcrfont_glyph_extents (s->font, code, NULL)); + } + + x_set_cr_source_with_gc_foreground (f, s->gc); + cairo_set_font_face (cr, ftcrfont_info->cr_font_face); + cairo_set_font_size (cr, s->font->pixel_size); + /* cairo_set_font_matrix */ + /* cairo_set_font_options */ + + FT_Activate_Size (ftcrfont_info->ft_size_draw); + cairo_show_glyphs (cr, glyphs, len); + surface = cairo_get_target (cr); + if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_XLIB) + cairo_surface_flush (surface); + + x_end_cr_clip (f); + + unblock_input (); + + return len; +} + + + +void +syms_of_ftcrfont (void) +{ + if (ftfont_info_size != offsetof (struct ftcrfont_info, cr_font_face)) + abort (); + + DEFSYM (Qftcr, "ftcr"); + + ftcrfont_driver = ftfont_driver; + ftcrfont_driver.type = Qftcr; + ftcrfont_driver.list = ftcrfont_list; + ftcrfont_driver.match = ftcrfont_match; + ftcrfont_driver.open = ftcrfont_open; + ftcrfont_driver.close = ftcrfont_close; + ftcrfont_driver.text_extents = ftcrfont_text_extents; + ftcrfont_driver.draw = ftcrfont_draw; + register_font_driver (&ftcrfont_driver, NULL); +} diff --git a/src/ftfont.c b/src/ftfont.c index adf188815de..75d59c16294 100644 --- a/src/ftfont.c +++ b/src/ftfont.c @@ -67,6 +67,8 @@ struct ftfont_info FT_Matrix matrix; }; +size_t ftfont_info_size = sizeof (struct ftfont_info); + enum ftfont_cache_for { FTFONT_CACHE_FOR_FACE, @@ -1161,8 +1163,11 @@ ftfont_list_family (struct frame *f) } -static Lisp_Object -ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size) +Lisp_Object +ftfont_open2 (struct frame *f, + Lisp_Object entity, + int pixel_size, + Lisp_Object font_object) { struct ftfont_info *ftfont_info; struct font *font; @@ -1170,7 +1175,7 @@ ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size) FT_Face ft_face; FT_Size ft_size; FT_UInt size; - Lisp_Object val, filename, idx, cache, font_object; + Lisp_Object val, filename, idx, cache; bool scalable; int spacing; int i; @@ -1210,8 +1215,6 @@ ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size) return Qnil; } - font_object = font_build_object (VECSIZE (struct ftfont_info), - Qfreetype, entity, size); ASET (font_object, FONT_FILE_INDEX, filename); font = XFONT_OBJECT (font_object); ftfont_info = (struct ftfont_info *) font; @@ -1294,6 +1297,19 @@ ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size) return font_object; } +static Lisp_Object +ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size) +{ + Lisp_Object font_object; + FT_UInt size; + size = XINT (AREF (entity, FONT_SIZE_INDEX)); + if (size == 0) + size = pixel_size; + font_object = font_build_object (VECSIZE (struct ftfont_info), + Qfreetype, entity, size); + return ftfont_open2 (f, entity, pixel_size, font_object); +} + static void ftfont_close (struct font *font) { diff --git a/src/ftfont.h b/src/ftfont.h index 210b634c094..0cfa0ae3e33 100644 --- a/src/ftfont.h +++ b/src/ftfont.h @@ -37,6 +37,11 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #endif /* HAVE_LIBOTF */ extern FcCharSet *ftfont_get_fc_charset (Lisp_Object); +extern Lisp_Object ftfont_open2 (struct frame *f, + Lisp_Object entity, + int pixel_size, + Lisp_Object font_object); +extern size_t ftfont_info_size; #endif /* EMACS_FTFONT_H */ diff --git a/src/gtkutil.c b/src/gtkutil.c index 6f1707894c1..f111ea80cef 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -845,22 +845,23 @@ xg_clear_under_internal_border (struct frame *f) { if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0) { +#ifndef USE_CAIRO GtkWidget *wfixed = f->output_data.x->edit_widget; gtk_widget_queue_draw (wfixed); gdk_window_process_all_updates (); - - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0, 0, +#endif + x_clear_area (f, 0, 0, FRAME_PIXEL_WIDTH (f), FRAME_INTERNAL_BORDER_WIDTH (f)); - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0, 0, + x_clear_area (f, 0, 0, FRAME_INTERNAL_BORDER_WIDTH (f), FRAME_PIXEL_HEIGHT (f)); - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0, + x_clear_area (f, 0, FRAME_PIXEL_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f), FRAME_PIXEL_WIDTH (f), FRAME_INTERNAL_BORDER_WIDTH (f)); - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + x_clear_area (f, FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f), 0, FRAME_INTERNAL_BORDER_WIDTH (f), FRAME_PIXEL_HEIGHT (f)); } @@ -2125,12 +2126,18 @@ xg_get_font (struct frame *f, const char *default_name) PangoWeight weight = pango_font_description_get_weight (desc); PangoStyle style = pango_font_description_get_style (desc); +#ifdef USE_CAIRO +#define FONT_TYPE_WANTED (Qftcr) +#else +#define FONT_TYPE_WANTED (Qxft) +#endif font = CALLN (Ffont_spec, QCname, build_string (name), QCsize, make_float (pango_units_to_double (size)), QCweight, XG_WEIGHT_TO_SYMBOL (weight), QCslant, XG_STYLE_TO_SYMBOL (style), - QCtype, Qxft); + QCtype, + FONT_TYPE_WANTED); pango_font_description_free (desc); dupstring (&x_last_font_name, name); @@ -3784,13 +3791,15 @@ xg_update_scrollbar_pos (struct frame *f, gtk_widget_show_all (wparent); gtk_widget_set_size_request (wscroll, width, height); } +#ifndef USE_CAIRO gtk_widget_queue_draw (wfixed); gdk_window_process_all_updates (); +#endif if (oldx != -1 && oldw > 0 && oldh > 0) /* Clear under old scroll bar position. This must be done after the gtk_widget_queue_draw and gdk_window_process_all_updates above. */ - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + x_clear_area (f, oldx, oldy, oldw, oldh); /* GTK does not redraw until the main loop is entered again, but @@ -3856,7 +3865,7 @@ xg_update_horizontal_scrollbar_pos (struct frame *f, /* Clear under old scroll bar position. This must be done after the gtk_widget_queue_draw and gdk_window_process_all_updates above. */ - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + x_clear_area (f, oldx, oldy, oldw, oldh); /* GTK does not redraw until the main loop is entered again, but @@ -4033,6 +4042,112 @@ xg_event_is_for_scrollbar (struct frame *f, const XEvent *event) return retval; } + +/*********************************************************************** + Printing + ***********************************************************************/ +#ifdef USE_CAIRO +static GtkPrintSettings *print_settings = NULL; +static GtkPageSetup *page_setup = NULL; + +void +xg_page_setup_dialog () +{ + GtkPageSetup *new_page_setup = NULL; + + if (print_settings == NULL) + print_settings = gtk_print_settings_new (); + new_page_setup = gtk_print_run_page_setup_dialog (NULL, page_setup, + print_settings); + if (page_setup) + g_object_unref (page_setup); + page_setup = new_page_setup; +} + +Lisp_Object +xg_get_page_setup () +{ + Lisp_Object result, orientation_symbol; + GtkPageOrientation orientation; + + if (page_setup == NULL) + page_setup = gtk_page_setup_new (); + result = list4 (Fcons (Qleft_margin, + make_float (gtk_page_setup_get_left_margin (page_setup, + GTK_UNIT_POINTS))), + Fcons (Qright_margin, + make_float (gtk_page_setup_get_right_margin (page_setup, + GTK_UNIT_POINTS))), + Fcons (Qtop_margin, + make_float (gtk_page_setup_get_top_margin (page_setup, + GTK_UNIT_POINTS))), + Fcons (Qbottom_margin, + make_float (gtk_page_setup_get_bottom_margin (page_setup, + GTK_UNIT_POINTS)))); + result = Fcons (Fcons (Qheight, + make_float (gtk_page_setup_get_page_height (page_setup, + GTK_UNIT_POINTS))), + result); + result = Fcons (Fcons (Qwidth, + make_float (gtk_page_setup_get_page_width (page_setup, + GTK_UNIT_POINTS))), + result); + orientation = gtk_page_setup_get_orientation (page_setup); + if (orientation == GTK_PAGE_ORIENTATION_PORTRAIT) + orientation_symbol = Qportrait; + else if (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE) + orientation_symbol = Qlandscape; + else if (orientation == GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT) + orientation_symbol = Qreverse_portrait; + else if (orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE) + orientation_symbol = Qreverse_landscape; + result = Fcons (Fcons (Qorientation, orientation_symbol), result); + + return result; +} + +static void +draw_page (operation, context, page_nr, user_data) + GtkPrintOperation *operation; + GtkPrintContext *context; + gint page_nr; + gpointer user_data; +{ + Lisp_Object frames = *((Lisp_Object *) user_data); + struct frame *f = XFRAME (Fnth (make_number (page_nr), frames)); + cairo_t *cr = gtk_print_context_get_cairo_context (context); + + x_cr_draw_frame (cr, f); +} + +void +xg_print_frames_dialog (frames) + Lisp_Object frames; +{ + GtkPrintOperation *print; + GtkPrintOperationResult res; + + print = gtk_print_operation_new (); + if (print_settings != NULL) + gtk_print_operation_set_print_settings (print, print_settings); + if (page_setup != NULL) + gtk_print_operation_set_default_page_setup (print, page_setup); + gtk_print_operation_set_n_pages (print, XINT (Flength (frames))); + g_signal_connect (print, "draw-page", G_CALLBACK (draw_page), &frames); + res = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, + NULL, NULL); + if (res == GTK_PRINT_OPERATION_RESULT_APPLY) + { + if (print_settings != NULL) + g_object_unref (print_settings); + print_settings = + g_object_ref (gtk_print_operation_get_print_settings (print)); + } + g_object_unref (print); +} + +#endif /* USE_CAIRO */ + /*********************************************************************** diff --git a/src/gtkutil.h b/src/gtkutil.h index 0ac49ca7db5..34338db58fb 100644 --- a/src/gtkutil.h +++ b/src/gtkutil.h @@ -180,6 +180,12 @@ extern bool xg_prepare_tooltip (struct frame *f, extern void xg_show_tooltip (struct frame *f, int root_x, int root_y); extern bool xg_hide_tooltip (struct frame *f); +#ifdef USE_CAIRO +extern void xg_page_setup_dialog (void); +extern Lisp_Object xg_get_page_setup (void); +extern void xg_print_frames_dialog (Lisp_Object); +#endif + /* Mark all callback data that are Lisp_object:s during GC. */ extern void xg_mark_data (void); diff --git a/src/image.c b/src/image.c index df299bbd164..09d068725d7 100644 --- a/src/image.c +++ b/src/image.c @@ -1299,6 +1299,14 @@ static void x_clear_image (struct frame *f, struct image *img) { block_input (); +#ifdef USE_CAIRO + if (img->cr_data) + { + cairo_surface_destroy ((cairo_surface_t *)img->cr_data); + unblock_input (); + return; + } +#endif x_clear_image_1 (f, img, CLEAR_IMAGE_PIXMAP | CLEAR_IMAGE_MASK | CLEAR_IMAGE_COLORS); unblock_input (); @@ -5403,7 +5411,7 @@ pbm_load (struct frame *f, struct image *img) PNG ***********************************************************************/ -#if defined (HAVE_PNG) || defined (HAVE_NS) +#if defined (HAVE_PNG) || defined (HAVE_NS) || defined (USE_CAIRO) /* Function prototypes. */ @@ -5477,10 +5485,10 @@ png_image_p (Lisp_Object object) return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1; } -#endif /* HAVE_PNG || HAVE_NS */ +#endif /* HAVE_PNG || HAVE_NS || USE_CAIRO */ -#if defined HAVE_PNG && !defined HAVE_NS +#if defined HAVE_PNG && !defined HAVE_NS && !defined USE_CAIRO # ifdef WINDOWSNT /* PNG library details. */ @@ -6049,7 +6057,44 @@ png_load (struct frame *f, struct image *img) image_spec_value (img->spec, QCdata, NULL)); } -#endif /* HAVE_NS */ +#elif defined USE_CAIRO + +static bool +png_load (struct frame *f, struct image *img) +{ + Lisp_Object file; + Lisp_Object specified_file = image_spec_value (img->spec, QCfile, NULL); + cairo_surface_t *surface; + + if (! STRINGP (specified_file)) + { + image_error ("Invalid image spec, file missing `%s'", img->spec, Qnil); + return false; + } + + file = x_find_image_file (specified_file); + if (! STRINGP (file)) + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + return false; + } + + surface = cairo_image_surface_create_from_png (SSDATA (file)); + if (! surface) + { + image_error ("Error creating surface from file `%s'", + specified_file, Qnil); + return false; + } + img->width = cairo_image_surface_get_width (surface); + img->height = cairo_image_surface_get_height (surface); + img->cr_data = surface; + img->pixmap = 0; + + return true; +} + +#endif /* USE_CAIRO */ @@ -9353,7 +9398,7 @@ lookup_image_type (Lisp_Object type) return define_image_type (&gif_type); #endif -#if defined (HAVE_PNG) || defined (HAVE_NS) +#if defined (HAVE_PNG) || defined (HAVE_NS) || defined (USE_CAIRO) if (EQ (type, Qpng)) return define_image_type (&png_type); #endif diff --git a/src/xfns.c b/src/xfns.c index 629ac4b26ff..23af4388e5f 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -3052,6 +3052,9 @@ This function is an internal primitive--use `make-frame' instead. */) specbind (Qx_resource_name, name); } +#ifdef USE_CAIRO + register_font_driver (&ftcrfont_driver, f); +#else #ifdef HAVE_FREETYPE #ifdef HAVE_XFT register_font_driver (&xftfont_driver, f); @@ -3060,6 +3063,7 @@ This function is an internal primitive--use `make-frame' instead. */) #endif /* not HAVE_XFT */ #endif /* HAVE_FREETYPE */ register_font_driver (&xfont_driver, f); +#endif /* not USE_CAIRO */ x_default_parameter (f, parms, Qfont_backend, Qnil, "fontBackend", "FontBackend", RES_TYPE_STRING); @@ -5049,6 +5053,9 @@ x_create_tip_frame (struct x_display_info *dpyinfo, specbind (Qx_resource_name, name); } +#ifdef USE_CAIRO + register_font_driver (&ftcrfont_driver, f); +#else register_font_driver (&xfont_driver, f); #ifdef HAVE_FREETYPE #ifdef HAVE_XFT @@ -5057,6 +5064,7 @@ x_create_tip_frame (struct x_display_info *dpyinfo, register_font_driver (&ftxfont_driver, f); #endif /* not HAVE_XFT */ #endif /* HAVE_FREETYPE */ +#endif /* not USE_CAIRO */ x_default_parameter (f, parms, Qfont_backend, Qnil, "fontBackend", "FontBackend", RES_TYPE_STRING); @@ -6140,6 +6148,160 @@ present and mapped to the usual X keysyms. */) /*********************************************************************** + Printing + ***********************************************************************/ + +#ifdef USE_CAIRO +DEFUN ("x-export-frames", Fx_export_frames, Sx_export_frames, 0, 2, 0, + doc: /* XXX Experimental. Return image data of FRAMES in TYPE format. +FRAMES should be nil (the selected frame), a frame, or a list of +frames (each of which corresponds to one page). Optional arg TYPE +should be either `pdf' (default), `png', `ps', or `svg'. Supported +types are determined by the compile-time configuration of cairo. */) + (frames, type) + Lisp_Object frames, type; +{ + Lisp_Object result, rest, tmp; + cairo_surface_type_t surface_type; + + if (NILP (frames)) + frames = selected_frame; + if (!CONSP (frames)) + frames = list1 (frames); + + tmp = Qnil; + for (rest = frames; CONSP (rest); rest = XCDR (rest)) + { + struct frame *f = XFRAME (XCAR (rest)); + + if (! FRAME_LIVE_P (f) || ! FRAME_X_P (f) || ! FRAME_LIVE_P (f)) + error ("Invalid frame"); + + Lisp_Object frame; + + XSETFRAME (frame, f); + tmp = Fcons (frame, tmp); + } + frames = Fnreverse (tmp); + +#ifdef CAIRO_HAS_PDF_SURFACE + if (NILP (type) || EQ (type, intern ("pdf"))) /* XXX: Qpdf */ + surface_type = CAIRO_SURFACE_TYPE_PDF; + else +#endif +#ifdef CAIRO_HAS_PNG_FUNCTIONS + if (EQ (type, intern ("png"))) + { + if (!NILP (XCDR (frames))) + error ("PNG export cannot handle multiple frames."); + surface_type = CAIRO_SURFACE_TYPE_IMAGE; + } + else +#endif +#ifdef CAIRO_HAS_PS_SURFACE + if (EQ (type, intern ("ps"))) + surface_type = CAIRO_SURFACE_TYPE_PS; + else +#endif +#ifdef CAIRO_HAS_SVG_SURFACE + if (EQ (type, intern ("svg"))) + { + /* For now, we stick to SVG 1.1. */ + if (!NILP (XCDR (frames))) + error ("SVG export cannot handle multiple frames."); + surface_type = CAIRO_SURFACE_TYPE_SVG; + } + else +#endif + error ("Unsupported export type"); + + result = x_cr_export_frames (frames, surface_type); + + return result; +} + +#ifdef USE_GTK +DEFUN ("x-page-setup-dialog", Fx_page_setup_dialog, Sx_page_setup_dialog, 0, 0, 0, + doc: /* Pop up a page setup dialog. +The current page setup can be obtained using `x-get-page-setup'. */) + () +{ + block_input (); + xg_page_setup_dialog (); + unblock_input (); + + return Qnil; +} + +DEFUN ("x-get-page-setup", Fx_get_page_setup, Sx_get_page_setup, 0, 0, 0, + doc: /* Return the value of the current page setup. +The return value is an alist containing the following keys: + + orientation: page orientation (symbol `portrait', `landscape', + `reverse-portrait', or `reverse-landscape'). + width, height: page width/height in points not including margins. + left-margin, right-margin, top-margin, bottom-margin: print margins, + which is the parts of the page that the printer cannot print + on, in points. + +The paper width can be obtained as the sum of width, left-margin, and +right-margin values. Likewise, the paper height is the sum of height, +top-margin, and bottom-margin values. */) + () +{ + Lisp_Object result; + + block_input (); + result = xg_get_page_setup (); + unblock_input (); + + return result; +} + +DEFUN ("x-print-frames-dialog", Fx_print_frames_dialog, Sx_print_frames_dialog, 0, 1, "", + doc: /* Pop up a print dialog to print the current contents of FRAMES. +FRAMES should be nil (the selected frame), a frame, or a list of +frames (each of which corresponds to one page). Each frame should be +visible. */) + (frames) + Lisp_Object frames; +{ + Lisp_Object rest, tmp; + + if (NILP (frames)) + frames = selected_frame; + if (!CONSP (frames)) + frames = list1 (frames); + + tmp = Qnil; + for (rest = frames; CONSP (rest); rest = XCDR (rest)) + { + struct frame *f = XFRAME (XCAR (rest)); + if (! FRAME_LIVE_P (f) || ! FRAME_X_P (f) || ! FRAME_LIVE_P (f)) + error ("Invalid frame"); + Lisp_Object frame; + + XSETFRAME (frame, f); + if (!EQ (Fframe_visible_p (frame), Qt)) + error ("Frames to be printed must be visible."); + tmp = Fcons (frame, tmp); + } + frames = Fnreverse (tmp); + + /* Make sure the current matrices are up-to-date. */ + Fredisplay (Qt); + + block_input (); + xg_print_frames_dialog (frames); + unblock_input (); + + return Qnil; +} +#endif /* USE_GTK */ +#endif /* USE_CAIRO */ + + +/*********************************************************************** Initialization ***********************************************************************/ @@ -6195,6 +6357,16 @@ syms_of_xfns (void) DEFSYM (Qcancel_timer, "cancel-timer"); DEFSYM (Qfont_param, "font-parameter"); +#ifdef USE_CAIRO + DEFSYM (Qorientation, "orientation"); + DEFSYM (Qtop_margin, "top-margin"); + DEFSYM (Qbottom_margin, "bottom-margin"); + DEFSYM (Qportrait, "portrait"); + DEFSYM (Qlandscape, "landscape"); + DEFSYM (Qreverse_portrait, "reverse-portrait"); + DEFSYM (Qreverse_landscape, "reverse-landscape"); +#endif + Fput (Qundefined_color, Qerror_conditions, listn (CONSTYPE_PURE, 2, Qundefined_color, Qerror)); Fput (Qundefined_color, Qerror_message, @@ -6335,6 +6507,20 @@ When using Gtk+ tooltips, the tooltip face is not used. */); } #endif /* USE_GTK */ +#ifdef USE_CAIRO + Fprovide (intern_c_string ("cairo"), Qnil); + + DEFVAR_LISP ("cairo-version-string", Vcairo_version_string, + doc: /* Version info for cairo. */); + { + char cairo_version[sizeof ".." + 3 * INT_STRLEN_BOUND (int)]; + int len = sprintf (cairo_version, "%d.%d.%d", + CAIRO_VERSION_MAJOR, CAIRO_VERSION_MINOR, + CAIRO_VERSION_MICRO); + Vcairo_version_string = make_pure_string (cairo_version, len, len, false); + } +#endif + /* X window properties. */ defsubr (&Sx_change_window_property); defsubr (&Sx_delete_window_property); @@ -6385,4 +6571,13 @@ When using Gtk+ tooltips, the tooltip face is not used. */); #if defined (USE_GTK) && defined (HAVE_FREETYPE) defsubr (&Sx_select_font); #endif + +#ifdef USE_CAIRO + defsubr (&Sx_export_frames); +#ifdef USE_GTK + defsubr (&Sx_page_setup_dialog); + defsubr (&Sx_get_page_setup); + defsubr (&Sx_print_frames_dialog); +#endif +#endif } diff --git a/src/xterm.c b/src/xterm.c index 0b3efe7b4b6..1074862ca3c 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -220,6 +220,7 @@ static int x_io_error_quitter (Display *); static struct terminal *x_create_terminal (struct x_display_info *); static void x_update_end (struct frame *); static void XTframe_up_to_date (struct frame *); +static void x_clear_area1 (Display *, Window, int, int, int, int, int); static void x_clear_frame (struct frame *); static _Noreturn void x_ins_del_lines (struct frame *, int, int); static void frame_highlight (struct frame *); @@ -325,6 +326,555 @@ record_event (char *locus, int type) #endif +static void x_prepare_for_xlibdraw (struct frame *); +static void x_set_clip_rectangles (struct frame *, GC, XRectangle *, int); +static void x_reset_clip_rectangles (struct frame *, GC); +static void x_fill_rectangle (struct frame *, GC, int, int, + unsigned int, unsigned int); +static void x_draw_rectangle (struct frame *, GC, int, int, + unsigned int, unsigned int); +static void x_fill_trapezoid_for_relief (struct frame *, GC, int, int, + unsigned int, unsigned int, int); +static void x_clear_window (struct frame *); + +#ifdef USE_CAIRO +static struct x_gc_ext_data *x_gc_get_ext_data (struct frame *, GC, int); +static void x_extension_initialize (struct x_display_info *); +static cairo_status_t x_cr_accumulate_data (void *, + const unsigned char *, + unsigned int); + +#define FRAME_CR_CONTEXT(f) ((f)->output_data.x->cr_context) +#define FRAME_CR_SURFACE(f) ((f)->output_data.x->cr_surface) + +static struct x_gc_ext_data * +x_gc_get_ext_data (f, gc, create_if_not_found_p) + struct frame *f; + GC gc; + int create_if_not_found_p; +{ + struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); + XEDataObject object; + XExtData **head, *ext_data; + + object.gc = gc; + head = XEHeadOfExtensionList (object); + ext_data = XFindOnExtensionList (head, dpyinfo->ext_codes->extension); + if (ext_data == NULL) + { + if (!create_if_not_found_p) + return NULL; + else + { + ext_data = xzalloc (sizeof (*ext_data)); + ext_data->number = dpyinfo->ext_codes->extension; + ext_data->private_data = xzalloc (sizeof (struct x_gc_ext_data)); + XAddToExtensionList (head, ext_data); + } + } + return (struct x_gc_ext_data *) ext_data->private_data; +} + +static void +x_extension_initialize (dpyinfo) + struct x_display_info *dpyinfo; +{ + XExtCodes *ext_codes = XAddExtension (dpyinfo->display); + + dpyinfo->ext_codes = ext_codes; +} + +static void +x_cr_destroy_surface (struct frame *f) +{ + if (FRAME_CR_SURFACE (f)) + { + cairo_t *cr = FRAME_CR_CONTEXT (f); + cairo_surface_destroy (FRAME_CR_SURFACE (f)); + FRAME_CR_SURFACE (f) = 0; + if (cr) cairo_destroy (cr); + FRAME_CR_CONTEXT (f) = NULL; + } +} + +cairo_t * +x_begin_cr_clip (f, gc) + struct frame *f; + GC gc; +{ + cairo_t *cr = FRAME_CR_CONTEXT (f); + + if (!cr) + { + + if (! FRAME_CR_SURFACE (f)) + { + cairo_surface_t *surface; + surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f), + FRAME_X_WINDOW (f), + FRAME_DISPLAY_INFO (f)->visual, + FRAME_PIXEL_WIDTH (f), + FRAME_PIXEL_HEIGHT (f)); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + } + else + cr = cairo_create (FRAME_CR_SURFACE (f)); + FRAME_CR_CONTEXT (f) = cr; + } + cairo_save (cr); + + if (gc) + { + struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0); + + if (gc_ext && gc_ext->n_clip_rects) + { + int i; + + for (i = 0; i < gc_ext->n_clip_rects; i++) + cairo_rectangle (cr, gc_ext->clip_rects[i].x, + gc_ext->clip_rects[i].y, + gc_ext->clip_rects[i].width, + gc_ext->clip_rects[i].height); + cairo_clip (cr); + } + } + + return cr; +} + +void +x_end_cr_clip (f) + struct frame *f; +{ + cairo_restore (FRAME_CR_CONTEXT (f)); +} + +void +x_set_cr_source_with_gc_foreground (f, gc) + struct frame *f; + GC gc; +{ + XGCValues xgcv; + XColor color; + + XGetGCValues (FRAME_X_DISPLAY (f), gc, GCForeground, &xgcv); + color.pixel = xgcv.foreground; + x_query_color (f, &color); + cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0, + color.green / 65535.0, color.blue / 65535.0); +} + +void +x_set_cr_source_with_gc_background (f, gc) + struct frame *f; + GC gc; +{ + XGCValues xgcv; + XColor color; + + XGetGCValues (FRAME_X_DISPLAY (f), gc, GCBackground, &xgcv); + color.pixel = xgcv.background; + x_query_color (f, &color); + cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0, + color.green / 65535.0, color.blue / 65535.0); +} + +/* Fringe bitmaps. */ + +static int max_fringe_bmp = 0; +static cairo_pattern_t **fringe_bmp = 0; + +static void +x_cr_define_fringe_bitmap (which, bits, h, wd) + int which; + unsigned short *bits; + int h, wd; +{ + int i, stride; + cairo_surface_t *surface; + unsigned char *data; + cairo_pattern_t *pattern; + + if (which >= max_fringe_bmp) + { + i = max_fringe_bmp; + max_fringe_bmp = which + 20; + fringe_bmp = (cairo_pattern_t **) xrealloc (fringe_bmp, max_fringe_bmp * sizeof (cairo_pattern_t *)); + while (i < max_fringe_bmp) + fringe_bmp[i++] = 0; + } + + block_input (); + + surface = cairo_image_surface_create (CAIRO_FORMAT_A1, wd, h); + stride = cairo_image_surface_get_stride (surface); + data = cairo_image_surface_get_data (surface); + + for (i = 0; i < h; i++) + { + *((unsigned short *) data) = bits[i]; + data += stride; + } + + pattern = cairo_pattern_create_for_surface (surface); + cairo_surface_destroy (surface); + + unblock_input (); + + fringe_bmp[which] = pattern; +} + +static void +x_cr_destroy_fringe_bitmap (which) + int which; +{ + if (which >= max_fringe_bmp) + return; + + if (fringe_bmp[which]) + { + block_input (); + cairo_pattern_destroy (fringe_bmp[which]); + unblock_input (); + } + fringe_bmp[which] = 0; +} + +static void +x_cr_draw_image (struct frame *f, + GC gc, + cairo_pattern_t *image, + int src_x, + int src_y, + unsigned int width, + unsigned int height, + int dest_x, + int dest_y, + bool overlay_p) +{ + cairo_t *cr; + cairo_matrix_t matrix; + cairo_surface_t *surface; + cairo_format_t format; + + cr = x_begin_cr_clip (f, gc); + if (overlay_p) + cairo_rectangle (cr, dest_x, dest_y, width, height); + else + { + x_set_cr_source_with_gc_background (f, gc); + cairo_rectangle (cr, dest_x, dest_y, width, height); + cairo_fill_preserve (cr); + } + cairo_clip (cr); + cairo_matrix_init_translate (&matrix, src_x - dest_x, src_y - dest_y); + cairo_pattern_set_matrix (image, &matrix); + cairo_pattern_get_surface (image, &surface); + format = cairo_image_surface_get_format (surface); + if (format != CAIRO_FORMAT_A8 && format != CAIRO_FORMAT_A1) + { + cairo_set_source (cr, image); + cairo_fill (cr); + } + else + { + x_set_cr_source_with_gc_foreground (f, gc); + cairo_mask (cr, image); + } + x_end_cr_clip (f); +} + +void +x_cr_draw_frame (cr, f) + cairo_t *cr; + struct frame *f; +{ + int width, height; + + width = FRAME_PIXEL_WIDTH (f); + height = FRAME_PIXEL_HEIGHT (f); + + x_prepare_for_xlibdraw (f); + FRAME_CR_CONTEXT (f) = cr; + x_clear_area (f, 0, 0, width, height); + expose_frame (f, 0, 0, width, height); + FRAME_CR_CONTEXT (f) = NULL; +} + +static cairo_status_t +x_cr_accumulate_data (closure, data, length) + void *closure; + const unsigned char *data; + unsigned int length; +{ + Lisp_Object *acc = (Lisp_Object *) closure; + + *acc = Fcons (make_unibyte_string (data, length), *acc); + + return CAIRO_STATUS_SUCCESS; +} + +static void +x_cr_destroy (arg) + Lisp_Object arg; +{ + cairo_t *cr = (cairo_t *) XSAVE_POINTER (arg, 0); + + block_input (); + cairo_destroy (cr); + unblock_input (); +} + +Lisp_Object +x_cr_export_frames (frames, surface_type) + Lisp_Object frames; + cairo_surface_type_t surface_type; +{ + struct frame *f; + cairo_surface_t *surface; + cairo_t *cr; + int width, height; + void (*surface_set_size_func) (cairo_surface_t *, double, double) = NULL; + Lisp_Object acc = Qnil, args[2]; + int count = SPECPDL_INDEX (); + + Fredisplay (Qt); + + f = XFRAME (XCAR (frames)); + frames = XCDR (frames); + width = FRAME_PIXEL_WIDTH (f); + height = FRAME_PIXEL_HEIGHT (f); + + block_input (); +#ifdef CAIRO_HAS_PDF_SURFACE + if (surface_type == CAIRO_SURFACE_TYPE_PDF) + { + surface = cairo_pdf_surface_create_for_stream (x_cr_accumulate_data, &acc, + width, height); + surface_set_size_func = cairo_pdf_surface_set_size; + } + else +#endif +#ifdef CAIRO_HAS_PNG_FUNCTIONS + if (surface_type == CAIRO_SURFACE_TYPE_IMAGE) + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); + else +#endif +#ifdef CAIRO_HAS_PS_SURFACE + if (surface_type == CAIRO_SURFACE_TYPE_PS) + { + surface = cairo_ps_surface_create_for_stream (x_cr_accumulate_data, &acc, + width, height); + surface_set_size_func = cairo_ps_surface_set_size; + } + else +#endif +#ifdef CAIRO_HAS_SVG_SURFACE + if (surface_type == CAIRO_SURFACE_TYPE_SVG) + surface = cairo_svg_surface_create_for_stream (x_cr_accumulate_data, &acc, + width, height); + else +#endif + abort (); + + cr = cairo_create (surface); + cairo_surface_destroy (surface); + record_unwind_protect (x_cr_destroy, make_save_ptr (cr)); + unblock_input (); + + while (1) + { + QUIT; + + block_input (); + x_prepare_for_xlibdraw (f); + FRAME_CR_CONTEXT (f) = cr; + x_clear_area (f, 0, 0, width, height); + expose_frame (f, 0, 0, width, height); + FRAME_CR_CONTEXT (f) = NULL; + unblock_input (); + + if (NILP (frames)) + break; + + block_input (); + cairo_surface_show_page (surface); + f = XFRAME (XCAR (frames)); + frames = XCDR (frames); + width = FRAME_PIXEL_WIDTH (f); + height = FRAME_PIXEL_HEIGHT (f); + if (surface_set_size_func) + (*surface_set_size_func) (surface, width, height); + unblock_input (); + } + +#ifdef CAIRO_HAS_PNG_FUNCTIONS + if (surface_type == CAIRO_SURFACE_TYPE_IMAGE) + { + block_input (); + cairo_surface_flush (surface); + cairo_surface_write_to_png_stream (surface, x_cr_accumulate_data, &acc); + unblock_input (); + } +#endif + unbind_to (count, Qnil); + + args[0] = intern ("concat"); + args[1] = Fnreverse (acc); + return Fapply (2, args); +} + +#endif /* USE_CAIRO */ + +static void +x_prepare_for_xlibdraw (f) + struct frame *f; +{ +#ifdef USE_CAIRO + if (f == NULL) + { + Lisp_Object rest, frame; + FOR_EACH_FRAME (rest, frame) + if (FRAME_X_P (XFRAME (frame))) + x_prepare_for_xlibdraw (XFRAME (frame)); + } + else + { + cairo_t *cr = FRAME_CR_CONTEXT (f); + + if (cr) + { + cairo_surface_t *surface = cairo_get_target (cr); + + if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB) + { + cairo_destroy (cr); + FRAME_CR_CONTEXT (f) = NULL; + } + } + } +#endif +} + +static void +x_set_clip_rectangles (f, gc, rectangles, n) + struct frame *f; + GC gc; + XRectangle *rectangles; + int n; +{ + XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, rectangles, n, Unsorted); +#ifdef USE_CAIRO + eassert (n >= 0 && n <= MAX_CLIP_RECTS); + + { + struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 1); + + gc_ext->n_clip_rects = n; + memcpy (gc_ext->clip_rects, rectangles, sizeof (XRectangle) * n); + } +#endif +} + +static void +x_reset_clip_rectangles (f, gc) + struct frame *f; + GC gc; +{ + XSetClipMask (FRAME_X_DISPLAY (f), gc, None); +#ifdef USE_CAIRO + { + struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0); + + if (gc_ext) + gc_ext->n_clip_rects = 0; + } +#endif +} + +static void +x_fill_rectangle (f, gc, x, y, width, height) + struct frame *f; + GC gc; + int x, y; + unsigned int width, height; +{ +#ifdef USE_CAIRO + cairo_t *cr; + + cr = x_begin_cr_clip (f, gc); + x_set_cr_source_with_gc_foreground (f, gc); + cairo_rectangle (cr, x, y, width, height); + cairo_fill (cr); + x_end_cr_clip (f); +#else + XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + gc, x, y, width, height); +#endif +} + +static void +x_draw_rectangle (f, gc, x, y, width, height) + struct frame *f; + GC gc; + int x, y; + unsigned int width, height; +{ +#ifdef USE_CAIRO + cairo_t *cr; + + cr = x_begin_cr_clip (f, gc); + x_set_cr_source_with_gc_foreground (f, gc); + cairo_rectangle (cr, x + 0.5, y + 0.5, width, height); + cairo_set_line_width (cr, 1); + cairo_stroke (cr); + x_end_cr_clip (f); +#else + XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + gc, x, y, width, height); +#endif +} + +static void +x_clear_window (f) + struct frame *f; +{ +#ifdef USE_CAIRO + cairo_t *cr; + + cr = x_begin_cr_clip (f, NULL); + x_set_cr_source_with_gc_background (f, f->output_data.x->normal_gc); + cairo_paint (cr); + x_end_cr_clip (f); +#else + XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); +#endif +} + +#ifdef USE_CAIRO +static void +x_fill_trapezoid_for_relief (f, gc, x, y, width, height, top_p) + struct frame *f; + GC gc; + int x, y; + unsigned int width, height; + int top_p; +{ + cairo_t *cr; + + cr = x_begin_cr_clip (f, gc); + x_set_cr_source_with_gc_foreground (f, gc); + cairo_move_to (cr, top_p ? x : x + height, y); + cairo_line_to (cr, x, y + height); + cairo_line_to (cr, top_p ? x + width - height : x + width, y + height); + cairo_line_to (cr, x + width, y); + cairo_close_path (cr); + cairo_fill (cr); + x_end_cr_clip (f); +} +#endif /* Return the struct x_display_info corresponding to DPY. */ @@ -452,9 +1002,38 @@ x_set_frame_alpha (struct frame *f) static void x_update_begin (struct frame *f) { - /* Nothing to do. */ -} +#ifdef USE_CAIRO + if (! FRAME_CR_SURFACE (f)) + { + int width, height; +#ifdef USE_GTK + if (FRAME_GTK_WIDGET (f)) + { + GdkWindow *w = gtk_widget_get_window (FRAME_GTK_WIDGET (f)); + width = gdk_window_get_width (w); + height = gdk_window_get_height (w); + } + else +#endif + { + width = FRAME_PIXEL_WIDTH (f); + height = FRAME_PIXEL_HEIGHT (f); + if (! FRAME_EXTERNAL_TOOL_BAR (f)) + height += FRAME_TOOL_BAR_HEIGHT (f); + if (! FRAME_EXTERNAL_MENU_BAR (f)) + height += FRAME_MENU_BAR_HEIGHT (f); + } + if (width > 0 && height > 0) + { + block_input(); + FRAME_CR_SURFACE (f) = cairo_image_surface_create + (CAIRO_FORMAT_ARGB32, width, height); + unblock_input(); + } + } +#endif /* USE_CAIRO */ +} /* Start update of window W. */ @@ -496,8 +1075,12 @@ x_draw_vertical_window_border (struct window *w, int x, int y0, int y1) XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc, face->foreground); +#ifdef USE_CAIRO + x_fill_rectangle (f, f->output_data.x->normal_gc, x, y0, 1, y1 - y0); +#else XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), f->output_data.x->normal_gc, x, y0, x, y1); +#endif } /* Draw a window divider from (x0,y0) to (x1,y1) */ @@ -612,6 +1195,43 @@ x_update_end (struct frame *f) /* Mouse highlight may be displayed again. */ MOUSE_HL_INFO (f)->mouse_face_defer = false; +#ifdef USE_CAIRO + if (FRAME_CR_SURFACE (f)) + { + cairo_t *cr = 0; + block_input(); +#if defined (USE_GTK) && defined (HAVE_GTK3) + if (FRAME_GTK_WIDGET (f)) + { + GdkWindow *w = gtk_widget_get_window (FRAME_GTK_WIDGET (f)); + cr = gdk_cairo_create (w); + } + else +#endif + { + cairo_surface_t *surface; + int width = FRAME_PIXEL_WIDTH (f); + int height = FRAME_PIXEL_HEIGHT (f); + if (! FRAME_EXTERNAL_TOOL_BAR (f)) + height += FRAME_TOOL_BAR_HEIGHT (f); + if (! FRAME_EXTERNAL_MENU_BAR (f)) + height += FRAME_MENU_BAR_HEIGHT (f); + surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f), + FRAME_X_WINDOW (f), + FRAME_DISPLAY_INFO (f)->visual, + width, + height); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + } + + cairo_set_source_surface (cr, FRAME_CR_SURFACE (f), 0, 0); + cairo_paint (cr); + cairo_destroy (cr); + unblock_input (); + } +#endif /* USE_CAIRO */ + #ifndef XFlush block_input (); XFlush (FRAME_X_DISPLAY (f)); @@ -638,18 +1258,16 @@ x_clear_under_internal_border (struct frame *f) { if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0) { - Display *display = FRAME_X_DISPLAY (f); - Window window = FRAME_X_WINDOW (f); int border = FRAME_INTERNAL_BORDER_WIDTH (f); int width = FRAME_PIXEL_WIDTH (f); int height = FRAME_PIXEL_HEIGHT (f); int margin = FRAME_TOP_MARGIN_HEIGHT (f); block_input (); - x_clear_area (display, window, 0, 0, border, height); - x_clear_area (display, window, 0, margin, width, border); - x_clear_area (display, window, width - border, 0, border, height); - x_clear_area (display, window, 0, height - border, width, border); + x_clear_area (f, 0, 0, border, height); + x_clear_area (f, 0, margin, width, border); + x_clear_area (f, width - border, 0, border, height); + x_clear_area (f, 0, height - border, width, border); unblock_input (); } } @@ -691,11 +1309,8 @@ x_after_update_window_line (struct window *w, struct glyph_row *desired_row) int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y)); block_input (); - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - 0, y, width, height); - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - FRAME_PIXEL_WIDTH (f) - width, - y, width, height); + x_clear_area (f, 0, y, width, height); + x_clear_area (f, FRAME_PIXEL_WIDTH (f) - width, y, width, height); unblock_input (); } } @@ -725,13 +1340,29 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring else XSetForeground (display, face->gc, face->background); - XFillRectangle (display, window, face->gc, - p->bx, p->by, p->nx, p->ny); + x_fill_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny); if (!face->stipple) XSetForeground (display, face->gc, face->foreground); } +#ifdef USE_CAIRO + if (p->which && p->which < max_fringe_bmp) + { + XGCValues gcv; + + XGetGCValues (display, gc, GCForeground | GCBackground, &gcv); + XSetForeground (display, gc, (p->cursor_p + ? (p->overlay_p ? face->background + : f->output_data.x->cursor_pixel) + : face->foreground)); + XSetBackground (display, gc, face->background); + x_cr_draw_image (f, gc, fringe_bmp[p->which], 0, p->dh, + p->wd, p->h, p->x, p->y, p->overlay_p); + XSetForeground (display, gc, gcv.foreground); + XSetBackground (display, gc, gcv.background); + } +#else /* not USE_CAIRO */ if (p->which) { char *bits; @@ -776,8 +1407,9 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring XFreePixmap (display, clipmask); } } +#endif /* not USE_CAIRO */ - XSetClipMask (display, gc, None); + x_reset_clip_rectangles (f, gc); } /*********************************************************************** @@ -985,7 +1617,7 @@ x_set_glyph_string_clipping (struct glyph_string *s) int n = get_glyph_string_clip_rects (s, r, 2); if (n > 0) - XSetClipRectangles (s->display, s->gc, 0, 0, r, n, Unsorted); + x_set_clip_rectangles (s->f, s->gc, r, n); s->num_clips = n; } @@ -1005,7 +1637,7 @@ x_set_glyph_string_clipping_exactly (struct glyph_string *src, struct glyph_stri r.height = src->height; dst->clip[0] = r; dst->num_clips = 1; - XSetClipRectangles (dst->display, dst->gc, 0, 0, &r, 1, Unsorted); + x_set_clip_rectangles (dst->f, dst->gc, &r, 1); } @@ -1057,7 +1689,7 @@ x_clear_glyph_string_rect (struct glyph_string *s, int x, int y, int w, int h) XGCValues xgcv; XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv); XSetForeground (s->display, s->gc, xgcv.background); - XFillRectangle (s->display, s->window, s->gc, x, y, w, h); + x_fill_rectangle (s->f, s->gc, x, y, w, h); XSetForeground (s->display, s->gc, xgcv.foreground); } @@ -1081,7 +1713,7 @@ x_draw_glyph_string_background (struct glyph_string *s, bool force_p) { /* Fill background with a stipple pattern. */ XSetFillStyle (s->display, s->gc, FillOpaqueStippled); - XFillRectangle (s->display, s->window, s->gc, s->x, + x_fill_rectangle (s->f, s->gc, s->x, s->y + box_line_width, s->background_width, s->height - 2 * box_line_width); @@ -1124,7 +1756,7 @@ x_draw_glyph_string_foreground (struct glyph_string *s) for (i = 0; i < s->nchars; ++i) { struct glyph *g = s->first_glyph + i; - XDrawRectangle (s->display, s->window, + x_draw_rectangle (s->f, s->gc, x, s->y, g->pixel_width - 1, s->height - 1); x += g->pixel_width; @@ -1176,7 +1808,7 @@ x_draw_composite_glyph_string_foreground (struct glyph_string *s) if (s->font_not_found_p) { if (s->cmp_from == 0) - XDrawRectangle (s->display, s->window, s->gc, x, s->y, + x_draw_rectangle (s->f, s->gc, x, s->y, s->width - 1, s->height - 1); } else if (! s->first_glyph->u.cmp.automatic) @@ -1310,7 +1942,7 @@ x_draw_glyphless_glyph_string_foreground (struct glyph_string *s) false); } if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE) - XDrawRectangle (s->display, s->window, s->gc, + x_draw_rectangle (s->f, s->gc, x, s->ybase - glyph->ascent, glyph->pixel_width - 1, glyph->ascent + glyph->descent - 1); @@ -1882,6 +2514,52 @@ x_draw_relief_rect (struct frame *f, bool left_p, bool right_p, XRectangle *clip_rect) { +#ifdef USE_CAIRO + GC top_left_gc, bottom_right_gc; + + if (raised_p) + { + top_left_gc = f->output_data.x->white_relief.gc; + bottom_right_gc = f->output_data.x->black_relief.gc; + } + else + { + top_left_gc = f->output_data.x->black_relief.gc; + bottom_right_gc = f->output_data.x->white_relief.gc; + } + + x_set_clip_rectangles (f, top_left_gc, clip_rect, 1); + x_set_clip_rectangles (f, bottom_right_gc, clip_rect, 1); + + if (left_p) + x_fill_rectangle (f, top_left_gc, left_x, top_y, + width, bottom_y + 1 - top_y); + if (right_p) + x_fill_rectangle (f, bottom_right_gc, right_x + 1 - width, top_y, + width, bottom_y + 1 - top_y); + if (top_p) + { + if (!right_p) + x_fill_rectangle (f, top_left_gc, left_x, top_y, + right_x + 1 - left_x, width); + else + x_fill_trapezoid_for_relief (f, top_left_gc, left_x, top_y, + right_x + 1 - left_x, width, 1); + } + if (bot_p) + { + if (!left_p) + x_fill_rectangle (f, bottom_right_gc, left_x, bottom_y + 1 - width, + right_x + 1 - left_x, width); + else + x_fill_trapezoid_for_relief (f, bottom_right_gc, + left_x, bottom_y + 1 - width, + right_x + 1 - left_x, width, 0); + } + + x_set_clip_rectangles (f, top_left_gc, clip_rect, 1); + x_set_clip_rectangles (f, bottom_right_gc, clip_rect, 1); +#else Display *dpy = FRAME_X_DISPLAY (f); Window window = FRAME_X_WINDOW (f); int i; @@ -1970,7 +2648,9 @@ x_draw_relief_rect (struct frame *f, right_x - i, bottom_y + 1 - (i + 1) * bot_p); } - XSetClipMask (dpy, gc, None); + x_reset_clip_rectangles (f, gc); + +#endif } @@ -1990,28 +2670,28 @@ x_draw_box_rect (struct glyph_string *s, XGetGCValues (s->display, s->gc, GCForeground, &xgcv); XSetForeground (s->display, s->gc, s->face->box_color); - XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted); + x_set_clip_rectangles (s->f, s->gc, clip_rect, 1); /* Top. */ - XFillRectangle (s->display, s->window, s->gc, + x_fill_rectangle (s->f, s->gc, left_x, top_y, right_x - left_x + 1, width); /* Left. */ if (left_p) - XFillRectangle (s->display, s->window, s->gc, + x_fill_rectangle (s->f, s->gc, left_x, top_y, width, bottom_y - top_y + 1); /* Bottom. */ - XFillRectangle (s->display, s->window, s->gc, + x_fill_rectangle (s->f, s->gc, left_x, bottom_y - width + 1, right_x - left_x + 1, width); /* Right. */ if (right_p) - XFillRectangle (s->display, s->window, s->gc, + x_fill_rectangle (s->f, s->gc, right_x - width + 1, top_y, width, bottom_y - top_y + 1); XSetForeground (s->display, s->gc, xgcv.foreground); - XSetClipMask (s->display, s->gc, None); + x_reset_clip_rectangles (s->f, s->gc); } @@ -2142,7 +2822,7 @@ x_draw_image_foreground (struct glyph_string *s) if (s->hl == DRAW_CURSOR) { int relief = eabs (s->img->relief); - XDrawRectangle (s->display, s->window, s->gc, + x_draw_rectangle (s->f, s->gc, x - relief, y - relief, s->slice.width + relief*2 - 1, s->slice.height + relief*2 - 1); @@ -2151,7 +2831,7 @@ x_draw_image_foreground (struct glyph_string *s) } else /* Draw a rectangle if image could not be loaded. */ - XDrawRectangle (s->display, s->window, s->gc, x, y, + x_draw_rectangle (s->f, s->gc, x, y, s->slice.width - 1, s->slice.height - 1); } @@ -2290,7 +2970,7 @@ x_draw_image_foreground_1 (struct glyph_string *s, Pixmap pixmap) if (s->hl == DRAW_CURSOR) { int r = eabs (s->img->relief); - XDrawRectangle (s->display, s->window, s->gc, x - r, y - r, + x_draw_rectangle (s->f, s->gc, x - r, y - r, s->slice.width + r*2 - 1, s->slice.height + r*2 - 1); } @@ -2298,7 +2978,7 @@ x_draw_image_foreground_1 (struct glyph_string *s, Pixmap pixmap) } else /* Draw a rectangle if image could not be loaded. */ - XDrawRectangle (s->display, pixmap, s->gc, x, y, + x_draw_rectangle (s->f, s->gc, x, y, s->slice.width - 1, s->slice.height - 1); } @@ -2313,7 +2993,7 @@ x_draw_glyph_string_bg_rect (struct glyph_string *s, int x, int y, int w, int h) { /* Fill background with a stipple pattern. */ XSetFillStyle (s->display, s->gc, FillOpaqueStippled); - XFillRectangle (s->display, s->window, s->gc, x, y, w, h); + x_fill_rectangle (s->f, s->gc, x, y, w, h); XSetFillStyle (s->display, s->gc, FillSolid); } else @@ -2422,7 +3102,22 @@ x_draw_image_glyph_string (struct glyph_string *s) } /* Draw the foreground. */ - if (pixmap != None) + if (s->img->cr_data) + { + cairo_t *cr = x_begin_cr_clip (s->f, s->gc); + + int x = s->x + s->img->hmargin; + int y = s->y + s->img->vmargin; + int width = s->background_width; + + cairo_set_source_surface (cr, s->img->cr_data, + x - s->slice.x, + y - s->slice.y); + cairo_rectangle (cr, x, y, width, height); + cairo_fill (cr); + x_end_cr_clip (s->f); + } + else if (pixmap != None) { x_draw_image_foreground_1 (s, pixmap); x_set_glyph_string_clipping (s); @@ -2505,13 +3200,13 @@ x_draw_stretch_glyph_string (struct glyph_string *s) gc = s->face->gc; get_glyph_string_clip_rect (s, &r); - XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted); + x_set_clip_rectangles (s->f, gc, &r, 1); if (s->face->stipple) { /* Fill background with a stipple pattern. */ XSetFillStyle (s->display, gc, FillOpaqueStippled); - XFillRectangle (s->display, s->window, gc, x, y, w, h); + x_fill_rectangle (s->f, gc, x, y, w, h); XSetFillStyle (s->display, gc, FillSolid); } else @@ -2519,7 +3214,7 @@ x_draw_stretch_glyph_string (struct glyph_string *s) XGCValues xgcv; XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv); XSetForeground (s->display, gc, xgcv.background); - XFillRectangle (s->display, s->window, gc, x, y, w, h); + x_fill_rectangle (s->f, gc, x, y, w, h); XSetForeground (s->display, gc, xgcv.foreground); } @@ -2778,14 +3473,14 @@ x_draw_glyph_string (struct glyph_string *s) s->underline_position = position; y = s->ybase + position; if (s->face->underline_defaulted_p) - XFillRectangle (s->display, s->window, s->gc, + x_fill_rectangle (s->f, s->gc, s->x, y, s->width, thickness); else { XGCValues xgcv; XGetGCValues (s->display, s->gc, GCForeground, &xgcv); XSetForeground (s->display, s->gc, s->face->underline_color); - XFillRectangle (s->display, s->window, s->gc, + x_fill_rectangle (s->f, s->gc, s->x, y, s->width, thickness); XSetForeground (s->display, s->gc, xgcv.foreground); } @@ -2797,14 +3492,14 @@ x_draw_glyph_string (struct glyph_string *s) unsigned long dy = 0, h = 1; if (s->face->overline_color_defaulted_p) - XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, + x_fill_rectangle (s->f, s->gc, s->x, s->y + dy, s->width, h); else { XGCValues xgcv; XGetGCValues (s->display, s->gc, GCForeground, &xgcv); XSetForeground (s->display, s->gc, s->face->overline_color); - XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, + x_fill_rectangle (s->f, s->gc, s->x, s->y + dy, s->width, h); XSetForeground (s->display, s->gc, xgcv.foreground); } @@ -2817,14 +3512,14 @@ x_draw_glyph_string (struct glyph_string *s) unsigned long dy = (s->height - h) / 2; if (s->face->strike_through_color_defaulted_p) - XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, + x_fill_rectangle (s->f, s->gc, s->x, s->y + dy, s->width, h); else { XGCValues xgcv; XGetGCValues (s->display, s->gc, GCForeground, &xgcv); XSetForeground (s->display, s->gc, s->face->strike_through_color); - XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, + x_fill_rectangle (s->f, s->gc, s->x, s->y + dy, s->width, h); XSetForeground (s->display, s->gc, xgcv.foreground); } @@ -2853,7 +3548,7 @@ x_draw_glyph_string (struct glyph_string *s) x_draw_glyph_string_foreground (prev); else x_draw_composite_glyph_string_foreground (prev); - XSetClipMask (prev->display, prev->gc, None); + x_reset_clip_rectangles (prev->f, prev->gc); prev->hl = save; prev->num_clips = 0; } @@ -2878,7 +3573,7 @@ x_draw_glyph_string (struct glyph_string *s) x_draw_glyph_string_foreground (next); else x_draw_composite_glyph_string_foreground (next); - XSetClipMask (next->display, next->gc, None); + x_reset_clip_rectangles (next->f, next->gc); next->hl = save; next->num_clips = 0; next->clip_head = s->next; @@ -2887,7 +3582,7 @@ x_draw_glyph_string (struct glyph_string *s) } /* Reset clipping. */ - XSetClipMask (s->display, s->gc, None); + x_reset_clip_rectangles (s->f, s->gc); s->num_clips = 0; } @@ -2896,6 +3591,7 @@ x_draw_glyph_string (struct glyph_string *s) static void x_shift_glyphs_for_insert (struct frame *f, int x, int y, int width, int height, int shift_by) { + x_prepare_for_xlibdraw (f); XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f), f->output_data.x->normal_gc, x, y, width, height, @@ -2915,11 +3611,35 @@ x_delete_glyphs (struct frame *f, register int n) /* Like XClearArea, but check that WIDTH and HEIGHT are reasonable. If they are <= 0, this is probably an error. */ +static void +x_clear_area1 (Display *dpy, Window window, + int x, int y, int width, int height, int exposures) +{ + eassert (width > 0 && height > 0); + XClearArea (dpy, window, x, y, width, height, exposures); +} + + void -x_clear_area (Display *dpy, Window window, int x, int y, int width, int height) +x_clear_area (f, x, y, width, height) + struct frame *f; + int x, y; + int width, height; { +#ifdef USE_CAIRO + cairo_t *cr; + eassert (width > 0 && height > 0); - XClearArea (dpy, window, x, y, width, height, False); + + cr = x_begin_cr_clip (f, NULL); + x_set_cr_source_with_gc_background (f, f->output_data.x->normal_gc); + cairo_rectangle (cr, x, y, width, height); + cairo_fill (cr); + x_end_cr_clip (f); +#else + x_clear_area1 (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + x, y, width, height, False); +#endif } @@ -2934,7 +3654,7 @@ x_clear_frame (struct frame *f) block_input (); - XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); + x_clear_window (f); /* We have to clear the scroll bars. If we have changed colors or something like that, then they should be notified. */ @@ -3240,12 +3960,16 @@ x_scroll_run (struct window *w, struct run *run) /* Cursor off. Will be switched on again in x_update_window_end. */ x_clear_cursor (w); +#ifdef USE_CAIRO + SET_FRAME_GARBAGED (f); +#else XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f), f->output_data.x->normal_gc, x, from_y, width, height, x, to_y); +#endif unblock_input (); } @@ -4154,7 +4878,7 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, dpyinfo->last_mouse_glyph_frame = f1; *bar_window = Qnil; - *part = scroll_bar_above_handle; + *part = 0; *fp = f1; XSETINT (*x, win_x); XSETINT (*y, win_y); @@ -4248,7 +4972,7 @@ x_window_to_menu_bar (Window window) #ifdef USE_TOOLKIT_SCROLL_BARS static void x_send_scroll_bar_event (Lisp_Object, enum scroll_bar_part, - int, int, bool); + int, int, bool); /* Lisp window being scrolled. Set when starting to interact with a toolkit scroll bar, reset to nil when ending the interaction. */ @@ -5505,8 +6229,7 @@ x_scroll_bar_create (struct window *w, int top, int left, for the case that a window has been split horizontally. In this case, no clear_frame is generated to reduce flickering. */ if (width > 0 && window_box_height (w) > 0) - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - left, top, width, window_box_height (w)); + x_clear_area (f, left, top, width, window_box_height (w)); window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), /* Position and size of scroll bar. */ @@ -5638,7 +6361,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end, /* Draw the empty space above the handle. Note that we can't clear zero-height areas; that means "clear to end of window." */ if ((inside_width > 0) && (start > 0)) - x_clear_area (FRAME_X_DISPLAY (f), w, + x_clear_area1 (FRAME_X_DISPLAY (f), w, VERTICAL_SCROLL_BAR_LEFT_BORDER, VERTICAL_SCROLL_BAR_TOP_BORDER, inside_width, start); @@ -5649,7 +6372,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end, f->output_data.x->scroll_bar_foreground_pixel); /* Draw the handle itself. */ - XFillRectangle (FRAME_X_DISPLAY (f), w, gc, + x_fill_rectangle (f, gc, /* x, y, width, height */ VERTICAL_SCROLL_BAR_LEFT_BORDER, VERTICAL_SCROLL_BAR_TOP_BORDER + start, @@ -5663,7 +6386,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end, /* Draw the empty space below the handle. Note that we can't clear zero-height areas; that means "clear to end of window." */ if ((inside_width > 0) && (end < inside_height)) - x_clear_area (FRAME_X_DISPLAY (f), w, + x_clear_area1 (FRAME_X_DISPLAY (f), w, VERTICAL_SCROLL_BAR_LEFT_BORDER, VERTICAL_SCROLL_BAR_TOP_BORDER + end, inside_width, inside_height - end); @@ -5730,8 +6453,7 @@ XTset_vertical_scroll_bar (struct window *w, int portion, int whole, int positio if (width > 0 && height > 0) { block_input (); - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - left, top, width, height); + x_clear_area (f, left, top, width, height); unblock_input (); } @@ -5763,8 +6485,7 @@ XTset_vertical_scroll_bar (struct window *w, int portion, int whole, int positio /* Since toolkit scroll bars are smaller than the space reserved for them on the frame, we have to clear "under" them. */ if (width > 0 && height > 0) - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - left, top, width, height); + x_clear_area (f, left, top, width, height); #ifdef USE_GTK xg_update_scrollbar_pos (f, bar->x_window, top, left, width, max (height, 1)); @@ -5850,8 +6571,7 @@ XTset_horizontal_scroll_bar (struct window *w, int portion, int whole, int posit /* Clear also part between window_width and WINDOW_PIXEL_WIDTH. */ - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - left, top, pixel_width, height); + x_clear_area (f, left, top, pixel_width, height); unblock_input (); } @@ -5882,7 +6602,7 @@ XTset_horizontal_scroll_bar (struct window *w, int portion, int whole, int posit /* Since toolkit scroll bars are smaller than the space reserved for them on the frame, we have to clear "under" them. */ if (width > 0 && height > 0) - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + x_clear_area (f, WINDOW_LEFT_EDGE_X (w), top, pixel_width - WINDOW_RIGHT_DIVIDER_WIDTH (w), height); #ifdef USE_GTK @@ -6128,7 +6848,7 @@ x_scroll_bar_expose (struct scroll_bar *bar, const XEvent *event) f->output_data.x->scroll_bar_foreground_pixel); /* Draw a one-pixel border just inside the edges of the scroll bar. */ - XDrawRectangle (FRAME_X_DISPLAY (f), w, gc, + x_draw_rectangle (f, gc, /* x, y, width, height */ 0, 0, bar->width - 1, bar->height - 1); @@ -6912,11 +7632,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, } else { -#ifdef USE_GTK +#if defined (USE_GTK) && ! defined (HAVE_GTK3) && ! defined (USE_CAIRO) /* This seems to be needed for GTK 2.6 and later, see http://debbugs.gnu.org/cgi/bugreport.cgi?bug=15398. */ - x_clear_area (event->xexpose.display, - event->xexpose.window, + x_clear_area (f, event->xexpose.x, event->xexpose.y, event->xexpose.width, event->xexpose.height); #endif @@ -7530,6 +8249,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, case ConfigureNotify: f = x_top_window_to_frame (dpyinfo, event->xconfigure.window); +#ifdef USE_CAIRO + if (f) x_cr_destroy_surface (f); +#endif #ifdef USE_GTK if (!f && (f = any) @@ -7537,6 +8259,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, { xg_frame_resized (f, event->xconfigure.width, event->xconfigure.height); + x_cr_destroy_surface (f); f = 0; } #endif @@ -7946,7 +8669,7 @@ x_clip_to_row (struct window *w, struct glyph_row *row, clip_rect.width = window_width; clip_rect.height = row->visible_height; - XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted); + x_set_clip_rectangles (f, gc, &clip_rect, 1); } @@ -7995,8 +8718,8 @@ x_draw_hollow_cursor (struct window *w, struct glyph_row *row) } /* Set clipping, draw the rectangle, and reset clipping again. */ x_clip_to_row (w, row, TEXT_AREA, gc); - XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h - 1); - XSetClipMask (dpy, gc, None); + x_draw_rectangle (f, gc, x, y, wd, h - 1); + x_reset_clip_rectangles (f, gc); } @@ -8074,7 +8797,7 @@ x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text if ((cursor_glyph->resolved_level & 1) != 0) x += cursor_glyph->pixel_width - width; - XFillRectangle (dpy, window, gc, x, + x_fill_rectangle (f, gc, x, WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y), width, row->height); } @@ -8094,13 +8817,13 @@ x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text if ((cursor_glyph->resolved_level & 1) != 0 && cursor_glyph->pixel_width > w->phys_cursor_width - 1) x += cursor_glyph->pixel_width - w->phys_cursor_width + 1; - XFillRectangle (dpy, window, gc, x, - WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y + - row->height - width), - w->phys_cursor_width - 1, width); + x_fill_rectangle (f, gc, x, + WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y + + row->height - width), + w->phys_cursor_width - 1, width); } - XSetClipMask (dpy, gc, None); + x_reset_clip_rectangles (f, gc); } } @@ -8122,7 +8845,7 @@ x_define_frame_cursor (struct frame *f, Cursor cursor) static void x_clear_frame_area (struct frame *f, int x, int y, int width, int height) { - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), x, y, width, height); + x_clear_area (f, x, y, width, height); #ifdef USE_GTK /* Must queue a redraw, because scroll bars might have been cleared. */ if (FRAME_GTK_WIDGET (f)) @@ -10235,6 +10958,7 @@ x_free_frame_resources (struct frame *f) free_frame_xic (f); #endif + x_prepare_for_xlibdraw (f); #ifdef USE_X_TOOLKIT if (f->output_data.x->widget) { @@ -11312,6 +12036,10 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) x_session_initialize (dpyinfo); #endif +#ifdef USE_CAIRO + x_extension_initialize (dpyinfo); +#endif + unblock_input (); return dpyinfo; @@ -11423,8 +12151,13 @@ static struct redisplay_interface x_redisplay_interface = x_get_glyph_overhangs, x_fix_overlapping_area, x_draw_fringe_bitmap, +#ifdef USE_CAIRO + x_cr_define_fringe_bitmap, + x_cr_destroy_fringe_bitmap, +#else 0, /* define_fringe_bitmap */ 0, /* destroy_fringe_bitmap */ +#endif x_compute_glyph_string_overhangs, x_draw_glyph_string, x_define_frame_cursor, @@ -11602,6 +12335,10 @@ x_initialize (void) #endif #endif +#ifdef USE_CAIRO + x_cr_init_fringe (&x_redisplay_interface); +#endif + /* Note that there is no real way portable across R3/R4 to get the original error handler. */ XSetErrorHandler (x_error_handler); diff --git a/src/xterm.h b/src/xterm.h index e597227c81c..eb8eaae5de5 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -70,6 +70,19 @@ typedef GtkWidget *xt_or_gtk_widget; #define USE_GTK_TOOLTIP #endif +#ifdef USE_CAIRO +#include <cairo-xlib.h> +#ifdef CAIRO_HAS_PDF_SURFACE +#include <cairo-pdf.h> +#endif +#ifdef CAIRO_HAS_PS_SURFACE +#include <cairo-ps.h> +#endif +#ifdef CAIRO_HAS_SVG_SURFACE +#include <cairo-svg.h> +#endif +#endif + #ifdef HAVE_X_I18N #include <X11/Xlocale.h> #endif @@ -115,6 +128,9 @@ struct xim_inst_t struct x_bitmap_record { +#ifdef USE_CAIRO + void *img; +#endif Pixmap pixmap; bool have_mask; Pixmap mask; @@ -124,6 +140,19 @@ struct x_bitmap_record int height, width, depth; }; +#ifdef USE_CAIRO +struct x_gc_ext_data +{ +#define MAX_CLIP_RECTS 2 + /* Number of clipping rectangles. */ + int n_clip_rects; + + /* Clipping rectangles. */ + XRectangle clip_rects[MAX_CLIP_RECTS]; +}; +#endif + + /* For each X display, we have a structure that records information about it. */ @@ -411,6 +440,10 @@ struct x_display_info /* SM */ Atom Xatom_SM_CLIENT_ID; + +#ifdef USE_CAIRO + XExtCodes *ext_codes; +#endif }; #ifdef HAVE_X_I18N @@ -645,7 +678,6 @@ struct x_output /* The offset we need to add to compensate for type A WMs. */ int move_offset_top; int move_offset_left; -}; /* Extreme 'short' and 'long' values suitable for libX11. */ #define X_SHRT_MAX 0x7fff @@ -654,6 +686,14 @@ struct x_output #define X_LONG_MIN (-1 - X_LONG_MAX) #define X_ULONG_MAX 0xffffffffUL +#ifdef USE_CAIRO + /* Cairo drawing context. */ + cairo_t *cr_context; + /* Cairo surface for double buffering */ + cairo_surface_t *cr_surface; +#endif +}; + #define No_Cursor (None) enum @@ -1000,7 +1040,8 @@ extern bool x_alloc_lighter_color_for_widget (Widget, Display *, Colormap, double, int); #endif extern bool x_alloc_nearest_color (struct frame *, Colormap, XColor *); -extern void x_clear_area (Display *, Window, int, int, int, int); +extern void x_query_color (struct frame *f, XColor *); +extern void x_clear_area (struct frame *f, int, int, int, int); #if !defined USE_X_TOOLKIT && !defined USE_GTK extern void x_mouse_leave (struct x_display_info *); #endif @@ -1009,6 +1050,14 @@ extern void x_mouse_leave (struct x_display_info *); extern int x_dispatch_event (XEvent *, Display *); #endif extern int x_x_to_emacs_modifiers (struct x_display_info *, int); +#ifdef USE_CAIRO +extern cairo_t *x_begin_cr_clip (struct frame *, GC); +extern void x_end_cr_clip (struct frame *); +extern void x_set_cr_source_with_gc_foreground (struct frame *, GC); +extern void x_set_cr_source_with_gc_background (struct frame *, GC); +extern void x_cr_draw_frame (cairo_t *, struct frame *); +extern Lisp_Object x_cr_export_frames (Lisp_Object, cairo_surface_type_t); +#endif INLINE int x_display_pixel_height (struct x_display_info *dpyinfo) |