mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-22 23:37:43 +08:00
feat(draw/sw): add support for vector fonts (#7560)
This commit is contained in:
@@ -1221,6 +1221,48 @@ Set how to align the lines of the text. Note that it doesn't align the Widget it
|
||||
<li style='display:inline-block; margin-right: 20px; margin-left: 0px'><strong>Ext. draw</strong> No</li>
|
||||
</ul>
|
||||
|
||||
text_outline_stroke_color
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sets the color of letter outline stroke.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<ul>
|
||||
<li style='display:inline-block; margin-right: 20px; margin-left: 0px'><strong>Default</strong> `0x000000`</li>
|
||||
<li style='display:inline-block; margin-right: 20px; margin-left: 0px'><strong>Inherited</strong> Yes</li>
|
||||
<li style='display:inline-block; margin-right: 20px; margin-left: 0px'><strong>Layout</strong> No</li>
|
||||
<li style='display:inline-block; margin-right: 20px; margin-left: 0px'><strong>Ext. draw</strong> No</li>
|
||||
</ul>
|
||||
|
||||
text_outline_stroke_width
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Set the letter outline stroke width in pixels.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<ul>
|
||||
<li style='display:inline-block; margin-right: 20px; margin-left: 0px'><strong>Default</strong> 0</li>
|
||||
<li style='display:inline-block; margin-right: 20px; margin-left: 0px'><strong>Inherited</strong> Yes</li>
|
||||
<li style='display:inline-block; margin-right: 20px; margin-left: 0px'><strong>Layout</strong> Yes</li>
|
||||
<li style='display:inline-block; margin-right: 20px; margin-left: 0px'><strong>Ext. draw</strong> No</li>
|
||||
</ul>
|
||||
|
||||
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
|
||||
|
||||
<ul>
|
||||
<li style='display:inline-block; margin-right: 20px; margin-left: 0px'><strong>Default</strong> `LV_OPA_COVER`</li>
|
||||
<li style='display:inline-block; margin-right: 20px; margin-left: 0px'><strong>Inherited</strong> Yes</li>
|
||||
<li style='display:inline-block; margin-right: 20px; margin-left: 0px'><strong>Layout</strong> No</li>
|
||||
<li style='display:inline-block; margin-right: 20px; margin-left: 0px'><strong>Ext. draw</strong> No</li>
|
||||
</ul>
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
|
||||
|
||||
@@ -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 <https://www.freetype.org/freetype2/docs/tutorial/step1.html>`__
|
||||
- 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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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). */
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**********************
|
||||
|
||||
@@ -13,3 +13,4 @@
|
||||
|
||||
#define THORVG_VERSION_STRING "0.15.3"
|
||||
|
||||
#define THORVG_THREAD_SUPPORT
|
||||
|
||||
+43
-40
@@ -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,
|
||||
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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 } \
|
||||
|
||||
@@ -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) &&
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,},
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user