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