diff --git a/docs/src/details/common-widget-features/styles/style-properties.rst b/docs/src/details/common-widget-features/styles/style-properties.rst
index 752c24dfda..367efeda8f 100644
--- a/docs/src/details/common-widget-features/styles/style-properties.rst
+++ b/docs/src/details/common-widget-features/styles/style-properties.rst
@@ -1221,6 +1221,48 @@ Set how to align the lines of the text. Note that it doesn't align the Widget it
Ext. draw No
+text_outline_stroke_color
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sets the color of letter outline stroke.
+
+.. raw:: html
+
+
+ - Default `0x000000`
+ - Inherited Yes
+ - Layout No
+ - Ext. draw No
+
+
+text_outline_stroke_width
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Set the letter outline stroke width in pixels.
+
+.. raw:: html
+
+
+ - Default 0
+ - Inherited Yes
+ - Layout Yes
+ - Ext. draw No
+
+
+text_outline_stroke_opa
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Set the opacity of the letter outline stroke. Value 0, `LV_OPA_0` or `LV_OPA_TRANSP` means fully transparent, 255, `LV_OPA_100` or `LV_OPA_COVER` means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency.
+
+.. raw:: html
+
+
+ - Default `LV_OPA_COVER`
+ - Inherited Yes
+ - Layout No
+ - Ext. draw No
+
+
Miscellaneous
-------------
diff --git a/docs/src/details/libs/freetype.rst b/docs/src/details/libs/freetype.rst
index 3ad38b6c13..ff37ee2cc8 100644
--- a/docs/src/details/libs/freetype.rst
+++ b/docs/src/details/libs/freetype.rst
@@ -30,7 +30,7 @@ There are two ways to use FreeType:
For UNIX
--------
-For UNIX systems, the following is recommended to compile and install FreeType libraries.
+For UNIX-like systems, the following is recommended to compile and install FreeType libraries.
- Enter the FreeType source code directory
- ``make``
@@ -124,6 +124,22 @@ please refer to the example code below.
- `FreeType tutorial `__
- LVGL's :ref:`add_font`
+Rendering vector fonts is supported with VGLite or ThorVG,
+when using vector fonts with ThorVG, it is possible to set a letter outline of a different color.
+
+This is achieved by setting the style attributes with the
+:cpp:func:`lv_style_set_text_outline_width` and :cpp:func:`lv_style_set_text_outline_color` functions
+
+You will have to account for the increased width and height of letter due to the added letter outline,
+to avoid letters overlapping space them out using :cpp:func:`lv_style_set_text_letter_space`
+
+To use vector fonts with ThorVG, you will have to enable ``LV_USE_VECTOR_GRAPHICS`` in ``lv_conf.h``
+
+.. note::
+
+ This feature is currently experimental, there are clipping issues especially when using large font sizes.
+
+See the :cpp:func:`lv_example_freetype_2_vector_font` function for a usage example
.. _freetype_example:
diff --git a/examples/libs/freetype/lv_example_freetype.h b/examples/libs/freetype/lv_example_freetype.h
index 28a61c17d0..ca234b2ddc 100644
--- a/examples/libs/freetype/lv_example_freetype.h
+++ b/examples/libs/freetype/lv_example_freetype.h
@@ -27,6 +27,7 @@ extern "C" {
**********************/
void lv_example_freetype_1(void);
void lv_example_freetype_2(void);
+void lv_example_freetype_2_vector_font(uint32_t font_size, uint32_t border_width);
/**********************
* MACROS
diff --git a/examples/libs/freetype/lv_example_freetype_2.c b/examples/libs/freetype/lv_example_freetype_2.c
index 3067fb70b0..095ccc7810 100644
--- a/examples/libs/freetype/lv_example_freetype_2.c
+++ b/examples/libs/freetype/lv_example_freetype_2.c
@@ -5,9 +5,49 @@
#if LV_FREETYPE_USE_LVGL_PORT
#define PATH_PREFIX "A:"
#else
- #define PATH_PREFIX "../"
+ #define PATH_PREFIX "./"
#endif
+/*
+ * Load a vector font
+ * ThorVG needs to be enabled, LV_USE_VECTOR_GRAPHICS=1
+ */
+void lv_example_freetype_2_vector_font(uint32_t font_size, uint32_t border_width)
+{
+ lv_font_t * font = lv_freetype_font_create(PATH_PREFIX "lvgl/examples/libs/freetype/Lato-Regular.ttf",
+ LV_FREETYPE_FONT_RENDER_MODE_OUTLINE,
+ font_size,
+ LV_FREETYPE_FONT_STYLE_NORMAL);
+
+
+ if(!font) {
+ LV_LOG_ERROR("Freetype font create failed.");
+ return;
+ }
+
+ /*Create style with the new font*/
+ static lv_style_t style;
+ lv_style_init(&style);
+ lv_style_set_text_font(&style, font);
+ lv_style_set_text_align(&style, LV_TEXT_ALIGN_CENTER);
+ lv_style_set_text_color(&style, lv_color_hex(0xFF0000));
+ lv_style_set_text_opa(&style, LV_OPA_100);
+ lv_style_set_text_outline_stroke_opa(&style, LV_OPA_100);
+ lv_style_set_text_outline_stroke_color(&style, lv_color_hex(0x00FF00));
+ lv_style_set_text_outline_stroke_width(&style, border_width);
+
+ /*Avoid overlapping issue when using letter outlines*/
+ lv_style_set_text_letter_space(&style, border_width);
+ lv_style_set_text_line_space(&style, border_width);
+
+ /*Create a label with the new style*/
+ lv_obj_t * label = lv_label_create(lv_screen_active());
+ lv_obj_add_style(label, &style, 0);
+ lv_label_set_text(label, "Hello world\nI'm a font created with FreeType");
+ lv_obj_center(label);
+
+}
+
/**
* Load a font with FreeType
*/
@@ -16,7 +56,7 @@ void lv_example_freetype_2(void)
/*Create a font*/
lv_font_t * font = lv_freetype_font_create(PATH_PREFIX "lvgl/examples/libs/freetype/Lato-Regular.ttf",
LV_FREETYPE_FONT_RENDER_MODE_BITMAP,
- 24,
+ 400,
LV_FREETYPE_FONT_STYLE_NORMAL);
/* this font is created from a downscaled NotoColorEmoji to 34x32px
@@ -24,7 +64,7 @@ void lv_example_freetype_2(void)
* Command: fonttools subset NotoColorEmoji.ttf --text=😀 */
lv_font_t * font_emoji = lv_freetype_font_create(PATH_PREFIX "lvgl/examples/libs/freetype/NotoColorEmoji-32.subset.ttf",
LV_FREETYPE_FONT_RENDER_MODE_BITMAP,
- 24,
+ 200,
LV_FREETYPE_FONT_STYLE_NORMAL);
if(!font || !font_emoji) {
diff --git a/scripts/style_api_gen.py b/scripts/style_api_gen.py
index 75e108def1..21acadcaf8 100755
--- a/scripts/style_api_gen.py
+++ b/scripts/style_api_gen.py
@@ -348,6 +348,18 @@ props = [
'style_type': 'num', 'var_type': 'lv_text_align_t' , 'default':'`LV_TEXT_ALIGN_AUTO`', 'inherited': 1, 'layout': 1, 'ext_draw': 0,
'dsc': "Set how to align the lines of the text. Note that it doesn't align the Widget itself, only the lines inside the Widget. Possible values are `LV_TEXT_ALIGN_LEFT/CENTER/RIGHT/AUTO`. `LV_TEXT_ALIGN_AUTO` detect the text base direction and uses left or right alignment accordingly"},
+{'name': 'TEXT_OUTLINE_STROKE_COLOR',
+'style_type': 'color', 'var_type': 'lv_color_t', 'default':'`0x000000`', 'inherited': 1, 'layout': 0, 'ext_draw': 0, 'filtered': 1,
+ 'dsc': "Sets the color of letter outline stroke."},
+
+{'name': 'TEXT_OUTLINE_STROKE_WIDTH',
+ 'style_type': 'num', 'var_type': 'int32_t' , 'default':0, 'inherited': 1, 'layout': 1, 'ext_draw': 0,
+ 'dsc': "Set the letter outline stroke width in pixels."},
+
+{'name': 'TEXT_OUTLINE_STROKE_OPA',
+ 'style_type': 'num', 'var_type': 'lv_opa_t', 'default':'`LV_OPA_COVER`', 'inherited': 1, 'layout': 0, 'ext_draw': 0,
+ 'dsc': "Set the opacity of the letter outline stroke. Value 0, `LV_OPA_0` or `LV_OPA_TRANSP` means fully transparent, 255, `LV_OPA_100` or `LV_OPA_COVER` means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency."},
+
{'section': 'Miscellaneous', 'dsc':'Mixed properties for various purposes.' },
{'name': 'RADIUS',
'style_type': 'num', 'var_type': 'int32_t', 'default':0, 'inherited': 0, 'layout': 0, 'ext_draw': 0,
diff --git a/src/core/lv_obj_style_gen.c b/src/core/lv_obj_style_gen.c
index 5fcb31df17..8910d9a0e3 100644
--- a/src/core/lv_obj_style_gen.c
+++ b/src/core/lv_obj_style_gen.c
@@ -674,6 +674,30 @@ void lv_obj_set_style_text_align(lv_obj_t * obj, lv_text_align_t value, lv_style
lv_obj_set_local_style_prop(obj, LV_STYLE_TEXT_ALIGN, v, selector);
}
+void lv_obj_set_style_text_outline_stroke_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector)
+{
+ lv_style_value_t v = {
+ .color = value
+ };
+ lv_obj_set_local_style_prop(obj, LV_STYLE_TEXT_OUTLINE_STROKE_COLOR, v, selector);
+}
+
+void lv_obj_set_style_text_outline_stroke_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
+{
+ lv_style_value_t v = {
+ .num = (int32_t)value
+ };
+ lv_obj_set_local_style_prop(obj, LV_STYLE_TEXT_OUTLINE_STROKE_WIDTH, v, selector);
+}
+
+void lv_obj_set_style_text_outline_stroke_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
+{
+ lv_style_value_t v = {
+ .num = (int32_t)value
+ };
+ lv_obj_set_local_style_prop(obj, LV_STYLE_TEXT_OUTLINE_STROKE_OPA, v, selector);
+}
+
void lv_obj_set_style_radius(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
{
lv_style_value_t v = {
diff --git a/src/core/lv_obj_style_gen.h b/src/core/lv_obj_style_gen.h
index 0e13447567..ff85e38b92 100644
--- a/src/core/lv_obj_style_gen.h
+++ b/src/core/lv_obj_style_gen.h
@@ -577,6 +577,30 @@ static inline lv_text_align_t lv_obj_get_style_text_align(const lv_obj_t * obj,
return (lv_text_align_t)v.num;
}
+static inline lv_color_t lv_obj_get_style_text_outline_stroke_color(const lv_obj_t * obj, lv_part_t part)
+{
+ lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_OUTLINE_STROKE_COLOR);
+ return v.color;
+}
+
+static inline lv_color_t lv_obj_get_style_text_outline_stroke_color_filtered(const lv_obj_t * obj, lv_part_t part)
+{
+ lv_style_value_t v = lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_OUTLINE_STROKE_COLOR));
+ return v.color;
+}
+
+static inline int32_t lv_obj_get_style_text_outline_stroke_width(const lv_obj_t * obj, lv_part_t part)
+{
+ lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_OUTLINE_STROKE_WIDTH);
+ return (int32_t)v.num;
+}
+
+static inline lv_opa_t lv_obj_get_style_text_outline_stroke_opa(const lv_obj_t * obj, lv_part_t part)
+{
+ lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_OUTLINE_STROKE_OPA);
+ return (lv_opa_t)v.num;
+}
+
static inline int32_t lv_obj_get_style_radius(const lv_obj_t * obj, lv_part_t part)
{
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_RADIUS);
@@ -858,6 +882,9 @@ void lv_obj_set_style_text_letter_space(lv_obj_t * obj, int32_t value, lv_style_
void lv_obj_set_style_text_line_space(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
void lv_obj_set_style_text_decor(lv_obj_t * obj, lv_text_decor_t value, lv_style_selector_t selector);
void lv_obj_set_style_text_align(lv_obj_t * obj, lv_text_align_t value, lv_style_selector_t selector);
+void lv_obj_set_style_text_outline_stroke_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector);
+void lv_obj_set_style_text_outline_stroke_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
+void lv_obj_set_style_text_outline_stroke_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
void lv_obj_set_style_radius(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
void lv_obj_set_style_radial_offset(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
void lv_obj_set_style_clip_corner(lv_obj_t * obj, bool value, lv_style_selector_t selector);
diff --git a/src/draw/lv_draw_label.c b/src/draw/lv_draw_label.c
index 2959c07e85..7375d06f85 100644
--- a/src/draw/lv_draw_label.c
+++ b/src/draw/lv_draw_label.c
@@ -315,6 +315,11 @@ void lv_draw_label_iterate_characters(lv_draw_task_t * t, const lv_draw_label_ds
draw_letter_dsc.color = dsc->color;
draw_letter_dsc.rotation = dsc->rotation;
+ /* Set letter outline stroke attributes */
+ draw_letter_dsc.outline_stroke_width = dsc->outline_stroke_width;
+ draw_letter_dsc.outline_stroke_opa = dsc->outline_stroke_opa;
+ draw_letter_dsc.outline_stroke_color = dsc->outline_stroke_color;
+
lv_draw_fill_dsc_t fill_dsc;
lv_draw_fill_dsc_init(&fill_dsc);
fill_dsc.opa = dsc->opa;
@@ -609,6 +614,14 @@ void lv_draw_unit_draw_letter(lv_draw_task_t * t, lv_draw_glyph_dsc_t * dsc, co
}
dsc->format = g.format;
+
+ if(g.format == LV_FONT_GLYPH_FORMAT_VECTOR) {
+
+ /*Load the outline of the glyph, even if the function says bitmap*/
+ g.outline_stroke_width = dsc->outline_stroke_width;
+ dsc->glyph_data = (void *) lv_font_get_glyph_bitmap(&g, draw_buf);
+ dsc->format = dsc->glyph_data ? g.format : LV_FONT_GLYPH_FORMAT_NONE;
+ }
}
else {
dsc->format = LV_FONT_GLYPH_FORMAT_NONE;
diff --git a/src/draw/lv_draw_label.h b/src/draw/lv_draw_label.h
index 5d7db01ff5..f2cc6daadb 100644
--- a/src/draw/lv_draw_label.h
+++ b/src/draw/lv_draw_label.h
@@ -100,6 +100,12 @@ typedef struct {
/**Pointer to an externally stored struct where some data can be cached to speed up rendering*/
lv_draw_label_hint_t * hint;
+
+ /* Properties of the letter outlines */
+ lv_opa_t outline_stroke_opa;
+ lv_color_t outline_stroke_color;
+ int32_t outline_stroke_width;
+
} lv_draw_label_dsc_t;
typedef struct {
@@ -119,6 +125,12 @@ typedef struct {
lv_opa_t opa;
lv_text_decor_t decor : 3;
lv_blend_mode_t blend_mode : 3;
+
+ /* Properties of the letter outlines */
+ lv_opa_t outline_stroke_opa;
+ int32_t outline_stroke_width;
+ lv_color_t outline_stroke_color;
+
} lv_draw_letter_dsc_t;
/**
diff --git a/src/draw/lv_draw_label_private.h b/src/draw/lv_draw_label_private.h
index 0162e4ad89..f4ee4ea03b 100644
--- a/src/draw/lv_draw_label_private.h
+++ b/src/draw/lv_draw_label_private.h
@@ -50,6 +50,9 @@ struct _lv_draw_glyph_dsc_t {
lv_font_glyph_dsc_t * g;
lv_color_t color;
lv_opa_t opa;
+ lv_color_t outline_stroke_color;
+ lv_opa_t outline_stroke_opa;
+ int32_t outline_stroke_width;
int32_t rotation;
lv_point_t pivot; /**< Rotation pivot point associated with total glyph including line_height */
lv_draw_buf_t * _draw_buf; /**< a shared draw buf for get_bitmap, do not use it directly, use glyph_data instead */
diff --git a/src/draw/sw/lv_draw_sw.c b/src/draw/sw/lv_draw_sw.c
index 2747a63041..69fcea80b0 100644
--- a/src/draw/sw/lv_draw_sw.c
+++ b/src/draw/sw/lv_draw_sw.c
@@ -96,7 +96,12 @@ void lv_draw_sw_init(void)
#endif
#if LV_USE_VECTOR_GRAPHIC && LV_USE_THORVG
- tvg_engine_init(TVG_ENGINE_SW, 0);
+ if(LV_DRAW_SW_DRAW_UNIT_CNT > 1) {
+ tvg_engine_init(TVG_ENGINE_SW, LV_DRAW_SW_DRAW_UNIT_CNT);
+ }
+ else {
+ tvg_engine_init(TVG_ENGINE_SW, 0);
+ }
#endif
lv_ll_init(&LV_GLOBAL_DEFAULT()->draw_sw_blend_handler_ll, sizeof(lv_draw_sw_custom_blend_handler_t));
diff --git a/src/draw/sw/lv_draw_sw_letter.c b/src/draw/sw/lv_draw_sw_letter.c
index 740761baa0..911bf3501f 100644
--- a/src/draw/sw/lv_draw_sw_letter.c
+++ b/src/draw/sw/lv_draw_sw_letter.c
@@ -8,7 +8,15 @@
*********************/
#include "blend/lv_draw_sw_blend_private.h"
#include "../lv_draw_label_private.h"
+#include "../../draw/lv_draw_private.h"
#include "lv_draw_sw.h"
+
+#if LV_USE_FREETYPE && LV_USE_VECTOR_GRAPHIC
+
+ #include "../../libs/freetype/lv_freetype_private.h"
+
+#endif
+
#if LV_USE_DRAW_SW
#include "../../display/lv_display.h"
@@ -35,6 +43,13 @@
static void /* LV_ATTRIBUTE_FAST_MEM */ draw_letter_cb(lv_draw_task_t * t, lv_draw_glyph_dsc_t * glyph_draw_dsc,
lv_draw_fill_dsc_t * fill_draw_dsc, const lv_area_t * fill_area);
+#if LV_USE_FREETYPE && LV_USE_VECTOR_GRAPHIC
+
+ static void freetype_outline_event_cb(lv_event_t * e);
+ static void draw_letter_outline(lv_draw_task_t * t, lv_draw_glyph_dsc_t * dsc);
+
+#endif
+
/**********************
* STATIC VARIABLES
**********************/
@@ -84,6 +99,15 @@ void lv_draw_sw_label(lv_draw_task_t * t, const lv_draw_label_dsc_t * dsc, const
if(dsc->opa <= LV_OPA_MIN) return;
LV_PROFILER_DRAW_BEGIN;
+
+#if LV_USE_FREETYPE && LV_USE_VECTOR_GRAPHIC
+ static bool is_init = false;
+ if(!is_init) {
+ lv_freetype_outline_add_event(freetype_outline_event_cb, LV_EVENT_ALL, t);
+ is_init = true;
+ }
+#endif
+
lv_draw_label_iterate_characters(t, dsc, coords, draw_letter_cb);
LV_PROFILER_DRAW_END;
}
@@ -154,6 +178,13 @@ static void LV_ATTRIBUTE_FAST_MEM draw_letter_cb(lv_draw_task_t * t, lv_draw_gly
}
break;
}
+ break;
+#if LV_USE_FREETYPE && LV_USE_VECTOR_GRAPHIC
+ case LV_FONT_GLYPH_FORMAT_VECTOR: {
+ draw_letter_outline(t, glyph_draw_dsc);
+ }
+ break;
+#endif
default:
break;
}
@@ -164,4 +195,216 @@ static void LV_ATTRIBUTE_FAST_MEM draw_letter_cb(lv_draw_task_t * t, lv_draw_gly
}
}
+#if LV_USE_FREETYPE && LV_USE_VECTOR_GRAPHIC
+
+typedef struct {
+ lv_vector_path_t * inside_path; /*The regular glyph*/
+ lv_vector_path_t * outside_path; /*A bigger glyph that goes in the background for the letter outline*/
+ lv_vector_path_t * cur_path;
+} lv_draw_sw_letter_outlines_t;
+
+/*
+ * Renders the vectors paths representing a glyph with ThorVG
+ * the result is then blended into the draw buffer
+ */
+static void draw_letter_outline(lv_draw_task_t * t, lv_draw_glyph_dsc_t * glyph_dsc)
+{
+
+ lv_draw_sw_letter_outlines_t * glyph_paths;
+ lv_vector_dsc_t * vector_dsc;
+ lv_draw_buf_t * draw_buf;
+ lv_matrix_t matrix;
+ lv_layer_t layer;
+
+ glyph_paths = (lv_draw_sw_letter_outlines_t *) glyph_dsc->glyph_data;
+ LV_ASSERT_NULL(glyph_paths);
+
+ int32_t cf;
+ int32_t w;
+ int32_t h;
+ uint32_t stride;
+ float scale;
+ lv_area_t buf_area;
+
+ cf = LV_COLOR_FORMAT_ARGB8888;
+
+ scale = LV_FREETYPE_F26DOT6_TO_FLOAT(lv_freetype_outline_get_scale(glyph_dsc->g->resolved_font));
+ w = (int32_t)((float) glyph_dsc->g->box_w + glyph_dsc->outline_stroke_width * 2 * scale);
+ h = (int32_t)((float) glyph_dsc->g->box_h + glyph_dsc->outline_stroke_width * 2 * scale);
+ buf_area.x1 = 0;
+ buf_area.y1 = 0;
+ lv_area_set_width(&buf_area, w);
+ lv_area_set_height(&buf_area, h);
+
+ stride = lv_draw_buf_width_to_stride(w, cf);
+ draw_buf = lv_draw_buf_create(w, h, cf, stride);
+ lv_draw_buf_clear(draw_buf, NULL);
+
+ lv_memzero(&layer, sizeof(lv_layer_t));
+ layer.draw_buf = draw_buf;
+ layer.color_format = cf;
+ layer.buf_area = buf_area;
+ layer.phy_clip_area = buf_area;
+ layer._clip_area = buf_area;
+
+ lv_memzero(&matrix, sizeof(lv_matrix_t));
+
+ lv_matrix_identity(&matrix);
+
+ vector_dsc = lv_vector_dsc_create(&layer);
+
+ int32_t offset_x;
+ int32_t offset_y;
+
+ offset_x = (int32_t)((float) glyph_dsc->g->ofs_x - glyph_dsc->outline_stroke_width * scale);
+ offset_y = (int32_t)((float) glyph_dsc->g->ofs_y - glyph_dsc->outline_stroke_width * scale);
+
+ /*Invert Y-Axis - Freetype's origin point is in the bottom left corner*/
+ lv_matrix_scale(&matrix, 1, -1);
+ lv_matrix_translate(&matrix, -offset_x, -h - offset_y);
+ lv_matrix_scale(&matrix, scale, scale);
+ lv_vector_dsc_set_transform(vector_dsc, &matrix);
+
+ /*Set attributes color, line width etc*/
+ if(cf == LV_COLOR_FORMAT_ARGB8888) {
+
+ if(glyph_dsc->outline_stroke_width > 0) {
+ lv_vector_dsc_set_fill_color(vector_dsc, glyph_dsc->outline_stroke_color);
+ lv_vector_dsc_set_fill_opa(vector_dsc, glyph_dsc->outline_stroke_opa);
+ lv_vector_dsc_add_path(vector_dsc, glyph_paths->outside_path);
+ }
+
+ lv_vector_dsc_set_fill_color(vector_dsc, glyph_dsc->color);
+ lv_vector_dsc_set_fill_opa(vector_dsc, glyph_dsc->opa);
+ lv_vector_dsc_add_path(vector_dsc, glyph_paths->inside_path);
+
+ }
+ else {
+ LV_LOG_ERROR("Unsupported color format: %d", cf);
+ }
+
+ lv_area_t old_area;
+ lv_area_t letter_coords;
+
+ /*Render vector path(s) - set the clip area so that it matches
+ *the size of the temporary buffer used to render the glyph path(s)*/
+ lv_memcpy(&old_area, &t->clip_area, sizeof(lv_area_t));
+ lv_memcpy(&t->clip_area, &buf_area, sizeof(lv_area_t));
+
+ lv_draw_vector(vector_dsc);
+ LV_ASSERT_NULL(layer.draw_task_head);
+
+ lv_draw_sw_vector(t, (lv_draw_vector_task_dsc_t *) layer.draw_task_head->draw_dsc);
+
+ /*Restore previous draw area of the entire text label*/
+ lv_memcpy(&t->clip_area, &old_area, sizeof(lv_area_t));
+
+ lv_memcpy(&letter_coords, glyph_dsc->letter_coords, sizeof(lv_area_t));
+ lv_area_set_width(&letter_coords, w);
+ lv_area_set_height(&letter_coords, h);
+
+ lv_draw_image_dsc_t img_dsc;
+
+ lv_draw_image_dsc_init(&img_dsc);
+ img_dsc.rotation = 0;
+ img_dsc.scale_x = LV_SCALE_NONE;
+ img_dsc.scale_y = LV_SCALE_NONE;
+ img_dsc.opa = LV_OPA_100;
+ img_dsc.src = draw_buf;
+ lv_draw_sw_image(t, &img_dsc, &letter_coords);
+
+ lv_vector_dsc_delete(vector_dsc);
+ lv_draw_buf_destroy(draw_buf);
+
+}
+
+/* Build the inside and outside vector paths for a glyph based
+ * on the recieved outline events emitted by lv_freetype_outline.c */
+static void freetype_outline_event_cb(lv_event_t * e)
+{
+
+ lv_fpoint_t pnt;
+ lv_fpoint_t ctrl_pnt1;
+ lv_fpoint_t ctrl_pnt2;
+ lv_draw_sw_letter_outlines_t * glyph_paths;
+ lv_vector_path_t * path;
+ lv_freetype_outline_event_param_t * outline_event;
+
+ outline_event = lv_event_get_param(e);
+ pnt.x = LV_FREETYPE_F26DOT6_TO_FLOAT(outline_event->to.x);
+ pnt.y = LV_FREETYPE_F26DOT6_TO_FLOAT(outline_event->to.y);
+ glyph_paths = outline_event->outline;
+
+ if(lv_event_get_code(e) == LV_EVENT_CREATE) {
+
+ glyph_paths = lv_malloc(sizeof(lv_draw_sw_letter_outlines_t));
+ LV_ASSERT_NULL(glyph_paths);
+
+ glyph_paths->cur_path = lv_vector_path_create(LV_VECTOR_PATH_QUALITY_HIGH);
+ glyph_paths->inside_path = glyph_paths->cur_path;
+ outline_event->outline = glyph_paths;
+ return;
+
+ }
+ else if(lv_event_get_code(e) == LV_EVENT_DELETE) {
+
+ if(glyph_paths->inside_path != NULL) {
+ lv_vector_path_clear(glyph_paths->inside_path);
+ lv_vector_path_delete(glyph_paths->inside_path);
+ }
+
+ if(glyph_paths->outside_path != NULL) {
+ lv_vector_path_clear(glyph_paths->outside_path);
+ lv_vector_path_delete(glyph_paths->outside_path);
+ }
+
+ lv_free(glyph_paths);
+ return;
+
+ }
+ else if(outline_event->type == LV_FREETYPE_OUTLINE_BORDER_START) {
+
+ /* Inside path is done - create the border path */
+ lv_vector_path_close(glyph_paths->cur_path);
+ glyph_paths->cur_path = lv_vector_path_create(LV_VECTOR_PATH_QUALITY_HIGH);
+ glyph_paths->outside_path = glyph_paths->cur_path;
+ return;
+ }
+
+ path = glyph_paths->cur_path;
+
+ switch(outline_event->type) {
+
+ case LV_FREETYPE_OUTLINE_MOVE_TO:
+ lv_vector_path_move_to(path, &pnt);
+ break;
+
+ case LV_FREETYPE_OUTLINE_LINE_TO:
+ lv_vector_path_line_to(path, &pnt);
+ break;
+
+ case LV_FREETYPE_OUTLINE_CUBIC_TO:
+ ctrl_pnt1.x = LV_FREETYPE_F26DOT6_TO_FLOAT(outline_event->control1.x);
+ ctrl_pnt1.y = LV_FREETYPE_F26DOT6_TO_FLOAT(outline_event->control1.y);
+ ctrl_pnt2.x = LV_FREETYPE_F26DOT6_TO_FLOAT(outline_event->control2.x);
+ ctrl_pnt2.y = LV_FREETYPE_F26DOT6_TO_FLOAT(outline_event->control2.y);
+ lv_vector_path_cubic_to(path, &ctrl_pnt1, &ctrl_pnt2, &pnt);
+ break;
+
+ case LV_FREETYPE_OUTLINE_CONIC_TO:
+ ctrl_pnt1.x = LV_FREETYPE_F26DOT6_TO_FLOAT(outline_event->control1.x);
+ ctrl_pnt1.y = LV_FREETYPE_F26DOT6_TO_FLOAT(outline_event->control1.y);
+ lv_vector_path_quad_to(path, &ctrl_pnt1, &pnt);
+ break;
+ case LV_FREETYPE_OUTLINE_END:
+ case LV_FREETYPE_OUTLINE_BORDER_START:
+ /* It's not necessary to close the path and
+ * border start is handled above
+ */
+ break;
+ }
+}
+
+#endif /* LV_USE_FREETYPE && LV_USE_VECTOR_GRAPHIC */
+
#endif /*LV_USE_DRAW_SW*/
diff --git a/src/draw/sw/lv_draw_sw_vector.c b/src/draw/sw/lv_draw_sw_vector.c
index d5b974383d..4a0afb1088 100644
--- a/src/draw/sw/lv_draw_sw_vector.c
+++ b/src/draw/sw/lv_draw_sw_vector.c
@@ -492,7 +492,6 @@ void lv_draw_sw_vector(lv_draw_task_t * t, const lv_draw_vector_task_dsc_t * dsc
buf = new_buf->data;
stride = new_buf->header.stride;
}
-
Tvg_Canvas * canvas = tvg_swcanvas_create();
tvg_swcanvas_set_target(canvas, buf, stride / 4, width, height, TVG_COLORSPACE_ARGB8888S);
diff --git a/src/font/lv_font.h b/src/font/lv_font.h
index fa9f3649f9..15d7a42e32 100644
--- a/src/font/lv_font.h
+++ b/src/font/lv_font.h
@@ -68,6 +68,7 @@ typedef struct {
int16_t ofs_y; /**< y offset of the bounding box*/
lv_font_glyph_format_t format; /**< Font format of the glyph see lv_font_glyph_format_t */
uint8_t is_placeholder: 1; /**< Glyph is missing. But placeholder will still be displayed*/
+ int32_t outline_stroke_width; /**< used with freetype vector fonts - width of the letter outline */
/** 0: Get bitmap should return an A8 or ARGB8888 image.
* 1: return the bitmap as it is (Maybe A1/2/4 or any proprietary formats). */
diff --git a/src/libs/freetype/lv_freetype.h b/src/libs/freetype/lv_freetype.h
index 6fe3a8f940..3bade7dbd6 100755
--- a/src/libs/freetype/lv_freetype.h
+++ b/src/libs/freetype/lv_freetype.h
@@ -18,6 +18,8 @@ extern "C" {
#include "../../misc/lv_types.h"
#include "../../misc/lv_event.h"
+#include "../../misc/lv_color.h"
+
#include LV_STDBOOL_INCLUDE
/*********************
@@ -56,6 +58,7 @@ typedef enum {
LV_FREETYPE_OUTLINE_LINE_TO,
LV_FREETYPE_OUTLINE_CUBIC_TO,
LV_FREETYPE_OUTLINE_CONIC_TO,
+ LV_FREETYPE_OUTLINE_BORDER_START, /* When line width > 0 the border glyph is drawn after the regular glyph */
} lv_freetype_outline_type_t;
/**********************
@@ -83,7 +86,6 @@ void lv_freetype_uninit(void);
*/
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);
-
/**
* Delete a freetype font.
* @param font freetype font to be deleted.
diff --git a/src/libs/freetype/lv_freetype_glyph.c b/src/libs/freetype/lv_freetype_glyph.c
index 5ecd048959..bd38fb5a8e 100644
--- a/src/libs/freetype/lv_freetype_glyph.c
+++ b/src/libs/freetype/lv_freetype_glyph.c
@@ -131,10 +131,9 @@ static bool freetype_get_glyph_dsc_cb(const lv_font_t * font, lv_font_glyph_dsc_
static bool freetype_glyph_create_cb(lv_freetype_glyph_cache_data_t * data, void * user_data)
{
LV_PROFILER_FONT_BEGIN;
- lv_freetype_font_dsc_t * dsc = (lv_freetype_font_dsc_t *)user_data;
FT_Error error;
-
+ lv_freetype_font_dsc_t * dsc = (lv_freetype_font_dsc_t *)user_data;
lv_font_glyph_dsc_t * dsc_out = &data->glyph_dsc;
lv_mutex_lock(&dsc->cache_node->face_lock);
@@ -169,6 +168,7 @@ static bool freetype_glyph_create_cb(lv_freetype_glyph_cache_data_t * data, void
FT_GlyphSlot glyph = face->glyph;
if(dsc->render_mode == LV_FREETYPE_FONT_RENDER_MODE_OUTLINE) {
+
dsc_out->adv_w = FT_F26DOT6_TO_INT(glyph->metrics.horiAdvance);
dsc_out->box_h = FT_F26DOT6_TO_INT(glyph->metrics.height); /*Height of the bitmap in [px]*/
dsc_out->box_w = FT_F26DOT6_TO_INT(glyph->metrics.width); /*Width of the bitmap in [px]*/
@@ -177,7 +177,7 @@ static bool freetype_glyph_create_cb(lv_freetype_glyph_cache_data_t * data, void
glyph->metrics.height); /*Y offset of the bitmap measured from the as line*/
dsc_out->format = LV_FONT_GLYPH_FORMAT_VECTOR;
- /*Transform the glyph to italic if required*/
+ /*Transform the glyph to italic if required */
if(dsc->style & LV_FREETYPE_FONT_STYLE_ITALIC) {
dsc_out->box_w = lv_freetype_italic_transform_on_pos((lv_point_t) {
dsc_out->box_w, dsc_out->box_h
diff --git a/src/libs/freetype/lv_freetype_outline.c b/src/libs/freetype/lv_freetype_outline.c
index 3f5c978c7c..f7d5edbd0d 100755
--- a/src/libs/freetype/lv_freetype_outline.c
+++ b/src/libs/freetype/lv_freetype_outline.c
@@ -33,7 +33,7 @@ typedef struct _lv_freetype_outline_node_t {
**********************/
static lv_freetype_outline_t outline_create(lv_freetype_context_t * ctx, FT_Face face, FT_UInt glyph_index,
- uint32_t size, uint32_t strength);
+ uint32_t size, uint32_t strength, uint32_t border_width);
static lv_result_t outline_delete(lv_freetype_context_t * ctx, lv_freetype_outline_t outline);
static const void * freetype_get_glyph_bitmap_cb(lv_font_glyph_dsc_t * g_dsc, lv_draw_buf_t * draw_buf);
static void freetype_release_glyph_cb(const lv_font_t * font, lv_font_glyph_dsc_t * g_dsc);
@@ -128,7 +128,8 @@ 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 ? 1 : 0,
+ dsc->outline_stroke_width);
lv_mutex_unlock(&dsc->cache_node->face_lock);
if(!outline) {
@@ -168,7 +169,11 @@ static const void * freetype_get_glyph_bitmap_cb(lv_font_glyph_dsc_t * g_dsc, lv
const lv_font_t * font = g_dsc->resolved_font;
lv_freetype_font_dsc_t * dsc = (lv_freetype_font_dsc_t *)font->dsc;
LV_ASSERT_FREETYPE_FONT_DSC(dsc);
+
+ dsc->outline_stroke_width = g_dsc->outline_stroke_width;
+
lv_cache_entry_t * entry = lv_freetype_outline_lookup(dsc, (FT_UInt)g_dsc->gid.index);
+
if(entry == NULL) {
return NULL;
}
@@ -300,11 +305,14 @@ static lv_freetype_outline_t outline_create(
FT_Face face,
FT_UInt glyph_index,
uint32_t size,
- uint32_t strength)
+ uint32_t strength,
+ uint32_t border_width)
{
LV_PROFILER_FONT_BEGIN;
LV_ASSERT_NULL(ctx);
FT_Error error;
+ FT_Glyph glyph;
+ FT_Stroker stroker;
error = FT_Set_Pixel_Sizes(face, 0, size);
if(error) {
@@ -313,6 +321,7 @@ static lv_freetype_outline_t outline_create(
return NULL;
}
+
/**
* Disable AUTOHINT(https://freetype.org/autohinting/hinter.html) to avoid display clipping
* caused by inconsistent glyph measurement and outline.
@@ -331,6 +340,7 @@ static lv_freetype_outline_t outline_create(
}
}
+
FT_Outline_Funcs outline_funcs = {
.move_to = outline_move_to_cb,
.line_to = outline_line_to_cb,
@@ -340,42 +350,14 @@ static lv_freetype_outline_t outline_create(
.delta = 0
};
-
lv_result_t res;
lv_freetype_outline_event_param_t param;
lv_memzero(¶m, sizeof(param));
- /*Calculate Total Segments Before decompose */
- int32_t tag_size = face->glyph->outline.n_points;
- int32_t segments = 0;
- int32_t vectors = 0;
-
- for(int j = 0; j < tag_size; j++) {
- if((face->glyph->outline.tags[j] & 0x1) == 0x1) {
- segments++;
- vectors++;
- }
- else {
- int jj = j + 1 < tag_size ? j + 1 : 0;
- if(face->glyph->outline.tags[jj] & 0x1) {
- vectors++;
- }
- else {
- segments++;
- vectors += 2;
- }
- }
- }
- /*Also for every contour we may have a line for close*/
- segments += face->glyph->outline.n_contours;
- vectors += face->glyph->outline.n_contours;
-
- param.sizes.data_size = vectors * 2;
- param.sizes.segments_size = segments;
+ lv_freetype_outline_t outline;
res = outline_send_event(ctx, LV_EVENT_CREATE, ¶m);
-
- lv_freetype_outline_t outline = param.outline;
+ outline = param.outline;
if(res != LV_RESULT_OK || !outline) {
LV_LOG_ERROR("Outline object create failed");
@@ -383,22 +365,104 @@ static lv_freetype_outline_t outline_create(
return NULL;
}
- /* Run outline decompose again to fill outline data */
- error = FT_Outline_Decompose(&face->glyph->outline, &outline_funcs, outline);
- if(error) {
- FT_ERROR_MSG("FT_Outline_Decompose", error);
- outline_delete(ctx, outline);
- LV_PROFILER_FONT_END;
- return NULL;
- }
+ /* 1 iteration if there is no border */
+ /* 2 iterations if there is a a border and the glyph itsef */
+ for(int i = 0; i < (border_width > 0 ? 2 : 1); i++) {
- /* close outline */
- res = outline_push_point(outline, LV_FREETYPE_OUTLINE_END, NULL, NULL, NULL);
- if(res != LV_RESULT_OK) {
- LV_LOG_ERROR("Outline object close failed");
- outline_delete(ctx, outline);
- LV_PROFILER_FONT_END;
- return NULL;
+ FT_Outline glyph_outline;
+
+ if(i == 1) {
+
+ /* decompose the border glyph */
+ FT_Stroker_New(ctx->library, &stroker);
+ FT_Stroker_Set(stroker, border_width * 64,
+ FT_STROKER_LINECAP_ROUND,
+ FT_STROKER_LINEJOIN_ROUND,
+ 0);
+
+ FT_Get_Glyph(face->glyph, &glyph);
+ FT_Glyph_StrokeBorder(&glyph, stroker, 0, true);
+ FT_OutlineGlyph g = (FT_OutlineGlyph) glyph;
+
+ FT_Stroker_Done(stroker);
+
+ glyph_outline = g->outline;
+
+ }
+ else {
+
+ /* decompose glyph */
+ glyph_outline = face->glyph->outline;
+ }
+
+ /*Calculate Total Segments Before decompose */
+ int32_t tag_size = glyph_outline.n_points;
+ int32_t segments = 0;
+ int32_t vectors = 0;
+
+ for(int j = 0; j < tag_size; j++) {
+
+#if 0
+ if(j == 0 && (glyph_outline.tags[j] & 0x1) == 0) {
+ /* TODO handle the case where the first point is 'off curve' */
+https://stackoverflow.com/questions/3465809/how-to-interpret-a-freetype-glyph-outline-when-the-first-point-on-the-contour-is
+ }
+#endif
+ if((glyph_outline.tags[j] & 0x1) == 0x1) {
+ segments++;
+ vectors++;
+ }
+ else {
+ int jj = j + 1 < tag_size ? j + 1 : 0;
+ if(glyph_outline.tags[jj] & 0x1) {
+ vectors++;
+ }
+ else {
+ segments++;
+ vectors += 2;
+ }
+ }
+ }
+
+ /*Also for every contour we may have a line for close*/
+ segments += glyph_outline.n_contours;
+ vectors += glyph_outline.n_contours;
+
+ param.sizes.data_size = vectors * 2;
+ param.sizes.segments_size = segments;
+
+ /* Run outline decompose again to fill outline data */
+ error = FT_Outline_Decompose(&glyph_outline, &outline_funcs, outline);
+ if(error) {
+ FT_ERROR_MSG("FT_Outline_Decompose", error);
+ outline_delete(ctx, outline);
+ LV_PROFILER_FONT_END;
+ return NULL;
+ }
+
+ if(i == 0 && border_width > 0) {
+
+ /* Close the border glyph before decomposing the inside glyph */
+ res = outline_push_point(outline, LV_FREETYPE_OUTLINE_BORDER_START, NULL, NULL, NULL);
+ if(res != LV_RESULT_OK) {
+ LV_LOG_ERROR("Outline object close failed");
+ outline_delete(ctx, outline);
+ LV_PROFILER_FONT_END;
+ return NULL;
+ }
+
+ }
+ else if(i == 0 || (i == 1 && border_width > 0)) {
+
+ /* Close the border glyph or the regular glyph */
+ res = outline_push_point(outline, LV_FREETYPE_OUTLINE_END, NULL, NULL, NULL);
+ if(res != LV_RESULT_OK) {
+ LV_LOG_ERROR("Outline object close failed");
+ outline_delete(ctx, outline);
+ LV_PROFILER_FONT_END;
+ return NULL;
+ }
+ }
}
LV_PROFILER_FONT_END;
diff --git a/src/libs/freetype/lv_freetype_private.h b/src/libs/freetype/lv_freetype_private.h
index 54db336821..f851704564 100755
--- a/src/libs/freetype/lv_freetype_private.h
+++ b/src/libs/freetype/lv_freetype_private.h
@@ -28,6 +28,7 @@ extern "C" {
#include FT_SIZES_H
#include FT_IMAGE_H
#include FT_OUTLINE_H
+#include FT_STROKER_H
/*********************
* DEFINES
@@ -119,6 +120,7 @@ typedef struct _lv_freetype_font_dsc_t {
lv_freetype_cache_node_t * cache_node;
lv_cache_entry_t * cache_node_entry;
FTC_FaceID face_id;
+ uint32_t outline_stroke_width;
} lv_freetype_font_dsc_t;
/**********************
diff --git a/src/libs/thorvg/config.h b/src/libs/thorvg/config.h
index b98d3f35f0..fa32babde9 100644
--- a/src/libs/thorvg/config.h
+++ b/src/libs/thorvg/config.h
@@ -13,3 +13,4 @@
#define THORVG_VERSION_STRING "0.15.3"
+#define THORVG_THREAD_SUPPORT
diff --git a/src/misc/lv_style.h b/src/misc/lv_style.h
index 7178878035..2da6cd1f8c 100644
--- a/src/misc/lv_style.h
+++ b/src/misc/lv_style.h
@@ -238,50 +238,53 @@ enum {
LV_STYLE_TEXT_LINE_SPACE = 92,
LV_STYLE_TEXT_DECOR = 93,
LV_STYLE_TEXT_ALIGN = 94,
+ LV_STYLE_TEXT_OUTLINE_STROKE_WIDTH = 95,
+ LV_STYLE_TEXT_OUTLINE_STROKE_OPA = 96,
+ LV_STYLE_TEXT_OUTLINE_STROKE_COLOR = 97,
- LV_STYLE_OPA = 95,
- LV_STYLE_OPA_LAYERED = 96,
- LV_STYLE_COLOR_FILTER_DSC = 97,
- LV_STYLE_COLOR_FILTER_OPA = 98,
- LV_STYLE_ANIM = 99,
- LV_STYLE_ANIM_DURATION = 100,
- LV_STYLE_TRANSITION = 102,
- LV_STYLE_BLEND_MODE = 103,
- LV_STYLE_TRANSFORM_WIDTH = 104,
- LV_STYLE_TRANSFORM_HEIGHT = 105,
- LV_STYLE_TRANSLATE_X = 106,
- LV_STYLE_TRANSLATE_Y = 107,
- LV_STYLE_TRANSFORM_SCALE_X = 108,
- LV_STYLE_TRANSFORM_SCALE_Y = 109,
- LV_STYLE_TRANSFORM_ROTATION = 110,
- LV_STYLE_TRANSFORM_PIVOT_X = 111,
- LV_STYLE_TRANSFORM_PIVOT_Y = 112,
- LV_STYLE_TRANSFORM_SKEW_X = 113,
- LV_STYLE_TRANSFORM_SKEW_Y = 114,
- LV_STYLE_BITMAP_MASK_SRC = 115,
- LV_STYLE_ROTARY_SENSITIVITY = 116,
- LV_STYLE_TRANSLATE_RADIAL = 117,
- LV_STYLE_RECOLOR = 118,
- LV_STYLE_RECOLOR_OPA = 119,
+ LV_STYLE_OPA = 98,
+ LV_STYLE_OPA_LAYERED = 99,
+ LV_STYLE_COLOR_FILTER_DSC = 100,
+ LV_STYLE_COLOR_FILTER_OPA = 101,
+ LV_STYLE_ANIM = 102,
+ LV_STYLE_ANIM_DURATION = 103,
+ LV_STYLE_TRANSITION = 104,
+ LV_STYLE_BLEND_MODE = 105,
+ LV_STYLE_TRANSFORM_WIDTH = 106,
+ LV_STYLE_TRANSFORM_HEIGHT = 107,
+ LV_STYLE_TRANSLATE_X = 108,
+ LV_STYLE_TRANSLATE_Y = 109,
+ LV_STYLE_TRANSFORM_SCALE_X = 110,
+ LV_STYLE_TRANSFORM_SCALE_Y = 111,
+ LV_STYLE_TRANSFORM_ROTATION = 112,
+ LV_STYLE_TRANSFORM_PIVOT_X = 113,
+ LV_STYLE_TRANSFORM_PIVOT_Y = 114,
+ LV_STYLE_TRANSFORM_SKEW_X = 115,
+ LV_STYLE_TRANSFORM_SKEW_Y = 116,
+ LV_STYLE_BITMAP_MASK_SRC = 117,
+ LV_STYLE_ROTARY_SENSITIVITY = 118,
+ LV_STYLE_TRANSLATE_RADIAL = 119,
+ LV_STYLE_RECOLOR = 120,
+ LV_STYLE_RECOLOR_OPA = 121,
- LV_STYLE_FLEX_FLOW = 125,
- LV_STYLE_FLEX_MAIN_PLACE = 126,
- LV_STYLE_FLEX_CROSS_PLACE = 127,
- LV_STYLE_FLEX_TRACK_PLACE = 128,
- LV_STYLE_FLEX_GROW = 129,
+ LV_STYLE_FLEX_FLOW = 122,
+ LV_STYLE_FLEX_MAIN_PLACE = 123,
+ LV_STYLE_FLEX_CROSS_PLACE = 124,
+ LV_STYLE_FLEX_TRACK_PLACE = 125,
+ LV_STYLE_FLEX_GROW = 126,
- LV_STYLE_GRID_COLUMN_ALIGN = 130,
- LV_STYLE_GRID_ROW_ALIGN = 131,
- LV_STYLE_GRID_ROW_DSC_ARRAY = 132,
- LV_STYLE_GRID_COLUMN_DSC_ARRAY = 133,
- LV_STYLE_GRID_CELL_COLUMN_POS = 134,
- LV_STYLE_GRID_CELL_COLUMN_SPAN = 135,
- LV_STYLE_GRID_CELL_X_ALIGN = 136,
- LV_STYLE_GRID_CELL_ROW_POS = 137,
- LV_STYLE_GRID_CELL_ROW_SPAN = 138,
- LV_STYLE_GRID_CELL_Y_ALIGN = 139,
+ LV_STYLE_GRID_COLUMN_ALIGN = 127,
+ LV_STYLE_GRID_ROW_ALIGN = 128,
+ LV_STYLE_GRID_ROW_DSC_ARRAY = 129,
+ LV_STYLE_GRID_COLUMN_DSC_ARRAY = 130,
+ LV_STYLE_GRID_CELL_COLUMN_POS = 131,
+ LV_STYLE_GRID_CELL_COLUMN_SPAN = 132,
+ LV_STYLE_GRID_CELL_X_ALIGN = 133,
+ LV_STYLE_GRID_CELL_ROW_POS = 134,
+ LV_STYLE_GRID_CELL_ROW_SPAN = 135,
+ LV_STYLE_GRID_CELL_Y_ALIGN = 136,
- LV_STYLE_LAST_BUILT_IN_PROP = 140,
+ LV_STYLE_LAST_BUILT_IN_PROP = 137,
LV_STYLE_NUM_BUILT_IN_PROPS = LV_STYLE_LAST_BUILT_IN_PROP + 1,
diff --git a/src/misc/lv_style_gen.c b/src/misc/lv_style_gen.c
index d2d5721406..cd7fe4f477 100644
--- a/src/misc/lv_style_gen.c
+++ b/src/misc/lv_style_gen.c
@@ -674,6 +674,30 @@ void lv_style_set_text_align(lv_style_t * style, lv_text_align_t value)
lv_style_set_prop(style, LV_STYLE_TEXT_ALIGN, v);
}
+void lv_style_set_text_outline_stroke_color(lv_style_t * style, lv_color_t value)
+{
+ lv_style_value_t v = {
+ .color = value
+ };
+ lv_style_set_prop(style, LV_STYLE_TEXT_OUTLINE_STROKE_COLOR, v);
+}
+
+void lv_style_set_text_outline_stroke_width(lv_style_t * style, int32_t value)
+{
+ lv_style_value_t v = {
+ .num = (int32_t)value
+ };
+ lv_style_set_prop(style, LV_STYLE_TEXT_OUTLINE_STROKE_WIDTH, v);
+}
+
+void lv_style_set_text_outline_stroke_opa(lv_style_t * style, lv_opa_t value)
+{
+ lv_style_value_t v = {
+ .num = (int32_t)value
+ };
+ lv_style_set_prop(style, LV_STYLE_TEXT_OUTLINE_STROKE_OPA, v);
+}
+
void lv_style_set_radius(lv_style_t * style, int32_t value)
{
lv_style_value_t v = {
diff --git a/src/misc/lv_style_gen.h b/src/misc/lv_style_gen.h
index c6d2e80850..b5c030dcb9 100644
--- a/src/misc/lv_style_gen.h
+++ b/src/misc/lv_style_gen.h
@@ -97,6 +97,9 @@ void lv_style_set_text_letter_space(lv_style_t * style, int32_t value);
void lv_style_set_text_line_space(lv_style_t * style, int32_t value);
void lv_style_set_text_decor(lv_style_t * style, lv_text_decor_t value);
void lv_style_set_text_align(lv_style_t * style, lv_text_align_t value);
+void lv_style_set_text_outline_stroke_color(lv_style_t * style, lv_color_t value);
+void lv_style_set_text_outline_stroke_width(lv_style_t * style, int32_t value);
+void lv_style_set_text_outline_stroke_opa(lv_style_t * style, lv_opa_t value);
void lv_style_set_radius(lv_style_t * style, int32_t value);
void lv_style_set_radial_offset(lv_style_t * style, int32_t value);
void lv_style_set_clip_corner(lv_style_t * style, bool value);
@@ -551,6 +554,21 @@ void lv_style_set_grid_cell_row_span(lv_style_t * style, int32_t value);
.prop = LV_STYLE_TEXT_ALIGN, .value = { .num = (int32_t)val } \
}
+#define LV_STYLE_CONST_TEXT_OUTLINE_STROKE_COLOR(val) \
+ { \
+ .prop = LV_STYLE_TEXT_OUTLINE_STROKE_COLOR, .value = { .color = val } \
+ }
+
+#define LV_STYLE_CONST_TEXT_OUTLINE_STROKE_WIDTH(val) \
+ { \
+ .prop = LV_STYLE_TEXT_OUTLINE_STROKE_WIDTH, .value = { .num = (int32_t)val } \
+ }
+
+#define LV_STYLE_CONST_TEXT_OUTLINE_STROKE_OPA(val) \
+ { \
+ .prop = LV_STYLE_TEXT_OUTLINE_STROKE_OPA, .value = { .num = (int32_t)val } \
+ }
+
#define LV_STYLE_CONST_RADIUS(val) \
{ \
.prop = LV_STYLE_RADIUS, .value = { .num = (int32_t)val } \
diff --git a/src/widgets/label/lv_label.c b/src/widgets/label/lv_label.c
index 46b7e5d001..1747cd2ab0 100644
--- a/src/widgets/label/lv_label.c
+++ b/src/widgets/label/lv_label.c
@@ -430,6 +430,7 @@ uint32_t lv_label_get_letter_on(const lv_obj_t * obj, lv_point_t * pos_in, bool
const int32_t letter_height = lv_font_get_line_height(font);
int32_t y = 0;
+
lv_text_flag_t flag = get_label_flags(label);
/*Search the line of the index letter*/;
@@ -775,6 +776,7 @@ static void lv_label_event(const lv_obj_class_t * class_p, lv_event_t * e)
if(label->invalid_size_cache) {
const lv_font_t * font = lv_obj_get_style_text_font(obj, LV_PART_MAIN);
int32_t letter_space = lv_obj_get_style_text_letter_space(obj, LV_PART_MAIN);
+
int32_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN);
lv_text_flag_t flag = LV_TEXT_FLAG_NONE;
if(label->recolor != 0) flag |= LV_TEXT_FLAG_RECOLOR;
@@ -840,6 +842,12 @@ static void draw_main(lv_event_t * e)
label_draw_dsc.sel_bg_color = lv_obj_get_style_bg_color(obj, LV_PART_SELECTED);
}
+ /* get the style attributes of a letter outline */
+ label_draw_dsc.outline_stroke_color = lv_obj_get_style_text_outline_stroke_color(obj, LV_PART_MAIN);
+ label_draw_dsc.outline_stroke_opa = lv_obj_get_style_text_outline_stroke_opa(obj, LV_PART_MAIN);
+ label_draw_dsc.outline_stroke_width = lv_obj_get_style_text_outline_stroke_width(obj, LV_PART_MAIN);
+
+
/* In SCROLL and SCROLL_CIRCULAR mode the CENTER and RIGHT are pointless, so remove them.
* (In addition, they will create misalignment in this situation)*/
if((label->long_mode == LV_LABEL_LONG_MODE_SCROLL || label->long_mode == LV_LABEL_LONG_MODE_SCROLL_CIRCULAR) &&
diff --git a/src/widgets/property/lv_obj_property_names.h b/src/widgets/property/lv_obj_property_names.h
index f63d12d014..d9a0543212 100644
--- a/src/widgets/property/lv_obj_property_names.h
+++ b/src/widgets/property/lv_obj_property_names.h
@@ -18,7 +18,7 @@
extern const lv_property_name_t lv_obj_property_names[73];
extern const lv_property_name_t lv_roller_property_names[3];
extern const lv_property_name_t lv_slider_property_names[8];
- extern const lv_property_name_t lv_style_property_names[117];
+ extern const lv_property_name_t lv_style_property_names[120];
extern const lv_property_name_t lv_textarea_property_names[15];
#endif
#endif
diff --git a/src/widgets/property/lv_style_properties.c b/src/widgets/property/lv_style_properties.c
index 99a39be12a..61ad99ba14 100644
--- a/src/widgets/property/lv_style_properties.c
+++ b/src/widgets/property/lv_style_properties.c
@@ -14,7 +14,7 @@
* Generated code from properties.py
*/
/* *INDENT-OFF* */
-const lv_property_name_t lv_style_property_names[117] = {
+const lv_property_name_t lv_style_property_names[120] = {
{"align", LV_PROPERTY_STYLE_ALIGN,},
{"anim", LV_PROPERTY_STYLE_ANIM,},
{"anim_duration", LV_PROPERTY_STYLE_ANIM_DURATION,},
@@ -116,6 +116,9 @@ const lv_property_name_t lv_style_property_names[117] = {
{"text_letter_space", LV_PROPERTY_STYLE_TEXT_LETTER_SPACE,},
{"text_line_space", LV_PROPERTY_STYLE_TEXT_LINE_SPACE,},
{"text_opa", LV_PROPERTY_STYLE_TEXT_OPA,},
+ {"text_outline_stroke_color", LV_PROPERTY_STYLE_TEXT_OUTLINE_STROKE_COLOR,},
+ {"text_outline_stroke_opa", LV_PROPERTY_STYLE_TEXT_OUTLINE_STROKE_OPA,},
+ {"text_outline_stroke_width", LV_PROPERTY_STYLE_TEXT_OUTLINE_STROKE_WIDTH,},
{"transform_height", LV_PROPERTY_STYLE_TRANSFORM_HEIGHT,},
{"transform_pivot_x", LV_PROPERTY_STYLE_TRANSFORM_PIVOT_X,},
{"transform_pivot_y", LV_PROPERTY_STYLE_TRANSFORM_PIVOT_Y,},
diff --git a/src/widgets/property/lv_style_properties.h b/src/widgets/property/lv_style_properties.h
index 0115e855ea..b53c751b7d 100644
--- a/src/widgets/property/lv_style_properties.h
+++ b/src/widgets/property/lv_style_properties.h
@@ -113,6 +113,9 @@ enum {
LV_PROPERTY_ID(STYLE, TEXT_LETTER_SPACE, LV_PROPERTY_TYPE_INT, LV_STYLE_TEXT_LETTER_SPACE),
LV_PROPERTY_ID(STYLE, TEXT_LINE_SPACE, LV_PROPERTY_TYPE_INT, LV_STYLE_TEXT_LINE_SPACE),
LV_PROPERTY_ID(STYLE, TEXT_OPA, LV_PROPERTY_TYPE_INT, LV_STYLE_TEXT_OPA),
+ LV_PROPERTY_ID(STYLE, TEXT_OUTLINE_STROKE_COLOR, LV_PROPERTY_TYPE_INT, LV_STYLE_TEXT_OUTLINE_STROKE_COLOR),
+ LV_PROPERTY_ID(STYLE, TEXT_OUTLINE_STROKE_OPA, LV_PROPERTY_TYPE_INT, LV_STYLE_TEXT_OUTLINE_STROKE_OPA),
+ LV_PROPERTY_ID(STYLE, TEXT_OUTLINE_STROKE_WIDTH, LV_PROPERTY_TYPE_INT, LV_STYLE_TEXT_OUTLINE_STROKE_WIDTH),
LV_PROPERTY_ID(STYLE, TRANSFORM_HEIGHT, LV_PROPERTY_TYPE_INT, LV_STYLE_TRANSFORM_HEIGHT),
LV_PROPERTY_ID(STYLE, TRANSFORM_PIVOT_X, LV_PROPERTY_TYPE_INT, LV_STYLE_TRANSFORM_PIVOT_X),
LV_PROPERTY_ID(STYLE, TRANSFORM_PIVOT_Y, LV_PROPERTY_TYPE_INT, LV_STYLE_TRANSFORM_PIVOT_Y),