diff --git a/misc/freetype/README.md b/misc/freetype/README.md index 885451a4..156e6511 100644 --- a/misc/freetype/README.md +++ b/misc/freetype/README.md @@ -121,6 +121,5 @@ struct FreeTypeTest ``` ### Known issues -- FreeType's memory allocator is not overridden. - `cfg.OversampleH`, `OversampleV` are ignored (but perhaps not so necessary with this rasterizer). diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 7c5403b6..814f506a 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -18,7 +18,6 @@ // For correct results you need to be using sRGB and convert to linear space in the pixel shader output. // The default imgui styles will be impacted by this change (alpha values will need tweaking). -// FIXME: FreeType's memory allocator is not overridden. // FIXME: cfg.OversampleH, OversampleV are not supported (but perhaps not so necessary with this rasterizer). #include "imgui_freetype.h" @@ -26,6 +25,7 @@ #include #include #include FT_FREETYPE_H // +#include FT_MODULE_H // #include FT_GLYPH_H // #include FT_SYNTHESIS_H // @@ -115,7 +115,6 @@ namespace bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags) { - // FIXME: substitute allocator FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &Face); if (error != 0) return false; @@ -566,15 +565,77 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns return true; } +static void* ImFreeTypeDefaultAllocFunc(size_t size, void* user_data) { (void)user_data; return ImGui::MemAlloc(size); } +static void ImFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { (void)user_data; ImGui::MemFree(ptr); } + +static void* (*GImFreeTypeAllocFunc)(size_t size, void* user_data) = ImFreeTypeDefaultAllocFunc; +static void (*GImFreeTypeFreeFunc)(void* ptr, void* user_data) = ImFreeTypeDefaultFreeFunc; +static void* GImFreeTypeAllocatorUserData = NULL; + +static void* FreeType_Alloc(FT_Memory memory, long size) +{ + (void)memory; + return GImFreeTypeAllocFunc(size, GImFreeTypeAllocatorUserData); +} + +static void FreeType_Free(FT_Memory memory, void* block) +{ + (void)memory; + GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData); +} + +static void* FreeType_Realloc(FT_Memory memory, long cur_size, long new_size, void* block) +{ + // Implement realloc() as we don't ask user to provide it. + + (void)memory; + + if (!block) + return GImFreeTypeAllocFunc(new_size, GImFreeTypeAllocatorUserData); + + if (new_size == 0) + { + GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData); + return nullptr; + } + + if (new_size > cur_size) + { + void* new_block = GImFreeTypeAllocFunc(new_size, GImFreeTypeAllocatorUserData); + memcpy(new_block, block, cur_size); + GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData); + block = new_block; + } + + return block; +} + bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags) { + // FreeType memory management: https://www.freetype.org/freetype2/docs/design/design-4.html + FT_MemoryRec_ memoryRec = {0}; + memoryRec.alloc = &FreeType_Alloc; + memoryRec.free = &FreeType_Free; + memoryRec.realloc = &FreeType_Realloc; + + // https://www.freetype.org/freetype2/docs/reference/ft2-module_management.html#FT_New_Library FT_Library ft_library; - FT_Error error = FT_Init_FreeType(&ft_library); + FT_Error error = FT_New_Library(&memoryRec, &ft_library); if (error != 0) return false; + // NB: If you don't call FT_Add_Default_Modules() the rest of code may work, but FreeType won't use our custom allocator. + FT_Add_Default_Modules(ft_library); + bool ret = ImFontAtlasBuildWithFreeType(ft_library, atlas, extra_flags); - FT_Done_FreeType(ft_library); + FT_Done_Library(ft_library); return ret; } + +void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data) +{ + GImFreeTypeAllocFunc = alloc_func; + GImFreeTypeFreeFunc = free_func; + GImFreeTypeAllocatorUserData = user_data; +} \ No newline at end of file diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h index aa0aba63..90f4b94c 100644 --- a/misc/freetype/imgui_freetype.h +++ b/misc/freetype/imgui_freetype.h @@ -28,4 +28,8 @@ namespace ImGuiFreeType }; IMGUI_API bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags = 0); + + // FreeType does lots of allocations so user might want to provide separate memory heap. + // By default ImGuiFreeType will use ImGui::MemAlloc()/MemFree(). + IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data = NULL); }