(Breaking) Fonts: refactor ImFontLoader to allow loading from glyph_index. (#9559, #5647)

cc #9540, #8466, #8465
This commit is contained in:
ocornut 2026-09-29 21:17:16 +02:00
parent 46ff5a7aab
commit 09d740ba32
5 changed files with 47 additions and 49 deletions

View File

@ -81,6 +81,9 @@ Other Changes:
ProggyClean on most Apple/Retina setups by default.
- imgui_freetype: Fixed blurryness rendering `AddFontDefaultVector()`. Caused by a
non-pixel aligned offset caused by `ExtraSizeScale`. (#9348, #9233) [@redpartizan, @RDMCz]
- (Internal) ImFontLoader: reworked `FontSrcContainsGlyph`, `FontBakedLoadGlyph` signatures
to take raw glyph index instead of codepoint. Added `FontSrcGetGlyphIndexFromCodepoint`.
(#9559, #5647, #9540, #8466, #8465)
- ColorEdit:
- ColorButton, ColorEdit, ColorPicker: cancel-out alpha caused by BeginDisabled() so
disabled color buttons have the same color as non-disabled oness. (#9511)

View File

@ -17710,7 +17710,8 @@ static int CalcFontGlyphSrcOverlapMask(ImFontAtlas* atlas, ImFont* font, unsigne
for (int src_n = 0; src_n < font->Sources.Size; src_n++)
{
ImFontConfig* src = font->Sources[src_n];
if (!(src->FontLoader ? src->FontLoader : atlas->FontLoader)->FontSrcContainsGlyph(atlas, src, (ImWchar)codepoint))
const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
if (loader->FontSrcGetGlyphIndexFromCodepoint(atlas, src, (ImWchar)codepoint) == 0)
continue;
mask |= (1 << src_n);
count++;

View File

@ -3123,7 +3123,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in)
}
if (font_cfg->FontLoader != NULL)
{
IM_ASSERT(font_cfg->FontLoader->FontBakedLoadGlyph != NULL);
IM_ASSERT(font_cfg->FontLoader->FontSrcGetGlyphIndexFromCodepoint != NULL && font_cfg->FontLoader->FontBakedLoadGlyph != NULL);
IM_ASSERT(font_cfg->FontLoader->LoaderInit == NULL && font_cfg->FontLoader->LoaderShutdown == NULL); // FIXME-NEWATLAS: Unsupported yet.
}
// | Target w/ Implicit RefSize | Target w/ Explicit RefSize |
@ -4606,10 +4606,15 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep
if (src->GlyphExcludeRanges && !ImFontAtlasBuildAcceptCodepointForSource(src, codepoint))
continue;
int glyph_index = loader->FontSrcGetGlyphIndexFromCodepoint(atlas, src, codepoint);
if (glyph_index == 0)
continue;
if (only_load_advance_x == NULL)
{
ImFontGlyph glyph_buf;
if (!loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint, &glyph_buf, NULL))
glyph_buf.Codepoint = codepoint;
if (!loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, glyph_index, &glyph_buf, NULL))
continue;
// FIXME: Add hooks for e.g. #7962
glyph_buf.Codepoint = src_codepoint;
@ -4619,7 +4624,7 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep
else
{
// Special mode but only loading glyphs metrics. Will rasterize and pack later.
if (!loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint, NULL, only_load_advance_x))
if (!loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, glyph_index, NULL, only_load_advance_x))
continue;
ImFontAtlasBakedAddFontGlyphAdvancedX(atlas, baked, src, codepoint, *only_load_advance_x);
return NULL;
@ -4707,10 +4712,8 @@ struct ImGui_ImplStbTrueType_FontSrcData
float ScaleFactor;
};
static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src)
static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas*, ImFontConfig* src)
{
IM_UNUSED(atlas);
ImGui_ImplStbTrueType_FontSrcData* bd_font_data = IM_NEW(ImGui_ImplStbTrueType_FontSrcData);
IM_ASSERT(src->FontLoaderData == NULL);
@ -4742,29 +4745,27 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig*
return true;
}
static void ImGui_ImplStbTrueType_FontSrcDestroy(ImFontAtlas* atlas, ImFontConfig* src)
static void ImGui_ImplStbTrueType_FontSrcDestroy(ImFontAtlas*, ImFontConfig* src)
{
IM_UNUSED(atlas);
ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData;
IM_DELETE(bd_font_data);
src->FontLoaderData = NULL;
}
static bool ImGui_ImplStbTrueType_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint)
static int ImGui_ImplStbTrueType_FontSrcGetGlyphIndexFromCodepoint(ImFontAtlas*, ImFontConfig* src, ImWchar codepoint)
{
IM_UNUSED(atlas);
ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData;
IM_ASSERT(bd_font_data != NULL);
int glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint);
return glyph_index != 0;
return stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint);
}
static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*)
static bool ImGui_ImplStbTrueType_FontSrcContainsGlyph(ImFontAtlas*, ImFontConfig* src, int glyph_index)
{
IM_UNUSED(atlas);
ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData;
return glyph_index > 0 && glyph_index < bd_font_data->FontInfo.numGlyphs;
}
static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas*, ImFontConfig* src, ImFontBaked* baked, void*)
{
ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData;
if (src->MergeMode == false)
{
@ -4780,14 +4781,12 @@ static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig
return true;
}
static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*, ImWchar codepoint, ImFontGlyph* out_glyph, float* out_advance_x)
static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*, int glyph_index, ImFontGlyph* out_glyph, float* out_advance_x)
{
// Search for first font which has the glyph
ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData;
IM_ASSERT(bd_font_data);
int glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint);
if (glyph_index == 0)
return false;
IM_ASSERT(glyph_index != 0);
// Fonts unit to pixels
int oversample_h, oversample_v;
@ -4812,7 +4811,6 @@ static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontC
}
// Prepare glyph
out_glyph->Codepoint = codepoint;
out_glyph->AdvanceX = advance * scale_for_layout;
// Pack and retrieve position inside texture atlas
@ -4874,6 +4872,7 @@ const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype()
loader.Name = "stb_truetype";
loader.FontSrcInit = ImGui_ImplStbTrueType_FontSrcInit;
loader.FontSrcDestroy = ImGui_ImplStbTrueType_FontSrcDestroy;
loader.FontSrcGetGlyphIndexFromCodepoint = ImGui_ImplStbTrueType_FontSrcGetGlyphIndexFromCodepoint;
loader.FontSrcContainsGlyph = ImGui_ImplStbTrueType_FontSrcContainsGlyph;
loader.FontBakedInit = ImGui_ImplStbTrueType_FontBakedInit;
loader.FontBakedDestroy = NULL;
@ -5405,7 +5404,7 @@ bool ImFont::IsGlyphInFont(ImWchar c)
for (ImFontConfig* src : Sources)
{
const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
if (loader->FontSrcContainsGlyph != NULL && loader->FontSrcContainsGlyph(atlas, src, c))
if (loader->FontSrcGetGlyphIndexFromCodepoint(atlas, src, c) != 0)
return true;
}
return false;

