]> git.eshelyaron.com Git - emacs.git/commitdiff
Support X core font driver on cairo (Bug#28236)
authorYAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
Sat, 8 Jun 2019 05:05:49 +0000 (14:05 +0900)
committerYAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
Sat, 8 Jun 2019 05:05:49 +0000 (14:05 +0900)
* configure.ac (HAVE_X_WINDOWS): Add xfont.o to FONT_OBJ if HAVE_CAIRO.

* doc/lispref/frames.texi (Font and Color Parameters): Mention X core font
driver with Cairo drawing.

* src/font.c (syms_of_font) [HAVE_X_WINDOWS && USE_CAIRO]: Call syms_of_xfont.

* src/xfns.c (x_create_tip_frame) [USE_CAIRO]: Register xfont_driver.

* src/xterm.c (x_cr_gc_clip) [USE_CAIRO]: New function extracted from
x_begin_cr_clip.
(x_begin_cr_clip) [USE_CAIRO]: Use it.
(xlib_surface_key, saved_drawable_key) [USE_CAIRO]: New variables.
(x_cr_destroy_xlib_surface, x_try_cr_xlib_drawable)
(x_end_cr_xlib_drawable) [USE_CAIRO]: New functions.
(x_draw_composite_glyph_string_foreground)
(x_draw_glyph_string_foreground) [USE_CAIRO]: Get Xlib surface when drawing
text with X core fonts into bitmap surfaces.  Add fallback code for drawing
into outline surfaces.

configure.ac
doc/lispref/frames.texi
src/font.c
src/xfns.c
src/xterm.c

index bd51f54212c8a59917b768e22a84e3f0a64f85ae..5c96f4231eed53ff1c1407d22a8c953f795a07ae 100644 (file)
@@ -5261,7 +5261,7 @@ if test "${HAVE_X_WINDOWS}" = "yes" ; then
   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
index 336075a1ca2d0b631a6ffa8447477444a15fb419..629cec3c5fe39bc422296e5343a6a9f50c8ae93b 100644 (file)
@@ -2282,11 +2282,11 @@ drawing characters on the frame, in order of priority.  In Emacs built
 without Cairo drawing on X, there are currently three available font
 backends: @code{x} (the X core font driver), @code{xft} (the Xft font
 driver), and @code{xfthb} (the Xft font driver with HarfBuzz text
-shaping).  If built with the Cairo drawing, there are two available
-font backends on X: @code{ftcr} (the FreeType font driver on Cairo)
-and @code{ftcrhb} (the FreeType font driver on Cairo with HarfBuzz
-text shaping).  On MS-Windows, there are currently three available
-font backends: @code{gdi} (the core MS-Windows font driver),
+shaping).  If built with the Cairo drawing, there are also three
+available font backends on X: @code{x}, @code{ftcr} (the FreeType font
+driver on Cairo), and @code{ftcrhb} (the FreeType font driver on Cairo
+with HarfBuzz text shaping).  On MS-Windows, there are currently three
+available font backends: @code{gdi} (the core MS-Windows font driver),
 @code{uniscribe} (font driver for OTF and TTF fonts with text shaping
 by the Uniscribe engine), and @code{harfbuzz} (font driver for OTF and
 TTF fonts with HarfBuzz text shaping) (@pxref{Windows Fonts,,, emacs,
index 6ab4923c3d2997f9f65330a891b6d31848ac7547..5705758b99f546ba316774627f196c91c7423902 100644 (file)
@@ -5497,10 +5497,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 ();
index 460dd1316e62cd47dc568dbae8c1929be46696bc..46f19ff82ac5871cffdd1f7d01534ca5649188c0 100644 (file)
@@ -3794,8 +3794,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;
index e0edd9c1a40a3ebbf8a5285d29932be510e080e7..3cd95b7a65d6d379d7a4f1dc7d6b7c582234d4fc 100644 (file)
@@ -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,116 @@ 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 into
+     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);
+    }
+
+  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;
@@ -1732,20 +1845,65 @@ x_draw_glyph_string_foreground (struct glyph_string *s)
   else
     {
       struct font *font = s->font;
-      int boff = font->baseline_offset;
-      int y;
+#ifdef USE_CAIRO
+      if (!EQ (font->driver->type, Qx)
+         || x_try_cr_xlib_drawable (s->f, s->gc))
+       {
+#endif /* USE_CAIRO */
+         int boff = font->baseline_offset;
+         int y;
 
-      if (font->vertical_centering)
-       boff = VCENTER_BASELINE_OFFSET (font, s->f) - boff;
+         if (font->vertical_centering)
+           boff = VCENTER_BASELINE_OFFSET (font, s->f) - boff;
 
-      y = s->ybase - boff;
-      if (s->for_overlaps
-         || (s->background_filled_p && s->hl != DRAW_CURSOR))
-       font->driver->draw (s, 0, s->nchars, x, y, false);
+         y = s->ybase - boff;
+         if (s->for_overlaps
+             || (s->background_filled_p && s->hl != DRAW_CURSOR))
+           font->driver->draw (s, 0, s->nchars, x, y, false);
+         else
+           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);
+       }
       else
