Summary
Add an opt-in ImGuiFreeType::RenderShapedText API, guarded by IMGUI_ENABLE_HARFBUZZ_SHAPING, that shapes a text cluster with HarfBuzz and renders the resulting (possibly ligature) glyphs. This forms GSUB ligatures -- ZWJ families (U+1F468 U+200D U+1F469 ... -> 👨👩👧👦) and regional-indicator flags (U+1F1EB U+1F1F7 -> 🇫🇷) -- that ImFont::RenderText cannot, because RenderText is codepoint-by-codepoint and never consults the font's GSUB table.
Why opt-in, not in RenderText
Text shaping is a historically sensitive topic (see #3903, #6186, etc.). This PR takes the least intrusive approach: a separate RenderShapedText function that renderers needing ligatures call explicitly. The existing RenderText hot path is untouched -- zero risk for the standard text rendering path. Consumers that don't call RenderShapedText see no change.
What (all in misc/freetype/imgui_freetype.cpp + .h, guarded by IMGUI_ENABLE_HARFBUZZ_SHAPING)
- An
hb_font_t*perFT_Face(hb_ft_font_createinInitFont, destroyed inCloseFont). - A per-(src,baked) shaped-glyph cache (
ImVector<ImFontGlyph>+ImGuiStorageglyph-index -> cache slot) for ligature glyphs that have no Unicode codepoint and so cannot live inImFontBaked's codepoint-indexedGlyphs/IndexLookuptables. ImGui_ImplFreeType_BakeGlyphByID: bake a glyph by its FT glyph index (skippingFT_Get_Char_Index) on demand, pack+blit into the atlas, set UVs/Colored, cache it.ImGuiFreeType::RenderShapedText:hb_shapethe cluster, then for each shaped glyph bake-by-ID and emit a quad with the shaped advance, mirroringRenderText's mid-frame texture-growth retry (cmd_count/goto begin).
The shaped-glyph cache lives in FontSrcBakedData (the FreeType backend's per-baked storage), not in the public ImFontBaked struct -- so no public struct ABI change.
Build
IMGUI_ENABLE_HARFBUZZ_SHAPING requires HarfBuzz headers + lib to be available when defined. imgui itself doesn't add a build-system target for HarfBuzz (imgui ships as sources); the consumer's build system links HarfBuzz when the flag is set (e.g. the cimgui-pack CMake option, see the companion PR JuliaImGui/cimgui-pack#20). When the flag is not defined, the shaping code is absent and the build is identical to today's FreeType builder.
Verification
Compiled with and without IMGUI_ENABLE_HARFBUZZ_SHAPING (clang, FreeType 2.13/2.14 + HarfBuzz 8.5/14.3):
- with:
imgui_freetype.cppcompiles,RenderShapedTextsymbol present; - without: identical object to the current FreeType builder (shaping code excluded by the guard).
A downstream TUI cell-grid renderer (ManyUI / ManyUICImGui, ImGui 1.92 docking via cimgui-pack, with the companion FreeType option PR) renders 👨👩👧👦 as a single family ligature and 🇫🇷 as a single flag glyph using RenderShapedText, where AddText (codepoint-by-codepoint) renders them as 4 separate people / "FR" letters.
Companion PRs:
- ocornut/imgui#9517 -- FreeType color glyph (BGRA) fix (independent, complementary: that PR fixes color rendering, this PR adds shaping).
- JuliaImGui/cimgui-pack#20 -- CMake option
CIMGUI_ENABLE_FREETYPE+IMGUI_USE_WCHAR32(the build-side enablement).
AI-assisted.