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);