Use bitmap strikes as fallbacks for ftcr font backend

* src/ftfont.h (struct font_info): New member bitmap_strike_index.
* src/ftfont.c (ftfont_open2): Try bitmap strikes as fallbacks.
(ftfont_open): Discard bitmap strikes.
* src/ftcrfont.c (ftcrfont_open): Recalculate metrics for bitmap strikes.
(ftcrfont_get_bitmap, ftcrfont_anchor_point, ftcrfont_shape): New functions.
(struct font_driver): Use them.
This commit is contained in:
YAMAMOTO Mitsuharu 2019-04-20 12:43:45 +09:00
parent 69771b4e6a
commit d1dde7d04e
3 changed files with 137 additions and 11 deletions

View file

@ -135,7 +135,10 @@ ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
font->driver = &ftcrfont_driver;
FT_New_Size (ft_face, &ftcrfont_info->ft_size_draw);
FT_Activate_Size (ftcrfont_info->ft_size_draw);
FT_Set_Pixel_Sizes (ft_face, 0, font->pixel_size);
if (ftcrfont_info->bitmap_strike_index < 0)
FT_Set_Pixel_Sizes (ft_face, 0, font->pixel_size);
else
FT_Select_Size (ft_face, ftcrfont_info->bitmap_strike_index);
cairo_font_face_t *font_face =
cairo_ft_font_face_create_for_ft_face (ft_face, 0);
cairo_matrix_t font_matrix, ctm;
@ -148,6 +151,56 @@ ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
cairo_font_options_destroy (options);
ftcrfont_info->metrics = NULL;
ftcrfont_info->metrics_nrows = 0;
if (ftcrfont_info->bitmap_strike_index >= 0)
{
/* Several members of struct font/font_info set by
ftfont_open2 are bogus. Recalculate them with cairo
scaled font functions. */
cairo_font_extents_t extents;
cairo_scaled_font_extents (ftcrfont_info->cr_scaled_font, &extents);
font->ascent = lround (extents.ascent);
font->descent = lround (extents.descent);
font->height = lround (extents.height);
cairo_glyph_t stack_glyph;
int n = 0;
font->min_width = font->average_width = font->space_width = 0;
for (char c = 32; c < 127; c++)
{
cairo_glyph_t *glyphs = &stack_glyph;
int num_glyphs = 1;
cairo_status_t status =
cairo_scaled_font_text_to_glyphs (ftcrfont_info->cr_scaled_font,
0, 0, &c, 1,
&glyphs, &num_glyphs,
NULL, NULL, NULL);
if (status == CAIRO_STATUS_SUCCESS)
{
if (glyphs != &stack_glyph)
cairo_glyph_free (glyphs);
else
{
int this_width =
ftcrfont_glyph_extents (font, stack_glyph.index, NULL);
if (this_width > 0
&& (! font->min_width
|| font->min_width > this_width))
font->min_width = this_width;
if (c == 32)
font->space_width = this_width;
font->average_width += this_width;
n++;
}
}
}
if (n > 0)
font->average_width /= n;
font->underline_position = -1;
font->underline_thickness = 0;
}
}
unblock_input ();
@ -210,6 +263,43 @@ ftcrfont_text_extents (struct font *font,
metrics->width = width;
}
static int
ftcrfont_get_bitmap (struct font *font, unsigned int code,
struct font_bitmap *bitmap, int bits_per_pixel)
{
struct font_info *ftcrfont_info = (struct font_info *) font;
if (ftcrfont_info->bitmap_strike_index < 0)
return ftfont_get_bitmap (font, code, bitmap, bits_per_pixel);
return -1;
}
static int
ftcrfont_anchor_point (struct font *font, unsigned int code, int idx,
int *x, int *y)
{
struct font_info *ftcrfont_info = (struct font_info *) font;
if (ftcrfont_info->bitmap_strike_index < 0)
return ftfont_anchor_point (font, code, idx, x, y);
return -1;
}
static Lisp_Object
ftcrfont_shape (Lisp_Object lgstring)
{
#if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
struct font_info *ftcrfont_info = (struct font_info *) font;
if (ftcrfont_info->bitmap_strike_index < 0)
return ftfont_shape (lgstring);
#endif
return make_fixnum (0);
}
static int
ftcrfont_draw (struct glyph_string *s,
int from, int to, int x, int y, bool with_background)
@ -286,14 +376,12 @@ struct font_driver const ftcrfont_driver =
.encode_char = ftfont_encode_char,
.text_extents = ftcrfont_text_extents,
.draw = ftcrfont_draw,
.get_bitmap = ftfont_get_bitmap,
.anchor_point = ftfont_anchor_point,
.get_bitmap = ftcrfont_get_bitmap,
.anchor_point = ftcrfont_anchor_point,
#ifdef HAVE_LIBOTF
.otf_capability = ftfont_otf_capability,
#endif
#if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
.shape = ftfont_shape,
#endif
.shape = ftcrfont_shape,
#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
.get_variation_glyphs = ftfont_variation_glyphs,
#endif

View file

@ -1097,6 +1097,7 @@ ftfont_open2 (struct frame *f,
int spacing;
int i;
double upEM;
FT_Int strike_index = -1;
val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
if (! CONSP (val))
@ -1126,12 +1127,32 @@ ftfont_open2 (struct frame *f,
size = pixel_size;
if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
{
if (cache_data->face_refcount == 0)
int min_distance = INT_MAX;
bool magnify = true;
for (FT_Int i = 0; i < ft_face->num_fixed_sizes; i++)
{
FT_Done_Face (ft_face);
cache_data->ft_face = NULL;
int distance = ft_face->available_sizes[i].height - (int) size;
/* Prefer down-scaling to upscaling. */
if (magnify == (distance < 0) ? abs (distance) <= min_distance
: magnify)
{
magnify = distance < 0;
min_distance = abs (distance);
strike_index = i;
}
}
if (strike_index < 0 || FT_Select_Size (ft_face, strike_index) != 0)
{
if (cache_data->face_refcount == 0)
{
FT_Done_Face (ft_face);
cache_data->ft_face = NULL;
}
return Qnil;
}
return Qnil;
}
cache_data->face_refcount++;
@ -1144,6 +1165,7 @@ ftfont_open2 (struct frame *f,
ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
ftfont_info->otf = NULL;
#endif /* HAVE_LIBOTF */
ftfont_info->bitmap_strike_index = strike_index;
/* This means that there's no need of transformation. */
ftfont_info->matrix.xx = 0;
font->pixel_size = size;
@ -1229,7 +1251,19 @@ ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
size = pixel_size;
font_object = font_build_object (VECSIZE (struct font_info),
Qfreetype, entity, size);
return ftfont_open2 (f, entity, pixel_size, font_object);
font_object = ftfont_open2 (f, entity, pixel_size, font_object);
if (FONT_OBJECT_P (font_object))
{
struct font *font = XFONT_OBJECT (font_object);
struct font_info *ftfont_info = (struct font_info *) font;
if (ftfont_info->bitmap_strike_index >= 0)
{
ftfont_close (font);
font_object = Qnil;
}
}
return font_object;
}
void

View file

@ -54,6 +54,10 @@ struct font_info
#endif /* HAVE_LIBOTF */
FT_Size ft_size;
int index;
/* Index of the bitmap strike used as a fallback for
FT_Set_Pixel_Sizes failure. If the value is non-negative, then
ft_size is not of the requested size. Otherwise it is -1. */
FT_Int bitmap_strike_index;
FT_Matrix matrix;
#ifdef USE_CAIRO