From 901236f721e59e9955637cd44121b28f89c5bebe Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 15 Jul 2022 12:55:31 -0600 Subject: [PATCH 1/5] [ft] Implement loading (color) bitmap fonts Fixes https://github.com/harfbuzz/harfbuzz/issues/489 Something about the vertical metrics is still off, not matching hb-ot. I cannot figure out what. --- src/hb-ft.cc | 92 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 36 deletions(-) diff --git a/src/hb-ft.cc b/src/hb-ft.cc index 78687e677..8b1128bea 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -136,18 +136,36 @@ _hb_ft_font_destroy (void *data) /* hb_font changed, update FT_Face. */ static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face) { - - FT_Set_Char_Size (ft_face, - abs (font->x_scale), abs (font->y_scale), - 0, 0); + float x_mult = 1.f, y_mult = 1.f; + if (FT_Set_Char_Size (ft_face, + abs (font->x_scale), abs (font->y_scale), + 0, 0 #if 0 font->x_ppem * 72 * 64 / font->x_scale, - font->y_ppem * 72 * 64 / font->y_scale); + font->y_ppem * 72 * 64 / font->y_scale #endif - if (font->x_scale < 0 || font->y_scale < 0) + ) && ft_face->num_fixed_sizes) { - FT_Matrix matrix = { font->x_scale < 0 ? -(1<<16) : +(1<<16), 0, - 0, font->y_scale < 0 ? -(1<<16) : +(1<<16)}; + /* Bitmap font, eg. bitmap color emoji. */ + /* TODO Pick largest size? */ + int x_scale = ft_face->available_sizes[0].x_ppem; + int y_scale = ft_face->available_sizes[0].y_ppem; + FT_Set_Char_Size (ft_face, + x_scale, y_scale, + 0, 0); + x_mult = (float) font->x_scale / x_scale; + y_mult = (float) font->y_scale / y_scale; + } + else + { /* Shrug */ } + + if (font->x_scale < 0) x_mult = -x_mult; + if (font->y_scale < 0) y_mult = -y_mult; + + if (x_mult != 1.f || y_mult != 1.f) + { + FT_Matrix matrix = { (int) roundf (x_mult * (1<<16)), 0, + 0, (int) roundf (y_mult * (1<<16))}; FT_Set_Transform (ft_face, &matrix, nullptr); } @@ -404,7 +422,9 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; int load_flags = ft_font->load_flags; - int mult = font->x_scale < 0 ? -1 : +1; + FT_Matrix matrix; + FT_Get_Transform (ft_face, &matrix, nullptr); + float mult = matrix.xx / 65536.f; for (unsigned int i = 0; i < count; i++) { @@ -420,7 +440,7 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, ft_font->advance_cache.set (glyph, v); } - *first_advance = (v * mult + (1<<9)) >> 10; + *first_advance = (int) (v * mult + (1<<9)) >> 10; first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } @@ -436,12 +456,14 @@ hb_ft_get_glyph_v_advance (hb_font_t *font, const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Fixed v; + FT_Matrix matrix; + FT_Get_Transform (ft_font->ft_face, &matrix, nullptr); + float y_mult = matrix.yy / 65536.f; if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v))) return 0; - if (font->y_scale < 0) - v = -v; + v = (int) (y_mult * v); /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates * have a Y growing upward. Hence the extra negation. */ @@ -462,6 +484,10 @@ hb_ft_get_glyph_v_origin (hb_font_t *font, const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; + FT_Matrix matrix; + FT_Get_Transform (ft_face, &matrix, nullptr); + float x_mult = matrix.xx / 65536.f; + float y_mult = matrix.yy / 65536.f; if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) return false; @@ -471,10 +497,8 @@ hb_ft_get_glyph_v_origin (hb_font_t *font, *x = ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX; *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY); - if (font->x_scale < 0) - *x = -*x; - if (font->y_scale < 0) - *y = -*y; + *x = (hb_position_t) (x_mult * *x); + *y = (hb_position_t) (y_mult * *y); return true; } @@ -510,24 +534,19 @@ hb_ft_get_glyph_extents (hb_font_t *font, const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; + FT_Matrix matrix; + FT_Get_Transform (ft_face, &matrix, nullptr); + float x_mult = matrix.xx / 65536.f; + float y_mult = matrix.yy / 65536.f; if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) return false; - extents->x_bearing = ft_face->glyph->metrics.horiBearingX; - extents->y_bearing = ft_face->glyph->metrics.horiBearingY; - extents->width = ft_face->glyph->metrics.width; - extents->height = -ft_face->glyph->metrics.height; - if (font->x_scale < 0) - { - extents->x_bearing = -extents->x_bearing; - extents->width = -extents->width; - } - if (font->y_scale < 0) - { - extents->y_bearing = -extents->y_bearing; - extents->height = -extents->height; - } + extents->x_bearing = (hb_position_t) (x_mult * ft_face->glyph->metrics.horiBearingX); + extents->y_bearing = (hb_position_t) (y_mult * ft_face->glyph->metrics.horiBearingY); + extents->width = (hb_position_t) (x_mult * ft_face->glyph->metrics.width); + extents->height = (hb_position_t) (y_mult * -ft_face->glyph->metrics.height); + return true; } @@ -620,16 +639,17 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; + FT_Matrix matrix; + FT_Get_Transform (ft_face, &matrix, nullptr); + float y_mult = matrix.yy / 65536.f; metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale); metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale); metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender); - if (font->y_scale < 0) - { - metrics->ascender = -metrics->ascender; - metrics->descender = -metrics->descender; - metrics->line_gap = -metrics->line_gap; - } + metrics->ascender = (hb_position_t) (y_mult * metrics->ascender); + metrics->descender = (hb_position_t) (y_mult * metrics->descender); + metrics->line_gap = (hb_position_t) (y_mult * metrics->line_gap); + return true; } From e294200dac3d7cd41a02e0753f63acfbb5e24820 Mon Sep 17 00:00:00 2001 From: Khaled Hosny Date: Fri, 15 Jul 2022 21:36:50 +0200 Subject: [PATCH 2/5] [ft] Check for FT_Get_Transform at build time --- configure.ac | 2 +- meson.build | 1 + src/hb-ft.cc | 22 ++++++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 8873907de..aec960090 100644 --- a/configure.ac +++ b/configure.ac @@ -308,7 +308,7 @@ if $have_freetype; then AC_DEFINE(HAVE_FREETYPE, 1, [Have FreeType 2 library]) save_libs=$LIBS LIBS="$LIBS $FREETYPE_LIBS" - AC_CHECK_FUNCS(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var) + AC_CHECK_FUNCS(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var FT_Get_Transform) LIBS=$save_libs fi AM_CONDITIONAL(HAVE_FREETYPE, $have_freetype) diff --git a/meson.build b/meson.build index 8039efdc2..d6a206e25 100644 --- a/meson.build +++ b/meson.build @@ -198,6 +198,7 @@ if freetype_dep.found() ['FT_Get_Var_Blend_Coordinates', {'deps': freetype_dep}], ['FT_Set_Var_Blend_Coordinates', {'deps': freetype_dep}], ['FT_Done_MM_Var', {'deps': freetype_dep}], + ['FT_Get_Transform', {'deps': freetype_dep}], ] if freetype_dep.type_name() == 'internal' diff --git a/src/hb-ft.cc b/src/hb-ft.cc index 8b1128bea..dd2cbbc44 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -422,9 +422,13 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; int load_flags = ft_font->load_flags; +#ifdef HAVE_FT_GET_TRANSFORM FT_Matrix matrix; FT_Get_Transform (ft_face, &matrix, nullptr); float mult = matrix.xx / 65536.f; +#else + float mult = font->x_scale < 0 ? -1 : +1; +#endif for (unsigned int i = 0; i < count; i++) { @@ -456,9 +460,13 @@ hb_ft_get_glyph_v_advance (hb_font_t *font, const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Fixed v; +#ifdef HAVE_FT_GET_TRANSFORM FT_Matrix matrix; FT_Get_Transform (ft_font->ft_face, &matrix, nullptr); float y_mult = matrix.yy / 65536.f; +#else + float y_mult = font->y_scale < 0 ? -1 : +1; +#endif if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v))) return 0; @@ -484,10 +492,15 @@ hb_ft_get_glyph_v_origin (hb_font_t *font, const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; +#ifdef HAVE_FT_GET_TRANSFORM FT_Matrix matrix; FT_Get_Transform (ft_face, &matrix, nullptr); float x_mult = matrix.xx / 65536.f; float y_mult = matrix.yy / 65536.f; +#else + float x_mult = font->x_scale < 0 ? -1 : +1; + float y_mult = font->y_scale < 0 ? -1 : +1; +#endif if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) return false; @@ -534,10 +547,15 @@ hb_ft_get_glyph_extents (hb_font_t *font, const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; +#ifdef HAVE_FT_GET_TRANSFORM FT_Matrix matrix; FT_Get_Transform (ft_face, &matrix, nullptr); float x_mult = matrix.xx / 65536.f; float y_mult = matrix.yy / 65536.f; +#else + float x_mult = font->x_scale < 0 ? -1 : +1; + float y_mult = font->y_scale < 0 ? -1 : +1; +#endif if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) return false; @@ -639,9 +657,13 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; +#ifdef HAVE_FT_GET_TRANSFORM FT_Matrix matrix; FT_Get_Transform (ft_face, &matrix, nullptr); float y_mult = matrix.yy / 65536.f; +#else + float y_mult = font->y_scale < 0 ? -1 : +1; +#endif metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale); metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale); From 87d338eb61e35d6d8270b083c8225e004f73c03f Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 15 Jul 2022 14:19:17 -0600 Subject: [PATCH 3/5] [ft] Fix test --- src/hb-ft.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hb-ft.cc b/src/hb-ft.cc index dd2cbbc44..d796855e8 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -146,6 +146,7 @@ static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face) #endif ) && ft_face->num_fixed_sizes) { +#ifdef HAVE_FT_GET_TRANSFORM /* Bitmap font, eg. bitmap color emoji. */ /* TODO Pick largest size? */ int x_scale = ft_face->available_sizes[0].x_ppem; @@ -155,6 +156,7 @@ static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face) 0, 0); x_mult = (float) font->x_scale / x_scale; y_mult = (float) font->y_scale / y_scale; +#endif } else { /* Shrug */ } From 307ee9baff687912e4f451a0cc463ff84314554f Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 15 Jul 2022 14:48:29 -0600 Subject: [PATCH 4/5] [ft] Fix bitmap-only vertical metrics --- src/hb-ft.cc | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/hb-ft.cc b/src/hb-ft.cc index d796855e8..4a281c972 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -667,9 +667,20 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, float y_mult = font->y_scale < 0 ? -1 : +1; #endif - metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale); - metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale); - metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender); + if (ft_face->units_per_EM != 0) + { + metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale); + metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale); + metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender); + } + else + { + /* Bitmap-only font, eg. color bitmap font. */ + metrics->ascender = ft_face->size->metrics.ascender; + metrics->descender = ft_face->size->metrics.descender; + metrics->line_gap = ft_face->size->metrics.height - (metrics->ascender - metrics->descender); + } + metrics->ascender = (hb_position_t) (y_mult * metrics->ascender); metrics->descender = (hb_position_t) (y_mult * metrics->descender); metrics->line_gap = (hb_position_t) (y_mult * metrics->line_gap); From 6ed57de15c92f5bf04d9872d989d6eb129f4bec0 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 15 Jul 2022 15:09:28 -0600 Subject: [PATCH 5/5] [ft] Fix negative font sizes for bitmaps --- src/hb-ft.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hb-ft.cc b/src/hb-ft.cc index 4a281c972..3f8fcc3d8 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -137,6 +137,10 @@ _hb_ft_font_destroy (void *data) static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face) { float x_mult = 1.f, y_mult = 1.f; + + if (font->x_scale < 0) x_mult = -x_mult; + if (font->y_scale < 0) y_mult = -y_mult; + if (FT_Set_Char_Size (ft_face, abs (font->x_scale), abs (font->y_scale), 0, 0 @@ -154,6 +158,8 @@ static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face) FT_Set_Char_Size (ft_face, x_scale, y_scale, 0, 0); + + /* This contains the sign that was previously in x_mult/y_mult. */ x_mult = (float) font->x_scale / x_scale; y_mult = (float) font->y_scale / y_scale; #endif @@ -161,8 +167,6 @@ static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face) else { /* Shrug */ } - if (font->x_scale < 0) x_mult = -x_mult; - if (font->y_scale < 0) y_mult = -y_mult; if (x_mult != 1.f || y_mult != 1.f) {