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_debug.h"
12 #include "../lv_draw/lv_draw.h"
13 #include "../lv_misc/lv_types.h"
14 #include "../lv_misc/lv_gc.h"
15 #include "../lv_misc/lv_log.h"
16 #include "../lv_misc/lv_utils.h"
17 #include "../lv_misc/lv_mem.h"
18 
19 #if defined(LV_GC_INCLUDE)
20     #include LV_GC_INCLUDE
21 #endif /* LV_ENABLE_GC */
22 
23 /*********************
24  *      DEFINES
25  *********************/
26 
27 /**********************
28  *      TYPEDEFS
29  **********************/
30 typedef enum {
31     RLE_STATE_SINGLE = 0,
32     RLE_STATE_REPEATE,
33     RLE_STATE_COUNTER,
34 } rle_state_t;
35 
36 /**********************
37  *  STATIC PROTOTYPES
38  **********************/
39 static uint32_t get_glyph_dsc_id(const lv_font_t * font, uint32_t letter);
40 static int8_t get_kern_value(const lv_font_t * font, uint32_t gid_left, uint32_t gid_right);
41 static int32_t unicode_list_compare(const void * ref, const void * element);
42 static int32_t kern_pair_8_compare(const void * ref, const void * element);
43 static int32_t kern_pair_16_compare(const void * ref, const void * element);
44 
45 #if LV_USE_FONT_COMPRESSED
46 static void decompress(const uint8_t * in, uint8_t * out, lv_coord_t w, lv_coord_t h, uint8_t bpp, bool prefilter);
47 static inline void decompress_line(uint8_t * out, lv_coord_t w);
48 static inline uint8_t get_bits(const uint8_t * in, uint32_t bit_pos, uint8_t len);
49 static inline void bits_write(uint8_t * out, uint32_t bit_pos, uint8_t val, uint8_t len);
50 static inline void rle_init(const uint8_t * in,  uint8_t bpp);
51 static inline uint8_t rle_next(void);
52 #endif /* LV_USE_FONT_COMPRESSED */
53 
54 /**********************
55  *  STATIC VARIABLES
56  **********************/
57 #if LV_USE_FONT_COMPRESSED
58 static uint32_t rle_rdp;
59 static const uint8_t * rle_in;
60 static uint8_t rle_bpp;
61 static uint8_t rle_prev_v;
62 static uint8_t rle_cnt;
63 static rle_state_t rle_state;
64 #endif /* LV_USE_FONT_COMPRESSED */
65 
66 /**********************
67  * GLOBAL PROTOTYPES
68  **********************/
69 
70 /**********************
71  *      MACROS
72  **********************/
73 
74 /**********************
75  *   GLOBAL FUNCTIONS
76  **********************/
77 
78 /**
79  * Used as `get_glyph_bitmap` callback in LittelvGL's native font format if the font is uncompressed.
80  * @param font pointer to font
81  * @param unicode_letter an unicode letter which bitmap should be get
82  * @return pointer to the bitmap or NULL if not found
83  */
lv_font_get_bitmap_fmt_txt(const lv_font_t * font,uint32_t unicode_letter)84 const uint8_t * lv_font_get_bitmap_fmt_txt(const lv_font_t * font, uint32_t unicode_letter)
85 {
86     if(unicode_letter == '\t') unicode_letter = ' ';
87 
88     lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *) font->dsc;
89     uint32_t gid = get_glyph_dsc_id(font, unicode_letter);
90     if(!gid) return NULL;
91 
92     const lv_font_fmt_txt_glyph_dsc_t * gdsc = &fdsc->glyph_dsc[gid];
93 
94     if(fdsc->bitmap_format == LV_FONT_FMT_TXT_PLAIN) {
95         if(gdsc) return &fdsc->glyph_bitmap[gdsc->bitmap_index];
96     }
97     /*Handle compressed bitmap*/
98     else {
99 #if LV_USE_FONT_COMPRESSED
100         uint32_t gsize = gdsc->box_w * gdsc->box_h;
101         if(gsize == 0) return NULL;
102 
103         uint32_t buf_size = gsize;
104         /*Compute memory size needed to hold decompressed glyph, rounding up*/
105         switch(fdsc->bpp) {
106             case 1:
107                 buf_size = (gsize + 7) >> 3;
108                 break;
109             case 2:
110                 buf_size = (gsize + 3) >> 2;
111                 break;
112             case 3:
113                 buf_size = (gsize + 1) >> 1;
114                 break;
115             case 4:
116                 buf_size = (gsize + 1) >> 1;
117                 break;
118         }
119 
120         if(_lv_mem_get_size(LV_GC_ROOT(_lv_font_decompr_buf)) < buf_size) {
121             LV_GC_ROOT(_lv_font_decompr_buf) = lv_mem_realloc(LV_GC_ROOT(_lv_font_decompr_buf), buf_size);
122             LV_ASSERT_MEM(LV_GC_ROOT(_lv_font_decompr_buf));
123             if(LV_GC_ROOT(_lv_font_decompr_buf) == NULL) return NULL;
124         }
125 
126         bool prefilter = fdsc->bitmap_format == LV_FONT_FMT_TXT_COMPRESSED ? true : false;
127         decompress(&fdsc->glyph_bitmap[gdsc->bitmap_index], LV_GC_ROOT(_lv_font_decompr_buf), gdsc->box_w, gdsc->box_h,
128                    (uint8_t)fdsc->bpp,
129                    prefilter);
130         return LV_GC_ROOT(_lv_font_decompr_buf);
131 #else /* !LV_USE_FONT_COMPRESSED */
132         return NULL;
133 #endif
134     }
135 
136     /*If not returned earlier then the letter is not found in this font*/
137     return NULL;
138 }
139 
140 /**
141  * Used as `get_glyph_dsc` callback in LittelvGL's native font format if the font is uncompressed.
142  * @param font_p pointer to font
143  * @param dsc_out store the result descriptor here
144  * @param letter an UNICODE letter code
145  * @return true: descriptor is successfully loaded into `dsc_out`.
146  *         false: the letter was not found, no data is loaded to `dsc_out`
147  */
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)148 bool lv_font_get_glyph_dsc_fmt_txt(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter,
149                                    uint32_t unicode_letter_next)
150 {
151     bool is_tab = false;
152     if(unicode_letter == '\t') {
153         unicode_letter = ' ';
154         is_tab = true;
155     }
156     lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *) font->dsc;
157     uint32_t gid = get_glyph_dsc_id(font, unicode_letter);
158     if(!gid) return false;
159 
160     int8_t kvalue = 0;
161     if(fdsc->kern_dsc) {
162         uint32_t gid_next = get_glyph_dsc_id(font, unicode_letter_next);
163         if(gid_next) {
164             kvalue = get_kern_value(font, gid, gid_next);
165         }
166     }
167 
168     /*Put together a glyph dsc*/
169     const lv_font_fmt_txt_glyph_dsc_t * gdsc = &fdsc->glyph_dsc[gid];
170 
171     int32_t kv = ((int32_t)((int32_t)kvalue * fdsc->kern_scale) >> 4);
172 
173     uint32_t adv_w = gdsc->adv_w;
174     if(is_tab) adv_w *= 2;
175 
176     adv_w += kv;
177     adv_w  = (adv_w + (1 << 3)) >> 4;
178 
179     dsc_out->adv_w = adv_w;
180     dsc_out->box_h = gdsc->box_h;
181     dsc_out->box_w = gdsc->box_w;
182     dsc_out->ofs_x = gdsc->ofs_x;
183     dsc_out->ofs_y = gdsc->ofs_y;
184     dsc_out->bpp   = (uint8_t)fdsc->bpp;
185 
186     if(is_tab) dsc_out->box_w = dsc_out->box_w * 2;
187 
188     return true;
189 }
190 
191 /**
192  * Free the allocated memories.
193  */
_lv_font_clean_up_fmt_txt(void)194 void _lv_font_clean_up_fmt_txt(void)
195 {
196     if(LV_GC_ROOT(_lv_font_decompr_buf)) {
197         lv_mem_free(LV_GC_ROOT(_lv_font_decompr_buf));
198         LV_GC_ROOT(_lv_font_decompr_buf) = NULL;
199     }
200 }
201 
202 
203 /**********************
204  *   STATIC FUNCTIONS
205  **********************/
206 
get_glyph_dsc_id(const lv_font_t * font,uint32_t letter)207 static uint32_t get_glyph_dsc_id(const lv_font_t * font, uint32_t letter)
208 {
209     if(letter == '\0') return 0;
210 
211     lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *) font->dsc;
212 
213     /*Check the cache first*/
214     if(letter == fdsc->last_letter) return fdsc->last_glyph_id;
215 
216     uint16_t i;
217     for(i = 0; i < fdsc->cmap_num; i++) {
218 
219         /*Relative code point*/
220         uint32_t rcp = letter - fdsc->cmaps[i].range_start;
221         if(rcp > fdsc->cmaps[i].range_length) continue;
222         uint32_t glyph_id = 0;
223         if(fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY) {
224             glyph_id = fdsc->cmaps[i].glyph_id_start + rcp;
225         }
226         else if(fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_FORMAT0_FULL) {
227             const uint8_t * gid_ofs_8 = fdsc->cmaps[i].glyph_id_ofs_list;
228             glyph_id = fdsc->cmaps[i].glyph_id_start + gid_ofs_8[rcp];
229         }
230         else if(fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_SPARSE_TINY) {
231             uint16_t key = rcp;
232             uint8_t * p = _lv_utils_bsearch(&key, fdsc->cmaps[i].unicode_list, fdsc->cmaps[i].list_length,
233                                             sizeof(fdsc->cmaps[i].unicode_list[0]), unicode_list_compare);
234 
235             if(p) {
236                 lv_uintptr_t ofs = (lv_uintptr_t)(p - (uint8_t *) fdsc->cmaps[i].unicode_list);
237                 ofs = ofs >> 1;     /*The list stores `uint16_t` so the get the index divide by 2*/
238                 glyph_id = fdsc->cmaps[i].glyph_id_start + ofs;
239             }
240         }
241         else if(fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_SPARSE_FULL) {
242             uint16_t key = rcp;
243             uint8_t * p = _lv_utils_bsearch(&key, fdsc->cmaps[i].unicode_list, fdsc->cmaps[i].list_length,
244                                             sizeof(fdsc->cmaps[i].unicode_list[0]), unicode_list_compare);
245 
246             if(p) {
247                 lv_uintptr_t ofs = (lv_uintptr_t)(p - (uint8_t *) fdsc->cmaps[i].unicode_list);
248                 ofs = ofs >> 1;     /*The list stores `uint16_t` so the get the index divide by 2*/
249                 const uint8_t * gid_ofs_16 = fdsc->cmaps[i].glyph_id_ofs_list;
250                 glyph_id = fdsc->cmaps[i].glyph_id_start + gid_ofs_16[ofs];
251             }
252         }
253 
254         /*Update the cache*/
255         fdsc->last_letter = letter;
256         fdsc->last_glyph_id = glyph_id;
257         return glyph_id;
258     }
259 
260     fdsc->last_letter = letter;
261     fdsc->last_glyph_id = 0;
262     return 0;
263 
264 }
265 
get_kern_value(const lv_font_t * font,uint32_t gid_left,uint32_t gid_right)266 static int8_t get_kern_value(const lv_font_t * font, uint32_t gid_left, uint32_t gid_right)
267 {
268     lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *) font->dsc;
269 
270     int8_t value = 0;
271 
272     if(fdsc->kern_classes == 0) {
273         /*Kern pairs*/
274         const lv_font_fmt_txt_kern_pair_t * kdsc = fdsc->kern_dsc;
275         if(kdsc->glyph_ids_size == 0) {
276             /* Use binary search to find the kern value.
277              * The pairs are ordered left_id first, then right_id secondly. */
278             const uint8_t * g_ids = kdsc->glyph_ids;
279             uint16_t g_id_both = (gid_right << 8) + gid_left; /*Create one number from the ids*/
280             uint8_t * kid_p = _lv_utils_bsearch(&g_id_both, g_ids, kdsc->pair_cnt, 2, kern_pair_8_compare);
281 
282             /*If the `g_id_both` were found get its index from the pointer*/
283             if(kid_p) {
284                 lv_uintptr_t ofs = (lv_uintptr_t)(kid_p - g_ids);
285                 ofs = ofs >> 1;     /*ofs is for pair, divide by 2 to refer as a single value*/
286                 value = kdsc->values[ofs];
287             }
288         }
289         else if(kdsc->glyph_ids_size == 1) {
290             /* Use binary search to find the kern value.
291              * The pairs are ordered left_id first, then right_id secondly. */
292             const uint16_t * g_ids = kdsc->glyph_ids;
293             lv_uintptr_t g_id_both = (uint32_t)((uint32_t)gid_right << 8) + gid_left; /*Create one number from the ids*/
294             uint8_t * kid_p = _lv_utils_bsearch(&g_id_both, g_ids, kdsc->pair_cnt, 4, kern_pair_16_compare);
295 
296             /*If the `g_id_both` were found get its index from the pointer*/
297             if(kid_p) {
298                 lv_uintptr_t ofs = (lv_uintptr_t)(kid_p - (const uint8_t *)g_ids);
299                 ofs = ofs >> 4;     /*ofs is 4 byte pairs, divide by 4 to refer as a single value*/
300                 value = kdsc->values[ofs];
301             }
302 
303         }
304         else {
305             /*Invalid value*/
306         }
307     }
308     else {
309         /*Kern classes*/
310         const lv_font_fmt_txt_kern_classes_t * kdsc = fdsc->kern_dsc;
311         uint8_t left_class = kdsc->left_class_mapping[gid_left];
312         uint8_t right_class = kdsc->right_class_mapping[gid_right];
313 
314         /* If class = 0, kerning not exist for that glyph
315          * else got the value form `class_pair_values` 2D array*/
316         if(left_class > 0 && right_class > 0) {
317             value = kdsc->class_pair_values[(left_class - 1) * kdsc->right_class_cnt + (right_class - 1)];
318         }
319 
320     }
321     return value;
322 }
323 
kern_pair_8_compare(const void * ref,const void * element)324 static int32_t kern_pair_8_compare(const void * ref, const void * element)
325 {
326     const uint8_t * ref8_p = ref;
327     const uint8_t * element8_p = element;
328 
329     /*If the MSB is different it will matter. If not return the diff. of the LSB*/
330     if(ref8_p[0] != element8_p[0]) return (int32_t)ref8_p[0] - element8_p[0];
331     else return (int32_t) ref8_p[1] - element8_p[1];
332 
333 }
334 
kern_pair_16_compare(const void * ref,const void * element)335 static int32_t kern_pair_16_compare(const void * ref, const void * element)
336 {
337     const uint16_t * ref16_p = ref;
338     const uint16_t * element16_p = element;
339 
340     /*If the MSB is different it will matter. If not return the diff. of the LSB*/
341     if(ref16_p[0] != element16_p[0]) return (int32_t)ref16_p[0] - element16_p[0];
342     else return (int32_t) ref16_p[1] - element16_p[1];
343 }
344 
345 #if LV_USE_FONT_COMPRESSED
346 /**
347  * The compress a glyph's bitmap
348  * @param in the compressed bitmap
349  * @param out buffer to store the result
350  * @param px_num number of pixels in the glyph (width * height)
351  * @param bpp bit per pixel (bpp = 3 will be converted to bpp = 4)
352  * @param prefilter true: the lines are XORed
353  */
decompress(const uint8_t * in,uint8_t * out,lv_coord_t w,lv_coord_t h,uint8_t bpp,bool prefilter)354 static void decompress(const uint8_t * in, uint8_t * out, lv_coord_t w, lv_coord_t h, uint8_t bpp, bool prefilter)
355 {
356     uint32_t wrp = 0;
357     uint8_t wr_size = bpp;
358     if(bpp == 3) wr_size = 4;
359 
360     rle_init(in, bpp);
361 
362     uint8_t * line_buf1 = _lv_mem_buf_get(w);
363 
364     uint8_t * line_buf2 = NULL;
365 
366     if(prefilter) {
367         line_buf2 = _lv_mem_buf_get(w);
368     }
369 
370     decompress_line(line_buf1, w);
371 
372     lv_coord_t y;
373     lv_coord_t x;
374 
375     for(x = 0; x < w; x++) {
376         bits_write(out, wrp, line_buf1[x], bpp);
377         wrp += wr_size;
378     }
379 
380     for(y = 1; y < h; y++) {
381         if(prefilter) {
382             decompress_line(line_buf2, w);
383 
384             for(x = 0; x < w; x++) {
385                 line_buf1[x] = line_buf2[x] ^ line_buf1[x];
386                 bits_write(out, wrp, line_buf1[x], bpp);
387                 wrp += wr_size;
388             }
389         }
390         else {
391             decompress_line(line_buf1, w);
392 
393             for(x = 0; x < w; x++) {
394                 bits_write(out, wrp, line_buf1[x], bpp);
395                 wrp += wr_size;
396             }
397         }
398     }
399 
400     _lv_mem_buf_release(line_buf1);
401     _lv_mem_buf_release(line_buf2);
402 }
403 
404 /**
405  * Decompress one line. Store one pixel per byte
406  * @param out output buffer
407  * @param w width of the line in pixel count
408  */
decompress_line(uint8_t * out,lv_coord_t w)409 static inline void decompress_line(uint8_t * out, lv_coord_t w)
410 {
411     lv_coord_t i;
412     for(i = 0; i < w; i++) {
413         out[i] = rle_next();
414     }
415 }
416 
417 /**
418  * Read bits from an input buffer. The read can cross byte boundary.
419  * @param in the input buffer to read from.
420  * @param bit_pos index of the first bit to read.
421  * @param len number of bits to read (must be <= 8).
422  * @return the read bits
423  */
get_bits(const uint8_t * in,uint32_t bit_pos,uint8_t len)424 static inline uint8_t get_bits(const uint8_t * in, uint32_t bit_pos, uint8_t len)
425 {
426     uint8_t bit_mask;
427     switch(len) {
428         case 1:
429             bit_mask = 0x1;
430             break;
431         case 2:
432             bit_mask = 0x3;
433             break;
434         case 3:
435             bit_mask = 0x7;
436             break;
437         case 4:
438             bit_mask = 0xF;
439             break;
440         case 8:
441             bit_mask = 0xFF;
442             break;
443         default:
444             bit_mask = (uint16_t)((uint16_t) 1 << len) - 1;
445     }
446 
447     uint32_t byte_pos = bit_pos >> 3;
448     bit_pos = bit_pos & 0x7;
449 
450     if(bit_pos + len >= 8) {
451         uint16_t in16 = (in[byte_pos] << 8) + in[byte_pos + 1];
452         return (in16 >> (16 - bit_pos - len)) & bit_mask;
453     }
454     else {
455         return (in[byte_pos] >> (8 - bit_pos - len)) & bit_mask;
456     }
457 }
458 
459 /**
460  * Write `val` data to `bit_pos` position of `out`. The write can NOT cross byte boundary.
461  * @param out buffer where to write
462  * @param bit_pos bit index to write
463  * @param val value to write
464  * @param len length of bits to write from `val`. (Counted from the LSB).
465  * @note `len == 3` will be converted to `len = 4` and `val` will be upscaled too
466  */
bits_write(uint8_t * out,uint32_t bit_pos,uint8_t val,uint8_t len)467 static inline void bits_write(uint8_t * out, uint32_t bit_pos, uint8_t val, uint8_t len)
468 {
469     if(len == 3) {
470         len = 4;
471         switch(val) {
472             case 0:
473                 val = 0;
474                 break;
475             case 1:
476                 val = 2;
477                 break;
478             case 2:
479                 val = 4;
480                 break;
481             case 3:
482                 val = 6;
483                 break;
484             case 4:
485                 val = 9;
486                 break;
487             case 5:
488                 val = 11;
489                 break;
490             case 6:
491                 val = 13;
492                 break;
493             case 7:
494                 val = 15;
495                 break;
496         }
497     }
498 
499     uint16_t byte_pos = bit_pos >> 3;
500     bit_pos = bit_pos & 0x7;
501     bit_pos = 8 - bit_pos - len;
502 
503     uint8_t bit_mask = (uint16_t)((uint16_t) 1 << len) - 1;
504     out[byte_pos] &= ((~bit_mask) << bit_pos);
505     out[byte_pos] |= (val << bit_pos);
506 }
507 
rle_init(const uint8_t * in,uint8_t bpp)508 static inline void rle_init(const uint8_t * in,  uint8_t bpp)
509 {
510     rle_in = in;
511     rle_bpp = bpp;
512     rle_state = RLE_STATE_SINGLE;
513     rle_rdp = 0;
514     rle_prev_v = 0;
515     rle_cnt = 0;
516 }
517 
rle_next(void)518 static inline uint8_t rle_next(void)
519 {
520     uint8_t v = 0;
521     uint8_t ret = 0;
522 
523     if(rle_state == RLE_STATE_SINGLE) {
524         ret = get_bits(rle_in, rle_rdp, rle_bpp);
525         if(rle_rdp != 0 && rle_prev_v == ret) {
526             rle_cnt = 0;
527             rle_state = RLE_STATE_REPEATE;
528         }
529 
530         rle_prev_v = ret;
531         rle_rdp += rle_bpp;
532     }
533     else if(rle_state == RLE_STATE_REPEATE) {
534         v = get_bits(rle_in, rle_rdp, 1);
535         rle_cnt++;
536         rle_rdp += 1;
537         if(v == 1) {
538             ret = rle_prev_v;
539             if(rle_cnt == 11) {
540                 rle_cnt = get_bits(rle_in, rle_rdp, 6);
541                 rle_rdp += 6;
542                 if(rle_cnt != 0) {
543                     rle_state = RLE_STATE_COUNTER;
544                 }
545                 else {
546                     ret = get_bits(rle_in, rle_rdp, rle_bpp);
547                     rle_prev_v = ret;
548                     rle_rdp += rle_bpp;
549                     rle_state = RLE_STATE_SINGLE;
550                 }
551             }
552         }
553         else {
554             ret = get_bits(rle_in, rle_rdp, rle_bpp);
555             rle_prev_v = ret;
556             rle_rdp += rle_bpp;
557             rle_state = RLE_STATE_SINGLE;
558         }
559 
560 
561     }
562     else if(rle_state == RLE_STATE_COUNTER) {
563         ret = rle_prev_v;
564         rle_cnt--;
565         if(rle_cnt == 0) {
566             ret = get_bits(rle_in, rle_rdp, rle_bpp);
567             rle_prev_v = ret;
568             rle_rdp += rle_bpp;
569             rle_state = RLE_STATE_SINGLE;
570         }
571     }
572 
573     return ret;
574 }
575 #endif /* LV_USE_FONT_COMPRESSED */
576 
577 /** Code Comparator.
578  *
579  *  Compares the value of both input arguments.
580  *
581  *  @param[in]  pRef        Pointer to the reference.
582  *  @param[in]  pElement    Pointer to the element to compare.
583  *
584  *  @return Result of comparison.
585  *  @retval < 0   Reference is greater than element.
586  *  @retval = 0   Reference is equal to element.
587  *  @retval > 0   Reference is less than element.
588  *
589  */
unicode_list_compare(const void * ref,const void * element)590 static int32_t unicode_list_compare(const void * ref, const void * element)
591 {
592     return ((int32_t)(*(uint16_t *)ref)) - ((int32_t)(*(uint16_t *)element));
593 }
594