From 7263a23f1beab16c72b4a72a036fd822313cfc4e Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 30 Sep 2026 18:41:31 +0200 Subject: [PATCH] Fonts: added ImFont::AddRemapCodepointToGlyphIndex(). (#9559, #5647, #609, #5748, #8466) --- imgui.h | 5 ++-- imgui_draw.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 60 insertions(+), 13 deletions(-) diff --git a/imgui.h b/imgui.h index 174660964..8c5be4a44 100644 --- a/imgui.h +++ b/imgui.h @@ -3967,7 +3967,7 @@ struct ImFont ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 17 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 8K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. bool EllipsisAutoBake; // 1 // // Mark when the "..." glyph (== EllipsisChar) needs to be generated by combining multiple '.'. - ImGuiStorage RemapPairs; // 16 // // Remapping pairs when using AddRemapCodepoint(), otherwise empty. + ImGuiStorage RemapPairs; // 16 // // Remapping pairs when using AddRemapCodepointXXX(). #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS float Scale; // 4 // in // Legacy base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() #endif @@ -3994,8 +3994,9 @@ struct ImFont // [Internal] Don't use! IMGUI_API void ClearOutputData(); IMGUI_API void AddRemapCodepoint(ImWchar from_codepoint, ImWchar to_codepoint); // Makes 'from_codepoint' character points to 'to_codepoint' glyph. + IMGUI_API void AddRemapCodepointToGlyphIndex(ImWchar from_codepoint, int font_src_idx, int glyph_idx); IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); - //inline void AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint) { AddRemapCodepointToCodepoint(from_codepoint, to_codepoint); } // Renamed in 1.93.0 (Oct 2026) + //inline void AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint) { AddRemapCodepoint(from_codepoint, to_codepoint); } // Renamed in 1.93.0 (Sep 2026) }; // This is provided for consistency (but we don't actually use this) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e2dd1f701..e2085f6e6 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4565,14 +4565,43 @@ static void ImFontBaked_BuildGrowIndex(ImFontBaked* baked, int new_size) // Remap a codepoint to another codepoint void ImFont::AddRemapCodepoint(ImWchar from_codepoint, ImWchar to_codepoint) { - RemapPairs.SetInt((ImGuiID)from_codepoint, (int)to_codepoint); + ImU32 data = (ImU32)to_codepoint; + IM_ASSERT((data & (1u << 31)) == 0); + RemapPairs.SetInt((ImGuiID)from_codepoint, (int)data); } -static void ImFontAtlas_FontHookRemapCodepoint(ImFontAtlas* atlas, ImFont* font, ImWchar* c) +static const int IMFONT_REMAPVALUE_GLYPHIDX_SHIFT = 0; +static const int IMFONT_REMAPVALUE_GLYPHIDX_MASK = 0xFFFF; +static const int IMFONT_REMAPVALUE_FONTSRCIDX_SHIFT = 16; +static const int IMFONT_REMAPVALUE_FONTSRCIDX_MASK = 0xFF0000; + +// Remap a codepoint to a raw glyph index inside the font. Allows accessing glyphs which are not mapped to codepoints. (#9559) +// font_src_idx = index in font->Sources[], or -1 for last added source. +// glyph_idx = index in TTF or OTF file. +void ImFont::AddRemapCodepointToGlyphIndex(ImWchar from_codepoint, int font_src_idx, int glyph_idx) +{ + if (font_src_idx == -1) + font_src_idx = Sources.Size - 1; + IM_ASSERT(font_src_idx >= 0 && font_src_idx < Sources.Size && ((font_src_idx << IMFONT_REMAPVALUE_FONTSRCIDX_SHIFT) & ~IMFONT_REMAPVALUE_FONTSRCIDX_MASK) == 0); + IM_ASSERT(glyph_idx >= 0 && ((glyph_idx << IMFONT_REMAPVALUE_GLYPHIDX_SHIFT) & ~IMFONT_REMAPVALUE_GLYPHIDX_MASK) == 0); + ImU32 data = ((ImU32)glyph_idx << IMFONT_REMAPVALUE_GLYPHIDX_SHIFT) | (font_src_idx << IMFONT_REMAPVALUE_FONTSRCIDX_SHIFT) | (1u << 31); + RemapPairs.SetInt((ImGuiID)from_codepoint, (int)data); +} + +static void ImFontAtlas_FontHookRemapCodepoint(ImFontAtlas* atlas, ImFont* font, ImWchar codepoint, ImWchar* out_codepoint, int* out_font_src_idx, int* out_glyph_idx) { IM_UNUSED(atlas); - if (font->RemapPairs.Data.Size != 0) - *c = (ImWchar)font->RemapPairs.GetInt((ImGuiID)*c, (int)*c); + if (font->RemapPairs.Data.Size == 0) + return; + ImU32 data = (ImU32)font->RemapPairs.GetInt((ImGuiID)codepoint, (int)codepoint); + if (data & (1u << 31)) + { + *out_codepoint = (ImWchar)-1; + *out_font_src_idx = (data & IMFONT_REMAPVALUE_FONTSRCIDX_MASK) >> IMFONT_REMAPVALUE_FONTSRCIDX_SHIFT; + *out_glyph_idx = (data & IMFONT_REMAPVALUE_GLYPHIDX_MASK) >> IMFONT_REMAPVALUE_GLYPHIDX_SHIFT; + return; + } + *out_codepoint = (ImWchar)data; } static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codepoint, float* only_load_advance_x) @@ -4589,7 +4618,8 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep // User remapping hooks ImWchar src_codepoint = codepoint; - ImFontAtlas_FontHookRemapCodepoint(atlas, font, &codepoint); + int src_font_idx = -1, src_glyph_idx = -1; + ImFontAtlas_FontHookRemapCodepoint(atlas, font, codepoint, &src_codepoint, &src_font_idx, &src_glyph_idx); //char utf8_buf[5]; //IMGUI_DEBUG_LOG("[font] BuildLoadGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint)); @@ -4609,10 +4639,19 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; loader_user_data_p_next = loader_user_data_p + loader->FontBakedSrcLoaderDataSize; - if (src->GlyphExcludeRanges && !ImFontAtlasBuildAcceptCodepointForSource(src, codepoint)) - continue; - - int glyph_index = loader->FontSrcGetGlyphIndexFromCodepoint(atlas, src, codepoint); + int glyph_index; + if (src_codepoint != (ImWchar)-1) + { + if (src->GlyphExcludeRanges && !ImFontAtlasBuildAcceptCodepointForSource(src, src_codepoint)) + continue; + glyph_index = loader->FontSrcGetGlyphIndexFromCodepoint(atlas, src, src_codepoint); + } + else + { + if (src_n != src_font_idx) + continue; + glyph_index = src_glyph_idx; + } if (glyph_index == 0) continue; @@ -4623,7 +4662,6 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep 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; glyph_buf.SourceIdx = src_n; return ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph_buf); } @@ -5401,7 +5439,15 @@ bool ImFontBaked::IsGlyphLoaded(ImWchar c) bool ImFont::IsGlyphInFont(ImWchar c) { ImFontAtlas* atlas = OwnerAtlas; - ImFontAtlas_FontHookRemapCodepoint(atlas, this, &c); + ImWchar src_codepoint = c; + int src_font_idx = -1, src_glyph_idx = -1; + ImFontAtlas_FontHookRemapCodepoint(atlas, this, c, &src_codepoint, &src_font_idx, &src_glyph_idx); + if (src_font_idx != -1) + { + ImFontConfig* src = Sources[src_font_idx]; + const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + return loader->FontSrcContainsGlyph ? loader->FontSrcContainsGlyph(atlas, src, src_glyph_idx) : false; + } for (ImFontConfig* src : Sources) { const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;