1 /**
2 * @file lv_freetype.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_freetype.h"
10 #if LV_USE_FREETYPE
11
12 #include "ft2build.h"
13 #include FT_FREETYPE_H
14 #include FT_GLYPH_H
15 #include FT_CACHE_H
16 #include FT_SIZES_H
17 #include FT_IMAGE_H
18 #include FT_OUTLINE_H
19
20 /*********************
21 * DEFINES
22 *********************/
23
24 /**********************
25 * TYPEDEFS
26 **********************/
27 typedef struct {
28 lv_ll_t face_ll;
29 } lv_faces_control_t;
30
31 typedef struct name_refer_t {
32 const char * name; /* point to font name string */
33 int32_t cnt; /* reference count */
34 } name_refer_t;
35
36 typedef struct {
37 const void * mem;
38 const char * name;
39 size_t mem_size;
40 #if LV_FREETYPE_CACHE_SIZE < 0
41 FT_Size size;
42 #endif
43 lv_font_t * font;
44 uint16_t style;
45 uint16_t height;
46 } lv_font_fmt_ft_dsc_t;
47
48 /**********************
49 * STATIC PROTOTYPES
50 **********************/
51 #if LV_FREETYPE_CACHE_SIZE >= 0
52 static FT_Error font_face_requester(FTC_FaceID face_id,
53 FT_Library library_is, FT_Pointer req_data, FT_Face * aface);
54 static bool lv_ft_font_init_cache(lv_ft_info_t * info);
55 static void lv_ft_font_destroy_cache(lv_font_t * font);
56 #else
57 static FT_Face face_find_in_list(lv_ft_info_t * info);
58 static void face_add_to_list(FT_Face face);
59 static void face_remove_from_list(FT_Face face);
60 static void face_generic_finalizer(void * object);
61 static bool lv_ft_font_init_nocache(lv_ft_info_t * info);
62 static void lv_ft_font_destroy_nocache(lv_font_t * font);
63 #endif
64
65 static const char * name_refer_save(const char * name);
66 static void name_refer_del(const char * name);
67 static const char * name_refer_find(const char * name);
68
69 /**********************
70 * STATIC VARIABLES
71 **********************/
72 static FT_Library library;
73 static lv_ll_t names_ll;
74
75 #if LV_FREETYPE_CACHE_SIZE >= 0
76 static FTC_Manager cache_manager;
77 static FTC_CMapCache cmap_cache;
78 static FT_Face current_face = NULL;
79
80 #if LV_FREETYPE_SBIT_CACHE
81 static FTC_SBitCache sbit_cache;
82 static FTC_SBit sbit;
83 #else
84 static FTC_ImageCache image_cache;
85 static FT_Glyph image_glyph;
86 #endif
87
88 #else
89 static lv_faces_control_t face_control;
90 #endif
91
92 /**********************
93 * MACROS
94 **********************/
95
96 /**********************
97 * GLOBAL FUNCTIONS
98 **********************/
99
lv_freetype_init(uint16_t max_faces,uint16_t max_sizes,uint32_t max_bytes)100 bool lv_freetype_init(uint16_t max_faces, uint16_t max_sizes, uint32_t max_bytes)
101 {
102 FT_Error error = FT_Init_FreeType(&library);
103 if(error) {
104 LV_LOG_ERROR("init freeType error(%d)", error);
105 return false;
106 }
107
108 _lv_ll_init(&names_ll, sizeof(name_refer_t));
109
110 #if LV_FREETYPE_CACHE_SIZE >= 0
111 error = FTC_Manager_New(library, max_faces, max_sizes,
112 max_bytes, font_face_requester, NULL, &cache_manager);
113 if(error) {
114 FT_Done_FreeType(library);
115 LV_LOG_ERROR("Failed to open cache manager");
116 return false;
117 }
118
119 error = FTC_CMapCache_New(cache_manager, &cmap_cache);
120 if(error) {
121 LV_LOG_ERROR("Failed to open Cmap Cache");
122 goto Fail;
123 }
124
125 #if LV_FREETYPE_SBIT_CACHE
126 error = FTC_SBitCache_New(cache_manager, &sbit_cache);
127 if(error) {
128 LV_LOG_ERROR("Failed to open sbit cache");
129 goto Fail;
130 }
131 #else
132 error = FTC_ImageCache_New(cache_manager, &image_cache);
133 if(error) {
134 LV_LOG_ERROR("Failed to open image cache");
135 goto Fail;
136 }
137 #endif
138
139 return true;
140 Fail:
141 FTC_Manager_Done(cache_manager);
142 FT_Done_FreeType(library);
143 return false;
144 #else
145 LV_UNUSED(max_faces);
146 LV_UNUSED(max_sizes);
147 LV_UNUSED(max_bytes);
148 _lv_ll_init(&face_control.face_ll, sizeof(FT_Face *));
149 return true;
150 #endif/* LV_FREETYPE_CACHE_SIZE */
151 }
152
lv_freetype_destroy(void)153 void lv_freetype_destroy(void)
154 {
155 #if LV_FREETYPE_CACHE_SIZE >= 0
156 FTC_Manager_Done(cache_manager);
157 #endif
158 FT_Done_FreeType(library);
159 }
160
lv_ft_font_init(lv_ft_info_t * info)161 bool lv_ft_font_init(lv_ft_info_t * info)
162 {
163 #if LV_FREETYPE_CACHE_SIZE >= 0
164 return lv_ft_font_init_cache(info);
165 #else
166 return lv_ft_font_init_nocache(info);
167 #endif
168 }
169
lv_ft_font_destroy(lv_font_t * font)170 void lv_ft_font_destroy(lv_font_t * font)
171 {
172 #if LV_FREETYPE_CACHE_SIZE >= 0
173 lv_ft_font_destroy_cache(font);
174 #else
175 lv_ft_font_destroy_nocache(font);
176 #endif
177 }
178
179 /**********************
180 * STATIC FUNCTIONS
181 **********************/
182 #if LV_FREETYPE_CACHE_SIZE >= 0
183
font_face_requester(FTC_FaceID face_id,FT_Library library_is,FT_Pointer req_data,FT_Face * aface)184 static FT_Error font_face_requester(FTC_FaceID face_id,
185 FT_Library library_is, FT_Pointer req_data, FT_Face * aface)
186 {
187 LV_UNUSED(library_is);
188 LV_UNUSED(req_data);
189
190 lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)face_id;
191 FT_Error error;
192 if(dsc->mem) {
193 error = FT_New_Memory_Face(library, dsc->mem, dsc->mem_size, 0, aface);
194 }
195 else {
196 error = FT_New_Face(library, dsc->name, 0, aface);
197 }
198 if(error) {
199 LV_LOG_ERROR("FT_New_Face error:%d\n", error);
200 return error;
201 }
202 return FT_Err_Ok;
203 }
204
get_bold_glyph(const lv_font_t * font,FT_Face face,FT_UInt glyph_index,lv_font_glyph_dsc_t * dsc_out)205 static bool get_bold_glyph(const lv_font_t * font, FT_Face face,
206 FT_UInt glyph_index, lv_font_glyph_dsc_t * dsc_out)
207 {
208 if(FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT)) {
209 return false;
210 }
211
212 lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->dsc);
213 if(face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
214 if(dsc->style & FT_FONT_STYLE_BOLD) {
215 int strength = 1 << 6;
216 FT_Outline_Embolden(&face->glyph->outline, strength);
217 }
218 }
219
220 if(FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL)) {
221 return false;
222 }
223
224 dsc_out->adv_w = (face->glyph->metrics.horiAdvance >> 6);
225 dsc_out->box_h = face->glyph->bitmap.rows; /*Height of the bitmap in [px]*/
226 dsc_out->box_w = face->glyph->bitmap.width; /*Width of the bitmap in [px]*/
227 dsc_out->ofs_x = face->glyph->bitmap_left; /*X offset of the bitmap in [pf]*/
228 dsc_out->ofs_y = face->glyph->bitmap_top -
229 face->glyph->bitmap.rows; /*Y offset of the bitmap measured from the as line*/
230 dsc_out->bpp = 8; /*Bit per pixel: 1/2/4/8*/
231
232 return true;
233 }
234
get_glyph_dsc_cb_cache(const lv_font_t * font,lv_font_glyph_dsc_t * dsc_out,uint32_t unicode_letter,uint32_t unicode_letter_next)235 static bool get_glyph_dsc_cb_cache(const lv_font_t * font,
236 lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next)
237 {
238 LV_UNUSED(unicode_letter_next);
239 if(unicode_letter < 0x20) {
240 dsc_out->adv_w = 0;
241 dsc_out->box_h = 0;
242 dsc_out->box_w = 0;
243 dsc_out->ofs_x = 0;
244 dsc_out->ofs_y = 0;
245 dsc_out->bpp = 0;
246 return true;
247 }
248
249 lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->dsc);
250
251 FTC_FaceID face_id = (FTC_FaceID)dsc;
252 FT_Size face_size;
253 struct FTC_ScalerRec_ scaler;
254 scaler.face_id = face_id;
255 scaler.width = dsc->height;
256 scaler.height = dsc->height;
257 scaler.pixel = 1;
258 if(FTC_Manager_LookupSize(cache_manager, &scaler, &face_size) != 0) {
259 return false;
260 }
261
262 FT_Face face = face_size->face;
263 FT_UInt charmap_index = FT_Get_Charmap_Index(face->charmap);
264 FT_UInt glyph_index = FTC_CMapCache_Lookup(cmap_cache, face_id, charmap_index, unicode_letter);
265 dsc_out->is_placeholder = glyph_index == 0;
266
267 if(dsc->style & FT_FONT_STYLE_ITALIC) {
268 FT_Matrix italic_matrix;
269 italic_matrix.xx = 1 << 16;
270 italic_matrix.xy = 0x5800;
271 italic_matrix.yx = 0;
272 italic_matrix.yy = 1 << 16;
273 FT_Set_Transform(face, &italic_matrix, NULL);
274 }
275
276 if(dsc->style & FT_FONT_STYLE_BOLD) {
277 current_face = face;
278 if(!get_bold_glyph(font, face, glyph_index, dsc_out)) {
279 current_face = NULL;
280 return false;
281 }
282 goto end;
283 }
284
285 FTC_ImageTypeRec desc_type;
286 desc_type.face_id = face_id;
287 desc_type.flags = FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL;
288 desc_type.height = dsc->height;
289 desc_type.width = dsc->height;
290
291 #if LV_FREETYPE_SBIT_CACHE
292 FT_Error error = FTC_SBitCache_Lookup(sbit_cache, &desc_type, glyph_index, &sbit, NULL);
293 if(error) {
294 LV_LOG_ERROR("SBitCache_Lookup error");
295 return false;
296 }
297
298 dsc_out->adv_w = sbit->xadvance;
299 dsc_out->box_h = sbit->height; /*Height of the bitmap in [px]*/
300 dsc_out->box_w = sbit->width; /*Width of the bitmap in [px]*/
301 dsc_out->ofs_x = sbit->left; /*X offset of the bitmap in [pf]*/
302 dsc_out->ofs_y = sbit->top - sbit->height; /*Y offset of the bitmap measured from the as line*/
303 dsc_out->bpp = 8; /*Bit per pixel: 1/2/4/8*/
304 #else
305 FT_Error error = FTC_ImageCache_Lookup(image_cache, &desc_type, glyph_index, &image_glyph, NULL);
306 if(error) {
307 LV_LOG_ERROR("ImageCache_Lookup error");
308 return false;
309 }
310 if(image_glyph->format != FT_GLYPH_FORMAT_BITMAP) {
311 LV_LOG_ERROR("Glyph_To_Bitmap error");
312 return false;
313 }
314
315 FT_BitmapGlyph glyph_bitmap = (FT_BitmapGlyph)image_glyph;
316 dsc_out->adv_w = (glyph_bitmap->root.advance.x >> 16);
317 dsc_out->box_h = glyph_bitmap->bitmap.rows; /*Height of the bitmap in [px]*/
318 dsc_out->box_w = glyph_bitmap->bitmap.width; /*Width of the bitmap in [px]*/
319 dsc_out->ofs_x = glyph_bitmap->left; /*X offset of the bitmap in [pf]*/
320 dsc_out->ofs_y = glyph_bitmap->top -
321 glyph_bitmap->bitmap.rows; /*Y offset of the bitmap measured from the as line*/
322 dsc_out->bpp = 8; /*Bit per pixel: 1/2/4/8*/
323 #endif
324
325 end:
326 if((dsc->style & FT_FONT_STYLE_ITALIC) && (unicode_letter_next == '\0')) {
327 dsc_out->adv_w = dsc_out->box_w + dsc_out->ofs_x;
328 }
329
330 return true;
331 }
332
get_glyph_bitmap_cb_cache(const lv_font_t * font,uint32_t unicode_letter)333 static const uint8_t * get_glyph_bitmap_cb_cache(const lv_font_t * font, uint32_t unicode_letter)
334 {
335 LV_UNUSED(unicode_letter);
336
337 lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->dsc);
338 if(dsc->style & FT_FONT_STYLE_BOLD) {
339 if(current_face && current_face->glyph->format == FT_GLYPH_FORMAT_BITMAP) {
340 return (const uint8_t *)(current_face->glyph->bitmap.buffer);
341 }
342 return NULL;
343 }
344
345 #if LV_FREETYPE_SBIT_CACHE
346 return (const uint8_t *)sbit->buffer;
347 #else
348 FT_BitmapGlyph glyph_bitmap = (FT_BitmapGlyph)image_glyph;
349 return (const uint8_t *)glyph_bitmap->bitmap.buffer;
350 #endif
351 }
352
lv_ft_font_init_cache(lv_ft_info_t * info)353 static bool lv_ft_font_init_cache(lv_ft_info_t * info)
354 {
355 size_t need_size = sizeof(lv_font_fmt_ft_dsc_t) + sizeof(lv_font_t);
356 lv_font_fmt_ft_dsc_t * dsc = lv_mem_alloc(need_size);
357 if(dsc == NULL) return false;
358 lv_memset_00(dsc, need_size);
359
360 dsc->font = (lv_font_t *)(((char *)dsc) + sizeof(lv_font_fmt_ft_dsc_t));
361 dsc->mem = info->mem;
362 dsc->mem_size = info->mem_size;
363 dsc->name = name_refer_save(info->name);
364 dsc->height = info->weight;
365 dsc->style = info->style;
366
367 /* use to get font info */
368 FT_Size face_size;
369 struct FTC_ScalerRec_ scaler;
370 scaler.face_id = (FTC_FaceID)dsc;
371 scaler.width = info->weight;
372 scaler.height = info->weight;
373 scaler.pixel = 1;
374 FT_Error error = FTC_Manager_LookupSize(cache_manager, &scaler, &face_size);
375 if(error) {
376 LV_LOG_ERROR("Failed to LookupSize");
377 goto Fail;
378 }
379
380 lv_font_t * font = dsc->font;
381 font->dsc = dsc;
382 font->get_glyph_dsc = get_glyph_dsc_cb_cache;
383 font->get_glyph_bitmap = get_glyph_bitmap_cb_cache;
384 font->subpx = LV_FONT_SUBPX_NONE;
385 font->line_height = (face_size->face->size->metrics.height >> 6);
386 font->base_line = -(face_size->face->size->metrics.descender >> 6);
387
388 FT_Fixed scale = face_size->face->size->metrics.y_scale;
389 int8_t thickness = FT_MulFix(scale, face_size->face->underline_thickness) >> 6;
390 font->underline_position = FT_MulFix(scale, face_size->face->underline_position) >> 6;
391 font->underline_thickness = thickness < 1 ? 1 : thickness;
392
393 /* return to user */
394 info->font = font;
395
396 return true;
397
398 Fail:
399 lv_mem_free(dsc);
400 return false;
401 }
402
lv_ft_font_destroy_cache(lv_font_t * font)403 void lv_ft_font_destroy_cache(lv_font_t * font)
404 {
405 if(font == NULL) {
406 return;
407 }
408
409 lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->dsc);
410 if(dsc) {
411 FTC_Manager_RemoveFaceID(cache_manager, (FTC_FaceID)dsc);
412 name_refer_del(dsc->name);
413 lv_mem_free(dsc);
414 }
415 }
416 #else/* LV_FREETYPE_CACHE_SIZE */
417
face_find_in_list(lv_ft_info_t * info)418 static FT_Face face_find_in_list(lv_ft_info_t * info)
419 {
420 lv_font_fmt_ft_dsc_t * dsc;
421 FT_Face * pface = _lv_ll_get_head(&face_control.face_ll);
422 while(pface) {
423 dsc = (lv_font_fmt_ft_dsc_t *)(*pface)->generic.data;
424 if(strcmp(dsc->name, info->name) == 0) {
425 return *pface;
426 }
427 pface = _lv_ll_get_next(&face_control.face_ll, pface);
428 }
429
430 return NULL;
431 }
432
face_add_to_list(FT_Face face)433 static void face_add_to_list(FT_Face face)
434 {
435 FT_Face * pface;
436 pface = (FT_Face *)_lv_ll_ins_tail(&face_control.face_ll);
437 *pface = face;
438 }
439
face_remove_from_list(FT_Face face)440 static void face_remove_from_list(FT_Face face)
441 {
442 FT_Face * pface = _lv_ll_get_head(&face_control.face_ll);
443 while(pface) {
444 if(*pface == face) {
445 _lv_ll_remove(&face_control.face_ll, pface);
446 lv_mem_free(pface);
447 break;
448 }
449 pface = _lv_ll_get_next(&face_control.face_ll, pface);
450 }
451 }
452
face_generic_finalizer(void * object)453 static void face_generic_finalizer(void * object)
454 {
455 FT_Face face = (FT_Face)object;
456 face_remove_from_list(face);
457 LV_LOG_INFO("face finalizer(%p)\n", face);
458 }
459
get_glyph_dsc_cb_nocache(const lv_font_t * font,lv_font_glyph_dsc_t * dsc_out,uint32_t unicode_letter,uint32_t unicode_letter_next)460 static bool get_glyph_dsc_cb_nocache(const lv_font_t * font,
461 lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next)
462 {
463 LV_UNUSED(unicode_letter_next);
464 if(unicode_letter < 0x20) {
465 dsc_out->adv_w = 0;
466 dsc_out->box_h = 0;
467 dsc_out->box_w = 0;
468 dsc_out->ofs_x = 0;
469 dsc_out->ofs_y = 0;
470 dsc_out->bpp = 0;
471 return true;
472 }
473
474 FT_Error error;
475 lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->dsc);
476 FT_Face face = dsc->size->face;
477
478 FT_UInt glyph_index = FT_Get_Char_Index(face, unicode_letter);
479
480 if(face->size != dsc->size) {
481 FT_Activate_Size(dsc->size);
482 }
483 dsc_out->is_placeholder = glyph_index == 0;
484
485 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
486 if(error) {
487 return false;
488 }
489
490 if(face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
491 if(dsc->style & FT_FONT_STYLE_BOLD) {
492 int strength = 1 << 6;
493 FT_Outline_Embolden(&face->glyph->outline, strength);
494 }
495
496 if(dsc->style & FT_FONT_STYLE_ITALIC) {
497 FT_Matrix italic_matrix;
498 italic_matrix.xx = 1 << 16;
499 italic_matrix.xy = 0x5800;
500 italic_matrix.yx = 0;
501 italic_matrix.yy = 1 << 16;
502 FT_Outline_Transform(&face->glyph->outline, &italic_matrix);
503 }
504 }
505
506 error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
507 if(error) {
508 return false;
509 }
510
511 dsc_out->adv_w = (face->glyph->metrics.horiAdvance >> 6);
512 dsc_out->box_h = face->glyph->bitmap.rows; /*Height of the bitmap in [px]*/
513 dsc_out->box_w = face->glyph->bitmap.width; /*Width of the bitmap in [px]*/
514 dsc_out->ofs_x = face->glyph->bitmap_left; /*X offset of the bitmap in [pf]*/
515 dsc_out->ofs_y = face->glyph->bitmap_top -
516 face->glyph->bitmap.rows; /*Y offset of the bitmap measured from the as line*/
517 dsc_out->bpp = 8; /*Bit per pixel: 1/2/4/8*/
518
519 if((dsc->style & FT_FONT_STYLE_ITALIC) && (unicode_letter_next == '\0')) {
520 dsc_out->adv_w = dsc_out->box_w + dsc_out->ofs_x;
521 }
522
523 return true;
524 }
525
get_glyph_bitmap_cb_nocache(const lv_font_t * font,uint32_t unicode_letter)526 static const uint8_t * get_glyph_bitmap_cb_nocache(const lv_font_t * font, uint32_t unicode_letter)
527 {
528 LV_UNUSED(unicode_letter);
529 lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->dsc);
530 FT_Face face = dsc->size->face;
531 return (const uint8_t *)(face->glyph->bitmap.buffer);
532 }
533
lv_ft_font_init_nocache(lv_ft_info_t * info)534 static bool lv_ft_font_init_nocache(lv_ft_info_t * info)
535 {
536 size_t need_size = sizeof(lv_font_fmt_ft_dsc_t) + sizeof(lv_font_t);
537 lv_font_fmt_ft_dsc_t * dsc = lv_mem_alloc(need_size);
538 if(dsc == NULL) return false;
539 lv_memset_00(dsc, need_size);
540
541 dsc->font = (lv_font_t *)(((char *)dsc) + sizeof(lv_font_fmt_ft_dsc_t));
542 dsc->mem = info->mem;
543 dsc->mem_size = info->mem_size;
544 dsc->name = name_refer_save(info->name);
545 dsc->height = info->weight;
546 dsc->style = info->style;
547
548 FT_Face face = face_find_in_list(info);
549 if(face == NULL) {
550 FT_Error error;
551 if(dsc->mem) {
552 error = FT_New_Memory_Face(library, dsc->mem, (FT_Long) dsc->mem_size, 0, &face);
553 }
554 else {
555 error = FT_New_Face(library, dsc->name, 0, &face);
556 }
557 if(error) {
558 LV_LOG_WARN("create face error(%d)", error);
559 goto Fail;
560 }
561
562 /* link face and face info */
563 face->generic.data = dsc;
564 face->generic.finalizer = face_generic_finalizer;
565 face_add_to_list(face);
566 }
567 else {
568 FT_Size size;
569 FT_Error error = FT_New_Size(face, &size);
570 if(error) {
571 goto Fail;
572 }
573 FT_Activate_Size(size);
574 FT_Reference_Face(face);
575 }
576
577 FT_Set_Pixel_Sizes(face, 0, info->weight);
578 dsc->size = face->size;
579
580 lv_font_t * font = dsc->font;
581 font->dsc = dsc;
582 font->get_glyph_dsc = get_glyph_dsc_cb_nocache;
583 font->get_glyph_bitmap = get_glyph_bitmap_cb_nocache;
584 font->line_height = (face->size->metrics.height >> 6);
585 font->base_line = -(face->size->metrics.descender >> 6);
586 font->subpx = LV_FONT_SUBPX_NONE;
587
588 FT_Fixed scale = face->size->metrics.y_scale;
589 int8_t thickness = FT_MulFix(scale, face->underline_thickness) >> 6;
590 font->underline_position = FT_MulFix(scale, face->underline_position) >> 6;
591 font->underline_thickness = thickness < 1 ? 1 : thickness;
592
593 info->font = font;
594 return true;
595
596 Fail:
597 lv_mem_free(dsc);
598 return false;
599 }
600
lv_ft_font_destroy_nocache(lv_font_t * font)601 static void lv_ft_font_destroy_nocache(lv_font_t * font)
602 {
603 if(font == NULL) {
604 return;
605 }
606
607 lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->dsc);
608 if(dsc) {
609 FT_Face face = dsc->size->face;
610 FT_Done_Size(dsc->size);
611 FT_Done_Face(face);
612 name_refer_del(dsc->name);
613 lv_mem_free(dsc);
614 }
615 }
616
617 #endif/* LV_FREETYPE_CACHE_SIZE */
618
619 /**
620 * find name string in names list.name string cnt += 1 if find.
621 * @param name name string
622 * @return the string pointer of name.
623 */
name_refer_find(const char * name)624 static const char * name_refer_find(const char * name)
625 {
626 name_refer_t * refer = _lv_ll_get_head(&names_ll);
627 while(refer) {
628 if(strcmp(refer->name, name) == 0) {
629 refer->cnt += 1;
630 return refer->name;
631 }
632 refer = _lv_ll_get_next(&names_ll, refer);
633 }
634 return NULL;
635 }
636
637 /**
638 * del name string from list.
639 */
name_refer_del(const char * name)640 static void name_refer_del(const char * name)
641 {
642 name_refer_t * refer = _lv_ll_get_head(&names_ll);
643 while(refer) {
644 if(strcmp(refer->name, name) == 0) {
645 refer->cnt -= 1;
646 if(refer->cnt <= 0) {
647 _lv_ll_remove(&names_ll, refer);
648 lv_mem_free((void *)refer->name);
649 lv_mem_free(refer);
650 }
651 return;
652 }
653 refer = _lv_ll_get_next(&names_ll, refer);
654 }
655
656 LV_LOG_WARN("name_in_names_del error(not find:%p).", name);
657 }
658
659 /**
660 * save name string to list.
661 * @param name name string
662 * @return Saved string pointer
663 */
name_refer_save(const char * name)664 static const char * name_refer_save(const char * name)
665 {
666 const char * pos = name_refer_find(name);
667 if(pos) {
668 return pos;
669 }
670
671 name_refer_t * refer = _lv_ll_ins_tail(&names_ll);
672 if(refer) {
673 uint32_t len = strlen(name) + 1;
674 refer->name = lv_mem_alloc(len);
675 if(refer->name) {
676 lv_memcpy((void *)refer->name, name, len);
677 refer->cnt = 1;
678 return refer->name;
679 }
680 _lv_ll_remove(&names_ll, refer);
681 lv_mem_free(refer);
682 }
683 LV_LOG_WARN("save_name_to_names error(not memory).");
684 return "";
685 }
686
687 #endif /*LV_USE_FREETYPE*/
688