acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

lv_canvas.c (27547B)

      1 /**
      2  * @file lv_canvas.c
      3  *
      4  */
      5 
      6 /*********************
      7  *      INCLUDES
      8  *********************/
      9 #include "lv_canvas.h"
     10 #include "../misc/lv_assert.h"
     11 #include "../misc/lv_math.h"
     12 #include "../draw/lv_draw.h"
     13 #include "../core/lv_refr.h"
     14 
     15 #if LV_USE_CANVAS != 0
     16 
     17 #include "../draw/sw/lv_draw_sw.h"
     18 
     19 /*********************
     20  *      DEFINES
     21  *********************/
     22 #define MY_CLASS &lv_canvas_class
     23 
     24 /**********************
     25  *      TYPEDEFS
     26  **********************/
     27 
     28 /**********************
     29  *  STATIC PROTOTYPES
     30  **********************/
     31 static void lv_canvas_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
     32 static void lv_canvas_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
     33 static void init_fake_disp(lv_obj_t * canvas, lv_disp_t * disp, lv_disp_drv_t * drv, lv_area_t * clip_area);
     34 static void deinit_fake_disp(lv_obj_t * canvas, lv_disp_t * disp);
     35 
     36 /**********************
     37  *  STATIC VARIABLES
     38  **********************/
     39 const lv_obj_class_t lv_canvas_class = {
     40     .constructor_cb = lv_canvas_constructor,
     41     .destructor_cb = lv_canvas_destructor,
     42     .instance_size = sizeof(lv_canvas_t),
     43     .base_class = &lv_img_class
     44 };
     45 
     46 /**********************
     47  *      MACROS
     48  **********************/
     49 
     50 /**********************
     51  *   GLOBAL FUNCTIONS
     52  **********************/
     53 
     54 lv_obj_t * lv_canvas_create(lv_obj_t * parent)
     55 {
     56     LV_LOG_INFO("begin");
     57     lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
     58     lv_obj_class_init_obj(obj);
     59     return obj;
     60 }
     61 
     62 /*=====================
     63  * Setter functions
     64  *====================*/
     65 
     66 void lv_canvas_set_buffer(lv_obj_t * obj, void * buf, lv_coord_t w, lv_coord_t h, lv_img_cf_t cf)
     67 {
     68     LV_ASSERT_OBJ(obj, MY_CLASS);
     69     LV_ASSERT_NULL(buf);
     70 
     71     lv_canvas_t * canvas = (lv_canvas_t *)obj;
     72 
     73     canvas->dsc.header.cf = cf;
     74     canvas->dsc.header.w  = w;
     75     canvas->dsc.header.h  = h;
     76     canvas->dsc.data      = buf;
     77 
     78     lv_img_set_src(obj, &canvas->dsc);
     79     lv_img_cache_invalidate_src(&canvas->dsc);
     80 }
     81 
     82 void lv_canvas_set_px_color(lv_obj_t * obj, lv_coord_t x, lv_coord_t y, lv_color_t c)
     83 {
     84     LV_ASSERT_OBJ(obj, MY_CLASS);
     85 
     86     lv_canvas_t * canvas = (lv_canvas_t *)obj;
     87 
     88     lv_img_buf_set_px_color(&canvas->dsc, x, y, c);
     89     lv_obj_invalidate(obj);
     90 }
     91 
     92 void lv_canvas_set_px_opa(lv_obj_t * obj, lv_coord_t x, lv_coord_t y, lv_opa_t opa)
     93 {
     94     LV_ASSERT_OBJ(obj, MY_CLASS);
     95 
     96     lv_canvas_t * canvas = (lv_canvas_t *)obj;
     97 
     98     lv_img_buf_set_px_alpha(&canvas->dsc, x, y, opa);
     99     lv_obj_invalidate(obj);
    100 }
    101 
    102 void lv_canvas_set_palette(lv_obj_t * obj, uint8_t id, lv_color_t c)
    103 {
    104     LV_ASSERT_OBJ(obj, MY_CLASS);
    105 
    106     lv_canvas_t * canvas = (lv_canvas_t *)obj;
    107 
    108     lv_img_buf_set_palette(&canvas->dsc, id, c);
    109     lv_obj_invalidate(obj);
    110 }
    111 
    112 /*=====================
    113  * Getter functions
    114  *====================*/
    115 
    116 lv_color_t lv_canvas_get_px(lv_obj_t * obj, lv_coord_t x, lv_coord_t y)
    117 {
    118     LV_ASSERT_OBJ(obj, MY_CLASS);
    119 
    120     lv_canvas_t * canvas = (lv_canvas_t *)obj;
    121     lv_color_t color = lv_obj_get_style_img_recolor(obj, LV_PART_MAIN);
    122 
    123     return lv_img_buf_get_px_color(&canvas->dsc, x, y, color);
    124 }
    125 
    126 lv_img_dsc_t * lv_canvas_get_img(lv_obj_t * obj)
    127 {
    128     LV_ASSERT_OBJ(obj, MY_CLASS);
    129 
    130     lv_canvas_t * canvas = (lv_canvas_t *)obj;
    131     return &canvas->dsc;
    132 }
    133 
    134 /*=====================
    135  * Other functions
    136  *====================*/
    137 
    138 void lv_canvas_copy_buf(lv_obj_t * obj, const void * to_copy, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h)
    139 {
    140     LV_ASSERT_OBJ(obj, MY_CLASS);
    141     LV_ASSERT_NULL(to_copy);
    142 
    143     lv_canvas_t * canvas = (lv_canvas_t *)obj;
    144 
    145     if(x + w - 1 >= (lv_coord_t)canvas->dsc.header.w || y + h - 1 >= (lv_coord_t)canvas->dsc.header.h) {
    146         LV_LOG_WARN("lv_canvas_copy_buf: x or y out of the canvas");
    147         return;
    148     }
    149 
    150     uint32_t px_size   = lv_img_cf_get_px_size(canvas->dsc.header.cf) >> 3;
    151     uint32_t px        = canvas->dsc.header.w * y * px_size + x * px_size;
    152     uint8_t * to_copy8 = (uint8_t *)to_copy;
    153     lv_coord_t i;
    154     for(i = 0; i < h; i++) {
    155         lv_memcpy((void *)&canvas->dsc.data[px], to_copy8, w * px_size);
    156         px += canvas->dsc.header.w * px_size;
    157         to_copy8 += w * px_size;
    158     }
    159 }
    160 
    161 void lv_canvas_transform(lv_obj_t * obj, lv_img_dsc_t * img, int16_t angle, uint16_t zoom, lv_coord_t offset_x,
    162                          lv_coord_t offset_y,
    163                          int32_t pivot_x, int32_t pivot_y, bool antialias)
    164 {
    165 #if LV_DRAW_COMPLEX
    166     LV_ASSERT_OBJ(obj, MY_CLASS);
    167     LV_ASSERT_NULL(img);
    168 
    169     lv_canvas_t * canvas = (lv_canvas_t *)obj;
    170     lv_color_t color = lv_obj_get_style_img_recolor(obj, LV_PART_MAIN);
    171 
    172     int32_t dest_width  = canvas->dsc.header.w;
    173     int32_t dest_height = canvas->dsc.header.h;
    174 
    175     int32_t x;
    176     int32_t y;
    177     bool ret;
    178 
    179     lv_img_transform_dsc_t dsc;
    180     dsc.cfg.angle = angle;
    181     dsc.cfg.zoom = zoom;
    182     dsc.cfg.src = img->data;
    183     dsc.cfg.src_w = img->header.w;
    184     dsc.cfg.src_h = img->header.h;
    185     dsc.cfg.cf = img->header.cf;
    186     dsc.cfg.pivot_x = pivot_x;
    187     dsc.cfg.pivot_y = pivot_y;
    188     dsc.cfg.color = color;
    189     dsc.cfg.antialias = antialias;
    190     _lv_img_buf_transform_init(&dsc);
    191 
    192     for(y = -offset_y; y < dest_height - offset_y; y++) {
    193         for(x = -offset_x; x < dest_width - offset_x; x++) {
    194 
    195             ret = _lv_img_buf_transform(&dsc, x, y);
    196 
    197             if(ret == false) continue;
    198 
    199             if(x + offset_x >= 0 && x + offset_x < dest_width && y + offset_y >= 0 && y + offset_y < dest_height) {
    200                 /*If the image has no alpha channel just simple set the result color on the canvas*/
    201                 if(lv_img_cf_has_alpha(img->header.cf) == false) {
    202                     lv_img_buf_set_px_color(&canvas->dsc, x + offset_x, y + offset_y, dsc.res.color);
    203                 }
    204                 else {
    205                     lv_color_t bg_color = lv_img_buf_get_px_color(&canvas->dsc, x + offset_x, y + offset_y, dsc.cfg.color);
    206 
    207                     /*If the canvas has no alpha but the image has mix the image's color with
    208                      * canvas*/
    209                     if(lv_img_cf_has_alpha(canvas->dsc.header.cf) == false) {
    210                         if(dsc.res.opa < LV_OPA_MAX) dsc.res.color = lv_color_mix(dsc.res.color, bg_color, dsc.res.opa);
    211                         lv_img_buf_set_px_color(&canvas->dsc, x + offset_x, y + offset_y, dsc.res.color);
    212                     }
    213                     /*Both the image and canvas has alpha channel. Some extra calculation is
    214                        required*/
    215                     else {
    216                         lv_opa_t bg_opa = lv_img_buf_get_px_alpha(&canvas->dsc, x + offset_x, y + offset_y);
    217                         /*Pick the foreground if it's fully opaque or the Background is fully
    218                          *transparent*/
    219                         if(dsc.res.opa >= LV_OPA_MAX || bg_opa <= LV_OPA_MIN) {
    220                             lv_img_buf_set_px_color(&canvas->dsc, x + offset_x, y + offset_y, dsc.res.color);
    221                             lv_img_buf_set_px_alpha(&canvas->dsc, x + offset_x, y + offset_y, dsc.res.opa);
    222                         }
    223                         /*Opaque background: use simple mix*/
    224                         else if(bg_opa >= LV_OPA_MAX) {
    225                             lv_img_buf_set_px_color(&canvas->dsc, x + offset_x, y + offset_y,
    226                                                     lv_color_mix(dsc.res.color, bg_color, dsc.res.opa));
    227                         }
    228                         /*Both colors have alpha. Expensive calculation need to be applied*/
    229                         else {
    230 
    231                             /*Info:
    232                              * https://en.wikipedia.org/wiki/Alpha_compositing#Analytical_derivation_of_the_over_operator*/
    233                             lv_opa_t opa_res_2 = 255 - ((uint16_t)((uint16_t)(255 - dsc.res.opa) * (255 - bg_opa)) >> 8);
    234                             if(opa_res_2 == 0) {
    235                                 opa_res_2 = 1; /*never happens, just to be sure*/
    236                             }
    237                             lv_opa_t ratio = (uint16_t)((uint16_t)dsc.res.opa * 255) / opa_res_2;
    238 
    239                             lv_img_buf_set_px_color(&canvas->dsc, x + offset_x, y + offset_y,
    240                                                     lv_color_mix(dsc.res.color, bg_color, ratio));
    241                             lv_img_buf_set_px_alpha(&canvas->dsc, x + offset_x, y + offset_y, opa_res_2);
    242                         }
    243                     }
    244                 }
    245             }
    246         }
    247     }
    248 
    249     lv_obj_invalidate(obj);
    250 #else
    251     LV_UNUSED(obj);
    252     LV_UNUSED(img);
    253     LV_UNUSED(angle);
    254     LV_UNUSED(zoom);
    255     LV_UNUSED(offset_x);
    256     LV_UNUSED(offset_y);
    257     LV_UNUSED(pivot_x);
    258     LV_UNUSED(pivot_y);
    259     LV_UNUSED(antialias);
    260     LV_LOG_WARN("Can't transform canvas with LV_DRAW_COMPLEX == 0");
    261 #endif
    262 }
    263 
    264 void lv_canvas_blur_hor(lv_obj_t * obj, const lv_area_t * area, uint16_t r)
    265 {
    266     LV_ASSERT_OBJ(obj, MY_CLASS);
    267 
    268     if(r == 0) return;
    269 
    270     lv_canvas_t * canvas = (lv_canvas_t *)obj;
    271 
    272     lv_area_t a;
    273     if(area) {
    274         lv_area_copy(&a, area);
    275         if(a.x1 < 0) a.x1 = 0;
    276         if(a.y1 < 0) a.y1 = 0;
    277         if(a.x2 > canvas->dsc.header.w - 1) a.x2 = canvas->dsc.header.w - 1;
    278         if(a.y2 > canvas->dsc.header.h - 1) a.y2 = canvas->dsc.header.h - 1;
    279     }
    280     else {
    281         a.x1 = 0;
    282         a.y1 = 0;
    283         a.x2 = canvas->dsc.header.w - 1;
    284         a.y2 = canvas->dsc.header.h - 1;
    285     }
    286 
    287     lv_color_t color = lv_obj_get_style_img_recolor(obj, LV_PART_MAIN);
    288 
    289     uint16_t r_back = r / 2;
    290     uint16_t r_front = r / 2;
    291 
    292     if((r & 0x1) == 0) r_back--;
    293 
    294     bool has_alpha = lv_img_cf_has_alpha(canvas->dsc.header.cf);
    295 
    296     lv_coord_t line_w = lv_img_buf_get_img_size(canvas->dsc.header.w, 1, canvas->dsc.header.cf);
    297     uint8_t * line_buf = lv_mem_buf_get(line_w);
    298 
    299     lv_img_dsc_t line_img;
    300     line_img.data = line_buf;
    301     line_img.header.always_zero = 0;
    302     line_img.header.w = canvas->dsc.header.w;
    303     line_img.header.h = 1;
    304     line_img.header.cf = canvas->dsc.header.cf;
    305 
    306     lv_coord_t x;
    307     lv_coord_t y;
    308     lv_coord_t x_safe;
    309 
    310     for(y = a.y1; y <= a.y2; y++) {
    311         uint32_t asum = 0;
    312         uint32_t rsum = 0;
    313         uint32_t gsum = 0;
    314         uint32_t bsum = 0;
    315 
    316         lv_color_t c;
    317         lv_opa_t opa = LV_OPA_TRANSP;
    318         lv_memcpy(line_buf, &canvas->dsc.data[y * line_w], line_w);
    319 
    320         for(x = a.x1 - r_back; x <= a.x1 + r_front; x++) {
    321             x_safe = x < 0 ? 0 : x;
    322             x_safe = x_safe > canvas->dsc.header.w - 1 ? canvas->dsc.header.w - 1 : x_safe;
    323 
    324             c = lv_img_buf_get_px_color(&line_img, x_safe, 0, color);
    325             if(has_alpha) opa = lv_img_buf_get_px_alpha(&line_img, x_safe, 0);
    326 
    327             rsum += c.ch.red;
    328 #if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP
    329             gsum += (c.ch.green_h << 3) + c.ch.green_l;
    330 #else
    331             gsum += c.ch.green;
    332 #endif
    333             bsum += c.ch.blue;
    334             if(has_alpha) asum += opa;
    335         }
    336 
    337         /*Just to indicate that the px is visible*/
    338         if(has_alpha == false) asum = LV_OPA_COVER;
    339 
    340         for(x = a.x1; x <= a.x2; x++) {
    341 
    342             if(asum) {
    343                 c.ch.red = rsum / r;
    344 #if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP
    345                 uint8_t gtmp = gsum / r;
    346                 c.ch.green_h = gtmp >> 3;
    347                 c.ch.green_l = gtmp & 0x7;
    348 #else
    349                 c.ch.green = gsum / r;
    350 #endif
    351                 c.ch.blue = bsum / r;
    352                 if(has_alpha) opa = asum / r;
    353 
    354                 lv_img_buf_set_px_color(&canvas->dsc, x, y, c);
    355             }
    356             if(has_alpha) lv_img_buf_set_px_alpha(&canvas->dsc, x, y, opa);
    357 
    358             x_safe = x - r_back;
    359             x_safe = x_safe < 0 ? 0 : x_safe;
    360             c = lv_img_buf_get_px_color(&line_img, x_safe, 0, color);
    361             if(has_alpha) opa = lv_img_buf_get_px_alpha(&line_img, x_safe, 0);
    362 
    363             rsum -= c.ch.red;
    364 #if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP
    365             gsum -= (c.ch.green_h << 3) + c.ch.green_l;
    366 #else
    367             gsum -= c.ch.green;
    368 #endif
    369             bsum -= c.ch.blue;
    370             if(has_alpha) asum -= opa;
    371 
    372             x_safe = x + 1 + r_front;
    373             x_safe = x_safe > canvas->dsc.header.w - 1 ? canvas->dsc.header.w - 1 : x_safe;
    374             c = lv_img_buf_get_px_color(&line_img, x_safe, 0, lv_color_white());
    375             if(has_alpha) opa = lv_img_buf_get_px_alpha(&line_img, x_safe, 0);
    376 
    377             rsum += c.ch.red;
    378 #if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP
    379             gsum += (c.ch.green_h << 3) + c.ch.green_l;
    380 #else
    381             gsum += c.ch.green;
    382 #endif
    383             bsum += c.ch.blue;
    384             if(has_alpha) asum += opa;
    385         }
    386     }
    387     lv_obj_invalidate(obj);
    388 
    389     lv_mem_buf_release(line_buf);
    390 }
    391 
    392 void lv_canvas_blur_ver(lv_obj_t * obj, const lv_area_t * area, uint16_t r)
    393 {
    394     LV_ASSERT_OBJ(obj, MY_CLASS);
    395 
    396     if(r == 0) return;
    397 
    398     lv_canvas_t * canvas = (lv_canvas_t *)obj;
    399 
    400     lv_area_t a;
    401     if(area) {
    402         lv_area_copy(&a, area);
    403         if(a.x1 < 0) a.x1 = 0;
    404         if(a.y1 < 0) a.y1 = 0;
    405         if(a.x2 > canvas->dsc.header.w - 1) a.x2 = canvas->dsc.header.w - 1;
    406         if(a.y2 > canvas->dsc.header.h - 1) a.y2 = canvas->dsc.header.h - 1;
    407     }
    408     else {
    409         a.x1 = 0;
    410         a.y1 = 0;
    411         a.x2 = canvas->dsc.header.w - 1;
    412         a.y2 = canvas->dsc.header.h - 1;
    413     }
    414 
    415     lv_color_t color = lv_obj_get_style_img_recolor(obj, LV_PART_MAIN);
    416 
    417     uint16_t r_back = r / 2;
    418     uint16_t r_front = r / 2;
    419 
    420     if((r & 0x1) == 0) r_back--;
    421 
    422     bool has_alpha = lv_img_cf_has_alpha(canvas->dsc.header.cf);
    423     lv_coord_t col_w = lv_img_buf_get_img_size(1, canvas->dsc.header.h, canvas->dsc.header.cf);
    424     uint8_t * col_buf = lv_mem_buf_get(col_w);
    425     lv_img_dsc_t line_img;
    426 
    427     line_img.data = col_buf;
    428     line_img.header.always_zero = 0;
    429     line_img.header.w = 1;
    430     line_img.header.h = canvas->dsc.header.h;
    431     line_img.header.cf = canvas->dsc.header.cf;
    432 
    433     lv_coord_t x;
    434     lv_coord_t y;
    435     lv_coord_t y_safe;
    436 
    437     for(x = a.x1; x <= a.x2; x++) {
    438         uint32_t asum = 0;
    439         uint32_t rsum = 0;
    440         uint32_t gsum = 0;
    441         uint32_t bsum = 0;
    442 
    443         lv_color_t c;
    444         lv_opa_t opa = LV_OPA_COVER;
    445 
    446         for(y = a.y1 - r_back; y <= a.y1 + r_front; y++) {
    447             y_safe = y < 0 ? 0 : y;
    448             y_safe = y_safe > canvas->dsc.header.h - 1 ? canvas->dsc.header.h - 1 : y_safe;
    449 
    450             c = lv_img_buf_get_px_color(&canvas->dsc, x, y_safe, color);
    451             if(has_alpha) opa = lv_img_buf_get_px_alpha(&canvas->dsc, x, y_safe);
    452 
    453             lv_img_buf_set_px_color(&line_img, 0, y_safe, c);
    454             if(has_alpha) lv_img_buf_set_px_alpha(&line_img, 0, y_safe, opa);
    455 
    456             rsum += c.ch.red;
    457 #if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP
    458             gsum += (c.ch.green_h << 3) + c.ch.green_l;
    459 #else
    460             gsum += c.ch.green;
    461 #endif
    462             bsum += c.ch.blue;
    463             if(has_alpha) asum += opa;
    464         }
    465 
    466         /*Just to indicate that the px is visible*/
    467         if(has_alpha == false) asum = LV_OPA_COVER;
    468 
    469         for(y = a.y1; y <= a.y2; y++) {
    470             if(asum) {
    471                 c.ch.red = rsum / r;
    472 #if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP
    473                 uint8_t gtmp = gsum / r;
    474                 c.ch.green_h = gtmp >> 3;
    475                 c.ch.green_l = gtmp & 0x7;
    476 #else
    477                 c.ch.green = gsum / r;
    478 #endif
    479                 c.ch.blue = bsum / r;
    480                 if(has_alpha) opa = asum / r;
    481 
    482                 lv_img_buf_set_px_color(&canvas->dsc, x, y, c);
    483             }
    484             if(has_alpha) lv_img_buf_set_px_alpha(&canvas->dsc, x, y, opa);
    485 
    486             y_safe = y - r_back;
    487             y_safe = y_safe < 0 ? 0 : y_safe;
    488             c = lv_img_buf_get_px_color(&line_img, 0, y_safe, color);
    489             if(has_alpha) opa = lv_img_buf_get_px_alpha(&line_img, 0, y_safe);
    490 
    491             rsum -= c.ch.red;
    492 #if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP
    493             gsum -= (c.ch.green_h << 3) + c.ch.green_l;
    494 #else
    495             gsum -= c.ch.green;
    496 #endif
    497             bsum -= c.ch.blue;
    498             if(has_alpha) asum -= opa;
    499 
    500             y_safe = y + 1 + r_front;
    501             y_safe = y_safe > canvas->dsc.header.h - 1 ? canvas->dsc.header.h - 1 : y_safe;
    502 
    503             c = lv_img_buf_get_px_color(&canvas->dsc, x, y_safe, color);
    504             if(has_alpha) opa = lv_img_buf_get_px_alpha(&canvas->dsc, x, y_safe);
    505 
    506             lv_img_buf_set_px_color(&line_img, 0, y_safe, c);
    507             if(has_alpha) lv_img_buf_set_px_alpha(&line_img, 0, y_safe, opa);
    508 
    509             rsum += c.ch.red;
    510 #if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP
    511             gsum += (c.ch.green_h << 3) + c.ch.green_l;
    512 #else
    513             gsum += c.ch.green;
    514 #endif
    515             bsum += c.ch.blue;
    516             if(has_alpha) asum += opa;
    517         }
    518     }
    519 
    520     lv_obj_invalidate(obj);
    521 
    522     lv_mem_buf_release(col_buf);
    523 }
    524 
    525 void lv_canvas_fill_bg(lv_obj_t * canvas, lv_color_t color, lv_opa_t opa)
    526 {
    527     LV_ASSERT_OBJ(canvas, MY_CLASS);
    528 
    529     lv_img_dsc_t * dsc = lv_canvas_get_img(canvas);
    530 
    531     if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT) {
    532         uint32_t row_byte_cnt = (dsc->header.w + 7) >> 3;
    533         /*+8 skip the palette*/
    534         lv_memset((uint8_t *)dsc->data + 8, color.full ? 0xff : 0x00, row_byte_cnt * dsc->header.h);
    535     }
    536     else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT) {
    537         uint32_t row_byte_cnt = (dsc->header.w + 7) >> 3;
    538         lv_memset((uint8_t *)dsc->data, opa > LV_OPA_50 ? 0xff : 0x00, row_byte_cnt * dsc->header.h);
    539     }
    540     else {
    541         uint32_t x;
    542         uint32_t y;
    543         for(y = 0; y < dsc->header.h; y++) {
    544             for(x = 0; x < dsc->header.w; x++) {
    545                 lv_img_buf_set_px_color(dsc, x, y, color);
    546                 lv_img_buf_set_px_alpha(dsc, x, y, opa);
    547             }
    548         }
    549     }
    550 
    551     lv_obj_invalidate(canvas);
    552 }
    553 
    554 void lv_canvas_draw_rect(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h,
    555                          const lv_draw_rect_dsc_t * draw_dsc)
    556 {
    557     LV_ASSERT_OBJ(canvas, MY_CLASS);
    558 
    559     lv_img_dsc_t * dsc = lv_canvas_get_img(canvas);
    560 
    561     if(dsc->header.cf >= LV_IMG_CF_INDEXED_1BIT && dsc->header.cf <= LV_IMG_CF_INDEXED_8BIT) {
    562         LV_LOG_WARN("lv_canvas_draw_rect: can't draw to LV_IMG_CF_INDEXED canvas");
    563         return;
    564     }
    565 
    566     /*Create a dummy display to fool the lv_draw function.
    567      *It will think it draws to real screen.*/
    568     lv_disp_t fake_disp;
    569     lv_disp_drv_t driver;
    570     lv_area_t clip_area;
    571     init_fake_disp(canvas, &fake_disp, &driver, &clip_area);
    572 
    573     lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing();
    574     _lv_refr_set_disp_refreshing(&fake_disp);
    575 
    576     /*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/
    577     lv_color_t ctransp = LV_COLOR_CHROMA_KEY;
    578     if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED &&
    579        draw_dsc->bg_color.full == ctransp.full) {
    580         fake_disp.driver->antialiasing = 0;
    581     }
    582 
    583     lv_area_t coords;
    584     coords.x1 = x;
    585     coords.y1 = y;
    586     coords.x2 = x + w - 1;
    587     coords.y2 = y + h - 1;
    588 
    589     lv_draw_rect(driver.draw_ctx, draw_dsc, &coords);
    590 
    591     _lv_refr_set_disp_refreshing(refr_ori);
    592 
    593     deinit_fake_disp(canvas, &fake_disp);
    594 
    595     lv_obj_invalidate(canvas);
    596 }
    597 
    598 void lv_canvas_draw_text(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord_t max_w,
    599                          lv_draw_label_dsc_t * draw_dsc, const char * txt)
    600 {
    601     LV_ASSERT_OBJ(canvas, MY_CLASS);
    602 
    603     lv_img_dsc_t * dsc = lv_canvas_get_img(canvas);
    604 
    605     if(dsc->header.cf >= LV_IMG_CF_INDEXED_1BIT && dsc->header.cf <= LV_IMG_CF_INDEXED_8BIT) {
    606         LV_LOG_WARN("lv_canvas_draw_text: can't draw to LV_IMG_CF_INDEXED canvas");
    607         return;
    608     }
    609 
    610     /*Create a dummy display to fool the lv_draw function.
    611      *It will think it draws to real screen.*/
    612     lv_disp_t fake_disp;
    613     lv_disp_drv_t driver;
    614     lv_area_t clip_area;
    615     init_fake_disp(canvas, &fake_disp, &driver, &clip_area);
    616 
    617     lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing();
    618     _lv_refr_set_disp_refreshing(&fake_disp);
    619 
    620     lv_area_t coords;
    621     coords.x1 = x;
    622     coords.y1 = y;
    623     coords.x2 = x + max_w - 1;
    624     coords.y2 = dsc->header.h - 1;
    625     lv_draw_label(driver.draw_ctx, draw_dsc, &coords, txt, NULL);
    626 
    627     _lv_refr_set_disp_refreshing(refr_ori);
    628 
    629     deinit_fake_disp(canvas, &fake_disp);
    630 
    631     lv_obj_invalidate(canvas);
    632 }
    633 
    634 void lv_canvas_draw_img(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, const void * src,
    635                         const lv_draw_img_dsc_t * draw_dsc)
    636 {
    637     LV_ASSERT_OBJ(canvas, MY_CLASS);
    638 
    639     lv_img_dsc_t * dsc = lv_canvas_get_img(canvas);
    640 
    641     if(dsc->header.cf >= LV_IMG_CF_INDEXED_1BIT && dsc->header.cf <= LV_IMG_CF_INDEXED_8BIT) {
    642         LV_LOG_WARN("lv_canvas_draw_img: can't draw to LV_IMG_CF_INDEXED canvas");
    643         return;
    644     }
    645 
    646     lv_img_header_t header;
    647     lv_res_t res = lv_img_decoder_get_info(src, &header);
    648     if(res != LV_RES_OK) {
    649         LV_LOG_WARN("lv_canvas_draw_img: Couldn't get the image data.");
    650         return;
    651     }
    652     /*Create a dummy display to fool the lv_draw function.
    653      *It will think it draws to real screen.*/
    654     lv_disp_t fake_disp;
    655     lv_disp_drv_t driver;
    656     lv_area_t clip_area;
    657     init_fake_disp(canvas, &fake_disp, &driver, &clip_area);
    658 
    659     lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing();
    660     _lv_refr_set_disp_refreshing(&fake_disp);
    661 
    662     lv_area_t coords;
    663     coords.x1 = x;
    664     coords.y1 = y;
    665     coords.x2 = x + header.w - 1;
    666     coords.y2 = y + header.h - 1;
    667 
    668     lv_draw_img(driver.draw_ctx, draw_dsc, &coords, src);
    669 
    670     _lv_refr_set_disp_refreshing(refr_ori);
    671 
    672     deinit_fake_disp(canvas, &fake_disp);
    673 
    674     lv_obj_invalidate(canvas);
    675 }
    676 
    677 void lv_canvas_draw_line(lv_obj_t * canvas, const lv_point_t points[], uint32_t point_cnt,
    678                          const lv_draw_line_dsc_t * draw_dsc)
    679 {
    680     LV_ASSERT_OBJ(canvas, MY_CLASS);
    681 
    682     lv_img_dsc_t * dsc = lv_canvas_get_img(canvas);
    683 
    684     if(dsc->header.cf >= LV_IMG_CF_INDEXED_1BIT && dsc->header.cf <= LV_IMG_CF_INDEXED_8BIT) {
    685         LV_LOG_WARN("lv_canvas_draw_line: can't draw to LV_IMG_CF_INDEXED canvas");
    686         return;
    687     }
    688 
    689     /*Create a dummy display to fool the lv_draw function.
    690      *It will think it draws to real screen.*/
    691     lv_disp_t fake_disp;
    692     lv_disp_drv_t driver;
    693     lv_area_t clip_area;
    694     init_fake_disp(canvas, &fake_disp, &driver, &clip_area);
    695 
    696     lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing();
    697     _lv_refr_set_disp_refreshing(&fake_disp);
    698 
    699 
    700     /*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/
    701     lv_color_t ctransp = LV_COLOR_CHROMA_KEY;
    702     if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED &&
    703        draw_dsc->color.full == ctransp.full) {
    704         fake_disp.driver->antialiasing = 0;
    705     }
    706 
    707     uint32_t i;
    708     for(i = 0; i < point_cnt - 1; i++) {
    709         lv_draw_line(driver.draw_ctx, draw_dsc, &points[i], &points[i + 1]);
    710     }
    711 
    712     _lv_refr_set_disp_refreshing(refr_ori);
    713 
    714     deinit_fake_disp(canvas, &fake_disp);
    715 
    716     lv_obj_invalidate(canvas);
    717 }
    718 
    719 void lv_canvas_draw_polygon(lv_obj_t * canvas, const lv_point_t points[], uint32_t point_cnt,
    720                             const lv_draw_rect_dsc_t * draw_dsc)
    721 {
    722     LV_ASSERT_OBJ(canvas, MY_CLASS);
    723 
    724     lv_img_dsc_t * dsc = lv_canvas_get_img(canvas);
    725 
    726     if(dsc->header.cf >= LV_IMG_CF_INDEXED_1BIT && dsc->header.cf <= LV_IMG_CF_INDEXED_8BIT) {
    727         LV_LOG_WARN("lv_canvas_draw_polygon: can't draw to LV_IMG_CF_INDEXED canvas");
    728         return;
    729     }
    730 
    731     /*Create a dummy display to fool the lv_draw function.
    732      *It will think it draws to real screen.*/
    733     lv_disp_t fake_disp;
    734     lv_disp_drv_t driver;
    735     lv_area_t clip_area;
    736     init_fake_disp(canvas, &fake_disp, &driver, &clip_area);
    737 
    738     lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing();
    739     _lv_refr_set_disp_refreshing(&fake_disp);
    740 
    741     /*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/
    742     lv_color_t ctransp = LV_COLOR_CHROMA_KEY;
    743     if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED &&
    744        draw_dsc->bg_color.full == ctransp.full) {
    745         fake_disp.driver->antialiasing = 0;
    746     }
    747 
    748     lv_draw_polygon(driver.draw_ctx, draw_dsc, points, point_cnt);
    749 
    750     _lv_refr_set_disp_refreshing(refr_ori);
    751 
    752     deinit_fake_disp(canvas, &fake_disp);
    753 
    754     lv_obj_invalidate(canvas);
    755 }
    756 
    757 void lv_canvas_draw_arc(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord_t r, int32_t start_angle,
    758                         int32_t end_angle, const lv_draw_arc_dsc_t * draw_dsc)
    759 {
    760 #if LV_DRAW_COMPLEX
    761     LV_ASSERT_OBJ(canvas, MY_CLASS);
    762 
    763     lv_img_dsc_t * dsc = lv_canvas_get_img(canvas);
    764 
    765     if(dsc->header.cf >= LV_IMG_CF_INDEXED_1BIT && dsc->header.cf <= LV_IMG_CF_INDEXED_8BIT) {
    766         LV_LOG_WARN("lv_canvas_draw_arc: can't draw to LV_IMG_CF_INDEXED canvas");
    767         return;
    768     }
    769 
    770     /*Create a dummy display to fool the lv_draw function.
    771      *It will think it draws to real screen.*/
    772     lv_disp_t fake_disp;
    773     lv_disp_drv_t driver;
    774     lv_area_t clip_area;
    775     init_fake_disp(canvas, &fake_disp, &driver, &clip_area);
    776 
    777     lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing();
    778     _lv_refr_set_disp_refreshing(&fake_disp);
    779 
    780     lv_point_t p = {x, y};
    781     lv_draw_arc(driver.draw_ctx, draw_dsc, &p, r,  start_angle, end_angle);
    782 
    783     _lv_refr_set_disp_refreshing(refr_ori);
    784 
    785     deinit_fake_disp(canvas, &fake_disp);
    786 
    787     lv_obj_invalidate(canvas);
    788 #else
    789     LV_UNUSED(canvas);
    790     LV_UNUSED(x);
    791     LV_UNUSED(y);
    792     LV_UNUSED(r);
    793     LV_UNUSED(start_angle);
    794     LV_UNUSED(end_angle);
    795     LV_UNUSED(draw_dsc);
    796     LV_LOG_WARN("Can't draw arc with LV_DRAW_COMPLEX == 0");
    797 #endif
    798 }
    799 
    800 /**********************
    801  *   STATIC FUNCTIONS
    802  **********************/
    803 
    804 static void lv_canvas_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
    805 {
    806     LV_UNUSED(class_p);
    807     LV_TRACE_OBJ_CREATE("begin");
    808 
    809     lv_canvas_t * canvas = (lv_canvas_t *)obj;
    810 
    811     canvas->dsc.header.always_zero = 0;
    812     canvas->dsc.header.cf          = LV_IMG_CF_TRUE_COLOR;
    813     canvas->dsc.header.h           = 0;
    814     canvas->dsc.header.w           = 0;
    815     canvas->dsc.data_size          = 0;
    816     canvas->dsc.data               = NULL;
    817 
    818     lv_img_set_src(obj, &canvas->dsc);
    819 
    820     LV_TRACE_OBJ_CREATE("finished");
    821 }
    822 
    823 static void lv_canvas_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
    824 {
    825     LV_UNUSED(class_p);
    826     LV_TRACE_OBJ_CREATE("begin");
    827 
    828     lv_canvas_t * canvas = (lv_canvas_t *)obj;
    829     lv_img_cache_invalidate_src(&canvas->dsc);
    830 }
    831 
    832 
    833 static void init_fake_disp(lv_obj_t * canvas, lv_disp_t * disp, lv_disp_drv_t * drv, lv_area_t * clip_area)
    834 {
    835     lv_img_dsc_t * dsc = lv_canvas_get_img(canvas);
    836 
    837     clip_area->x1 = 0;
    838     clip_area->x2 = dsc->header.w - 1;
    839     clip_area->y1 = 0;
    840     clip_area->y2 = dsc->header.h - 1;
    841 
    842     /*Allocate the fake driver on the stack as the entire display doesn't outlive this function*/
    843     lv_memset_00(disp, sizeof(lv_disp_t));
    844     disp->driver = drv;
    845 
    846     lv_disp_drv_init(disp->driver);
    847     disp->driver->hor_res = dsc->header.w;
    848     disp->driver->ver_res = dsc->header.h;
    849 
    850     lv_draw_ctx_t * draw_ctx = lv_mem_alloc(sizeof(lv_draw_sw_ctx_t));
    851     LV_ASSERT_MALLOC(draw_ctx);
    852     if(draw_ctx == NULL)  return;
    853     lv_draw_sw_init_ctx(drv, draw_ctx);
    854     disp->driver->draw_ctx = draw_ctx;
    855     draw_ctx->clip_area = clip_area;
    856     draw_ctx->buf_area = clip_area;
    857     draw_ctx->buf = (void *)dsc->data;
    858 
    859     lv_disp_drv_use_generic_set_px_cb(disp->driver, dsc->header.cf);
    860 }
    861 
    862 static void deinit_fake_disp(lv_obj_t * canvas, lv_disp_t * disp)
    863 {
    864     LV_UNUSED(canvas);
    865     lv_draw_sw_deinit_ctx(disp->driver, disp->driver->draw_ctx);
    866     lv_mem_free(disp->driver->draw_ctx);
    867 }
    868 
    869 
    870 
    871 #endif