1 /**
2  * @file lv_canvas.c
3  *
4  */
5 
6 /**
7  * Modified by NXP in 2024
8  */
9 
10 /*********************
11  *      INCLUDES
12  *********************/
13 #include "lv_canvas_private.h"
14 #include "../../core/lv_obj_class_private.h"
15 #if LV_USE_CANVAS != 0
16 #include "../../misc/lv_assert.h"
17 #include "../../misc/lv_math.h"
18 #include "../../draw/lv_draw_private.h"
19 #include "../../core/lv_refr.h"
20 #include "../../display/lv_display.h"
21 #include "../../draw/sw/lv_draw_sw.h"
22 #include "../../stdlib/lv_string.h"
23 #include "../../misc/cache/lv_cache.h"
24 /*********************
25  *      DEFINES
26  *********************/
27 #define MY_CLASS (&lv_canvas_class)
28 
29 /**********************
30  *      TYPEDEFS
31  **********************/
32 
33 /**********************
34  *  STATIC PROTOTYPES
35  **********************/
36 static void lv_canvas_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
37 static void lv_canvas_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
38 
39 /**********************
40  *  STATIC VARIABLES
41  **********************/
42 
43 const lv_obj_class_t lv_canvas_class = {
44     .constructor_cb = lv_canvas_constructor,
45     .destructor_cb = lv_canvas_destructor,
46     .instance_size = sizeof(lv_canvas_t),
47     .base_class = &lv_image_class,
48     .name = "canvas",
49 };
50 
51 /**********************
52  *      MACROS
53  **********************/
54 
55 /**********************
56  *   GLOBAL FUNCTIONS
57  **********************/
58 
lv_canvas_create(lv_obj_t * parent)59 lv_obj_t * lv_canvas_create(lv_obj_t * parent)
60 {
61     LV_LOG_INFO("begin");
62     lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
63     lv_obj_class_init_obj(obj);
64     return obj;
65 }
66 
67 /*=====================
68  * Setter functions
69  *====================*/
70 
lv_canvas_set_buffer(lv_obj_t * obj,void * buf,int32_t w,int32_t h,lv_color_format_t cf)71 void lv_canvas_set_buffer(lv_obj_t * obj, void * buf, int32_t w, int32_t h, lv_color_format_t cf)
72 {
73     LV_ASSERT_OBJ(obj, MY_CLASS);
74     LV_ASSERT_NULL(buf);
75 
76     lv_canvas_t * canvas = (lv_canvas_t *)obj;
77     uint32_t stride = lv_draw_buf_width_to_stride(w, cf);
78     lv_draw_buf_init(&canvas->static_buf, w, h, cf, stride, buf, stride * h);
79     canvas->draw_buf = &canvas->static_buf;
80 
81     const void * src = lv_image_get_src(obj);
82     if(src) {
83         lv_image_cache_drop(src);
84     }
85 
86     lv_image_set_src(obj, canvas->draw_buf);
87     lv_image_cache_drop(canvas->draw_buf);
88 }
89 
lv_canvas_set_draw_buf(lv_obj_t * obj,lv_draw_buf_t * draw_buf)90 void lv_canvas_set_draw_buf(lv_obj_t * obj, lv_draw_buf_t * draw_buf)
91 {
92     LV_ASSERT_OBJ(obj, MY_CLASS);
93     LV_ASSERT_NULL(draw_buf);
94 
95     lv_canvas_t * canvas = (lv_canvas_t *)obj;
96     canvas->draw_buf = draw_buf;
97 
98     const void * src = lv_image_get_src(obj);
99     if(src) {
100         lv_image_cache_drop(src);
101     }
102 
103     lv_image_set_src(obj, draw_buf);
104     lv_image_cache_drop(draw_buf);
105 }
106 
lv_canvas_set_px(lv_obj_t * obj,int32_t x,int32_t y,lv_color_t color,lv_opa_t opa)107 void lv_canvas_set_px(lv_obj_t * obj, int32_t x, int32_t y, lv_color_t color, lv_opa_t opa)
108 {
109     LV_ASSERT_OBJ(obj, MY_CLASS);
110 
111     lv_canvas_t * canvas = (lv_canvas_t *)obj;
112     lv_draw_buf_t * draw_buf = canvas->draw_buf;
113 
114     lv_color_format_t cf = draw_buf->header.cf;
115     uint8_t * data = lv_draw_buf_goto_xy(draw_buf, x, y);
116 
117     if(LV_COLOR_FORMAT_IS_INDEXED(cf)) {
118         uint8_t shift;
119         uint8_t c_int = color.blue;
120         switch(cf) {
121             case LV_COLOR_FORMAT_I1:
122                 shift = 7 - (x & 0x7);
123                 break;
124             case LV_COLOR_FORMAT_I2:
125                 shift = 6 - 2 * (x & 0x3);
126                 break;
127             case LV_COLOR_FORMAT_I4:
128                 shift = 4 - 4 * (x & 0x1);
129                 break;
130             case LV_COLOR_FORMAT_I8:
131                 /*Indexed8 format is a easy case, process and return.*/
132                 shift = 0;
133                 *data = c_int;
134             default:
135                 return;
136         }
137 
138         uint8_t bpp = lv_color_format_get_bpp(cf);
139         uint8_t mask = (1 << bpp) - 1;
140         c_int &= mask;
141         *data = (*data & ~(mask << shift)) | (c_int << shift);
142     }
143     else if(cf == LV_COLOR_FORMAT_L8) {
144         *data = lv_color_luminance(color);
145     }
146     else if(cf == LV_COLOR_FORMAT_A8) {
147         *data = opa;
148     }
149     else if(cf == LV_COLOR_FORMAT_RGB565) {
150         lv_color16_t * buf = (lv_color16_t *)data;
151         buf->red = color.red >> 3;
152         buf->green = color.green >> 2;
153         buf->blue = color.blue >> 3;
154     }
155     else if(cf == LV_COLOR_FORMAT_RGB888) {
156         data[2] = color.red;
157         data[1] = color.green;
158         data[0] = color.blue;
159     }
160     else if(cf == LV_COLOR_FORMAT_XRGB8888) {
161         data[2] = color.red;
162         data[1] = color.green;
163         data[0] = color.blue;
164         data[3] = 0xFF;
165     }
166     else if(cf == LV_COLOR_FORMAT_ARGB8888) {
167         lv_color32_t * buf = (lv_color32_t *)data;
168         buf->red = color.red;
169         buf->green = color.green;
170         buf->blue = color.blue;
171         buf->alpha = opa;
172     }
173     else if(cf == LV_COLOR_FORMAT_AL88) {
174         lv_color16a_t * buf = (lv_color16a_t *)data;
175         buf->lumi = lv_color_luminance(color);
176         buf->alpha = 255;
177     }
178     lv_obj_invalidate(obj);
179 }
180 
lv_canvas_set_palette(lv_obj_t * obj,uint8_t index,lv_color32_t color)181 void lv_canvas_set_palette(lv_obj_t * obj, uint8_t index, lv_color32_t color)
182 {
183     LV_ASSERT_OBJ(obj, MY_CLASS);
184 
185     lv_canvas_t * canvas = (lv_canvas_t *)obj;
186 
187     lv_draw_buf_set_palette(canvas->draw_buf, index, color);
188     lv_obj_invalidate(obj);
189 }
190 
191 /*=====================
192  * Getter functions
193  *====================*/
194 
lv_canvas_get_draw_buf(lv_obj_t * obj)195 lv_draw_buf_t * lv_canvas_get_draw_buf(lv_obj_t * obj)
196 {
197     LV_ASSERT_OBJ(obj, MY_CLASS);
198 
199     lv_canvas_t * canvas = (lv_canvas_t *)obj;
200     return canvas->draw_buf;
201 }
202 
lv_canvas_get_px(lv_obj_t * obj,int32_t x,int32_t y)203 lv_color32_t lv_canvas_get_px(lv_obj_t * obj, int32_t x, int32_t y)
204 {
205     LV_ASSERT_OBJ(obj, MY_CLASS);
206 
207     lv_color32_t ret = { 0 };
208     lv_canvas_t * canvas = (lv_canvas_t *)obj;
209     if(canvas->draw_buf == NULL) return ret;
210 
211     lv_image_header_t * header = &canvas->draw_buf->header;
212     const uint8_t * px = lv_draw_buf_goto_xy(canvas->draw_buf, x, y);
213 
214     switch(header->cf) {
215         case LV_COLOR_FORMAT_ARGB8888:
216             ret = *(lv_color32_t *)px;
217             break;
218         case LV_COLOR_FORMAT_RGB888:
219         case LV_COLOR_FORMAT_XRGB8888:
220             ret.red = px[2];
221             ret.green = px[1];
222             ret.blue = px[0];
223             ret.alpha = 0xFF;
224             break;
225         case LV_COLOR_FORMAT_RGB565: {
226                 lv_color16_t * c16 = (lv_color16_t *) px;
227                 ret.red = (c16[x].red * 2106) >> 8;  /*To make it rounded*/
228                 ret.green = (c16[x].green * 1037) >> 8;
229                 ret.blue = (c16[x].blue * 2106) >> 8;
230                 ret.alpha = 0xFF;
231                 break;
232             }
233         case LV_COLOR_FORMAT_A8: {
234                 lv_color_t alpha_color = lv_obj_get_style_image_recolor(obj, LV_PART_MAIN);
235                 ret.red = alpha_color.red;
236                 ret.green = alpha_color.green;
237                 ret.blue = alpha_color.blue;
238                 ret.alpha = px[0];
239                 break;
240             }
241         case LV_COLOR_FORMAT_L8: {
242                 ret.red = *px;
243                 ret.green = *px;
244                 ret.blue = *px;
245                 ret.alpha = 0xFF;
246                 break;
247             }
248         default:
249             lv_memzero(&ret, sizeof(lv_color32_t));
250             break;
251     }
252 
253     return ret;
254 }
255 
lv_canvas_get_image(lv_obj_t * obj)256 lv_image_dsc_t * lv_canvas_get_image(lv_obj_t * obj)
257 {
258     LV_ASSERT_OBJ(obj, MY_CLASS);
259 
260     lv_canvas_t * canvas = (lv_canvas_t *)obj;
261     return (lv_image_dsc_t *)canvas->draw_buf;
262 }
263 
lv_canvas_get_buf(lv_obj_t * obj)264 const void * lv_canvas_get_buf(lv_obj_t * obj)
265 {
266     LV_ASSERT_OBJ(obj, MY_CLASS);
267 
268     lv_canvas_t * canvas = (lv_canvas_t *)obj;
269     if(canvas->draw_buf)
270         return canvas->draw_buf->unaligned_data;
271 
272     return NULL;
273 }
274 
275 /*=====================
276  * Other functions
277  *====================*/
278 
lv_canvas_copy_buf(lv_obj_t * obj,const lv_area_t * canvas_area,lv_draw_buf_t * dest_buf,const lv_area_t * dest_area)279 void lv_canvas_copy_buf(lv_obj_t * obj, const lv_area_t * canvas_area, lv_draw_buf_t * dest_buf,
280                         const lv_area_t * dest_area)
281 {
282     LV_ASSERT_OBJ(obj, MY_CLASS);
283     LV_ASSERT_NULL(canvas_area && dest_buf);
284 
285     lv_canvas_t * canvas = (lv_canvas_t *)obj;
286     if(canvas->draw_buf == NULL) return;
287 
288     LV_ASSERT_MSG(canvas->draw_buf->header.cf == dest_buf->header.cf, "Color formats must be the same");
289 
290     lv_draw_buf_copy(canvas->draw_buf, canvas_area, dest_buf, dest_area);
291 }
292 
lv_canvas_fill_bg(lv_obj_t * obj,lv_color_t color,lv_opa_t opa)293 void lv_canvas_fill_bg(lv_obj_t * obj, lv_color_t color, lv_opa_t opa)
294 {
295     LV_ASSERT_OBJ(obj, MY_CLASS);
296 
297     lv_canvas_t * canvas = (lv_canvas_t *)obj;
298     lv_draw_buf_t * draw_buf = canvas->draw_buf;
299     if(draw_buf == NULL) return;
300 
301     lv_image_header_t * header = &draw_buf->header;
302     uint32_t x;
303     uint32_t y;
304 
305     uint32_t stride = header->stride;
306     uint8_t * data = draw_buf->data;
307     if(header->cf == LV_COLOR_FORMAT_RGB565) {
308         uint16_t c16 = lv_color_to_u16(color);
309         for(y = 0; y < header->h; y++) {
310             uint16_t * buf16 = (uint16_t *)(data + y * stride);
311             for(x = 0; x < header->w; x++) {
312                 buf16[x] = c16;
313             }
314         }
315     }
316     else if(header->cf == LV_COLOR_FORMAT_XRGB8888 || header->cf == LV_COLOR_FORMAT_ARGB8888) {
317         uint32_t c32 = lv_color_to_u32(color);
318         if(header->cf == LV_COLOR_FORMAT_ARGB8888) {
319             c32 &= 0x00ffffff;
320             c32 |= (uint32_t)opa << 24;
321         }
322         for(y = 0; y < header->h; y++) {
323             uint32_t * buf32 = (uint32_t *)(data + y * stride);
324             for(x = 0; x < header->w; x++) {
325                 buf32[x] = c32;
326             }
327         }
328     }
329     else if(header->cf == LV_COLOR_FORMAT_RGB888) {
330         for(y = 0; y < header->h; y++) {
331             uint8_t * buf8 = (uint8_t *)(data + y * stride);
332             for(x = 0; x < header->w * 3; x += 3) {
333                 buf8[x + 0] = color.blue;
334                 buf8[x + 1] = color.green;
335                 buf8[x + 2] = color.red;
336             }
337         }
338     }
339     else if(header->cf == LV_COLOR_FORMAT_L8) {
340         uint8_t c8 = lv_color_luminance(color);
341         for(y = 0; y < header->h; y++) {
342             uint8_t * buf = (uint8_t *)(data + y * stride);
343             for(x = 0; x < header->w; x++) {
344                 buf[x] = c8;
345             }
346         }
347     }
348     else if(header->cf == LV_COLOR_FORMAT_AL88) {
349         lv_color16a_t c;
350         c.lumi = lv_color_luminance(color);
351         c.alpha = 255;
352         for(y = 0; y < header->h; y++) {
353             lv_color16a_t * buf = (lv_color16a_t *)(data + y * stride);
354             for(x = 0; x < header->w; x++) {
355                 buf[x] = c;
356             }
357         }
358     }
359 
360     else {
361         for(y = 0; y < header->h; y++) {
362             for(x = 0; x < header->w; x++) {
363                 lv_canvas_set_px(obj, x, y, color, opa);
364             }
365         }
366     }
367 
368     lv_obj_invalidate(obj);
369 }
370 
lv_canvas_init_layer(lv_obj_t * obj,lv_layer_t * layer)371 void lv_canvas_init_layer(lv_obj_t * obj, lv_layer_t * layer)
372 {
373     LV_ASSERT_NULL(obj);
374     LV_ASSERT_NULL(layer);
375     lv_canvas_t * canvas = (lv_canvas_t *)obj;
376     if(canvas->draw_buf == NULL) return;
377 
378     lv_image_header_t * header = &canvas->draw_buf->header;
379     lv_area_t canvas_area = {0, 0, header->w - 1,  header->h - 1};
380     lv_layer_init(layer);
381 
382     layer->draw_buf = canvas->draw_buf;
383     layer->color_format = header->cf;
384     layer->buf_area = canvas_area;
385     layer->_clip_area = canvas_area;
386     layer->phy_clip_area = canvas_area;
387 }
388 
lv_canvas_finish_layer(lv_obj_t * canvas,lv_layer_t * layer)389 void lv_canvas_finish_layer(lv_obj_t * canvas, lv_layer_t * layer)
390 {
391     if(layer->draw_task_head == NULL) return;
392 
393     bool task_dispatched;
394 
395     while(layer->draw_task_head) {
396         lv_draw_dispatch_wait_for_request();
397         task_dispatched = lv_draw_dispatch_layer(lv_obj_get_display(canvas), layer);
398 
399         if(!task_dispatched) {
400             lv_draw_wait_for_finish();
401             lv_draw_dispatch_request();
402         }
403     }
404     lv_obj_invalidate(canvas);
405 }
406 
lv_canvas_buf_size(int32_t w,int32_t h,uint8_t bpp,uint8_t stride)407 uint32_t lv_canvas_buf_size(int32_t w, int32_t h, uint8_t bpp, uint8_t stride)
408 {
409     return (uint32_t)LV_CANVAS_BUF_SIZE(w, h, bpp, stride);
410 }
411 
412 /**********************
413  *   STATIC FUNCTIONS
414  **********************/
415 
lv_canvas_constructor(const lv_obj_class_t * class_p,lv_obj_t * obj)416 static void lv_canvas_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
417 {
418     LV_UNUSED(class_p);
419     LV_UNUSED(obj);
420 }
421 
lv_canvas_destructor(const lv_obj_class_t * class_p,lv_obj_t * obj)422 static void lv_canvas_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
423 {
424     LV_UNUSED(class_p);
425     LV_TRACE_OBJ_CREATE("begin");
426 
427     lv_canvas_t * canvas = (lv_canvas_t *)obj;
428     if(canvas->draw_buf == NULL) return;
429 
430     lv_image_cache_drop(&canvas->draw_buf);
431 }
432 
433 #endif
434