-       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);
+       {
+         /* 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);
+
+             if (s->stippled_p)
+               {
+                 Display *display = FRAME_X_DISPLAY (s->f);
+
+                 /* Fill background with a stipple pattern.  */
+                 XSetFillStyle (display, s->gc, FillOpaqueStippled);
+                 x_fill_rectangle (s->f, s->gc, s->x,
+                                   s->y + box_line_width,
+                                   s->background_width,
+                                   s->height - 2 * box_line_width);
+                 XSetFillStyle (display, s->gc, FillSolid);
+               }
+             else
+               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;
+           }
+       }
+#endif /* USE_CAIRO */
     }
 }
 
@@ -1778,65 +1936,84 @@ 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)
-    {
-      int y = s->ybase;
-
-      for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
-       /* TAB in a composition means display glyphs with padding
-          space on the left or right.  */
-       if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
-         {
-           int xx = x + s->cmp->offsets[j * 2];
-           int yy = y - s->cmp->offsets[j * 2 + 1];
-
-           font->driver->draw (s, j, j + 1, xx, yy, false);
-           if (s->face->overstrike)
-             font->driver->draw (s, j, j + 1, xx + 1, yy, false);
-         }
-    }
   else
-    {
-      Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
-      Lisp_Object glyph;
-      int y = s->ybase;
-      int width = 0;
-
-      for (i = j = s->cmp_from; i < s->cmp_to; i++)
-       {
-         glyph = LGSTRING_GLYPH (gstring, i);
-         if (NILP (LGLYPH_ADJUSTMENT (glyph)))
-           width += LGLYPH_WIDTH (glyph);
-         else
-           {
-             int xoff, yoff, wadjust;
+#ifdef USE_CAIRO
+    if (!EQ (font->driver->type, Qx)
+       || x_try_cr_xlib_drawable (s->f, s->gc))
+      {
+#endif /* USE_CAIRO */
+       if (! s->first_glyph->u.cmp.automatic)
+         {
+           int y = s->ybase;
 
-             if (j < i)
+           for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
+             /* TAB in a composition means display glyphs with
+                padding space on the left or right.  */
+             if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
                {
-                 font->driver->draw (s, j, i, x, y, false);
+                 int xx = x + s->cmp->offsets[j * 2];
+                 int yy = y - s->cmp->offsets[j * 2 + 1];
+
+                 font->driver->draw (s, j, j + 1, xx, yy, false);
                  if (s->face->overstrike)
-                   font->driver->draw (s, j, i, x + 1, y, false);
-                 x += width;
+                   font->driver->draw (s, j, j + 1, xx + 1, yy, false);
                }
-             xoff = LGLYPH_XOFF (glyph);
-             yoff = LGLYPH_YOFF (glyph);
-             wadjust = LGLYPH_WADJUST (glyph);
-             font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
-             if (s->face->overstrike)
-               font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
-                                   false);
-             x += wadjust;
-             j = i + 1;
-             width = 0;
-           }
-       }
-      if (j < i)
-       {
-         font->driver->draw (s, j, i, x, y, false);
-         if (s->face->overstrike)
-           font->driver->draw (s, j, i, x + 1, y, false);
-       }
-    }
+         }
+       else
+         {
+           Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
+           Lisp_Object glyph;
+           int y = s->ybase;
+           int width = 0;
+
+           for (i = j = s->cmp_from; i < s->cmp_to; i++)
+             {
+               glyph = LGSTRING_GLYPH (gstring, i);
+               if (NILP (LGLYPH_ADJUSTMENT (glyph)))
+                 width += LGLYPH_WIDTH (glyph);
+               else
+                 {
+                   int xoff, yoff, wadjust;
+
+                   if (j < i)
+                     {
+                       font->driver->draw (s, j, i, x, y, false);
+                       if (s->face->overstrike)
+                         font->driver->draw (s, j, i, x + 1, y, false);
+                       x += width;
+                     }
+                   xoff = LGLYPH_XOFF (glyph);
+                   yoff = LGLYPH_YOFF (glyph);
+                   wadjust = LGLYPH_WADJUST (glyph);
+                   font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
+                   if (s->face->overstrike)
+                     font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
+                                         false);
+                   x += wadjust;
+                   j = i + 1;
+                   width = 0;
+                 }
+             }
+           if (j < i)
+             {
+               font->driver->draw (s, j, i, x, y, false);
+               if (s->face->overstrike)
+                 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);
+      }
+    else
+      {
+       /* 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);
+      }
+#endif /* USE_CAIRO */
 }