From: Po Lu Date: Mon, 24 Jan 2022 04:44:55 +0000 (+0800) Subject: Add some code for transparent frame backgrounds without Cairo X-Git-Tag: emacs-29.0.90~2824 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=45208755d13f23f92edcab4d6959e0fd9423843b;p=emacs.git Add some code for transparent frame backgrounds without Cairo * src/image.c (svg_load_image): Fix build without native image transforms. * src/xfns.c (set_up_x_back_buffer): (tear_down_x_back_buffer): Free XR picture if present. * src/xftfont.c (xftfont_get_xft_draw): Fix formatting issue. * src/xterm.c (x_xr_ensure_picture): New function. (FRAME_CR_CONTEXT, FRAME_CR_CONTEXT): (FRAME_CR_SURFACE_DESIRED_WIDTH) (FRAME_CR_SURFACE_DESIRED_HEIGHT): Move to separate USE_CAIRO block so the ext data code can be used on builds with XRender as well. (x_xr_apply_ext_clip): (x_xr_reset_ext_clip): New functions. (x_set_clip_rectangles): (x_reset_clip_rectangles): Set ext data on XRender as well. (x_term_init): Look for a picture format appropriate for our purposes. (x_clear_area): Use XRenderFillRectangle to draw backgrounds if available. (x_xrender_color_from_gc_foreground): (x_xrender_color_from_gc_background): New functions. * src/xterm.h (FRAME_X_PICTURE): (FRAME_X_PICTURE_FORMAT) (FRAME_CHECK_XR_VERSION): New macros. (struct x_gc_ext_data): Define on XRender as well. (struct x_display_info): Define ext_codes when using XRender and add new field `pict_format'. (struct x_output): New field `picture'. --- diff --git a/src/image.c b/src/image.c index 7ee595297fa..951531505e6 100644 --- a/src/image.c +++ b/src/image.c @@ -10672,11 +10672,16 @@ svg_load_image (struct frame *f, struct image *img, char *contents, viewbox_height = dimension_data.height; #endif +#ifdef HAVE_NATIVE_TRANSFORMS compute_image_size (viewbox_width, viewbox_height, img, &width, &height); width = scale_image_size (width, 1, FRAME_SCALE_FACTOR (f)); height = scale_image_size (height, 1, FRAME_SCALE_FACTOR (f)); +#else + width = viewbox_width; + height = viewbox_height; +#endif if (! check_image_size (f, width, height)) { diff --git a/src/xfns.c b/src/xfns.c index 7123198724a..92aed2d46a7 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -3267,6 +3267,17 @@ x_mark_frame_dirty (struct frame *f) static void set_up_x_back_buffer (struct frame *f) { +#ifdef HAVE_XRENDER + block_input (); + if (FRAME_X_PICTURE (f) != None) + { + XRenderFreePicture (FRAME_X_DISPLAY (f), + FRAME_X_PICTURE (f)); + FRAME_X_PICTURE (f) = None; + } + unblock_input (); +#endif + #ifdef HAVE_XDBE block_input (); if (FRAME_X_WINDOW (f) && !FRAME_X_DOUBLE_BUFFERED_P (f)) @@ -3281,10 +3292,10 @@ set_up_x_back_buffer (struct frame *f) server ran out of memory or we don't have the right kind of visual, just use single-buffered rendering. */ x_catch_errors (FRAME_X_DISPLAY (f)); - FRAME_X_RAW_DRAWABLE (f) = XdbeAllocateBackBufferName ( - FRAME_X_DISPLAY (f), - FRAME_X_WINDOW (f), - XdbeCopied); + FRAME_X_RAW_DRAWABLE (f) + = XdbeAllocateBackBufferName (FRAME_X_DISPLAY (f), + FRAME_X_WINDOW (f), + XdbeCopied); if (x_had_errors_p (FRAME_X_DISPLAY (f))) FRAME_X_RAW_DRAWABLE (f) = FRAME_X_WINDOW (f); x_uncatch_errors_after_check (); @@ -3297,6 +3308,17 @@ set_up_x_back_buffer (struct frame *f) void tear_down_x_back_buffer (struct frame *f) { +#ifdef HAVE_XRENDER + block_input (); + if (FRAME_X_PICTURE (f) != None) + { + XRenderFreePicture (FRAME_X_DISPLAY (f), + FRAME_X_PICTURE (f)); + FRAME_X_PICTURE (f) = None; + } + unblock_input (); +#endif + #ifdef HAVE_XDBE block_input (); if (FRAME_X_WINDOW (f) && FRAME_X_DOUBLE_BUFFERED_P (f)) diff --git a/src/xftfont.c b/src/xftfont.c index f305738410e..c2175d96141 100644 --- a/src/xftfont.c +++ b/src/xftfont.c @@ -441,10 +441,10 @@ xftfont_get_xft_draw (struct frame *f) if (! xft_draw) { block_input (); - xft_draw= XftDrawCreate (FRAME_X_DISPLAY (f), - FRAME_X_DRAWABLE (f), - FRAME_X_VISUAL (f), - FRAME_X_COLORMAP (f)); + xft_draw = XftDrawCreate (FRAME_X_DISPLAY (f), + FRAME_X_DRAWABLE (f), + FRAME_X_VISUAL (f), + FRAME_X_COLORMAP (f)); unblock_input (); eassert (xft_draw != NULL); font_put_frame_data (f, Qxft, xft_draw); diff --git a/src/xterm.c b/src/xterm.c index cc0e1a4485d..436238c4a17 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -358,6 +358,22 @@ x_flush (struct frame *f) unblock_input (); } +#ifdef HAVE_XRENDER +MAYBE_UNUSED static void +x_xr_ensure_picture (struct frame *f) +{ + if (FRAME_X_PICTURE (f) == None && FRAME_X_PICTURE_FORMAT (f)) + { + XRenderPictureAttributes attrs; + attrs.clip_mask = None; + + FRAME_X_PICTURE (f) = XRenderCreatePicture (FRAME_X_DISPLAY (f), + FRAME_X_RAW_DRAWABLE (f), + FRAME_X_PICTURE_FORMAT (f), + CPClipMask, &attrs); + } +} +#endif /* Remove calls to XFlush by defining XFlush to an empty replacement. Calls to XFlush should be unnecessary because the X output buffer @@ -401,14 +417,7 @@ record_event (char *locus, int type) #endif -#ifdef USE_CAIRO - -#define FRAME_CR_CONTEXT(f) ((f)->output_data.x->cr_context) -#define FRAME_CR_SURFACE_DESIRED_WIDTH(f) \ - ((f)->output_data.x->cr_surface_desired_width) -#define FRAME_CR_SURFACE_DESIRED_HEIGHT(f) \ - ((f)->output_data.x->cr_surface_desired_height) - +#if defined USE_CAIRO || defined HAVE_XRENDER static struct x_gc_ext_data * x_gc_get_ext_data (struct frame *f, GC gc, int create_if_not_found_p) { @@ -441,6 +450,15 @@ x_extension_initialize (struct x_display_info *dpyinfo) dpyinfo->ext_codes = ext_codes; } +#endif + +#ifdef USE_CAIRO + +#define FRAME_CR_CONTEXT(f) ((f)->output_data.x->cr_context) +#define FRAME_CR_SURFACE_DESIRED_WIDTH(f) \ + ((f)->output_data.x->cr_surface_desired_width) +#define FRAME_CR_SURFACE_DESIRED_HEIGHT(f) \ + ((f)->output_data.x->cr_surface_desired_height) #endif /* HAVE_CAIRO */ @@ -1184,11 +1202,37 @@ x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type) #endif /* USE_CAIRO */ +#if defined HAVE_XRENDER && !defined USE_CAIRO +MAYBE_UNUSED static void +x_xr_apply_ext_clip (struct frame *f, GC gc) +{ + eassert (FRAME_X_PICTURE (f) != None); + + struct x_gc_ext_data *data = x_gc_get_ext_data (f, gc, 1); + + if (data->n_clip_rects) + XRenderSetPictureClipRectangles (FRAME_X_DISPLAY (f), + FRAME_X_PICTURE (f), + 0, 0, data->clip_rects, + data->n_clip_rects); +} + +MAYBE_UNUSED static void +x_xr_reset_ext_clip (struct frame *f) +{ + XRenderPictureAttributes attrs = { .clip_mask = None }; + + XRenderChangePicture (FRAME_X_DISPLAY (f), + FRAME_X_PICTURE (f), + CPClipMask, &attrs); +} +#endif + static void x_set_clip_rectangles (struct frame *f, GC gc, XRectangle *rectangles, int n) { XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, rectangles, n, Unsorted); -#ifdef USE_CAIRO +#if defined USE_CAIRO || defined HAVE_XRENDER eassert (n >= 0 && n <= MAX_CLIP_RECTS); { @@ -1204,7 +1248,7 @@ static void x_reset_clip_rectangles (struct frame *f, GC gc) { XSetClipMask (FRAME_X_DISPLAY (f), gc, None); -#ifdef USE_CAIRO +#if defined USE_CAIRO || defined HAVE_XRENDER { struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0); @@ -4510,10 +4554,31 @@ x_clear_area (struct frame *f, int x, int y, int width, int height) #ifndef USE_GTK if (FRAME_X_DOUBLE_BUFFERED_P (f)) #endif - XFillRectangle (FRAME_X_DISPLAY (f), - FRAME_X_DRAWABLE (f), - f->output_data.x->reverse_gc, - x, y, width, height); + { +#if defined HAVE_XRENDER && \ + (RENDER_MAJOR > 0 || (RENDER_MINOR >= 2)) + x_xr_ensure_picture (f); + if (FRAME_X_PICTURE (f) != None + && FRAME_CHECK_XR_VERSION (f, 0, 2)) + { + XRenderColor xc; + GC gc = f->output_data.x->reverse_gc; + + x_xr_apply_ext_clip (f, gc); + x_xrender_color_from_gc_foreground (f, gc, &xc); + XRenderFillRectangle (FRAME_X_DISPLAY (f), + PictOpSrc, FRAME_X_PICTURE (f), + &xc, x, y, width, height); + x_xr_reset_ext_clip (f); + x_mark_frame_dirty (f); + } + else +#endif + XFillRectangle (FRAME_X_DISPLAY (f), + FRAME_X_DRAWABLE (f), + f->output_data.x->reverse_gc, + x, y, width, height); + } #ifndef USE_GTK else x_clear_area1 (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), @@ -15431,6 +15496,9 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) if (!XRenderQueryVersion (dpyinfo->display, &dpyinfo->xrender_major, &dpyinfo->xrender_minor)) dpyinfo->xrender_supported_p = false; + else + dpyinfo->pict_format = XRenderFindVisualFormat (dpyinfo->display, + dpyinfo->visual); } #endif @@ -15714,7 +15782,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) x_session_initialize (dpyinfo); #endif -#ifdef USE_CAIRO +#if defined USE_CAIRO || defined HAVE_XRENDER x_extension_initialize (dpyinfo); #endif @@ -16090,6 +16158,40 @@ init_xterm (void) } #endif +#ifdef HAVE_XRENDER +void +x_xrender_color_from_gc_foreground (struct frame *f, GC gc, XRenderColor *color) +{ + XGCValues xgcv; + XColor xc; + + XGetGCValues (FRAME_X_DISPLAY (f), gc, GCForeground, &xgcv); + xc.pixel = xgcv.foreground; + x_query_colors (f, &xc, 1); + + color->alpha = 65535; + color->red = xc.red; + color->blue = xc.blue; + color->green = xc.green; +} + +void +x_xrender_color_from_gc_background (struct frame *f, GC gc, XRenderColor *color) +{ + XGCValues xgcv; + XColor xc; + + XGetGCValues (FRAME_X_DISPLAY (f), gc, GCBackground, &xgcv); + xc.pixel = xgcv.foreground; + x_query_colors (f, &xc, 1); + + color->alpha = 65535; + color->red = xc.red; + color->blue = xc.blue; + color->green = xc.green; +} +#endif + void syms_of_xterm (void) { diff --git a/src/xterm.h b/src/xterm.h index a4ad57eddaa..33887be52b0 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -54,6 +54,10 @@ typedef Widget xt_or_gtk_widget; #define GTK_CHECK_VERSION(i, j, k) false #endif +#ifdef HAVE_XRENDER +#include +#endif + #ifdef USE_GTK /* Some definitions to reduce conditionals. */ typedef GtkWidget *xt_or_gtk_widget; @@ -148,7 +152,7 @@ struct x_bitmap_record int height, width, depth; }; -#ifdef USE_CAIRO +#if defined USE_CAIRO || defined HAVE_XRENDER struct x_gc_ext_data { #define MAX_CLIP_RECTS 2 @@ -158,7 +162,9 @@ struct x_gc_ext_data /* Clipping rectangles. */ XRectangle clip_rects[MAX_CLIP_RECTS]; }; +#endif +#ifdef USE_CAIRO extern cairo_pattern_t *x_bitmap_stipple (struct frame *, Pixmap); #endif @@ -239,6 +245,11 @@ struct x_display_info /* The Visual being used for this display. */ Visual *visual; +#ifdef HAVE_XRENDER + /* The picture format for this display. */ + XRenderPictFormat *pict_format; +#endif + /* The colormap being used. */ Colormap cmap; @@ -509,7 +520,7 @@ struct x_display_info int xrandr_minor_version; #endif -#ifdef USE_CAIRO +#if defined USE_CAIRO || defined HAVE_XRENDER XExtCodes *ext_codes; #endif @@ -616,6 +627,13 @@ struct x_output window's back buffer. */ Drawable draw_desc; +#ifdef HAVE_XRENDER + /* The Xrender picture that corresponds to this drawable. None + means no picture format was found, or the Xrender extension is + not present. */ + Picture picture; +#endif + /* Flag that indicates whether we've modified the back buffer and need to publish our modifications to the front buffer at a convenient time. */ @@ -933,6 +951,17 @@ extern void x_mark_frame_dirty (struct frame *f); /* This is the Visual which frame F is on. */ #define FRAME_X_VISUAL(f) FRAME_DISPLAY_INFO (f)->visual +#ifdef HAVE_XRENDER +#define FRAME_X_PICTURE_FORMAT(f) FRAME_DISPLAY_INFO (f)->pict_format +#define FRAME_X_PICTURE(f) ((f)->output_data.x->picture) +#define FRAME_CHECK_XR_VERSION(f, major, minor) \ + (FRAME_DISPLAY_INFO (f)->xrender_supported_p \ + && ((FRAME_DISPLAY_INFO (f)->xrender_major == (major) \ + && FRAME_DISPLAY_INFO (f)->xrender_minor >= (minor)) \ + || (FRAME_DISPLAY_INFO (f)->xrender_major > (major)))) +#endif + + /* This is the Colormap which frame F uses. */ #define FRAME_X_COLORMAP(f) FRAME_DISPLAY_INFO (f)->cmap @@ -1212,6 +1241,11 @@ extern void x_cr_draw_frame (cairo_t *, struct frame *); extern Lisp_Object x_cr_export_frames (Lisp_Object, cairo_surface_type_t); #endif +#ifdef HAVE_XRENDER +extern void x_xrender_color_from_gc_foreground (struct frame *, GC, XRenderColor *); +extern void x_xrender_color_from_gc_background (struct frame *, GC, XRenderColor *); +#endif + INLINE int x_display_pixel_height (struct x_display_info *dpyinfo) {