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