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