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
This commit is contained in:
Harley Acheson
2025-07-30 21:25:18 +02:00
committed by Harley Acheson
parent 4afe62ee29
commit 276eee8f53
8 changed files with 76 additions and 26 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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;
}
/** \} */

View File

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

View File

@@ -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];

View File

@@ -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<VChar *>(BLI_ghashIterator_getValue(&gh_iter));
if (che == nullptr) {
continue;
}
while (che->nurbsbase.first) {
Nurb *nu = static_cast<Nurb *>(che->nurbsbase.first);

View File

@@ -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<VChar *>(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<VChar *>(*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);
}

View File

@@ -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<const VChar *>(src));
return src ? BKE_vfontdata_char_copy(static_cast<const VChar *>(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);