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