From d1dde7d04e5244179735592adc11d2a6f0af64ac Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Sat, 20 Apr 2019 12:43:45 +0900 Subject: [PATCH] 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. --- src/ftcrfont.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++--- src/ftfont.c | 44 +++++++++++++++++++--- src/ftfont.h | 4 ++ 3 files changed, 137 insertions(+), 11 deletions(-) diff --git a/src/ftcrfont.c b/src/ftcrfont.c index 4845ee4cf3d..e341c409b1e 100644 --- a/src/ftcrfont.c +++ b/src/ftcrfont.c @@ -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 diff --git a/src/ftfont.c b/src/ftfont.c index 3e820f583ff..d0078a37701 100644 --- a/src/ftfont.c +++ b/src/ftfont.c @@ -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 diff --git a/src/ftfont.h b/src/ftfont.h index 327cd085acf..adbda49ff1c 100644 --- a/src/ftfont.h +++ b/src/ftfont.h @@ -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 -- 2.39.5