Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bdk/libs/lvgl/lv_objx/lv_canvas.c
1476 views
1
/**
2
* @file lv_canvas.c
3
*
4
*/
5
6
/*********************
7
* INCLUDES
8
*********************/
9
#include "lv_canvas.h"
10
#if USE_LV_CANVAS != 0
11
12
/*********************
13
* DEFINES
14
*********************/
15
16
/**********************
17
* TYPEDEFS
18
**********************/
19
20
/**********************
21
* STATIC PROTOTYPES
22
**********************/
23
static lv_res_t lv_canvas_signal(lv_obj_t * canvas, lv_signal_t sign, void * param);
24
25
/**********************
26
* STATIC VARIABLES
27
**********************/
28
static lv_signal_func_t ancestor_signal;
29
static lv_design_func_t ancestor_design;
30
31
/**********************
32
* MACROS
33
**********************/
34
35
/**********************
36
* GLOBAL FUNCTIONS
37
**********************/
38
39
/**
40
* Create a canvas object
41
* @param par pointer to an object, it will be the parent of the new canvas
42
* @param copy pointer to a canvas object, if not NULL then the new object will be copied from it
43
* @return pointer to the created canvas
44
*/
45
lv_obj_t * lv_canvas_create(lv_obj_t * par, const lv_obj_t * copy)
46
{
47
LV_LOG_TRACE("canvas create started");
48
49
/*Create the ancestor of canvas*/
50
lv_obj_t * new_canvas = lv_img_create(par, copy);
51
lv_mem_assert(new_canvas);
52
if(new_canvas == NULL) return NULL;
53
54
/*Allocate the canvas type specific extended data*/
55
lv_canvas_ext_t * ext = lv_obj_allocate_ext_attr(new_canvas, sizeof(lv_canvas_ext_t));
56
lv_mem_assert(ext);
57
if(ext == NULL) return NULL;
58
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_canvas);
59
if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_canvas);
60
61
/*Initialize the allocated 'ext' */
62
ext->dsc.header.always_zero = 0;
63
ext->dsc.header.cf = LV_IMG_CF_TRUE_COLOR;
64
ext->dsc.header.h = 0;
65
ext->dsc.header.w = 0;
66
ext->dsc.data_size = 0;
67
ext->dsc.data = NULL;
68
69
lv_img_set_src(new_canvas, &ext->dsc);
70
71
/*The signal and design functions are not copied so set them here*/
72
lv_obj_set_signal_func(new_canvas, lv_canvas_signal);
73
74
/*Init the new canvas canvas*/
75
if(copy == NULL) {
76
77
}
78
/*Copy an existing canvas*/
79
else {
80
//lv_canvas_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
81
82
/*Refresh the style with new signal function*/
83
lv_obj_refresh_style(new_canvas);
84
}
85
86
LV_LOG_INFO("canvas created");
87
88
return new_canvas;
89
}
90
91
/*=====================
92
* Setter functions
93
*====================*/
94
95
/**
96
* Set a buffer for the canvas.
97
* @param buf a buffer where the content of the canvas will be.
98
* The required size is (lv_img_color_format_get_px_size(cf) * w * h) / 8)
99
* It can be allocated with `lv_mem_alloc()` or
100
* it can be statically allocated array (e.g. static lv_color_t buf[100*50]) or
101
* it can be an address in RAM or external SRAM
102
* @param canvas pointer to a canvas object
103
* @param w width of the canvas
104
* @param h height of the canvas
105
* @param cf color format. The following formats are supported:
106
* LV_IMG_CF_TRUE_COLOR, LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, LV_IMG_CF_INDEXES_1/2/4/8BIT
107
*
108
*/
109
void lv_canvas_set_buffer(lv_obj_t * canvas, void * buf, lv_coord_t w, lv_coord_t h, lv_img_cf_t cf)
110
{
111
lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);
112
113
ext->dsc.header.cf = cf;
114
ext->dsc.header.w = w;
115
ext->dsc.header.h = h;
116
ext->dsc.data = buf;
117
ext->dsc.data_size = (lv_img_color_format_get_px_size(cf) * w * h) / 8;
118
119
lv_img_set_src(canvas, &ext->dsc);
120
}
121
/**
122
* Set the color of a pixel on the canvas
123
* @param canvas
124
* @param x x coordinate of the point to set
125
* @param y x coordinate of the point to set
126
* @param c color of the point
127
*/
128
void lv_canvas_set_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t c)
129
{
130
131
lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);
132
if(x >= ext->dsc.header.w || y >= ext->dsc.header.h) {
133
LV_LOG_WARN("lv_canvas_set_px: x or y out of the canvas");
134
return;
135
}
136
137
uint8_t * buf_u8 = (uint8_t *) ext->dsc.data;
138
139
if(ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR ||
140
ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED)
141
{
142
uint32_t px = ext->dsc.header.w * y * sizeof(lv_color_t) + x * sizeof(lv_color_t);
143
144
memcpy(&buf_u8[px], &c, sizeof(lv_color_t));
145
}
146
else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_1BIT) {
147
buf_u8 += 4 * 2;
148
uint8_t bit = x & 0x7;
149
x = x >> 3;
150
151
uint32_t px = (ext->dsc.header.w >> 3) * y + x;
152
buf_u8[px] = buf_u8[px] & ~(1 << (7 - bit));
153
buf_u8[px] = buf_u8[px] | ((c.full & 0x1) << (7 - bit));
154
}
155
else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_2BIT) {
156
buf_u8 += 4 * 4;
157
uint8_t bit = (x & 0x3) * 2;
158
x = x >> 2;
159
160
uint32_t px = (ext->dsc.header.w >> 2) * y + x;
161
162
buf_u8[px] = buf_u8[px] & ~(3 << (6 - bit));
163
buf_u8[px] = buf_u8[px] | ((c.full & 0x3) << (6 - bit));
164
}
165
else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_4BIT) {
166
buf_u8 += 4 * 16;
167
uint8_t bit = (x & 0x1) * 4;
168
x = x >> 1;
169
170
uint32_t px = (ext->dsc.header.w >> 1) * y + x;
171
172
buf_u8[px] = buf_u8[px] & ~(0xF << (4 - bit));
173
buf_u8[px] = buf_u8[px] | ((c.full & 0xF) << (4 - bit));
174
}
175
else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_8BIT) {
176
buf_u8 += 4 * 256;
177
uint32_t px = ext->dsc.header.w * y + x;
178
buf_u8[px] = c.full;
179
}
180
}
181
182
/**
183
* Set a style of a canvas.
184
* @param canvas pointer to canvas object
185
* @param type which style should be set
186
* @param style pointer to a style
187
*/
188
void lv_canvas_set_style(lv_obj_t * canvas, lv_canvas_style_t type, lv_style_t * style)
189
{
190
switch(type) {
191
case LV_CANVAS_STYLE_MAIN:
192
lv_img_set_style(canvas, style);
193
break;
194
}
195
}
196
197
/*=====================
198
* Getter functions
199
*====================*/
200
201
/**
202
* Get the color of a pixel on the canvas
203
* @param canvas
204
* @param x x coordinate of the point to set
205
* @param y x coordinate of the point to set
206
* @return color of the point
207
*/
208
lv_color_t lv_canvas_get_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y)
209
{
210
lv_color_t p_color = LV_COLOR_BLACK;
211
lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);
212
if(x >= ext->dsc.header.w || y >= ext->dsc.header.h) {
213
LV_LOG_WARN("lv_canvas_get_px: x or y out of the canvas");
214
return p_color;
215
}
216
217
uint8_t * buf_u8 = (uint8_t *) ext->dsc.data;
218
219
if(ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR ||
220
ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED)
221
{
222
uint32_t px = ext->dsc.header.w * y * sizeof(lv_color_t) + x * sizeof(lv_color_t);
223
memcpy(&p_color, &buf_u8[px], sizeof(lv_color_t));
224
}
225
else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_1BIT) {
226
buf_u8 += 4 * 2;
227
uint8_t bit = x & 0x7;
228
x = x >> 3;
229
230
uint32_t px = (ext->dsc.header.w >> 3) * y + x;
231
p_color.full = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit);
232
}
233
else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_2BIT) {
234
buf_u8 += 4 * 4;
235
uint8_t bit = (x & 0x3) * 2;
236
x = x >> 2;
237
238
uint32_t px = (ext->dsc.header.w >> 2) * y + x;
239
p_color.full = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit);
240
}
241
else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_4BIT) {
242
buf_u8 += 4 * 16;
243
uint8_t bit = (x & 0x1) * 4;
244
x = x >> 1;
245
246
uint32_t px = (ext->dsc.header.w >> 1) * y + x;
247
p_color.full = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit);
248
}
249
else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_8BIT) {
250
buf_u8 += 4 * 256;
251
uint32_t px = ext->dsc.header.w * y + x;
252
p_color.full = buf_u8[px];
253
}
254
return p_color;
255
}
256
257
/**
258
* Get style of a canvas.
259
* @param canvas pointer to canvas object
260
* @param type which style should be get
261
* @return style pointer to the style
262
*/
263
lv_style_t * lv_canvas_get_style(const lv_obj_t * canvas, lv_canvas_style_t type)
264
{
265
// lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);
266
lv_style_t * style = NULL;
267
268
switch(type) {
269
case LV_CANVAS_STYLE_MAIN:
270
style = lv_img_get_style(canvas);
271
break;
272
default:
273
style = NULL;
274
}
275
276
return style;
277
}
278
279
/*=====================
280
* Other functions
281
*====================*/
282
283
/**
284
* Copy a buffer to the canvas
285
* @param canvas pointer to a canvas object
286
* @param to_copy buffer to copy. The color format has to match with the canvas's buffer color format
287
* @param w width of the buffer to copy
288
* @param h height of the buffer to copy
289
* @param x left side of the destination position
290
* @param y top side of the destination position
291
*/
292
void lv_canvas_copy_buf(lv_obj_t * canvas, const void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y)
293
{
294
lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);
295
if(x + w >= ext->dsc.header.w || y + h >= ext->dsc.header.h) {
296
LV_LOG_WARN("lv_canvas_copy_buf: x or y out of the canvas");
297
return;
298
}
299
300
uint32_t px_size = lv_img_color_format_get_px_size(ext->dsc.header.cf) >> 3;
301
uint32_t px = ext->dsc.header.w * y * px_size + x * px_size;
302
uint8_t * to_copy8 = (uint8_t *) to_copy;
303
lv_coord_t i;
304
for(i = 0; i < h; i++) {
305
memcpy((void*)&ext->dsc.data[px], to_copy8, w * px_size);
306
px += ext->dsc.header.w * px_size;
307
to_copy8 += w * px_size;
308
}
309
}
310
311
/**
312
* Multiply a buffer with the canvas
313
* @param canvas pointer to a canvas object
314
* @param to_copy buffer to copy (multiply). LV_IMG_CF_TRUE_COLOR_ALPHA is not supported
315
* @param w width of the buffer to copy
316
* @param h height of the buffer to copy
317
* @param x left side of the destination position
318
* @param y top side of the destination position
319
*/
320
void lv_canvas_mult_buf(lv_obj_t * canvas, void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y)
321
{
322
lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);
323
if(x + w >= ext->dsc.header.w || y + h >= ext->dsc.header.h) {
324
LV_LOG_WARN("lv_canvas_mult_buf: x or y out of the canvas");
325
return;
326
}
327
328
if(ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
329
LV_LOG_WARN("lv_canvas_mult_buf: LV_IMG_CF_TRUE_COLOR_ALPHA is not supported");
330
return;
331
}
332
333
uint32_t px_size = lv_img_color_format_get_px_size(ext->dsc.header.cf) >> 3;
334
uint32_t px = ext->dsc.header.w * y * px_size + x * px_size;
335
lv_color_t * copy_buf_color = (lv_color_t *) to_copy;
336
lv_color_t * canvas_buf_color = (lv_color_t *) &ext->dsc.data[px];
337
338
lv_coord_t i;
339
lv_coord_t j;
340
for(i = 0; i < h; i++) {
341
for(j = 0; j < w; j++) {
342
#if LV_COLOR_DEPTH == 32
343
canvas_buf_color[j].red = (uint16_t) ((uint16_t) canvas_buf_color[j].red * copy_buf_color[j].red) >> 8;
344
canvas_buf_color[j].green = (uint16_t) ((uint16_t) canvas_buf_color[j].green * copy_buf_color[j].green) >> 8;
345
canvas_buf_color[j].blue = (uint16_t) ((uint16_t) canvas_buf_color[j].blue * copy_buf_color[j].blue) >> 8;
346
#elif LV_COLOR_DEPTH == 16
347
348
canvas_buf_color[j].red = (uint16_t) ((uint16_t) canvas_buf_color[j].red * copy_buf_color[j].red) >> 5;
349
canvas_buf_color[j].blue = (uint16_t) ((uint16_t) canvas_buf_color[j].blue * copy_buf_color[j].blue) >> 5;
350
# if LV_COLOR_16_SWAP == 0
351
canvas_buf_color[j].green = (uint16_t) ((uint16_t) canvas_buf_color[j].green * copy_buf_color[j].green) >> 6;
352
# else
353
uint8_t green_canvas = (canvas_buf_color[j].green_h << 3) + (canvas_buf_color[j].green_l);
354
uint8_t green_buf = (copy_buf_color[j].green_h << 3) + (copy_buf_color[j].green_l);
355
uint8_t green_res = (uint16_t)((uint16_t)green_canvas * green_buf) >> 6;
356
canvas_buf_color[j].green_h = (green_res >> 3) & 0x07;
357
canvas_buf_color[j].green_l = green_res & 0x07;
358
# endif /*LV_COLOR_16_SWAP*/
359
360
#elif LV_COLOR_DEPTH == 8
361
canvas_buf_color[j].red = (uint16_t) ((uint16_t) canvas_buf_color[j].red * copy_buf_color[j].red) >> 3;
362
canvas_buf_color[j].green = (uint16_t) ((uint16_t) canvas_buf_color[j].green * copy_buf_color[j].green) >> 3;
363
canvas_buf_color[j].blue = (uint16_t) ((uint16_t) canvas_buf_color[j].blue * copy_buf_color[j].blue) >> 2;
364
#endif
365
}
366
copy_buf_color += w;
367
canvas_buf_color += ext->dsc.header.w;
368
}
369
}
370
371
/**
372
* Draw circle function of the canvas
373
* @param canvas pointer to a canvas object
374
* @param x0 x coordinate of the circle
375
* @param y0 y coordinate of the circle
376
* @param radius radius of the circle
377
* @param color border color of the circle
378
*/
379
void lv_canvas_draw_circle(lv_obj_t * canvas, lv_coord_t x0, lv_coord_t y0, lv_coord_t radius, lv_color_t color)
380
{
381
int x = radius;
382
int y = 0;
383
int err = 0;
384
385
while (x >= y)
386
{
387
lv_canvas_set_px(canvas, x0 + x, y0 + y, color);
388
lv_canvas_set_px(canvas, x0 + y, y0 + x, color);
389
lv_canvas_set_px(canvas, x0 - y, y0 + x, color);
390
lv_canvas_set_px(canvas, x0 - x, y0 + y, color);
391
lv_canvas_set_px(canvas, x0 - x, y0 - y, color);
392
lv_canvas_set_px(canvas, x0 - y, y0 - x, color);
393
lv_canvas_set_px(canvas, x0 + y, y0 - x, color);
394
lv_canvas_set_px(canvas, x0 + x, y0 - y, color);
395
396
if (err <= 0)
397
{
398
y += 1;
399
err += 2*y + 1;
400
}
401
402
if (err > 0)
403
{
404
x -= 1;
405
err -= 2*x + 1;
406
}
407
}
408
}
409
410
/**
411
* Draw line function of the canvas
412
* @param canvas pointer to a canvas object
413
* @param point1 start point of the line
414
* @param point2 end point of the line
415
* @param color color of the line
416
*
417
* NOTE: The lv_canvas_draw_line function originates from https://github.com/jb55/bresenham-line.c.
418
*/
419
/*
420
* NOTE: The lv_canvas_draw_line function originates from https://github.com/jb55/bresenham-line.c.
421
*/
422
void lv_canvas_draw_line(lv_obj_t * canvas, lv_point_t point1, lv_point_t point2, lv_color_t color)
423
{
424
lv_coord_t x0, y0, x1, y1;
425
426
x0 = point1.x;
427
y0 = point1.y;
428
x1 = point2.x;
429
y1 = point2.y;
430
431
int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
432
int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
433
int err = (dx>dy ? dx : -dy)/2, e2;
434
435
for(;;){
436
lv_canvas_set_px(canvas, x0, y0, color);
437
438
if (x0==x1 && y0==y1) break;
439
e2 = err;
440
if (e2 >-dx) { err -= dy; x0 += sx; }
441
if (e2 < dy) { err += dx; y0 += sy; }
442
}
443
}
444
445
/**
446
* Draw triangle function of the canvas
447
* @param canvas pointer to a canvas object
448
* @param points edge points of the triangle
449
* @param color line color of the triangle
450
*/
451
void lv_canvas_draw_triangle(lv_obj_t * canvas, lv_point_t * points, lv_color_t color)
452
{
453
lv_canvas_draw_polygon(canvas, points, 3, color);
454
}
455
456
/**
457
* Draw rectangle function of the canvas
458
* @param canvas pointer to a canvas object
459
* @param points edge points of the rectangle
460
* @param color line color of the rectangle
461
*/
462
void lv_canvas_draw_rect(lv_obj_t * canvas, lv_point_t * points, lv_color_t color)
463
{
464
lv_canvas_draw_polygon(canvas, points, 4, color);
465
}
466
467
/**
468
* Draw polygon function of the canvas
469
* @param canvas pointer to a canvas object
470
* @param points edge points of the polygon
471
* @param size edge count of the polygon
472
* @param color line color of the polygon
473
*/
474
void lv_canvas_draw_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t color)
475
{
476
uint8_t i;
477
478
for(i=0; i < (size - 1); i++) {
479
lv_canvas_draw_line(canvas, points[i], points[i + 1], color);
480
}
481
482
lv_canvas_draw_line(canvas, points[size - 1], points[0], color);
483
}
484
485
/**
486
* Fill polygon function of the canvas
487
* @param canvas pointer to a canvas object
488
* @param points edge points of the polygon
489
* @param size edge count of the polygon
490
* @param boundary_color line color of the polygon
491
* @param fill_color fill color of the polygon
492
*/
493
void lv_canvas_fill_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t boundary_color, lv_color_t fill_color)
494
{
495
uint32_t x = 0, y = 0;
496
uint8_t i;
497
498
for(i=0; i<size; i++) {
499
x += points[i].x;
500
y += points[i].y;
501
}
502
503
x = x / size;
504
y = y / size;
505
506
lv_canvas_boundary_fill4(canvas, (lv_coord_t) x, (lv_coord_t) y, boundary_color, fill_color);
507
}
508
509
/**
510
* Boundary fill function of the canvas
511
* @param canvas pointer to a canvas object
512
* @param x x coordinate of the start position (seed)
513
* @param y y coordinate of the start position (seed)
514
* @param boundary_color edge/boundary color of the area
515
* @param fill_color fill color of the area
516
*/
517
void lv_canvas_boundary_fill4(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t boundary_color, lv_color_t fill_color)
518
{
519
lv_color_t c;
520
521
c = lv_canvas_get_px(canvas, x, y);
522
523
if(c.full != boundary_color.full &&
524
c.full != fill_color.full)
525
{
526
lv_canvas_set_px(canvas, x, y, fill_color);
527
528
lv_canvas_boundary_fill4(canvas, x + 1, y, boundary_color, fill_color);
529
lv_canvas_boundary_fill4(canvas, x, y + 1, boundary_color, fill_color);
530
lv_canvas_boundary_fill4(canvas, x - 1, y, boundary_color, fill_color);
531
lv_canvas_boundary_fill4(canvas, x, y - 1, boundary_color, fill_color);
532
}
533
}
534
535
/**
536
* Flood fill function of the canvas
537
* @param canvas pointer to a canvas object
538
* @param x x coordinate of the start position (seed)
539
* @param y y coordinate of the start position (seed)
540
* @param fill_color fill color of the area
541
* @param bg_color background color of the area
542
*/
543
void lv_canvas_flood_fill(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t fill_color, lv_color_t bg_color)
544
{
545
lv_color_t c;
546
547
c = lv_canvas_get_px(canvas, x, y);
548
549
if(c.full == bg_color.full)
550
{
551
lv_canvas_set_px(canvas, x, y, fill_color);
552
553
lv_canvas_flood_fill(canvas, x+1, y, fill_color, bg_color);
554
lv_canvas_flood_fill(canvas, x, y+1, fill_color, bg_color);
555
lv_canvas_flood_fill(canvas, x-1, y, fill_color, bg_color);
556
lv_canvas_flood_fill(canvas, x, y-1, fill_color, bg_color);
557
}
558
}
559
560
/**********************
561
* STATIC FUNCTIONS
562
**********************/
563
564
/**
565
* Signal function of the canvas
566
* @param canvas pointer to a canvas object
567
* @param sign a signal type from lv_signal_t enum
568
* @param param pointer to a signal specific variable
569
* @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
570
*/
571
static lv_res_t lv_canvas_signal(lv_obj_t * canvas, lv_signal_t sign, void * param)
572
{
573
lv_res_t res;
574
575
/* Include the ancient signal function */
576
res = ancestor_signal(canvas, sign, param);
577
if(res != LV_RES_OK) return res;
578
579
if(sign == LV_SIGNAL_CLEANUP) {
580
/*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/
581
} else if(sign == LV_SIGNAL_GET_TYPE) {
582
lv_obj_type_t * buf = param;
583
uint8_t i;
584
for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/
585
if(buf->type[i] == NULL) break;
586
}
587
buf->type[i] = "lv_canvas";
588
}
589
590
return res;
591
}
592
593
#endif
594
595