mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-24 16:37:18 +08:00
fix(blur): fix incorrect invalidation if part has blur or dropshadow (#9930)
This commit is contained in:
committed by
GitHub
parent
b1e55eabe9
commit
14a1e1fd47
+43
-33
@@ -38,6 +38,8 @@ static bool is_transformed(const lv_obj_t * obj);
|
||||
static lv_result_t invalidate_area_core(const lv_obj_t * obj, lv_area_t * area_tmp);
|
||||
static lv_result_t obj_invalidate_area_internal(const lv_display_t * disp, const lv_obj_t * obj,
|
||||
const lv_area_t * area);
|
||||
static bool has_blur(const lv_obj_t * obj);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
@@ -790,7 +792,7 @@ bool lv_obj_refresh_self_size(lv_obj_t * obj)
|
||||
return false;
|
||||
|
||||
/**
|
||||
* Refresh the parent's layout, because the childs size is in some way dependent on its contents we need to force a
|
||||
* Refresh the parent's layout, because the children size is in some way dependent on its contents we need to force a
|
||||
* recalculation of the parents layout
|
||||
*/
|
||||
lv_obj_t * parent = lv_obj_get_parent(obj);
|
||||
@@ -1046,7 +1048,8 @@ typedef struct {
|
||||
static lv_obj_tree_walk_res_t blur_walk_cb(lv_obj_t * obj, void * user_data)
|
||||
{
|
||||
blur_walk_data_t * blur_data = user_data;
|
||||
if(obj == blur_data->requester_obj) return LV_OBJ_TREE_WALK_SKIP_CHILDREN;
|
||||
/*The requester obj was checked already*/
|
||||
if(blur_data->requester_obj == obj) return LV_OBJ_TREE_WALK_SKIP_CHILDREN;
|
||||
|
||||
/*Truncate the area to the object*/
|
||||
lv_area_t obj_coords;
|
||||
@@ -1060,48 +1063,23 @@ static lv_obj_tree_walk_res_t blur_walk_cb(lv_obj_t * obj, void * user_data)
|
||||
|
||||
/*If the widget has blur set, invalidate it*/
|
||||
if(lv_area_is_on(blur_data->inv_area, &obj_coords)) {
|
||||
const uint32_t group_blur = (uint32_t)1 << lv_style_get_prop_group(LV_STYLE_BLUR_RADIUS);
|
||||
const uint32_t group_dropshadow = (uint32_t)1 << lv_style_get_prop_group(LV_STYLE_DROP_SHADOW_OPA);
|
||||
const lv_state_t state = lv_obj_style_get_selector_state(lv_obj_get_state(obj));
|
||||
const lv_state_t state_inv = ~state;
|
||||
lv_style_value_t v;
|
||||
uint32_t i;
|
||||
for(i = 0; i < obj->style_cnt; i++) {
|
||||
lv_obj_style_t * obj_style = &obj->styles[i];
|
||||
if(obj_style->is_disabled) continue;
|
||||
|
||||
lv_state_t state_style = lv_obj_style_get_selector_state(obj->styles[i].selector);
|
||||
if((state_style & state_inv)) continue;
|
||||
|
||||
bool invalidation_needed = false;
|
||||
if((obj_style->style->has_group & group_blur) &&
|
||||
lv_style_get_prop(obj_style->style, LV_STYLE_BLUR_RADIUS, &v)) {
|
||||
invalidation_needed = true;
|
||||
}
|
||||
if((obj_style->style->has_group & group_dropshadow) &&
|
||||
lv_style_get_prop(obj_style->style, LV_STYLE_DROP_SHADOW_OPA, &v)) {
|
||||
invalidation_needed = true;
|
||||
}
|
||||
|
||||
if(invalidation_needed == false) continue;
|
||||
|
||||
/*Truncate the area to the object*/
|
||||
if(has_blur(obj)) {
|
||||
ext_size = lv_obj_get_ext_draw_size(obj);
|
||||
lv_area_copy(&obj_coords, &obj->coords);
|
||||
obj_coords.x1 -= ext_size;
|
||||
obj_coords.y1 -= ext_size;
|
||||
obj_coords.x2 += ext_size;
|
||||
obj_coords.y2 += ext_size;
|
||||
|
||||
invalidate_area_core(obj, &obj_coords);
|
||||
|
||||
/*No need to check the children as the widget is already invalidated
|
||||
*which will redraw the children too*/
|
||||
return LV_OBJ_TREE_WALK_SKIP_CHILDREN;
|
||||
}
|
||||
|
||||
/*Check the next child, maybe it's blurred*/
|
||||
return LV_OBJ_TREE_WALK_NEXT;
|
||||
else {
|
||||
/*Check the next child, maybe it's blurred*/
|
||||
return LV_OBJ_TREE_WALK_NEXT;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*Not on the area of interest, skip it*/
|
||||
@@ -1117,7 +1095,10 @@ lv_result_t lv_obj_invalidate_area(const lv_obj_t * obj, const lv_area_t * area)
|
||||
lv_display_t * disp = lv_obj_get_display(obj);
|
||||
if(!lv_display_is_invalidation_enabled(disp)) return LV_RESULT_INVALID;
|
||||
|
||||
return obj_invalidate_area_internal(disp, obj, area);
|
||||
/*If there are blurred or drop-shadow parts the whole widget needs to be invalidated
|
||||
*as these can't be calculated partially. */
|
||||
if(has_blur(obj)) return lv_obj_invalidate(obj);
|
||||
else return obj_invalidate_area_internal(disp, obj, area);
|
||||
}
|
||||
|
||||
|
||||
@@ -1667,3 +1648,32 @@ static lv_result_t invalidate_area_core(const lv_obj_t * obj, lv_area_t * area_t
|
||||
lv_result_t res = lv_inv_area(lv_obj_get_display(obj), area_tmp);
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool has_blur(const lv_obj_t * obj)
|
||||
{
|
||||
const uint32_t group_blur = (uint32_t)1 << lv_style_get_prop_group(LV_STYLE_BLUR_RADIUS);
|
||||
const uint32_t group_dropshadow = (uint32_t)1 << lv_style_get_prop_group(LV_STYLE_DROP_SHADOW_OPA);
|
||||
const lv_state_t state = lv_obj_style_get_selector_state(lv_obj_get_state(obj));
|
||||
const lv_state_t state_inv = ~state;
|
||||
lv_style_value_t v;
|
||||
uint32_t i;
|
||||
for(i = 0; i < obj->style_cnt; i++) {
|
||||
lv_obj_style_t * obj_style = &obj->styles[i];
|
||||
if(obj_style->is_disabled) continue;
|
||||
|
||||
lv_state_t state_style = lv_obj_style_get_selector_state(obj->styles[i].selector);
|
||||
if((state_style & state_inv)) continue;
|
||||
|
||||
if((obj_style->style->has_group & group_blur) &&
|
||||
lv_style_get_prop(obj_style->style, LV_STYLE_BLUR_RADIUS, &v)) {
|
||||
if(v.num > 0) return true;
|
||||
}
|
||||
if((obj_style->style->has_group & group_dropshadow) &&
|
||||
lv_style_get_prop(obj_style->style, LV_STYLE_DROP_SHADOW_OPA, &v)) {
|
||||
if(v.num > 0) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
@@ -56,7 +56,6 @@
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static lv_test_screenshot_result_t screenshot_compare(const char * fn_ref, uint8_t tolerance);
|
||||
static unsigned read_png_file(lv_draw_buf_t ** refr_draw_buf, unsigned * width, unsigned * height,
|
||||
const char * file_name);
|
||||
static unsigned write_png_file(void * raw_img, uint32_t width, uint32_t height, char * file_name);
|
||||
@@ -83,20 +82,11 @@ lv_test_screenshot_result_t lv_test_screenshot_compare(const char * fn_ref)
|
||||
lv_refr_now(NULL);
|
||||
|
||||
lv_test_screenshot_result_t res;
|
||||
res = screenshot_compare(fn_ref, REF_IMG_TOLERANCE);
|
||||
res = lv_test_screenshot_compare_core(fn_ref);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Compare the content of the frame buffer with a reference image
|
||||
* @param fn_ref reference image path
|
||||
* @return An element of lv_test_screenshot_result_t
|
||||
*/
|
||||
static lv_test_screenshot_result_t screenshot_compare(const char * fn_ref, uint8_t tolerance)
|
||||
lv_test_screenshot_result_t lv_test_screenshot_compare_core(const char * fn_ref)
|
||||
{
|
||||
char fn_ref_full[256];
|
||||
lv_snprintf(fn_ref_full, sizeof(fn_ref_full), "%s%s", REF_IMGS_PATH, fn_ref);
|
||||
@@ -150,9 +140,9 @@ static lv_test_screenshot_result_t screenshot_compare(const char * fn_ref, uint8
|
||||
uint8_t * ptr_ref = &(ref_row[x * 4]);
|
||||
uint8_t * ptr_act = &screen_buf_tmp[x * 4];
|
||||
|
||||
if(LV_ABS((int32_t) ptr_act[0] - (int32_t) ptr_ref[0]) > tolerance ||
|
||||
LV_ABS((int32_t) ptr_act[1] - (int32_t) ptr_ref[1]) > tolerance ||
|
||||
LV_ABS((int32_t) ptr_act[2] - (int32_t) ptr_ref[2]) > tolerance) {
|
||||
if(LV_ABS((int32_t) ptr_act[0] - (int32_t) ptr_ref[0]) > REF_IMG_TOLERANCE ||
|
||||
LV_ABS((int32_t) ptr_act[1] - (int32_t) ptr_ref[1]) > REF_IMG_TOLERANCE ||
|
||||
LV_ABS((int32_t) ptr_act[2] - (int32_t) ptr_ref[2]) > REF_IMG_TOLERANCE) {
|
||||
uint32_t act_px = (ptr_act[2] << 16) + (ptr_act[1] << 8) + (ptr_act[0] << 0);
|
||||
uint32_t ref_px = 0;
|
||||
memcpy(&ref_px, ptr_ref, 3);
|
||||
@@ -162,7 +152,7 @@ static lv_test_screenshot_result_t screenshot_compare(const char * fn_ref, uint8
|
||||
" - Expected: %X\n"
|
||||
" - Actual: %X\n"
|
||||
" - Tolerance: %d\n",
|
||||
fn_ref_full, x, y, ref_px, act_px, tolerance);
|
||||
fn_ref_full, x, y, ref_px, act_px, REF_IMG_TOLERANCE);
|
||||
err = true;
|
||||
break;
|
||||
}
|
||||
@@ -188,6 +178,10 @@ static lv_test_screenshot_result_t screenshot_compare(const char * fn_ref, uint8
|
||||
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static unsigned read_png_file(lv_draw_buf_t ** refr_draw_buf, unsigned * width, unsigned * height,
|
||||
const char * file_name)
|
||||
{
|
||||
|
||||
@@ -53,7 +53,7 @@ typedef enum {
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Compare the current content of the test screen with a reference PNG image
|
||||
* Invalidate and redraw the current screen and compare its content with a reference PNG image
|
||||
* - If the reference image is not found it will be created automatically from the rendered screen.
|
||||
* - If the compare fails an `<image_name>_err.png` file will be created with the rendered content next to the reference image.
|
||||
*
|
||||
@@ -66,6 +66,14 @@ typedef enum {
|
||||
*/
|
||||
lv_test_screenshot_result_t lv_test_screenshot_compare(const char * fn_ref);
|
||||
|
||||
|
||||
/**
|
||||
* Works the same way as `lv_test_screenshot_compare` but it doesn't invalidate and redraw the screen
|
||||
* but uses its current content. (lv_refr_now(NULL) might be called earlier)
|
||||
* @param fn_ref reference image path
|
||||
*/
|
||||
lv_test_screenshot_result_t lv_test_screenshot_compare_core(const char * fn_ref);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 82 KiB |
@@ -16,8 +16,14 @@ void tearDown(void)
|
||||
lv_obj_clean(lv_screen_active());
|
||||
}
|
||||
|
||||
void test_draw_drop_shadow(void)
|
||||
|
||||
|
||||
void test_draw_drop_shadow_basic(void)
|
||||
{
|
||||
/*It doesn't work with VGLite*/
|
||||
#if LV_USE_DRAW_VG_LITE
|
||||
TEST_PASS();
|
||||
#else
|
||||
static lv_style_t style;
|
||||
lv_style_init(&style);
|
||||
lv_style_set_drop_shadow_opa(&style, 255);
|
||||
@@ -70,6 +76,68 @@ void test_draw_drop_shadow(void)
|
||||
lv_label_set_text(label, "Hello world");
|
||||
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("draw/draw_drop_shadow.png");
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_draw_drop_shadow_invalidate(void)
|
||||
{
|
||||
/*It doesn't work with VGLite*/
|
||||
#if LV_USE_DRAW_VG_LITE
|
||||
TEST_PASS();
|
||||
#else
|
||||
static lv_style_t style;
|
||||
lv_style_init(&style);
|
||||
|
||||
lv_style_set_drop_shadow_color(&style, lv_palette_main(LV_PALETTE_RED));
|
||||
lv_style_set_drop_shadow_radius(&style, 16);
|
||||
lv_style_set_drop_shadow_opa(&style, 255);
|
||||
lv_style_set_drop_shadow_offset_x(&style, 5);
|
||||
lv_style_set_drop_shadow_offset_y(&style, 10);
|
||||
|
||||
/*Create an object with the new style*/
|
||||
lv_obj_t * obj = lv_arc_create(lv_screen_active());
|
||||
lv_obj_add_style(obj, &style, LV_PART_INDICATOR);
|
||||
lv_obj_set_pos(obj, 10, 10);
|
||||
lv_arc_set_value(obj, 50);
|
||||
|
||||
/*Don't use TEST_ASSERT_EQUAL_SCREENSHOT as it invalidates the screen removing all
|
||||
*manual partial invalidations below*/
|
||||
const char * path = "draw/draw_drop_shadow_invalidate.png";
|
||||
lv_refr_now(NULL);
|
||||
TEST_ASSERT_MESSAGE(lv_test_screenshot_compare_core(path), path);
|
||||
|
||||
lv_arc_set_value(obj, 10);
|
||||
lv_refr_now(NULL);
|
||||
lv_arc_set_value(obj, 20);
|
||||
lv_refr_now(NULL);
|
||||
lv_arc_set_value(obj, 30);
|
||||
lv_refr_now(NULL);
|
||||
lv_arc_set_value(obj, 40);
|
||||
lv_refr_now(NULL);
|
||||
lv_arc_set_value(obj, 50);
|
||||
lv_refr_now(NULL);
|
||||
lv_arc_set_value(obj, 60);
|
||||
lv_refr_now(NULL);
|
||||
lv_arc_set_value(obj, 70);
|
||||
lv_refr_now(NULL);
|
||||
lv_arc_set_value(obj, 80);
|
||||
lv_refr_now(NULL);
|
||||
lv_arc_set_value(obj, 90);
|
||||
lv_refr_now(NULL);
|
||||
lv_arc_set_value(obj, 100);
|
||||
lv_refr_now(NULL);
|
||||
|
||||
lv_arc_set_value(obj, 50);
|
||||
lv_refr_now(NULL);
|
||||
|
||||
TEST_ASSERT_MESSAGE(lv_test_screenshot_compare_core(path), path);
|
||||
|
||||
lv_area_t a = {20, 20, 200, 60};
|
||||
lv_obj_invalidate_area(obj, &a);
|
||||
lv_refr_now(NULL);
|
||||
TEST_ASSERT_MESSAGE(lv_test_screenshot_compare_core(path), path);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user