From 2755cf1848b551436b9cc2eff6e4b882b10c07aa Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Wed, 27 Mar 2019 11:04:46 +0900 Subject: [PATCH] Support native image resizing on cairo * src/xterm.c (x_cr_draw_image): Add arguments image_width and image_height and support scaling. All callers changed. * src/image.c (Fimage_scaling_p): Return t when USE_CAIRO. (x_set_image_size) [USE_CAIRO]: Record the scaled dimensions in the image struct. * src/dispextern.h (HAVE_NATIVE_SCALING): Define when USE_CAIRO as well. * etc/NEWS: Update the announcement of native image scaling. --- etc/NEWS | 6 +++--- src/dispextern.h | 2 +- src/image.c | 7 +++++-- src/xterm.c | 34 +++++++++++++++++++++++++--------- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 71127ac7250..7486d6bcfed 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1718,9 +1718,9 @@ the process. That way 'make-process' can start remote processes. +++ ** Emacs now supports resizing (scaling) of images without ImageMagick. All modern systems are supported by this feature. (On GNU and Unix -systems, the XRender extension to X11 is required for this to be -available; the configure script will test for it and, if found, enable -scaling.) +systems, Cairo drawing or the XRender extension to X11 is required for +this to be available; the configure script will test for it and, if +found, enable scaling.) The new function 'image-scaling-p' can be used to test whether any given frame supports resizing. diff --git a/src/dispextern.h b/src/dispextern.h index 4d96e51d73b..1a536563532 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -2938,7 +2938,7 @@ struct redisplay_interface #ifdef HAVE_WINDOW_SYSTEM -# if defined HAVE_XRENDER || defined HAVE_NS || defined HAVE_NTGUI +# if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS || defined HAVE_NTGUI # define HAVE_NATIVE_SCALING # endif diff --git a/src/image.c b/src/image.c index 16c5978db6e..6e415ef1f70 100644 --- a/src/image.c +++ b/src/image.c @@ -1878,7 +1878,10 @@ x_set_image_size (struct frame *f, struct image *img) img->height = height; # endif -# ifdef HAVE_XRENDER +# ifdef USE_CAIRO + img->width = width; + img->height = height; +# elif defined HAVE_XRENDER if (img->picture) { double xscale = img->width / (double) width; @@ -9918,7 +9921,7 @@ DEFUN ("image-scaling-p", Fimage_scaling_p, Simage_scaling_p, 0, 1, 0, Return t if FRAME supports native scaling, nil otherwise. */) (Lisp_Object frame) { -#if defined (HAVE_NS) || defined (HAVE_NTGUI) +#if defined (USE_CAIRO) || defined (HAVE_NS) || defined (HAVE_NTGUI) return Qt; #elif defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER) int event_basep, error_basep; diff --git a/src/xterm.c b/src/xterm.c index 33eb0f3b5e3..f90d6713b02 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -480,13 +480,12 @@ x_cr_destroy_fringe_bitmap (int which) static void x_cr_draw_image (struct frame *f, GC gc, cairo_surface_t *image, + int image_width, int image_height, int src_x, int src_y, int width, int height, int dest_x, int dest_y, bool overlay_p) { - cairo_t *cr; - cairo_format_t format; + cairo_t *cr = x_begin_cr_clip (f, gc); - cr = x_begin_cr_clip (f, gc); if (overlay_p) cairo_rectangle (cr, dest_x, dest_y, width, height); else @@ -495,18 +494,33 @@ x_cr_draw_image (struct frame *f, GC gc, cairo_surface_t *image, cairo_rectangle (cr, dest_x, dest_y, width, height); cairo_fill_preserve (cr); } - format = cairo_image_surface_get_format (image); + + int orig_image_width = cairo_image_surface_get_width (image); + if (image_width == 0) image_width = orig_image_width; + int orig_image_height = cairo_image_surface_get_height (image); + if (image_height == 0) image_height = orig_image_height; + + cairo_pattern_t *pattern = cairo_pattern_create_for_surface (image); + cairo_matrix_t matrix; + cairo_matrix_init_scale (&matrix, orig_image_width / (double) image_width, + orig_image_height / (double) image_height); + cairo_matrix_translate (&matrix, src_x - dest_x, src_y - dest_y); + cairo_pattern_set_matrix (pattern, &matrix); + + cairo_format_t format = cairo_image_surface_get_format (image); if (format != CAIRO_FORMAT_A8 && format != CAIRO_FORMAT_A1) { - cairo_set_source_surface (cr, image, dest_x - src_x, dest_y - src_y); + cairo_set_source (cr, pattern); cairo_fill (cr); } else { x_set_cr_source_with_gc_foreground (f, gc); cairo_clip (cr); - cairo_mask_surface (cr, image, dest_x - src_x, dest_y - src_y); + cairo_mask (cr, pattern); } + cairo_pattern_destroy (pattern); + x_end_cr_clip (f); } @@ -1430,7 +1444,7 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring : 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, + x_cr_draw_image (f, gc, fringe_bmp[p->which], 0, 0, 0, p->dh, p->wd, p->h, p->x, p->y, p->overlay_p); XSetForeground (display, gc, gcv.foreground); XSetBackground (display, gc, gcv.background); @@ -3041,8 +3055,10 @@ x_draw_image_foreground (struct glyph_string *s) if (s->img->cr_data) { x_set_glyph_string_clipping (s); - x_cr_draw_image (s->f, s->gc, s->img->cr_data, s->slice.x, s->slice.y, - s->slice.width, s->slice.height, x, y, true); + x_cr_draw_image (s->f, s->gc, + s->img->cr_data, s->img->width, s->img->height, + s->slice.x, s->slice.y, s->slice.width, s->slice.height, + x, y, true); if (!s->img->mask) { /* When the image has a mask, we can expect that at -- 2.39.5