From 88c49ac31898e7b2c29338ca55cae292c450f7be Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Sat, 8 Jun 2019 13:05:15 +0900 Subject: [PATCH] Implement native image rotation and cropping on cairo * src/dispextern.h (struct image) [USE_CAIRO]: * src/image.c (free_image, image_clear_image_1) (image_set_crop, image_set_size, image_set_rotation) (image_create_x_image_and_pixmap) [USE_CAIRO]: #ifdef out HAVE_XRENDER part. * src/image.c (cr_create_surface_from_pix_containers) [USE_CAIRO]: Rename from cr_create_surface_from_pix_containers. Change arguments to pair of Emacs_Pix_Container:s. Move block_input and unblock_input to caller. (cr_put_image_to_cr_data) [USE_CAIRO]: New function. (prepare_image_for_display) [USE_CAIRO]: Use it. (image_set_transform) [USE_CAIRO]: Create dummy solid color pattern equipped with transformation matrix and set it to img->cr_data. * src/xterm.c (fringe_bmp) [USE_CAIRO]: Change type to cairo_pattern_t **. (x_cr_define_fringe_bitmap, x_cr_destroy_fringe_bitmap) [USE_CAIRO]: Create or destroy cairo pattern. (x_cr_draw_image) [USE_CAIRO]: Remove arguments image_width and image_height. Change type of image to cairo pattern. All callers changed. * src/gtkutil.c (xg_get_image_for_pixmap) [USE_CAIRO]: Get cairo surface from img->cr_data, which is of cairo pattern now. --- src/dispextern.h | 2 +- src/gtkutil.c | 5 +++- src/image.c | 74 ++++++++++++++++++++++++++++++++++-------------- src/xterm.c | 38 ++++++++++--------------- 4 files changed, 73 insertions(+), 46 deletions(-) diff --git a/src/dispextern.h b/src/dispextern.h index 9ba8e746b22..cc2d963a96b 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3016,7 +3016,7 @@ struct image synchronized to Pixmap. */ XImage *ximg, *mask_img; -# ifdef HAVE_NATIVE_TRANSFORMS +# if !defined USE_CAIRO && defined HAVE_XRENDER /* Picture versions of pixmap and mask for compositing. */ Picture picture, mask_picture; # endif diff --git a/src/gtkutil.c b/src/gtkutil.c index 59e4328a6fc..dccee159254 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -394,7 +394,10 @@ xg_get_image_for_pixmap (struct frame *f, certain themes. */ #ifdef USE_CAIRO - surface = img->cr_data; + if (cairo_pattern_get_type (img->cr_data) == CAIRO_PATTERN_TYPE_SURFACE) + cairo_pattern_get_surface (img->cr_data, &surface); + else + surface = NULL; if (surface) { diff --git a/src/image.c b/src/image.c index 30f4f4b0bc5..86f8e8f4bb7 100644 --- a/src/image.c +++ b/src/image.c @@ -207,12 +207,12 @@ image_pix_container_create_from_bitmap_data (struct frame *f, } static cairo_surface_t * -cr_create_cr_surface_from_image (struct frame *f, struct image *img) +cr_create_surface_from_pix_containers (Emacs_Pix_Container pimg, + Emacs_Pix_Container mask) { - Emacs_Pix_Container pimg = img->pixmap; cairo_surface_t *surface; - if (img->mask) + if (mask) { int x, y; @@ -223,30 +223,49 @@ cr_create_cr_surface_from_image (struct frame *f, struct image *img) int r, g, b; color = GET_PIXEL (pimg, x, y); - alpha = GET_PIXEL (img->mask, x, y); + alpha = GET_PIXEL (mask, x, y); r = (RED_FROM_ULONG (color) * alpha + 0x7f) / 0xff; g = (GREEN_FROM_ULONG (color) * alpha + 0x7f) / 0xff; b = (BLUE_FROM_ULONG (color) * alpha + 0x7f) / 0xff; PUT_PIXEL (pimg, x, y, ARGB_TO_ULONG (alpha, r, g, b)); } - xfree (img->mask->data); - img->mask->data = NULL; + xfree (mask->data); + mask->data = NULL; } - block_input (); surface = cairo_image_surface_create_for_data ((unsigned char *) pimg->data, - (img->mask - ? CAIRO_FORMAT_ARGB32 + (mask ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24), pimg->width, pimg->height, pimg->bytes_per_line); static const cairo_user_data_key_t key; cairo_surface_set_user_data (surface, &key, pimg->data, xfree); - unblock_input (); pimg->data = NULL; return surface; } +static void +cr_put_image_to_cr_data (struct image *img) +{ + cairo_pattern_t *pattern = NULL; + cairo_surface_t *surface = cr_create_surface_from_pix_containers (img->pixmap, + img->mask); + if (surface) + { + pattern = cairo_pattern_create_for_surface (surface); + if (img->cr_data) + { + cairo_matrix_t matrix; + cairo_pattern_get_matrix (img->cr_data, &matrix); + cairo_pattern_set_matrix (pattern, &matrix); + cairo_pattern_destroy (img->cr_data); + } + cairo_surface_destroy (surface); + } + + img->cr_data = pattern; +} + #endif /* USE_CAIRO */ #ifdef HAVE_NS @@ -1150,7 +1169,7 @@ free_image (struct frame *f, struct image *img) c->images[img->id] = NULL; -#ifdef HAVE_XRENDER +#if !defined USE_CAIRO && defined HAVE_XRENDER if (img->picture) XRenderFreePicture (FRAME_X_DISPLAY (f), img->picture); if (img->mask_picture) @@ -1212,14 +1231,20 @@ prepare_image_for_display (struct frame *f, struct image *img) img->load_failed_p = ! img->type->load (f, img); #ifdef USE_CAIRO - if (!img->load_failed_p && img->cr_data == NULL) + if (!img->load_failed_p) { - img->cr_data = cr_create_cr_surface_from_image (f, img); - if (img->cr_data == NULL) + block_input (); + if (img->cr_data == NULL || (cairo_pattern_get_type (img->cr_data) + != CAIRO_PATTERN_TYPE_SURFACE)) { - img->load_failed_p = 1; - img->type->free (f, img); + cr_put_image_to_cr_data (img); + if (img->cr_data == NULL) + { + img->load_failed_p = 1; + img->type->free (f, img); + } } + unblock_input (); } #elif defined HAVE_X_WINDOWS if (!img->load_failed_p) @@ -1470,7 +1495,7 @@ image_clear_image_1 (struct frame *f, struct image *img, int flags) #ifdef USE_CAIRO if (img->cr_data) { - cairo_surface_destroy ((cairo_surface_t *) img->cr_data); + cairo_pattern_destroy (img->cr_data); img->cr_data = NULL; } #endif /* USE_CAIRO */ @@ -1973,7 +1998,7 @@ image_set_rotation (struct image *img, matrix3x3 tm) return; # endif -# ifdef HAVE_XRENDER +# if !defined USE_CAIRO && defined HAVE_XRENDER if (!img->picture) return; # endif @@ -2064,7 +2089,7 @@ image_set_crop (struct image *img, matrix3x3 tm) return; # endif -# ifdef HAVE_XRENDER +# if !defined USE_CAIRO && defined HAVE_XRENDER if (!img->picture) return; # endif @@ -2156,7 +2181,7 @@ image_set_size (struct image *img, matrix3x3 tm) return; # endif -# ifdef HAVE_XRENDER +# if !defined USE_CAIRO && defined HAVE_XRENDER if (!img->picture) return; # endif @@ -2186,6 +2211,13 @@ image_set_transform (struct frame *f, struct image *img, matrix3x3 matrix) /* Under NS the transform is applied to the drawing surface at drawing time, so store it for later. */ ns_image_set_transform (img->pixmap, matrix); +# elif defined USE_CAIRO + cairo_matrix_t cr_matrix = {matrix[0][0], matrix[0][1], matrix[1][0], + matrix[1][1], matrix[2][0], matrix[2][1]}; + cairo_pattern_t *pattern = cairo_pattern_create_rgb (0, 0, 0); + cairo_pattern_set_matrix (pattern, &cr_matrix); + /* Dummy solid color pattern just to record pattern matrix. */ + img->cr_data = pattern; # elif defined (HAVE_XRENDER) if (img->picture) { @@ -2745,7 +2777,7 @@ image_create_x_image_and_pixmap (struct frame *f, struct image *img, eassert ((!mask_p ? img->pixmap : img->mask) == NO_PIXMAP); Picture *picture = NULL; -#ifdef HAVE_XRENDER +#if !defined USE_CAIRO && defined HAVE_XRENDER picture = !mask_p ? &img->picture : &img->mask_picture; #endif return image_create_x_image_and_pixmap_1 (f, width, height, depth, ximg, diff --git a/src/xterm.c b/src/xterm.c index c064647da0c..e0edd9c1a40 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -437,13 +437,14 @@ x_set_cr_source_with_gc_background (struct frame *f, GC gc) /* Fringe bitmaps. */ static int max_fringe_bmp = 0; -static cairo_surface_t **fringe_bmp = 0; +static cairo_pattern_t **fringe_bmp = 0; static void x_cr_define_fringe_bitmap (int which, unsigned short *bits, int h, int wd) { int i, stride; cairo_surface_t *surface; + cairo_pattern_t *pattern; unsigned char *data; if (which >= max_fringe_bmp) @@ -468,10 +469,12 @@ x_cr_define_fringe_bitmap (int which, unsigned short *bits, int h, int wd) } cairo_surface_mark_dirty (surface); + pattern = cairo_pattern_create_for_surface (surface); + cairo_surface_destroy (surface); unblock_input (); - fringe_bmp[which] = surface; + fringe_bmp[which] = pattern; } static void @@ -483,15 +486,14 @@ x_cr_destroy_fringe_bitmap (int which) if (fringe_bmp[which]) { block_input (); - cairo_surface_destroy (fringe_bmp[which]); + cairo_pattern_destroy (fringe_bmp[which]); unblock_input (); } fringe_bmp[which] = 0; } static void -x_cr_draw_image (struct frame *f, GC gc, cairo_surface_t *image, - int image_width, int image_height, +x_cr_draw_image (struct frame *f, GC gc, cairo_pattern_t *image, int src_x, int src_y, int width, int height, int dest_x, int dest_y, bool overlay_p) { @@ -506,31 +508,22 @@ x_cr_draw_image (struct frame *f, GC gc, cairo_surface_t *image, cairo_fill_preserve (cr); } - 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_translate (cr, dest_x - src_x, dest_y - src_y); - cairo_format_t format = cairo_image_surface_get_format (image); + cairo_surface_t *surface; + cairo_pattern_get_surface (image, &surface); + cairo_format_t format = cairo_image_surface_get_format (surface); if (format != CAIRO_FORMAT_A8 && format != CAIRO_FORMAT_A1) { - cairo_set_source (cr, pattern); + cairo_set_source (cr, image); cairo_fill (cr); } else { x_set_cr_source_with_gc_foreground (f, gc); cairo_clip (cr); - cairo_mask (cr, pattern); + cairo_mask (cr, image); } - cairo_pattern_destroy (pattern); x_end_cr_clip (f); } @@ -1352,7 +1345,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, 0, 0, p->dh, + 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); @@ -2929,8 +2922,7 @@ 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->img->width, s->img->height, + 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); if (!s->img->mask) -- 2.39.2