From 9c063d57c6f07c4ccde70480957e356861989d16 Mon Sep 17 00:00:00 2001 From: lixianjing Date: Fri, 5 Nov 2021 06:49:44 +0800 Subject: [PATCH] add vgcanvas_get_clip_rect --- 3rd/nanovg/base/nanovg.c | 30 +++++ 3rd/nanovg/base/nanovg.h | 15 ++- docs/changes.md | 3 + src/base/canvas.c | 172 +++++++++++------------- src/base/canvas.h | 13 ++ src/base/canvas_offline.inc | 3 +- src/base/ffr_draw_rounded_rect.inc | 6 +- src/base/lcd.h | 2 + src/base/vgcanvas.c | 28 ++-- src/base/vgcanvas.h | 32 ++++- src/base/widget_vtable.c | 5 +- src/base/wuxiaolin.inc | 11 +- src/ext_widgets/scroll_view/list_view.c | 3 +- src/ext_widgets/slide_menu/slide_menu.c | 7 +- src/lcd/lcd_mem_fragment.inc | 43 ++++++ src/lcd/lcd_vgcanvas.inc | 11 +- src/vgcanvas/vgcanvas_nanovg.inc | 22 ++- src/vgcanvas/vgcanvas_nanovg_plus.c | 1 - src/vgcanvas/vgcanvas_nanovg_plus.inc | 24 +++- 19 files changed, 294 insertions(+), 137 deletions(-) diff --git a/3rd/nanovg/base/nanovg.c b/3rd/nanovg/base/nanovg.c index c1570869c..ab7f507b6 100644 --- a/3rd/nanovg/base/nanovg.c +++ b/3rd/nanovg/base/nanovg.c @@ -1045,6 +1045,36 @@ static void nvg__isectRects(float* dst, dst[3] = nvg__maxf(0.0f, maxy - miny); } +int nvgGetCurrScissor(NVGcontext* ctx, float* x, float* y, float* w, float* h) +{ + NVGstate* state = nvg__getState(ctx); + float pxform[6], invxorm[6]; + float rect[4]; + float ex, ey, tex, tey; + + // If no previous scissor has been set, set the scissor as current scissor. + if (state->scissor.extent[0] < 0) { + *w = 0; + *h = 0; + return 0; + } + + // Transform the current scissor rect into current transform space. + // If there is difference in rotation, this will be approximation. + memcpy(pxform, state->scissor.xform, sizeof(float)*6); + ex = state->scissor.extent[0]; + ey = state->scissor.extent[1]; + nvgTransformInverse(invxorm, state->xform); + nvgTransformMultiply(pxform, invxorm); + tex = ex*nvg__absf(pxform[0]) + ey*nvg__absf(pxform[2]); + tey = ex*nvg__absf(pxform[1]) + ey*nvg__absf(pxform[3]); + + *x = pxform[4] - tex; + *y = pxform[5] - tey; + *w = tex * 2; + *h = tey * 2; + return 1; +} void nvgIntersectScissorForOtherRect(NVGcontext* ctx, float x, float y, float w, float h, float dx, float dy, float dw, float dh) { diff --git a/3rd/nanovg/base/nanovg.h b/3rd/nanovg/base/nanovg.h index 5f0c234d7..4ab569b61 100644 --- a/3rd/nanovg/base/nanovg.h +++ b/3rd/nanovg/base/nanovg.h @@ -457,13 +457,26 @@ void nvgIntersectScissor(NVGcontext* ctx, float x, float y, float w, float h); * @param {float_t} w 裁剪区宽度。 * @param {float_t} h 裁剪区高度。 * - * @return {ret_t} 返回RET_OK表示成功,否则表示失败。 */ void nvgIntersectScissor_ex(NVGcontext* ctx, float* x, float* y, float* w, float* h); // Reset and disables scissoring. void nvgResetScissor(NVGcontext* ctx); +/** + * @method nvgGetCurrScissor + * 获取当前裁剪区 + * + * @annotation ["scriptable"] + * @param {NVGcontext*} ctx nanovg的对象 + * @param {float_t*} x 裁剪区x坐标。 + * @param {float_t*} y 裁剪区y坐标。 + * @param {float_t*} w 裁剪区宽度。 + * @param {float_t*} h 裁剪区高度。 + * + * @return {int} 返回成功返回 1,失败返回 0。 + */ +int nvgGetCurrScissor(NVGcontext* ctx, float* x, float* y, float* w, float* h); /** * @method nvgIntersectScissorForOtherRect diff --git a/docs/changes.md b/docs/changes.md index 3af439b23..a77fb560a 100644 --- a/docs/changes.md +++ b/docs/changes.md @@ -1,5 +1,8 @@ # 最新动态 +2021/11/05 + * 增加了nanovg获取当前裁剪区的函数和增加矩形是否在裁剪区的函数以及统一修改相关判断是否在裁剪区的代码(感谢智明提供补丁) + 2021/11/03 * 增加 fs\_foreach\_file * 完善 demoui 界面(感谢兆坤提供补丁) diff --git a/src/base/canvas.c b/src/base/canvas.c index f40cbfc4e..0c93b1392 100644 --- a/src/base/canvas.c +++ b/src/base/canvas.c @@ -146,64 +146,30 @@ ret_t canvas_get_clip_rect(canvas_t* c, rect_t* r) { return RET_OK; } +bool_t canvas_is_rect_in_clip_rect(canvas_t* c, xy_t left, xy_t top, xy_t right, xy_t bottom) { + if (c->lcd->is_rect_in_clip_rect != NULL) { + return c->lcd->is_rect_in_clip_rect(c->lcd, left, top, right, bottom); + } else { + if (left > c->clip_right || right < c->clip_left || top > c->clip_bottom || bottom < c->clip_top) { + return FALSE; + } + return TRUE; + } +} + ret_t canvas_set_clip_rect(canvas_t* c, const rect_t* r_in) { wh_t lcd_w = 0; wh_t lcd_h = 0; rect_t r_fix = rect_init(0, 0, 0, 0); rect_t* r = canvas_fix_rect(r_in, &r_fix); -#ifdef FRAGMENT_FRAME_BUFFER_SIZE - rect_t dirty_r; - lcd_get_dirty_rect(c->lcd, &dirty_r); -#endif - return_value_if_fail(c != NULL, RET_BAD_PARAMS); lcd_w = lcd_get_width(c->lcd); lcd_h = lcd_get_height(c->lcd); - if (r) { -#ifdef FRAGMENT_FRAME_BUFFER_SIZE - r_fix = rect_intersect(&r_fix, &dirty_r); -#endif - - c->clip_left = tk_max(0, r->x); - c->clip_top = tk_max(0, r->y); - c->clip_right = r->x + r->w - 1; - c->clip_bottom = r->y + r->h - 1; - } else { -#ifdef FRAGMENT_FRAME_BUFFER_SIZE - c->clip_left = tk_max(0, dirty_r.x); - c->clip_top = tk_max(0, dirty_r.y); - c->clip_right = dirty_r.x + dirty_r.w - 1; - c->clip_bottom = dirty_r.y + dirty_r.h - 1; -#else - c->clip_left = 0; - c->clip_top = 0; - c->clip_right = lcd_w - 1; - c->clip_bottom = lcd_h - 1; -#endif - } - - if (c->clip_left < 0) { - c->clip_left = 0; - } - - if (c->clip_top < 0) { - c->clip_top = 0; - } - - if (c->clip_right >= lcd_w) { - c->clip_right = lcd_w - 1; - } - - if (c->clip_bottom >= lcd_h) { - c->clip_bottom = lcd_h - 1; - } - if (c->lcd->set_clip_rect != NULL) { - /* 在 opengl 的状态下让 vg 来处理裁剪区的大小直接交给 vg 来处理,去除 LCD 的大小限制的问题 */ - if (r) { + if (r != NULL) { rect_t clip_r = rect_init(tk_max(0, r->x), tk_max(0, r->y), tk_max(0, r->w), tk_max(0, r->h)); lcd_set_clip_rect(c->lcd, &clip_r); } else { @@ -211,12 +177,25 @@ ret_t canvas_set_clip_rect(canvas_t* c, const rect_t* r_in) { lcd_set_clip_rect(c->lcd, &clip_r); } #ifdef WITH_GPU + /* 兼容以前的逻辑,以免以前的用户不使用 canvas_is_rect_in_clip_rect 来判断出问题 */ /* 把 canvas 的裁剪区设置为无限大,在 opengl 的状态下让 vg 来处理裁剪区的问题 */ c->clip_left = 0; c->clip_top = 0; c->clip_right = 0x7fffffff; c->clip_bottom = 0x7fffffff; #endif + } else { + if (r != NULL) { + c->clip_left = tk_max(0, r->x); + c->clip_top = tk_max(0, r->y); + c->clip_right = tk_min(lcd_w - 1, r->x + r->w - 1); + c->clip_bottom = tk_min(lcd_h - 1, r->y + r->h - 1); + } else { + c->clip_left = 0; + c->clip_top = 0; + c->clip_right = lcd_w - 1; + c->clip_bottom = lcd_h - 1; + } } return RET_OK; @@ -389,14 +368,16 @@ ret_t canvas_begin_frame(canvas_t* c, const dirty_rects_t* dirty_rects, lcd_draw } static ret_t canvas_draw_hline_impl(canvas_t* c, xy_t x, xy_t y, wh_t w) { + rect_t r; xy_t x2 = x + w - 1; - if (y < c->clip_top || y > c->clip_bottom || x2 < c->clip_left || x > c->clip_right) { + if (!canvas_is_rect_in_clip_rect(c, x, y, x2, y)) { return RET_OK; } + canvas_get_clip_rect(c, &r); - x = tk_max(x, c->clip_left); - x2 = tk_min(x2, c->clip_right); + x = tk_max(x, r.x); + x2 = tk_min(x2, r.x + r.w - 1); w = x2 - x + 1; return lcd_draw_hline(c->lcd, x, y, w); @@ -413,14 +394,16 @@ ret_t canvas_draw_hline(canvas_t* c, xy_t x, xy_t y, wh_t w) { } static ret_t canvas_draw_vline_impl(canvas_t* c, xy_t x, xy_t y, wh_t h) { + rect_t r; xy_t y2 = y + h - 1; - if (x < c->clip_left || x > c->clip_right || y2 < c->clip_top || y > c->clip_bottom) { + if (!canvas_is_rect_in_clip_rect(c, x, y, x, y2)) { return RET_OK; } + canvas_get_clip_rect(c, &r); - y = tk_max(y, c->clip_top); - y2 = tk_min(y2, c->clip_bottom); + y = tk_max(y, r.y); + y2 = tk_min(y2, r.y + r.h - 1); h = y2 - y + 1; return lcd_draw_vline(c->lcd, x, y, h); @@ -438,11 +421,6 @@ ret_t canvas_draw_vline(canvas_t* c, xy_t x, xy_t y, wh_t h) { } static ret_t canvas_draw_line_impl(canvas_t* c, xy_t x1, xy_t y1, xy_t x2, xy_t y2) { - if ((x1 < c->clip_left && x2 < c->clip_left) || (x1 > c->clip_right && x2 > c->clip_right) || - (y1 < c->clip_top && y2 < c->clip_top) || (y1 > c->clip_bottom && y2 > c->clip_bottom)) { - return RET_OK; - } - if (x1 == x2) { return canvas_draw_vline_impl(c, x1, y1, tk_abs(y2 - y1) + 1); } else if (y1 == y2) { @@ -464,22 +442,20 @@ ret_t canvas_draw_line(canvas_t* c, xy_t x1, xy_t y1, xy_t x2, xy_t y2) { static ret_t canvas_do_draw_points(canvas_t* c, const point_t* points, uint32_t nr) { uint32_t i = 0; uint32_t real_nr = 0; - xy_t left = c->clip_left; - xy_t top = c->clip_top; - xy_t right = c->clip_right; - xy_t bottom = c->clip_bottom; point_t real_points[MAX_POINTS_PER_DRAW]; return_value_if_fail(nr <= MAX_POINTS_PER_DRAW, RET_BAD_PARAMS); for (i = 0; i < nr; i++) { const point_t* p = points + i; - if (p->x < left || p->x > right || p->y < top || p->y > bottom) { + xy_t x = p->x + c->ox; + xy_t y = p->y + c->oy; + if (!canvas_is_rect_in_clip_rect(c, x, y, x, y)) { continue; } - real_points[real_nr].x = p->x + c->ox; - real_points[real_nr].y = p->y + c->oy; + real_points[real_nr].x = x; + real_points[real_nr].y = y; real_nr++; } @@ -512,17 +488,19 @@ ret_t canvas_draw_points(canvas_t* c, const point_t* points, uint32_t nr) { } static ret_t canvas_fill_rect_impl(canvas_t* c, xy_t x, xy_t y, wh_t w, wh_t h) { + rect_t r; xy_t x2 = x + w - 1; xy_t y2 = y + h - 1; - if (x > c->clip_right || x2 < c->clip_left || y > c->clip_bottom || y2 < c->clip_top) { + if (!canvas_is_rect_in_clip_rect(c, x, y, x2, y2)) { return RET_OK; } + canvas_get_clip_rect(c, &r); - x = tk_max(x, c->clip_left); - y = tk_max(y, c->clip_top); - x2 = tk_min(x2, c->clip_right); - y2 = tk_min(y2, c->clip_bottom); + x = tk_max(x, r.x); + y = tk_max(y, r.y); + x2 = tk_min(x2, r.x + r.w - 1); + y2 = tk_min(y2, r.y + r.h - 1); w = x2 - x + 1; h = y2 - y + 1; @@ -538,18 +516,21 @@ ret_t canvas_fill_rect(canvas_t* c, xy_t x, xy_t y, wh_t w, wh_t h) { static ret_t canvas_fill_rect_gradient_impl(canvas_t* c, xy_t x, xy_t y, wh_t w, wh_t h, gradient_t* gradient) { + rect_t r; xy_t x2 = x + w - 1; xy_t y2 = y + h - 1; vgcanvas_t* vg = NULL; - if (x > c->clip_right || x2 < c->clip_left || y > c->clip_bottom || y2 < c->clip_top) { + if (!canvas_is_rect_in_clip_rect(c, x, y, x2, y2)) { return RET_OK; } - x = tk_max(x, c->clip_left); - y = tk_max(y, c->clip_top); - x2 = tk_min(x2, c->clip_right); - y2 = tk_min(y2, c->clip_bottom); + canvas_get_clip_rect(c, &r); + + x = tk_max(x, r.x); + y = tk_max(y, r.y); + x2 = tk_min(x2, r.x + r.w - 1); + y2 = tk_min(y2, r.y + r.h - 1); w = x2 - x + 1; h = y2 - y + 1; if (w == 0 || h == 0) { @@ -596,17 +577,20 @@ ret_t canvas_fill_rect_gradient(canvas_t* c, xy_t x, xy_t y, wh_t w, wh_t h, gra } static ret_t canvas_clear_rect_impl(canvas_t* c, xy_t x, xy_t y, wh_t w, wh_t h) { + rect_t r; xy_t x2 = x + w - 1; xy_t y2 = y + h - 1; - if (x > c->clip_right || x2 < c->clip_left || y > c->clip_bottom || y2 < c->clip_top) { + if (!canvas_is_rect_in_clip_rect(c, x, y, x2, y2)) { return RET_OK; } - x = tk_max(x, c->clip_left); - y = tk_max(y, c->clip_top); - x2 = tk_min(x2, c->clip_right); - y2 = tk_min(y2, c->clip_bottom); + canvas_get_clip_rect(c, &r); + + x = tk_max(x, r.x); + y = tk_max(y, r.y); + x2 = tk_min(x2, r.x + r.w - 1); + y2 = tk_min(y2, r.y + r.h - 1); w = x2 - x + 1; h = y2 - y + 1; @@ -643,20 +627,21 @@ ret_t canvas_stroke_rect(canvas_t* c, xy_t x, xy_t y, wh_t w, wh_t h) { } static ret_t canvas_draw_glyph(canvas_t* c, glyph_t* g, xy_t x, xy_t y) { + rect_t r; rect_t src; rect_t dst; xy_t x2 = x + g->w - 1; xy_t y2 = y + g->h - 1; - if (g->data == NULL || x > c->clip_right || x2 < c->clip_left || y > c->clip_bottom || - y2 < c->clip_top) { + if (g->data == NULL || !canvas_is_rect_in_clip_rect(c, x, y, x2, y2)) { return RET_OK; } + canvas_get_clip_rect(c, &r); - dst.x = tk_max(x, c->clip_left); - dst.y = tk_max(y, c->clip_top); - dst.w = tk_min(x2, c->clip_right) - dst.x + 1; - dst.h = tk_min(y2, c->clip_bottom) - dst.y + 1; + dst.x = tk_max(x, r.x); + dst.y = tk_max(y, r.y); + dst.w = tk_min(x2, r.x + r.w - 1) - dst.x + 1; + dst.h = tk_min(y2, r.y + r.h - 1) - dst.y + 1; src.x = dst.x - x; src.y = dst.y - y; @@ -752,6 +737,7 @@ ret_t canvas_draw_utf8(canvas_t* c, const char* str, xy_t x, xy_t y) { } static ret_t canvas_do_draw_image(canvas_t* c, bitmap_t* img, const rect_t* s, const rect_t* d) { + rect_t r; rectf_t src; rectf_t dst; float_t scale_w = 0; @@ -762,15 +748,16 @@ static ret_t canvas_do_draw_image(canvas_t* c, bitmap_t* img, const rect_t* s, c xy_t x2 = d->x + d->w - 1; xy_t y2 = d->y + d->h - 1; - if (d->w <= 0 || d->h <= 0 || s->w <= 0 || s->h <= 0 || x > c->clip_right || x2 < c->clip_left || - y > c->clip_bottom || y2 < c->clip_top) { + if (d->w <= 0 || d->h <= 0 || s->w <= 0 || s->h <= 0 || + !canvas_is_rect_in_clip_rect(c, x, y, x2, y2)) { return RET_OK; } + canvas_get_clip_rect(c, &r); - dst.x = tk_max(x, c->clip_left); - dst.y = tk_max(y, c->clip_top); - dst.w = tk_min(x2, c->clip_right) - dst.x + 1; - dst.h = tk_min(y2, c->clip_bottom) - dst.y + 1; + dst.x = tk_max(x, r.x); + dst.y = tk_max(y, r.y); + dst.w = tk_min(x2, r.x + r.w - 1) - dst.x + 1; + dst.h = tk_min(y2, r.y + r.h - 1) - dst.y + 1; /* 因为 blend 函数中缩放,使用 256 倍的定点数,所以这里为了减低多次转换数据出现误差 */ scale_w = ((s->w << 8) / d->w / 256.0f); @@ -1611,8 +1598,7 @@ ret_t canvas_draw_image_matrix(canvas_t* c, bitmap_t* img, matrix_t* matrix) { info.matrix = *matrix; info.src = rect_init(0, 0, img->w, img->h); info.dst = rect_init(0, 0, img->w, img->h); - info.clip = rect_init(c->clip_left, c->clip_top, c->clip_right - c->clip_left, - c->clip_bottom - c->clip_top); + canvas_get_clip_rect(c, &info.clip); return lcd_draw_image_matrix(c->lcd, &info); } diff --git a/src/base/canvas.h b/src/base/canvas.h index ebcc6d1f4..61b82b5e5 100644 --- a/src/base/canvas.h +++ b/src/base/canvas.h @@ -215,6 +215,19 @@ wh_t canvas_get_height(canvas_t* c); */ ret_t canvas_get_clip_rect(canvas_t* c, rect_t* r); +/** + * @method canvas_is_rect_in_clip_rect + * 判断改矩形区域是否在裁剪区中 + * @param {canvas_t*} c canvas对象。 + * @param {xy_t} left 矩形区域左边。 + * @param {xy_t} top 矩形区域上边。 + * @param {xy_t} right 矩形区域右边。 + * @param {xy_t} bottom 矩形区域下边。 + * + * @return {ret_t} 返回RET_OK表示成功,否则表示失败。 + */ +bool_t canvas_is_rect_in_clip_rect(canvas_t* c, xy_t left, xy_t top, xy_t right, xy_t bottom); + /** * @method canvas_set_clip_rect * 设置裁剪区。 diff --git a/src/base/canvas_offline.inc b/src/base/canvas_offline.inc index ffab67711..7ac13f10e 100644 --- a/src/base/canvas_offline.inc +++ b/src/base/canvas_offline.inc @@ -273,8 +273,7 @@ ret_t canvas_offline_begin_draw(canvas_t* canvas) { c = (canvas_offline_gpu_t*)canvas; if (vg != NULL && canvas_offline->begin_draw == 0) { canvas_get_clip_rect(canvas, &canvas_offline->canvas_clip_rect); - canvas_offline->vg_clip_rect = - rect_init(vg->clip_rect.x, vg->clip_rect.y, vg->clip_rect.w, vg->clip_rect.h); + canvas_offline->vg_clip_rect = rect_from_rectf(vgcanvas_get_clip_rect(vg)); c->base.lcd_w = canvas->lcd->w; c->base.lcd_h = canvas->lcd->h; diff --git a/src/base/ffr_draw_rounded_rect.inc b/src/base/ffr_draw_rounded_rect.inc index a3a21af89..01e644364 100644 --- a/src/base/ffr_draw_rounded_rect.inc +++ b/src/base/ffr_draw_rounded_rect.inc @@ -1062,8 +1062,7 @@ static ret_t ffr_draw_fill_rounded_rect_ex(canvas_t* c, const rect_t* r, const r xy_t y2 = y + r->h - 1; return_value_if_fail(c != NULL && r != NULL && gradient != NULL, RET_BAD_PARAMS); - if (x > c->clip_right || x2 < c->clip_left || - y > c->clip_bottom || y2 < c->clip_top) { + if (!canvas_is_rect_in_clip_rect(c, x, y, x2, y2)) { return RET_OK; } @@ -1092,8 +1091,7 @@ static ret_t ffr_draw_stroke_rounded_rect_ex(canvas_t* c, const rect_t* r, const xy_t y2 = y + r->h - 1; return_value_if_fail(c != NULL && r != NULL && color != NULL, RET_BAD_PARAMS); tc = *color; - if (x > c->clip_right || x2 < c->clip_left || - y > c->clip_bottom || y2 < c->clip_top || border_model == BORDER_NONE) { + if (!canvas_is_rect_in_clip_rect(c, x, y, x2, y2) || border_model == BORDER_NONE) { return RET_OK; } diff --git a/src/base/lcd.h b/src/base/lcd.h index 836277edc..7ad1eb19d 100644 --- a/src/base/lcd.h +++ b/src/base/lcd.h @@ -49,6 +49,7 @@ typedef ret_t (*lcd_get_dirty_rect_t)(lcd_t* lcd, rect_t* r); typedef const dirty_rects_t* (*lcd_get_dirty_rects_t)(lcd_t* lcd); typedef ret_t (*lcd_begin_frame_t)(lcd_t* lcd, const dirty_rects_t* dirty_rects); +typedef bool_t(*lcd_is_rect_in_clip_rect_t)(lcd_t* lcd, xy_t left, xy_t top, xy_t right, xy_t bottom); typedef ret_t (*lcd_set_clip_rect_t)(lcd_t* lcd, const rect_t* rect); typedef ret_t (*lcd_get_clip_rect_t)(lcd_t* lcd, rect_t* rect); typedef ret_t (*lcd_set_orientation_t)(lcd_t* lcd, lcd_orientation_t old_orientation, @@ -180,6 +181,7 @@ struct _lcd_t { lcd_begin_frame_t begin_frame; lcd_set_clip_rect_t set_clip_rect; lcd_get_clip_rect_t get_clip_rect; + lcd_is_rect_in_clip_rect_t is_rect_in_clip_rect; lcd_set_global_alpha_t set_global_alpha; lcd_set_text_color_t set_text_color; lcd_set_stroke_color_t set_stroke_color; diff --git a/src/base/vgcanvas.c b/src/base/vgcanvas.c index 300175f96..68d94f230 100644 --- a/src/base/vgcanvas.c +++ b/src/base/vgcanvas.c @@ -101,32 +101,28 @@ ret_t vgcanvas_clip_path(vgcanvas_t* vg) { return vg->vt->clip_path(vg); } +bool_t vgcanvas_is_rectf_int_clip_rect(vgcanvas_t* vg, float_t left, float_t top, float_t right, float_t bottom) { + return_value_if_fail(vg != NULL && vg->vt->is_rectf_int_clip_rect != NULL, FALSE); + + return vg->vt->is_rectf_int_clip_rect(vg, left, top, right, bottom); +} + +const rectf_t* vgcanvas_get_clip_rect(vgcanvas_t* vg) { + return_value_if_fail(vg != NULL && vg->vt->get_clip_rect != NULL, NULL); + return vg->vt->get_clip_rect(vg); +} + ret_t vgcanvas_clip_rect(vgcanvas_t* vg, float_t x, float_t y, float_t w, float_t h) { return_value_if_fail(vg != NULL && vg->vt->clip_rect != NULL, RET_BAD_PARAMS); - fix_xywh(x, y, w, h); - vg->clip_rect.x = x; - vg->clip_rect.y = y; - vg->clip_rect.w = w; - vg->clip_rect.h = h; - return vg->vt->clip_rect(vg, x, y, w, h); } ret_t vgcanvas_intersect_clip_rect(vgcanvas_t* vg, float_t x, float_t y, float_t w, float_t h) { - ret_t ret = RET_OK; return_value_if_fail(vg != NULL && vg->vt->intersect_clip_rect != NULL, RET_BAD_PARAMS); fix_xywh(x, y, w, h); - - ret = vg->vt->intersect_clip_rect(vg, &x, &y, &w, &h); - - vg->clip_rect.x = x; - vg->clip_rect.y = y; - vg->clip_rect.w = w; - vg->clip_rect.h = h; - - return ret; + return vg->vt->intersect_clip_rect(vg, &x, &y, &w, &h); } ret_t vgcanvas_fill(vgcanvas_t* vg) { diff --git a/src/base/vgcanvas.h b/src/base/vgcanvas.h index 7a6b080b9..719a1cd3e 100644 --- a/src/base/vgcanvas.h +++ b/src/base/vgcanvas.h @@ -85,6 +85,8 @@ typedef ret_t (*vgcanvas_set_transform_t)(vgcanvas_t* vg, float_t a, float_t b, float_t d, float_t e, float_t f); typedef ret_t (*vgcanvas_clip_path_t)(vgcanvas_t* vg); +typedef const rectf_t* (*vgcanvas_get_clip_rect_t)(vgcanvas_t* vg); +typedef bool_t(*vgcanvas_is_rectf_int_clip_rect_t)(vgcanvas_t* vg, float_t left, float_t top, float_t right, float_t bottom); typedef ret_t (*vgcanvas_clip_rect_t)(vgcanvas_t* vg, float_t x, float_t y, float_t w, float_t h); typedef ret_t (*vgcanvas_nanovg_intersect_clip_rect_t)(vgcanvas_t* vg, float_t* x, float_t* y, float_t* w, float_t* h); @@ -185,6 +187,8 @@ typedef struct _vgcanvas_vtable_t { vgcanvas_clip_path_t clip_path; vgcanvas_clip_rect_t clip_rect; + vgcanvas_get_clip_rect_t get_clip_rect; + vgcanvas_is_rectf_int_clip_rect_t is_rectf_int_clip_rect; vgcanvas_nanovg_intersect_clip_rect_t intersect_clip_rect; vgcanvas_fill_t fill; vgcanvas_stroke_t stroke; @@ -398,7 +402,7 @@ struct _vgcanvas_t { * frame buffer format */ bitmap_format_t format; - rect_t clip_rect; + rectf_t clip_rect; rect_t dirty_rect; const vgcanvas_vtable_t* vt; assets_manager_t* assets_manager; @@ -792,6 +796,32 @@ ret_t vgcanvas_clip_path(vgcanvas_t* vg); */ ret_t vgcanvas_clip_rect(vgcanvas_t* vg, float_t x, float_t y, float_t w, float_t h); +/** + * @method vgcanvas_get_clip_rect + * 获取矩形裁剪。 + * + * @annotation ["scriptable"] + * @param {vgcanvas_t*} vg vgcanvas对象。 + * + * @return {const rectf_t*} 返回裁剪区。 + */ +const rectf_t* vgcanvas_get_clip_rect(vgcanvas_t* vg); + +/** + * @method vgcanvas_is_rectf_int_clip_rect + * 矩形区域是否在矩形裁剪中。 + * + * @annotation ["scriptable"] + * @param {vgcanvas_t*} vg vgcanvas对象。 + * @param {float_t} left 矩形区域左边。 + * @param {float_t} top 矩形区域上边。 + * @param {float_t} right 矩形区域右边。 + * @param {float_t} bottom 矩形区域下边。 + * + * @return {bool_t} 返回 TURE 则在区域中,返回 FALSE 则不在区域中。 + */ +bool_t vgcanvas_is_rectf_int_clip_rect(vgcanvas_t* vg, float_t left, float_t top, float_t right, float_t bottom); + /** * @method vgcanvas_intersect_clip_rect * 设置一个与前一个裁剪区做交集的矩形裁剪区。 diff --git a/src/base/widget_vtable.c b/src/base/widget_vtable.c index 5db30db12..c435f1969 100644 --- a/src/base/widget_vtable.c +++ b/src/base/widget_vtable.c @@ -114,8 +114,7 @@ ret_t widget_on_paint_children_default(widget_t* widget, canvas_t* c) { int32_t bottom = top + iter->h + 2 * tolerance; int32_t right = left + iter->w + 2 * tolerance; - if (left > c->clip_right || right < c->clip_left || top > c->clip_bottom || - bottom < c->clip_top) { + if (!canvas_is_rect_in_clip_rect(c, left, top, right, bottom)) { iter->dirty = FALSE; continue; } @@ -248,7 +247,7 @@ ret_t widget_paint_with_clip(widget_t* widget, rect_t* clip, canvas_t* c, canvas_get_clip_rect(c, &r_save); if (vg != NULL) { vgcanvas_save(vg); - r_vg_save = rect_init(vg->clip_rect.x, vg->clip_rect.y, vg->clip_rect.w, vg->clip_rect.h); + r_vg_save = rect_from_rectf(vgcanvas_get_clip_rect(vg)); } if (clip != NULL) { diff --git a/src/base/wuxiaolin.inc b/src/base/wuxiaolin.inc index 590bb511d..24169421b 100644 --- a/src/base/wuxiaolin.inc +++ b/src/base/wuxiaolin.inc @@ -24,15 +24,18 @@ } while (0) void draw_line(canvas_t* c, int x1, int y1, int x2, int y2) { + rect_t r; point_t p; lcd_t* lcd = c->lcd; - xy_t xmin = c->clip_left; - xy_t xmax = c->clip_right; - xy_t ymin = c->clip_top; - xy_t ymax = c->clip_bottom; + xy_t xmin, xmax, ymin, ymax; color_t* color = &(c->lcd->stroke_color); double dx = (double)x2 - (double)x1; double dy = (double)y2 - (double)y1; + canvas_get_clip_rect(c, &r); + xmin = r.x; + xmax = r.x + r.w - 1; + ymin = r.y; + ymax = r.y + r.h - 1; if (fabs(dx) > fabs(dy)) { if (x2 < x1) { diff --git a/src/ext_widgets/scroll_view/list_view.c b/src/ext_widgets/scroll_view/list_view.c index da1095897..fc80866d9 100644 --- a/src/ext_widgets/scroll_view/list_view.c +++ b/src/ext_widgets/scroll_view/list_view.c @@ -328,8 +328,7 @@ static ret_t list_view_on_scroll_view_paint_children(widget_t* widget, canvas_t* continue; } - if (left > c->clip_right || right < c->clip_left || top > c->clip_bottom || - bottom < c->clip_top) { + if (!canvas_is_rect_in_clip_rect(c, left, top, right, bottom)) { iter->dirty = FALSE; continue; } diff --git a/src/ext_widgets/slide_menu/slide_menu.c b/src/ext_widgets/slide_menu/slide_menu.c index 60caa76ec..393d6f7fb 100644 --- a/src/ext_widgets/slide_menu/slide_menu.c +++ b/src/ext_widgets/slide_menu/slide_menu.c @@ -124,11 +124,16 @@ static rect_t slide_menu_get_clip_r(widget_t* widget) { } static ret_t slide_menu_paint_children(widget_t* widget, canvas_t* c) { + rect_t r; + xy_t clip_right, clip_left; + canvas_get_clip_rect(c, &r); + clip_left = r.x; + clip_right = r.x + r.w - 1; WIDGET_FOR_EACH_CHILD_BEGIN(widget, iter, i) int32_t left = c->ox + iter->x; int32_t right = left + iter->w; - if (left >= (c->clip_right - 1) || right <= (c->clip_left + 1)) { + if (left >= (clip_right - 1) || right <= (clip_left + 1)) { iter->dirty = FALSE; continue; } diff --git a/src/lcd/lcd_mem_fragment.inc b/src/lcd/lcd_mem_fragment.inc index ed57aebba..a40fcfb40 100644 --- a/src/lcd/lcd_mem_fragment.inc +++ b/src/lcd/lcd_mem_fragment.inc @@ -35,6 +35,9 @@ typedef struct _lcd_mem_fragment_t { xy_t y; wh_t w; wh_t h; + + rect_t dirty_rect; + bitmap_t fb; graphic_buffer_t* gb; pixel_t buff[FRAGMENT_FRAME_BUFFER_SIZE]; @@ -302,12 +305,52 @@ uint8_t* lcd_mem_fragment_get_buff(lcd_t* lcd) { return (uint8_t*)mem->buff; } +static ret_t lcd_mem_fragment_set_clip_rect(lcd_t* lcd, const rect_t* r) { + rect_t dirty_r; + rect_t r_fix = rect_init(0, 0, 0, 0); + lcd_mem_fragment_t* mem = (lcd_mem_fragment_t*)lcd; + return_value_if_fail(mem != NULL && r != NULL, RET_BAD_PARAMS); + lcd_get_dirty_rect(lcd, &dirty_r); + mem->dirty_rect = rect_intersect(r, &dirty_r); + + return RET_OK; +} + +static bool_t lcd_mem_fragment_is_rect_in_clip_rect(lcd_t* lcd, xy_t left, xy_t top, xy_t right, xy_t bottom) { + lcd_mem_fragment_t* mem = (lcd_mem_fragment_t*)lcd; + xy_t clip_left, clip_top, clip_right, clip_bottom; + return_value_if_fail(mem != NULL, FALSE); + clip_left = mem->dirty_rect.x; + clip_top = mem->dirty_rect.y; + clip_right = mem->dirty_rect.x + mem->dirty_rect.w - 1; + clip_bottom = mem->dirty_rect.y + mem->dirty_rect.h - 1; + + if (left > clip_right || right < clip_left || top > clip_bottom || bottom < clip_top) { + return FALSE; + } + return TRUE; +} + +static ret_t lcd_mem_fragment_get_clip_rect(lcd_t* lcd, rect_t* rect) { + lcd_mem_fragment_t* mem = (lcd_mem_fragment_t*)lcd; + return_value_if_fail(mem != NULL, RET_BAD_PARAMS); + rect->x = mem->dirty_rect.x; + rect->y = mem->dirty_rect.y; + rect->w = mem->dirty_rect.w; + rect->h = mem->dirty_rect.h; + + return RET_OK; +} + lcd_t* lcd_mem_fragment_create(wh_t w, wh_t h) { lcd_mem_fragment_t* mem = &s_lcd_mem_fragment; lcd_t* base = (lcd_t*)mem; system_info_t* info = system_info(); base->begin_frame = lcd_mem_fragment_begin_frame; + base->set_clip_rect = lcd_mem_fragment_set_clip_rect; + base->get_clip_rect = lcd_mem_fragment_get_clip_rect; + base->is_rect_in_clip_rect = lcd_mem_fragment_is_rect_in_clip_rect; base->draw_vline = lcd_mem_fragment_draw_vline; base->draw_hline = lcd_mem_fragment_draw_hline; base->fill_rect = lcd_mem_fragment_fill_rect; diff --git a/src/lcd/lcd_vgcanvas.inc b/src/lcd/lcd_vgcanvas.inc index 21e8f27a6..32850aaa5 100644 --- a/src/lcd/lcd_vgcanvas.inc +++ b/src/lcd/lcd_vgcanvas.inc @@ -70,10 +70,14 @@ static ret_t lcd_vgcanvas_set_clip_rect(lcd_t* lcd, const rect_t* r) { return vgcanvas_clip_rect(LCD(lcd)->canvas, r->x, r->y, r->w, r->h); } +static bool_t lcd_vgcanvas_is_rect_in_clip_rect(lcd_t* lcd, xy_t left, xy_t top, xy_t right, xy_t bottom) { + vgcanvas_t* canvas = LCD(lcd)->canvas; + return vgcanvas_is_rectf_int_clip_rect(canvas, (float_t)left, (float_t)top, (float_t)right, (float_t)bottom); +} + static ret_t lcd_vgcanvas_get_clip_rect(lcd_t* lcd, rect_t* r) { vgcanvas_t* canvas = LCD(lcd)->canvas; - *r = canvas->clip_rect; - + *r = rect_from_rectf(vgcanvas_get_clip_rect(canvas)); return RET_OK; } @@ -321,6 +325,7 @@ lcd_t* lcd_vgcanvas_init(wh_t w, wh_t h, vgcanvas_t* canvas) { base->begin_frame = lcd_vgcanvas_begin_frame; base->set_clip_rect = lcd_vgcanvas_set_clip_rect; base->get_clip_rect = lcd_vgcanvas_get_clip_rect; + base->is_rect_in_clip_rect = lcd_vgcanvas_is_rect_in_clip_rect; base->draw_vline = lcd_vgcanvas_draw_vline; base->draw_hline = lcd_vgcanvas_draw_hline; base->fill_rect = lcd_vgcanvas_fill_rect; @@ -361,6 +366,6 @@ lcd_t* lcd_vgcanvas_init(wh_t w, wh_t h, vgcanvas_t* canvas) { str_init(&(lcd->temp_text), 100); lcd->canvas = canvas; - + return base; } diff --git a/src/vgcanvas/vgcanvas_nanovg.inc b/src/vgcanvas/vgcanvas_nanovg.inc index b94b76ca8..3ff3a12fa 100644 --- a/src/vgcanvas/vgcanvas_nanovg.inc +++ b/src/vgcanvas/vgcanvas_nanovg.inc @@ -256,7 +256,7 @@ static ret_t vgcanvas_nanovg_intersect_clip_rect(vgcanvas_t* vgcanvas, float_t* NVGcontext* vg = ((vgcanvas_nanovg_t*)vgcanvas)->vg; nvgIntersectScissor_ex(vg, x, y, w, h); - + nvgGetCurrScissor(vg, &vgcanvas->clip_rect.x, &vgcanvas->clip_rect.y, &vgcanvas->clip_rect.w, &vgcanvas->clip_rect.h); return RET_OK; } @@ -331,10 +331,26 @@ static ret_t vgcanvas_nanovg_clip_rect(vgcanvas_t* vgcanvas, float_t x, float_t #else nvgScissor(vg, x, y, w, h); #endif - + nvgGetCurrScissor(vg, &vgcanvas->clip_rect.x, &vgcanvas->clip_rect.y, &vgcanvas->clip_rect.w, &vgcanvas->clip_rect.h); return RET_OK; } +static bool_t vgcanvas_nanovg_is_rectf_int_clip_rect(vgcanvas_t* vgcanvas, float_t left, float_t top, float_t right, float_t bottom) { + float_t clip_left = vgcanvas->clip_rect.x; + float_t clip_right = vgcanvas->clip_rect.x + vgcanvas->clip_rect.w; + float_t clip_top = vgcanvas->clip_rect.y; + float_t clip_bottom = vgcanvas->clip_rect.y + vgcanvas->clip_rect.h; + if (left > clip_right || right < clip_left || top > clip_bottom || bottom < clip_top) { + return FALSE; + } + return TRUE; +} + + +const rectf_t* vgcanvas_nanovg_get_clip_rect(vgcanvas_t* vgcanvas) { + return &(vgcanvas->clip_rect); +} + static ret_t vgcanvas_nanovg_fill(vgcanvas_t* vgcanvas) { NVGcontext* vg = ((vgcanvas_nanovg_t*)vgcanvas)->vg; @@ -717,6 +733,8 @@ static const vgcanvas_vtable_t vt = { .transform = vgcanvas_nanovg_transform, .set_transform = vgcanvas_nanovg_set_transform, .clip_rect = vgcanvas_nanovg_clip_rect, + .get_clip_rect = vgcanvas_nanovg_get_clip_rect, + .is_rectf_int_clip_rect = vgcanvas_nanovg_is_rectf_int_clip_rect, .intersect_clip_rect = vgcanvas_nanovg_intersect_clip_rect, .path_winding = vgcanvas_nanovg_path_winding, .fill = vgcanvas_nanovg_fill, diff --git a/src/vgcanvas/vgcanvas_nanovg_plus.c b/src/vgcanvas/vgcanvas_nanovg_plus.c index cca16ac19..f0a84b06f 100644 --- a/src/vgcanvas/vgcanvas_nanovg_plus.c +++ b/src/vgcanvas/vgcanvas_nanovg_plus.c @@ -13,7 +13,6 @@ typedef struct _vgcanvas_nanovg_plus_t { vgcanvas_t base; int font_id; - char font_name[TK_NAME_LEN]; nvgp_context_t* vg; uint32_t text_align_v; uint32_t text_align_h; diff --git a/src/vgcanvas/vgcanvas_nanovg_plus.inc b/src/vgcanvas/vgcanvas_nanovg_plus.inc index 2462bb9fb..b0754d2d9 100644 --- a/src/vgcanvas/vgcanvas_nanovg_plus.inc +++ b/src/vgcanvas/vgcanvas_nanovg_plus.inc @@ -256,17 +256,35 @@ static ret_t vgcanvas_nanovg_plus_intersect_clip_rect(vgcanvas_t* vgcanvas, floa nvgp_context_t* vg = ((vgcanvas_nanovg_plus_t*)vgcanvas)->vg; nvgp_intersect_scissor(vg, x, y, w, h); + nvgp_get_curr_clip_rect(vg, &vgcanvas->clip_rect.x, &vgcanvas->clip_rect.y, &vgcanvas->clip_rect.w, &vgcanvas->clip_rect.h); return RET_OK; } +static bool_t vgcanvas_nanovg_plus_is_rectf_int_clip_rect(vgcanvas_t* vgcanvas, float_t left, float_t top, float_t right, float_t bottom) { + vgcanvas_nanovg_plus_t* canvas = (vgcanvas_nanovg_plus_t*)vgcanvas; + float_t clip_left = vgcanvas->clip_rect.x; + float_t clip_right = vgcanvas->clip_rect.x + vgcanvas->clip_rect.w; + float_t clip_top = vgcanvas->clip_rect.y; + float_t clip_bottom = vgcanvas->clip_rect.y + vgcanvas->clip_rect.h; + if (left > clip_right || right < clip_left || top > clip_bottom || bottom < clip_top) { + return FALSE; + } + return TRUE; +} + static ret_t vgcanvas_nanovg_plus_clip_rect(vgcanvas_t* vgcanvas, float_t x, float_t y, float_t w, float_t h) { nvgp_context_t* vg = ((vgcanvas_nanovg_plus_t*)vgcanvas)->vg; nvgp_scissor(vg, x, y, w, h); + nvgp_get_curr_clip_rect(vg, &vgcanvas->clip_rect.x, &vgcanvas->clip_rect.y, &vgcanvas->clip_rect.w, &vgcanvas->clip_rect.h); return RET_OK; } +const rectf_t* vgcanvas_nanovg_plus_get_clip_rect(vgcanvas_t* vgcanvas) { + return &(vgcanvas->clip_rect); +} + static ret_t vgcanvas_nanovg_plus_fill(vgcanvas_t* vgcanvas) { nvgp_context_t* vg = ((vgcanvas_nanovg_plus_t*)vgcanvas)->vg; @@ -381,9 +399,6 @@ static ret_t vgcanvas_nanovg_plus_set_font(vgcanvas_t* vgcanvas, const char* nam nvgp_context_t* vg = ((vgcanvas_nanovg_plus_t*)vgcanvas)->vg; vgcanvas_nanovg_plus_t* canvas = (vgcanvas_nanovg_plus_t*)vgcanvas; return_value_if_fail(name && *name, RET_BAD_PARAMS); - if (tk_str_eq(canvas->font_name, name)) { - return RET_OK; - } font_id = tk_pointer_to_int(vgcanvas_asset_manager_get_font_ctx(vgcanvas_asset_manager(), vgcanvas, name, &reuslt)); @@ -420,7 +435,6 @@ static ret_t vgcanvas_nanovg_plus_set_font(vgcanvas_t* vgcanvas, const char* nam } canvas->font_id = font_id; - memcpy(canvas->font_name, name, sizeof(name)); nvgp_font_face_id(vg, font_id); return RET_OK; @@ -738,6 +752,8 @@ static const vgcanvas_vtable_t vt = { .transform = vgcanvas_nanovg_plus_transform, .set_transform = vgcanvas_nanovg_plus_set_transform, .clip_rect = vgcanvas_nanovg_plus_clip_rect, + .get_clip_rect = vgcanvas_nanovg_plus_get_clip_rect, + .is_rectf_int_clip_rect = vgcanvas_nanovg_plus_is_rectf_int_clip_rect, .intersect_clip_rect = vgcanvas_nanovg_plus_intersect_clip_rect, .path_winding = vgcanvas_nanovg_plus_path_winding, .fill = vgcanvas_nanovg_plus_fill,