Fonts: A font source can specify its own loader/backend.

This commit is contained in:
ocornut
2025-02-06 19:31:13 +01:00
parent 1cfc0de31d
commit c06a7585a3
2 changed files with 57 additions and 27 deletions

View File

@@ -3444,7 +3444,9 @@ struct ImFontConfig
// [Internal]
char Name[40]; // Name (strictly to ease debugging)
ImFontFlags Flags; // Font flags (don't use just yet)
ImFont* DstFont; // Target font (as we merging fonts, multiple ImFontConfig may target the same font)
const ImFontLoader* FontLoader; // Custom font backend for this source (other use one stored in ImFontAtlas)
void* FontLoaderData; // Font loader opaque storage (per font config)
IMGUI_API ImFontConfig();

View File

@@ -2607,14 +2607,18 @@ ImFontAtlas::ImFontAtlas()
ImFontAtlas::~ImFontAtlas()
{
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
Clear();
RendererHasTextures = false; // Full Clear() is supported, but ClearTexData() only isn't.
ClearFonts();
ClearTexData();
TexList.clear_delete();
TexData = NULL;
}
void ImFontAtlas::Clear()
{
ClearFonts();
bool backup_renderer_has_textures = RendererHasTextures;
RendererHasTextures = false; // Full Clear() is supported, but ClearTexData() only isn't.
ClearFonts();
ClearTexData();
if (Builder != NULL)
ImFontAtlasBuildClearTexture(this);
@@ -2631,8 +2635,9 @@ void ImFontAtlas::ClearInputData()
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
for (ImFontConfig& font_cfg : Sources)
{
if (FontLoader && FontLoader->FontSrcDestroy != NULL)
FontLoader->FontSrcDestroy(this, &font_cfg);
const ImFontLoader* loader = font_cfg.FontLoader ? font_cfg.FontLoader : FontLoader;
if (loader && loader->FontSrcDestroy != NULL)
loader->FontSrcDestroy(this, &font_cfg);
if (font_cfg.FontData && font_cfg.FontDataOwnedByAtlas)
{
IM_FREE(font_cfg.FontData);
@@ -2957,7 +2962,7 @@ bool ImFontAtlas::Build()
ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
{
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0);
IM_ASSERT((font_cfg->FontData != NULL && font_cfg->FontDataSize > 0) || (font_cfg->FontLoader != NULL));
IM_ASSERT(font_cfg->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?");
IM_ASSERT(font_cfg->RasterizerDensity > 0.0f && "Is ImFontConfig struct correctly initialized?");
@@ -2971,6 +2976,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
{
font = IM_NEW(ImFont)();
font->FontId = FontNextUniqueID++;
font->Flags = font_cfg->Flags;
Fonts.push_back(font);
}
else
@@ -2998,6 +3004,9 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
IM_ASSERT((size & 1) == 0 && "GlyphExcludeRanges[] size must be multiple of two!");
IM_ASSERT((size <= 64) && "GlyphExcludeRanges[] size must be small!");
}
if (font_cfg->FontLoader != NULL)
IM_ASSERT(font_cfg->FontLoader->FontBakedAddGlyph != NULL);
IM_ASSERT(font_cfg->FontLoaderData == NULL);
// Round font size
// - We started rounding in 1.90 WIP (18991) as our layout system currently doesn't support non-rounded font size well yet.
@@ -3165,8 +3174,9 @@ void ImFontAtlas::RemoveFont(ImFont* font)
for (int src_n = 0; src_n < font->SourcesCount; src_n++)
{
ImFontConfig* src = (ImFontConfig*)(void*)&font->Sources[src_n];
if (FontLoader && FontLoader->FontSrcDestroy != NULL)
FontLoader->FontSrcDestroy(this, src);
const ImFontLoader* loader = src->FontLoader ? src->FontLoader : FontLoader;
if (loader && loader->FontSrcDestroy != NULL)
loader->FontSrcDestroy(this, src);
if (src->FontData != NULL && src->FontDataOwnedByAtlas)
IM_FREE(src->FontData);
}
@@ -3317,6 +3327,8 @@ void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* ou
*out_oversample_v = (src->OversampleV != 0) ? src->OversampleV : 1;
}
// Setup main font loader for the atlas
// Every font source (ImFontConfig) will use this unless ImFontConfig::FontLoader specify a custom loader.
void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* font_loader)
{
if (atlas->FontLoader == font_loader)
@@ -3521,9 +3533,10 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src)
IM_ASSERT(font->Sources == src);
}
const ImFontLoader* font_loader = atlas->FontLoader;
if (!font_loader->FontSrcInit(atlas, src))
return false;
const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
if (loader->FontSrcInit != NULL)
if (!loader->FontSrcInit(atlas, src))
return false;
ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, font, src);
return true;
@@ -3680,15 +3693,22 @@ ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, floa
baked->LastUsedFrame = atlas->Builder->FrameCount;
// Initialize backend data
size_t loader_data_size = font->SourcesCount * atlas->FontLoader->FontBakedSrcLoaderDataSize;
size_t loader_data_size = 0;
for (int src_n = 0; src_n < font->SourcesCount; src_n++) // Cannot easily be cached as we allow changing backend
{
ImFontConfig* src = &font->Sources[src_n];
const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
loader_data_size += loader->FontBakedSrcLoaderDataSize;
}
baked->FontLoaderDatas = (loader_data_size > 0) ? IM_ALLOC(loader_data_size) : NULL;
char* backend_user_data_p = (char*)baked->FontLoaderDatas;
char* loader_data_p = (char*)baked->FontLoaderDatas;
for (int src_n = 0; src_n < font->SourcesCount; src_n++)
{
ImFontConfig* src = &font->Sources[src_n];
if (atlas->FontLoader->FontBakedInit)
atlas->FontLoader->FontBakedInit(atlas, src, baked, backend_user_data_p);
backend_user_data_p += atlas->FontLoader->FontBakedSrcLoaderDataSize;
const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
if (loader->FontBakedInit)
loader->FontBakedInit(atlas, src, baked, loader_data_p);
loader_data_p += loader->FontBakedSrcLoaderDataSize;
}
ImFontAtlasBuildSetupFontBakedSpecialGlyphs(atlas, baked->ContainerFont, baked);
@@ -3704,13 +3724,14 @@ void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBa
if (glyph.PackId >= 0)
ImFontAtlasPackDiscardRect(atlas, glyph.PackId);
char* backend_user_data_p = (char*)baked->FontLoaderDatas;
char* loader_data_p = (char*)baked->FontLoaderDatas;
for (int src_n = 0; src_n < font->SourcesCount; src_n++)
{
ImFontConfig* src = &font->Sources[src_n];
if (atlas->FontLoader->FontBakedDestroy)
atlas->FontLoader->FontBakedDestroy(atlas, src, baked, backend_user_data_p);
backend_user_data_p += atlas->FontLoader->FontBakedSrcLoaderDataSize;
const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
if (loader->FontBakedDestroy)
loader->FontBakedDestroy(atlas, src, baked, loader_data_p);
loader_data_p += loader->FontBakedSrcLoaderDataSize;
}
if (baked->FontLoaderDatas)
{
@@ -4094,9 +4115,12 @@ void ImFontAtlasBuildDestroy(ImFontAtlas* atlas)
{
for (ImFont* font : atlas->Fonts)
font->ClearOutputData();
if (atlas->FontLoader && atlas->FontLoader->FontSrcDestroy != NULL)
for (ImFontConfig& font_cfg : atlas->Sources)
atlas->FontLoader->FontSrcDestroy(atlas, &font_cfg);
for (ImFontConfig& font_cfg : atlas->Sources)
{
const ImFontLoader* loader = font_cfg.FontLoader ? font_cfg.FontLoader : atlas->FontLoader;
if (loader && loader->FontSrcDestroy != NULL)
loader->FontSrcDestroy(atlas, &font_cfg);
}
IM_DELETE(atlas->Builder);
atlas->Builder = NULL;
@@ -4258,19 +4282,19 @@ ImFontGlyph* ImFontBaked::BuildLoadGlyph(ImWchar codepoint)
ImFontConfig* srcs = (font->LockSingleSrcConfigIdx != -1) ? &font->Sources[font->LockSingleSrcConfigIdx] : font->Sources;
// Call backend
const ImFontLoader* font_loader = atlas->FontLoader;
char* backend_user_data_p = (char*)baked->FontLoaderDatas;
char* loader_user_data_p = (char*)baked->FontLoaderDatas;
for (int src_n = 0; src_n < srcs_count; src_n++)
{
ImFontConfig* src = &srcs[src_n];
const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
if (!src->GlyphExcludeRanges || ImFontAtlasBuildAcceptCodepointForSource(src, codepoint))
if (font_loader->FontBakedAddGlyph(atlas, src, baked, backend_user_data_p, codepoint))
if (loader->FontBakedAddGlyph(atlas, src, baked, loader_user_data_p, codepoint))
{
// FIXME: Add hooks for e.g. #7962
ImFontGlyph* glyph = &baked->Glyphs.back();
return glyph;
}
backend_user_data_p += font_loader->FontBakedSrcLoaderDataSize;
loader_user_data_p += loader->FontBakedSrcLoaderDataSize;
}
// Mark index as not found, so we don't attempt the search twice
@@ -5017,8 +5041,12 @@ bool ImFont::IsGlyphInFont(ImWchar c)
{
ImFontAtlas* atlas = ContainerAtlas;
for (int src_n = 0; src_n < SourcesCount; src_n++)
if (atlas->FontLoader->FontSrcContainsGlyph(atlas, &Sources[src_n], c))
{
ImFontConfig* src = &Sources[src_n];
const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
if (loader->FontSrcContainsGlyph != NULL && loader->FontSrcContainsGlyph(atlas, src, c))
return true;
}
return false;
}