1 /**
2  * @file lv_font_loader.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #include <stdint.h>
11 #include <stdbool.h>
12 
13 #include "../lvgl.h"
14 #include "../misc/lv_fs.h"
15 #include "lv_font_loader.h"
16 
17 /**********************
18  *      TYPEDEFS
19  **********************/
20 typedef struct {
21     lv_fs_file_t * fp;
22     int8_t bit_pos;
23     uint8_t byte_value;
24 } bit_iterator_t;
25 
26 typedef struct font_header_bin {
27     uint32_t version;
28     uint16_t tables_count;
29     uint16_t font_size;
30     uint16_t ascent;
31     int16_t descent;
32     uint16_t typo_ascent;
33     int16_t typo_descent;
34     uint16_t typo_line_gap;
35     int16_t min_y;
36     int16_t max_y;
37     uint16_t default_advance_width;
38     uint16_t kerning_scale;
39     uint8_t index_to_loc_format;
40     uint8_t glyph_id_format;
41     uint8_t advance_width_format;
42     uint8_t bits_per_pixel;
43     uint8_t xy_bits;
44     uint8_t wh_bits;
45     uint8_t advance_width_bits;
46     uint8_t compression_id;
47     uint8_t subpixels_mode;
48     uint8_t padding;
49     int16_t underline_position;
50     uint16_t underline_thickness;
51 } font_header_bin_t;
52 
53 typedef struct cmap_table_bin {
54     uint32_t data_offset;
55     uint32_t range_start;
56     uint16_t range_length;
57     uint16_t glyph_id_start;
58     uint16_t data_entries_count;
59     uint8_t format_type;
60     uint8_t padding;
61 } cmap_table_bin_t;
62 
63 /**********************
64  *  STATIC PROTOTYPES
65  **********************/
66 static bit_iterator_t init_bit_iterator(lv_fs_file_t * fp);
67 static bool lvgl_load_font(lv_fs_file_t * fp, lv_font_t * font);
68 int32_t load_kern(lv_fs_file_t * fp, lv_font_fmt_txt_dsc_t * font_dsc, uint8_t format, uint32_t start);
69 
70 static int read_bits_signed(bit_iterator_t * it, int n_bits, lv_fs_res_t * res);
71 static unsigned int read_bits(bit_iterator_t * it, int n_bits, lv_fs_res_t * res);
72 
73 /**********************
74  *      MACROS
75  **********************/
76 
77 /**********************
78  *   GLOBAL FUNCTIONS
79  **********************/
80 
81 /**
82  * Loads a `lv_font_t` object from a binary font file
83  * @param font_name filename where the font file is located
84  * @return a pointer to the font or NULL in case of error
85  */
lv_font_load(const char * font_name)86 lv_font_t * lv_font_load(const char * font_name)
87 {
88     lv_fs_file_t file;
89     lv_fs_res_t res = lv_fs_open(&file, font_name, LV_FS_MODE_RD);
90     if(res != LV_FS_RES_OK)
91         return NULL;
92 
93     lv_font_t * font = lv_mem_alloc(sizeof(lv_font_t));
94     if(font) {
95         memset(font, 0, sizeof(lv_font_t));
96         if(!lvgl_load_font(&file, font)) {
97             LV_LOG_WARN("Error loading font file: %s\n", font_name);
98             /*
99             * When `lvgl_load_font` fails it can leak some pointers.
100             * All non-null pointers can be assumed as allocated and
101             * `lv_font_free` should free them correctly.
102             */
103             lv_font_free(font);
104             font = NULL;
105         }
106     }
107 
108     lv_fs_close(&file);
109 
110     return font;
111 }
112 
113 /**
114  * Frees the memory allocated by the `lv_font_load()` function
115  * @param font lv_font_t object created by the lv_font_load function
116  */
lv_font_free(lv_font_t * font)117 void lv_font_free(lv_font_t * font)
118 {
119     if(NULL != font) {
120         lv_font_fmt_txt_dsc_t * dsc = (lv_font_fmt_txt_dsc_t *)font->dsc;
121 
122         if(NULL != dsc) {
123 
124             if(dsc->kern_classes == 0) {
125                 lv_font_fmt_txt_kern_pair_t * kern_dsc =
126                     (lv_font_fmt_txt_kern_pair_t *)dsc->kern_dsc;
127 
128                 if(NULL != kern_dsc) {
129                     if(kern_dsc->glyph_ids)
130                         lv_mem_free((void *)kern_dsc->glyph_ids);
131 
132                     if(kern_dsc->values)
133                         lv_mem_free((void *)kern_dsc->values);
134 
135                     lv_mem_free((void *)kern_dsc);
136                 }
137             }
138             else {
139                 lv_font_fmt_txt_kern_classes_t * kern_dsc =
140                     (lv_font_fmt_txt_kern_classes_t *)dsc->kern_dsc;
141 
142                 if(NULL != kern_dsc) {
143                     if(kern_dsc->class_pair_values)
144                         lv_mem_free((void *)kern_dsc->class_pair_values);
145 
146                     if(kern_dsc->left_class_mapping)
147                         lv_mem_free((void *)kern_dsc->left_class_mapping);
148 
149                     if(kern_dsc->right_class_mapping)
150                         lv_mem_free((void *)kern_dsc->right_class_mapping);
151 
152                     lv_mem_free((void *)kern_dsc);
153                 }
154             }
155 
156             lv_font_fmt_txt_cmap_t * cmaps =
157                 (lv_font_fmt_txt_cmap_t *)dsc->cmaps;
158 
159             if(NULL != cmaps) {
160                 for(int i = 0; i < dsc->cmap_num; ++i) {
161                     if(NULL != cmaps[i].glyph_id_ofs_list)
162                         lv_mem_free((void *)cmaps[i].glyph_id_ofs_list);
163                     if(NULL != cmaps[i].unicode_list)
164                         lv_mem_free((void *)cmaps[i].unicode_list);
165                 }
166                 lv_mem_free(cmaps);
167             }
168 
169             if(NULL != dsc->glyph_bitmap) {
170                 lv_mem_free((void *)dsc->glyph_bitmap);
171             }
172             if(NULL != dsc->glyph_dsc) {
173                 lv_mem_free((void *)dsc->glyph_dsc);
174             }
175             lv_mem_free(dsc);
176         }
177         lv_mem_free(font);
178     }
179 }
180 
181 /**********************
182  *   STATIC FUNCTIONS
183  **********************/
184 
init_bit_iterator(lv_fs_file_t * fp)185 static bit_iterator_t init_bit_iterator(lv_fs_file_t * fp)
186 {
187     bit_iterator_t it;
188     it.fp = fp;
189     it.bit_pos = -1;
190     it.byte_value = 0;
191     return it;
192 }
193 
read_bits(bit_iterator_t * it,int n_bits,lv_fs_res_t * res)194 static unsigned int read_bits(bit_iterator_t * it, int n_bits, lv_fs_res_t * res)
195 {
196     unsigned int value = 0;
197     while(n_bits--) {
198         it->byte_value = it->byte_value << 1;
199         it->bit_pos--;
200 
201         if(it->bit_pos < 0) {
202             it->bit_pos = 7;
203             *res = lv_fs_read(it->fp, &(it->byte_value), 1, NULL);
204             if(*res != LV_FS_RES_OK) {
205                 return 0;
206             }
207         }
208         int8_t bit = (it->byte_value & 0x80) ? 1 : 0;
209 
210         value |= (bit << n_bits);
211     }
212     *res = LV_FS_RES_OK;
213     return value;
214 }
215 
read_bits_signed(bit_iterator_t * it,int n_bits,lv_fs_res_t * res)216 static int read_bits_signed(bit_iterator_t * it, int n_bits, lv_fs_res_t * res)
217 {
218     unsigned int value = read_bits(it, n_bits, res);
219     if(value & (1 << (n_bits - 1))) {
220         value |= ~0u << n_bits;
221     }
222     return value;
223 }
224 
read_label(lv_fs_file_t * fp,int start,const char * label)225 static int read_label(lv_fs_file_t * fp, int start, const char * label)
226 {
227     lv_fs_seek(fp, start, LV_FS_SEEK_SET);
228 
229     uint32_t length;
230     char buf[4];
231 
232     if(lv_fs_read(fp, &length, 4, NULL) != LV_FS_RES_OK
233        || lv_fs_read(fp, buf, 4, NULL) != LV_FS_RES_OK
234        || memcmp(label, buf, 4) != 0) {
235         LV_LOG_WARN("Error reading '%s' label.", label);
236         return -1;
237     }
238 
239     return length;
240 }
241 
load_cmaps_tables(lv_fs_file_t * fp,lv_font_fmt_txt_dsc_t * font_dsc,uint32_t cmaps_start,cmap_table_bin_t * cmap_table)242 static bool load_cmaps_tables(lv_fs_file_t * fp, lv_font_fmt_txt_dsc_t * font_dsc,
243                               uint32_t cmaps_start, cmap_table_bin_t * cmap_table)
244 {
245     if(lv_fs_read(fp, cmap_table, font_dsc->cmap_num * sizeof(cmap_table_bin_t), NULL) != LV_FS_RES_OK) {
246         return false;
247     }
248 
249     for(unsigned int i = 0; i < font_dsc->cmap_num; ++i) {
250         lv_fs_res_t res = lv_fs_seek(fp, cmaps_start + cmap_table[i].data_offset, LV_FS_SEEK_SET);
251         if(res != LV_FS_RES_OK) {
252             return false;
253         }
254 
255         lv_font_fmt_txt_cmap_t * cmap = (lv_font_fmt_txt_cmap_t *) & (font_dsc->cmaps[i]);
256 
257         cmap->range_start = cmap_table[i].range_start;
258         cmap->range_length = cmap_table[i].range_length;
259         cmap->glyph_id_start = cmap_table[i].glyph_id_start;
260         cmap->type = cmap_table[i].format_type;
261 
262         switch(cmap_table[i].format_type) {
263             case LV_FONT_FMT_TXT_CMAP_FORMAT0_FULL: {
264                     uint8_t ids_size = sizeof(uint8_t) * cmap_table[i].data_entries_count;
265                     uint8_t * glyph_id_ofs_list = lv_mem_alloc(ids_size);
266 
267                     cmap->glyph_id_ofs_list = glyph_id_ofs_list;
268 
269                     if(lv_fs_read(fp, glyph_id_ofs_list, ids_size, NULL) != LV_FS_RES_OK) {
270                         return false;
271                     }
272 
273                     cmap->list_length = cmap->range_length;
274                     break;
275                 }
276             case LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY:
277                 break;
278             case LV_FONT_FMT_TXT_CMAP_SPARSE_FULL:
279             case LV_FONT_FMT_TXT_CMAP_SPARSE_TINY: {
280                     uint32_t list_size = sizeof(uint16_t) * cmap_table[i].data_entries_count;
281                     uint16_t * unicode_list = (uint16_t *)lv_mem_alloc(list_size);
282 
283                     cmap->unicode_list = unicode_list;
284                     cmap->list_length = cmap_table[i].data_entries_count;
285 
286                     if(lv_fs_read(fp, unicode_list, list_size, NULL) != LV_FS_RES_OK) {
287                         return false;
288                     }
289 
290                     if(cmap_table[i].format_type == LV_FONT_FMT_TXT_CMAP_SPARSE_FULL) {
291                         uint16_t * buf = lv_mem_alloc(sizeof(uint16_t) * cmap->list_length);
292 
293                         cmap->glyph_id_ofs_list = buf;
294 
295                         if(lv_fs_read(fp, buf, sizeof(uint16_t) * cmap->list_length, NULL) != LV_FS_RES_OK) {
296                             return false;
297                         }
298                     }
299                     break;
300                 }
301             default:
302                 LV_LOG_WARN("Unknown cmaps format type %d.", cmap_table[i].format_type);
303                 return false;
304         }
305     }
306     return true;
307 }
308 
load_cmaps(lv_fs_file_t * fp,lv_font_fmt_txt_dsc_t * font_dsc,uint32_t cmaps_start)309 static int32_t load_cmaps(lv_fs_file_t * fp, lv_font_fmt_txt_dsc_t * font_dsc, uint32_t cmaps_start)
310 {
311     int32_t cmaps_length = read_label(fp, cmaps_start, "cmap");
312     if(cmaps_length < 0) {
313         return -1;
314     }
315 
316     uint32_t cmaps_subtables_count;
317     if(lv_fs_read(fp, &cmaps_subtables_count, sizeof(uint32_t), NULL) != LV_FS_RES_OK) {
318         return -1;
319     }
320 
321     lv_font_fmt_txt_cmap_t * cmaps =
322         lv_mem_alloc(cmaps_subtables_count * sizeof(lv_font_fmt_txt_cmap_t));
323 
324     memset(cmaps, 0, cmaps_subtables_count * sizeof(lv_font_fmt_txt_cmap_t));
325 
326     font_dsc->cmaps = cmaps;
327     font_dsc->cmap_num = cmaps_subtables_count;
328 
329     cmap_table_bin_t * cmaps_tables = lv_mem_alloc(sizeof(cmap_table_bin_t) * font_dsc->cmap_num);
330 
331     bool success = load_cmaps_tables(fp, font_dsc, cmaps_start, cmaps_tables);
332 
333     lv_mem_free(cmaps_tables);
334 
335     return success ? cmaps_length : -1;
336 }
337 
load_glyph(lv_fs_file_t * fp,lv_font_fmt_txt_dsc_t * font_dsc,uint32_t start,uint32_t * glyph_offset,uint32_t loca_count,font_header_bin_t * header)338 static int32_t load_glyph(lv_fs_file_t * fp, lv_font_fmt_txt_dsc_t * font_dsc,
339                           uint32_t start, uint32_t * glyph_offset, uint32_t loca_count, font_header_bin_t * header)
340 {
341     int32_t glyph_length = read_label(fp, start, "glyf");
342     if(glyph_length < 0) {
343         return -1;
344     }
345 
346     lv_font_fmt_txt_glyph_dsc_t * glyph_dsc = (lv_font_fmt_txt_glyph_dsc_t *)
347                                               lv_mem_alloc(loca_count * sizeof(lv_font_fmt_txt_glyph_dsc_t));
348 
349     memset(glyph_dsc, 0, loca_count * sizeof(lv_font_fmt_txt_glyph_dsc_t));
350 
351     font_dsc->glyph_dsc = glyph_dsc;
352 
353     int cur_bmp_size = 0;
354 
355     for(unsigned int i = 0; i < loca_count; ++i) {
356         lv_font_fmt_txt_glyph_dsc_t * gdsc = &glyph_dsc[i];
357 
358         lv_fs_res_t res = lv_fs_seek(fp, start + glyph_offset[i], LV_FS_SEEK_SET);
359         if(res != LV_FS_RES_OK) {
360             return -1;
361         }
362 
363         bit_iterator_t bit_it = init_bit_iterator(fp);
364 
365         if(header->advance_width_bits == 0) {
366             gdsc->adv_w = header->default_advance_width;
367         }
368         else {
369             gdsc->adv_w = read_bits(&bit_it, header->advance_width_bits, &res);
370             if(res != LV_FS_RES_OK) {
371                 return -1;
372             }
373         }
374 
375         if(header->advance_width_format == 0) {
376             gdsc->adv_w *= 16;
377         }
378 
379         gdsc->ofs_x = read_bits_signed(&bit_it, header->xy_bits, &res);
380         if(res != LV_FS_RES_OK) {
381             return -1;
382         }
383 
384         gdsc->ofs_y = read_bits_signed(&bit_it, header->xy_bits, &res);
385         if(res != LV_FS_RES_OK) {
386             return -1;
387         }
388 
389         gdsc->box_w = read_bits(&bit_it, header->wh_bits, &res);
390         if(res != LV_FS_RES_OK) {
391             return -1;
392         }
393 
394         gdsc->box_h = read_bits(&bit_it, header->wh_bits, &res);
395         if(res != LV_FS_RES_OK) {
396             return -1;
397         }
398 
399         int nbits = header->advance_width_bits + 2 * header->xy_bits + 2 * header->wh_bits;
400         int next_offset = (i < loca_count - 1) ? glyph_offset[i + 1] : (uint32_t)glyph_length;
401         int bmp_size = next_offset - glyph_offset[i] - nbits / 8;
402 
403         if(i == 0) {
404             gdsc->adv_w = 0;
405             gdsc->box_w = 0;
406             gdsc->box_h = 0;
407             gdsc->ofs_x = 0;
408             gdsc->ofs_y = 0;
409         }
410 
411         gdsc->bitmap_index = cur_bmp_size;
412         if(gdsc->box_w * gdsc->box_h != 0) {
413             cur_bmp_size += bmp_size;
414         }
415     }
416 
417     uint8_t * glyph_bmp = (uint8_t *)lv_mem_alloc(sizeof(uint8_t) * cur_bmp_size);
418 
419     font_dsc->glyph_bitmap = glyph_bmp;
420 
421     cur_bmp_size = 0;
422 
423     for(unsigned int i = 1; i < loca_count; ++i) {
424         lv_fs_res_t res = lv_fs_seek(fp, start + glyph_offset[i], LV_FS_SEEK_SET);
425         if(res != LV_FS_RES_OK) {
426             return -1;
427         }
428         bit_iterator_t bit_it = init_bit_iterator(fp);
429 
430         int nbits = header->advance_width_bits + 2 * header->xy_bits + 2 * header->wh_bits;
431 
432         read_bits(&bit_it, nbits, &res);
433         if(res != LV_FS_RES_OK) {
434             return -1;
435         }
436 
437         if(glyph_dsc[i].box_w * glyph_dsc[i].box_h == 0) {
438             continue;
439         }
440 
441         int next_offset = (i < loca_count - 1) ? glyph_offset[i + 1] : (uint32_t)glyph_length;
442         int bmp_size = next_offset - glyph_offset[i] - nbits / 8;
443 
444         if(nbits % 8 == 0) {  /*Fast path*/
445             if(lv_fs_read(fp, &glyph_bmp[cur_bmp_size], bmp_size, NULL) != LV_FS_RES_OK) {
446                 return -1;
447             }
448         }
449         else {
450             for(int k = 0; k < bmp_size - 1; ++k) {
451                 glyph_bmp[cur_bmp_size + k] = read_bits(&bit_it, 8, &res);
452                 if(res != LV_FS_RES_OK) {
453                     return -1;
454                 }
455             }
456             glyph_bmp[cur_bmp_size + bmp_size - 1] = read_bits(&bit_it, 8 - nbits % 8, &res);
457             if(res != LV_FS_RES_OK) {
458                 return -1;
459             }
460 
461             /*The last fragment should be on the MSB but read_bits() will place it to the LSB*/
462             glyph_bmp[cur_bmp_size + bmp_size - 1] = glyph_bmp[cur_bmp_size + bmp_size - 1] << (nbits % 8);
463 
464         }
465 
466         cur_bmp_size += bmp_size;
467     }
468     return glyph_length;
469 }
470 
471 /*
472  * Loads a `lv_font_t` from a binary file, given a `lv_fs_file_t`.
473  *
474  * Memory allocations on `lvgl_load_font` should be immediately zeroed and
475  * the pointer should be set on the `lv_font_t` data before any possible return.
476  *
477  * When something fails, it returns `false` and the memory on the `lv_font_t`
478  * still needs to be freed using `lv_font_free`.
479  *
480  * `lv_font_free` will assume that all non-null pointers are allocated and
481  * should be freed.
482  */
lvgl_load_font(lv_fs_file_t * fp,lv_font_t * font)483 static bool lvgl_load_font(lv_fs_file_t * fp, lv_font_t * font)
484 {
485     lv_font_fmt_txt_dsc_t * font_dsc = (lv_font_fmt_txt_dsc_t *)
486                                        lv_mem_alloc(sizeof(lv_font_fmt_txt_dsc_t));
487 
488     memset(font_dsc, 0, sizeof(lv_font_fmt_txt_dsc_t));
489 
490     font->dsc = font_dsc;
491 
492     /*header*/
493     int32_t header_length = read_label(fp, 0, "head");
494     if(header_length < 0) {
495         return false;
496     }
497 
498     font_header_bin_t font_header;
499     if(lv_fs_read(fp, &font_header, sizeof(font_header_bin_t), NULL) != LV_FS_RES_OK) {
500         return false;
501     }
502 
503     font->base_line = -font_header.descent;
504     font->line_height = font_header.ascent - font_header.descent;
505     font->get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt;
506     font->get_glyph_bitmap = lv_font_get_bitmap_fmt_txt;
507     font->subpx = font_header.subpixels_mode;
508     font->underline_position = font_header.underline_position;
509     font->underline_thickness = font_header.underline_thickness;
510 
511     font_dsc->bpp = font_header.bits_per_pixel;
512     font_dsc->kern_scale = font_header.kerning_scale;
513     font_dsc->bitmap_format = font_header.compression_id;
514 
515     /*cmaps*/
516     uint32_t cmaps_start = header_length;
517     int32_t cmaps_length = load_cmaps(fp, font_dsc, cmaps_start);
518     if(cmaps_length < 0) {
519         return false;
520     }
521 
522     /*loca*/
523     uint32_t loca_start = cmaps_start + cmaps_length;
524     int32_t loca_length = read_label(fp, loca_start, "loca");
525     if(loca_length < 0) {
526         return false;
527     }
528 
529     uint32_t loca_count;
530     if(lv_fs_read(fp, &loca_count, sizeof(uint32_t), NULL) != LV_FS_RES_OK) {
531         return false;
532     }
533 
534     bool failed = false;
535     uint32_t * glyph_offset = lv_mem_alloc(sizeof(uint32_t) * (loca_count + 1));
536 
537     if(font_header.index_to_loc_format == 0) {
538         for(unsigned int i = 0; i < loca_count; ++i) {
539             uint16_t offset;
540             if(lv_fs_read(fp, &offset, sizeof(uint16_t), NULL) != LV_FS_RES_OK) {
541                 failed = true;
542                 break;
543             }
544             glyph_offset[i] = offset;
545         }
546     }
547     else if(font_header.index_to_loc_format == 1) {
548         if(lv_fs_read(fp, glyph_offset, loca_count * sizeof(uint32_t), NULL) != LV_FS_RES_OK) {
549             failed = true;
550         }
551     }
552     else {
553         LV_LOG_WARN("Unknown index_to_loc_format: %d.", font_header.index_to_loc_format);
554         failed = true;
555     }
556 
557     if(failed) {
558         lv_mem_free(glyph_offset);
559         return false;
560     }
561 
562     /*glyph*/
563     uint32_t glyph_start = loca_start + loca_length;
564     int32_t glyph_length = load_glyph(
565                                fp, font_dsc, glyph_start, glyph_offset, loca_count, &font_header);
566 
567     lv_mem_free(glyph_offset);
568 
569     if(glyph_length < 0) {
570         return false;
571     }
572 
573     if(font_header.tables_count < 4) {
574         font_dsc->kern_dsc = NULL;
575         font_dsc->kern_classes = 0;
576         font_dsc->kern_scale = 0;
577         return true;
578     }
579 
580     uint32_t kern_start = glyph_start + glyph_length;
581 
582     int32_t kern_length = load_kern(fp, font_dsc, font_header.glyph_id_format, kern_start);
583 
584     return kern_length >= 0;
585 }
586 
load_kern(lv_fs_file_t * fp,lv_font_fmt_txt_dsc_t * font_dsc,uint8_t format,uint32_t start)587 int32_t load_kern(lv_fs_file_t * fp, lv_font_fmt_txt_dsc_t * font_dsc, uint8_t format, uint32_t start)
588 {
589     int32_t kern_length = read_label(fp, start, "kern");
590     if(kern_length < 0) {
591         return -1;
592     }
593 
594     uint8_t kern_format_type;
595     int32_t padding;
596     if(lv_fs_read(fp, &kern_format_type, sizeof(uint8_t), NULL) != LV_FS_RES_OK ||
597        lv_fs_read(fp, &padding, 3 * sizeof(uint8_t), NULL) != LV_FS_RES_OK) {
598         return -1;
599     }
600 
601     if(0 == kern_format_type) { /*sorted pairs*/
602         lv_font_fmt_txt_kern_pair_t * kern_pair = lv_mem_alloc(sizeof(lv_font_fmt_txt_kern_pair_t));
603 
604         memset(kern_pair, 0, sizeof(lv_font_fmt_txt_kern_pair_t));
605 
606         font_dsc->kern_dsc = kern_pair;
607         font_dsc->kern_classes = 0;
608 
609         uint32_t glyph_entries;
610         if(lv_fs_read(fp, &glyph_entries, sizeof(uint32_t), NULL) != LV_FS_RES_OK) {
611             return -1;
612         }
613 
614         int ids_size;
615         if(format == 0) {
616             ids_size = sizeof(int8_t) * 2 * glyph_entries;
617         }
618         else {
619             ids_size = sizeof(int16_t) * 2 * glyph_entries;
620         }
621 
622         uint8_t * glyph_ids = lv_mem_alloc(ids_size);
623         int8_t * values = lv_mem_alloc(glyph_entries);
624 
625         kern_pair->glyph_ids_size = format;
626         kern_pair->pair_cnt = glyph_entries;
627         kern_pair->glyph_ids = glyph_ids;
628         kern_pair->values = values;
629 
630         if(lv_fs_read(fp, glyph_ids, ids_size, NULL) != LV_FS_RES_OK) {
631             return -1;
632         }
633 
634         if(lv_fs_read(fp, values, glyph_entries, NULL) != LV_FS_RES_OK) {
635             return -1;
636         }
637     }
638     else if(3 == kern_format_type) { /*array M*N of classes*/
639 
640         lv_font_fmt_txt_kern_classes_t * kern_classes = lv_mem_alloc(sizeof(lv_font_fmt_txt_kern_classes_t));
641 
642         memset(kern_classes, 0, sizeof(lv_font_fmt_txt_kern_classes_t));
643 
644         font_dsc->kern_dsc = kern_classes;
645         font_dsc->kern_classes = 1;
646 
647         uint16_t kern_class_mapping_length;
648         uint8_t kern_table_rows;
649         uint8_t kern_table_cols;
650 
651         if(lv_fs_read(fp, &kern_class_mapping_length, sizeof(uint16_t), NULL) != LV_FS_RES_OK ||
652            lv_fs_read(fp, &kern_table_rows, sizeof(uint8_t), NULL) != LV_FS_RES_OK ||
653            lv_fs_read(fp, &kern_table_cols, sizeof(uint8_t), NULL) != LV_FS_RES_OK) {
654             return -1;
655         }
656 
657         int kern_values_length = sizeof(int8_t) * kern_table_rows * kern_table_cols;
658 
659         uint8_t * kern_left = lv_mem_alloc(kern_class_mapping_length);
660         uint8_t * kern_right = lv_mem_alloc(kern_class_mapping_length);
661         int8_t * kern_values = lv_mem_alloc(kern_values_length);
662 
663         kern_classes->left_class_mapping  = kern_left;
664         kern_classes->right_class_mapping = kern_right;
665         kern_classes->left_class_cnt = kern_table_rows;
666         kern_classes->right_class_cnt = kern_table_cols;
667         kern_classes->class_pair_values = kern_values;
668 
669         if(lv_fs_read(fp, kern_left, kern_class_mapping_length, NULL) != LV_FS_RES_OK ||
670            lv_fs_read(fp, kern_right, kern_class_mapping_length, NULL) != LV_FS_RES_OK ||
671            lv_fs_read(fp, kern_values, kern_values_length, NULL) != LV_FS_RES_OK) {
672             return -1;
673         }
674     }
675     else {
676         LV_LOG_WARN("Unknown kern_format_type: %d", kern_format_type);
677         return -1;
678     }
679 
680     return kern_length;
681 }
682