1 #if LV_BUILD_TEST
2 #include "../lvgl.h"
3 #include "../../lvgl_private.h"
4 
5 #include "unity/unity.h"
6 
7 #if LV_USE_FREETYPE && LV_USE_FONT_MANAGER
8 
9 #include "rnd_unicodes/lv_rnd_unicodes.h"
10 
11 #ifndef NON_AMD64_BUILD
12 #define TEST_FREETYPE_ASSERT_EQUAL_SCREENSHOT(INDEX) \
13     lv_snprintf(buf, sizeof(buf), "libs/font_stress/snapshot_%0d.lp64.png", (INDEX));\
14     TEST_ASSERT_EQUAL_SCREENSHOT(buf)
15 #else
16 #define TEST_FREETYPE_ASSERT_EQUAL_SCREENSHOT(INDEX) \
17     lv_snprintf(buf, sizeof(buf), "libs/font_stress/snapshot_%0d.lp32.png", (INDEX));\
18     TEST_ASSERT_EQUAL_SCREENSHOT(buf)
19 #endif
20 
21 /**********************
22  *      TYPEDEFS
23  **********************/
24 
25 typedef struct {
26     const char ** font_name_arr;
27     int font_cnt;
28     int label_cnt;
29     int loop_cnt;
30 } font_stress_config_t;
31 
32 struct _font_stress_ctx_t;
33 
34 typedef lv_font_t * (*font_create_cb_t)(struct _font_stress_ctx_t * ctx,
35                                         const char * name,
36                                         lv_freetype_font_render_mode_t render_mode,
37                                         uint32_t size,
38                                         lv_freetype_font_style_t style);
39 
40 typedef void (*font_delete_cb_t)(struct _font_stress_ctx_t * ctx, lv_font_t * font);
41 
42 typedef struct _font_stress_ctx_t {
43     font_stress_config_t config;
44     lv_obj_t * par;
45     lv_obj_t ** label_arr;
46     lv_font_manager_t * font_manager;
47     font_create_cb_t font_create_cb;
48     font_delete_cb_t font_delete_cb;
49 } font_stress_ctx_t;
50 
51 /**********************
52  *  STATIC PROTOTYPES
53  **********************/
54 
55 /**********************
56  *  STATIC VARIABLES
57  **********************/
58 
59 static font_stress_ctx_t g_ctx = { 0 };
60 
61 /**********************
62  *      MACROS
63  **********************/
64 
65 #define RND_START_SEED 0x114514
66 #define CAPTURE_SKIP_FRAMES 17
67 
68 #define MAX_FONT_SIZE 128
69 #define MAX_LABEL_CNT 32
70 #define MAX_LOOP_CNT 200
71 #define MAX_LABEL_CONTENT_LEN 16
72 
73 /**********************
74  *   GLOBAL FUNCTIONS
75  **********************/
76 
77 /**********************
78  *   STATIC FUNCTIONS
79  **********************/
80 
font_stress_label_create(font_stress_ctx_t * ctx,const char * font_name,lv_obj_t * par,int size,int x,int y)81 static lv_obj_t * font_stress_label_create(font_stress_ctx_t * ctx, const char * font_name, lv_obj_t * par, int size,
82                                            int x, int y)
83 {
84     static const uint16_t font_style[] = {
85         LV_FREETYPE_FONT_STYLE_NORMAL,
86         LV_FREETYPE_FONT_STYLE_ITALIC,
87         LV_FREETYPE_FONT_STYLE_BOLD,
88     };
89 
90     uint32_t index = lv_rand(0, sizeof(font_style) / sizeof(uint16_t) - 1);
91     uint32_t r = lv_rand(0, 0xFF);
92     uint32_t g = lv_rand(0, 0xFF);
93     uint32_t b = lv_rand(0, 0xFF);
94     lv_opa_t opa = lv_rand(0, LV_OPA_COVER);
95     lv_color_t color = lv_color_make(r, g, b);
96 
97     lv_font_t * font = ctx->font_create_cb(ctx, font_name, LV_FREETYPE_FONT_RENDER_MODE_BITMAP, size, font_style[index]);
98     if(!font) {
99         return NULL;
100     }
101 
102     lv_obj_t * label = lv_label_create(par);
103     lv_obj_set_style_text_font(label, font, 0);
104     lv_obj_set_style_text_opa(label, opa, 0);
105     lv_obj_set_style_text_color(label, color, 0);
106     lv_obj_set_pos(label, x, y);
107     lv_obj_set_style_outline_color(label, color, 0);
108     lv_obj_set_style_outline_width(label, 1, 0);
109 
110     uint8_t str[128];
111     lv_random_utf8_chars(str, sizeof(str), LV_RND_UNICODE_ALPHANUM_AND_CJK_TABLE, LV_RND_UNICODE_ALPHANUM_AND_CJK_TABLE_LEN,
112                          MAX_LABEL_CONTENT_LEN);
113     lv_label_set_text(label, (char *)str);
114     return label;
115 }
116 
font_stress_label_delete(font_stress_ctx_t * ctx,lv_obj_t * label)117 static void font_stress_label_delete(font_stress_ctx_t * ctx, lv_obj_t * label)
118 {
119     const lv_font_t * font = lv_obj_get_style_text_font(label, 0);
120     TEST_ASSERT_NOT_NULL(font);
121     lv_obj_del(label);
122     ctx->font_delete_cb(ctx, (lv_font_t *)font);
123 }
124 
font_stress_label_delete_all(font_stress_ctx_t * ctx)125 static void font_stress_label_delete_all(font_stress_ctx_t * ctx)
126 {
127     for(int i = 0; i < ctx->config.label_cnt; i++) {
128         lv_obj_t * label = ctx->label_arr[i];
129         if(label) {
130             font_stress_label_delete(ctx, label);
131             ctx->label_arr[i] = NULL;
132         }
133     }
134 }
135 
font_stress_update(font_stress_ctx_t * ctx)136 static void font_stress_update(font_stress_ctx_t * ctx)
137 {
138     uint32_t label_index = lv_rand(0, ctx->config.label_cnt - 1);
139     uint32_t font_index = lv_rand(0, ctx->config.font_cnt - 1);
140     uint32_t font_size = lv_rand(0, MAX_FONT_SIZE);
141     uint32_t label_x = lv_rand(0, LV_HOR_RES) - LV_HOR_RES / 2;
142     uint32_t label_y = lv_rand(0, LV_VER_RES);
143 
144     lv_obj_t * label = ctx->label_arr[label_index];
145     if(label) {
146         font_stress_label_delete(ctx, label);
147         ctx->label_arr[label_index] = NULL;
148     }
149     else {
150         const char * pathname = ctx->config.font_name_arr[font_index];
151         TEST_ASSERT_NOT_NULL(pathname);
152         label = font_stress_label_create(
153                     ctx,
154                     pathname,
155                     ctx->par,
156                     (int)font_size,
157                     (int)label_x,
158                     (int)label_y);
159         ctx->label_arr[label_index] = label;
160     }
161 }
162 
freetype_font_create_cb(font_stress_ctx_t * ctx,const char * name,lv_freetype_font_render_mode_t render_mode,uint32_t size,lv_freetype_font_style_t style)163 static lv_font_t * freetype_font_create_cb(font_stress_ctx_t * ctx,
164                                            const char * name,
165                                            lv_freetype_font_render_mode_t render_mode,
166                                            uint32_t size,
167                                            lv_freetype_font_style_t style)
168 {
169     LV_UNUSED(ctx);
170     return lv_freetype_font_create(name, render_mode, size, style);
171 }
172 
freetype_font_delete_cb(font_stress_ctx_t * ctx,lv_font_t * font)173 static void freetype_font_delete_cb(font_stress_ctx_t * ctx, lv_font_t * font)
174 {
175     LV_UNUSED(ctx);
176     lv_freetype_font_delete(font);
177 }
178 
font_manager_font_create_cb(font_stress_ctx_t * ctx,const char * name,lv_freetype_font_render_mode_t render_mode,uint32_t size,lv_freetype_font_style_t style)179 static lv_font_t * font_manager_font_create_cb(font_stress_ctx_t * ctx,
180                                                const char * name,
181                                                lv_freetype_font_render_mode_t render_mode,
182                                                uint32_t size,
183                                                lv_freetype_font_style_t style)
184 {
185     TEST_ASSERT_NOT_NULL(ctx->font_manager);
186     return lv_font_manager_create_font(ctx->font_manager, name, render_mode, size, style);
187 }
188 
font_manager_font_delete_cb(font_stress_ctx_t * ctx,lv_font_t * font)189 static void font_manager_font_delete_cb(font_stress_ctx_t * ctx, lv_font_t * font)
190 {
191     TEST_ASSERT_NOT_NULL(ctx->font_manager);
192     lv_font_manager_delete_font(ctx->font_manager, font);
193 }
194 
setUp(void)195 void setUp(void)
196 {
197     lv_freetype_init(LV_FREETYPE_CACHE_FT_GLYPH_CNT);
198 
199     g_ctx.par = lv_screen_active();
200     g_ctx.config.label_cnt = MAX_LABEL_CNT;
201     g_ctx.label_arr = lv_malloc_zeroed(sizeof(lv_obj_t *) * g_ctx.config.label_cnt);
202     TEST_ASSERT_NOT_NULL(g_ctx.label_arr);
203 }
204 
tearDown(void)205 void tearDown(void)
206 {
207     lv_freetype_uninit();
208     lv_free(g_ctx.label_arr);
209     g_ctx.label_arr = NULL;
210 }
211 
test_font_stress(void)212 void test_font_stress(void)
213 {
214     lv_rand_set_seed(RND_START_SEED);
215 
216     static const char * font_name_arr[] = {
217         "./src/test_files/fonts/noto/NotoSansSC-Regular.ttf",
218         "../src/libs/freetype/arial.ttf",
219         "../demos/multilang/assets/fonts/Montserrat-Bold.ttf",
220         "UNKNOWN_FONT_NAME"
221     };
222 
223     g_ctx.config.loop_cnt = MAX_LOOP_CNT;
224     g_ctx.config.font_name_arr = font_name_arr;
225     g_ctx.config.font_cnt = sizeof(font_name_arr) / sizeof(font_name_arr[0]);
226     g_ctx.font_create_cb = freetype_font_create_cb;
227     g_ctx.font_delete_cb = freetype_font_delete_cb;
228 
229     for(uint32_t i = 0; g_ctx.config.loop_cnt > 0; g_ctx.config.loop_cnt--) {
230         font_stress_update(&g_ctx);
231         lv_refr_now(NULL);
232 
233         if(g_ctx.config.loop_cnt % CAPTURE_SKIP_FRAMES == 0) {
234             char buf[64];
235             TEST_FREETYPE_ASSERT_EQUAL_SCREENSHOT(i);
236             i++;
237         }
238     }
239 
240     font_stress_label_delete_all(&g_ctx);
241 }
242 
test_font_manager_stress(void)243 void test_font_manager_stress(void)
244 {
245     lv_rand_set_seed(RND_START_SEED);
246 
247     g_ctx.font_manager = lv_font_manager_create(2);
248     TEST_ASSERT_NOT_NULL(g_ctx.font_manager);
249     lv_font_manager_add_path_static(g_ctx.font_manager, "NotoSansSC-Regular",
250                                     "./src/test_files/fonts/noto/NotoSansSC-Regular.ttf");
251     lv_font_manager_add_path_static(g_ctx.font_manager, "Arial", "../src/libs/freetype/arial.ttf");
252     lv_font_manager_add_path(g_ctx.font_manager, "Montserrat-Bold", "../demos/multilang/assets/fonts/Montserrat-Bold.ttf");
253     lv_font_manager_add_path(g_ctx.font_manager, "UNKNOWN", "UNKNOWN_FONT_PATH");
254 
255     static const char * font_name_arr[] = {
256         "NotoSansSC-Regular,Arial",
257         "Arial",
258         "Montserrat-Bold",
259         "UNKNOWN"
260     };
261 
262     g_ctx.config.loop_cnt = MAX_LOOP_CNT;
263     g_ctx.config.font_name_arr = font_name_arr;
264     g_ctx.config.font_cnt = sizeof(font_name_arr) / sizeof(font_name_arr[0]);
265     g_ctx.font_create_cb = font_manager_font_create_cb;
266     g_ctx.font_delete_cb = font_manager_font_delete_cb;
267 
268     for(uint32_t i = 0; g_ctx.config.loop_cnt > 0; g_ctx.config.loop_cnt--) {
269         font_stress_update(&g_ctx);
270         lv_refr_now(NULL);
271 
272         if(g_ctx.config.loop_cnt % CAPTURE_SKIP_FRAMES == 0) {
273             char buf[64];
274             TEST_FREETYPE_ASSERT_EQUAL_SCREENSHOT(i);
275             i++;
276         }
277     }
278 
279     font_stress_label_delete_all(&g_ctx);
280 
281     bool remove_ok = lv_font_manager_remove_path(g_ctx.font_manager, "Arial");
282     TEST_ASSERT_TRUE(remove_ok);
283 
284     remove_ok = lv_font_manager_remove_path(g_ctx.font_manager, "UNKNOWN");
285     TEST_ASSERT_TRUE(remove_ok);
286 
287     bool success = lv_font_manager_delete(g_ctx.font_manager);
288     TEST_ASSERT_TRUE(success);
289     g_ctx.font_manager = NULL;
290 }
291 
292 #else
293 
setUp(void)294 void setUp(void)
295 {
296 }
297 
tearDown(void)298 void tearDown(void)
299 {
300 }
301 
test_font_stress(void)302 void test_font_stress(void)
303 {
304 }
305 
test_font_manager_stress(void)306 void test_font_manager_stress(void)
307 {
308 }
309 
310 #endif
311 
312 #endif
313