]> git.eshelyaron.com Git - emacs.git/commitdiff
Add some code for transparent frame backgrounds without Cairo
authorPo Lu <luangruo@yahoo.com>
Mon, 24 Jan 2022 04:44:55 +0000 (12:44 +0800)
committerPo Lu <luangruo@yahoo.com>
Mon, 24 Jan 2022 04:44:55 +0000 (12:44 +0800)
* 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'.

src/image.c
src/xfns.c
src/xftfont.c
src/xterm.c
src/xterm.h

index 7ee595297fad564da06390b2a30cca2a25d90e19..951531505e693c0b7059f65b75686a35c2d45cb4 100644 (file)
@@ -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))
     {
index 7123198724a237f52c759d002db1944e1b8ce37b..92aed2d46a71b1fdf7aee1789595d1728a4e92ed 100644 (file)
@@ -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))
index f305738410e2ad39adaa7d50dc4289a2c4fbf687..c2175d961416370e3b5d8d9f81e2d2df1386909b 100644 (file)
@@ -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);
index cc0e1a4485d5ece8408424f0a17a1376fc414d9e..436238c4a1723be257fe200fd1d97a1f9d8f05f3 100644 (file)
@@ -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)
 {
index a4ad57eddaaf5dc6b6fe181581101e05e3a60d8b..33887be52b01039f403643fcdf6689c46cafd61f 100644 (file)
@@ -54,6 +54,10 @@ typedef Widget xt_or_gtk_widget;
 #define GTK_CHECK_VERSION(i, j, k) false
 #endif
 
+#ifdef HAVE_XRENDER
+#include <X11/extensions/Xrender.h>
+#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;
 };
 \f
-#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)
 {