1 /**
2  * @file test_font_loader.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #if LV_BUILD_TEST
11 #include "../../lvgl.h"
12 
13 #include "unity/unity.h"
14 
15 /*********************
16  *      DEFINES
17  *********************/
18 
19 /**********************
20  *      TYPEDEFS
21  **********************/
22 
23 /**********************
24  *  STATIC PROTOTYPES
25  **********************/
26 
27 static int compare_fonts(lv_font_t * f1, lv_font_t * f2);
28 void test_font_loader_with_cache(void);
29 void test_font_loader_no_cache(void);
30 void test_font_loader_from_buffer(void);
31 
32 /**********************
33  *  STATIC VARIABLES
34  **********************/
35 
36 /**********************
37  *      MACROS
38  **********************/
39 
40 /**********************
41  *   GLOBAL FUNCTIONS
42  **********************/
43 
44 /* fonts converted to C structs using the LVGL Font Converter */
45 extern lv_font_t test_font_1;
46 extern lv_font_t test_font_2;
47 extern lv_font_t test_font_3;
48 
49 /* font binaries converted to plain C arrays */
50 extern uint8_t const test_font_1_buf[6876];
51 extern uint8_t const test_font_2_buf[7252];
52 extern uint8_t const test_font_3_buf[4892];
53 
54 static lv_font_t * font_1_bin = NULL;
55 static lv_font_t * font_2_bin = NULL;
56 static lv_font_t * font_3_bin = NULL;
57 
setUp(void)58 void setUp(void)
59 {
60     /* Function run before every test */
61 }
62 
tearDown(void)63 void tearDown(void)
64 {
65     /* Function run after every test */
66 
67 }
68 
common(void)69 static void common(void)
70 {
71     compare_fonts(&test_font_1, font_1_bin);
72     compare_fonts(&test_font_2, font_2_bin);
73     compare_fonts(&test_font_3, font_3_bin);
74 
75     /* create labels for testing */
76     lv_obj_t * scr = lv_screen_active();
77     lv_obj_t * label1 = lv_label_create(scr);
78     lv_obj_t * label2 = lv_label_create(scr);
79     lv_obj_t * label3 = lv_label_create(scr);
80 
81     lv_obj_set_flex_flow(scr, LV_FLEX_FLOW_COLUMN);
82     lv_obj_set_flex_align(scr, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
83 
84     lv_label_set_text(label1, "The quick brown fox jumped over the lazy dog");
85     lv_obj_set_style_text_font(label1, font_1_bin, 0);
86     lv_label_set_text(label2, "The quick brown fox jumped over the lazy dog");
87     lv_obj_set_style_text_font(label2, font_2_bin, 0);
88     lv_label_set_text(label3, "The quick brown fox jumped over the lazy dog");
89     lv_obj_set_style_text_font(label3, font_3_bin, 0);
90 
91     TEST_ASSERT_EQUAL_SCREENSHOT("font_loader_1.png");
92 
93     lv_obj_clean(lv_screen_active());
94 
95     lv_binfont_destroy(font_1_bin);
96     lv_binfont_destroy(font_2_bin);
97     lv_binfont_destroy(font_3_bin);
98 }
99 
test_font_loader_with_cache(void)100 void test_font_loader_with_cache(void)
101 {
102     /*Test with cache ('A' has cache)*/
103 
104     font_1_bin = lv_binfont_create("A:src/test_assets/test_font_1.fnt");
105     TEST_ASSERT_NOT_NULL(font_1_bin);
106 
107     font_2_bin = lv_binfont_create("A:src/test_assets/test_font_2.fnt");
108     TEST_ASSERT_NOT_NULL(font_2_bin);
109 
110     font_3_bin = lv_binfont_create("A:src/test_assets/test_font_3.fnt");
111     TEST_ASSERT_NOT_NULL(font_3_bin);
112 
113     common();
114 }
115 
test_font_loader_no_cache(void)116 void test_font_loader_no_cache(void)
117 {
118     /*Test without cache ('B' has NO cache)*/
119 
120     font_1_bin = lv_binfont_create("B:src/test_assets/test_font_1.fnt");
121     TEST_ASSERT_NOT_NULL(font_1_bin);
122 
123     font_2_bin = lv_binfont_create("B:src/test_assets/test_font_2.fnt");
124     TEST_ASSERT_NOT_NULL(font_2_bin);
125 
126     font_3_bin = lv_binfont_create("B:src/test_assets/test_font_3.fnt");
127     TEST_ASSERT_NOT_NULL(font_3_bin);
128 
129     common();
130 }
131 
test_font_loader_from_buffer(void)132 void test_font_loader_from_buffer(void)
133 {
134     /*Test with memfs*/
135 
136     font_1_bin = lv_binfont_create_from_buffer((void *)&test_font_1_buf, sizeof(test_font_1_buf));
137     TEST_ASSERT_NOT_NULL(font_1_bin);
138 
139     font_2_bin = lv_binfont_create_from_buffer((void *)&test_font_2_buf, sizeof(test_font_2_buf));
140     TEST_ASSERT_NOT_NULL(font_2_bin);
141 
142     font_3_bin = lv_binfont_create_from_buffer((void *)&test_font_3_buf, sizeof(test_font_3_buf));
143     TEST_ASSERT_NOT_NULL(font_3_bin);
144 
145     common();
146 }
147 
test_font_loader_reload(void)148 void test_font_loader_reload(void)
149 {
150     /*Reload a font which is being used by a label*/
151     lv_obj_t * scr = lv_screen_active();
152     lv_obj_t * label = lv_label_create(scr);
153     lv_obj_center(label);
154     lv_label_set_text(label, "The quick brown fox jumped over the lazy dog");
155 
156     lv_font_t style_font;
157     lv_font_t * font;
158     font = lv_binfont_create("A:src/test_assets/test_font_2.fnt");
159     TEST_ASSERT_NOT_NULL(font);
160     lv_memcpy(&style_font, font, sizeof(lv_font_t));
161 
162     lv_obj_set_style_text_font(label, &style_font, 0);
163 
164     TEST_ASSERT_EQUAL_SCREENSHOT("font_loader_2.png");
165 
166     lv_binfont_destroy(font);
167 
168     font = lv_binfont_create("A:src/test_assets/test_font_3.fnt");
169     TEST_ASSERT_NOT_NULL(font);
170     lv_memcpy(&style_font, font, sizeof(lv_font_t));
171 
172     lv_obj_report_style_change(NULL);
173 
174     TEST_ASSERT_EQUAL_SCREENSHOT("font_loader_3.png");
175 
176     lv_obj_delete(label);
177 
178     lv_binfont_destroy(font);
179 }
180 
compare_fonts(lv_font_t * f1,lv_font_t * f2)181 static int compare_fonts(lv_font_t * f1, lv_font_t * f2)
182 {
183     TEST_ASSERT_NOT_NULL_MESSAGE(f1, "font not null");
184     TEST_ASSERT_NOT_NULL_MESSAGE(f2, "font not null");
185 
186     //    Skip these test because -Wpedantic tells
187     //    ISO C forbids passing argument 1 of ‘TEST_ASSERT_EQUAL_PTR_MESSAGE’ between function pointer and ‘void *’
188     //    TEST_ASSERT_EQUAL_PTR_MESSAGE(f1->get_glyph_dsc, f2->get_glyph_dsc, "glyph_dsc");
189     //    TEST_ASSERT_EQUAL_PTR_MESSAGE(f1->get_glyph_bitmap, f2->get_glyph_bitmap, "glyph_bitmap");
190 
191     TEST_ASSERT_EQUAL_INT_MESSAGE(f1->line_height, f2->line_height, "line_height");
192     TEST_ASSERT_EQUAL_INT_MESSAGE(f1->base_line, f2->base_line, "base_line");
193     TEST_ASSERT_EQUAL_INT_MESSAGE(f1->subpx, f2->subpx, "subpx");
194     lv_font_fmt_txt_dsc_t * dsc1 = (lv_font_fmt_txt_dsc_t *)f1->dsc;
195     lv_font_fmt_txt_dsc_t * dsc2 = (lv_font_fmt_txt_dsc_t *)f2->dsc;
196 
197     TEST_ASSERT_EQUAL_INT_MESSAGE(dsc1->kern_scale, dsc2->kern_scale, "kern_scale");
198     TEST_ASSERT_EQUAL_INT_MESSAGE(dsc1->cmap_num, dsc2->cmap_num, "cmap_num");
199     TEST_ASSERT_EQUAL_INT_MESSAGE(dsc1->bpp, dsc2->bpp, "bpp");
200     TEST_ASSERT_EQUAL_INT_MESSAGE(dsc1->kern_classes, dsc2->kern_classes, "kern_classes");
201     TEST_ASSERT_EQUAL_INT_MESSAGE(dsc1->bitmap_format, dsc2->bitmap_format, "bitmap_format");
202 
203     // cmaps
204     int total_glyphs = 0;
205     for(int i = 0; i < dsc1->cmap_num; ++i) {
206         lv_font_fmt_txt_cmap_t * cmaps1 = (lv_font_fmt_txt_cmap_t *)&dsc1->cmaps[i];
207         lv_font_fmt_txt_cmap_t * cmaps2 = (lv_font_fmt_txt_cmap_t *)&dsc2->cmaps[i];
208 
209         TEST_ASSERT_EQUAL_INT_MESSAGE(cmaps1->range_start, cmaps2->range_start, "range_start");
210         TEST_ASSERT_EQUAL_INT_MESSAGE(cmaps1->range_length, cmaps2->range_length, "range_length");
211         TEST_ASSERT_EQUAL_INT_MESSAGE(cmaps1->glyph_id_start, cmaps2->glyph_id_start, "glyph_id_start");
212         TEST_ASSERT_EQUAL_INT_MESSAGE(cmaps1->type, cmaps2->type, "type");
213         TEST_ASSERT_EQUAL_INT_MESSAGE(cmaps1->list_length, cmaps2->list_length, "list_length");
214 
215         if(cmaps1->unicode_list != NULL && cmaps2->unicode_list != NULL) {
216             TEST_ASSERT_TRUE_MESSAGE(cmaps1->unicode_list && cmaps2->unicode_list, "unicode_list");
217 
218             TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(
219                 (uint8_t *)cmaps1->unicode_list,
220                 (uint8_t *)cmaps2->unicode_list,
221                 sizeof(uint16_t) * cmaps1->list_length,
222                 "unicode_list");
223             total_glyphs += cmaps1->list_length;
224         }
225         else {
226             total_glyphs += cmaps1->range_length;
227             TEST_ASSERT_EQUAL_PTR_MESSAGE(cmaps1->unicode_list, cmaps2->unicode_list, "unicode_list");
228         }
229 
230         if(cmaps1->glyph_id_ofs_list != NULL && cmaps2->glyph_id_ofs_list != NULL) {
231             uint8_t * ids1 = (uint8_t *)cmaps1->glyph_id_ofs_list;
232             uint8_t * ids2 = (uint8_t *)cmaps2->glyph_id_ofs_list;
233 
234             TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(ids1, ids2, cmaps1->list_length, "glyph_id_ofs_list");
235         }
236         else {
237             TEST_ASSERT_EQUAL_PTR_MESSAGE(cmaps1->glyph_id_ofs_list, cmaps2->glyph_id_ofs_list, "glyph_id_ofs_list");
238         }
239     }
240 
241     // kern_dsc
242     if(dsc1->kern_classes == 1 && dsc2->kern_classes == 1) {
243         lv_font_fmt_txt_kern_classes_t * kern1 = (lv_font_fmt_txt_kern_classes_t *)dsc1->kern_dsc;
244         lv_font_fmt_txt_kern_classes_t * kern2 = (lv_font_fmt_txt_kern_classes_t *)dsc2->kern_dsc;
245         if(kern1 != NULL && kern2 != NULL) {
246             TEST_ASSERT_EQUAL_INT_MESSAGE(kern1->right_class_cnt, kern2->right_class_cnt, "right_class_cnt");
247             TEST_ASSERT_EQUAL_INT_MESSAGE(kern1->left_class_cnt, kern2->left_class_cnt, "left_class_cnt");
248 
249             TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(
250                 (uint8_t *)kern1->left_class_mapping,
251                 (uint8_t *)kern2->left_class_mapping,
252                 kern1->left_class_cnt,
253                 "left_class_mapping");
254 
255             TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(
256                 (uint8_t *)kern1->right_class_mapping,
257                 (uint8_t *)kern2->right_class_mapping,
258                 kern1->right_class_cnt,
259                 "right_class_mapping");
260 
261             TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(
262                 (uint8_t *)kern1->class_pair_values,
263                 (uint8_t *)kern2->class_pair_values,
264                 kern1->right_class_cnt * kern1->left_class_cnt,
265                 "class_pair_values");
266         }
267         else {
268             TEST_ASSERT_EQUAL_PTR_MESSAGE(kern1, kern2, "kern");
269         }
270     }
271     else if(dsc1->kern_classes == 0 && dsc2->kern_classes == 0) {
272         lv_font_fmt_txt_kern_pair_t * kern1 = (lv_font_fmt_txt_kern_pair_t *)dsc1->kern_dsc;
273         lv_font_fmt_txt_kern_pair_t * kern2 = (lv_font_fmt_txt_kern_pair_t *)dsc2->kern_dsc;
274         if(kern1 != NULL && kern2 != NULL) {
275             TEST_ASSERT_EQUAL_INT_MESSAGE(kern1->glyph_ids_size, kern2->glyph_ids_size, "glyph_ids_size");
276             TEST_ASSERT_EQUAL_INT_MESSAGE(kern1->pair_cnt, kern2->pair_cnt, "pair_cnt");
277 
278             int ids_size;
279 
280             if(kern1->glyph_ids_size == 0) {
281                 ids_size = sizeof(int8_t) * 2 * kern1->pair_cnt;
282             }
283             else {
284                 ids_size = sizeof(int16_t) * 2 * kern1->pair_cnt;
285             }
286 
287             TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(kern1->glyph_ids, kern2->glyph_ids, ids_size, "glyph_ids");
288             TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(
289                 (uint8_t *) kern1->values,
290                 (uint8_t *) kern2->values,
291                 kern1->pair_cnt,
292                 "glyph_values");
293         }
294     }
295 
296     lv_font_fmt_txt_glyph_dsc_t * glyph_dsc1 = (lv_font_fmt_txt_glyph_dsc_t *)dsc1->glyph_dsc;
297     lv_font_fmt_txt_glyph_dsc_t * glyph_dsc2 = (lv_font_fmt_txt_glyph_dsc_t *)dsc2->glyph_dsc;
298 
299     for(int i = 0; i < total_glyphs; ++i) {
300         if(i < total_glyphs - 1) {
301             int size1 = glyph_dsc1[i + 1].bitmap_index - glyph_dsc1[i].bitmap_index;
302 
303             if(size1 > 0) {
304                 TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(
305                     dsc1->glyph_bitmap + glyph_dsc1[i].bitmap_index,
306                     dsc2->glyph_bitmap + glyph_dsc2[i].bitmap_index,
307                     size1 - 1, "glyph_bitmap");
308             }
309         }
310         TEST_ASSERT_EQUAL_INT_MESSAGE(glyph_dsc1[i].adv_w, glyph_dsc2[i].adv_w, "adv_w");
311         TEST_ASSERT_EQUAL_INT_MESSAGE(glyph_dsc1[i].box_w, glyph_dsc2[i].box_w, "box_w");
312         TEST_ASSERT_EQUAL_INT_MESSAGE(glyph_dsc1[i].box_h, glyph_dsc2[i].box_h, "box_h");
313         TEST_ASSERT_EQUAL_INT_MESSAGE(glyph_dsc1[i].ofs_x, glyph_dsc2[i].ofs_x, "ofs_x");
314         TEST_ASSERT_EQUAL_INT_MESSAGE(glyph_dsc1[i].ofs_y, glyph_dsc2[i].ofs_y, "ofs_y");
315     }
316 
317     LV_LOG_INFO("No differences found!");
318     return 0;
319 }
320 
321 /**********************
322  *   STATIC FUNCTIONS
323  **********************/
324 
325 #endif // LV_BUILD_TEST
326