From 276eee8f5364e93b60cef0193821ed62998d6f34 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Wed, 30 Jul 2025 21:25:18 +0200 Subject: [PATCH] BLF: Correct the Showing of VFont Not Found Character When VFont objects use a custom (non-default) font and reference a character that is not contained in that font, our intention is to show placeholder curves that represents "not found". Instead we are currently showing the ".notdef" glyph if there is one defined inside the font or blank space if not. This PR fixes that by altering BLF_character_to_curves so that it returns a boolean success instead of character advance. This way we can properly distinguish "not found" from the return of other empty, non-advancing characters. Pull Request: https://projects.blender.org/blender/blender/pulls/143484 --- source/blender/blenfont/BLF_api.hh | 9 +++++-- source/blender/blenfont/intern/blf.cc | 12 ++++++--- source/blender/blenfont/intern/blf_glyph.cc | 19 +++++++++++--- .../blender/blenfont/intern/blf_internal.hh | 11 ++++---- source/blender/blenkernel/BKE_vfontdata.hh | 7 ++++++ source/blender/blenkernel/intern/vfont.cc | 3 +++ .../blender/blenkernel/intern/vfont_curve.cc | 25 +++++++++++++------ .../blenkernel/intern/vfontdata_freetype.cc | 16 +++++++++--- 8 files changed, 76 insertions(+), 26 deletions(-) diff --git a/source/blender/blenfont/BLF_api.hh b/source/blender/blenfont/BLF_api.hh index 9c18c92ae1d..e606d76ad67 100644 --- a/source/blender/blenfont/BLF_api.hh +++ b/source/blender/blenfont/BLF_api.hh @@ -126,9 +126,14 @@ bool BLF_get_vfont_metrics(int fontid, float *ascend_ratio, float *em_ratio, flo /** * Convert a character's outlines into curves. + * \return success if the character was found and converted. */ -float BLF_character_to_curves( - int fontid, unsigned int unicode, ListBase *nurbsbase, const float scale, bool use_fallback); +bool BLF_character_to_curves(int fontid, + unsigned int unicode, + ListBase *nurbsbase, + const float scale, + bool use_fallback, + float *r_advance); /** * Check if font supports a particular glyph. diff --git a/source/blender/blenfont/intern/blf.cc b/source/blender/blenfont/intern/blf.cc index 76213986ce0..2c92283bd27 100644 --- a/source/blender/blenfont/intern/blf.cc +++ b/source/blender/blenfont/intern/blf.cc @@ -1127,14 +1127,18 @@ bool BLF_get_vfont_metrics(int fontid, float *ascend_ratio, float *em_ratio, flo return true; } -float BLF_character_to_curves( - int fontid, uint unicode, ListBase *nurbsbase, const float scale, bool use_fallback) +bool BLF_character_to_curves(int fontid, + uint unicode, + ListBase *nurbsbase, + const float scale, + bool use_fallback, + float *r_advance) { FontBLF *font = blf_get(fontid); if (!font) { - return 0.0f; + return false; } - return blf_character_to_curves(font, unicode, nurbsbase, scale, use_fallback); + return blf_character_to_curves(font, unicode, nurbsbase, scale, use_fallback, r_advance); } #ifndef NDEBUG diff --git a/source/blender/blenfont/intern/blf_glyph.cc b/source/blender/blenfont/intern/blf_glyph.cc index 53f1326a1da..1c3d17172e3 100644 --- a/source/blender/blenfont/intern/blf_glyph.cc +++ b/source/blender/blenfont/intern/blf_glyph.cc @@ -1863,6 +1863,11 @@ static FT_GlyphSlot blf_glyphslot_ensure_outline(FontBLF *font, uint charcode, b FontBLF *font_with_glyph = font; FT_UInt glyph_index = use_fallback ? blf_glyph_index_from_charcode(&font_with_glyph, charcode) : blf_get_char_index(font_with_glyph, charcode); + + if (!glyph_index) { + return nullptr; + } + if (!blf_ensure_face(font_with_glyph)) { return nullptr; } @@ -1883,16 +1888,22 @@ static FT_GlyphSlot blf_glyphslot_ensure_outline(FontBLF *font, uint charcode, b return glyph; } -float blf_character_to_curves( - FontBLF *font, uint unicode, ListBase *nurbsbase, const float scale, bool use_fallback) +bool blf_character_to_curves(FontBLF *font, + uint unicode, + ListBase *nurbsbase, + const float scale, + bool use_fallback, + float *r_advance) { FT_GlyphSlot glyph = blf_glyphslot_ensure_outline(font, unicode, use_fallback); if (!glyph) { - return 0.0f; + *r_advance = 0.0f; + return false; } blf_glyph_to_curves(glyph->outline, nurbsbase, scale); - return float(glyph->advance.x) * scale; + *r_advance = float(glyph->advance.x) * scale; + return true; } /** \} */ diff --git a/source/blender/blenfont/intern/blf_internal.hh b/source/blender/blenfont/intern/blf_internal.hh index b041868ee89..f3c22d9f875 100644 --- a/source/blender/blenfont/intern/blf_internal.hh +++ b/source/blender/blenfont/intern/blf_internal.hh @@ -203,11 +203,12 @@ GlyphBLF *blf_glyph_ensure_icon( /** * Convert a character's outlines into curves. */ -float blf_character_to_curves(FontBLF *font, - unsigned int unicode, - ListBase *nurbsbase, - const float scale, - bool use_fallback); +bool blf_character_to_curves(FontBLF *font, + unsigned int unicode, + ListBase *nurbsbase, + const float scale, + bool use_fallback, + float *r_advance); void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, int x, int y); diff --git a/source/blender/blenkernel/BKE_vfontdata.hh b/source/blender/blenkernel/BKE_vfontdata.hh index bc499cd4177..5d3f2ede717 100644 --- a/source/blender/blenkernel/BKE_vfontdata.hh +++ b/source/blender/blenkernel/BKE_vfontdata.hh @@ -38,6 +38,13 @@ struct VFontData_Metrics { }; struct VFontData { + /** + * A hash that maps `uint -> VChar` (code-points to character outlines). + * + * \note values may be null when the character does not exist in the font. + * This is done to differentiate characters known not to exist from + * characters that have not yet been loaded. + */ GHash *characters; char name[128]; diff --git a/source/blender/blenkernel/intern/vfont.cc b/source/blender/blenkernel/intern/vfont.cc index 86c4e7a47e3..66151df0e6a 100644 --- a/source/blender/blenkernel/intern/vfont.cc +++ b/source/blender/blenkernel/intern/vfont.cc @@ -245,6 +245,9 @@ void BKE_vfont_data_free(VFont *vfont) GHashIterator gh_iter; GHASH_ITER (gh_iter, vfont->data->characters) { VChar *che = static_cast(BLI_ghashIterator_getValue(&gh_iter)); + if (che == nullptr) { + continue; + } while (che->nurbsbase.first) { Nurb *nu = static_cast(che->nurbsbase.first); diff --git a/source/blender/blenkernel/intern/vfont_curve.cc b/source/blender/blenkernel/intern/vfont_curve.cc index c24c7a8b646..2db9b82977b 100644 --- a/source/blender/blenkernel/intern/vfont_curve.cc +++ b/source/blender/blenkernel/intern/vfont_curve.cc @@ -107,9 +107,14 @@ static VFontData *vfont_data_ensure_with_lock(VFont *vfont) return vfont->data; } -static VChar *vfont_char_find(const VFontData *vfd, char32_t charcode) +static bool vfont_char_find(const VFontData *vfd, char32_t charcode, VChar **r_che) { - return static_cast(BLI_ghash_lookup(vfd->characters, POINTER_FROM_UINT(charcode))); + if (void **che_p = BLI_ghash_lookup_p(vfd->characters, POINTER_FROM_UINT(charcode))) { + *r_che = static_cast(*che_p); + return true; + } + *r_che = nullptr; + return false; } /** @@ -124,19 +129,19 @@ static VChar *vfont_char_ensure_with_lock(VFont *vfont, char32_t charcode) if (vfont && vfont->data) { VFontData *vfd = vfont->data; BLI_rw_mutex_lock(&vfont_rwlock, THREAD_LOCK_READ); - che = vfont_char_find(vfd, charcode); + bool che_found = vfont_char_find(vfd, charcode, &che); BLI_rw_mutex_unlock(&vfont_rwlock); /* The character wasn't in the current curve base so load it. */ - if (che == nullptr) { + if (che_found == false) { BLI_rw_mutex_lock(&vfont_rwlock, THREAD_LOCK_WRITE); /* Check it once again, char might have been already load * between previous #BLI_rw_mutex_unlock() and this #BLI_rw_mutex_lock(). * * Such a check should not be a bottleneck since it wouldn't * happen often once all the chars are load. */ - che = vfont_char_find(vfd, charcode); - if (che == nullptr) { + che_found = vfont_char_find(vfd, charcode, &che); + if (che_found == false) { che = BKE_vfontdata_char_from_freetypefont(vfont, charcode); } BLI_rw_mutex_unlock(&vfont_rwlock); @@ -268,7 +273,10 @@ static VChar *vfont_char_find_or_placeholder(const VFontData *vfd, char32_t charcode, VCharPlaceHolder &che_placeholder) { - VChar *che = vfd ? vfont_char_find(vfd, charcode) : nullptr; + VChar *che = nullptr; + if (vfd) { + vfont_char_find(vfd, charcode, &che); + } if (UNLIKELY(che == nullptr)) { che = vfont_placeholder_ensure(che_placeholder, charcode); } @@ -491,7 +499,8 @@ void BKE_vfont_char_build(Curve *cu, if (!vfd) { return; } - VChar *che = vfont_char_find(vfd, charcode); + VChar *che; + vfont_char_find(vfd, charcode, &che); vfont_char_build_impl(cu, nubase, che, info, ofsx, ofsy, rot, charidx, fsize); } diff --git a/source/blender/blenkernel/intern/vfontdata_freetype.cc b/source/blender/blenkernel/intern/vfontdata_freetype.cc index 63df82e3e82..ffcdff149f7 100644 --- a/source/blender/blenkernel/intern/vfontdata_freetype.cc +++ b/source/blender/blenkernel/intern/vfontdata_freetype.cc @@ -71,7 +71,7 @@ VFontData *BKE_vfontdata_from_freetypefont(PackedFile *pf) static void *vfontdata_copy_characters_value_cb(const void *src) { - return BKE_vfontdata_char_copy(static_cast(src)); + return src ? BKE_vfontdata_char_copy(static_cast(src)) : nullptr; } VFontData *BKE_vfontdata_copy(const VFontData *vfont_src, const int /*flag*/) @@ -122,8 +122,18 @@ VChar *BKE_vfontdata_char_from_freetypefont(VFont *vfont, uint character) /* need to set a size for embolden, etc. */ BLF_size(font_id, 16); - che->width = BLF_character_to_curves( - font_id, character, &che->nurbsbase, vfont->data->metrics.scale, use_fallback); + if (!BLF_character_to_curves(font_id, + character, + &che->nurbsbase, + vfont->data->metrics.scale, + use_fallback, + &che->width)) + { + /* Free but add to the character cache to prevent future lookups + * from attempting to load the font again. */ + MEM_freeN(che); + che = nullptr; + } BLI_ghash_insert(vfont->data->characters, POINTER_FROM_UINT(character), che); BLF_unload_id(font_id);