From 60072360e1e01ac0134def097f606c528c4f8e49 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 21 Apr 2026 16:05:48 +0300 Subject: [PATCH] sokol: fix gg.draw_text text corruption with font size and long string on mac (fixes #20457) --- vlib/gg/text_rendering.c.v | 40 +++++++++++++++++++++++++++-------- vlib/gg/text_rendering_test.v | 24 +++++++++++++++++++-- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/vlib/gg/text_rendering.c.v b/vlib/gg/text_rendering.c.v index f77b9cbb6..98ba6aab2 100644 --- a/vlib/gg/text_rendering.c.v +++ b/vlib/gg/text_rendering.c.v @@ -33,19 +33,41 @@ pub enum VerticalAlign { baseline = C.FONS_ALIGN_BASELINE } -const buff_size = int($d('gg_text_buff_size', 2048)) +const initial_text_atlas_size = int($d('gg_text_buff_size', 2048)) +const max_text_atlas_size = 8192 -fn clear_atlas_callback(uptr voidptr, error int, _val int) { - if error == 1 { // atlas overflow error code - fons := unsafe { &fontstash.Context(uptr) } - fons.reset_atlas(buff_size, buff_size) +fn expand_atlas_callback(uptr voidptr, error int, _val int) { + if error != C.FONS_ATLAS_FULL { + return + } + fons := unsafe { &fontstash.Context(uptr) } + width, height := fons.get_atlas_size() + mut next_width := if width > 0 { width } else { initial_text_atlas_size } + mut next_height := if height > 0 { height } else { initial_text_atlas_size } + if next_width < max_text_atlas_size { + next_width = if next_width * 2 > max_text_atlas_size { + max_text_atlas_size + } else { + next_width * 2 + } + } + if next_height < max_text_atlas_size { + next_height = if next_height * 2 > max_text_atlas_size { + max_text_atlas_size + } else { + next_height * 2 + } + } + if next_width == width && next_height == height { + return } + fons.expand_atlas(next_width, next_height) } fn new_ft(c FTConfig) ?&FT { if c.font_path == '' { if c.bytes_normal.len > 0 { - fons := sfons.create(buff_size, buff_size, 1) + fons := sfons.create(initial_text_atlas_size, initial_text_atlas_size, 1) bytes_normal := c.bytes_normal bytes_bold := if c.bytes_bold.len > 0 { c.bytes_bold @@ -65,7 +87,7 @@ fn new_ft(c FTConfig) ?&FT { debug_font_println('setting italic variant to normal') bytes_normal } - fons.set_error_callback(clear_atlas_callback, fons) + fons.set_error_callback(expand_atlas_callback, fons) return &FT{ fons: fons font_normal: fons.add_font_mem('sans', bytes_normal.clone(), true) @@ -126,12 +148,12 @@ fn new_ft(c FTConfig) ?&FT { italic_path = c.font_path bytes } - fons := sfons.create(buff_size, buff_size, 1) + fons := sfons.create(initial_text_atlas_size, initial_text_atlas_size, 1) debug_font_println('Font used for font_normal : ${normal_path}') debug_font_println('Font used for font_bold : ${bold_path}') debug_font_println('Font used for font_mono : ${mono_path}') debug_font_println('Font used for font_italic : ${italic_path}') - fons.set_error_callback(clear_atlas_callback, fons) + fons.set_error_callback(expand_atlas_callback, fons) return &FT{ fons: fons font_normal: fons.add_font_mem('sans', bytes.clone(), true) diff --git a/vlib/gg/text_rendering_test.v b/vlib/gg/text_rendering_test.v index ab841162a..8ae348cfa 100644 --- a/vlib/gg/text_rendering_test.v +++ b/vlib/gg/text_rendering_test.v @@ -5,9 +5,13 @@ import fontstash const embedded_test_mono_font = $embed_file('@VEXEROOT/examples/assets/fonts/RobotoMono-Regular.ttf') fn new_test_text_context() (&Context, &fontstash.Context) { + return new_test_text_context_with_atlas(512, 512) +} + +fn new_test_text_context_with_atlas(width int, height int) (&Context, &fontstash.Context) { mut fons := fontstash.create_internal(&C.FONSparams{ - width: 512 - height: 512 + width: width + height: height flags: 0 }) assert fons != unsafe { nil } @@ -15,6 +19,7 @@ fn new_test_text_context() (&Context, &fontstash.Context) { assert font_id != fontstash.invalid fons.set_font(font_id) fons.set_size(16) + fons.set_error_callback(expand_atlas_callback, fons) return &Context{ ft: &FT{ fons: fons @@ -57,3 +62,18 @@ fn test_text_width_counts_trailing_space_advance() { width, _ := ctx.text_size('a ') assert width == int(advance / ctx.scale) } + +fn test_text_atlas_expands_on_overflow() { + _, fons := new_test_text_context_with_atlas(64, 64) + defer { + fontstash.delete_internal(fons) + } + before_width, before_height := fons.get_atlas_size() + mut bounds := [4]f32{} + for size in [48, 64, 80] { + fons.set_size(size) + _ = fons.text_bounds(0, 0, 'Some very long text here 0123456789', &bounds[0]) + } + after_width, after_height := fons.get_atlas_size() + assert after_width > before_width || after_height > before_height +} -- 2.39.5