all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
To: Robert Pluim <rpluim@gmail.com>
Cc: 28236@debbugs.gnu.org, ari.roponen@gmail.com,
	andrei.elkin@pp.inet.fi, dgutov@yandex.ru
Subject: bug#28236: 'configure --with-cairo' causes 'emacs -font' to fail
Date: Tue, 04 Jun 2019 16:47:56 +0900	[thread overview]
Message-ID: <wl4l557pw3.wl-mituharu@math.s.chiba-u.ac.jp> (raw)
In-Reply-To: <m25zvxeaqy.fsf@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1904 bytes --]

On Thu, 13 Dec 2018 23:56:21 +0900,
Robert Pluim wrote:
> 
> >> So xfns.c only initializes the xfont driver when not using Cairo. I
> >> made the obvious changes there, and 'emacs -Q -fn 7x14' starts up, and
> >> 'C-u C-x =' tells me:
> >> 
> >>  x:-misc-fixed-medium-r-normal--14-130-75-75-c-70-iso8859-1 (#x68)
> >> 
> >> Unfortunately *scratch* does not (re-)display properly
> >
> > Can you tell more details about this improper redisplay?
> 
> I see text for the menu-bar, but *scratch* looks empty (and thereʼs no
> text displayed in the mode-line). The text is actually there in
> *scratch*, though.
> 
> I donʼt think this is a viable path to look at, especially given Ari's
> workaround of copying the required fonts.

Previously the cairo drawing code does its own double-buffering using
the image surface, where all the drawing should happen on the client
side and not compatible with X core fonts that are drawn on the server
side.  Copying back the result of server side drawing is not
impossible, but inefficient.

Recently, I've made a change to the cairo drawing code in the master
so it draws into Xlib surfaces instead of image ones if the X Double
Buffer Extension is available.  On top of that, it is rather
straightforward to cope with X core fonts.

I implemented both in the attached patch.  The former corresponds to
the case that the frame parameter `inhibit-double-buffering' is t, and
the latter to nil.  I think the latter is usable, but the former is
not.  The code for the former is not an total waste because we can use
it for exporting displayed contents to bitmap images, i.e.,
(x-export-frames FRAME 'png).  The same approach cannot be used for
exporting to outline images (PDF or SVG), so characters in X core
fonts are replaced with hollow boxes in such cases.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp

[-- Attachment #2: cairo-xfont.diff --]
[-- Type: application/octet-stream, Size: 9025 bytes --]

diff --git a/configure.ac b/configure.ac
index 0f1fd5d26ef..90f13b99fc3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5229,7 +5229,7 @@ AC_DEFUN
   XOBJ="xterm.o xfns.o xselect.o xrdb.o xsmfns.o xsettings.o"
   FONT_OBJ=xfont.o
   if test "$HAVE_CAIRO" = "yes"; then
-    FONT_OBJ="ftfont.o ftcrfont.o"
+    FONT_OBJ="$FONT_OBJ ftfont.o ftcrfont.o"
   elif test "$HAVE_XFT" = "yes"; then
     FONT_OBJ="$FONT_OBJ ftfont.o xftfont.o ftxfont.o"
   elif test "$HAVE_FREETYPE" = "yes"; then
diff --git a/src/font.c b/src/font.c
index 5ca89c97dcf..52bf5dae95b 100644
--- a/src/font.c
+++ b/src/font.c
@@ -5489,10 +5489,10 @@ cause Xft crashes.  Only has an effect in Xft builds.  */);
 #ifdef HAVE_FREETYPE
   syms_of_ftfont ();
 #ifdef HAVE_X_WINDOWS
+  syms_of_xfont ();
 #ifdef USE_CAIRO
   syms_of_ftcrfont ();
 #else
-  syms_of_xfont ();
   syms_of_ftxfont ();
 #ifdef HAVE_XFT
   syms_of_xftfont ();
diff --git a/src/xfns.c b/src/xfns.c
index 4195980d33e..1dcad6f3db1 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -3788,8 +3788,8 @@ This function is an internal primitive--use `make-frame' instead.  */)
   register_font_driver (&ftxfont_driver, f);
 #endif	/* not HAVE_XFT */
 #endif	/* HAVE_FREETYPE */
-  register_font_driver (&xfont_driver, f);
 #endif	/* not USE_CAIRO */
+  register_font_driver (&xfont_driver, f);
 
   image_cache_refcount =
     FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
diff --git a/src/xterm.c b/src/xterm.c
index ccc84dcc716..8c4df4efb01 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -357,6 +357,25 @@ x_cr_update_surface_desired_size (struct frame *f, int width, int height)
     }
 }
 
