aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Third2019-11-09 17:04:25 +0000
committerAlan Third2019-11-29 21:22:26 +0000
commit3e9c82d99902230812c10e8d464f4908a8a6ea42 (patch)
treec5698e1d0c7158a63af8572148d0592731dfe209
parentb1a69505843c593a3a757a614dea16e2a7185579 (diff)
downloademacs-3e9c82d99902230812c10e8d464f4908a8a6ea42.tar.gz
emacs-3e9c82d99902230812c10e8d464f4908a8a6ea42.zip
Fix image scaling with masks (bug#38109)
* src/image.c (lookup_image): Move call to image_set_transform after postprocess_image. (image_create_x_image_and_pixmap_1): Use new function. (image_set_transform): Apply the transform to the mask too. (x_create_xrender_picture): New function. (Create_Pixmap_From_Bitmap_Data): (xpm_load): Use new function. * src/xterm.c (x_composite_image): Use PictOpOver when there is a mask so the transparency is honoured. (x_draw_image_foreground_1): Use x_composite_image.
-rw-r--r--src/image.c147
-rw-r--r--src/xterm.c11
2 files changed, 106 insertions, 52 deletions
diff --git a/src/image.c b/src/image.c
index 870f008b14f..70d932f9edb 100644
--- a/src/image.c
+++ b/src/image.c
@@ -2244,6 +2244,14 @@ image_set_transform (struct frame *f, struct image *img)
2244 XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest, 2244 XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest,
2245 0, 0); 2245 0, 0);
2246 XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat); 2246 XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat);
2247
2248 if (img->mask_picture)
2249 {
2250 XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->mask_picture,
2251 FilterBest, 0, 0);
2252 XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->mask_picture,
2253 &tmat);
2254 }
2247 } 2255 }
2248# elif defined HAVE_NTGUI 2256# elif defined HAVE_NTGUI
2249 /* Store the transform matrix for application at draw time. */ 2257 /* Store the transform matrix for application at draw time. */
@@ -2313,10 +2321,6 @@ lookup_image (struct frame *f, Lisp_Object spec)
2313 Lisp_Object ascent, margin, relief, bg; 2321 Lisp_Object ascent, margin, relief, bg;
2314 int relief_bound; 2322 int relief_bound;
2315 2323
2316#ifdef HAVE_NATIVE_TRANSFORMS
2317 image_set_transform (f, img);
2318#endif
2319
2320 ascent = image_spec_value (spec, QCascent, NULL); 2324 ascent = image_spec_value (spec, QCascent, NULL);
2321 if (FIXNUMP (ascent)) 2325 if (FIXNUMP (ascent))
2322 img->ascent = XFIXNUM (ascent); 2326 img->ascent = XFIXNUM (ascent);
@@ -2357,6 +2361,13 @@ lookup_image (struct frame *f, Lisp_Object spec)
2357 don't have the image yet. */ 2361 don't have the image yet. */
2358 if (!EQ (builtin_lisp_symbol (img->type->type), Qpostscript)) 2362 if (!EQ (builtin_lisp_symbol (img->type->type), Qpostscript))
2359 postprocess_image (f, img); 2363 postprocess_image (f, img);
2364
2365 /* postprocess_image above may modify the image or the mask,
2366 relying on the image's real width and height, so
2367 image_set_transform must be called after it. */
2368#ifdef HAVE_NATIVE_TRANSFORMS
2369 image_set_transform (f, img);
2370#endif
2360 } 2371 }
2361 2372
2362 unblock_input (); 2373 unblock_input ();
@@ -2527,6 +2538,61 @@ x_destroy_x_image (XImage *ximg)
2527 } 2538 }
2528} 2539}
2529 2540
2541# if !defined USE_CAIRO && defined HAVE_XRENDER
2542/* Create and return an XRender Picture for XRender transforms. */
2543static Picture
2544x_create_xrender_picture (struct frame *f, Emacs_Pixmap pixmap, int depth)
2545{
2546 Picture p;
2547 Display *display = FRAME_X_DISPLAY (f);
2548 int event_basep, error_basep;
2549
2550 if (XRenderQueryExtension (display, &event_basep, &error_basep))
2551 {
2552 if (depth <= 0)
2553 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
2554 if (depth == 32 || depth == 24 || depth == 8 || depth == 4 || depth == 1)
2555 {
2556 /* FIXME: Do we need to handle all possible bit depths?
2557 XRenderFindStandardFormat supports PictStandardARGB32,
2558 PictStandardRGB24, PictStandardA8, PictStandardA4,
2559 PictStandardA1, and PictStandardNUM (what is this?!).
2560
2561 XRenderFindFormat may support more, but I don't
2562 understand the documentation. */
2563 XRenderPictFormat *format;
2564 format = XRenderFindStandardFormat (display,
2565 depth == 32 ? PictStandardARGB32
2566 : depth == 24 ? PictStandardRGB24
2567 : depth == 8 ? PictStandardA8
2568 : depth == 4 ? PictStandardA4
2569 : PictStandardA1);
2570
2571 /* Set the Picture repeat to "pad". This means when
2572 operations look at pixels outside the image area they
2573 will use the value of the nearest real pixel instead of
2574 using a transparent black pixel. */
2575 XRenderPictureAttributes attr;
2576 unsigned long attr_mask = CPRepeat;
2577 attr.repeat = RepeatPad;
2578
2579 p = XRenderCreatePicture (display, pixmap, format, attr_mask, &attr);
2580 }
2581 else
2582 {
2583 image_error ("Specified image bit depth is not supported by XRender");
2584 return 0;
2585 }
2586 }
2587 else
2588 {
2589 /* XRender not supported on this display. */
2590 return 0;
2591 }
2592
2593 return p;
2594}
2595# endif /* !defined USE_CAIRO && defined HAVE_XRENDER */
2530#endif /* HAVE_X_WINDOWS */ 2596#endif /* HAVE_X_WINDOWS */
2531 2597
2532/* Return true if XIMG's size WIDTH x HEIGHT doesn't break the 2598/* Return true if XIMG's size WIDTH x HEIGHT doesn't break the
@@ -2579,36 +2645,8 @@ image_create_x_image_and_pixmap_1 (struct frame *f, int width, int height, int d
2579 if (!x_create_x_image_and_pixmap (f, width, height, depth, pimg, pixmap)) 2645 if (!x_create_x_image_and_pixmap (f, width, height, depth, pimg, pixmap))
2580 return 0; 2646 return 0;
2581# ifdef HAVE_XRENDER 2647# ifdef HAVE_XRENDER
2582 Display *display = FRAME_X_DISPLAY (f); 2648 if (picture)
2583 int event_basep, error_basep; 2649 *picture = x_create_xrender_picture (f, *pixmap, depth);
2584 if (picture && XRenderQueryExtension (display, &event_basep, &error_basep))
2585 {
2586 if (depth <= 0)
2587 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
2588 if (depth == 32 || depth == 24 || depth == 8)
2589 {
2590 XRenderPictFormat *format;
2591 XRenderPictureAttributes attr;
2592
2593 /* FIXME: Do we need to handle all possible bit depths?
2594 XRenderFindStandardFormat supports PictStandardARGB32,
2595 PictStandardRGB24, PictStandardA8, PictStandardA4,
2596 PictStandardA1, and PictStandardNUM (what is this?!).
2597
2598 XRenderFindFormat may support more, but I don't
2599 understand the documentation. */
2600 format = XRenderFindStandardFormat (display,
2601 depth == 32 ? PictStandardARGB32
2602 : depth == 24 ? PictStandardRGB24
2603 : PictStandardA8);
2604 *picture = XRenderCreatePicture (display, *pixmap, format, 0, &attr);
2605 }
2606 else
2607 {
2608 image_error ("Specified image bit depth is not supported by XRender");
2609 *picture = 0;
2610 }
2611 }
2612# endif 2650# endif
2613 2651
2614 return 1; 2652 return 1;
@@ -3387,6 +3425,11 @@ Create_Pixmap_From_Bitmap_Data (struct frame *f, struct image *img, char *data,
3387 img->width, img->height, 3425 img->width, img->height,
3388 fg, bg, 3426 fg, bg,
3389 DefaultDepthOfScreen (FRAME_X_SCREEN (f))); 3427 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
3428# if !defined USE_CAIRO && defined HAVE_XRENDER
3429 if (img->pixmap)
3430 img->picture = x_create_xrender_picture (f, img->pixmap, 0);
3431# endif
3432
3390#elif defined HAVE_NTGUI 3433#elif defined HAVE_NTGUI
3391 img->pixmap 3434 img->pixmap
3392 = w32_create_pixmap_from_bitmap_data (img->width, img->height, data); 3435 = w32_create_pixmap_from_bitmap_data (img->width, img->height, data);
@@ -4359,18 +4402,30 @@ xpm_load (struct frame *f, struct image *img)
4359 image_clear_image (f, img); 4402 image_clear_image (f, img);
4360 rc = XpmNoMemory; 4403 rc = XpmNoMemory;
4361 } 4404 }
4362 else if (img->mask_img) 4405 else
4363 { 4406 {
4364 img->mask = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), 4407# if !defined USE_CAIRO && defined HAVE_XRENDER
4365 img->mask_img->width, 4408 img->picture = x_create_xrender_picture (f, img->pixmap,
4366 img->mask_img->height, 4409 img->ximg->depth);
4367 img->mask_img->depth); 4410# endif
4368 if (img->mask == NO_PIXMAP) 4411 if (img->mask_img)
4369 { 4412 {
4370 image_clear_image (f, img); 4413 img->mask = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
4371 rc = XpmNoMemory; 4414 img->mask_img->width,
4372 } 4415 img->mask_img->height,
4373 } 4416 img->mask_img->depth);
4417 if (img->mask == NO_PIXMAP)
4418 {
4419 image_clear_image (f, img);
4420 rc = XpmNoMemory;
4421 }
4422# if !defined USE_CAIRO && defined HAVE_XRENDER
4423 else
4424 img->mask_picture = x_create_xrender_picture
4425 (f, img->mask, img->mask_img->depth);
4426# endif
4427 }
4428 }
4374 } 4429 }
4375#endif 4430#endif
4376 4431
diff --git a/src/xterm.c b/src/xterm.c
index d55bc3890d6..9a6eda4488d 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -3049,14 +3049,12 @@ x_composite_image (struct glyph_string *s, Pixmap dest,
3049 XRenderPictFormat *default_format; 3049 XRenderPictFormat *default_format;
3050 XRenderPictureAttributes attr; 3050 XRenderPictureAttributes attr;
3051 3051
3052 /* FIXME: Should we do this each time or would it make sense to
3053 store destination in the frame struct? */
3054 default_format = XRenderFindVisualFormat (display, 3052 default_format = XRenderFindVisualFormat (display,
3055 DefaultVisual (display, 0)); 3053 DefaultVisual (display, 0));
3056 destination = XRenderCreatePicture (display, dest, 3054 destination = XRenderCreatePicture (display, dest,
3057 default_format, 0, &attr); 3055 default_format, 0, &attr);
3058 3056
3059 XRenderComposite (display, PictOpSrc, 3057 XRenderComposite (display, s->img->mask_picture ? PictOpOver : PictOpSrc,
3060 s->img->picture, s->img->mask_picture, destination, 3058 s->img->picture, s->img->mask_picture, destination,
3061 srcX, srcY, 3059 srcX, srcY,
3062 srcX, srcY, 3060 srcX, srcY,
@@ -3315,6 +3313,7 @@ x_draw_image_foreground_1 (struct glyph_string *s, Pixmap pixmap)
3315 trust on the shape extension to be available 3313 trust on the shape extension to be available
3316 (XShapeCombineRegion). So, compute the rectangle to draw 3314 (XShapeCombineRegion). So, compute the rectangle to draw
3317 manually. */ 3315 manually. */
3316 /* FIXME: Do we need to do this when using XRender compositing? */
3318 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin 3317 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3319 | GCFunction); 3318 | GCFunction);
3320 XGCValues xgcv; 3319 XGCValues xgcv;
@@ -3325,9 +3324,9 @@ x_draw_image_foreground_1 (struct glyph_string *s, Pixmap pixmap)
3325 xgcv.function = GXcopy; 3324 xgcv.function = GXcopy;
3326 XChangeGC (display, s->gc, mask, &xgcv); 3325 XChangeGC (display, s->gc, mask, &xgcv);
3327 3326
3328 XCopyArea (display, s->img->pixmap, pixmap, s->gc, 3327 x_composite_image (s, pixmap,
3329 s->slice.x, s->slice.y, 3328 s->slice.x, s->slice.y,
3330 s->slice.width, s->slice.height, x, y); 3329 x, y, s->slice.width, s->slice.height);
3331 XSetClipMask (display, s->gc, None); 3330 XSetClipMask (display, s->gc, None);
3332 } 3331 }
3333 else 3332 else