View File

@ -3932,10 +3932,11 @@ struct ImFontLoader
void (*LoaderShutdown)(ImFontAtlas* atlas);
bool (*FontSrcInit)(ImFontAtlas* atlas, ImFontConfig* src);
void (*FontSrcDestroy)(ImFontAtlas* atlas, ImFontConfig* src);
bool (*FontSrcContainsGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint);
int (*FontSrcGetGlyphIndexFromCodepoint)(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint); // Required
bool (*FontSrcContainsGlyph)(ImFontAtlas* atlas, ImFontConfig* src, int glyph_index);
bool (*FontBakedInit)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src);
void (*FontBakedDestroy)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src);
bool (*FontBakedLoadGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint, ImFontGlyph* out_glyph, float* out_advance_x);
bool (*FontBakedLoadGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, int glyph_index, ImFontGlyph* out_glyph, float* out_advance_x); // Required
// Size of backend data, Per Baked * Per Source. Buffers are managed by core to avoid excessive allocations.
// FIXME: At this point the two other types of buffers may be managed by core to be consistent?

View File

@ -221,17 +221,14 @@ void ImGui_ImplFreeType_FontSrcData::CloseFont()
}
}
static const FT_Glyph_Metrics* ImGui_ImplFreeType_LoadGlyph(ImGui_ImplFreeType_FontSrcData* src_data, uint32_t codepoint)
static const FT_Glyph_Metrics* ImGui_ImplFreeType_LoadGlyph(ImGui_ImplFreeType_FontSrcData* src_data, uint32_t glyph_index)
{
uint32_t glyph_index = FT_Get_Char_Index(src_data->FtFace, codepoint);
if (glyph_index == 0)
return nullptr;
// If this crash for you: FreeType 2.11.0 has a crash bug on some bitmap/colored fonts.
// - https://gitlab.freedesktop.org/freetype/freetype/-/issues/1076
// - https://github.com/ocornut/imgui/issues/4567
// - https://github.com/ocornut/imgui/issues/4566
// You can use FreeType 2.10, or the patched version of 2.11.0 in VcPkg, or probably any upcoming FreeType version.
IM_ASSERT(glyph_index != 0);
FT_Error error = FT_Load_Glyph(src_data->FtFace, glyph_index, src_data->LoadFlags);
if (error)
return nullptr;
@ -417,17 +414,15 @@ static bool ImGui_ImplFreeType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src
return true;
}
static void ImGui_ImplFreeType_FontSrcDestroy(ImFontAtlas* atlas, ImFontConfig* src)
static void ImGui_ImplFreeType_FontSrcDestroy(ImFontAtlas*, ImFontConfig* src)
{
IM_UNUSED(atlas);
ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData;
IM_DELETE(bd_font_data);
src->FontLoaderData = nullptr;
}
static bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src)
static bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas*, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src)
{
IM_UNUSED(atlas);
float size = baked->Size;
const float ref_size = baked->OwnerFont->Sources[0]->SizePixels;
if (src->MergeMode && src->SizePixels != 0.0f)
@ -475,9 +470,8 @@ static bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* s
return true;
}
static void ImGui_ImplFreeType_FontBakedDestroy(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src)
static void ImGui_ImplFreeType_FontBakedDestroy(ImFontAtlas*, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src)
{
IM_UNUSED(atlas);
IM_UNUSED(baked);
IM_UNUSED(src);
ImGui_ImplFreeType_FontSrcBakedData* bd_baked_data = (ImGui_ImplFreeType_FontSrcBakedData*)loader_data_for_baked_src;
@ -486,13 +480,9 @@ static void ImGui_ImplFreeType_FontBakedDestroy(ImFontAtlas* atlas, ImFontConfig
bd_baked_data->~ImGui_ImplFreeType_FontSrcBakedData(); // ~IM_PLACEMENT_DELETE()
}
static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint, ImFontGlyph* out_glyph, float* out_advance_x)
static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, int glyph_index, ImFontGlyph* out_glyph, float* out_advance_x)
{
ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData;
uint32_t glyph_index = FT_Get_Char_Index(bd_font_data->FtFace, codepoint);
if (glyph_index == 0)
return false;
if (bd_font_data->BakedLastActivated != baked) // <-- could use id
{
// Activate current size
@ -501,7 +491,7 @@ static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConf
bd_font_data->BakedLastActivated = baked;
}
const FT_Glyph_Metrics* metrics = ImGui_ImplFreeType_LoadGlyph(bd_font_data, codepoint);
const FT_Glyph_Metrics* metrics = ImGui_ImplFreeType_LoadGlyph(bd_font_data, glyph_index);
if (metrics == nullptr)
return false;
@ -530,7 +520,6 @@ static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConf
const bool is_visible = (w != 0 && h != 0);
// Prepare glyph
out_glyph->Codepoint = codepoint;
out_glyph->AdvanceX = advance_x;
// Pack and retrieve position inside texture atlas
@ -573,12 +562,16 @@ static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConf
return true;
}
static bool ImGui_ImplFreetype_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint)
static int ImGui_ImplFreetype_FontSrcGetGlyphIndexFromCodepoint(ImFontAtlas*, ImFontConfig* src, ImWchar codepoint)
{
IM_UNUSED(atlas);
ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData;
int glyph_index = FT_Get_Char_Index(bd_font_data->FtFace, codepoint);
return glyph_index != 0;
return (int)FT_Get_Char_Index(bd_font_data->FtFace, codepoint);
}
static bool ImGui_ImplFreeType_FontSrcContainsGlyph(ImFontAtlas*, ImFontConfig* src, int glyph_index)
{
ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData;
return glyph_index > 0 && glyph_index < bd_font_data->FtFace->num_glyphs;
}
const ImFontLoader* ImGuiFreeType::GetFontLoader()
@ -589,7 +582,8 @@ const ImFontLoader* ImGuiFreeType::GetFontLoader()
loader->LoaderShutdown = ImGui_ImplFreeType_LoaderShutdown;
loader->FontSrcInit = ImGui_ImplFreeType_FontSrcInit;
loader->FontSrcDestroy = ImGui_ImplFreeType_FontSrcDestroy;
loader->FontSrcContainsGlyph = ImGui_ImplFreetype_FontSrcContainsGlyph;
loader->FontSrcGetGlyphIndexFromCodepoint = ImGui_ImplFreetype_FontSrcGetGlyphIndexFromCodepoint;
loader->FontSrcContainsGlyph = ImGui_ImplFreeType_FontSrcContainsGlyph;
loader->FontBakedInit = ImGui_ImplFreeType_FontBakedInit;
loader->FontBakedDestroy = ImGui_ImplFreeType_FontBakedDestroy;
loader->FontBakedLoadGlyph = ImGui_ImplFreeType_FontBakedLoadGlyph;