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