+static void
+x_cr_gc_clip (cairo_t *cr, struct frame *f, GC gc)
+{
+  if (gc)
+    {
+      struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
+
+      if (gc_ext && gc_ext->n_clip_rects)
+	{
+	  for (int i = 0; i < gc_ext->n_clip_rects; i++)
+	    cairo_rectangle (cr, gc_ext->clip_rects[i].x,
+			     gc_ext->clip_rects[i].y,
+			     gc_ext->clip_rects[i].width,
+			     gc_ext->clip_rects[i].height);
+	  cairo_clip (cr);
+	}
+    }
+}
+
 cairo_t *
 x_begin_cr_clip (struct frame *f, GC gc)
 {
@@ -379,23 +398,7 @@ x_begin_cr_clip (struct frame *f, GC gc)
       cairo_surface_destroy (surface);
     }
   cairo_save (cr);
-
-  if (gc)
-    {
-      struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
-
-      if (gc_ext && gc_ext->n_clip_rects)
-	{
-	  int i;
-
-	  for (i = 0; i < gc_ext->n_clip_rects; i++)
-	    cairo_rectangle (cr, gc_ext->clip_rects[i].x,
-			     gc_ext->clip_rects[i].y,
-			     gc_ext->clip_rects[i].width,
-			     gc_ext->clip_rects[i].height);
-	  cairo_clip (cr);
-	}
-    }
+  x_cr_gc_clip (cr, f, gc);
 
   return cr;
 }
@@ -434,6 +437,126 @@ x_set_cr_source_with_gc_background (struct frame *f, GC gc)
 			color.green / 65535.0, color.blue / 65535.0);
 }
 
