66#include < algorithm>
77#include < cmath>
88#include < cstddef>
9+ #include < memory>
910#include < mutex>
11+ #include < stdexcept>
1012#include < string_view>
1113#include < vector>
1214
@@ -22,15 +24,14 @@ constexpr int kNumGlyphs = kLastChar - kFirstChar + 1;
2224} // namespace
2325
2426GlyphCache::GlyphCache (const unsigned char * ttf_data, unsigned int /* ttf_size*/ )
27+ : font_info_(std::make_unique<stbtt_fontinfo>())
2528{
26- font_info_ = new stbtt_fontinfo;
27- stbtt_InitFont (font_info_, ttf_data, 0 );
29+ if (!stbtt_InitFont (font_info_.get (), ttf_data, 0 )) {
30+ throw std::runtime_error (" Failed to initialize font from TTF data" );
31+ }
2832}
2933
30- GlyphCache::~GlyphCache ()
31- {
32- delete font_info_;
33- }
34+ GlyphCache::~GlyphCache () = default ;
3435
3536const GlyphCache::SizeSlot& GlyphCache::getSlot (int font_height) const
3637{
@@ -41,10 +42,10 @@ const GlyphCache::SizeSlot& GlyphCache::getSlot(int font_height) const
4142 }
4243
4344 SizeSlot& slot = cache_[font_height];
44- slot.scale = stbtt_ScaleForPixelHeight (font_info_, font_height);
45+ slot.scale = stbtt_ScaleForPixelHeight (font_info_. get () , font_height);
4546
4647 int ascent, descent, line_gap;
47- stbtt_GetFontVMetrics (font_info_, &ascent, &descent, &line_gap);
48+ stbtt_GetFontVMetrics (font_info_. get () , &ascent, &descent, &line_gap);
4849 slot.ascent = static_cast <int >(std::round (ascent * slot.scale ));
4950 const int desc_px = static_cast <int >(std::round (descent * slot.scale ));
5051 slot.cell_height = slot.ascent - desc_px;
@@ -67,11 +68,11 @@ const GlyphCache::SizeSlot& GlyphCache::getSlot(int font_height) const
6768 auto & t = temps[i];
6869
6970 int advance_raw, lsb_raw;
70- stbtt_GetCodepointHMetrics (font_info_, cp, &advance_raw, &lsb_raw);
71+ stbtt_GetCodepointHMetrics (font_info_. get () , cp, &advance_raw, &lsb_raw);
7172 t.advance = static_cast <int >(std::round (advance_raw * slot.scale ));
7273
7374 unsigned char * bmp = stbtt_GetCodepointBitmap (
74- font_info_, 0 , slot.scale , cp, &t.gw , &t.gh , &t.xoff , &t.yoff );
75+ font_info_. get () , 0 , slot.scale , cp, &t.gw , &t.gh , &t.xoff , &t.yoff );
7576 if (bmp && t.gw > 0 && t.gh > 0 ) {
7677 const size_t n = static_cast <size_t >(t.gw ) * t.gh ;
7778 t.bitmap .assign (bmp, bmp + n);
@@ -112,64 +113,95 @@ const GlyphCache::SizeSlot& GlyphCache::getSlot(int font_height) const
112113 return slot;
113114}
114115
115- int GlyphCache::textWidth (std::string_view text, int font_height) const
116+ // --- FontSize (lock-free handle) -------------------------------------------
117+
118+ GlyphCache::FontSize::FontSize (const SizeSlot& slot,
119+ const stbtt_fontinfo* font_info)
120+ : slot_(slot), font_info_(font_info)
121+ {
122+ }
123+
124+ GlyphCache::GlyphInfo GlyphCache::FontSize::glyph (char ch) const
125+ {
126+ const int idx = static_cast <unsigned char >(ch) - kFirstChar ;
127+ if (idx < 0 || idx >= kNumGlyphs ) {
128+ return {.alpha = nullptr ,
129+ .bmp_width = 0 ,
130+ .bmp_height = 0 ,
131+ .x_offset = 0 ,
132+ .y_offset = 0 ,
133+ .advance = 0 };
134+ }
135+ const auto & cg = slot_.glyphs [idx];
136+ const unsigned char * alpha_ptr
137+ = cg.bmp_width > 0 ? slot_.alpha .data () + cg.alpha_offset : nullptr ;
138+ return {.alpha = alpha_ptr,
139+ .bmp_width = cg.bmp_width ,
140+ .bmp_height = cg.bmp_height ,
141+ .x_offset = cg.x_offset ,
142+ .y_offset = cg.y_offset ,
143+ .advance = cg.advance };
144+ }
145+
146+ int GlyphCache::FontSize::kern (char ch1, char ch2) const
147+ {
148+ const int raw = stbtt_GetCodepointKernAdvance (font_info_, ch1, ch2);
149+ return static_cast <int >(std::round (raw * slot_.scale ));
150+ }
151+
152+ int GlyphCache::FontSize::textWidth (std::string_view text) const
116153{
117154 if (text.empty ()) {
118155 return 0 ;
119156 }
120- const auto & slot = getSlot (font_height);
121157 int width = 0 ;
122158 for (size_t i = 0 ; i < text.size (); ++i) {
123159 const int idx = static_cast <unsigned char >(text[i]) - kFirstChar ;
124160 if (idx >= 0 && idx < kNumGlyphs ) {
125- width += slot .glyphs [idx].advance ;
161+ width += slot_ .glyphs [idx].advance ;
126162 }
127- // Add kerning with next character.
128163 if (i + 1 < text.size ()) {
129- width += kern (font_height, text[i], text[i + 1 ]);
164+ width += kern (text[i], text[i + 1 ]);
130165 }
131166 }
132167 return width;
133168}
134169
170+ int GlyphCache::FontSize::cellHeight () const
171+ {
172+ return slot_.cell_height ;
173+ }
174+
175+ // --- GlyphCache public API (convenience, locks per call) -------------------
176+
177+ GlyphCache::FontSize GlyphCache::getFont (int font_height) const
178+ {
179+ return FontSize (getSlot (font_height), font_info_.get ());
180+ }
181+
182+ int GlyphCache::textWidth (std::string_view text, int font_height) const
183+ {
184+ return getFont (font_height).textWidth (text);
185+ }
186+
135187int GlyphCache::textHeight (int font_height) const
136188{
137- return getSlot (font_height).cell_height ;
189+ return getFont (font_height).cellHeight () ;
138190}
139191
140192int GlyphCache::cellHeight (int font_height) const
141193{
142- return getSlot (font_height).cell_height ;
194+ return getFont (font_height).cellHeight () ;
143195}
144196
145197GlyphCache::GlyphInfo GlyphCache::glyph (int font_height, char ch) const
146198{
147- const int idx = static_cast <unsigned char >(ch) - kFirstChar ;
148- const auto & slot = getSlot (font_height);
149- if (idx < 0 || idx >= kNumGlyphs ) {
150- return {.alpha = nullptr ,
151- .bmp_width = 0 ,
152- .bmp_height = 0 ,
153- .x_offset = 0 ,
154- .y_offset = 0 ,
155- .advance = 0 };
156- }
157- const auto & cg = slot.glyphs [idx];
158- const unsigned char * alpha_ptr
159- = cg.bmp_width > 0 ? slot.alpha .data () + cg.alpha_offset : nullptr ;
160- return {.alpha = alpha_ptr,
161- .bmp_width = cg.bmp_width ,
162- .bmp_height = cg.bmp_height ,
163- .x_offset = cg.x_offset ,
164- .y_offset = cg.y_offset ,
165- .advance = cg.advance };
199+ return getFont (font_height).glyph (ch);
166200}
167201
168202int GlyphCache::kern (int font_height, char ch1, char ch2) const
169203{
170- const auto & slot = getSlot (font_height);
171- const int raw = stbtt_GetCodepointKernAdvance (font_info_, ch1, ch2);
172- return static_cast <int >(std::round (raw * slot.scale ));
204+ return getFont (font_height).kern (ch1, ch2);
173205}
174206
175207const GlyphCache& glyphCache ()
0 commit comments