1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-28 07:03:00 +08:00

feat(image, layer): add bitmap mask feature (#5545)

This commit is contained in:
Gabor Kiss-Vamosi 2024-02-10 20:57:46 +01:00 committed by GitHub
parent cfd14cdacd
commit 10978c94c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 280 additions and 72 deletions

View File

@ -4,6 +4,12 @@
Layers
======
In LVGL "layers" can be interpreted in various ways:
1. The order of widget creation naturally creates a layering of widgets
2. Permanent screen-sized layers can be also used
3. For some draw operations LVGL renders a widget and all its children into a buffer (a.k.a. layer) first
.. _layers_creation:
Order of creation
@ -45,7 +51,7 @@ its children.
.. _layers_order:
Change order
************
------------
There are four explicit ways to bring an object to the foreground:
@ -60,10 +66,12 @@ There are four explicit ways to bring an object to the foreground:
- Use :cpp:expr:`lv_obj_swap(obj1, obj2)` to swap the relative layer position of two objects.
- When :cpp:expr:`lv_obj_set_parent(obj, new_parent)` is used, ``obj`` will be on the foreground of the ``new_parent``.
Screen-like layers
******************
.. _layers_top_and_sys:
Top and sys layers
******************
------------------
LVGL uses two special layers named ``layer_top`` and ``layer_sys``. Both
are visible and common on all screens of a display. **They are not,
@ -92,7 +100,7 @@ always visible.
.. _layers_bottom:
Bottom layers
*************
-------------
Similarly top and sys. layer bottom layer is also screen size but
it's located below the active screen. It's visible only if the active screen's
@ -100,6 +108,45 @@ background opacity is < 255.
The get the bottom layer use :cpp:func:`lv_layer_bottom`.
Draw layers
***********
Some style properties make LVGL to allocate a buffer and render a widget and its children there first. Later that layer will be merged to the screen or its parent layer after applying some transformations or other modifications.
Simple layer
------------
The following style properties trigger the creation of a "Simple layer":
- ``opa_layered``
- ``bitmap_mask_src``
- ``blend_mode``
In this case widget will be sliced into ``LV_DRAW_SW_LAYER_SIMPLE_BUF_SIZE`` sized chunks.
If there is no memory for a new chunk, LVGL will try allocating layer when an other chunk is rendered and freed.
Transformed layer
---------------
When the widget is transformed a larger part of the widget needs to rendered to provide enough data for transformation. LVGL tries to render as small area of the widget as possible, but due to the nature of transformations no slicing is possible in this case.
The following style properties trigger the creation of a "Transform layer":
- ``transform_scale_x``
- ``transform_scale_y``
- ``transform_skew_x``
- ``transform_skew_y``
- ``transform_rotate``
Clip corner
-----------
The ``clip_corner`` style property also makes LVGL to create a 2 layers with radius height for the top and bottom part of the widget.
.. _layers_api:
API

View File

@ -873,6 +873,15 @@ Set the base direction of the object. The possible values are `LV_BIDI_DIR_LTR/R
<li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Ext. draw</strong> No</li>
</ul>
### bitmap_mask_src
If set a layer will be created for the widget and the layer will be masked with this A8 bitmap mask.
<ul>
<li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Default</strong> `NULL`</li>
<li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Inherited</strong> No</li>
<li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Layout</strong> No</li>
<li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Ext. draw</strong> No</li>
</ul>
## Flex
Flex layout properties.

View File

@ -7,15 +7,10 @@ void lv_example_image_1(void)
lv_obj_t * img1 = lv_image_create(lv_screen_active());
lv_image_set_src(img1, &img_cogwheel_argb);
lv_obj_align(img1, LV_ALIGN_CENTER, 0, 0);
lv_image_set_scale_x(img1, 512);
lv_image_set_scale_y(img1, 128);
lv_image_set_rotation(img1, 10);
lv_obj_t * img2 = lv_image_create(lv_screen_active());
lv_image_set_src(img2, LV_SYMBOL_OK "Accept");
lv_obj_align_to(img2, img1, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
lv_obj_set_style_bg_opa(img1, 100, 0);
}
#endif

View File

@ -389,6 +389,9 @@ props = [
'style_type': 'num', 'var_type': 'lv_base_dir_t', 'default':'`LV_BASE_DIR_AUTO`', 'inherited': 1, 'layout': 1, 'ext_draw': 0,
'dsc': "Set the base direction of the object. The possible values are `LV_BIDI_DIR_LTR/RTL/AUTO`."},
{'name': 'BITMAP_MASK_SRC',
'style_type': 'ptr', 'var_type': 'const lv_image_dsc_t *', 'default':'`NULL`', 'inherited': 0, 'layout': 0, 'ext_draw': 0,
'dsc': "If set a layer will be created for the widget and the layer will be masked with this A8 bitmap mask."},
{'section': 'Flex', 'dsc':'Flex layout properties.', 'guard':'LV_USE_FLEX'},

View File

@ -1016,6 +1016,7 @@ static lv_layer_type_t calculate_layer_type(lv_obj_t * obj)
if(lv_obj_get_style_transform_skew_x(obj, 0) != 0) return LV_LAYER_TYPE_TRANSFORM;
if(lv_obj_get_style_transform_skew_y(obj, 0) != 0) return LV_LAYER_TYPE_TRANSFORM;
if(lv_obj_get_style_opa_layered(obj, 0) != LV_OPA_COVER) return LV_LAYER_TYPE_SIMPLE;
if(lv_obj_get_style_bitmap_mask_src(obj, 0) != NULL) return LV_LAYER_TYPE_SIMPLE;
if(lv_obj_get_style_blend_mode(obj, 0) != LV_BLEND_MODE_NORMAL) return LV_LAYER_TYPE_SIMPLE;
return LV_LAYER_TYPE_NONE;
}

View File

@ -690,8 +690,7 @@ void lv_obj_set_style_opa_layered(lv_obj_t * obj, lv_opa_t value, lv_style_selec
lv_obj_set_local_style_prop(obj, LV_STYLE_OPA_LAYERED, v, selector);
}
void lv_obj_set_style_color_filter_dsc(lv_obj_t * obj, const lv_color_filter_dsc_t * value,
lv_style_selector_t selector)
void lv_obj_set_style_color_filter_dsc(lv_obj_t * obj, const lv_color_filter_dsc_t * value, lv_style_selector_t selector)
{
lv_style_value_t v = {
.ptr = value
@ -754,6 +753,14 @@ void lv_obj_set_style_base_dir(lv_obj_t * obj, lv_base_dir_t value, lv_style_sel
};
lv_obj_set_local_style_prop(obj, LV_STYLE_BASE_DIR, v, selector);
}
void lv_obj_set_style_bitmap_mask_src(lv_obj_t * obj, const lv_image_dsc_t * value, lv_style_selector_t selector)
{
lv_style_value_t v = {
.ptr = value
};
lv_obj_set_local_style_prop(obj, LV_STYLE_BITMAP_MASK_SRC, v, selector);
}
#if LV_USE_FLEX

View File

@ -6,6 +6,7 @@
**********************************************************************
*/
#ifndef LV_OBJ_STYLE_GEN_H
#define LV_OBJ_STYLE_GEN_H
@ -225,8 +226,7 @@ static inline lv_color_t lv_obj_get_style_bg_grad_color(const lv_obj_t * obj, ui
static inline lv_color_t lv_obj_get_style_bg_grad_color_filtered(const lv_obj_t * obj, uint32_t part)
{
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part,
LV_STYLE_BG_GRAD_COLOR));
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BG_GRAD_COLOR));
return v.color;
}
@ -286,8 +286,7 @@ static inline lv_color_t lv_obj_get_style_bg_image_recolor(const lv_obj_t * obj,
static inline lv_color_t lv_obj_get_style_bg_image_recolor_filtered(const lv_obj_t * obj, uint32_t part)
{
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part,
LV_STYLE_BG_IMAGE_RECOLOR));
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BG_IMAGE_RECOLOR));
return v.color;
}
@ -311,8 +310,7 @@ static inline lv_color_t lv_obj_get_style_border_color(const lv_obj_t * obj, uin
static inline lv_color_t lv_obj_get_style_border_color_filtered(const lv_obj_t * obj, uint32_t part)
{
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part,
LV_STYLE_BORDER_COLOR));
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BORDER_COLOR));
return v.color;
}
@ -354,8 +352,7 @@ static inline lv_color_t lv_obj_get_style_outline_color(const lv_obj_t * obj, ui
static inline lv_color_t lv_obj_get_style_outline_color_filtered(const lv_obj_t * obj, uint32_t part)
{
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part,
LV_STYLE_OUTLINE_COLOR));
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_OUTLINE_COLOR));
return v.color;
}
@ -403,8 +400,7 @@ static inline lv_color_t lv_obj_get_style_shadow_color(const lv_obj_t * obj, uin
static inline lv_color_t lv_obj_get_style_shadow_color_filtered(const lv_obj_t * obj, uint32_t part)
{
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part,
LV_STYLE_SHADOW_COLOR));
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_COLOR));
return v.color;
}
@ -428,8 +424,7 @@ static inline lv_color_t lv_obj_get_style_image_recolor(const lv_obj_t * obj, ui
static inline lv_color_t lv_obj_get_style_image_recolor_filtered(const lv_obj_t * obj, uint32_t part)
{
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part,
LV_STYLE_IMAGE_RECOLOR));
lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_IMAGE_RECOLOR));
return v.color;
}
@ -637,6 +632,12 @@ static inline lv_base_dir_t lv_obj_get_style_base_dir(const lv_obj_t * obj, uint
return (lv_base_dir_t)v.num;
}
static inline const lv_image_dsc_t * lv_obj_get_style_bitmap_mask_src(const lv_obj_t * obj, uint32_t part)
{
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BITMAP_MASK_SRC);
return (const lv_image_dsc_t *)v.ptr;
}
#if LV_USE_FLEX
static inline lv_flex_flow_t lv_obj_get_style_flex_flow(const lv_obj_t * obj, uint32_t part)
@ -820,8 +821,7 @@ void lv_obj_set_style_radius(lv_obj_t * obj, int32_t value, lv_style_selector_t
void lv_obj_set_style_clip_corner(lv_obj_t * obj, bool value, lv_style_selector_t selector);
void lv_obj_set_style_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
void lv_obj_set_style_opa_layered(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
void lv_obj_set_style_color_filter_dsc(lv_obj_t * obj, const lv_color_filter_dsc_t * value,
lv_style_selector_t selector);
void lv_obj_set_style_color_filter_dsc(lv_obj_t * obj, const lv_color_filter_dsc_t * value, lv_style_selector_t selector);
void lv_obj_set_style_color_filter_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
void lv_obj_set_style_anim(lv_obj_t * obj, const lv_anim_t * value, lv_style_selector_t selector);
void lv_obj_set_style_anim_duration(lv_obj_t * obj, uint32_t value, lv_style_selector_t selector);
@ -829,27 +829,29 @@ void lv_obj_set_style_transition(lv_obj_t * obj, const lv_style_transition_dsc_t
void lv_obj_set_style_blend_mode(lv_obj_t * obj, lv_blend_mode_t value, lv_style_selector_t selector);
void lv_obj_set_style_layout(lv_obj_t * obj, uint16_t value, lv_style_selector_t selector);
void lv_obj_set_style_base_dir(lv_obj_t * obj, lv_base_dir_t value, lv_style_selector_t selector);
void lv_obj_set_style_bitmap_mask_src(lv_obj_t * obj, const lv_image_dsc_t * value, lv_style_selector_t selector);
#if LV_USE_FLEX
void lv_obj_set_style_flex_flow(lv_obj_t * obj, lv_flex_flow_t value, lv_style_selector_t selector);
void lv_obj_set_style_flex_main_place(lv_obj_t * obj, lv_flex_align_t value, lv_style_selector_t selector);
void lv_obj_set_style_flex_cross_place(lv_obj_t * obj, lv_flex_align_t value, lv_style_selector_t selector);
void lv_obj_set_style_flex_track_place(lv_obj_t * obj, lv_flex_align_t value, lv_style_selector_t selector);
void lv_obj_set_style_flex_grow(lv_obj_t * obj, uint8_t value, lv_style_selector_t selector);
void lv_obj_set_style_flex_flow(lv_obj_t * obj, lv_flex_flow_t value, lv_style_selector_t selector);
void lv_obj_set_style_flex_main_place(lv_obj_t * obj, lv_flex_align_t value, lv_style_selector_t selector);
void lv_obj_set_style_flex_cross_place(lv_obj_t * obj, lv_flex_align_t value, lv_style_selector_t selector);
void lv_obj_set_style_flex_track_place(lv_obj_t * obj, lv_flex_align_t value, lv_style_selector_t selector);
void lv_obj_set_style_flex_grow(lv_obj_t * obj, uint8_t value, lv_style_selector_t selector);
#endif /*LV_USE_FLEX*/
#if LV_USE_GRID
void lv_obj_set_style_grid_column_dsc_array(lv_obj_t * obj, const int32_t * value, lv_style_selector_t selector);
void lv_obj_set_style_grid_column_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector);
void lv_obj_set_style_grid_row_dsc_array(lv_obj_t * obj, const int32_t * value, lv_style_selector_t selector);
void lv_obj_set_style_grid_row_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector);
void lv_obj_set_style_grid_cell_column_pos(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
void lv_obj_set_style_grid_cell_x_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector);
void lv_obj_set_style_grid_cell_column_span(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
void lv_obj_set_style_grid_cell_row_pos(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
void lv_obj_set_style_grid_cell_y_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector);
void lv_obj_set_style_grid_cell_row_span(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
void lv_obj_set_style_grid_column_dsc_array(lv_obj_t * obj, const int32_t * value, lv_style_selector_t selector);
void lv_obj_set_style_grid_column_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector);
void lv_obj_set_style_grid_row_dsc_array(lv_obj_t * obj, const int32_t * value, lv_style_selector_t selector);
void lv_obj_set_style_grid_row_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector);
void lv_obj_set_style_grid_cell_column_pos(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
void lv_obj_set_style_grid_cell_x_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector);
void lv_obj_set_style_grid_cell_column_span(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
void lv_obj_set_style_grid_cell_row_pos(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
void lv_obj_set_style_grid_cell_y_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector);
void lv_obj_set_style_grid_cell_row_span(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
#endif /*LV_USE_GRID*/
#endif /* LV_OBJ_STYLE_GEN_H */

View File

@ -820,18 +820,17 @@ static void refr_obj_and_children(lv_layer_t * layer, lv_obj_t * top_obj)
}
static lv_result_t layer_get_area(lv_layer_t * layer, lv_obj_t * obj, lv_layer_type_t layer_type,
lv_area_t * layer_area_out)
lv_area_t * layer_area_out, lv_area_t * obj_draw_size_out)
{
int32_t ext_draw_size = _lv_obj_get_ext_draw_size(obj);
lv_area_t obj_coords_ext;
lv_obj_get_coords(obj, &obj_coords_ext);
lv_area_increase(&obj_coords_ext, ext_draw_size, ext_draw_size);
lv_obj_get_coords(obj, obj_draw_size_out);
lv_area_increase(obj_draw_size_out, ext_draw_size, ext_draw_size);
if(layer_type == LV_LAYER_TYPE_TRANSFORM) {
/*Get the transformed area and clip it to the current clip area.
*This area needs to be updated on the screen.*/
lv_area_t clip_coords_for_obj;
lv_area_t tranf_coords = obj_coords_ext;
lv_area_t tranf_coords = *obj_draw_size_out;
lv_obj_get_transformed_area(obj, &tranf_coords, false, false);
if(!_lv_area_intersect(&clip_coords_for_obj, &layer->_clip_area, &tranf_coords)) {
return LV_RESULT_INVALID;
@ -842,7 +841,7 @@ static lv_result_t layer_get_area(lv_layer_t * layer, lv_obj_t * obj, lv_layer_t
*in order to cover transformed area after transformation.*/
lv_area_t inverse_clip_coords_for_obj = clip_coords_for_obj;
lv_obj_get_transformed_area(obj, &inverse_clip_coords_for_obj, false, true);
if(!_lv_area_intersect(&inverse_clip_coords_for_obj, &inverse_clip_coords_for_obj, &obj_coords_ext)) {
if(!_lv_area_intersect(&inverse_clip_coords_for_obj, &inverse_clip_coords_for_obj, obj_draw_size_out)) {
return LV_RESULT_INVALID;
}
@ -851,7 +850,7 @@ static lv_result_t layer_get_area(lv_layer_t * layer, lv_obj_t * obj, lv_layer_t
}
else if(layer_type == LV_LAYER_TYPE_SIMPLE) {
lv_area_t clip_coords_for_obj;
if(!_lv_area_intersect(&clip_coords_for_obj, &layer->_clip_area, &obj_coords_ext)) {
if(!_lv_area_intersect(&clip_coords_for_obj, &layer->_clip_area, obj_draw_size_out)) {
return LV_RESULT_INVALID;
}
*layer_area_out = clip_coords_for_obj;
@ -891,7 +890,8 @@ void refr_obj(lv_layer_t * layer, lv_obj_t * obj)
if(opa < LV_OPA_MIN) return;
lv_area_t layer_area_full;
lv_result_t res = layer_get_area(layer, obj, layer_type, &layer_area_full);
lv_area_t obj_draw_size;
lv_result_t res = layer_get_area(layer, obj, layer_type, &layer_area_full, &obj_draw_size);
if(res != LV_RESULT_OK) return;
/*Simple layers can be subdivied into smaller layers*/
@ -940,6 +940,8 @@ void refr_obj(lv_layer_t * layer, lv_obj_t * obj)
layer_draw_dsc.skew_y = lv_obj_get_style_transform_skew_y(obj, 0);
layer_draw_dsc.blend_mode = lv_obj_get_style_blend_mode(obj, 0);
layer_draw_dsc.antialias = disp_refr->antialiasing;
layer_draw_dsc.bitmap_mask_src = lv_obj_get_style_bitmap_mask_src(obj, 0);
layer_draw_dsc.original_area = obj_draw_size;
layer_draw_dsc.src = new_layer;
lv_draw_layer(layer, &layer_draw_dsc, &layer_area_act);

View File

@ -51,6 +51,7 @@ void lv_draw_image_dsc_init(lv_draw_image_dsc_t * dsc)
dsc->scale_x = LV_SCALE_NONE;
dsc->scale_y = LV_SCALE_NONE;
dsc->antialias = LV_COLOR_DEPTH > 8 ? 1 : 0;
dsc->original_area.x2 = LV_COORD_MIN; /*Indicate invalid area by default by setting a negative size*/
dsc->base.dsc_size = sizeof(lv_draw_image_dsc_t);
}

View File

@ -55,9 +55,14 @@ typedef struct _lv_draw_image_dsc_t {
lv_opa_t opa;
lv_blend_mode_t blend_mode : 4;
uint16_t antialias : 1;
uint16_t tile : 1;
uint16_t antialias : 1;
uint16_t tile : 1;
lv_draw_image_sup_t * sup;
/** Might be used to indicate the original size of the image if only a small portion is rendered now.
* Used when a part of a layer is rendered to show the total layer size*/
lv_area_t original_area;
const lv_image_dsc_t * bitmap_mask_src;
} lv_draw_image_dsc_t;
/**

View File

@ -93,6 +93,11 @@ void lv_draw_sw_blend(lv_draw_unit_t * draw_unit, const lv_draw_sw_blend_dsc_t *
return;
}
if(blend_dsc->mask_area && !_lv_area_intersect(&blend_area, &blend_area, blend_dsc->mask_area)) {
LV_PROFILER_END;
return;
}
_lv_draw_sw_blend_image_dsc_t image_dsc;
image_dsc.dest_w = lv_area_get_width(&blend_area);
image_dsc.dest_h = lv_area_get_height(&blend_area);

View File

@ -264,6 +264,17 @@ static int32_t evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task)
if(draw_dsc->skew_x != 0 || draw_dsc->skew_y != 0) {
return 0;
}
bool transformed = draw_dsc->rotation != 0 || draw_dsc->scale_x != LV_SCALE_NONE ||
draw_dsc->scale_y != LV_SCALE_NONE ? true : false;
bool masked = draw_dsc->bitmap_mask_src != NULL;
if(masked && transformed) return 0;
lv_color_format_t cf = draw_dsc->header.cf;
if(masked && (cf == LV_COLOR_FORMAT_A8 || cf == LV_COLOR_FORMAT_RGB565A8)) {
return 0;
}
}
break;
default:

View File

@ -179,6 +179,8 @@ static void img_draw_core(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t
bool transformed = draw_dsc->rotation != 0 || draw_dsc->scale_x != LV_SCALE_NONE ||
draw_dsc->scale_y != LV_SCALE_NONE ? true : false;
bool masked = draw_dsc->bitmap_mask_src != NULL;
lv_draw_sw_blend_dsc_t blend_dsc;
const lv_draw_buf_t * decoded = decoder_dsc->decoded;
const uint8_t * src_buf = decoded->data;
@ -191,7 +193,7 @@ static void img_draw_core(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t
blend_dsc.blend_mode = draw_dsc->blend_mode;
blend_dsc.src_stride = img_stride;
if(!transformed && cf == LV_COLOR_FORMAT_A8) {
if(!transformed && !masked && cf == LV_COLOR_FORMAT_A8) {
lv_area_t clipped_coords;
if(!_lv_area_intersect(&clipped_coords, img_coords, draw_unit->clip_area)) return;
@ -205,7 +207,7 @@ static void img_draw_core(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t
blend_dsc.blend_area = img_coords;
lv_draw_sw_blend(draw_unit, &blend_dsc);
}
else if(!transformed && cf == LV_COLOR_FORMAT_RGB565A8 && draw_dsc->recolor_opa <= LV_OPA_MIN) {
else if(!transformed && !masked && cf == LV_COLOR_FORMAT_RGB565A8 && draw_dsc->recolor_opa <= LV_OPA_MIN) {
int32_t src_h = lv_area_get_height(img_coords);
int32_t src_w = lv_area_get_width(img_coords);
blend_dsc.src_area = img_coords;
@ -225,14 +227,33 @@ static void img_draw_core(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t
lv_draw_sw_blend(draw_unit, &blend_dsc);
}
/*The simplest case just copy the pixels into the draw_buf. Blending will convert the colors if needed*/
else if(!transformed && draw_dsc->recolor_opa <= LV_OPA_MIN) {
else if(!transformed && !masked && draw_dsc->recolor_opa <= LV_OPA_MIN) {
blend_dsc.src_area = img_coords;
blend_dsc.src_buf = src_buf;
blend_dsc.blend_area = img_coords;
blend_dsc.src_color_format = cf;
lv_draw_sw_blend(draw_unit, &blend_dsc);
}
/* check whethr it is possible to accelerate the operation in synchronouse mode */
/*Handle masked RGB565, RGB888, XRGB888, or ARGB8888 images*/
else if(!transformed && masked && draw_dsc->recolor_opa <= LV_OPA_MIN) {
blend_dsc.src_area = img_coords;
blend_dsc.src_buf = src_buf;
blend_dsc.blend_area = img_coords;
blend_dsc.src_color_format = cf;
blend_dsc.mask_buf = draw_dsc->bitmap_mask_src->data;
blend_dsc.mask_stride = draw_dsc->bitmap_mask_src->header.stride;
const lv_area_t * original_area;
if(lv_area_get_width(&draw_dsc->original_area) < 0) original_area = img_coords;
else original_area = &draw_dsc->original_area;
lv_area_t a = {0, 0, draw_dsc->bitmap_mask_src->header.w - 1, draw_dsc->bitmap_mask_src->header.h - 1};
lv_area_align(original_area, &a, LV_ALIGN_CENTER, 0, 0);
blend_dsc.mask_area = &a;
blend_dsc.mask_res = LV_DRAW_SW_MASK_RES_CHANGED;
lv_draw_sw_blend(draw_unit, &blend_dsc);
}
/* check whether it is possible to accelerate the operation in synchronouse mode */
else if(LV_RESULT_INVALID == LV_DRAW_SW_IMAGE(transformed, /* whether require transform */
cf, /* image format */
src_buf, /* image buffer */

View File

@ -136,6 +136,7 @@ const uint8_t _lv_style_builtin_prop_flag_lookup_table[_LV_STYLE_NUM_BUILT_IN_PR
[LV_STYLE_BLEND_MODE] = LV_STYLE_PROP_FLAG_LAYER_UPDATE,
[LV_STYLE_LAYOUT] = LV_STYLE_PROP_FLAG_LAYOUT_UPDATE,
[LV_STYLE_BASE_DIR] = LV_STYLE_PROP_FLAG_INHERITABLE | LV_STYLE_PROP_FLAG_LAYOUT_UPDATE,
[LV_STYLE_BITMAP_MASK_SRC] = LV_STYLE_PROP_FLAG_LAYER_UPDATE,
#if LV_USE_FLEX
[LV_STYLE_FLEX_FLOW] = LV_STYLE_PROP_FLAG_LAYOUT_UPDATE,

View File

@ -299,28 +299,30 @@ enum _lv_style_prop_t {
LV_STYLE_TRANSFORM_SKEW_X = 113,
LV_STYLE_TRANSFORM_SKEW_Y = 114,
LV_STYLE_BITMAP_MASK_SRC = 115,
#if LV_USE_FLEX
LV_STYLE_FLEX_FLOW = 115,
LV_STYLE_FLEX_MAIN_PLACE = 116,
LV_STYLE_FLEX_CROSS_PLACE = 117,
LV_STYLE_FLEX_TRACK_PLACE = 118,
LV_STYLE_FLEX_GROW = 119,
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,
#endif
#if LV_USE_GRID
LV_STYLE_GRID_COLUMN_ALIGN = 120,
LV_STYLE_GRID_ROW_ALIGN = 121,
LV_STYLE_GRID_ROW_DSC_ARRAY = 122,
LV_STYLE_GRID_COLUMN_DSC_ARRAY = 123,
LV_STYLE_GRID_CELL_COLUMN_POS = 124,
LV_STYLE_GRID_CELL_COLUMN_SPAN = 125,
LV_STYLE_GRID_CELL_X_ALIGN = 126,
LV_STYLE_GRID_CELL_ROW_POS = 127,
LV_STYLE_GRID_CELL_ROW_SPAN = 128,
LV_STYLE_GRID_CELL_Y_ALIGN = 129,
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,
#endif
_LV_STYLE_LAST_BUILT_IN_PROP = 130,
_LV_STYLE_LAST_BUILT_IN_PROP = 140,
_LV_STYLE_NUM_BUILT_IN_PROPS = _LV_STYLE_LAST_BUILT_IN_PROP + 1,

View File

@ -937,6 +937,16 @@ void lv_style_set_base_dir(lv_style_t * style, lv_base_dir_t value)
}
const lv_style_prop_t _lv_style_const_prop_id_BASE_DIR = LV_STYLE_BASE_DIR;
void lv_style_set_bitmap_mask_src(lv_style_t * style, const lv_image_dsc_t * value)
{
lv_style_value_t v = {
.ptr = value
};
lv_style_set_prop(style, LV_STYLE_BITMAP_MASK_SRC, v);
}
const lv_style_prop_t _lv_style_const_prop_id_BITMAP_MASK_SRC = LV_STYLE_BITMAP_MASK_SRC;
#if LV_USE_FLEX
void lv_style_set_flex_flow(lv_style_t * style, lv_flex_flow_t value)

View File

@ -195,6 +195,8 @@ void lv_style_set_layout(lv_style_t * style, uint16_t value);
LV_ATTRIBUTE_EXTERN_DATA extern const lv_style_prop_t _lv_style_const_prop_id_LAYOUT;
void lv_style_set_base_dir(lv_style_t * style, lv_base_dir_t value);
LV_ATTRIBUTE_EXTERN_DATA extern const lv_style_prop_t _lv_style_const_prop_id_BASE_DIR;
void lv_style_set_bitmap_mask_src(lv_style_t * style, const lv_image_dsc_t * value);
LV_ATTRIBUTE_EXTERN_DATA extern const lv_style_prop_t _lv_style_const_prop_id_BITMAP_MASK_SRC;
#if LV_USE_FLEX
void lv_style_set_flex_flow(lv_style_t * style, lv_flex_flow_t value);
@ -697,6 +699,11 @@ LV_ATTRIBUTE_EXTERN_DATA extern const lv_style_prop_t _lv_style_const_prop_id_BA
{ \
.prop_ptr = &_lv_style_const_prop_id_BASE_DIR, .value = { .num = (int32_t)val } \
}
#define LV_STYLE_CONST_BITMAP_MASK_SRC(val) \
{ \
.prop_ptr = &_lv_style_const_prop_id_BITMAP_MASK_SRC, .value = { .ptr = val } \
}
#if LV_USE_FLEX
#define LV_STYLE_CONST_FLEX_FLOW(val) \

View File

@ -421,12 +421,19 @@ void lv_image_set_inner_align(lv_obj_t * obj, lv_image_align_t align)
if(align == img->align) return;
img->align = align;
update_align(obj);
lv_obj_invalidate(obj);
}
void lv_image_set_bitmap_map_src(lv_obj_t * obj, const lv_image_dsc_t * src)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_image_t * img = (lv_image_t *)obj;
img->bitmap_mask_src = src;
lv_obj_invalidate(obj);
}
/*=====================
* Getter functions
*====================*/
@ -531,6 +538,15 @@ lv_image_align_t lv_image_get_inner_align(lv_obj_t * obj)
return img->align;
}
const lv_image_dsc_t * lv_image_get_bitmap_map_src(lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_image_t * img = (lv_image_t *)obj;
return img->bitmap_mask_src;
}
/**********************
* STATIC FUNCTIONS
**********************/
@ -701,6 +717,10 @@ static void draw_image(lv_event_t * e)
return;
}
}
if(img->bitmap_mask_src) {
info->res = LV_COVER_RES_NOT_COVER;
return;
}
}
else if(code == LV_EVENT_DRAW_MAIN) {
@ -722,6 +742,7 @@ static void draw_image(lv_event_t * e)
draw_dsc.rotation = img->rotation;
draw_dsc.antialias = img->antialias;
draw_dsc.blend_mode = img->blend_mode;
draw_dsc.bitmap_mask_src = img->bitmap_mask_src;
draw_dsc.src = img->src;
lv_area_t img_area = {obj->coords.x1, obj->coords.y1,

View File

@ -40,6 +40,7 @@ extern "C" {
typedef struct {
lv_obj_t obj;
const void * src; /**< Image source: Pointer to an array or a file or a symbol*/
const lv_image_dsc_t * bitmap_mask_src; /**< Pointer to an A8 bitmap mask */
lv_point_t offset;
int32_t w; /**< Width of the image (Handled by the library)*/
int32_t h; /**< Height of the image (Handled by the library)*/
@ -230,6 +231,13 @@ void lv_image_set_antialias(lv_obj_t * obj, bool antialias);
*/
void lv_image_set_inner_align(lv_obj_t * obj, lv_image_align_t align);
/**
* Set an A8 bitmap mask for the image.
* @param obj pointer to an image object
* @param src an lv_image_dsc_t bitmap mask source.
*/
void lv_image_set_bitmap_map_src(lv_obj_t * obj, const lv_image_dsc_t * src);
/*=====================
* Getter functions
*====================*/
@ -314,6 +322,13 @@ bool lv_image_get_antialias(lv_obj_t * obj);
*/
lv_image_align_t lv_image_get_inner_align(lv_obj_t * obj);
/**
* Get the bitmap mask source.
* @param obj pointer to an image object
* @return an lv_image_dsc_t bitmap mask source.
*/
const lv_image_dsc_t * lv_image_get_bitmap_map_src(lv_obj_t * obj);
/**********************
* MACROS
**********************/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -19,6 +19,12 @@ static lv_obj_t * create_panel(int32_t radius, bool transform)
lv_obj_set_style_pad_all(parent, 3, 0);
lv_obj_set_style_radius(parent, radius, 0);
lv_obj_set_style_clip_corner(parent, true, 0);
lv_obj_set_style_shadow_color(parent, lv_color_hex(0x888888), 0);
lv_obj_set_style_shadow_width(parent, 30, 0);
lv_obj_set_style_shadow_spread(parent, 10, 0);
lv_obj_set_style_outline_color(parent, lv_color_hex(0xff0000), 0);
lv_obj_set_style_outline_width(parent, 2, 0);
lv_obj_set_style_outline_pad(parent, 5, 0);
if(transform) lv_obj_set_style_transform_rotation(parent, 300, 0);
lv_obj_t * label = lv_label_create(parent);
@ -35,7 +41,7 @@ static lv_obj_t * create_panel(int32_t radius, bool transform)
return parent;
}
void test_func_1(void)
void test_clip_corner_1(void)
{
lv_obj_set_flex_flow(lv_screen_active(), LV_FLEX_FLOW_ROW_WRAP);
lv_obj_set_flex_align(lv_screen_active(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_EVENLY);
@ -52,7 +58,7 @@ void test_func_1(void)
create_panel(30, true);
create_panel(100, true);
TEST_ASSERT_EQUAL_SCREENSHOT("clip_corner_1.png");
TEST_ASSERT_EQUAL_SCREENSHOT("draw/clip_corner_1.png");
}

View File

@ -0,0 +1,37 @@
#if LV_BUILD_TEST
#include "../lvgl.h"
#include "unity/unity.h"
void setUp(void)
{
/* Function run before every test */
}
void tearDown(void)
{
/* Function run after every test */
lv_obj_clean(lv_screen_active());
}
void test_draw_layer_bitmap_mask(void)
{
LV_IMAGE_DECLARE(test_image_cogwheel_a8);
lv_obj_t * obj = lv_obj_create(lv_screen_active());
lv_obj_set_size(obj, 200, 200);
lv_obj_set_style_bg_color(obj, lv_color_hex3(0xf88), 0);
lv_obj_set_style_bitmap_mask_src(obj, &test_image_cogwheel_a8, 0);
lv_obj_center(obj);
lv_obj_t * label = lv_label_create(obj);
lv_obj_set_width(label, lv_pct(100));
lv_label_set_text(label,
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque suscipit risus nec pharetra pulvinar. In hac habitasse platea dictumst. Proin placerat congue massa eu luctus. Suspendisse risus nulla, consectetur eget odio ut, mollis sollicitudin magna. Suspendisse volutpat consequat laoreet. Aenean sodales suscipit leo, vitae pulvinar lorem pulvinar eu. Nullam molestie hendrerit est sit amet imperdiet.");
lv_obj_center(label);
TEST_ASSERT_EQUAL_SCREENSHOT("draw/draw_layer_bitmap_mask.png");
}
#endif