1 /**
2  * @file lv_font.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_font.h"
10 #include "lv_font_fmt_txt.h"
11 #include "../lv_misc/lv_types.h"
12 #include "../lv_misc/lv_log.h"
13 #include "../lv_misc/lv_utils.h"
14 
15 /*********************
16  *      DEFINES
17  *********************/
18 
19 /**********************
20  *      TYPEDEFS
21  **********************/
22 
23 /**********************
24  *  STATIC PROTOTYPES
25  **********************/
26 static uint32_t get_glyph_dsc_id(const lv_font_t * font, uint32_t letter);
27 static int8_t get_kern_value(const lv_font_t * font, uint32_t gid_left, uint32_t gid_right);
28 static int32_t unicode_list_compare(const void * ref, const void * element);
29 static int32_t kern_pair_8_compare(const void * ref, const void * element);
30 static int32_t kern_pair_16_compare(const void * ref, const void * element);
31 
32 /**********************
33  *  STATIC VARIABLES
34  **********************/
35 
36 /**********************
37  * GLOBAL PROTOTYPES
38  **********************/
39 
40 /**********************
41  *      MACROS
42  **********************/
43 
44 /**********************
45  *   GLOBAL FUNCTIONS
46  **********************/
47 
48 /**
49  * Used as `get_glyph_bitmap` callback in LittelvGL's native font format if the font is uncompressed.
50  * @param font pointer to font
51  * @param unicode_letter an unicode letter which bitmap should be get
52  * @return pointer to the bitmap or NULL if not found
53  */
lv_font_get_bitmap_fmt_txt(const lv_font_t * font,uint32_t unicode_letter)54 const uint8_t * lv_font_get_bitmap_fmt_txt(const lv_font_t * font, uint32_t unicode_letter)
55 {
56     lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *) font->dsc;
57     uint32_t gid = get_glyph_dsc_id(font, unicode_letter);
58     if(!gid) return false;
59 
60     const lv_font_fmt_txt_glyph_dsc_t * gdsc = &fdsc->glyph_dsc[gid];
61 
62     if(gdsc) return &fdsc->glyph_bitmap[gdsc->bitmap_index];
63 
64     /*If not returned earlier then the letter is not found in this font*/
65     return NULL;
66 }
67 
68 /**
69  * Used as `get_glyph_dsc` callback in LittelvGL's native font format if the font is uncompressed.
70  * @param font_p pointer to font
71  * @param dsc_out store the result descriptor here
72  * @param letter an UNICODE letter code
73  * @return true: descriptor is successfully loaded into `dsc_out`.
74  *         false: the letter was not found, no data is loaded to `dsc_out`
75  */
lv_font_get_glyph_dsc_fmt_txt(const lv_font_t * font,lv_font_glyph_dsc_t * dsc_out,uint32_t unicode_letter,uint32_t unicode_letter_next)76 bool lv_font_get_glyph_dsc_fmt_txt(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next)
77 {
78     lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *) font->dsc;
79     uint32_t gid = get_glyph_dsc_id(font, unicode_letter);
80     if(!gid) return false;
81 
82     int8_t kvalue = 0;
83     if(fdsc->kern_dsc) {
84         uint32_t gid_next = get_glyph_dsc_id(font, unicode_letter_next);
85         if(gid_next) {
86             kvalue = get_kern_value(font, gid, gid_next);
87         }
88     }
89 
90     /*Put together a glyph dsc*/
91     const lv_font_fmt_txt_glyph_dsc_t * gdsc = &fdsc->glyph_dsc[gid];
92 
93     uint32_t adv_w = gdsc->adv_w + ((int32_t)((int32_t)kvalue * fdsc->kern_scale) >> 4);
94     adv_w  = (adv_w + (1 << 3)) >> 4;
95 
96     dsc_out->adv_w = adv_w;
97     dsc_out->box_h = gdsc->box_h;
98     dsc_out->box_w = gdsc->box_w;
99     dsc_out->ofs_x = gdsc->ofs_x;
100     dsc_out->ofs_y = gdsc->ofs_y;
101     dsc_out->bpp   = fdsc->bpp;
102 
103     return true;
104 }
105 
106 /**********************
107  *   STATIC FUNCTIONS
108  **********************/
109 
get_glyph_dsc_id(const lv_font_t * font,uint32_t letter)110 static uint32_t get_glyph_dsc_id(const lv_font_t * font, uint32_t letter)
111 {
112     if(letter == '\0') return 0;
113 
114     lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *) font->dsc;
115 
116     /*Check the cache first*/
117     if(letter == fdsc->last_letter) return fdsc->last_glyph_id;
118 
119     uint16_t i;
120     for(i = 0; i < fdsc->cmap_num; i++) {
121 
122         /*Relative code point*/
123         uint32_t rcp = letter - fdsc->cmaps[i].range_start;
124         if(rcp > fdsc->cmaps[i].range_length) continue;
125         uint32_t glyph_id = 0;
126         if(fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY) {
127             glyph_id = fdsc->cmaps[i].glyph_id_start + rcp;
128         }
129         else if(fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_FORMAT0_FULL) {
130             const uint8_t * gid_ofs_8 = fdsc->cmaps[i].glyph_id_ofs_list;
131             glyph_id = fdsc->cmaps[i].glyph_id_start + gid_ofs_8[rcp];
132         }
133         else if(fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_SPARSE_TINY) {
134             uint8_t * p = lv_utils_bsearch(&rcp, fdsc->cmaps[i].unicode_list, fdsc->cmaps[i].list_length, sizeof(fdsc->cmaps[i].unicode_list[0]), unicode_list_compare);
135 
136             if(p) {
137                 uint32_t ofs = (lv_uintptr_t)p - (lv_uintptr_t) fdsc->cmaps[i].unicode_list;
138                 ofs = ofs >> 1;     /*The list stores `uint16_t` so the get the index divide by 2*/
139                 glyph_id = fdsc->cmaps[i].glyph_id_start + ofs;
140             }
141         }
142         else if(fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_SPARSE_FULL) {
143             uint8_t * p = lv_utils_bsearch(&rcp, fdsc->cmaps[i].unicode_list, fdsc->cmaps[i].list_length, sizeof(fdsc->cmaps[i].unicode_list[0]), unicode_list_compare);
144 
145             if(p) {
146                 uint32_t ofs = (lv_uintptr_t)p - (lv_uintptr_t) fdsc->cmaps[i].unicode_list;
147                 ofs = ofs >> 1;     /*The list stores `uint16_t` so the get the index divide by 2*/
148                 const uint8_t * gid_ofs_16 = fdsc->cmaps[i].glyph_id_ofs_list;
149                 glyph_id = fdsc->cmaps[i].glyph_id_start + gid_ofs_16[ofs];
150             }
151         }
152 
153         /*Update the cache*/
154         fdsc->last_letter = letter;
155         fdsc->last_glyph_id = glyph_id;
156         return glyph_id;
157     }
158 
159     fdsc->last_letter = letter;
160     fdsc->last_glyph_id = 0;
161     return 0;
162 
163 }
164 
get_kern_value(const lv_font_t * font,uint32_t gid_left,uint32_t gid_right)165 static int8_t get_kern_value(const lv_font_t * font, uint32_t gid_left, uint32_t gid_right)
166 {
167     lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *) font->dsc;
168 
169     int8_t value = 0;
170 
171     if(fdsc->kern_classes == 0) {
172         /*Kern pairs*/
173         const lv_font_fmt_txt_kern_pair_t * kdsc = fdsc->kern_dsc;
174         if(kdsc->glyph_ids_size == 0) {
175             /* Use binary search to find the kern value.
176              * The pairs are ordered left_id first, then right_id secondly. */
177             const uint8_t * g_ids = kdsc->glyph_ids;
178             uint16_t g_id_both = (gid_right << 8) + gid_left; /*Create one number from the ids*/
179             uint8_t * kid_p = lv_utils_bsearch(&g_id_both, g_ids, kdsc->pair_cnt, 2, kern_pair_8_compare);
180 
181             /*If the `g_id_both` were found get its index from the pointer*/
182             if(kid_p) {
183                 uint32_t ofs = (lv_uintptr_t)kid_p - (lv_uintptr_t)g_ids;
184                 ofs = ofs >> 1;     /*ofs is for pair, divide by 2 to refer as a single value*/
185                 value = kdsc->values[ofs];
186             }
187         } else if(kdsc->glyph_ids_size == 1) {
188             /* Use binary search to find the kern value.
189              * The pairs are ordered left_id first, then right_id secondly. */
190             const uint16_t * g_ids = kdsc->glyph_ids;
191             uint32_t g_id_both = (uint32_t)((uint32_t)gid_right << 8) + gid_left; /*Create one number from the ids*/
192             uint8_t * kid_p = lv_utils_bsearch(&g_id_both, g_ids, kdsc->pair_cnt, 4, kern_pair_16_compare);
193 
194             /*If the `g_id_both` were found get its index from the pointer*/
195             if(kid_p) {
196                 uint32_t ofs = (lv_uintptr_t)kid_p - (lv_uintptr_t)g_ids;
197                 ofs = ofs >> 4;     /*ofs is 4 byte pairs, divide by 4 to refer as a single value*/
198                 value = kdsc->values[ofs];
199             }
200 
201         } else {
202             /*Invalid value*/
203         }
204     } else {
205         /*Kern classes*/
206         const lv_font_fmt_txt_kern_classes_t * kdsc = fdsc->kern_dsc;
207         uint8_t left_class = kdsc->left_class_mapping[gid_left];
208         uint8_t right_class = kdsc->left_class_mapping[gid_right];
209 
210         /* If class = 0, kerning not exist for that glyph
211          * else got the value form `class_pair_values` 2D array*/
212         if(left_class > 0 && right_class > 0) {
213             value = kdsc->class_pair_values[(left_class-1)* kdsc->right_class_cnt + (right_class-1)];
214         }
215 
216     }
217     return value;
218 }
219 
kern_pair_8_compare(const void * ref,const void * element)220 static int32_t kern_pair_8_compare(const void * ref, const void * element)
221 {
222     const uint8_t * ref8_p = ref;
223     const uint8_t * element8_p = element;
224 
225     /*If the MSB is different it will matter. If not return the diff. of the LSB*/
226     if(ref8_p[0] != element8_p[0]) return (int32_t)ref8_p[0] - element8_p[0];
227     else return (int32_t) ref8_p[1] - element8_p[1];
228 
229 }
230 
kern_pair_16_compare(const void * ref,const void * element)231 static int32_t kern_pair_16_compare(const void * ref, const void * element)
232 {
233     const uint16_t * ref16_p = ref;
234     const uint16_t * element16_p = element;
235 
236     /*If the MSB is different it will matter. If not return the diff. of the LSB*/
237     if(ref16_p[0] != element16_p[0]) return (int32_t)ref16_p[0] - element16_p[0];
238     else return (int32_t) ref16_p[1] - element16_p[1];
239 }
240 
241 /** Code Comparator.
242  *
243  *  Compares the value of both input arguments.
244  *
245  *  @param[in]  pRef        Pointer to the reference.
246  *  @param[in]  pElement    Pointer to the element to compare.
247  *
248  *  @return Result of comparison.
249  *  @retval < 0   Reference is greater than element.
250  *  @retval = 0   Reference is equal to element.
251  *  @retval > 0   Reference is less than element.
252  *
253  */
unicode_list_compare(const void * ref,const void * element)254 static int32_t unicode_list_compare(const void * ref, const void * element)
255 {
256     return (*(uint16_t *)ref) - (*(uint16_t *)element);
257 }
258