From 6039290c33d1873ec5a2acfa6e453d788ceda9b9 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Sat, 21 Oct 2023 17:58:18 -0700 Subject: [PATCH] BLF: Improved Cached Fallback Font Setup Changes to FontBLF initialization so that the cached fallback fonts - which remain faceless until needed - get all required setup. Otherwise they are not kerned and we also don't get metrics from them. --- This is actually an old PR on Phab. https://archive.blender.org/developer/D15844 This largely just breaks up `blf_ensure_face` into two parts so that some setup can be called from it and also from the `blf_cache_face_requester` callback. We distribute some fonts that are specific to particular languages or uses and we therefore do not want to fully set them up until they are actually used. But with the addition of the FreeType Caching subsystem those fonts do not get a Face until the caching system itself initiates it and we are informed via a callback. At that point calling blf_ensure_face does nothing since the face now exists. This means that they do not get some setup that they would have gotten if caching wasn't enabled or if they were not created to be initially faceless. Without this fix, fallback fonts will not do kerning if the font supports that, but none of these fonts are used for Latin text anyway. They also will not support variable font features if they are of that type. And we would not get font metrics from them. All these things are now becoming more important. --- source/blender/blenfont/intern/blf_font.cc | 101 ++++++++++-------- .../blenfont/intern/blf_internal_types.h | 7 +- 2 files changed, 60 insertions(+), 48 deletions(-) diff --git a/source/blender/blenfont/intern/blf_font.cc b/source/blender/blenfont/intern/blf_font.cc index fa2a9b0f581..cc7d76b70f9 100644 --- a/source/blender/blenfont/intern/blf_font.cc +++ b/source/blender/blenfont/intern/blf_font.cc @@ -75,6 +75,8 @@ static ft_pix blf_font_width_max_ft_pix(FontBLF *font); /** \name FreeType Caching * \{ */ +static bool blf_setup_face(FontBLF *font); + /** * Called when a face is removed by the cache. FreeType will call #FT_Done_Face. */ @@ -112,6 +114,11 @@ static FT_Error blf_cache_face_requester(FTC_FaceID faceID, font->face = *face; font->face->generic.data = font; font->face->generic.finalizer = blf_face_finalizer; + + /* More FontBLF setup now that we have a face. */ + if (!blf_setup_face(font)) { + err = FT_Err_Cannot_Open_Resource; + } } else { /* Clear this on error to avoid exception in FTC_Manager_LookupFace. */ @@ -1454,10 +1461,6 @@ static void blf_font_metrics(FT_Face face, FontMetrics *metrics) metrics->underline_position = short(face->underline_position); metrics->underline_thickness = short(face->underline_thickness); metrics->num_glyphs = int(face->num_glyphs); - metrics->bounding_box.xmin = int(face->bbox.xMin); - metrics->bounding_box.xmax = int(face->bbox.xMax); - metrics->bounding_box.ymin = int(face->bbox.yMin); - metrics->bounding_box.ymax = int(face->bbox.yMax); if (metrics->cap_height == 0) { /* Calculate or guess cap height if it is not set in the font. */ @@ -1537,6 +1540,46 @@ static void blf_font_metrics(FT_Face face, FontMetrics *metrics) if (metrics->superscript_yoffset == 0) { metrics->superscript_yoffset = short(float(metrics->units_per_EM) * 0.35f); } + + metrics->valid = true; +} + +/** + * Extra FontBLF setup needed after it gets a Face. Called from + * both blf_ensure_face and from the blf_cache_face_requester callback. + */ +static bool blf_setup_face(FontBLF *font) +{ + font->face_flags = font->face->face_flags; + + if (FT_HAS_MULTIPLE_MASTERS(font) && !font->variations) { + FT_Get_MM_Var(font->face, &(font->variations)); + } + + if (!font->metrics.valid) { + blf_font_metrics(font->face, &font->metrics); + font->char_weight = font->metrics.weight; + font->char_slant = font->metrics.slant; + font->char_width = font->metrics.width; + font->char_spacing = font->metrics.spacing; + } + + if (FT_IS_FIXED_WIDTH(font)) { + font->flags |= BLF_MONOSPACED; + } + + if (FT_HAS_KERNING(font) && !font->kerning_cache) { + /* Create kerning cache table and fill with value indicating "unset". */ + font->kerning_cache = static_cast( + MEM_mallocN(sizeof(KerningCacheBLF), __func__)); + for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) { + for (uint j = 0; j < KERNING_CACHE_TABLE_SIZE; j++) { + font->kerning_cache->ascii_table[i][j] = KERNING_ENTRY_UNSET; + } + } + } + + return true; } bool blf_ensure_face(FontBLF *font) @@ -1620,45 +1663,8 @@ bool blf_ensure_face(FontBLF *font) font->ft_size = font->face->size; } - font->face_flags = font->face->face_flags; - - if (FT_HAS_MULTIPLE_MASTERS(font)) { - FT_Get_MM_Var(font->face, &(font->variations)); - } - - blf_ensure_size(font); - blf_font_metrics(font->face, &font->metrics); - - font->char_weight = font->metrics.weight; - font->char_slant = font->metrics.slant; - font->char_width = font->metrics.width; - font->char_spacing = font->metrics.spacing; - - /* Save TrueType table with bits to quickly test most unicode block coverage. */ - TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(font->face, FT_SFNT_OS2); - if (os2_table) { - font->unicode_ranges[0] = uint(os2_table->ulUnicodeRange1); - font->unicode_ranges[1] = uint(os2_table->ulUnicodeRange2); - font->unicode_ranges[2] = uint(os2_table->ulUnicodeRange3); - font->unicode_ranges[3] = uint(os2_table->ulUnicodeRange4); - } - - if (FT_IS_FIXED_WIDTH(font)) { - font->flags |= BLF_MONOSPACED; - } - - if (FT_HAS_KERNING(font) && !font->kerning_cache) { - /* Create kerning cache table and fill with value indicating "unset". */ - font->kerning_cache = static_cast( - MEM_mallocN(sizeof(KerningCacheBLF), __func__)); - for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) { - for (uint j = 0; j < KERNING_CACHE_TABLE_SIZE; j++) { - font->kerning_cache->ascii_table[i][j] = KERNING_ENTRY_UNSET; - } - } - } - - return true; + /* Setup Font details that require having a Face. */ + return blf_setup_face(font); } struct FaceDetails { @@ -1755,6 +1761,15 @@ static FontBLF *blf_font_new_impl(const char *filepath, blf_font_free(font); return nullptr; } + + /* Save TrueType table with bits to quickly test most unicode block coverage. */ + TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(font->face, FT_SFNT_OS2); + if (os2_table) { + font->unicode_ranges[0] = uint(os2_table->ulUnicodeRange1); + font->unicode_ranges[1] = uint(os2_table->ulUnicodeRange2); + font->unicode_ranges[2] = uint(os2_table->ulUnicodeRange3); + font->unicode_ranges[3] = uint(os2_table->ulUnicodeRange4); + } } /* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */ diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 5afd7f171a8..3783246296e 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -210,6 +210,8 @@ typedef struct FontBufInfoBLF { } FontBufInfoBLF; typedef struct FontMetrics { + /** Indicate that these values have been properly loaded. */ + bool valid; /** This font's default weight, 100-900, 400 is normal. */ short weight; /** This font's default width, 1 is normal, 2 is twice as wide. */ @@ -232,11 +234,6 @@ typedef struct FontMetrics { /** Maximum Unicode index, or 0xFFFF if greater than. */ short last_charindex; - /** - * Bounds that can contain every glyph in the font when in default positions. Can be used for - * maximum ascender, minimum descender. Can be out by a pixel when hinting. Does not change with - * variation axis changes. */ - rcti bounding_box; /** * Positive number of font units from baseline to top of typical capitals. Can be slightly more * than cap height when head serifs, terminals, or apexes extend above cap line. */ -- 2.30.2