aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorYAMAMOTO Mitsuharu2019-06-08 13:05:15 +0900
committerYAMAMOTO Mitsuharu2019-06-08 13:05:15 +0900
commit88c49ac31898e7b2c29338ca55cae292c450f7be (patch)
tree6130d1732acceaf2eef70327acb724c14171934d /src
parent890a0826f3f68f4476f6ec0b56fe96c6bc047142 (diff)
downloademacs-88c49ac31898e7b2c29338ca55cae292c450f7be.tar.gz
emacs-88c49ac31898e7b2c29338ca55cae292c450f7be.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/dispextern.h2
-rw-r--r--src/gtkutil.c5
-rw-r--r--src/image.c74
-rw-r--r--src/xterm.c38
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
3016 synchronized to Pixmap. */ 3016 synchronized to Pixmap. */
3017 XImage *ximg, *mask_img; 3017 XImage *ximg, *mask_img;
3018 3018
3019# ifdef HAVE_NATIVE_TRANSFORMS 3019# if !defined USE_CAIRO && defined HAVE_XRENDER
3020 /* Picture versions of pixmap and mask for compositing. */ 3020 /* Picture versions of pixmap and mask for compositing. */
3021 Picture picture, mask_picture; 3021 Picture picture, mask_picture;
3022# endif 3022# 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,
394 certain themes. */ 394 certain themes. */
395 395
396#ifdef USE_CAIRO 396#ifdef USE_CAIRO
397 surface = img->cr_data; 397 if (cairo_pattern_get_type (img->cr_data) == CAIRO_PATTERN_TYPE_SURFACE)
398 cairo_pattern_get_surface (img->cr_data, &surface);
399 else
400 surface = NULL;
398 401
399 if (surface) 402 if (surface)
400 { 403 {
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,
207} 207}
208 208
209static cairo_surface_t * 209static cairo_surface_t *
210cr_create_cr_surface_from_image (struct frame *f, struct image *img) 210cr_create_surface_from_pix_containers (Emacs_Pix_Container pimg,
211 Emacs_Pix_Container mask)
211{ 212{
212 Emacs_Pix_Container pimg = img->pixmap;
213 cairo_surface_t *surface; 213 cairo_surface_t *surface;
214 214
215 if (img->mask) 215 if (mask)
216 { 216 {
217 int x, y; 217 int x, y;
218 218
@@ -223,30 +223,49 @@ cr_create_cr_surface_from_image (struct frame *f, struct image *img)
223 int r, g, b; 223 int r, g, b;
224 224
225 color = GET_PIXEL (pimg, x, y); 225 color = GET_PIXEL (pimg, x, y);
226 alpha = GET_PIXEL (img->mask, x, y); 226 alpha = GET_PIXEL (mask, x, y);
227 r = (RED_FROM_ULONG (color) * alpha + 0x7f) / 0xff; 227 r = (RED_FROM_ULONG (color) * alpha + 0x7f) / 0xff;
228 g = (GREEN_FROM_ULONG (color) * alpha + 0x7f) / 0xff; 228 g = (GREEN_FROM_ULONG (color) * alpha + 0x7f) / 0xff;
229 b = (BLUE_FROM_ULONG (color) * alpha + 0x7f) / 0xff; 229 b = (BLUE_FROM_ULONG (color) * alpha + 0x7f) / 0xff;
230 PUT_PIXEL (pimg, x, y, ARGB_TO_ULONG (alpha, r, g, b)); 230 PUT_PIXEL (pimg, x, y, ARGB_TO_ULONG (alpha, r, g, b));
231 } 231 }
232 xfree (img->mask->data); 232 xfree (mask->data);
233 img->mask->data = NULL; 233 mask->data = NULL;
234 } 234 }
235 block_input ();
236 surface = cairo_image_surface_create_for_data ((unsigned char *) pimg->data, 235 surface = cairo_image_surface_create_for_data ((unsigned char *) pimg->data,
237 (img->mask 236 (mask ? CAIRO_FORMAT_ARGB32
238 ? CAIRO_FORMAT_ARGB32
239 : CAIRO_FORMAT_RGB24), 237 : CAIRO_FORMAT_RGB24),
240 pimg->width, pimg->height, 238 pimg->width, pimg->height,
241 pimg->bytes_per_line); 239 pimg->bytes_per_line);
242 static const cairo_user_data_key_t key; 240 static const cairo_user_data_key_t key;
243 cairo_surface_set_user_data (surface, &key, pimg->data, xfree); 241 cairo_surface_set_user_data (surface, &key, pimg->data, xfree);
244 unblock_input ();
245 pimg->data = NULL; 242 pimg->data = NULL;
246 243
247 return surface; 244 return surface;
248} 245}
249 246
247static void
248cr_put_image_to_cr_data (struct image *img)
249{
250 cairo_pattern_t *pattern = NULL;
251 cairo_surface_t *surface = cr_create_surface_from_pix_containers (img->pixmap,
252 img->mask);
253 if (surface)
254 {
255 pattern = cairo_pattern_create_for_surface (surface);
256 if (img->cr_data)
257 {
258 cairo_matrix_t matrix;
259 cairo_pattern_get_matrix (img->cr_data, &matrix);
260 cairo_pattern_set_matrix (pattern, &matrix);
261 cairo_pattern_destroy (img->cr_data);
262 }
263 cairo_surface_destroy (surface);
264 }
265
266 img->cr_data = pattern;
267}
268
250#endif /* USE_CAIRO */ 269#endif /* USE_CAIRO */
251 270
252#ifdef HAVE_NS 271#ifdef HAVE_NS
@@ -1150,7 +1169,7 @@ free_image (struct frame *f, struct image *img)
1150 1169
1151 c->images[img->id] = NULL; 1170 c->images[img->id] = NULL;
1152 1171
1153#ifdef HAVE_XRENDER 1172#if !defined USE_CAIRO && defined HAVE_XRENDER
1154 if (img->picture) 1173 if (img->picture)
1155 XRenderFreePicture (FRAME_X_DISPLAY (f), img->picture); 1174 XRenderFreePicture (FRAME_X_DISPLAY (f), img->picture);
1156 if (img->mask_picture) 1175 if (img->mask_picture)
@@ -1212,14 +1231,20 @@ prepare_image_for_display (struct frame *f, struct image *img)
1212 img->load_failed_p = ! img->type->load (f, img); 1231 img->load_failed_p = ! img->type->load (f, img);
1213 1232
1214#ifdef USE_CAIRO 1233#ifdef USE_CAIRO
1215 if (!img->load_failed_p && img->cr_data == NULL) 1234 if (!img->load_failed_p)
1216 { 1235 {
1217 img->cr_data = cr_create_cr_surface_from_image (f, img); 1236 block_input ();
1218 if (img->cr_data == NULL) 1237 if (img->cr_data == NULL || (cairo_pattern_get_type (img->cr_data)
1238 != CAIRO_PATTERN_TYPE_SURFACE))
1219 { 1239 {
1220 img->load_failed_p = 1; 1240 cr_put_image_to_cr_data (img);
1221 img->type->free (f, img); 1241 if (img->cr_data == NULL)
1242 {
1243 img->load_failed_p = 1;
1244 img->type->free (f, img);
1245 }
1222 } 1246 }
1247 unblock_input ();
1223 } 1248 }
1224#elif defined HAVE_X_WINDOWS 1249#elif defined HAVE_X_WINDOWS
1225 if (!img->load_failed_p) 1250 if (!img->load_failed_p)
@@ -1470,7 +1495,7 @@ image_clear_image_1 (struct frame *f, struct image *img, int flags)
1470#ifdef USE_CAIRO 1495#ifdef USE_CAIRO
1471 if (img->cr_data) 1496 if (img->cr_data)
1472 { 1497 {
1473 cairo_surface_destroy ((cairo_surface_t *) img->cr_data); 1498 cairo_pattern_destroy (img->cr_data);
1474 img->cr_data = NULL; 1499 img->cr_data = NULL;
1475 } 1500 }
1476#endif /* USE_CAIRO */ 1501#endif /* USE_CAIRO */
@@ -1973,7 +1998,7 @@ image_set_rotation (struct image *img, matrix3x3 tm)
1973 return; 1998 return;
1974# endif 1999# endif
1975 2000
1976# ifdef HAVE_XRENDER 2001# if !defined USE_CAIRO && defined HAVE_XRENDER
1977 if (!img->picture) 2002 if (!img->picture)
1978 return; 2003 return;
1979# endif 2004# endif
@@ -2064,7 +2089,7 @@ image_set_crop (struct image *img, matrix3x3 tm)
2064 return; 2089 return;
2065# endif 2090# endif
2066 2091
2067# ifdef HAVE_XRENDER 2092# if !defined USE_CAIRO && defined HAVE_XRENDER
2068 if (!img->picture) 2093 if (!img->picture)
2069 return; 2094 return;
2070# endif 2095# endif
@@ -2156,7 +2181,7 @@ image_set_size (struct image *img, matrix3x3 tm)
2156 return; 2181 return;
2157# endif 2182# endif
2158 2183
2159# ifdef HAVE_XRENDER 2184# if !defined USE_CAIRO && defined HAVE_XRENDER
2160 if (!img->picture) 2185 if (!img->picture)
2161 return; 2186 return;
2162# endif 2187# endif
@@ -2186,6 +2211,13 @@ image_set_transform (struct frame *f, struct image *img, matrix3x3 matrix)
2186 /* Under NS the transform is applied to the drawing surface at 2211 /* Under NS the transform is applied to the drawing surface at
2187 drawing time, so store it for later. */ 2212 drawing time, so store it for later. */
2188 ns_image_set_transform (img->pixmap, matrix); 2213 ns_image_set_transform (img->pixmap, matrix);
2214# elif defined USE_CAIRO
2215 cairo_matrix_t cr_matrix = {matrix[0][0], matrix[0][1], matrix[1][0],
2216 matrix[1][1], matrix[2][0], matrix[2][1]};
2217 cairo_pattern_t *pattern = cairo_pattern_create_rgb (0, 0, 0);
2218 cairo_pattern_set_matrix (pattern, &cr_matrix);
2219 /* Dummy solid color pattern just to record pattern matrix. */
2220 img->cr_data = pattern;
2189# elif defined (HAVE_XRENDER) 2221# elif defined (HAVE_XRENDER)
2190 if (img->picture) 2222 if (img->picture)
2191 { 2223 {
@@ -2745,7 +2777,7 @@ image_create_x_image_and_pixmap (struct frame *f, struct image *img,
2745 eassert ((!mask_p ? img->pixmap : img->mask) == NO_PIXMAP); 2777 eassert ((!mask_p ? img->pixmap : img->mask) == NO_PIXMAP);
2746 2778
2747 Picture *picture = NULL; 2779 Picture *picture = NULL;
2748#ifdef HAVE_XRENDER 2780#if !defined USE_CAIRO && defined HAVE_XRENDER
2749 picture = !mask_p ? &img->picture : &img->mask_picture; 2781 picture = !mask_p ? &img->picture : &img->mask_picture;
2750#endif 2782#endif
2751 return image_create_x_image_and_pixmap_1 (f, width, height, depth, ximg, 2783 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)
437/* Fringe bitmaps. */ 437/* Fringe bitmaps. */
438 438
439static int max_fringe_bmp = 0; 439static int max_fringe_bmp = 0;
440static cairo_surface_t **fringe_bmp = 0; 440static cairo_pattern_t **fringe_bmp = 0;
441 441
442static void 442static void
443x_cr_define_fringe_bitmap (int which, unsigned short *bits, int h, int wd) 443x_cr_define_fringe_bitmap (int which, unsigned short *bits, int h, int wd)
444{ 444{
445 int i, stride; 445 int i, stride;
446 cairo_surface_t *surface; 446 cairo_surface_t *surface;
447 cairo_pattern_t *pattern;
447 unsigned char *data; 448 unsigned char *data;
448 449
449 if (which >= max_fringe_bmp) 450 if (which >= max_fringe_bmp)
@@ -468,10 +469,12 @@ x_cr_define_fringe_bitmap (int which, unsigned short *bits, int h, int wd)
468 } 469 }
469 470
470 cairo_surface_mark_dirty (surface); 471 cairo_surface_mark_dirty (surface);
472 pattern = cairo_pattern_create_for_surface (surface);
473 cairo_surface_destroy (surface);
471 474
472 unblock_input (); 475 unblock_input ();
473 476
474 fringe_bmp[which] = surface; 477 fringe_bmp[which] = pattern;
475} 478}
476 479
477static void 480static void
@@ -483,15 +486,14 @@ x_cr_destroy_fringe_bitmap (int which)
483 if (fringe_bmp[which]) 486 if (fringe_bmp[which])
484 { 487 {
485 block_input (); 488 block_input ();
486 cairo_surface_destroy (fringe_bmp[which]); 489 cairo_pattern_destroy (fringe_bmp[which]);
487 unblock_input (); 490 unblock_input ();
488 } 491 }
489 fringe_bmp[which] = 0; 492 fringe_bmp[which] = 0;
490} 493}
491 494
492static void 495static void
493x_cr_draw_image (struct frame *f, GC gc, cairo_surface_t *image, 496x_cr_draw_image (struct frame *f, GC gc, cairo_pattern_t *image,
494 int image_width, int image_height,
495 int src_x, int src_y, int width, int height, 497 int src_x, int src_y, int width, int height,
496 int dest_x, int dest_y, bool overlay_p) 498 int dest_x, int dest_y, bool overlay_p)
497{ 499{
@@ -506,31 +508,22 @@ x_cr_draw_image (struct frame *f, GC gc, cairo_surface_t *image,
506 cairo_fill_preserve (cr); 508 cairo_fill_preserve (cr);
507 } 509 }
508 510
509 int orig_image_width = cairo_image_surface_get_width (image); 511 cairo_translate (cr, dest_x - src_x, dest_y - src_y);
510 if (image_width == 0) image_width = orig_image_width;
511 int orig_image_height = cairo_image_surface_get_height (image);
512 if (image_height == 0) image_height = orig_image_height;
513
514 cairo_pattern_t *pattern = cairo_pattern_create_for_surface (image);
515 cairo_matrix_t matrix;
516 cairo_matrix_init_scale (&matrix, orig_image_width / (double) image_width,
517 orig_image_height / (double) image_height);
518 cairo_matrix_translate (&matrix, src_x - dest_x, src_y - dest_y);
519 cairo_pattern_set_matrix (pattern, &matrix);
520 512
521 cairo_format_t format = cairo_image_surface_get_format (image); 513 cairo_surface_t *surface;
514 cairo_pattern_get_surface (image, &surface);
515 cairo_format_t format = cairo_image_surface_get_format (surface);
522 if (format != CAIRO_FORMAT_A8 && format != CAIRO_FORMAT_A1) 516 if (format != CAIRO_FORMAT_A8 && format != CAIRO_FORMAT_A1)
523 { 517 {
524 cairo_set_source (cr, pattern); 518 cairo_set_source (cr, image);
525 cairo_fill (cr); 519 cairo_fill (cr);
526 } 520 }
527 else 521 else
528 { 522 {
529 x_set_cr_source_with_gc_foreground (f, gc); 523 x_set_cr_source_with_gc_foreground (f, gc);
530 cairo_clip (cr); 524 cairo_clip (cr);
531 cairo_mask (cr, pattern); 525 cairo_mask (cr, image);
532 } 526 }
533 cairo_pattern_destroy (pattern);
534 527
535 x_end_cr_clip (f); 528 x_end_cr_clip (f);
536} 529}
@@ -1352,7 +1345,7 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring
1352 : f->output_data.x->cursor_pixel) 1345 : f->output_data.x->cursor_pixel)
1353 : face->foreground)); 1346 : face->foreground));
1354 XSetBackground (display, gc, face->background); 1347 XSetBackground (display, gc, face->background);
1355 x_cr_draw_image (f, gc, fringe_bmp[p->which], 0, 0, 0, p->dh, 1348 x_cr_draw_image (f, gc, fringe_bmp[p->which], 0, p->dh,
1356 p->wd, p->h, p->x, p->y, p->overlay_p); 1349 p->wd, p->h, p->x, p->y, p->overlay_p);
1357 XSetForeground (display, gc, gcv.foreground); 1350 XSetForeground (display, gc, gcv.foreground);
1358 XSetBackground (display, gc, gcv.background); 1351 XSetBackground (display, gc, gcv.background);
@@ -2929,8 +2922,7 @@ x_draw_image_foreground (struct glyph_string *s)
2929 if (s->img->cr_data) 2922 if (s->img->cr_data)
2930 { 2923 {
2931 x_set_glyph_string_clipping (s); 2924 x_set_glyph_string_clipping (s);
2932 x_cr_draw_image (s->f, s->gc, 2925 x_cr_draw_image (s->f, s->gc, s->img->cr_data,
2933 s->img->cr_data, s->img->width, s->img->height,
2934 s->slice.x, s->slice.y, s->slice.width, s->slice.height, 2926 s->slice.x, s->slice.y, s->slice.width, s->slice.height,
2935 x, y, true); 2927 x, y, true);
2936 if (!s->img->mask) 2928 if (!s->img->mask)