From 03feb9376b54c489e24478954a11061e9b0d6db7 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Thu, 23 May 2019 10:30:59 +0900 Subject: [PATCH] Make Cairo build obey hint-style font setting (Bug#35781) * src/ftfont.h (ftfont_open2): Remove extern. (ftfont_fix_match, ftfont_add_rendering_parameters) (ftfont_entity_pattern): Add externs. (struct font_info): Remove member bitmap_strike_index. (struct font_info) [USE_CAIRO]: Remove member ft_size_draw. All uses removed. Add member bitmap_position_unit. * src/xftfont.c (xftfont_fix_match, xftfont_add_rendering_parameters): Move functions from here ... * src/ftfont.c (ftfont_fix_match, ftfont_add_rendering_parameters): ... to here. All uses changed. * src/xftfont.c (xftfont_open): Extract FcPattern creation from font entity from here ... * src/ftfont.c (ftfont_entity_pattern): ... to here. * src/xftfont.c (syms_of_xftfont): Move DEFSYMs for Fontconfig's rendering parameters from here ... * src/ftfont.c (syms_of_ftfont): ... to here. * src/ftfont.c (ftfont_open, ftfont_open2): Undo introduction of bitmap_strike_index. Merge functions into ftfont_open. * src/ftcrfont.c (ftcrfont_open): Align code with xftfont_open rather than ftfont_open. (ftcrfont_close): Likewise. (ftcrfont_has_char, ftcrfont_encode_char): (ftcrfont_otf_capability) [HAVE_LIBOTF]: (ftcrfont_variation_glyphs) [HAVE_OTF_GET_VARIATION_GLYPHS]: New functions. (ftcrfont_driver): Register them. (ftcrfont_get_bitmap, ftcrfont_anchor_point): (ftcrfont_shape) [HAVE_M17N_FLT && HAVE_LIBOTF]: Use bitmap_position_unit instead of bitmap_strike_index to screen bitmap fonts. (ftcrfont_get_bitmap, ftcrfont_anchor_point): (ftcrfont_otf_capability) [HAVE_LIBOTF]: (ftcrfont_shape) [HAVE_M17N_FLT && HAVE_LIBOTF]: (ftcrfont_variation_glyphs) [HAVE_OTF_GET_VARIATION_GLYPHS]: Temporarily assign ftcrfont_info->ft_size and call corresponding ftfont functions. (ftcrfont_draw): Don't flush cairo surface when exporting. --- src/ftcrfont.c | 370 ++++++++++++++++++++++++++++++++++--------------- src/ftfont.c | 222 +++++++++++++++++++++-------- src/ftfont.h | 18 +-- src/xftfont.c | 151 +------------------- 4 files changed, 433 insertions(+), 328 deletions(-) diff --git a/src/ftcrfont.c b/src/ftcrfont.c index 2d5a7665578..9686cec0e8c 100644 --- a/src/ftcrfont.c +++ b/src/ftcrfont.c @@ -79,7 +79,6 @@ ftcrfont_glyph_extents (struct font *font, cairo_glyph_t cr_glyph = {.index = glyph}; cairo_text_extents_t extents; - FT_Activate_Size (ftcrfont_info->ft_size_draw); cairo_scaled_font_glyph_extents (ftcrfont_info->cr_scaled_font, &cr_glyph, 1, &extents); cache->lbearing = floor (extents.x_bearing); @@ -118,103 +117,159 @@ ftcrfont_match (struct frame *f, Lisp_Object spec) static Lisp_Object ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size) { - Lisp_Object font_object; - - FT_UInt size = XFIXNUM (AREF (entity, FONT_SIZE_INDEX)); + FcResult result; + Lisp_Object val, filename, font_object; + FcPattern *pat, *match; + struct font_info *ftcrfont_info; + struct font *font; + double size = 0; + cairo_font_face_t *font_face; + cairo_font_extents_t extents; + FT_Face ft_face; + FcMatrix *matrix; + + val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX)); + if (! CONSP (val)) + return Qnil; + val = XCDR (val); + filename = XCAR (val); + size = XFIXNUM (AREF (entity, FONT_SIZE_INDEX)); if (size == 0) size = pixel_size; + + block_input (); + + pat = ftfont_entity_pattern (entity, pixel_size); + FcConfigSubstitute (NULL, pat, FcMatchPattern); + FcDefaultSubstitute (pat); + match = FcFontMatch (NULL, pat, &result); + ftfont_fix_match (pat, match); + + FcPatternDestroy (pat); + font_face = cairo_ft_font_face_create_for_pattern (match); + if (!font_face) + { + unblock_input (); + FcPatternDestroy (match); + return Qnil; + } + cairo_matrix_t font_matrix, ctm; + cairo_matrix_init_scale (&font_matrix, pixel_size, pixel_size); + cairo_matrix_init_identity (&ctm); + cairo_font_options_t *options = cairo_font_options_create (); + cairo_scaled_font_t *scaled_font + = cairo_scaled_font_create (font_face, &font_matrix, &ctm, options); + cairo_font_face_destroy (font_face); + cairo_font_options_destroy (options); + unblock_input (); + font_object = font_build_object (VECSIZE (struct font_info), Qftcr, entity, size); + ASET (font_object, FONT_FILE_INDEX, filename); + font = XFONT_OBJECT (font_object); + font->pixel_size = size; + font->driver = &ftcrfont_driver; + font->encoding_charset = font->repertory_charset = -1; + + ftcrfont_info = (struct font_info *) font; + ftcrfont_info->cr_scaled_font = scaled_font; + + /* This means that there's no need of transformation. */ + ftcrfont_info->matrix.xx = 0; + if (FcPatternGetMatrix (match, FC_MATRIX, 0, &matrix) == FcResultMatch) + { + ftcrfont_info->matrix.xx = 0x10000L * matrix->xx; + ftcrfont_info->matrix.yy = 0x10000L * matrix->yy; + ftcrfont_info->matrix.xy = 0x10000L * matrix->xy; + ftcrfont_info->matrix.yx = 0x10000L * matrix->yx; + } + + ftcrfont_info->metrics = NULL; + ftcrfont_info->metrics_nrows = 0; + block_input (); - font_object = ftfont_open2 (f, entity, pixel_size, font_object); - if (FONT_OBJECT_P (font_object)) + 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++) { - struct font *font = XFONT_OBJECT (font_object); - struct font_info *ftcrfont_info = (struct font_info *) font; - FT_Face ft_face = ftcrfont_info->ft_size->face; - - font->driver = &ftcrfont_driver; - FT_New_Size (ft_face, &ftcrfont_info->ft_size_draw); - FT_Activate_Size (ftcrfont_info->ft_size_draw); - 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; - cairo_matrix_init_scale (&font_matrix, pixel_size, pixel_size); - cairo_matrix_init_identity (&ctm); - cairo_font_options_t *options = cairo_font_options_create (); - ftcrfont_info->cr_scaled_font = - cairo_scaled_font_create (font_face, &font_matrix, &ctm, options); - cairo_font_face_destroy (font_face); - cairo_font_options_destroy (options); - ftcrfont_info->metrics = NULL; - ftcrfont_info->metrics_nrows = 0; - if (ftcrfont_info->bitmap_strike_index >= 0) + 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) { - /* 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); - Lisp_Object val = assq_no_quit (QCminspace, - AREF (entity, FONT_EXTRA_INDEX)); - if (!(CONSP (val) && NILP (XCDR (val)))) - { - font->descent = lround (extents.descent); - font->height = font->ascent + font->descent; - } - else + if (glyphs != &stack_glyph) + cairo_glyph_free (glyphs); + else if (stack_glyph.index) { - font->height = lround (extents.height); - font->descent = font->height - font->ascent; + 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; - 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 if (stack_glyph.index) - { - 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; + cairo_scaled_font_extents (ftcrfont_info->cr_scaled_font, &extents); + font->ascent = lround (extents.ascent); + val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX)); + if (!(CONSP (val) && NILP (XCDR (val)))) + { + font->descent = lround (extents.descent); + font->height = font->ascent + font->descent; + } + else + { + font->height = lround (extents.height); + font->descent = font->height - font->ascent; + } - font->underline_position = -1; - font->underline_thickness = 0; - } + ft_face = cairo_ft_scaled_font_lock_face (scaled_font); + if (XFIXNUM (AREF (entity, FONT_SIZE_INDEX)) == 0) + { + int upEM = ft_face->units_per_EM; + + font->underline_position = -ft_face->underline_position * size / upEM; + font->underline_thickness = ft_face->underline_thickness * size / upEM; + if (font->underline_thickness > 2) + font->underline_position -= font->underline_thickness / 2; + } + else + { + font->underline_position = -1; + font->underline_thickness = 0; } +#ifdef HAVE_LIBOTF + ftcrfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0; + ftcrfont_info->otf = NULL; +#endif /* HAVE_LIBOTF */ + if (ft_face->units_per_EM) + ftcrfont_info->bitmap_position_unit = 0; + else + ftcrfont_info->bitmap_position_unit = (extents.height + / ft_face->size->metrics.height); + cairo_ft_scaled_font_unlock_face (scaled_font); + ftcrfont_info->ft_size = NULL; unblock_input (); + font->baseline_offset = 0; + font->relative_compose = 0; + font->default_ascent = 0; + font->vertical_centering = false; + return font_object; } @@ -225,19 +280,58 @@ ftcrfont_close (struct font *font) return; struct font_info *ftcrfont_info = (struct font_info *) font; - int i; block_input (); - for (i = 0; i < ftcrfont_info->metrics_nrows; i++) +#ifdef HAVE_LIBOTF + if (ftcrfont_info->otf) + { + OTF_close (ftcrfont_info->otf); + ftcrfont_info->otf = NULL; + } +#endif + for (int i = 0; i < ftcrfont_info->metrics_nrows; i++) if (ftcrfont_info->metrics[i]) xfree (ftcrfont_info->metrics[i]); if (ftcrfont_info->metrics) xfree (ftcrfont_info->metrics); - FT_Done_Size (ftcrfont_info->ft_size_draw); cairo_scaled_font_destroy (ftcrfont_info->cr_scaled_font); unblock_input (); +} + +static int +ftcrfont_has_char (Lisp_Object font, int c) +{ + if (FONT_ENTITY_P (font)) + return ftfont_has_char (font, c); - ftfont_close (font); + return -1; +} + +static unsigned +ftcrfont_encode_char (struct font *font, int c) +{ + struct font_info *ftcrfont_info = (struct font_info *) font; + unsigned code = FONT_INVALID_CODE; + unsigned char utf8[MAX_MULTIBYTE_LENGTH]; + unsigned char *p = utf8; + cairo_glyph_t stack_glyph; + cairo_glyph_t *glyphs = &stack_glyph; + int num_glyphs = 1; + + CHAR_STRING_ADVANCE (c, p); + if (cairo_scaled_font_text_to_glyphs (ftcrfont_info->cr_scaled_font, 0, 0, + (char *) utf8, p - utf8, + &glyphs, &num_glyphs, + NULL, NULL, NULL) + == CAIRO_STATUS_SUCCESS) + { + if (glyphs != &stack_glyph) + cairo_glyph_free (glyphs); + else if (stack_glyph.index) + code = stack_glyph.index; + } + + return code; } static void @@ -280,10 +374,18 @@ ftcrfont_get_bitmap (struct font *font, unsigned int code, { 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); + if (ftcrfont_info->bitmap_position_unit) + return -1; - return -1; + cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font; + FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font); + + ftcrfont_info->ft_size = ft_face->size; + int result = ftfont_get_bitmap (font, code, bitmap, bits_per_pixel); + cairo_ft_scaled_font_unlock_face (scaled_font); + ftcrfont_info->ft_size = NULL; + + return result; } static int @@ -292,25 +394,75 @@ ftcrfont_anchor_point (struct font *font, unsigned int code, int idx, { 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); + if (ftcrfont_info->bitmap_position_unit) + return -1; - return -1; + cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font; + FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font); + + ftcrfont_info->ft_size = ft_face->size; + int result = ftfont_anchor_point (font, code, idx, x, y); + cairo_ft_scaled_font_unlock_face (scaled_font); + ftcrfont_info->ft_size = NULL; + + return result; } +#ifdef HAVE_LIBOTF static Lisp_Object -ftcrfont_shape (Lisp_Object lgstring) +ftcrfont_otf_capability (struct font *font) { + struct font_info *ftcrfont_info = (struct font_info *) font; + cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font; + FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font); + + ftcrfont_info->ft_size = ft_face->size; + Lisp_Object result = ftfont_otf_capability (font); + cairo_ft_scaled_font_unlock_face (scaled_font); + ftcrfont_info->ft_size = NULL; + + return result; +} +#endif + #if defined HAVE_M17N_FLT && defined HAVE_LIBOTF +static Lisp_Object +ftcrfont_shape (Lisp_Object lgstring) +{ struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring)); struct font_info *ftcrfont_info = (struct font_info *) font; - if (ftcrfont_info->bitmap_strike_index < 0) - return ftfont_shape (lgstring); + if (ftcrfont_info->bitmap_position_unit) + return make_fixnum (0); + + cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font; + FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font); + + ftcrfont_info->ft_size = ft_face->size; + Lisp_Object result = ftfont_shape (lgstring); + cairo_ft_scaled_font_unlock_face (scaled_font); + ftcrfont_info->ft_size = NULL; + + return result; +} #endif - return make_fixnum (0); +#ifdef HAVE_OTF_GET_VARIATION_GLYPHS +static int +ftcrfont_variation_glyphs (struct font *font, int c, unsigned variations[256]) +{ + struct font_info *ftcrfont_info = (struct font_info *) font; + cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font; + FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font); + + ftcrfont_info->ft_size = ft_face->size; + int result = ftfont_variation_glyphs (font, c, variations); + cairo_ft_scaled_font_unlock_face (scaled_font); + ftcrfont_info->ft_size = NULL; + + return result; } +#endif /* HAVE_OTF_GET_VARIATION_GLYPHS */ static int ftcrfont_draw (struct glyph_string *s, @@ -321,8 +473,6 @@ ftcrfont_draw (struct glyph_string *s, struct font_info *ftcrfont_info = (struct font_info *) s->font; cairo_t *cr; cairo_glyph_t *glyphs; - cairo_surface_t *surface; - cairo_surface_type_t surface_type; int len = to - from; int i; @@ -351,17 +501,7 @@ ftcrfont_draw (struct glyph_string *s, x_set_cr_source_with_gc_foreground (f, s->gc); cairo_set_scaled_font (cr, ftcrfont_info->cr_scaled_font); - - FT_Activate_Size (ftcrfont_info->ft_size_draw); cairo_show_glyphs (cr, glyphs, len); - surface = cairo_get_target (cr); - /* XXX: It used to be necessary to flush when exporting. It might - be the case that this is no longer necessary. */ - surface_type = cairo_surface_get_type (surface); - if (surface_type != CAIRO_SURFACE_TYPE_XLIB - && (surface_type != CAIRO_SURFACE_TYPE_IMAGE - || cairo_image_surface_get_format (surface) != CAIRO_FORMAT_ARGB32)) - cairo_surface_flush (surface); x_end_cr_clip (f); @@ -383,18 +523,20 @@ struct font_driver const ftcrfont_driver = .list_family = ftfont_list_family, .open = ftcrfont_open, .close = ftcrfont_close, - .has_char = ftfont_has_char, - .encode_char = ftfont_encode_char, + .has_char = ftcrfont_has_char, + .encode_char = ftcrfont_encode_char, .text_extents = ftcrfont_text_extents, .draw = ftcrfont_draw, .get_bitmap = ftcrfont_get_bitmap, .anchor_point = ftcrfont_anchor_point, #ifdef HAVE_LIBOTF - .otf_capability = ftfont_otf_capability, + .otf_capability = ftcrfont_otf_capability, #endif +#if defined HAVE_M17N_FLT && defined HAVE_LIBOTF .shape = ftcrfont_shape, +#endif #ifdef HAVE_OTF_GET_VARIATION_GLYPHS - .get_variation_glyphs = ftfont_variation_glyphs, + .get_variation_glyphs = ftcrfont_variation_glyphs, #endif .filter_properties = ftfont_filter_properties, .combining_capability = ftfont_combining_capability, diff --git a/src/ftfont.c b/src/ftfont.c index f17bd9ab3f7..d8b510d7032 100644 --- a/src/ftfont.c +++ b/src/ftfont.c @@ -1079,12 +1079,159 @@ ftfont_list_family (struct frame *f) return list; } +void +ftfont_fix_match (FcPattern *pat, FcPattern *match) +{ + /* These values are not used for matching (except antialias), but for + rendering, so make sure they are carried over to the match. + We also put antialias here because most fonts are antialiased, so + the match will have antialias true. */ + + FcBool b = FcTrue; + int i; + double dpi; + + FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b); + if (! b) + { + FcPatternDel (match, FC_ANTIALIAS); + FcPatternAddBool (match, FC_ANTIALIAS, FcFalse); + } + FcPatternGetBool (pat, FC_HINTING, 0, &b); + if (! b) + { + FcPatternDel (match, FC_HINTING); + FcPatternAddBool (match, FC_HINTING, FcFalse); + } +#ifndef FC_HINT_STYLE +# define FC_HINT_STYLE "hintstyle" +#endif + if (FcResultMatch == FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &i)) + { + FcPatternDel (match, FC_HINT_STYLE); + FcPatternAddInteger (match, FC_HINT_STYLE, i); + } +#ifndef FC_LCD_FILTER + /* Older fontconfig versions don't have FC_LCD_FILTER. */ +#define FC_LCD_FILTER "lcdfilter" +#endif + if (FcResultMatch == FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &i)) + { + FcPatternDel (match, FC_LCD_FILTER); + FcPatternAddInteger (match, FC_LCD_FILTER, i); + } + if (FcResultMatch == FcPatternGetInteger (pat, FC_RGBA, 0, &i)) + { + FcPatternDel (match, FC_RGBA); + FcPatternAddInteger (match, FC_RGBA, i); + } + if (FcResultMatch == FcPatternGetDouble (pat, FC_DPI, 0, &dpi)) + { + FcPatternDel (match, FC_DPI); + FcPatternAddDouble (match, FC_DPI, dpi); + } +} + +void +ftfont_add_rendering_parameters (FcPattern *pat, Lisp_Object entity) +{ + Lisp_Object tail; + int ival; + + for (tail = AREF (entity, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail)) + { + Lisp_Object key = XCAR (XCAR (tail)); + Lisp_Object val = XCDR (XCAR (tail)); + + if (EQ (key, QCantialias)) + FcPatternAddBool (pat, FC_ANTIALIAS, NILP (val) ? FcFalse : FcTrue); + else if (EQ (key, QChinting)) + FcPatternAddBool (pat, FC_HINTING, NILP (val) ? FcFalse : FcTrue); + else if (EQ (key, QCautohint)) + FcPatternAddBool (pat, FC_AUTOHINT, NILP (val) ? FcFalse : FcTrue); + else if (EQ (key, QChintstyle)) + { + if (FIXNUMP (val)) + FcPatternAddInteger (pat, FC_HINT_STYLE, XFIXNUM (val)); + else if (SYMBOLP (val) + && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival)) + FcPatternAddInteger (pat, FC_HINT_STYLE, ival); + } + else if (EQ (key, QCrgba)) + { + if (FIXNUMP (val)) + FcPatternAddInteger (pat, FC_RGBA, XFIXNUM (val)); + else if (SYMBOLP (val) + && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival)) + FcPatternAddInteger (pat, FC_RGBA, ival); + } + else if (EQ (key, QClcdfilter)) + { + if (FIXNUMP (val)) + FcPatternAddInteger (pat, FC_LCD_FILTER, ival = XFIXNUM (val)); + else if (SYMBOLP (val) + && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival)) + FcPatternAddInteger (pat, FC_LCD_FILTER, ival); + } +#ifdef FC_EMBOLDEN + else if (EQ (key, QCembolden)) + FcPatternAddBool (pat, FC_EMBOLDEN, NILP (val) ? FcFalse : FcTrue); +#endif + } +} + +FcPattern * +ftfont_entity_pattern (Lisp_Object entity, int pixel_size) +{ + Lisp_Object val, filename, idx; + FcPattern *pat; + int i; + + val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX)); + eassert (CONSP (val)); + val = XCDR (val); + filename = XCAR (val); + idx = XCDR (val); + pat = FcPatternCreate (); + FcPatternAddInteger (pat, FC_WEIGHT, FONT_WEIGHT_NUMERIC (entity)); + i = FONT_SLANT_NUMERIC (entity) - 100; + if (i < 0) i = 0; + FcPatternAddInteger (pat, FC_SLANT, i); + FcPatternAddInteger (pat, FC_WIDTH, FONT_WIDTH_NUMERIC (entity)); + FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size); + val = AREF (entity, FONT_FAMILY_INDEX); + if (! NILP (val)) + FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val))); + val = AREF (entity, FONT_FOUNDRY_INDEX); + if (! NILP (val)) + FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) SDATA (SYMBOL_NAME (val))); + val = AREF (entity, FONT_SPACING_INDEX); + if (! NILP (val)) + FcPatternAddInteger (pat, FC_SPACING, XFIXNUM (val)); + val = AREF (entity, FONT_DPI_INDEX); + if (! NILP (val)) + { + double dbl = XFIXNUM (val); + + FcPatternAddDouble (pat, FC_DPI, dbl); + } + val = AREF (entity, FONT_AVGWIDTH_INDEX); + if (FIXNUMP (val) && XFIXNUM (val) == 0) + FcPatternAddBool (pat, FC_SCALABLE, FcTrue); + /* This is necessary to identify the exact font (e.g. 10x20.pcf.gz + over 10x20-ISO8859-1.pcf.gz). */ + FcPatternAddCharSet (pat, FC_CHARSET, ftfont_get_fc_charset (entity)); + + ftfont_add_rendering_parameters (pat, entity); + + FcPatternAddString (pat, FC_FILE, (FcChar8 *) SDATA (filename)); + FcPatternAddInteger (pat, FC_INDEX, XFIXNUM (idx)); + + return pat; +} Lisp_Object -ftfont_open2 (struct frame *f, - Lisp_Object entity, - int pixel_size, - Lisp_Object font_object) +ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size) { struct font_info *ftfont_info; struct font *font; @@ -1092,12 +1239,11 @@ ftfont_open2 (struct frame *f, FT_Face ft_face; FT_Size ft_size; FT_UInt size; - Lisp_Object val, filename, idx, cache; + Lisp_Object val, filename, idx, cache, font_object; bool scalable; 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,35 +1272,17 @@ ftfont_open2 (struct frame *f, size = pixel_size; if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0) { - int min_distance = INT_MAX; - bool magnify = true; - - for (FT_Int i = 0; i < ft_face->num_fixed_sizes; i++) - { - 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) { - if (cache_data->face_refcount == 0) - { - FT_Done_Face (ft_face); - cache_data->ft_face = NULL; - } - return Qnil; + FT_Done_Face (ft_face); + cache_data->ft_face = NULL; } + return Qnil; } cache_data->face_refcount++; + font_object = font_build_object (VECSIZE (struct font_info), + Qfreetype, entity, size); ASET (font_object, FONT_FILE_INDEX, filename); font = XFONT_OBJECT (font_object); ftfont_info = (struct font_info *) font; @@ -1164,7 +1292,6 @@ 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; @@ -1258,31 +1385,6 @@ ftfont_open2 (struct frame *f, return font_object; } -Lisp_Object -ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size) -{ - Lisp_Object font_object; - FT_UInt size; - size = XFIXNUM (AREF (entity, FONT_SIZE_INDEX)); - if (size == 0) - size = pixel_size; - font_object = font_build_object (VECSIZE (struct font_info), - Qfreetype, entity, size); - 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 ftfont_close (struct font *font) { @@ -2789,6 +2891,14 @@ syms_of_ftfont (void) /* The boolean-valued font property key specifying the use of leading. */ DEFSYM (QCminspace, ":minspace"); + /* Fontconfig's rendering parameters. */ + DEFSYM (QChinting, ":hinting"); + DEFSYM (QCautohint, ":autohint"); + DEFSYM (QChintstyle, ":hintstyle"); + DEFSYM (QCrgba, ":rgba"); + DEFSYM (QCembolden, ":embolden"); + DEFSYM (QClcdfilter, ":lcdfilter"); + staticpro (&freetype_font_cache); freetype_font_cache = list1 (Qt); diff --git a/src/ftfont.h b/src/ftfont.h index adbda49ff1c..7860469491f 100644 --- a/src/ftfont.h +++ b/src/ftfont.h @@ -37,10 +37,9 @@ along with GNU Emacs. If not, see . */ #endif /* HAVE_LIBOTF */ extern FcCharSet *ftfont_get_fc_charset (Lisp_Object); -extern Lisp_Object ftfont_open2 (struct frame *f, - Lisp_Object entity, - int pixel_size, - Lisp_Object font_object); +extern void ftfont_fix_match (FcPattern *, FcPattern *); +extern void ftfont_add_rendering_parameters (FcPattern *, Lisp_Object); +extern FcPattern *ftfont_entity_pattern (Lisp_Object, int); /* This struct is shared by the XFT, Freetype, and Cairo font backends. Members up to and including 'matrix' are common, the @@ -54,17 +53,14 @@ 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 cairo_scaled_font_t *cr_scaled_font; - /* To prevent cairo from cluttering the activated FT_Size maintained - in ftfont.c, we activate this special FT_Size before drawing. */ - FT_Size ft_size_draw; + /* Scale factor from the bitmap strike metrics in 1/64 pixels, used + as the hb_position_t value in HarfBuzz, to those in (scaled) + pixels. The value is 0 for scalable fonts. */ + double bitmap_position_unit; /* Font metrics cache. */ struct font_metrics **metrics; short metrics_nrows; diff --git a/src/xftfont.c b/src/xftfont.c index 2edc51fe356..4f0a0d81d85 100644 --- a/src/xftfont.c +++ b/src/xftfont.c @@ -127,120 +127,18 @@ xftfont_match (struct frame *f, Lisp_Object spec) static FcChar8 ascii_printable[95]; -static void -xftfont_fix_match (FcPattern *pat, FcPattern *match) -{ - /* These values are not used for matching (except antialias), but for - rendering, so make sure they are carried over to the match. - We also put antialias here because most fonts are antialiased, so - the match will have antialias true. */ - - FcBool b = FcTrue; - int i; - double dpi; - - FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b); - if (! b) - { - FcPatternDel (match, FC_ANTIALIAS); - FcPatternAddBool (match, FC_ANTIALIAS, FcFalse); - } - FcPatternGetBool (pat, FC_HINTING, 0, &b); - if (! b) - { - FcPatternDel (match, FC_HINTING); - FcPatternAddBool (match, FC_HINTING, FcFalse); - } -#ifndef FC_HINT_STYLE -# define FC_HINT_STYLE "hintstyle" -#endif - if (FcResultMatch == FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &i)) - { - FcPatternDel (match, FC_HINT_STYLE); - FcPatternAddInteger (match, FC_HINT_STYLE, i); - } -#ifndef FC_LCD_FILTER - /* Older fontconfig versions don't have FC_LCD_FILTER. */ -#define FC_LCD_FILTER "lcdfilter" -#endif - if (FcResultMatch == FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &i)) - { - FcPatternDel (match, FC_LCD_FILTER); - FcPatternAddInteger (match, FC_LCD_FILTER, i); - } - if (FcResultMatch == FcPatternGetInteger (pat, FC_RGBA, 0, &i)) - { - FcPatternDel (match, FC_RGBA); - FcPatternAddInteger (match, FC_RGBA, i); - } - if (FcResultMatch == FcPatternGetDouble (pat, FC_DPI, 0, &dpi)) - { - FcPatternDel (match, FC_DPI); - FcPatternAddDouble (match, FC_DPI, dpi); - } -} - -static void -xftfont_add_rendering_parameters (FcPattern *pat, Lisp_Object entity) -{ - Lisp_Object tail; - int ival; - - for (tail = AREF (entity, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail)) - { - Lisp_Object key = XCAR (XCAR (tail)); - Lisp_Object val = XCDR (XCAR (tail)); - - if (EQ (key, QCantialias)) - FcPatternAddBool (pat, FC_ANTIALIAS, NILP (val) ? FcFalse : FcTrue); - else if (EQ (key, QChinting)) - FcPatternAddBool (pat, FC_HINTING, NILP (val) ? FcFalse : FcTrue); - else if (EQ (key, QCautohint)) - FcPatternAddBool (pat, FC_AUTOHINT, NILP (val) ? FcFalse : FcTrue); - else if (EQ (key, QChintstyle)) - { - if (FIXNUMP (val)) - FcPatternAddInteger (pat, FC_HINT_STYLE, XFIXNUM (val)); - else if (SYMBOLP (val) - && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival)) - FcPatternAddInteger (pat, FC_HINT_STYLE, ival); - } - else if (EQ (key, QCrgba)) - { - if (FIXNUMP (val)) - FcPatternAddInteger (pat, FC_RGBA, XFIXNUM (val)); - else if (SYMBOLP (val) - && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival)) - FcPatternAddInteger (pat, FC_RGBA, ival); - } - else if (EQ (key, QClcdfilter)) - { - if (FIXNUMP (val)) - FcPatternAddInteger (pat, FC_LCD_FILTER, ival = XFIXNUM (val)); - else if (SYMBOLP (val) - && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival)) - FcPatternAddInteger (pat, FC_LCD_FILTER, ival); - } -#ifdef FC_EMBOLDEN - else if (EQ (key, QCembolden)) - FcPatternAddBool (pat, FC_EMBOLDEN, NILP (val) ? FcFalse : FcTrue); -#endif - } -} - static Lisp_Object xftfont_open (struct frame *f, Lisp_Object entity, int pixel_size) { FcResult result; Display *display = FRAME_X_DISPLAY (f); - Lisp_Object val, filename, idx, font_object; + Lisp_Object val, filename, font_object; FcPattern *pat = NULL, *match; struct font_info *xftfont_info = NULL; struct font *font; double size = 0; XftFont *xftfont = NULL; int spacing; - int i; XGlyphInfo extents; FT_Face ft_face; FcMatrix *matrix; @@ -250,52 +148,17 @@ xftfont_open (struct frame *f, Lisp_Object entity, int pixel_size) return Qnil; val = XCDR (val); filename = XCAR (val); - idx = XCDR (val); size = XFIXNUM (AREF (entity, FONT_SIZE_INDEX)); if (size == 0) size = pixel_size; - pat = FcPatternCreate (); - FcPatternAddInteger (pat, FC_WEIGHT, FONT_WEIGHT_NUMERIC (entity)); - i = FONT_SLANT_NUMERIC (entity) - 100; - if (i < 0) i = 0; - FcPatternAddInteger (pat, FC_SLANT, i); - FcPatternAddInteger (pat, FC_WIDTH, FONT_WIDTH_NUMERIC (entity)); - FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size); - val = AREF (entity, FONT_FAMILY_INDEX); - if (! NILP (val)) - FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val))); - val = AREF (entity, FONT_FOUNDRY_INDEX); - if (! NILP (val)) - FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) SDATA (SYMBOL_NAME (val))); - val = AREF (entity, FONT_SPACING_INDEX); - if (! NILP (val)) - FcPatternAddInteger (pat, FC_SPACING, XFIXNUM (val)); - val = AREF (entity, FONT_DPI_INDEX); - if (! NILP (val)) - { - double dbl = XFIXNUM (val); - - FcPatternAddDouble (pat, FC_DPI, dbl); - } - val = AREF (entity, FONT_AVGWIDTH_INDEX); - if (FIXNUMP (val) && XFIXNUM (val) == 0) - FcPatternAddBool (pat, FC_SCALABLE, FcTrue); - /* This is necessary to identify the exact font (e.g. 10x20.pcf.gz - over 10x20-ISO8859-1.pcf.gz). */ - FcPatternAddCharSet (pat, FC_CHARSET, ftfont_get_fc_charset (entity)); - - xftfont_add_rendering_parameters (pat, entity); - - FcPatternAddString (pat, FC_FILE, (FcChar8 *) SDATA (filename)); - FcPatternAddInteger (pat, FC_INDEX, XFIXNUM (idx)); - block_input (); + pat = ftfont_entity_pattern (entity, pixel_size); /* Substitute in values from X resources and XftDefaultSet. */ XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat); match = XftFontMatch (display, FRAME_X_SCREEN_NUMBER (f), pat, &result); - xftfont_fix_match (pat, match); + ftfont_fix_match (pat, match); FcPatternDestroy (pat); xftfont = XftFontOpenPattern (display, match); @@ -695,7 +558,7 @@ xftfont_cached_font_ok (struct frame *f, Lisp_Object font_object, bool ok = false; int i1, i2, r1, r2; - xftfont_add_rendering_parameters (pat, entity); + ftfont_add_rendering_parameters (pat, entity); XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat); r1 = FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b1); @@ -768,12 +631,6 @@ void syms_of_xftfont (void) { DEFSYM (Qxft, "xft"); - DEFSYM (QChinting, ":hinting"); - DEFSYM (QCautohint, ":autohint"); - DEFSYM (QChintstyle, ":hintstyle"); - DEFSYM (QCrgba, ":rgba"); - DEFSYM (QCembolden, ":embolden"); - DEFSYM (QClcdfilter, ":lcdfilter"); DEFVAR_BOOL ("xft-font-ascent-descent-override", xft_font_ascent_descent_override, -- 2.39.2