Question: Is keep_outside = 1 in lv_draw_mask_rect() supposed to clear the inside or the outside?

Hi LVGL team :wave:,

I’m experimenting with lv_draw_mask_rect() and I have a question about how the keep_outside parameter is expected to behave — especially when using a radius mask.

According to the documentation:

  • If keep_outside = 1, the area outside the rectangle should be kept, and the inside should be cleared (transparent).

However, in the following example, when I apply a rectangle mask with keep_outside = 1, the inside of the masked area is still visible, and the outside is cleared — which feels like the behavior of keep_outside = 0.

:page_facing_up: Full Example Code

static void event_cb_draw_mask(lv_event_t * e)
{
    const auto * obj = static_cast<lv_obj_t *>(lv_event_get_target(e));
    const lv_draw_task_t * draw_task = lv_event_get_draw_task(e);
    const auto * base_dsc = static_cast<lv_draw_dsc_base_t *>(lv_draw_task_get_draw_dsc(draw_task));
    lv_area_t obj_coords;
    lv_obj_get_coords(obj, &obj_coords);
    lv_layer_t * layer = base_dsc->layer;
    lv_area_t layer_area = {0,0, 200, 200};
    lv_area_align(&obj_coords, &layer_area, LV_ALIGN_CENTER, 0, 0);

    if(base_dsc->part == LV_PART_MAIN) {
        // Draw red background
        lv_draw_rect_dsc_t draw_background_dsc;
        lv_draw_rect_dsc_init(&draw_background_dsc);
        draw_background_dsc.bg_color = lv_color_hex(0xFF0000);
        lv_draw_rect(layer, &draw_background_dsc, &layer_area);

        // Draw black rect into a new layer
        lv_layer_t * new_layer = lv_draw_layer_create(layer, LV_COLOR_FORMAT_ARGB8888, &layer_area);
        lv_draw_rect_dsc_t draw_yellow_rect_dsc;
        lv_draw_rect_dsc_init(&draw_yellow_rect_dsc);
        draw_yellow_rect_dsc.bg_color = lv_color_hex(0x000000);
        lv_draw_rect(new_layer, &draw_yellow_rect_dsc, &layer_area);

        // Apply rectangle mask with radius and keep_outside = 1
        lv_draw_mask_rect_dsc_t mask_dsc;
        lv_draw_mask_rect_dsc_init(&mask_dsc);
        mask_dsc.area = layer_area;
        mask_dsc.radius = LV_RADIUS_CIRCLE;
        mask_dsc.keep_outside = 1;
        lv_draw_mask_rect(new_layer, &mask_dsc);

        // Composite back
        lv_draw_image_dsc_t image_draw_dsc;
        lv_draw_image_dsc_init(&image_draw_dsc);
        image_draw_dsc.src = new_layer;
        lv_draw_layer(layer, &image_draw_dsc, &layer_area);
    }
}

void lv_example_event_draw(void)
{
    lv_obj_t * cont = lv_obj_create(lv_screen_active());
    lv_obj_set_size(cont, 200, 200);
    lv_obj_center(cont);
    lv_obj_add_event_cb(cont, event_cb_draw_mask, LV_EVENT_DRAW_TASK_ADDED, nullptr);
    lv_obj_add_flag(cont, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
}

:test_tube: Observed Behavior

Despite setting keep_outside = 1, the inside of the rectangle is preserved and the outside is cleared, which matches what I’d expect from keep_outside = 0.

:mag: Internal Code Observation

In the source code of lv_draw_sw_mask_rect(), this line appears:

lv_draw_sw_mask_radius_init(&param, &dsc->area, dsc->radius, false);

But shouldn’t the last invert parameter reflect dsc->keep_outside?
Changing it to:

lv_draw_sw_mask_radius_init(&param, &dsc->area, dsc->radius, dsc->keep_outside);

…produces the expected behavior.

Current result:
image

Expected result:
image