WIP: Optional VFont Char Loading by Glyph ID #116288

Draft
Harley Acheson wants to merge 3 commits from Harley/blender:vfontbyglyph into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
9 changed files with 131 additions and 41 deletions

View File

@ -78,13 +78,25 @@ char *BLF_display_name_from_id(int fontid);
*/
bool BLF_get_vfont_metrics(int fontid, float *ascend_ratio, float *em_ratio, float *scale);
typedef struct GlyphData {
uint32_t glyphid;
uint32_t codepoint;
int logical_position;
float advance_x;
float advance_y;
float offset_x;
float offset_y;
} GlyphData;
//int BLF_glyph_data(int fontid, const char32_t *str, int len, struct GlyphData **r_glyphs);
/**
* Convert a character's outlines into curves.
*/
float BLF_character_to_curves(int fontid,
unsigned int unicode,
struct ListBase *nurbsbase,
const float scale);
bool BLF_character_to_curves(int fontid,
const float scale,
struct GlyphData *rw_glyph_data,
struct ListBase *nurbsbase);
/**
* Check if font supports a particular glyph.

View File

@ -1008,13 +1008,16 @@ 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 BLF_character_to_curves(int fontid,
const float scale,
GlyphData *rw_glyph_data,
ListBase *nurbsbase)
{
FontBLF *font = blf_get(fontid);
if (!font) {
return 0.0f;
return false;
}
return blf_character_to_curves(font, unicode, nurbsbase, scale);
return blf_character_to_curves(font, scale, rw_glyph_data, nurbsbase);
}
#ifndef NDEBUG

View File

@ -1805,11 +1805,16 @@ static void blf_glyph_to_curves(FT_Outline ftoutline, ListBase *nurbsbase, const
MEM_freeN(onpoints);
}
static FT_GlyphSlot blf_glyphslot_ensure_outline(FontBLF *font, const uint charcode)
static FT_GlyphSlot blf_glyphslot_ensure_outline(FontBLF *font, const uint charcode, const uint glypyid)
{
/* Glyph might not come from the initial font. */
FontBLF *font_with_glyph = font;
FT_UInt glyph_index = blf_glyph_index_from_charcode(&font_with_glyph, charcode);
FT_UInt glyph_index = glypyid;
if (!glyph_index) {
glyph_index = blf_glyph_index_from_charcode(&font_with_glyph, charcode);
}
if (!blf_ensure_face(font_with_glyph)) {
return nullptr;
@ -1831,15 +1836,27 @@ static FT_GlyphSlot blf_glyphslot_ensure_outline(FontBLF *font, const uint charc
return glyph;
}
float blf_character_to_curves(FontBLF *font, uint unicode, ListBase *nurbsbase, const float scale)
bool blf_character_to_curves(FontBLF *font,
const float scale,
GlyphData *rw_glyph_data,
ListBase *nurbsbase)
{
FT_GlyphSlot glyph = blf_glyphslot_ensure_outline(font, unicode);
FT_GlyphSlot glyph = blf_glyphslot_ensure_outline(
font, rw_glyph_data->codepoint, rw_glyph_data->glyphid);
if (!glyph) {
return 0.0f;
return false;
}
blf_glyph_to_curves(glyph->outline, nurbsbase, scale);
return float(glyph->advance.x) * scale;
rw_glyph_data->glyphid = glyph->glyph_index;
rw_glyph_data->advance_x = float(glyph->advance.x) * scale;
rw_glyph_data->advance_y = float(glyph->advance.y) * scale;
rw_glyph_data->offset_x = 0.0f;
rw_glyph_data->offset_y = 0.0f;
return true;
}
/** \} */

View File

@ -189,10 +189,10 @@ struct GlyphBLF *blf_glyph_ensure_subpixel(struct FontBLF *font,
/**
* Convert a character's outlines into curves.
*/
float blf_character_to_curves(FontBLF *font,
unsigned int unicode,
struct ListBase *nurbsbase,
const float scale);
bool blf_character_to_curves(FontBLF *font,
const float scale,
struct GlyphData *rw_glyph_data,
struct ListBase *nurbsbase);
void blf_glyph_free(struct GlyphBLF *g);
void blf_glyph_draw(

View File

@ -110,7 +110,8 @@ int BKE_vfont_cursor_to_text_index(Object *ob, float cursor_location[2]);
bool BKE_vfont_to_curve(Object *ob, eEditFontMode mode);
void BKE_vfont_build_char(Curve *cu,
ListBase *nubase,
unsigned int character,
uint codepoint,
uint glyphid,
CharInfo *info,
float ofsx,
float ofsy,

View File

@ -18,6 +18,7 @@ struct VFont;
struct VFontData {
GHash *characters;
GHash *glyphs;
char name[128];
float scale;
/* Calculated from the font. */
@ -27,8 +28,17 @@ struct VFontData {
struct VChar {
ListBase nurbsbase;
unsigned int index;
float width;
/* UTF-32/UCS-4 code unit of the character in the Unicode set. */
unsigned int codepoint;
/* Index of the character within the current font. */
unsigned int glyphid;
/* How much the pen is moved after this character is placed. */
float advance_x;
float advance_y;
/* Positional adjustment unrelated to advance. Usually used for centering
* typographical marks above previous character when complex shaping. */
float offset_x;
float offset_y;
};
/**
@ -40,5 +50,5 @@ struct VChar {
VFontData *BKE_vfontdata_from_freetypefont(PackedFile *pf);
VFontData *BKE_vfontdata_copy(const VFontData *vfont_src, int flag);
VChar *BKE_vfontdata_char_from_freetypefont(VFont *vfont, unsigned long character);
VChar *BKE_vfontdata_char_from_freetypefont(VFont *vfont, ulong codepoint, ulong glyphid = 0);
VChar *BKE_vfontdata_char_copy(const VChar *vchar_src);

View File

@ -196,21 +196,30 @@ void BKE_vfont_free_data(VFont *vfont)
GHashIterator gh_iter;
GHASH_ITER (gh_iter, vfont->data->characters) {
VChar *che = static_cast<VChar *>(BLI_ghashIterator_getValue(&gh_iter));
while (che->nurbsbase.first) {
while (che && che->nurbsbase.first) {
Nurb *nu = static_cast<Nurb *>(che->nurbsbase.first);
if (nu->bezt) {
MEM_freeN(nu->bezt);
}
MEM_SAFE_FREE(nu->bezt);
BLI_freelinkN(&che->nurbsbase, nu);
}
MEM_freeN(che);
MEM_SAFE_FREE(che);
}
BLI_ghash_free(vfont->data->characters, nullptr, nullptr);
}
if (vfont->data->glyphs) {
GHashIterator gh_iter;
GHASH_ITER (gh_iter, vfont->data->glyphs) {
VChar *che = static_cast<VChar *>(BLI_ghashIterator_getValue(&gh_iter));
while (che && che->nurbsbase.first) {
Nurb *nu = static_cast<Nurb *>(che->nurbsbase.first);
MEM_SAFE_FREE(nu->bezt);
BLI_freelinkN(&che->nurbsbase, nu);
}
MEM_SAFE_FREE(che);
}
BLI_ghash_free(vfont->data->glyphs, nullptr, nullptr);
}
MEM_freeN(vfont->data);
vfont->data = nullptr;
}
@ -427,9 +436,25 @@ VFont *BKE_vfont_builtin_get()
return vfont;
}
static VChar *find_vfont_char(VFontData *vfd, uint character)
static VChar *find_vfont_char(VFontData *vfd, uint codepoint, uint glyphid = 0)
{
return static_cast<VChar *>(BLI_ghash_lookup(vfd->characters, POINTER_FROM_UINT(character)));
VChar *che = nullptr;
if (glyphid) {
che = static_cast<VChar *>(BLI_ghash_lookup(vfd->glyphs, POINTER_FROM_UINT(glyphid)));
if (che) {
return che;
}
}
if (codepoint) {
che = static_cast<VChar *>(BLI_ghash_lookup(vfd->characters, POINTER_FROM_UINT(codepoint)));
if (che) {
return che;
}
}
return che;
}
static void build_underline(Curve *cu,
@ -498,7 +523,8 @@ static void build_underline(Curve *cu,
void BKE_vfont_build_char(Curve *cu,
ListBase *nubase,
uint character,
uint codepoint,
uint glyphid,
CharInfo *info,
float ofsx,
float ofsy,
@ -516,7 +542,7 @@ void BKE_vfont_build_char(Curve *cu,
float si = sinf(rot);
float co = cosf(rot);
VChar *che = find_vfont_char(vfd, character);
VChar *che = find_vfont_char(vfd, codepoint, glyphid);
/* Select the glyph data */
Nurb *nu1 = nullptr;
@ -678,10 +704,10 @@ static float char_width(Curve *cu, VChar *che, CharInfo *info)
return 0.0f;
}
if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
return che->width * cu->smallcaps_scale;
return che->advance_x * cu->smallcaps_scale;
}
return che->width;
return che->advance_x;
}
static void textbox_scale(TextBox *tb_dst, const TextBox *tb_src, float scale)
@ -1688,7 +1714,7 @@ static bool vfont_to_curve(Object *ob,
}
/* We don't want to see any character for '\n'. */
if (cha != '\n') {
BKE_vfont_build_char(cu, r_nubase, cha, info, ct->xof, ct->yof, ct->rot, i, font_size);
BKE_vfont_build_char(cu, r_nubase, cha, 0, info, ct->xof, ct->yof, ct->rot, i, font_size);
}
if ((info->flag & CU_CHINFO_UNDERLINE) && (cha != '\n')) {

View File

@ -52,6 +52,7 @@ VFontData *BKE_vfontdata_from_freetypefont(PackedFile *pf)
BLF_get_vfont_metrics(fontid, &vfd->ascender, &vfd->em_height, &vfd->scale);
vfd->characters = BLI_ghash_int_new_ex(__func__, 255);
vfd->glyphs = BLI_ghash_int_new_ex(__func__, 255);
BLF_unload_id(fontid);
@ -71,11 +72,15 @@ VFontData *BKE_vfontdata_copy(const VFontData *vfont_src, const int /*flag*/)
vfont_dst->characters = BLI_ghash_copy(
vfont_src->characters, nullptr, vfontdata_copy_characters_value_cb);
}
if (vfont_src->glyphs != nullptr) {
vfont_dst->glyphs = BLI_ghash_copy(
vfont_src->glyphs, nullptr, vfontdata_copy_characters_value_cb);
}
return vfont_dst;
}
VChar *BKE_vfontdata_char_from_freetypefont(VFont *vfont, ulong character)
VChar *BKE_vfontdata_char_from_freetypefont(VFont *vfont, ulong codepoint, ulong glyphid)
{
if (!vfont) {
return nullptr;
@ -97,14 +102,30 @@ VChar *BKE_vfontdata_char_from_freetypefont(VFont *vfont, ulong character)
}
VChar *che = (VChar *)MEM_callocN(sizeof(VChar), "objfnt_char");
che->index = 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->scale);
GlyphData glyph_data;
glyph_data.codepoint = codepoint;
glyph_data.glyphid = glyphid;
if (BLF_character_to_curves(font_id, vfont->data->scale, &glyph_data, &che->nurbsbase)) {
che->codepoint = glyph_data.codepoint;
che->glyphid = glyph_data.glyphid;
che->advance_x = glyph_data.advance_x;
che->advance_y = glyph_data.advance_y;
che->offset_x = glyph_data.offset_x;
che->offset_y = glyph_data.offset_y;
if (codepoint) {
BLI_ghash_insert(vfont->data->characters, POINTER_FROM_UINT(che->codepoint), che);
}
else if (che->glyphid) {
BLI_ghash_insert(vfont->data->glyphs, POINTER_FROM_UINT(che->glyphid), che);
}
}
BLI_ghash_insert(vfont->data->characters, POINTER_FROM_UINT(che->index), che);
BLF_unload_id(font_id);
return che;
}

View File

@ -285,7 +285,7 @@ static Map<int, int> create_curve_instances(GeoNodeExecParams &params,
CharInfo charinfo = {0};
charinfo.mat_nr = 1;
BKE_vfont_build_char(&cu, &cu.nurb, layout.char_codes[i], &charinfo, 0, 0, 0, i, 1);
BKE_vfont_build_char(&cu, &cu.nurb, layout.char_codes[i], 0, &charinfo, 0, 0, 0, i, 1);
Curves *curves_id = bke::curve_legacy_to_curves(cu);
if (curves_id == nullptr) {
if (pivot_required) {