+static const cairo_user_data_key_t xlib_surface_key, saved_drawable_key;
+
+static void
+x_cr_destroy_xlib_surface (cairo_surface_t *xlib_surface)
+{
+  if (xlib_surface)
+    {
+      XFreePixmap (cairo_xlib_surface_get_display (xlib_surface),
+		   cairo_xlib_surface_get_drawable (xlib_surface));
+      cairo_surface_destroy (xlib_surface);
+    }
+}
+
+static bool
+x_try_cr_xlib_drawable (struct frame *f, GC gc)
+{
+  cairo_t *cr = FRAME_CR_CONTEXT (f);
+  if (!cr)
+    return true;
+
+  cairo_surface_t *surface = cairo_get_target (cr);
+  switch (cairo_surface_get_type (surface))
+    {
+    case CAIRO_SURFACE_TYPE_XLIB:
+      cairo_surface_flush (surface);
+      return true;
+
+    case CAIRO_SURFACE_TYPE_IMAGE:
+      break;
+
+    default:
+      return false;
+    }
+
+  /* FRAME_CR_CONTEXT (f) is an image surface we can not draw directly
+     with Xlib.  Set up a Pixmap so we can copy back the result later
+     in x_end_cr_xlib_drawable.  */
+  cairo_surface_t *xlib_surface = cairo_get_user_data (cr, &xlib_surface_key);
+  int width = FRAME_CR_SURFACE_DESIRED_WIDTH (f);
+  int height = FRAME_CR_SURFACE_DESIRED_HEIGHT (f);
+  Pixmap pixmap;
+  if (xlib_surface
+      && cairo_xlib_surface_get_width (xlib_surface) == width
+      && cairo_xlib_surface_get_height (xlib_surface) == height)
+    pixmap = cairo_xlib_surface_get_drawable (xlib_surface);
+  else
+    {
+      pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_RAW_DRAWABLE (f),
+			      width, height,
+			      DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
+      xlib_surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
+						pixmap, FRAME_X_VISUAL (f),
+						width, height);
+      cairo_set_user_data (cr, &xlib_surface_key, xlib_surface,
+			   (cairo_destroy_func_t) x_cr_destroy_xlib_surface);
+    }
+
+#if 0				/* This seems to be unnecessary.  */
+  if (cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32)
+    {
+      cairo_surface_flush (xlib_surface);
+      XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_RAW_DRAWABLE (f), pixmap, gc,
+		 0, 0, width, height, 0, 0);
+      cairo_surface_mark_dirty (xlib_surface);
+    }
+#endif
+
+  cairo_t *buf = cairo_create (xlib_surface);
+  cairo_set_source_surface (buf, surface, 0, 0);
+  cairo_matrix_t matrix;
+  cairo_get_matrix (cr, &matrix);
+  cairo_pattern_set_matrix (cairo_get_source (cr), &matrix);
+  cairo_set_operator (buf, CAIRO_OPERATOR_SOURCE);
+  x_cr_gc_clip (buf, f, gc);
+  cairo_paint (buf);
+  cairo_destroy (buf);
+
+  cairo_set_user_data (cr, &saved_drawable_key,
+		       (void *) (uintptr_t) FRAME_X_RAW_DRAWABLE (f), NULL);
+  FRAME_X_RAW_DRAWABLE (f) = pixmap;
+  cairo_surface_flush (xlib_surface);
+
+  return true;
+}
+
+static void
+x_end_cr_xlib_drawable (struct frame *f, GC gc)
+{
+  cairo_t *cr = FRAME_CR_CONTEXT (f);
+  if (!cr)
+    return;
+
+  Drawable saved_drawable
+    = (uintptr_t) cairo_get_user_data (cr, &saved_drawable_key);
+  cairo_surface_t *surface = (saved_drawable
+			      ? cairo_get_user_data (cr, &xlib_surface_key)
+			      : cairo_get_target (cr));
+  struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
+  if (gc_ext && gc_ext->n_clip_rects)
+    for (int i = 0; i < gc_ext->n_clip_rects; i++)
+      cairo_surface_mark_dirty_rectangle (surface, gc_ext->clip_rects[i].x,
+					  gc_ext->clip_rects[i].y,
+					  gc_ext->clip_rects[i].width,
+					  gc_ext->clip_rects[i].height);
+  else
+    cairo_surface_mark_dirty (surface);
+  if (!saved_drawable)
+    return;
+
+  cairo_save (cr);
+  cairo_set_source_surface (cr, surface, 0, 0);
+  cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+  x_cr_gc_clip (cr, f, gc);
+  cairo_paint (cr);
+  cairo_restore (cr);
+
+  FRAME_X_RAW_DRAWABLE (f) = saved_drawable;
+  cairo_set_user_data (cr, &saved_drawable_key, NULL, NULL);
+}
+
 /* Fringe bitmaps.  */
 
 static int max_fringe_bmp = 0;
