summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>2019-06-08 14:05:49 +0900
committerYAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>2019-06-08 14:05:49 +0900
commitfaf10bd8eb3272880b774fe220fa9916ed1f00c0 (patch)
treef933e9f012e0c96effefb02daa31ead9acc22aed
parent88c49ac31898e7b2c29338ca55cae292c450f7be (diff)
downloademacs-faf10bd8eb3272880b774fe220fa9916ed1f00c0.tar.gz
Support X core font driver on cairo (Bug#28236)
* 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.
-rw-r--r--configure.ac2
-rw-r--r--doc/lispref/frames.texi10
-rw-r--r--src/font.c2
-rw-r--r--src/xfns.c2
-rw-r--r--src/xterm.c341
5 files changed, 267 insertions, 90 deletions
diff --git a/configure.ac b/configure.ac
index bd51f54212c..5c96f4231ee 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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
diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi
index 336075a1ca2..629cec3c5fe 100644
--- a/doc/lispref/frames.texi
+++ b/doc/lispref/frames.texi
@@ -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,
diff --git a/src/font.c b/src/font.c
index 6ab4923c3d2..5705758b99f 100644
--- a/src/font.c
+++ b/src/font.c
@@ -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 ();
diff --git a/src/xfns.c b/src/xfns.c
index 460dd1316e6..46f19ff82ac 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -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;
diff --git a/src/xterm.c b/src/xterm.c
index e0edd9c1a40..3cd95b7a65d 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,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 */
}