Browse Source

Fonts: added ImFontAtlas::RemoveFont(), fixed various leaks.

ocornut 8 months ago
parent
commit
cec3e945f0
4 changed files with 84 additions and 6 deletions
  1. 6 0
      imgui.cpp
  2. 3 2
      imgui.h
  3. 74 4
      imgui_draw.cpp
  4. 1 0
      imgui_internal.h

+ 6 - 0
imgui.cpp

@@ -16484,6 +16484,12 @@ void ImGui::DebugNodeFont(ImFont* font)
     }
     if (SmallButton("Set as default"))
         GetIO().FontDefault = font;
+    if (font->ContainerAtlas->Fonts.Size > 1 && !font->ContainerAtlas->Locked)
+    {
+        SameLine();
+        if (SmallButton("Remove"))
+            font->ContainerAtlas->RemoveFont(font);
+    }
 
     // Display details
     SetNextItemWidth(GetFontSize() * 8);

+ 3 - 2
imgui.h

@@ -3521,10 +3521,11 @@ struct ImFontAtlas
     IMGUI_API ImFont*           AddFontFromMemoryTTF(void* font_data, int font_data_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted after destruction of the atlas. Set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed.
     IMGUI_API ImFont*           AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_data_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp.
     IMGUI_API ImFont*           AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL);              // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter.
+    IMGUI_API void              RemoveFont(ImFont* font);
 
     // FIXME-NEWATLAS: Clarify meaning/purpose
-    IMGUI_API void              Clear();                    // Clear all input and output.
-    IMGUI_API void              ClearCache();               // Clear cached glyphs
+    IMGUI_API void              Clear();                    // Clear everything (input fonts, output glyphs/textures)
+    IMGUI_API void              ClearCache();               // Clear cached glyphs and textures.
     // As we are transitioning toward a new font system, we expect to obsolete those soon:
     IMGUI_API void              ClearInputData();           // [OBSOLETE] Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts.
     IMGUI_API void              ClearFonts();               // [OBSOLETE] Clear input+output font data (same as ClearInputData() + glyphs storage, UV coordinates).

+ 74 - 4
imgui_draw.cpp

@@ -2476,6 +2476,8 @@ void ImTextureData::DestroyPixels()
 // - ImFontAtlas::AddFontFromMemoryTTF()
 // - ImFontAtlas::AddFontFromMemoryCompressedTTF()
 // - ImFontAtlas::AddFontFromMemoryCompressedBase85TTF()
+// - ImFontAtlas::RemoveFont()
+// - ImFontAtlasBuildNotifySetFont()
 //-----------------------------------------------------------------------------
 // - ImFontAtlas::AddCustomRectRegular()
 // - ImFontAtlas::AddCustomRectFontGlyph()
@@ -2593,11 +2595,15 @@ 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);
         if (font_cfg.FontData && font_cfg.FontDataOwnedByAtlas)
         {
             IM_FREE(font_cfg.FontData);
             font_cfg.FontData = NULL;
         }
+    }
 
     // When clearing this we lose access to the font name and other information used to build the font.
     for (ImFont* font : Fonts)
@@ -2641,12 +2647,12 @@ void ImFontAtlas::ClearFonts()
 void ImFontAtlas::Clear()
 {
     //IM_DELETE(Builder); // FIXME-NEW-ATLAS: Clarify ClearXXX functions
-    const ImFontLoader* font_loader = FontLoader;
-    ImFontAtlasBuildSetupFontLoader(this, NULL);
+    //const ImFontLoader* font_loader = FontLoader;
+    //ImFontAtlasBuildSetupFontLoader(this, NULL);
     ClearInputData();
     ClearTexData();
     ClearFonts();
-    ImFontAtlasBuildSetupFontLoader(this, font_loader);
+    //ImFontAtlasBuildSetupFontLoader(this, font_loader);
 }
 
 // FIXME-NEWATLAS: Too widespread purpose. Clarify each call site in current WIP demo.
@@ -3041,6 +3047,59 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed
     return font;
 }
 
