diff --git a/docs/src/libs/font_support/freetype.mdx b/docs/src/libs/font_support/freetype.mdx index cec6fdad89..5d2e464fbe 100644 --- a/docs/src/libs/font_support/freetype.mdx +++ b/docs/src/libs/font_support/freetype.mdx @@ -98,6 +98,17 @@ software, and can be set by using following values where style values are requir These values can be combined, e.g. . + is only supported with `LV_FREETYPE_FONT_RENDER_MODE_OUTLINE`, +unless the font is variable weight. + +Variable weight fonts are supported. You can set the weight of the font by using + and setting the `weight` field of +. The weight value follows CSS conventions (1-2000, +typical: 100-900 where 400 = normal, 700 = bold). If `weight` is 0 (default), +the weight is determined by the style: +maps to 700, otherwise 400. If the font is not a variable weight font, the weight +setting will have no effect. + The FreeType extension also supports colored bitmap glyphs such as emojis. Note that only bitmaps are supported at this time. Colored vector graphics cannot be rendered. An example on how to draw a colored bitmap glyph is shown below. diff --git a/include/lvgl/font/lv_font.h b/include/lvgl/font/lv_font.h index 59760fb410..5883440d52 100644 --- a/include/lvgl/font/lv_font.h +++ b/include/lvgl/font/lv_font.h @@ -178,6 +178,7 @@ struct _lv_font_info_t { uint32_t size; /**< Font size in pixel*/ uint32_t render_mode; /**< Font rendering mode, see `lv_freetype_font_render_mode_t`*/ uint32_t style; /**< Font style, see `lv_freetype_font_style_t`*/ + int32_t weight; /**< Font weight for variable fonts (range 1-2000, CSS-like values 100-900; 0 = default: 400 normal, 700 if bold style) */ lv_font_kerning_t kerning; /**< Font kerning, see `lv_font_kerning_t`*/ }; diff --git a/include/lvgl/font/lv_freetype.h b/include/lvgl/font/lv_freetype.h index aecf81abf2..93129465da 100755 --- a/include/lvgl/font/lv_freetype.h +++ b/include/lvgl/font/lv_freetype.h @@ -60,7 +60,7 @@ typedef enum { LV_FREETYPE_OUTLINE_CONIC_TO, } lv_freetype_outline_type_t; -/* Only path string is required */ +/** Only path string is required */ typedef const char lv_freetype_font_src_t; LV_ATTRIBUTE_EXTERN_DATA extern const lv_font_class_t lv_freetype_font_class; @@ -101,7 +101,9 @@ lv_font_t * lv_freetype_font_create_with_info(const lv_font_info_t * font_info); * @param style font style(see lv_freetype_font_style_t for details). * @return Created font, or NULL on failure. */ -lv_font_t * lv_freetype_font_create(const char * pathname, lv_freetype_font_render_mode_t render_mode, uint32_t size, +lv_font_t * lv_freetype_font_create(const char * pathname, + lv_freetype_font_render_mode_t render_mode, + uint32_t size, lv_freetype_font_style_t style); /** diff --git a/src/draw/sw/lv_draw_sw_letter.c b/src/draw/sw/lv_draw_sw_letter.c index 7b8b253f63..5dfeec2d70 100644 --- a/src/draw/sw/lv_draw_sw_letter.c +++ b/src/draw/sw/lv_draw_sw_letter.c @@ -390,9 +390,7 @@ static void freetype_outline_event_cb(lv_event_t * e) lv_vector_path_quad_to(path, &ctrl_pnt1, &pnt); break; case LV_FREETYPE_OUTLINE_END: - /* It's not necessary to close the path and - * border start is handled above - */ + /* It's not necessary to close the path */ break; } break; diff --git a/src/font/lv_font.c b/src/font/lv_font.c index c05effc96b..fbbef8d38b 100644 --- a/src/font/lv_font.c +++ b/src/font/lv_font.c @@ -185,6 +185,7 @@ bool lv_font_info_is_equal(const lv_font_info_t * ft_info_1, const lv_font_info_ bool is_equal = (ft_info_1->size == ft_info_2->size && ft_info_1->style == ft_info_2->style && ft_info_1->render_mode == ft_info_2->render_mode + && ft_info_1->weight == ft_info_2->weight && ft_info_1->kerning == ft_info_2->kerning && lv_strcmp(ft_info_1->name, ft_info_2->name) == 0); diff --git a/src/libs/freetype/lv_freetype.c b/src/libs/freetype/lv_freetype.c index 9fb57ddbec..568b967f3b 100755 --- a/src/libs/freetype/lv_freetype.c +++ b/src/libs/freetype/lv_freetype.c @@ -21,6 +21,20 @@ #define ft_ctx LV_GLOBAL_DEFAULT()->ft_context #define LV_FREETYPE_OUTLINE_REF_SIZE_DEF 128 +/* Temporary stack buffer size for variable-font axes. + * Most fonts have only a few axes; use heap only when needed. */ +#define LV_FREETYPE_MAX_STACK_AXES 8 + +/* Clamp for requested variable font weight before converting to 16.16. + * Fonts commonly use CSS-like 100..900, but some support extended ranges. + * Keeping this bounded avoids unreasonable inputs and keeps conversion safe. */ +#define LV_FREETYPE_VAR_WEIGHT_MIN 1 +#define LV_FREETYPE_VAR_WEIGHT_MAX 2000 + +#define LV_FREETYPE_VAR_WEIGHT_DEFAULT 0 /**< 0 = resolved from style: NORMAL(400) or BOLD(700) */ +#define LV_FREETYPE_VAR_WEIGHT_NORMAL 400 +#define LV_FREETYPE_VAR_WEIGHT_BOLD 700 + /**< This value is from the FreeType's function `FT_GlyphSlot_Oblique` in `ftsynth.c` */ #define LV_FREETYPE_OBLIQUE_SLANT_DEF 0x0366A @@ -51,6 +65,7 @@ static bool cache_node_cache_create_cb(lv_freetype_cache_node_t * node, void * u static void cache_node_cache_free_cb(lv_freetype_cache_node_t * node, void * user_data); static lv_cache_compare_res_t cache_node_cache_compare_cb(const lv_freetype_cache_node_t * lhs, const lv_freetype_cache_node_t * rhs); +static bool lv_freetype_set_weight_if_variable(FT_Face face, int weight); static lv_font_t * freetype_font_create_cb(const lv_font_info_t * info, const void * src); static void freetype_font_delete_cb(lv_font_t * font); @@ -135,6 +150,7 @@ void lv_freetype_init_font_info(lv_font_info_t * font_info) font_info->class_p = &lv_freetype_font_class; font_info->render_mode = LV_FREETYPE_FONT_RENDER_MODE_BITMAP; font_info->style = LV_FREETYPE_FONT_STYLE_NORMAL; + font_info->weight = LV_FREETYPE_VAR_WEIGHT_DEFAULT; font_info->kerning = LV_FONT_KERNING_NONE; } @@ -160,6 +176,9 @@ lv_font_t * lv_freetype_font_create_with_info(const lv_font_info_t * font_info) .pathname = lv_freetype_req_face_id(ctx, pathname), .style = font_info->style, .render_mode = font_info->render_mode, + /* Normalize weight: DEFAULT(0) resolves to BOLD(700) or NORMAL(400) to avoid duplicate cache nodes */ + .weight = font_info->weight > LV_FREETYPE_VAR_WEIGHT_DEFAULT ? font_info->weight + : ((font_info->style & LV_FREETYPE_FONT_STYLE_BOLD) ? LV_FREETYPE_VAR_WEIGHT_BOLD : LV_FREETYPE_VAR_WEIGHT_NORMAL), }; bool cache_hitting = true; @@ -442,8 +461,113 @@ static bool cache_node_cache_create_cb(lv_freetype_cache_node_t * node, void * u lv_freetype_glyph_l1_init(node); #endif + /* Apply variable font weight */ + if(!lv_freetype_set_weight_if_variable(face, node->weight)) { + /* Only log when an explicit weight was requested, to avoid spamming logs + * for default weights on non-variable fonts. */ + if(node->weight != LV_FREETYPE_VAR_WEIGHT_NORMAL && node->weight != LV_FREETYPE_VAR_WEIGHT_BOLD) { + LV_LOG_INFO("font '%s' does not support variable weight, requested weight %d ignored", node->pathname, node->weight); + } + } + return true; } + +static void lv_freetype_done_mm_var(FT_MM_Var * mm_var) +{ + lv_freetype_context_t * ctx = lv_freetype_get_context(); + LV_ASSERT_NULL(ctx); + LV_ASSERT_NULL(ctx->library); + FT_Error err = FT_Done_MM_Var(ctx->library, mm_var); + if(err != 0) { + FT_ERROR_MSG("FT_Done_MM_Var", err); + } +} + +/* If the font is variable, set the 'wght' axis to the requested value. Returns true if applied. */ +static bool lv_freetype_set_weight_if_variable(FT_Face face, int weight) +{ + if(!face) + return false; + if(!FT_HAS_MULTIPLE_MASTERS(face)) + return false; + + FT_MM_Var * mm_var = NULL; + FT_Error mm_err = FT_Get_MM_Var(face, &mm_var); + if(mm_err != 0 || !mm_var || mm_var->num_axis == 0) { + if(mm_err != 0) { + FT_ERROR_MSG("FT_Get_MM_Var", mm_err); + } + else if(mm_var) { + /* FT_Get_MM_Var succeeded but no usable axes; free to avoid leak */ + lv_freetype_done_mm_var(mm_var); + } + + return false; + } + + FT_UInt axis_count = mm_var->num_axis; + FT_Fixed coords_stack[LV_FREETYPE_MAX_STACK_AXES]; + FT_Fixed * coords = coords_stack; + const bool use_heap = axis_count > LV_FREETYPE_MAX_STACK_AXES; + bool applied = false; + FT_ULong wght_tag; + int wght_index; + FT_UInt i; + + if(use_heap) { + coords = (FT_Fixed *)lv_malloc(axis_count * sizeof(FT_Fixed)); + LV_ASSERT_MALLOC(coords); + if(!coords) { + LV_LOG_ERROR("failed to allocate memory for %u font axes", axis_count); + lv_freetype_done_mm_var(mm_var); + return false; + } + } + + FT_Error coord_err = FT_Get_Var_Design_Coordinates(face, axis_count, coords); + if(coord_err != 0) { + FT_ERROR_MSG("FT_Get_Var_Design_Coordinates", coord_err); + goto cleanup; + } + + wght_tag = FT_MAKE_TAG('w', 'g', 'h', 't'); + wght_index = -1; + for(i = 0; i < axis_count; i++) { + if(mm_var->axis[i].tag == wght_tag) { + wght_index = (int)i; + break; + } + } + + if(wght_index >= 0) { + FT_Fixed min_v = mm_var->axis[wght_index].minimum; + FT_Fixed max_v = mm_var->axis[wght_index].maximum; + FT_Fixed target; + FT_Error set_err; + + weight = LV_CLAMP(LV_FREETYPE_VAR_WEIGHT_MIN, weight, LV_FREETYPE_VAR_WEIGHT_MAX); + target = LV_CLAMP(min_v, FT_INT_TO_F16DOT16(weight), max_v); + coords[wght_index] = target; + + set_err = FT_Set_Var_Design_Coordinates(face, axis_count, coords); + if(set_err != 0) { + FT_ERROR_MSG("FT_Set_Var_Design_Coordinates", set_err); + } + else { + applied = true; + } + } + +cleanup: + if(use_heap) { + lv_free(coords); + } + + lv_freetype_done_mm_var(mm_var); + return applied; +} + static void cache_node_cache_free_cb(lv_freetype_cache_node_t * node, void * user_data) { #if LV_FREETYPE_CACHE_FT_GLYPH_L1 @@ -471,6 +595,9 @@ static lv_cache_compare_res_t cache_node_cache_compare_cb(const lv_freetype_cach if(lhs->style != rhs->style) { return lhs->style > rhs->style ? 1 : -1; } + if(lhs->weight != rhs->weight) { + return lhs->weight > rhs->weight ? 1 : -1; + } int32_t cmp_res = lv_strcmp(lhs->pathname, rhs->pathname); if(cmp_res != 0) { @@ -482,6 +609,7 @@ static lv_cache_compare_res_t cache_node_cache_compare_cb(const lv_freetype_cach static lv_font_t * freetype_font_create_cb(const lv_font_info_t * info, const void * src) { + LV_ASSERT_NULL(info); lv_font_info_t font_info = *info; font_info.name = src; return lv_freetype_font_create_with_info(&font_info); diff --git a/src/libs/freetype/lv_freetype_outline.c b/src/libs/freetype/lv_freetype_outline.c index ca094c2dd0..f0c48a643f 100755 --- a/src/libs/freetype/lv_freetype_outline.c +++ b/src/libs/freetype/lv_freetype_outline.c @@ -130,7 +130,7 @@ static bool freetype_glyph_outline_create_cb(lv_freetype_outline_node_t * node, dsc->cache_node->face, node->glyph_index, dsc->cache_node->ref_size, - dsc->style & LV_FREETYPE_FONT_STYLE_BOLD ? 1 : 0); + (dsc->style & LV_FREETYPE_FONT_STYLE_BOLD) && !FT_HAS_MULTIPLE_MASTERS(dsc->cache_node->face) ? 1 : 0); lv_mutex_unlock(&dsc->cache_node->face_lock); if(!outline) { diff --git a/src/libs/freetype/lv_freetype_private.h b/src/libs/freetype/lv_freetype_private.h index ce3004213b..9f1c0d3023 100755 --- a/src/libs/freetype/lv_freetype_private.h +++ b/src/libs/freetype/lv_freetype_private.h @@ -27,6 +27,7 @@ extern "C" { #include FT_IMAGE_H #include FT_OUTLINE_H #include FT_STROKER_H +#include FT_MULTIPLE_MASTERS_H /********************* * DEFINES @@ -90,6 +91,7 @@ struct _lv_freetype_cache_node_t { const char * pathname; lv_freetype_font_style_t style; lv_freetype_font_render_mode_t render_mode; + int32_t weight; /**< Variable font weight (range 1-2000, 0 = default; values are clamped) */ uint32_t ref_size; /**< Reference size for calculating outline glyph's real size.*/ diff --git a/tests/ref_imgs/libs/freetype_render_bitmap.lp32.png b/tests/ref_imgs/libs/freetype_render_bitmap.lp32.png index 6b01f4b1a6..7bc3dde442 100644 Binary files a/tests/ref_imgs/libs/freetype_render_bitmap.lp32.png and b/tests/ref_imgs/libs/freetype_render_bitmap.lp32.png differ diff --git a/tests/ref_imgs/libs/freetype_render_bitmap.lp64.png b/tests/ref_imgs/libs/freetype_render_bitmap.lp64.png index 3bdc2ea213..7bc3dde442 100644 Binary files a/tests/ref_imgs/libs/freetype_render_bitmap.lp64.png and b/tests/ref_imgs/libs/freetype_render_bitmap.lp64.png differ diff --git a/tests/ref_imgs/libs/freetype_render_outline.lp32.png b/tests/ref_imgs/libs/freetype_render_outline.lp32.png index 7e6c7f3914..191ff515b4 100644 Binary files a/tests/ref_imgs/libs/freetype_render_outline.lp32.png and b/tests/ref_imgs/libs/freetype_render_outline.lp32.png differ diff --git a/tests/ref_imgs/libs/freetype_render_outline.lp64.png b/tests/ref_imgs/libs/freetype_render_outline.lp64.png index b1e0170291..682b2ade6a 100644 Binary files a/tests/ref_imgs/libs/freetype_render_outline.lp64.png and b/tests/ref_imgs/libs/freetype_render_outline.lp64.png differ diff --git a/tests/ref_imgs_vg_lite/libs/freetype_render_bitmap.lp32.png b/tests/ref_imgs_vg_lite/libs/freetype_render_bitmap.lp32.png index 9dc7949b38..5dee84cc8b 100644 Binary files a/tests/ref_imgs_vg_lite/libs/freetype_render_bitmap.lp32.png and b/tests/ref_imgs_vg_lite/libs/freetype_render_bitmap.lp32.png differ diff --git a/tests/ref_imgs_vg_lite/libs/freetype_render_bitmap.lp64.png b/tests/ref_imgs_vg_lite/libs/freetype_render_bitmap.lp64.png index 9072900649..5dee84cc8b 100644 Binary files a/tests/ref_imgs_vg_lite/libs/freetype_render_bitmap.lp64.png and b/tests/ref_imgs_vg_lite/libs/freetype_render_bitmap.lp64.png differ diff --git a/tests/ref_imgs_vg_lite/libs/freetype_render_outline.lp32.png b/tests/ref_imgs_vg_lite/libs/freetype_render_outline.lp32.png index 80ff389c74..b5d2dd8461 100644 Binary files a/tests/ref_imgs_vg_lite/libs/freetype_render_outline.lp32.png and b/tests/ref_imgs_vg_lite/libs/freetype_render_outline.lp32.png differ diff --git a/tests/ref_imgs_vg_lite/libs/freetype_render_outline.lp64.png b/tests/ref_imgs_vg_lite/libs/freetype_render_outline.lp64.png index e7041a7930..9bb2ca1a5d 100644 Binary files a/tests/ref_imgs_vg_lite/libs/freetype_render_outline.lp64.png and b/tests/ref_imgs_vg_lite/libs/freetype_render_outline.lp64.png differ diff --git a/tests/src/test_cases/libs/test_freetype.c b/tests/src/test_cases/libs/test_freetype.c index 84767e190f..068c5a46fb 100644 --- a/tests/src/test_cases/libs/test_freetype.c +++ b/tests/src/test_cases/libs/test_freetype.c @@ -61,6 +61,34 @@ static void test_freetype_with_render_mode(lv_freetype_font_render_mode_t render LV_FREETYPE_FONT_STYLE_NORMAL); TEST_ASSERT_NOT_NULL(font_normal_small); + lv_font_t * font_variable_default = lv_freetype_font_create( + "./src/test_files/fonts/Montserrat-VariableFont.ttf", render_mode, 24, LV_FREETYPE_FONT_STYLE_NORMAL); + TEST_ASSERT_NOT_NULL(font_variable_default); + + lv_font_t * font_variable_bold = lv_freetype_font_create( + "./src/test_files/fonts/Montserrat-VariableFont.ttf", render_mode, 24, LV_FREETYPE_FONT_STYLE_BOLD); + TEST_ASSERT_NOT_NULL(font_variable_bold); + + /* Use lv_font_info_t to set explicit weight */ + lv_font_info_t info_thin; + lv_freetype_init_font_info(&info_thin); + info_thin.name = "./src/test_files/fonts/Montserrat-VariableFont.ttf"; + info_thin.render_mode = render_mode; + info_thin.size = 24; + info_thin.style = LV_FREETYPE_FONT_STYLE_ITALIC; + info_thin.weight = 300; + lv_font_t * font_variable_thin = lv_freetype_font_create_with_info(&info_thin); + TEST_ASSERT_NOT_NULL(font_variable_thin); + + lv_font_info_t info_thick; + lv_freetype_init_font_info(&info_thick); + info_thick.name = "./src/test_files/fonts/Montserrat-VariableFont.ttf"; + info_thick.render_mode = render_mode; + info_thick.size = 24; + info_thick.weight = 1000; + lv_font_t * font_variable_thick = lv_freetype_font_create_with_info(&info_thick); + TEST_ASSERT_NOT_NULL(font_variable_thick); + /* Emoji is only supported in bitmap mode */ lv_font_t * font_emoji = lv_freetype_font_create("../examples/libs/freetype/NotoColorEmoji-32.subset.ttf", LV_FREETYPE_FONT_RENDER_MODE_BITMAP, @@ -68,8 +96,7 @@ static void test_freetype_with_render_mode(lv_freetype_font_render_mode_t render LV_FREETYPE_FONT_STYLE_NORMAL); TEST_ASSERT_NOT_NULL(font_emoji); - lv_font_t * font_path_error = lv_freetype_font_create("ERROR_PATH", render_mode, 24, - LV_FREETYPE_FONT_STYLE_NORMAL); + lv_font_t * font_path_error = lv_freetype_font_create("ERROR_PATH", render_mode, 24, LV_FREETYPE_FONT_STYLE_NORMAL); TEST_ASSERT_NULL(font_path_error); font_path_error = lv_freetype_font_create("", render_mode, 24, LV_FREETYPE_FONT_STYLE_NORMAL); @@ -101,30 +128,70 @@ static void test_freetype_with_render_mode(lv_freetype_font_render_mode_t render static lv_style_t style_normal_small; lv_style_init(&style_normal_small); lv_style_set_text_font(&style_normal_small, font_normal_small); + lv_style_set_text_align(&style_normal_small, LV_TEXT_ALIGN_CENTER); + + static lv_style_t style_variable_default; + lv_style_init(&style_variable_default); + lv_style_set_text_font(&style_variable_default, font_variable_default); + lv_style_set_text_align(&style_variable_default, LV_TEXT_ALIGN_CENTER); + + static lv_style_t style_variable_bold; + lv_style_init(&style_variable_bold); + lv_style_set_text_font(&style_variable_bold, font_variable_bold); + lv_style_set_text_align(&style_variable_bold, LV_TEXT_ALIGN_CENTER); + + static lv_style_t style_variable_thin; + lv_style_init(&style_variable_thin); + lv_style_set_text_font(&style_variable_thin, font_variable_thin); + lv_style_set_text_align(&style_variable_thin, LV_TEXT_ALIGN_CENTER); + + static lv_style_t style_variable_thick; + lv_style_init(&style_variable_thick); + lv_style_set_text_font(&style_variable_thick, font_variable_thick); + lv_style_set_text_align(&style_variable_thick, LV_TEXT_ALIGN_CENTER); static lv_style_t style_normal_emoji; lv_style_init(&style_normal_emoji); lv_style_set_text_font(&style_normal_emoji, font_emoji); lv_style_set_text_align(&style_normal_emoji, LV_TEXT_ALIGN_CENTER); + lv_obj_set_flex_flow(lv_screen_active(), LV_FLEX_FLOW_COLUMN); + /*Create a label with the new style*/ lv_obj_t * label0 = lv_label_create(lv_screen_active()); lv_obj_add_style(label0, &style_italic, 0); lv_obj_set_width(label0, lv_obj_get_width(lv_screen_active()) - 20); lv_label_set_text(label0, UNIVERSAL_DECLARATION_OF_HUMAN_RIGHTS_CN); - lv_obj_align(label0, LV_ALIGN_TOP_MID, 0, 10); lv_obj_t * label1 = lv_label_create(lv_screen_active()); lv_obj_add_style(label1, &style_normal_with_outline, 0); lv_obj_set_width(label1, lv_obj_get_width(lv_screen_active()) - 20); lv_label_set_text(label1, UNIVERSAL_DECLARATION_OF_HUMAN_RIGHTS_EN); - lv_obj_align_to(label1, label0, LV_ALIGN_OUT_BOTTOM_MID, 0, 10); lv_obj_t * label2 = lv_label_create(lv_screen_active()); lv_obj_add_style(label2, &style_normal_small, 0); lv_obj_set_width(label2, lv_obj_get_width(lv_screen_active()) - 20); lv_label_set_text(label2, UNIVERSAL_DECLARATION_OF_HUMAN_RIGHTS_JP); - lv_obj_align_to(label2, label1, LV_ALIGN_OUT_BOTTOM_MID, 0, 10); + + lv_obj_t * label3 = lv_label_create(lv_screen_active()); + lv_obj_add_style(label3, &style_variable_default, 0); + lv_obj_set_width(label3, lv_obj_get_width(lv_screen_active()) - 20); + lv_label_set_text(label3, "Variable Font Default Weight"); + + lv_obj_t * label4 = lv_label_create(lv_screen_active()); + lv_obj_add_style(label4, &style_variable_bold, 0); + lv_obj_set_width(label4, lv_obj_get_width(lv_screen_active()) - 20); + lv_label_set_text(label4, "Variable Font Bold Weight"); + + lv_obj_t * label5 = lv_label_create(lv_screen_active()); + lv_obj_add_style(label5, &style_variable_thin, 0); + lv_obj_set_width(label5, lv_obj_get_width(lv_screen_active()) - 20); + lv_label_set_text(label5, "Variable Font 300 Weight"); + + lv_obj_t * label6 = lv_label_create(lv_screen_active()); + lv_obj_add_style(label6, &style_variable_thick, 0); + lv_obj_set_width(label6, lv_obj_get_width(lv_screen_active()) - 20); + lv_label_set_text(label6, "Variable Font 1000 Weight"); /* test emoji rendering * emoji font does not contain normal characters, use fallback to render them */ @@ -134,19 +201,27 @@ static void test_freetype_with_render_mode(lv_freetype_font_render_mode_t render lv_obj_add_style(label_emoji, &style_normal_emoji, 0); lv_obj_set_width(label_emoji, lv_obj_get_width(lv_screen_active()) - 20); lv_label_set_text(label_emoji, "FreeType Emoji test: 😀"); - lv_obj_align_to(label_emoji, label2, LV_ALIGN_OUT_BOTTOM_MID, 0, 10); TEST_ASSERT_EQUAL_SCREENSHOT(screenshot_name); + lv_obj_set_layout(lv_screen_active(), LV_LAYOUT_NONE); lv_obj_clean(lv_screen_active()); lv_style_reset(&style_italic); lv_style_reset(&style_normal_with_outline); lv_style_reset(&style_normal_small); + lv_style_reset(&style_variable_default); + lv_style_reset(&style_variable_bold); + lv_style_reset(&style_variable_thin); + lv_style_reset(&style_variable_thick); lv_style_reset(&style_normal_emoji); lv_freetype_font_delete(font_italic); lv_freetype_font_delete(font_normal); lv_freetype_font_delete(font_normal_small); lv_freetype_font_delete(font_emoji); + lv_freetype_font_delete(font_variable_default); + lv_freetype_font_delete(font_variable_bold); + lv_freetype_font_delete(font_variable_thin); + lv_freetype_font_delete(font_variable_thick); } void test_freetype_render_bitmap(void) diff --git a/tests/src/test_files/fonts/Montserrat-VariableFont.ttf b/tests/src/test_files/fonts/Montserrat-VariableFont.ttf new file mode 100644 index 0000000000..451e69288c Binary files /dev/null and b/tests/src/test_files/fonts/Montserrat-VariableFont.ttf differ