1 /**
2 * @file lv_tiny_ttf.c
3 *
4 */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "../../lvgl.h"
10 
11 #if LV_USE_TINY_TTF != 0
12 #include "../../core/lv_global.h"
13 
14 #define font_draw_buf_handlers &(LV_GLOBAL_DEFAULT()->font_draw_buf_handlers)
15 
16 /*********************
17  *      DEFINES
18  *********************/
19 
20 #define STB_RECT_PACK_IMPLEMENTATION
21 #define STBRP_STATIC
22 #define STBTT_STATIC
23 #define STB_TRUETYPE_IMPLEMENTATION
24 #define STBTT_HEAP_FACTOR_SIZE_32 50
25 #define STBTT_HEAP_FACTOR_SIZE_128 20
26 #define STBTT_HEAP_FACTOR_SIZE_DEFAULT 10
27 #define STBTT_malloc(x, u) ((void)(u), lv_malloc(x))
28 #define STBTT_free(x, u) ((void)(u), lv_free(x))
29 
30 #if LV_TINY_TTF_FILE_SUPPORT != 0
31 /* for stream support */
32 #define STBTT_STREAM_TYPE ttf_cb_stream_t *
33 #define STBTT_STREAM_SEEK(s, x) ttf_cb_stream_seek(s, x);
34 #define STBTT_STREAM_READ(s, x, y) ttf_cb_stream_read(s, x, y);
35 
36 /* a hydra stream that can be in memory or from a file*/
37 typedef struct ttf_cb_stream {
38     lv_fs_file_t * file;
39     const void * data;
40     size_t size;
41     size_t position;
42 } ttf_cb_stream_t;
43 
44 static void ttf_cb_stream_read(ttf_cb_stream_t * stream, void * data, size_t to_read);
45 static void ttf_cb_stream_seek(ttf_cb_stream_t * stream, size_t position);
46 #endif
47 
48 #include "stb_rect_pack.h"
49 #include "stb_truetype_htcw.h"
50 
51 /**********************
52  *      TYPEDEFS
53  **********************/
54 
55 typedef struct ttf_font_desc {
56     lv_fs_file_t file;
57 #if LV_TINY_TTF_FILE_SUPPORT != 0
58     ttf_cb_stream_t stream;
59 #else
60     const uint8_t * stream;
61 #endif
62     stbtt_fontinfo info;
63     float scale;
64     int ascent;
65     int descent;
66 
67     lv_font_kerning_t kerning;
68 
69     int cache_size;
70     lv_cache_t * glyph_cache;
71     lv_cache_t * draw_data_cache;
72 } ttf_font_desc_t;
73 
74 typedef struct _tiny_ttf_glyph_cache_data_t {
75     uint32_t unicode;
76     int adv_w;
77     lv_font_glyph_dsc_t glyph_dsc;
78 } tiny_ttf_glyph_cache_data_t;
79 
80 typedef struct _lv_tiny_ttf_cache_data_t {
81     uint32_t glyph_index;
82     uint32_t size;
83     lv_draw_buf_t * draw_buf;
84 } tiny_ttf_cache_data_t;
85 /**********************
86  *  STATIC PROTOTYPES
87  **********************/
88 static bool ttf_get_glyph_dsc_cb(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter,
89                                  uint32_t unicode_letter_next);
90 static const void * ttf_get_glyph_bitmap_cb(lv_font_glyph_dsc_t * g_dsc, lv_draw_buf_t * draw_buf);
91 static void ttf_release_glyph_cb(const lv_font_t * font, lv_font_glyph_dsc_t * g_dsc);
92 static lv_font_t * lv_tiny_ttf_create(const char * path, const void * data, size_t data_size,
93                                       int32_t font_size, lv_font_kerning_t kerning,
94                                       size_t cache_size);
95 
96 static bool tiny_ttf_glyph_cache_create_cb(tiny_ttf_glyph_cache_data_t * node, void * user_data);
97 static void tiny_ttf_glyph_cache_free_cb(tiny_ttf_glyph_cache_data_t * node, void * user_data);
98 static lv_cache_compare_res_t tiny_ttf_glyph_cache_compare_cb(const tiny_ttf_glyph_cache_data_t * lhs,
99                                                               const tiny_ttf_glyph_cache_data_t * rhs);
100 
101 static bool tiny_ttf_draw_data_cache_create_cb(tiny_ttf_cache_data_t * node, void * user_data);
102 static void tiny_ttf_draw_data_cache_free_cb(tiny_ttf_cache_data_t * node, void * user_data);
103 static lv_cache_compare_res_t tiny_ttf_draw_data_cache_compare_cb(const tiny_ttf_cache_data_t * lhs,
104                                                                   const tiny_ttf_cache_data_t * rhs);
105 
106 static void lv_tiny_ttf_cache_create(ttf_font_desc_t * dsc);
107 /**********************
108  *  GLOBAL VARIABLES
109  **********************/
110 
111 /**********************
112  *  STATIC VARIABLES
113  **********************/
114 
115 /**********************
116  *      MACROS
117  **********************/
118 
119 /**********************
120  *   GLOBAL FUNCTIONS
121  **********************/
122 
lv_tiny_ttf_set_size(lv_font_t * font,int32_t font_size)123 void lv_tiny_ttf_set_size(lv_font_t * font, int32_t font_size)
124 {
125     if(font_size <= 0) {
126         LV_LOG_ERROR("invalid font size: %"LV_PRIx32, font_size);
127         return;
128     }
129     ttf_font_desc_t * dsc = (ttf_font_desc_t *)font->dsc;
130     dsc->scale = stbtt_ScaleForMappingEmToPixels(&dsc->info, font_size);
131     int line_gap = 0;
132     stbtt_GetFontVMetrics(&dsc->info, &dsc->ascent, &dsc->descent, &line_gap);
133     font->line_height = (int32_t)(dsc->scale * (dsc->ascent - dsc->descent + line_gap));
134     font->base_line = (int32_t)(dsc->scale * (line_gap - dsc->descent));
135 
136     /* size change means cache needs to be invalidated. */
137 
138     if(dsc->glyph_cache) {
139         lv_cache_destroy(dsc->glyph_cache, NULL);
140         dsc->glyph_cache = NULL;
141     }
142 
143     if(dsc->draw_data_cache) {
144         lv_cache_destroy(dsc->draw_data_cache, NULL);
145         dsc->draw_data_cache = NULL;
146     }
147 
148     lv_tiny_ttf_cache_create(dsc);
149 }
150 
lv_tiny_ttf_destroy(lv_font_t * font)151 void lv_tiny_ttf_destroy(lv_font_t * font)
152 {
153     LV_ASSERT_NULL(font);
154 
155     if(font->dsc != NULL) {
156         ttf_font_desc_t * ttf = (ttf_font_desc_t *)font->dsc;
157 #if LV_TINY_TTF_FILE_SUPPORT != 0
158         if(ttf->stream.file != NULL) {
159             lv_fs_close(&ttf->file);
160         }
161 #endif
162         lv_cache_destroy(ttf->glyph_cache, NULL);
163         lv_cache_destroy(ttf->draw_data_cache, NULL);
164         lv_free(ttf);
165         font->dsc = NULL;
166     }
167 
168     lv_free(font);
169 }
170 
171 /**********************
172  *   STATIC FUNCTIONS
173  **********************/
174 
175 #if LV_TINY_TTF_FILE_SUPPORT != 0
ttf_cb_stream_read(ttf_cb_stream_t * stream,void * data,size_t to_read)176 static void ttf_cb_stream_read(ttf_cb_stream_t * stream, void * data, size_t to_read)
177 {
178     if(stream->file != NULL) {
179         uint32_t br;
180         lv_fs_read(stream->file, data, to_read, &br);
181     }
182     else {
183         if(to_read + stream->position >= stream->size) {
184             to_read = stream->size - stream->position;
185         }
186         memcpy(data, ((const unsigned char *)stream->data + stream->position), to_read);
187         stream->position += to_read;
188     }
189 }
ttf_cb_stream_seek(ttf_cb_stream_t * stream,size_t position)190 static void ttf_cb_stream_seek(ttf_cb_stream_t * stream, size_t position)
191 {
192     if(stream->file != NULL) {
193         lv_fs_seek(stream->file, position, LV_FS_SEEK_SET);
194     }
195     else {
196         if(position > stream->size) {
197             stream->position = stream->size;
198         }
199         else {
200             stream->position = position;
201         }
202     }
203 }
204 #endif
205 
ttf_get_glyph_dsc_cb(const lv_font_t * font,lv_font_glyph_dsc_t * dsc_out,uint32_t unicode_letter,uint32_t unicode_letter_next)206 static bool ttf_get_glyph_dsc_cb(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter,
207                                  uint32_t unicode_letter_next)
208 {
209     if(unicode_letter < 0x20 ||
210        unicode_letter == 0xf8ff || /*LV_SYMBOL_DUMMY*/
211        unicode_letter == 0x200c) { /*ZERO WIDTH NON-JOINER*/
212         dsc_out->box_w = 0;
213         dsc_out->adv_w = 0;
214         dsc_out->box_h = 0; /*height of the bitmap in [px]*/
215         dsc_out->ofs_x = 0; /*X offset of the bitmap in [pf]*/
216         dsc_out->ofs_y = 0; /*Y offset of the bitmap in [pf]*/
217         dsc_out->format = LV_FONT_GLYPH_FORMAT_NONE;
218         dsc_out->is_placeholder = false;
219         return true;
220     }
221 
222     ttf_font_desc_t * dsc = (ttf_font_desc_t *)font->dsc;
223 
224     tiny_ttf_glyph_cache_data_t search_key = {
225         .unicode = unicode_letter,
226     };
227 
228     int adv_w;
229     lv_cache_entry_t * entry = lv_cache_acquire_or_create(dsc->glyph_cache, &search_key, (void *)dsc);
230 
231     if(entry == NULL) {
232         if(!dsc->cache_size) {  /* no cache, do everything directly */
233             uint32_t g1 = stbtt_FindGlyphIndex(&dsc->info, (int)unicode_letter);
234             tiny_ttf_glyph_cache_create_cb(&search_key, dsc);
235             *dsc_out = search_key.glyph_dsc;
236             adv_w = search_key.adv_w;
237 
238             /*Kerning correction*/
239             if(font->kerning == LV_FONT_KERNING_NORMAL &&
240                unicode_letter_next != 0) {
241                 int g2 = stbtt_FindGlyphIndex(&dsc->info, (int)unicode_letter_next); /* not using cache, only do glyph id lookup */
242                 if(g2) {
243                     int k = stbtt_GetGlyphKernAdvance(&dsc->info, g1, g2);
244                     dsc_out->adv_w = (uint16_t)floor((((float)adv_w + (float)k) * dsc->scale) +
245                                                      0.5f); /*Horizontal space required by the glyph in [px]*/
246                 }
247             }
248 
249             dsc_out->entry = NULL;
250             return true;
251         }
252         LV_LOG_ERROR("cache not allocated");
253         return false;
254     }
255 
256     tiny_ttf_glyph_cache_data_t * data = lv_cache_entry_get_data(entry);
257     *dsc_out = data->glyph_dsc;
258     adv_w = data->adv_w;
259     lv_cache_release(dsc->glyph_cache, entry, NULL);
260 
261     /*Kerning correction*/
262     if(font->kerning == LV_FONT_KERNING_NORMAL &&
263        unicode_letter_next != 0) { /* check if we need to do any kerning calculations */
264         uint32_t g1 = dsc_out->gid.index;
265 
266         int g2 = 0;
267         search_key.unicode = unicode_letter_next; /* reuse search key */
268         lv_cache_entry_t * entry_next = lv_cache_acquire_or_create(dsc->glyph_cache, &search_key, (void *)dsc);
269 
270         if(entry_next == NULL)
271             g2 = stbtt_FindGlyphIndex(&dsc->info, (int)unicode_letter_next);
272         else {
273             tiny_ttf_glyph_cache_data_t * data_next = lv_cache_entry_get_data(entry_next);
274             g2 = data_next->glyph_dsc.gid.index;
275             lv_cache_release(dsc->glyph_cache, entry_next, NULL);
276         }
277 
278         if(g2) {
279             int k = stbtt_GetGlyphKernAdvance(&dsc->info, g1, g2);
280             dsc_out->adv_w = (uint16_t)floor((((float)adv_w + (float)k) * dsc->scale) +
281                                              0.5f); /*Horizontal space required by the glyph in [px]*/
282         }
283     }
284 
285     dsc_out->entry = NULL;
286     return true; /*true: glyph found; false: glyph was not found*/
287 }
288 
ttf_get_glyph_bitmap_cb(lv_font_glyph_dsc_t * g_dsc,lv_draw_buf_t * draw_buf)289 static const void * ttf_get_glyph_bitmap_cb(lv_font_glyph_dsc_t * g_dsc, lv_draw_buf_t * draw_buf)
290 {
291     LV_UNUSED(draw_buf);
292     uint32_t glyph_index = g_dsc->gid.index;
293     const lv_font_t * font = g_dsc->resolved_font;
294     ttf_font_desc_t * dsc = (ttf_font_desc_t *)font->dsc;
295     tiny_ttf_cache_data_t search_key = {
296         .glyph_index = glyph_index,
297         .size = font->line_height,
298     };
299 
300     lv_cache_entry_t * entry = lv_cache_acquire_or_create(dsc->draw_data_cache, &search_key, (void *)font->dsc);
301     if(entry == NULL) {
302         if(!dsc->cache_size) {  /* no cache, do everything directly */
303             if(tiny_ttf_draw_data_cache_create_cb(&search_key, (void *)font->dsc)) {
304                 /* use the cache entry to store the buffer if no cache specified */
305                 g_dsc->entry = (lv_cache_entry_t *)search_key.draw_buf;
306                 return g_dsc->entry;
307             }
308             else {
309                 return NULL;
310             }
311         }
312         LV_LOG_ERROR("cache not allocated");
313         return NULL;
314     }
315 
316     g_dsc->entry = entry;
317     tiny_ttf_cache_data_t * cached_data = lv_cache_entry_get_data(entry);
318     return cached_data->draw_buf;
319 }
320 
ttf_release_glyph_cb(const lv_font_t * font,lv_font_glyph_dsc_t * g_dsc)321 static void ttf_release_glyph_cb(const lv_font_t * font, lv_font_glyph_dsc_t * g_dsc)
322 {
323     LV_ASSERT_NULL(font);
324 
325     ttf_font_desc_t * dsc = (ttf_font_desc_t *)font->dsc;
326     if(!dsc->cache_size) {  /* no cache, do everything directly */
327         lv_draw_buf_destroy_user(font_draw_buf_handlers, (lv_draw_buf_t *)g_dsc->entry);
328     }
329     else {
330         if(g_dsc->entry == NULL) {
331             return;
332         }
333         lv_cache_release(dsc->draw_data_cache, g_dsc->entry, NULL);
334     }
335     g_dsc->entry = NULL;
336 }
337 
lv_tiny_ttf_cache_create(ttf_font_desc_t * dsc)338 static void lv_tiny_ttf_cache_create(ttf_font_desc_t * dsc)
339 {
340     /*Init cache*/
341     dsc->glyph_cache = lv_cache_create(&lv_cache_class_lru_rb_count, sizeof(tiny_ttf_glyph_cache_data_t), dsc->cache_size,
342     (lv_cache_ops_t) {
343         .compare_cb = (lv_cache_compare_cb_t)tiny_ttf_glyph_cache_compare_cb,
344         .create_cb = (lv_cache_create_cb_t)tiny_ttf_glyph_cache_create_cb,
345         .free_cb = (lv_cache_free_cb_t)tiny_ttf_glyph_cache_free_cb
346     });
347     lv_cache_set_name(dsc->glyph_cache, "TINY_TTF_GLYPH");
348 
349     dsc->draw_data_cache = lv_cache_create(&lv_cache_class_lru_rb_count, sizeof(tiny_ttf_cache_data_t), dsc->cache_size,
350     (lv_cache_ops_t) {
351         .compare_cb = (lv_cache_compare_cb_t)tiny_ttf_draw_data_cache_compare_cb,
352         .create_cb = (lv_cache_create_cb_t)tiny_ttf_draw_data_cache_create_cb,
353         .free_cb = (lv_cache_free_cb_t)tiny_ttf_draw_data_cache_free_cb,
354     });
355     lv_cache_set_name(dsc->draw_data_cache, "TINY_TTF_DRAW_DATA");
356 }
357 
lv_tiny_ttf_create(const char * path,const void * data,size_t data_size,int32_t font_size,lv_font_kerning_t kerning,size_t cache_size)358 static lv_font_t * lv_tiny_ttf_create(const char * path, const void * data, size_t data_size, int32_t font_size,
359                                       lv_font_kerning_t kerning, size_t cache_size)
360 {
361     LV_UNUSED(data_size);
362     if((path == NULL && data == NULL) || 0 >= font_size) {
363         LV_LOG_ERROR("tiny_ttf: invalid argument");
364         return NULL;
365     }
366     ttf_font_desc_t * dsc = lv_malloc_zeroed(sizeof(ttf_font_desc_t));
367     if(dsc == NULL) {
368         LV_LOG_ERROR("tiny_ttf: out of memory");
369         return NULL;
370     }
371 #if LV_TINY_TTF_FILE_SUPPORT != 0
372     if(path != NULL) {
373         if(LV_FS_RES_OK != lv_fs_open(&dsc->file, path, LV_FS_MODE_RD)) {
374             lv_free(dsc);
375             LV_LOG_ERROR("tiny_ttf: unable to open %s\n", path);
376             return NULL;
377         }
378         dsc->stream.file = &dsc->file;
379     }
380     else {
381         dsc->stream.data = (const uint8_t *)data;
382         dsc->stream.size = data_size;
383     }
384     if(0 == stbtt_InitFont(&dsc->info, &dsc->stream, stbtt_GetFontOffsetForIndex(&dsc->stream, 0))) {
385         lv_free(dsc);
386         LV_LOG_ERROR("tiny_ttf: init failed");
387         return NULL;
388     }
389 
390 #else
391     dsc->stream = (const uint8_t *)data;
392     if(0 == stbtt_InitFont(&dsc->info, dsc->stream, stbtt_GetFontOffsetForIndex(dsc->stream, 0))) {
393         lv_free(dsc);
394         LV_LOG_ERROR("tiny_ttf: init failed");
395         return NULL;
396     }
397 #endif
398 
399     dsc->cache_size = cache_size;
400 
401     lv_font_t * out_font = lv_malloc_zeroed(sizeof(lv_font_t));
402     if(out_font == NULL) {
403         lv_free(dsc);
404         LV_LOG_ERROR("tiny_ttf: out of memory");
405         return NULL;
406     }
407 
408     /* check if font  has kerning tables to use, else disable kerning automatically. */
409     if(stbtt_KernTableCheck(&dsc->info) == 0) {
410         kerning = LV_FONT_KERNING_NONE; /* disable kerning if font has no tables. */
411     }
412 
413     dsc->kerning = kerning;
414     out_font->kerning = kerning;
415 
416     out_font->get_glyph_dsc = ttf_get_glyph_dsc_cb;
417     out_font->get_glyph_bitmap = ttf_get_glyph_bitmap_cb;
418     out_font->release_glyph = ttf_release_glyph_cb;
419     out_font->dsc = dsc;
420     lv_tiny_ttf_set_size(out_font, font_size);
421     return out_font;
422 }
423 #if LV_TINY_TTF_FILE_SUPPORT != 0
lv_tiny_ttf_create_file_ex(const char * path,int32_t font_size,lv_font_kerning_t kerning,size_t cache_size)424 lv_font_t * lv_tiny_ttf_create_file_ex(const char * path, int32_t font_size, lv_font_kerning_t kerning,
425                                        size_t cache_size)
426 {
427     return lv_tiny_ttf_create(path, NULL, 0, font_size, kerning, cache_size);
428 }
lv_tiny_ttf_create_file(const char * path,int32_t font_size)429 lv_font_t * lv_tiny_ttf_create_file(const char * path, int32_t font_size)
430 {
431     return lv_tiny_ttf_create(path, NULL, 0, font_size, LV_FONT_KERNING_NORMAL, LV_TINY_TTF_CACHE_GLYPH_CNT);
432 }
433 #endif
434 
lv_tiny_ttf_create_data_ex(const void * data,size_t data_size,int32_t font_size,lv_font_kerning_t kerning,size_t cache_size)435 lv_font_t * lv_tiny_ttf_create_data_ex(const void * data, size_t data_size, int32_t font_size,
436                                        lv_font_kerning_t kerning, size_t cache_size)
437 {
438     return lv_tiny_ttf_create(NULL, data, data_size, font_size, kerning, cache_size);
439 }
lv_tiny_ttf_create_data(const void * data,size_t data_size,int32_t font_size)440 lv_font_t * lv_tiny_ttf_create_data(const void * data, size_t data_size, int32_t font_size)
441 {
442     return lv_tiny_ttf_create(NULL, data, data_size, font_size, LV_FONT_KERNING_NORMAL, LV_TINY_TTF_CACHE_GLYPH_CNT);
443 }
444 
445 /*-----------------
446  * Cache Callbacks
447  *----------------*/
448 
tiny_ttf_glyph_cache_create_cb(tiny_ttf_glyph_cache_data_t * node,void * user_data)449 static bool tiny_ttf_glyph_cache_create_cb(tiny_ttf_glyph_cache_data_t * node, void * user_data)
450 {
451     ttf_font_desc_t * dsc = (ttf_font_desc_t *)user_data;
452     lv_font_glyph_dsc_t * dsc_out = &node->glyph_dsc;
453 
454     uint32_t unicode_letter = node->unicode;
455 
456     int g1 = stbtt_FindGlyphIndex(&dsc->info, (int)unicode_letter);
457     if(g1 == 0) {
458         /* Glyph not found */
459         return false;
460     }
461     int x1, y1, x2, y2;
462 
463     stbtt_GetGlyphBitmapBox(&dsc->info, g1, dsc->scale, dsc->scale, &x1, &y1, &x2, &y2);
464 
465     int advw, lsb;
466     stbtt_GetGlyphHMetrics(&dsc->info, g1, &advw, &lsb);
467     if(dsc->kerning != LV_FONT_KERNING_NORMAL) { /* calculate default advance */
468         int k = stbtt_GetGlyphKernAdvance(&dsc->info, g1, 0);
469         dsc_out->adv_w = (uint16_t)floor((((float)advw + (float)k) * dsc->scale) +
470                                          0.5f); /*Horizontal space required by the glyph in [px]*/
471     }
472     else {
473         dsc_out->adv_w = (uint16_t)floor(((float)advw * dsc->scale) +
474                                          0.5f); /*Horizontal space required by the glyph in [px]*/;
475     }
476     /* precalculate no kerning value */
477     node->adv_w = advw;
478     dsc_out->box_w = (x2 - x1 + 1);         /*width of the bitmap in [px]*/
479     dsc_out->box_h = (y2 - y1 + 1);         /*height of the bitmap in [px]*/
480     dsc_out->ofs_x = x1;                    /*X offset of the bitmap in [pf]*/
481     dsc_out->ofs_y = -y2;                   /*Y offset of the bitmap measured from the as line*/
482     dsc_out->format = LV_FONT_GLYPH_FORMAT_A8;
483     dsc_out->is_placeholder = false;
484     dsc_out->gid.index = (uint32_t)g1;
485 
486     return true;
487 }
488 
tiny_ttf_glyph_cache_free_cb(tiny_ttf_glyph_cache_data_t * node,void * user_data)489 static void tiny_ttf_glyph_cache_free_cb(tiny_ttf_glyph_cache_data_t * node, void * user_data)
490 {
491     LV_UNUSED(node);
492     LV_UNUSED(user_data);
493 }
494 
tiny_ttf_glyph_cache_compare_cb(const tiny_ttf_glyph_cache_data_t * lhs,const tiny_ttf_glyph_cache_data_t * rhs)495 static lv_cache_compare_res_t tiny_ttf_glyph_cache_compare_cb(const tiny_ttf_glyph_cache_data_t * lhs,
496                                                               const tiny_ttf_glyph_cache_data_t * rhs)
497 {
498     if(lhs->unicode != rhs->unicode) {
499         return lhs->unicode > rhs->unicode ? 1 : -1;
500     }
501 
502     return 0;
503 }
504 
tiny_ttf_draw_data_cache_create_cb(tiny_ttf_cache_data_t * node,void * user_data)505 static bool tiny_ttf_draw_data_cache_create_cb(tiny_ttf_cache_data_t * node, void * user_data)
506 {
507     int g1 = (int)node->glyph_index;
508     if(g1 == 0) {
509         /* Glyph not found */
510         return false;
511     }
512 
513     ttf_font_desc_t * dsc = (ttf_font_desc_t *)user_data;
514 
515     const stbtt_fontinfo * info = (const stbtt_fontinfo *)&dsc->info;
516     int x1, y1, x2, y2;
517     stbtt_GetGlyphBitmapBox(info, g1, dsc->scale, dsc->scale, &x1, &y1, &x2, &y2);
518     int w, h;
519     w = x2 - x1 + 1;
520     h = y2 - y1 + 1;
521 
522     lv_draw_buf_t * draw_buf = lv_draw_buf_create_ex(font_draw_buf_handlers, w, h, LV_COLOR_FORMAT_A8, LV_STRIDE_AUTO);
523     if(NULL == draw_buf) {
524         LV_LOG_ERROR("tiny_ttf: out of memory");
525         return false;
526     }
527 
528     lv_draw_buf_clear(draw_buf, NULL);
529 
530     uint32_t stride = draw_buf->header.stride;
531     stbtt_MakeGlyphBitmap(info, draw_buf->data, w, h, stride, dsc->scale, dsc->scale, g1);
532 
533     node->draw_buf = draw_buf;
534     return true;
535 }
536 
tiny_ttf_draw_data_cache_free_cb(tiny_ttf_cache_data_t * node,void * user_data)537 static void tiny_ttf_draw_data_cache_free_cb(tiny_ttf_cache_data_t * node, void * user_data)
538 {
539     LV_UNUSED(user_data);
540 
541     lv_draw_buf_destroy(node->draw_buf);
542 }
543 
tiny_ttf_draw_data_cache_compare_cb(const tiny_ttf_cache_data_t * lhs,const tiny_ttf_cache_data_t * rhs)544 static lv_cache_compare_res_t tiny_ttf_draw_data_cache_compare_cb(const tiny_ttf_cache_data_t * lhs,
545                                                                   const tiny_ttf_cache_data_t * rhs)
546 {
547     if(lhs->glyph_index != rhs->glyph_index) {
548         return lhs->glyph_index > rhs->glyph_index ? 1 : -1;
549     }
550 
551     if(lhs->size != rhs->size) {
552         return lhs->size > rhs->size ? 1 : -1;
553     }
554 
555     return 0;
556 }
557 
558 #endif
559