1 /**
2  * @file lv_draw_buf.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_draw_buf_private.h"
10 #include "../misc/lv_types.h"
11 #include "../stdlib/lv_string.h"
12 #include "../core/lv_global.h"
13 #include "../misc/lv_math.h"
14 #include "../misc/lv_area_private.h"
15 
16 /*********************
17  *      DEFINES
18  *********************/
19 #define default_handlers LV_GLOBAL_DEFAULT()->draw_buf_handlers
20 #define font_draw_buf_handlers LV_GLOBAL_DEFAULT()->font_draw_buf_handlers
21 #define image_cache_draw_buf_handlers LV_GLOBAL_DEFAULT()->image_cache_draw_buf_handlers
22 
23 /**********************
24  *      TYPEDEFS
25  **********************/
26 
27 /**********************
28  *  STATIC PROTOTYPES
29  **********************/
30 static void * buf_malloc(size_t size, lv_color_format_t color_format);
31 static void buf_free(void * buf);
32 static void * buf_align(void * buf, lv_color_format_t color_format);
33 static void * draw_buf_malloc(const lv_draw_buf_handlers_t * handler, size_t size_bytes,
34                               lv_color_format_t color_format);
35 static void draw_buf_free(const lv_draw_buf_handlers_t * handler, void * buf);
36 static uint32_t width_to_stride(uint32_t w, lv_color_format_t color_format);
37 static uint32_t _calculate_draw_buf_size(uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride);
38 static void draw_buf_get_full_area(const lv_draw_buf_t * draw_buf, lv_area_t * full_area);
39 
40 /**********************
41  *  STATIC VARIABLES
42  **********************/
43 
44 /**********************
45  *      MACROS
46  **********************/
47 
48 /**********************
49  *   GLOBAL FUNCTIONS
50  **********************/
51 
lv_draw_buf_init_handlers(void)52 void lv_draw_buf_init_handlers(void)
53 {
54     lv_draw_buf_init_with_default_handlers(&default_handlers);
55     lv_draw_buf_init_with_default_handlers(&font_draw_buf_handlers);
56     lv_draw_buf_init_with_default_handlers(&image_cache_draw_buf_handlers);
57 }
58 
lv_draw_buf_init_with_default_handlers(lv_draw_buf_handlers_t * handlers)59 void lv_draw_buf_init_with_default_handlers(lv_draw_buf_handlers_t * handlers)
60 {
61     lv_draw_buf_handlers_init(handlers, buf_malloc, buf_free, buf_align, NULL, NULL, width_to_stride);
62 }
63 
lv_draw_buf_handlers_init(lv_draw_buf_handlers_t * handlers,lv_draw_buf_malloc_cb buf_malloc_cb,lv_draw_buf_free_cb buf_free_cb,lv_draw_buf_align_cb align_pointer_cb,lv_draw_buf_cache_operation_cb invalidate_cache_cb,lv_draw_buf_cache_operation_cb flush_cache_cb,lv_draw_buf_width_to_stride_cb width_to_stride_cb)64 void lv_draw_buf_handlers_init(lv_draw_buf_handlers_t * handlers,
65                                lv_draw_buf_malloc_cb buf_malloc_cb,
66                                lv_draw_buf_free_cb buf_free_cb,
67                                lv_draw_buf_align_cb align_pointer_cb,
68                                lv_draw_buf_cache_operation_cb invalidate_cache_cb,
69                                lv_draw_buf_cache_operation_cb flush_cache_cb,
70                                lv_draw_buf_width_to_stride_cb width_to_stride_cb)
71 {
72     lv_memzero(handlers, sizeof(lv_draw_buf_handlers_t));
73     handlers->buf_malloc_cb = buf_malloc_cb;
74     handlers->buf_free_cb = buf_free_cb;
75     handlers->align_pointer_cb = align_pointer_cb;
76     handlers->invalidate_cache_cb = invalidate_cache_cb;
77     handlers->flush_cache_cb = flush_cache_cb;
78     handlers->width_to_stride_cb = width_to_stride_cb;
79 }
80 
lv_draw_buf_get_handlers(void)81 lv_draw_buf_handlers_t * lv_draw_buf_get_handlers(void)
82 {
83     return &default_handlers;
84 }
85 
lv_draw_buf_get_font_handlers(void)86 lv_draw_buf_handlers_t * lv_draw_buf_get_font_handlers(void)
87 {
88     return &font_draw_buf_handlers;
89 }
90 
lv_draw_buf_get_image_handlers(void)91 lv_draw_buf_handlers_t * lv_draw_buf_get_image_handlers(void)
92 {
93     return &image_cache_draw_buf_handlers;
94 }
95 
lv_draw_buf_width_to_stride(uint32_t w,lv_color_format_t color_format)96 uint32_t lv_draw_buf_width_to_stride(uint32_t w, lv_color_format_t color_format)
97 {
98     return lv_draw_buf_width_to_stride_ex(&default_handlers, w, color_format);
99 }
100 
lv_draw_buf_width_to_stride_ex(const lv_draw_buf_handlers_t * handlers,uint32_t w,lv_color_format_t color_format)101 uint32_t lv_draw_buf_width_to_stride_ex(const lv_draw_buf_handlers_t * handlers, uint32_t w,
102                                         lv_color_format_t color_format)
103 {
104     if(handlers->width_to_stride_cb) return handlers->width_to_stride_cb(w, color_format);
105     else return 0;
106 }
107 
lv_draw_buf_align(void * data,lv_color_format_t color_format)108 void * lv_draw_buf_align(void * data, lv_color_format_t color_format)
109 {
110     return lv_draw_buf_align_ex(&default_handlers, data, color_format);
111 }
112 
lv_draw_buf_align_ex(const lv_draw_buf_handlers_t * handlers,void * data,lv_color_format_t color_format)113 void * lv_draw_buf_align_ex(const lv_draw_buf_handlers_t * handlers, void * data, lv_color_format_t color_format)
114 {
115     if(handlers->align_pointer_cb) return handlers->align_pointer_cb(data, color_format);
116     else return NULL;
117 }
118 
lv_draw_buf_invalidate_cache(const lv_draw_buf_t * draw_buf,const lv_area_t * area)119 void lv_draw_buf_invalidate_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area)
120 {
121     LV_ASSERT_NULL(draw_buf);
122     LV_ASSERT_NULL(draw_buf->handlers);
123 
124     const lv_draw_buf_handlers_t * handlers = draw_buf->handlers;
125     if(!handlers->invalidate_cache_cb) {
126         return;
127     }
128 
129     LV_PROFILER_DRAW_BEGIN;
130 
131     lv_area_t full;
132     if(area == NULL) {
133         draw_buf_get_full_area(draw_buf, &full);
134         area = &full;
135     }
136 
137     handlers->invalidate_cache_cb(draw_buf, area);
138     LV_PROFILER_DRAW_END;
139 }
140 
lv_draw_buf_flush_cache(const lv_draw_buf_t * draw_buf,const lv_area_t * area)141 void lv_draw_buf_flush_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area)
142 {
143     LV_ASSERT_NULL(draw_buf);
144     LV_ASSERT_NULL(draw_buf->handlers);
145 
146     const lv_draw_buf_handlers_t * handlers = draw_buf->handlers;
147     if(!handlers->flush_cache_cb) {
148         return;
149     }
150 
151     LV_PROFILER_DRAW_BEGIN;
152 
153     lv_area_t full;
154     if(area == NULL) {
155         draw_buf_get_full_area(draw_buf, &full);
156         area = &full;
157     }
158 
159     handlers->flush_cache_cb(draw_buf, area);
160     LV_PROFILER_DRAW_END;
161 }
162 
lv_draw_buf_clear(lv_draw_buf_t * draw_buf,const lv_area_t * a)163 void lv_draw_buf_clear(lv_draw_buf_t * draw_buf, const lv_area_t * a)
164 {
165     LV_ASSERT_NULL(draw_buf);
166     LV_PROFILER_DRAW_BEGIN;
167 
168     const lv_image_header_t * header = &draw_buf->header;
169     uint32_t stride = header->stride;
170 
171     if(a == NULL) {
172         uint8_t * buf = lv_draw_buf_goto_xy(draw_buf, 0, 0);
173         lv_memzero(buf, header->h * stride);
174         lv_draw_buf_flush_cache(draw_buf, a);
175         LV_PROFILER_DRAW_END;
176         return;
177     }
178 
179     lv_area_t a_draw_buf;
180     a_draw_buf.x1 = 0;
181     a_draw_buf.y1 = 0;
182     a_draw_buf.x2 = draw_buf->header.w - 1;
183     a_draw_buf.y2 = draw_buf->header.h - 1;
184 
185     lv_area_t a_clipped;
186     if(!lv_area_intersect(&a_clipped, a, &a_draw_buf)) {
187         LV_PROFILER_DRAW_END;
188         return;
189     }
190 
191     if(lv_area_get_width(&a_clipped) <= 0) {
192         LV_PROFILER_DRAW_END;
193         return;
194     }
195 
196     if(lv_area_get_height(&a_clipped) <= 0) {
197         LV_PROFILER_DRAW_END;
198         return;
199     }
200 
201     uint8_t * buf = lv_draw_buf_goto_xy(draw_buf, a_clipped.x1, a_clipped.y1);
202     uint8_t bpp = lv_color_format_get_bpp(header->cf);
203     uint32_t line_length = (lv_area_get_width(&a_clipped) * bpp + 7) >> 3;
204     int32_t y;
205     for(y = a_clipped.y1; y <= a_clipped.y2; y++) {
206         lv_memzero(buf, line_length);
207         buf += stride;
208     }
209     lv_draw_buf_flush_cache(draw_buf, a);
210     LV_PROFILER_DRAW_END;
211 }
212 
lv_draw_buf_copy(lv_draw_buf_t * dest,const lv_area_t * dest_area,const lv_draw_buf_t * src,const lv_area_t * src_area)213 void lv_draw_buf_copy(lv_draw_buf_t * dest, const lv_area_t * dest_area,
214                       const lv_draw_buf_t * src, const lv_area_t * src_area)
215 {
216     LV_PROFILER_DRAW_BEGIN;
217     uint8_t * dest_bufc;
218     uint8_t * src_bufc;
219     int32_t line_width;
220 
221     /*Source and dest color format must be same. Color conversion is not supported yet.*/
222     LV_ASSERT_FORMAT_MSG(dest->header.cf == src->header.cf, "Color format mismatch: %d != %d",
223                          dest->header.cf, src->header.cf);
224 
225     if(dest_area == NULL) line_width = dest->header.w;
226     else line_width = lv_area_get_width(dest_area);
227 
228     /* For indexed image, copy the palette if we are copying full image area*/
229     if(dest_area == NULL || src_area == NULL) {
230         if(LV_COLOR_FORMAT_IS_INDEXED(dest->header.cf)) {
231             lv_memcpy(dest->data, src->data, LV_COLOR_INDEXED_PALETTE_SIZE(dest->header.cf) * sizeof(lv_color32_t));
232         }
233     }
234 
235     /*Check source and dest area have same width*/
236     if((src_area == NULL && line_width != src->header.w) || \
237        (src_area != NULL && line_width != lv_area_get_width(src_area))) {
238         LV_ASSERT_MSG(0, "Source and destination areas have different width");
239         LV_PROFILER_DRAW_END;
240         return;
241     }
242 
243     if(src_area) src_bufc = lv_draw_buf_goto_xy(src, src_area->x1, src_area->y1);
244     else src_bufc = lv_draw_buf_goto_xy(src, 0, 0);
245 
246     if(dest_area) dest_bufc = lv_draw_buf_goto_xy(dest, dest_area->x1, dest_area->y1);
247     else dest_bufc = lv_draw_buf_goto_xy(dest, 0, 0);
248 
249     int32_t start_y, end_y;
250     if(dest_area) {
251         start_y = dest_area->y1;
252         end_y = dest_area->y2;
253     }
254     else {
255         start_y = 0;
256         end_y = dest->header.h - 1;
257     }
258 
259     uint32_t dest_stride = dest->header.stride;
260     uint32_t src_stride = src->header.stride;
261     uint32_t line_bytes = (line_width * lv_color_format_get_bpp(dest->header.cf) + 7) >> 3;
262 
263     for(; start_y <= end_y; start_y++) {
264         lv_memcpy(dest_bufc, src_bufc, line_bytes);
265         dest_bufc += dest_stride;
266         src_bufc += src_stride;
267     }
268     LV_PROFILER_DRAW_END;
269 }
270 
lv_draw_buf_init(lv_draw_buf_t * draw_buf,uint32_t w,uint32_t h,lv_color_format_t cf,uint32_t stride,void * data,uint32_t data_size)271 lv_result_t lv_draw_buf_init(lv_draw_buf_t * draw_buf, uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride,
272                              void * data, uint32_t data_size)
273 {
274     LV_ASSERT_NULL(draw_buf);
275     if(draw_buf == NULL) return LV_RESULT_INVALID;
276 
277     lv_memzero(draw_buf, sizeof(lv_draw_buf_t));
278     if(stride == 0) stride = lv_draw_buf_width_to_stride(w, cf);
279     if(stride * h > data_size) {
280         LV_LOG_WARN("Data size too small, required: %" LV_PRId32 ", provided: %" LV_PRId32, stride * h,
281                     data_size);
282         return LV_RESULT_INVALID;
283     }
284 
285     lv_image_header_t * header = &draw_buf->header;
286     header->w = w;
287     header->h = h;
288     header->cf = cf;
289     header->stride = stride;
290     header->flags = 0;
291     header->magic = LV_IMAGE_HEADER_MAGIC;
292 
293     draw_buf->data = data;
294     draw_buf->unaligned_data = data;
295     draw_buf->handlers = &default_handlers;
296     draw_buf->data_size = data_size;
297     if(lv_draw_buf_align(data, cf) != draw_buf->unaligned_data) {
298         LV_LOG_WARN("Data is not aligned, ignored");
299     }
300     return LV_RESULT_OK;
301 }
302 
lv_draw_buf_create(uint32_t w,uint32_t h,lv_color_format_t cf,uint32_t stride)303 lv_draw_buf_t * lv_draw_buf_create(uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride)
304 {
305     return lv_draw_buf_create_ex(&default_handlers, w, h, cf, stride);
306 }
307 
lv_draw_buf_create_ex(const lv_draw_buf_handlers_t * handlers,uint32_t w,uint32_t h,lv_color_format_t cf,uint32_t stride)308 lv_draw_buf_t * lv_draw_buf_create_ex(const lv_draw_buf_handlers_t * handlers, uint32_t w, uint32_t h,
309                                       lv_color_format_t cf, uint32_t stride)
310 {
311     LV_PROFILER_DRAW_BEGIN;
312     lv_draw_buf_t * draw_buf = lv_malloc_zeroed(sizeof(lv_draw_buf_t));
313     LV_ASSERT_MALLOC(draw_buf);
314     if(draw_buf == NULL) {
315         LV_PROFILER_DRAW_END;
316         return NULL;
317     }
318     if(stride == 0) stride = lv_draw_buf_width_to_stride(w, cf);
319 
320     uint32_t size = _calculate_draw_buf_size(w, h, cf, stride);
321 
322     void * buf = draw_buf_malloc(handlers, size, cf);
323     /*Do not assert here as LVGL or the app might just want to try creating a draw_buf*/
324     if(buf == NULL) {
325         LV_LOG_WARN("No memory: %"LV_PRIu32"x%"LV_PRIu32", cf: %d, stride: %"LV_PRIu32", %"LV_PRIu32"Byte, ",
326                     w, h, cf, stride, size);
327         lv_free(draw_buf);
328         LV_PROFILER_DRAW_END;
329         return NULL;
330     }
331 
332     draw_buf->header.w = w;
333     draw_buf->header.h = h;
334     draw_buf->header.cf = cf;
335     draw_buf->header.flags = LV_IMAGE_FLAGS_MODIFIABLE | LV_IMAGE_FLAGS_ALLOCATED;
336     draw_buf->header.stride = stride;
337     draw_buf->header.magic = LV_IMAGE_HEADER_MAGIC;
338     draw_buf->data = lv_draw_buf_align(buf, cf);
339     draw_buf->unaligned_data = buf;
340     draw_buf->data_size = size;
341     draw_buf->handlers = handlers;
342     LV_PROFILER_DRAW_END;
343     return draw_buf;
344 }
345 
lv_draw_buf_dup(const lv_draw_buf_t * draw_buf)346 lv_draw_buf_t * lv_draw_buf_dup(const lv_draw_buf_t * draw_buf)
347 {
348     return lv_draw_buf_dup_ex(&default_handlers, draw_buf);
349 }
350 
lv_draw_buf_dup_ex(const lv_draw_buf_handlers_t * handlers,const lv_draw_buf_t * draw_buf)351 lv_draw_buf_t * lv_draw_buf_dup_ex(const lv_draw_buf_handlers_t * handlers, const lv_draw_buf_t * draw_buf)
352 {
353     LV_PROFILER_DRAW_BEGIN;
354     const lv_image_header_t * header = &draw_buf->header;
355     lv_draw_buf_t * new_buf = lv_draw_buf_create_ex(handlers, header->w, header->h, header->cf, header->stride);
356     if(new_buf == NULL) {
357         LV_PROFILER_DRAW_END;
358         return NULL;
359     }
360 
361     new_buf->header.flags = draw_buf->header.flags;
362     new_buf->header.flags |= LV_IMAGE_FLAGS_MODIFIABLE | LV_IMAGE_FLAGS_ALLOCATED;
363 
364     /*Choose the smaller size to copy*/
365     uint32_t size = LV_MIN(draw_buf->data_size, new_buf->data_size);
366 
367     /*Copy image data*/
368     lv_memcpy(new_buf->data, draw_buf->data, size);
369     LV_PROFILER_DRAW_END;
370     return new_buf;
371 }
372 
lv_draw_buf_reshape(lv_draw_buf_t * draw_buf,lv_color_format_t cf,uint32_t w,uint32_t h,uint32_t stride)373 lv_draw_buf_t * lv_draw_buf_reshape(lv_draw_buf_t * draw_buf, lv_color_format_t cf, uint32_t w, uint32_t h,
374                                     uint32_t stride)
375 {
376     if(draw_buf == NULL) return NULL;
377     LV_PROFILER_DRAW_BEGIN;
378 
379     /*If color format is unknown, keep using the original color format.*/
380     if(cf == LV_COLOR_FORMAT_UNKNOWN) cf = draw_buf->header.cf;
381     if(stride == 0) stride = lv_draw_buf_width_to_stride(w, cf);
382 
383     uint32_t size = _calculate_draw_buf_size(w, h, cf, stride);
384 
385     if(size > draw_buf->data_size) {
386         LV_LOG_TRACE("Draw buf too small for new shape");
387         LV_PROFILER_DRAW_END;
388         return NULL;
389     }
390 
391     draw_buf->header.cf = cf;
392     draw_buf->header.w = w;
393     draw_buf->header.h = h;
394     draw_buf->header.stride = stride;
395 
396     LV_PROFILER_DRAW_END;
397     return draw_buf;
398 }
399 
lv_draw_buf_destroy(lv_draw_buf_t * draw_buf)400 void lv_draw_buf_destroy(lv_draw_buf_t * draw_buf)
401 {
402     LV_ASSERT_NULL(draw_buf);
403     if(draw_buf == NULL) return;
404     LV_PROFILER_DRAW_BEGIN;
405 
406     if(draw_buf->header.flags & LV_IMAGE_FLAGS_ALLOCATED) {
407         LV_ASSERT_NULL(draw_buf->handlers);
408 
409         const lv_draw_buf_handlers_t * handlers = draw_buf->handlers;
410         draw_buf_free(handlers, draw_buf->unaligned_data);
411         lv_free(draw_buf);
412     }
413     else {
414         LV_LOG_ERROR("draw buffer is not allocated, ignored");
415     }
416     LV_PROFILER_DRAW_END;
417 }
418 
lv_draw_buf_goto_xy(const lv_draw_buf_t * buf,uint32_t x,uint32_t y)419 void * lv_draw_buf_goto_xy(const lv_draw_buf_t * buf, uint32_t x, uint32_t y)
420 {
421     LV_ASSERT_NULL(buf);
422     if(buf == NULL) return NULL;
423 
424     uint8_t * data = buf->data;
425 
426     /*Skip palette*/
427     data += LV_COLOR_INDEXED_PALETTE_SIZE(buf->header.cf) * sizeof(lv_color32_t);
428     data += buf->header.stride * y;
429 
430     if(x == 0) return data;
431 
432     return data + x * lv_color_format_get_bpp(buf->header.cf) / 8;
433 }
434 
lv_draw_buf_adjust_stride(lv_draw_buf_t * src,uint32_t stride)435 lv_result_t lv_draw_buf_adjust_stride(lv_draw_buf_t * src, uint32_t stride)
436 {
437     LV_ASSERT_NULL(src);
438     LV_ASSERT_NULL(src->data);
439     if(src == NULL) return LV_RESULT_INVALID;
440     if(src->data == NULL) return LV_RESULT_INVALID;
441     LV_PROFILER_DRAW_BEGIN;
442 
443     const lv_image_header_t * header = &src->header;
444     uint32_t w = header->w;
445     uint32_t h = header->h;
446 
447     if(!lv_draw_buf_has_flag(src, LV_IMAGE_FLAGS_MODIFIABLE)) {
448         LV_PROFILER_DRAW_END;
449         return LV_RESULT_INVALID;
450     }
451 
452     /*Use global stride*/
453     if(stride == 0) stride = lv_draw_buf_width_to_stride(w, header->cf);
454 
455     /*Check if stride already match*/
456     if(header->stride == stride) {
457         LV_PROFILER_DRAW_END;
458         return LV_RESULT_OK;
459     }
460 
461     /*Calculate the minimal stride allowed from bpp*/
462     uint32_t bpp = lv_color_format_get_bpp(header->cf);
463     uint32_t min_stride = (w * bpp + 7) >> 3;
464     if(stride < min_stride) {
465         LV_LOG_WARN("New stride is too small. min: %" LV_PRId32, min_stride);
466         LV_PROFILER_DRAW_END;
467         return LV_RESULT_INVALID;
468     }
469 
470     /*Check if buffer has enough space. */
471     uint32_t new_size = _calculate_draw_buf_size(w, h, header->cf, stride);
472     if(new_size > src->data_size) {
473         LV_PROFILER_DRAW_END;
474         return LV_RESULT_INVALID;
475     }
476 
477     uint32_t offset = LV_COLOR_INDEXED_PALETTE_SIZE(header->cf) * 4;
478 
479     if(stride > header->stride) {
480         /*Copy from the last line to the first*/
481         uint8_t * src_data = src->data + offset + header->stride * (h - 1);
482         uint8_t * dst_data = src->data + offset + stride * (h - 1);
483         for(uint32_t y = 0; y < h; y++) {
484             lv_memmove(dst_data, src_data, min_stride);
485             src_data -= header->stride;
486             dst_data -= stride;
487         }
488     }
489     else {
490         /*Copy from the first line to the last*/
491         uint8_t * src_data = src->data + offset;
492         uint8_t * dst_data = src->data + offset;
493         for(uint32_t y = 0; y < h; y++) {
494             lv_memmove(dst_data, src_data, min_stride);
495             src_data += header->stride;
496             dst_data += stride;
497         }
498     }
499 
500     src->header.stride = stride;
501 
502     LV_PROFILER_DRAW_END;
503     return LV_RESULT_OK;
504 }
505 
lv_draw_buf_premultiply(lv_draw_buf_t * draw_buf)506 lv_result_t lv_draw_buf_premultiply(lv_draw_buf_t * draw_buf)
507 {
508     LV_ASSERT_NULL(draw_buf);
509     if(draw_buf == NULL) return LV_RESULT_INVALID;
510 
511     if(draw_buf->header.flags & LV_IMAGE_FLAGS_PREMULTIPLIED) return LV_RESULT_INVALID;
512     if((draw_buf->header.flags & LV_IMAGE_FLAGS_MODIFIABLE) == 0) {
513         LV_LOG_WARN("draw buf is not modifiable: 0x%04x", draw_buf->header.flags);
514         return LV_RESULT_INVALID;
515     }
516     LV_PROFILER_DRAW_BEGIN;
517 
518     /*Premultiply color with alpha, do case by case by judging color format*/
519     lv_color_format_t cf = draw_buf->header.cf;
520     if(LV_COLOR_FORMAT_IS_INDEXED(cf)) {
521         int size = LV_COLOR_INDEXED_PALETTE_SIZE(cf);
522         lv_color32_t * palette = (lv_color32_t *)draw_buf->data;
523         for(int i = 0; i < size; i++) {
524             lv_color_premultiply(&palette[i]);
525         }
526     }
527     else if(cf == LV_COLOR_FORMAT_ARGB8888) {
528         uint32_t h = draw_buf->header.h;
529         uint32_t w = draw_buf->header.w;
530         uint32_t stride = draw_buf->header.stride;
531         uint8_t * line = (uint8_t *)draw_buf->data;
532         for(uint32_t y = 0; y < h; y++) {
533             lv_color32_t * pixel = (lv_color32_t *)line;
534             for(uint32_t x = 0; x < w; x++) {
535                 lv_color_premultiply(pixel);
536                 pixel++;
537             }
538             line += stride;
539         }
540     }
541     else if(cf == LV_COLOR_FORMAT_RGB565A8) {
542         uint32_t h = draw_buf->header.h;
543         uint32_t w = draw_buf->header.w;
544         uint32_t stride = draw_buf->header.stride;
545         uint32_t alpha_stride = stride / 2;
546         uint8_t * line = (uint8_t *)draw_buf->data;
547         lv_opa_t * alpha = (lv_opa_t *)(line + stride * h);
548         for(uint32_t y = 0; y < h; y++) {
549             lv_color16_t * pixel = (lv_color16_t *)line;
550             for(uint32_t x = 0; x < w; x++) {
551                 lv_color16_premultiply(pixel, alpha[x]);
552                 pixel++;
553             }
554             line += stride;
555             alpha += alpha_stride;
556         }
557     }
558     else if(cf == LV_COLOR_FORMAT_ARGB8565) {
559         uint32_t h = draw_buf->header.h;
560         uint32_t w = draw_buf->header.w;
561         uint32_t stride = draw_buf->header.stride;
562         uint8_t * line = (uint8_t *)draw_buf->data;
563         for(uint32_t y = 0; y < h; y++) {
564             uint8_t * pixel = line;
565             for(uint32_t x = 0; x < w; x++) {
566                 uint8_t alpha = pixel[2];
567                 lv_color16_premultiply((lv_color16_t *)pixel, alpha);
568                 pixel += 3;
569             }
570             line += stride;
571         }
572     }
573     else if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(cf)) {
574         /*Pass*/
575     }
576     else {
577         LV_LOG_WARN("draw buf has no alpha, cf: %d", cf);
578     }
579 
580     draw_buf->header.flags |= LV_IMAGE_FLAGS_PREMULTIPLIED;
581 
582     LV_PROFILER_DRAW_END;
583     return LV_RESULT_OK;
584 }
585 
lv_draw_buf_set_palette(lv_draw_buf_t * draw_buf,uint8_t index,lv_color32_t color)586 void lv_draw_buf_set_palette(lv_draw_buf_t * draw_buf, uint8_t index, lv_color32_t color)
587 {
588     LV_ASSERT_NULL(draw_buf);
589     if(draw_buf == NULL) return;
590 
591     if(!LV_COLOR_FORMAT_IS_INDEXED(draw_buf->header.cf)) {
592         LV_LOG_WARN("Not indexed color format");
593         return;
594     }
595 
596     lv_color32_t * palette = (lv_color32_t *)draw_buf->data;
597     palette[index] = color;
598 }
599 
lv_draw_buf_has_flag(const lv_draw_buf_t * draw_buf,lv_image_flags_t flag)600 bool lv_draw_buf_has_flag(const lv_draw_buf_t * draw_buf, lv_image_flags_t flag)
601 {
602     return draw_buf->header.flags & flag;
603 }
604 
lv_draw_buf_set_flag(lv_draw_buf_t * draw_buf,lv_image_flags_t flag)605 void lv_draw_buf_set_flag(lv_draw_buf_t * draw_buf, lv_image_flags_t flag)
606 {
607     draw_buf->header.flags |= flag;
608 }
609 
lv_draw_buf_clear_flag(lv_draw_buf_t * draw_buf,lv_image_flags_t flag)610 void lv_draw_buf_clear_flag(lv_draw_buf_t * draw_buf, lv_image_flags_t flag)
611 {
612     draw_buf->header.flags &= ~flag;
613 }
614 
lv_draw_buf_from_image(lv_draw_buf_t * buf,const lv_image_dsc_t * img)615 void lv_draw_buf_from_image(lv_draw_buf_t * buf, const lv_image_dsc_t * img)
616 {
617     lv_draw_buf_init(buf, img->header.w, img->header.h, img->header.cf, img->header.stride,
618                      (void *)img->data, img->data_size);
619     buf->header.flags = img->header.flags;
620 }
621 
lv_draw_buf_to_image(const lv_draw_buf_t * buf,lv_image_dsc_t * img)622 void lv_draw_buf_to_image(const lv_draw_buf_t * buf, lv_image_dsc_t * img)
623 {
624     lv_memcpy((void *)img, buf, sizeof(lv_image_dsc_t));
625 }
626 
lv_image_buf_set_palette(lv_image_dsc_t * dsc,uint8_t id,lv_color32_t c)627 void lv_image_buf_set_palette(lv_image_dsc_t * dsc, uint8_t id, lv_color32_t c)
628 {
629     LV_LOG_WARN("Deprecated API, use lv_draw_buf_set_palette instead.");
630     lv_draw_buf_set_palette((lv_draw_buf_t *)dsc, id, c);
631 }
632 
lv_image_buf_free(lv_image_dsc_t * dsc)633 void lv_image_buf_free(lv_image_dsc_t * dsc)
634 {
635     LV_LOG_WARN("Deprecated API, use lv_draw_buf_destroy instead.");
636     if(dsc != NULL) {
637         if(dsc->data != NULL)
638             lv_free((void *)dsc->data);
639 
640         lv_free((void *)dsc);
641     }
642 }
643 
644 /**********************
645  *   STATIC FUNCTIONS
646  **********************/
647 
buf_malloc(size_t size_bytes,lv_color_format_t color_format)648 static void * buf_malloc(size_t size_bytes, lv_color_format_t color_format)
649 {
650     LV_UNUSED(color_format);
651 
652     /*Allocate larger memory to be sure it can be aligned as needed*/
653     size_bytes += LV_DRAW_BUF_ALIGN - 1;
654     return lv_malloc(size_bytes);
655 }
656 
buf_free(void * buf)657 static void buf_free(void * buf)
658 {
659     lv_free(buf);
660 }
661 
buf_align(void * buf,lv_color_format_t color_format)662 static void * buf_align(void * buf, lv_color_format_t color_format)
663 {
664     LV_UNUSED(color_format);
665 
666     uint8_t * buf_u8 = buf;
667     if(buf_u8) {
668         buf_u8 = (uint8_t *)LV_ROUND_UP((lv_uintptr_t)buf_u8, LV_DRAW_BUF_ALIGN);
669     }
670     return buf_u8;
671 }
672 
width_to_stride(uint32_t w,lv_color_format_t color_format)673 static uint32_t width_to_stride(uint32_t w, lv_color_format_t color_format)
674 {
675     uint32_t width_byte;
676     width_byte = w * lv_color_format_get_bpp(color_format);
677     width_byte = (width_byte + 7) >> 3; /*Round up*/
678 
679     return LV_ROUND_UP(width_byte, LV_DRAW_BUF_STRIDE_ALIGN);
680 }
681 
draw_buf_malloc(const lv_draw_buf_handlers_t * handlers,size_t size_bytes,lv_color_format_t color_format)682 static void * draw_buf_malloc(const lv_draw_buf_handlers_t * handlers, size_t size_bytes,
683                               lv_color_format_t color_format)
684 {
685     if(handlers->buf_malloc_cb) return handlers->buf_malloc_cb(size_bytes, color_format);
686     else return NULL;
687 }
688 
draw_buf_free(const lv_draw_buf_handlers_t * handlers,void * buf)689 static void draw_buf_free(const lv_draw_buf_handlers_t * handlers, void * buf)
690 {
691     if(handlers->buf_free_cb)
692         handlers->buf_free_cb(buf);
693 }
694 
695 /**
696  * For given width, height, color format, and stride, calculate the size needed for a new draw buffer.
697  */
_calculate_draw_buf_size(uint32_t w,uint32_t h,lv_color_format_t cf,uint32_t stride)698 static uint32_t _calculate_draw_buf_size(uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride)
699 {
700     uint32_t size;
701 
702     if(stride == 0) stride = lv_draw_buf_width_to_stride(w, cf);
703 
704     size = stride * h;
705     if(cf == LV_COLOR_FORMAT_RGB565A8) {
706         size += (stride / 2) * h; /*A8 mask*/
707     }
708     else if(LV_COLOR_FORMAT_IS_INDEXED(cf)) {
709         /*@todo we have to include palette right before image data*/
710         size += LV_COLOR_INDEXED_PALETTE_SIZE(cf) * 4;
711     }
712 
713     return size;
714 }
715 
draw_buf_get_full_area(const lv_draw_buf_t * draw_buf,lv_area_t * full_area)716 static void draw_buf_get_full_area(const lv_draw_buf_t * draw_buf, lv_area_t * full_area)
717 {
718     const lv_image_header_t * header = &draw_buf->header;
719     lv_area_set(full_area, 0, 0, header->w - 1, header->h - 1);
720 }
721