+// We allow old_font == new_font which forces updating all values (e.g. sizes)
+static void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font, ImFont* new_font)
+{
+    if (ImDrawListSharedData* shared_data = atlas->DrawListSharedData)
+    {
+        if (shared_data->Font == old_font)
+            shared_data->Font = new_font;
+        if (ImGuiContext* ctx = shared_data->Context)
+        {
+            if (ctx->IO.FontDefault == old_font)
+                ctx->IO.FontDefault = new_font;
+            if (ctx->Font == old_font)
+            {
+                ImGuiContext* curr_ctx = ImGui::GetCurrentContext();
+                bool need_bind_ctx = ctx != curr_ctx;
+                if (need_bind_ctx)
+                    ImGui::SetCurrentContext(ctx);
+                ImGui::SetCurrentFont(new_font);
+                if (need_bind_ctx)
+                    ImGui::SetCurrentContext(curr_ctx);
+            }
+        }
+    }
+}
+
+void ImFontAtlas::RemoveFont(ImFont* font)
+{
+    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
+    ImFontAtlasBuildDiscardFontGlyphs(this, 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);
+        if (src->FontData != NULL && src->FontDataOwnedByAtlas)
+            IM_FREE(src->FontData);
+    }
+
+    bool removed = Fonts.find_erase(font);
+    IM_ASSERT(removed);
+
+    Sources.erase(font->Sources, font->Sources + font->SourcesCount);
+    ImFontAtlasBuildUpdatePointers(this);
+
+    font->ContainerAtlas = NULL;
+    IM_DELETE(font);
+
+    // Notify external systems
+    ImFont* new_current_font = Fonts.empty() ? NULL : Fonts[0];
+    ImFontAtlasBuildNotifySetFont(this, font, new_current_font);
+}
+
 // FIXME-NEWATLAS-V1: Feature is broken for now.
 /*
     // Register custom rectangle glyphs
@@ -3485,13 +3544,19 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* sr
     font->LockSingleSrcConfigIdx = -1;
 }
 
-void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font)
+void ImFontAtlasBuildDiscardFontGlyphs(ImFontAtlas* atlas, ImFont* font)
 {
     for (ImFontGlyph& glyph : font->Glyphs)
         if (glyph.PackId >= 0)
             ImFontAtlasPackDiscardRect(atlas, glyph.PackId);
     font->BuildClearGlyphs();
+    font->FallbackChar = font->EllipsisChar = 0;
+}
 
+// Discard old glyphs and reload font. Use if changing font size.
+void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font)
+{
+    ImFontAtlasBuildDiscardFontGlyphs(atlas, font);
     for (int src_n = 0; src_n < font->SourcesCount; src_n++)
     {
         ImFontConfig* src = (ImFontConfig*)(void*)&font->Sources[src_n];
@@ -3505,6 +3570,9 @@ void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font)
 
         ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, src); // Technically this is called for each source sub-font, tho 99.9% of the time the first one fills everything.
     }
+
+    // Notify external systems
+    ImFontAtlasBuildNotifySetFont(atlas, font, font);
 }
 
 // Those functions are designed to facilitate changing the underlying structures for ImFontAtlas to store an array of ImDrawListSharedData*
@@ -4023,11 +4091,13 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig*
     const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)src->FontData, src->FontNo);
     if (font_offset < 0)
     {
+        IM_DELETE(bd_font_data);
         IM_ASSERT_USER_ERROR(0, "stbtt_GetFontOffsetForIndex(): FontData is incorrect, or FontNo cannot be found.");
         return false;
     }
     if (!stbtt_InitFont(&bd_font_data->FontInfo, (unsigned char*)src->FontData, font_offset))
     {
+        IM_DELETE(bd_font_data);
         IM_ASSERT_USER_ERROR(0, "stbtt_InitFont(): failed to parse FontData. It is correct and complete? Check FontDataSize.");
         return false;
     }

+ 1 - 0
imgui_internal.h

@@ -3717,6 +3717,7 @@ IMGUI_API ImVec2i           ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas*
 
 IMGUI_API bool              ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src);
 IMGUI_API void              ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* src);
+IMGUI_API void              ImFontAtlasBuildDiscardFontGlyphs(ImFontAtlas* atlas, ImFont* font);
 IMGUI_API void              ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font);
 IMGUI_API void              ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy
 IMGUI_API void              ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, int* out_oversample_h, int* out_oversample_v);