@@ -1739,6 +1862,33 @@ x_draw_glyph_string_foreground (struct glyph_string *s)
   else
     {
       struct font *font = s->font;
+#ifdef USE_CAIRO
+      if (EQ (font->driver->type, Qx)
+	  && !x_try_cr_xlib_drawable (s->f, s->gc))
+	{
+	  /* Fallback for the case that no Xlib Drawable is available
+	     for drawing text with X core fonts.  */
+	  if (!(s->for_overlaps
+		|| (s->background_filled_p && s->hl != DRAW_CURSOR)))
+	    {
+	      int box_line_width = max (s->face->box_line_width, 0);
+
+	      x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
+					 s->background_width,
+					 s->height - 2 * box_line_width);
+	    }
+	  for (i = 0; i < s->nchars; ++i)
+	    {
+	      struct glyph *g = s->first_glyph + i;
+	      x_draw_rectangle (s->f,
+				s->gc, x, s->y, g->pixel_width - 1,
+				s->height - 1);
+	      x += g->pixel_width;
+	    }
+	}
+      else
+	{
+#endif	/* USE_CAIRO */
       int boff = font->baseline_offset;
       int y;
 
@@ -1753,6 +1903,11 @@ x_draw_glyph_string_foreground (struct glyph_string *s)
 	font->driver->draw (s, 0, s->nchars, x, y, true);
       if (s->face->overstrike)
 	font->driver->draw (s, 0, s->nchars, x + 1, y, false);
+#ifdef USE_CAIRO
+	  if (EQ (font->driver->type, Qx))
+	    x_end_cr_xlib_drawable (s->f, s->gc);
+	}
+#endif	/* USE_CAIRO */
     }
 }
 
@@ -1785,7 +1940,21 @@ x_draw_composite_glyph_string_foreground (struct glyph_string *s)
 	x_draw_rectangle (s->f, s->gc, x, s->y,
 			s->width - 1, s->height - 1);
     }
-  else if (! s->first_glyph->u.cmp.automatic)
+  else
+#ifdef USE_CAIRO
+    if (EQ (font->driver->type, Qx)
+	&& !x_try_cr_xlib_drawable (s->f, s->gc))
+      {
+	/* Fallback for the case that no Xlib Drawable is available
+	   for drawing text with X core fonts.  */
+	if (s->cmp_from == 0)
+	  x_draw_rectangle (s->f, s->gc, x, s->y,
+			    s->width - 1, s->height - 1);
+      }
+    else
+      {
+#endif	/* USE_CAIRO */
+  if (! s->first_glyph->u.cmp.automatic)
     {
       int y = s->ybase;
 
@@ -1844,6 +2013,11 @@ x_draw_composite_glyph_string_foreground (struct glyph_string *s)
 	    font->driver->draw (s, j, i, x + 1, y, false);
 	}
     }
+#ifdef USE_CAIRO
+	if (EQ (font->driver->type, Qx))
+	  x_end_cr_xlib_drawable (s->f, s->gc);
+      }
+#endif	/* USE_CAIRO */
 }
 
 

  reply	other threads:[~2019-06-04  7:47 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-25 19:57 bug#28236: 'configure --with-cairo' causes 'emacs -font' to fail andrei.elkin
2017-08-26  7:24 ` Eli Zaretskii
2018-12-11  1:50 ` Dmitry Gutov
2018-12-11  6:25   ` Eli Zaretskii
2018-12-12 12:03     ` Ari Roponen
2018-12-12 15:16       ` Eli Zaretskii
2018-12-12 15:41         ` Robert Pluim
2018-12-12 16:37           ` Eli Zaretskii
2018-12-13 11:34             ` Robert Pluim
2018-12-13 13:52               ` Eli Zaretskii
2018-12-13 14:56                 ` Robert Pluim
2019-06-04  7:47                   ` YAMAMOTO Mitsuharu [this message]
2019-06-08  5:13                     ` YAMAMOTO Mitsuharu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=wl4l557pw3.wl-mituharu@math.s.chiba-u.ac.jp \
    --to=mituharu@math.s.chiba-u.ac.jp \
    --cc=28236@debbugs.gnu.org \
    --cc=andrei.elkin@pp.inet.fi \
    --cc=ari.roponen@gmail.com \
    --cc=dgutov@yandex.ru \
    --cc=rpluim@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.