Commit faf10bd8 authored by YAMAMOTO Mitsuharu's avatar YAMAMOTO Mitsuharu

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.
parent 88c49ac3
Pipeline #1930 failed with stage
in 9 seconds
......@@ -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
......
......@@ -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,
......
......@@ -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 ();
......
......@@ -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;
......
......@@ -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 */
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment