1 /**
2  * @file lv_draw_sw_blend.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_draw_sw.h"
10 #include "../../misc/lv_math.h"
11 #include "../../hal/lv_hal_disp.h"
12 #include "../../core/lv_refr.h"
13 
14 /*********************
15  *      DEFINES
16  *********************/
17 
18 /**********************
19  *      TYPEDEFS
20  **********************/
21 
22 /**********************
23  *  STATIC PROTOTYPES
24  **********************/
25 
26 static void fill_set_px(lv_color_t * dest_buf, const lv_area_t * blend_area, lv_coord_t dest_stride,
27                         lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stide);
28 LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_area_t * dest_area,
29                                               lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride);
30 #if LV_DRAW_COMPLEX
31 static void fill_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, lv_color_t color,
32                          lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride, lv_blend_mode_t blend_mode);
33 #endif  /*LV_DRAW_COMPLEX*/
34 
35 static void map_set_px(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
36                        const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride);
37 
38 LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
39                                              const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride);
40 
41 #if LV_DRAW_COMPLEX
42 static void map_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
43                         const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa,
44                         const lv_opa_t * mask, lv_coord_t mask_stride, lv_blend_mode_t blend_mode);
45 
46 static inline lv_color_t color_blend_true_color_additive(lv_color_t fg, lv_color_t bg, lv_opa_t opa);
47 static inline lv_color_t color_blend_true_color_subtractive(lv_color_t fg, lv_color_t bg, lv_opa_t opa);
48 static inline lv_color_t color_blend_true_color_multiply(lv_color_t fg, lv_color_t bg, lv_opa_t opa);
49 #endif /*LV_DRAW_COMPLEX*/
50 
51 /**********************
52  *  STATIC VARIABLES
53  **********************/
54 
55 /**********************
56  *      MACROS
57  **********************/
58 #if LV_COLOR_SCREEN_TRANSP == 0
59 #define FILL_NORMAL_MASK_PX(color)                                                          \
60     if(*mask == LV_OPA_COVER) *dest_buf = color;                                 \
61     else *dest_buf = lv_color_mix(color, *dest_buf, *mask);            \
62     mask++;                                                         \
63     dest_buf++;
64 
65 #else
66 #define FILL_NORMAL_MASK_PX(color)                                               \
67     if(*mask == LV_OPA_COVER) *dest_buf = color;                                 \
68     else if(disp->driver->screen_transp) lv_color_mix_with_alpha(*dest_buf, dest_buf->ch.alpha, color, *mask, dest_buf, &dest_buf->ch.alpha);           \
69     else *dest_buf = lv_color_mix(color, *dest_buf, *mask);            \
70     mask++;                                                         \
71     dest_buf++;
72 #endif
73 
74 #define MAP_NORMAL_MASK_PX(x)                                                          \
75     if(*mask_tmp_x) {          \
76         if(*mask_tmp_x == LV_OPA_COVER) dest_buf[x] = src_buf[x];                                 \
77         else dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], *mask_tmp_x);            \
78     }                                                                                               \
79     mask_tmp_x++;
80 
81 #define MAP_NORMAL_MASK_PX_SCR_TRANSP(x)                        \
82     if(*mask_tmp_x) {          \
83         if(*mask_tmp_x == LV_OPA_COVER) dest_buf[x] = src_buf[x];                                 \
84         else if(disp->driver->screen_transp) lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha,              \
85                                                                          src_buf[x], *mask_tmp_x, &dest_buf[x], &dest_buf[x].ch.alpha);                  \
86         else dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], *mask_tmp_x);            \
87     }                                                                                               \
88     mask_tmp_x++;
89 
90 
91 /**********************
92  *   GLOBAL FUNCTIONS
93  **********************/
94 
lv_draw_sw_blend(lv_draw_ctx_t * draw_ctx,const lv_draw_sw_blend_dsc_t * dsc)95 void lv_draw_sw_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
96 {
97     /*Do not draw transparent things*/
98     if(dsc->opa <= LV_OPA_MIN) return;
99 
100     lv_area_t blend_area;
101     if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return;
102 
103     if(draw_ctx->wait_for_finish) draw_ctx->wait_for_finish(draw_ctx);
104 
105     ((lv_draw_sw_ctx_t *)draw_ctx)->blend(draw_ctx, dsc);
106 }
107 
lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx,const lv_draw_sw_blend_dsc_t * dsc)108 LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
109 {
110     const lv_opa_t * mask;
111     if(dsc->mask_buf == NULL) mask = NULL;
112     if(dsc->mask_buf && dsc->mask_res == LV_DRAW_MASK_RES_TRANSP) return;
113     else if(dsc->mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask = NULL;
114     else mask = dsc->mask_buf;
115 
116     lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
117 
118     lv_area_t blend_area;
119     if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return;
120 
121     lv_disp_t * disp = _lv_refr_get_disp_refreshing();
122     lv_color_t * dest_buf = draw_ctx->buf;
123     if(disp->driver->set_px_cb == NULL) {
124         dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1);
125     }
126 
127     const lv_color_t * src_buf = dsc->src_buf;
128     lv_coord_t src_stride;
129     if(src_buf) {
130         src_stride = lv_area_get_width(dsc->blend_area);
131         src_buf += src_stride * (blend_area.y1 - dsc->blend_area->y1) + (blend_area.x1 - dsc->blend_area->x1);
132     }
133     else {
134         src_stride = 0;
135     }
136 
137     lv_coord_t mask_stride;
138     if(mask) {
139         mask_stride = lv_area_get_width(dsc->mask_area);
140         mask += mask_stride * (dsc->mask_area->y1 - blend_area.y1) + (dsc->mask_area->x1 - blend_area.x1);
141     }
142     else {
143         mask_stride = 0;
144     }
145 
146     lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
147 
148 
149     if(disp->driver->set_px_cb) {
150         if(dsc->src_buf == NULL) {
151             fill_set_px(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride);
152         }
153         else {
154             map_set_px(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride);
155         }
156     }
157     else if(dsc->src_buf == NULL) {
158         if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
159             fill_normal(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride);
160         }
161 #if LV_DRAW_COMPLEX
162         else {
163             fill_blended(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride, dsc->blend_mode);
164         }
165 #endif
166     }
167     else {
168         if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
169             map_normal(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride);
170         }
171 #if LV_DRAW_COMPLEX
172         else {
173             map_blended(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride, dsc->blend_mode);
174         }
175 #endif
176     }
177 }
178 
179 
180 /**********************
181  *   STATIC FUNCTIONS
182  **********************/
183 
fill_set_px(lv_color_t * dest_buf,const lv_area_t * blend_area,lv_coord_t dest_stride,lv_color_t color,lv_opa_t opa,const lv_opa_t * mask,lv_coord_t mask_stide)184 static void fill_set_px(lv_color_t * dest_buf, const lv_area_t * blend_area, lv_coord_t dest_stride,
185                         lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stide)
186 {
187     lv_disp_t * disp = _lv_refr_get_disp_refreshing();
188 
189     int32_t x;
190     int32_t y;
191 
192     if(mask == NULL) {
193         for(y = blend_area->y1; y <= blend_area->y2; y++) {
194             for(x = blend_area->x1; x <= blend_area->x2; x++) {
195                 disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, x, y, color, opa);
196             }
197         }
198     }
199     else {
200         int32_t w = lv_area_get_width(blend_area);
201         int32_t h = lv_area_get_height(blend_area);
202 
203         for(y = 0; y < h; y++) {
204             for(x = 0; x < w; x++) {
205                 if(mask[x]) {
206                     disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, blend_area->x1 + x, blend_area->y1 + y, color,
207                                             (uint32_t)((uint32_t)opa * mask[x]) >> 8);
208                 }
209             }
210             mask += mask_stide;
211         }
212     }
213 }
214 
fill_normal(lv_color_t * dest_buf,const lv_area_t * dest_area,lv_coord_t dest_stride,lv_color_t color,lv_opa_t opa,const lv_opa_t * mask,lv_coord_t mask_stride)215 LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_area_t * dest_area,
216                                               lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride)
217 {
218     lv_disp_t * disp = _lv_refr_get_disp_refreshing();
219     int32_t w = lv_area_get_width(dest_area);
220     int32_t h = lv_area_get_height(dest_area);
221 
222     int32_t x;
223     int32_t y;
224 
225     /*No mask*/
226     if(mask == NULL) {
227         if(opa >= LV_OPA_MAX) {
228             for(y = 0; y < h; y++) {
229                 lv_color_fill(dest_buf, color, w);
230                 dest_buf += dest_stride;
231             }
232         }
233         /*Has opacity*/
234         else {
235             lv_color_t last_dest_color = lv_color_black();
236             lv_color_t last_res_color = lv_color_mix(color, last_dest_color, opa);
237 
238             uint16_t color_premult[3];
239             lv_color_premult(color, opa, color_premult);
240             lv_opa_t opa_inv = 255 - opa;
241 
242             for(y = 0; y < h; y++) {
243                 for(x = 0; x < w; x++) {
244                     if(last_dest_color.full != dest_buf[x].full) {
245                         last_dest_color = dest_buf[x];
246 
247 #if LV_COLOR_SCREEN_TRANSP
248                         if(disp->driver->screen_transp) {
249                             lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, color, opa, &last_res_color,
250                                                     &last_res_color.ch.alpha);
251                         }
252                         else
253 #else
254                         LV_UNUSED(disp);
255 #endif
256                         {
257                             last_res_color = lv_color_mix_premult(color_premult, dest_buf[x], opa_inv);
258                         }
259                     }
260                     dest_buf[x] = last_res_color;
261                 }
262                 dest_buf += dest_stride;
263             }
264         }
265     }
266     /*Masked*/
267     else {
268 #if LV_COLOR_DEPTH == 16
269         uint32_t c32 = color.full + ((uint32_t)color.full << 16);
270 #endif
271         /*Only the mask matters*/
272         if(opa >= LV_OPA_MAX) {
273             int32_t x_end4 = w - 4;
274             for(y = 0; y < h; y++) {
275                 for(x = 0; x < w && ((lv_uintptr_t)(mask) & 0x3); x++) {
276                     FILL_NORMAL_MASK_PX(color)
277                 }
278 
279                 for(; x <= x_end4; x += 4) {
280                     uint32_t mask32 = *((uint32_t *)mask);
281                     if(mask32 == 0xFFFFFFFF) {
282 #if LV_COLOR_DEPTH == 16
283                         if((lv_uintptr_t)dest_buf & 0x3) {
284                             *(dest_buf + 0) = color;
285                             uint32_t * d = (uint32_t *)(dest_buf + 1);
286                             *d = c32;
287                             *(dest_buf + 3) = color;
288                         }
289                         else {
290                             uint32_t * d = (uint32_t *)dest_buf;
291                             *d = c32;
292                             *(d + 1) = c32;
293                         }
294 #else
295                         dest_buf[0] = color;
296                         dest_buf[1] = color;
297                         dest_buf[2] = color;
298                         dest_buf[3] = color;
299 #endif
300                         dest_buf += 4;
301                         mask += 4;
302                     }
303                     else if(mask32) {
304                         FILL_NORMAL_MASK_PX(color)
305                         FILL_NORMAL_MASK_PX(color)
306                         FILL_NORMAL_MASK_PX(color)
307                         FILL_NORMAL_MASK_PX(color)
308                     }
309                     else {
310                         mask += 4;
311                         dest_buf += 4;
312                     }
313                 }
314 
315                 for(; x < w ; x++) {
316                     FILL_NORMAL_MASK_PX(color)
317                 }
318                 dest_buf += (dest_stride - w);
319                 mask += (mask_stride - w);
320             }
321         }
322         /*With opacity*/
323         else {
324             /*Buffer the result color to avoid recalculating the same color*/
325             lv_color_t last_dest_color;
326             lv_color_t last_res_color;
327             lv_opa_t last_mask = LV_OPA_TRANSP;
328             last_dest_color.full = dest_buf[0].full;
329             last_res_color.full = dest_buf[0].full;
330             lv_opa_t opa_tmp = LV_OPA_TRANSP;
331 
332             for(y = 0; y < h; y++) {
333                 for(x = 0; x < w; x++) {
334                     if(*mask) {
335                         if(*mask != last_mask) opa_tmp = *mask == LV_OPA_COVER ? opa :
336                                                              (uint32_t)((uint32_t)(*mask) * opa) >> 8;
337                         if(*mask != last_mask || last_dest_color.full != dest_buf[x].full) {
338 #if LV_COLOR_SCREEN_TRANSP
339                             if(disp->driver->screen_transp) {
340                                 lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, color, opa_tmp, &last_res_color,
341                                                         &last_res_color.ch.alpha);
342                             }
343                             else
344 #endif
345                             {
346                                 if(opa_tmp == LV_OPA_COVER) last_res_color = color;
347                                 else last_res_color = lv_color_mix(color, dest_buf[x], opa_tmp);
348                             }
349                             last_mask = *mask;
350                             last_dest_color.full = dest_buf[x].full;
351                         }
352                         dest_buf[x] = last_res_color;
353                     }
354                     mask++;
355                 }
356                 dest_buf += dest_stride;
357                 mask += (mask_stride - w);
358             }
359         }
360     }
361 }
362 
363 #if LV_DRAW_COMPLEX
fill_blended(lv_color_t * dest_buf,const lv_area_t * dest_area,lv_coord_t dest_stride,lv_color_t color,lv_opa_t opa,const lv_opa_t * mask,lv_coord_t mask_stride,lv_blend_mode_t blend_mode)364 static void fill_blended(lv_color_t * dest_buf, const lv_area_t * dest_area,
365                          lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride,
366                          lv_blend_mode_t blend_mode)
367 {
368 
369     int32_t w = lv_area_get_width(dest_area);
370     int32_t h = lv_area_get_height(dest_area);
371 
372     int32_t x;
373     int32_t y;
374 
375     lv_color_t (*blend_fp)(lv_color_t, lv_color_t, lv_opa_t);
376     switch(blend_mode) {
377         case LV_BLEND_MODE_ADDITIVE:
378             blend_fp = color_blend_true_color_additive;
379             break;
380         case LV_BLEND_MODE_SUBTRACTIVE:
381             blend_fp = color_blend_true_color_subtractive;
382             break;
383         case LV_BLEND_MODE_MULTIPLY:
384             blend_fp = color_blend_true_color_multiply;
385             break;
386         default:
387             LV_LOG_WARN("fill_blended: unsupported blend mode");
388             return;
389     }
390 
391     /*Simple fill (maybe with opacity), no masking*/
392     if(mask == NULL) {
393         lv_color_t last_dest_color = dest_buf[0];
394         lv_color_t last_res_color = blend_fp(color, dest_buf[0], opa);
395         for(y = 0; y < h; y++) {
396             for(x = 0; x < w; x++) {
397                 if(last_dest_color.full != dest_buf[x].full) {
398                     last_dest_color = dest_buf[x];
399                     last_res_color = blend_fp(color, dest_buf[x], opa);
400                 }
401                 dest_buf[x] = last_res_color;
402             }
403             dest_buf += dest_stride;
404         }
405     }
406     /*Masked*/
407     else {
408         /*Buffer the result color to avoid recalculating the same color*/
409         lv_color_t last_dest_color;
410         lv_color_t last_res_color;
411         lv_opa_t last_mask = LV_OPA_TRANSP;
412         last_dest_color = dest_buf[0];
413         lv_opa_t opa_tmp = mask[0] >= LV_OPA_MAX ? opa : (uint32_t)((uint32_t)mask[0] * opa) >> 8;
414         last_res_color = blend_fp(color, last_dest_color, opa_tmp);
415 
416         for(y = 0; y < h; y++) {
417             for(x = 0; x < w; x++) {
418                 if(mask[x] == 0) continue;
419                 if(mask[x] != last_mask || last_dest_color.full != dest_buf[x].full) {
420                     opa_tmp = mask[x] >= LV_OPA_MAX ? opa : (uint32_t)((uint32_t)mask[x] * opa) >> 8;
421 
422                     last_res_color = blend_fp(color, dest_buf[x], opa_tmp);
423                     last_mask = mask[x];
424                     last_dest_color.full = dest_buf[x].full;
425                 }
426                 dest_buf[x] = last_res_color;
427             }
428             dest_buf += dest_stride;
429             mask += mask_stride;
430         }
431     }
432 }
433 #endif
434 
map_set_px(lv_color_t * dest_buf,const lv_area_t * dest_area,lv_coord_t dest_stride,const lv_color_t * src_buf,lv_coord_t src_stride,lv_opa_t opa,const lv_opa_t * mask,lv_coord_t mask_stride)435 static void map_set_px(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
436                        const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride)
437 
438 {
439     lv_disp_t * disp = _lv_refr_get_disp_refreshing();
440 
441     int32_t w = lv_area_get_width(dest_area);
442     int32_t h = lv_area_get_height(dest_area);
443 
444     int32_t x;
445     int32_t y;
446 
447     if(mask == NULL) {
448         for(y = 0; y < h; y++) {
449             for(x = 0; x < w; x++) {
450                 disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, dest_area->x1 + x, dest_area->y1 + y, src_buf[x],
451                                         opa);
452             }
453             src_buf += src_stride;
454         }
455     }
456     else {
457         for(y = 0; y < h; y++) {
458             for(x = 0; x < w; x++) {
459                 if(mask[x]) {
460                     disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, dest_area->x1 + x, dest_area->y1 + y, src_buf[x],
461                                             (uint32_t)((uint32_t)opa * mask[x]) >> 8);
462                 }
463             }
464             mask += mask_stride;
465             src_buf += src_stride;
466         }
467     }
468 }
469 
map_normal(lv_color_t * dest_buf,const lv_area_t * dest_area,lv_coord_t dest_stride,const lv_color_t * src_buf,lv_coord_t src_stride,lv_opa_t opa,const lv_opa_t * mask,lv_coord_t mask_stride)470 LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
471                                              const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride)
472 
473 {
474     int32_t w = lv_area_get_width(dest_area);
475     int32_t h = lv_area_get_height(dest_area);
476 
477     int32_t x;
478     int32_t y;
479 
480 #if LV_COLOR_SCREEN_TRANSP
481     lv_disp_t * disp = _lv_refr_get_disp_refreshing();
482 #endif
483 
484     /*Simple fill (maybe with opacity), no masking*/
485     if(mask == NULL) {
486         if(opa >= LV_OPA_MAX) {
487             for(y = 0; y < h; y++) {
488                 lv_memcpy(dest_buf, src_buf, w * sizeof(lv_color_t));
489                 dest_buf += dest_stride;
490                 src_buf += src_stride;
491             }
492         }
493         else {
494             for(y = 0; y < h; y++) {
495                 for(x = 0; x < w; x++) {
496 #if LV_COLOR_SCREEN_TRANSP
497                     if(disp->driver->screen_transp) {
498                         lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, src_buf[x], opa, &dest_buf[x],
499                                                 &dest_buf[x].ch.alpha);
500                     }
501                     else
502 #endif
503                     {
504                         dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], opa);
505                     }
506                 }
507                 dest_buf += dest_stride;
508                 src_buf += src_stride;
509             }
510         }
511     }
512     /*Masked*/
513     else {
514         /*Only the mask matters*/
515         if(opa > LV_OPA_MAX) {
516             int32_t x_end4 = w - 4;
517 
518             for(y = 0; y < h; y++) {
519                 const lv_opa_t * mask_tmp_x = mask;
520 #if 0
521                 for(x = 0; x < w; x++) {
522                     MAP_NORMAL_MASK_PX(x);
523                 }
524 #else
525                 for(x = 0; x < w && ((lv_uintptr_t)mask_tmp_x & 0x3); x++) {
526 #if LV_COLOR_SCREEN_TRANSP
527                     MAP_NORMAL_MASK_PX_SCR_TRANSP(x)
528 #else
529                     MAP_NORMAL_MASK_PX(x)
530 #endif
531                 }
532 
533                 uint32_t * mask32 = (uint32_t *)mask_tmp_x;
534                 for(; x < x_end4; x += 4) {
535                     if(*mask32) {
536                         if((*mask32) == 0xFFFFFFFF) {
537                             dest_buf[x] = src_buf[x];
538                             dest_buf[x + 1] = src_buf[x + 1];
539                             dest_buf[x + 2] = src_buf[x + 2];
540                             dest_buf[x + 3] = src_buf[x + 3];
541                         }
542                         else {
543                             mask_tmp_x = (const lv_opa_t *)mask32;
544 #if LV_COLOR_SCREEN_TRANSP
545                             MAP_NORMAL_MASK_PX_SCR_TRANSP(x)
546                             MAP_NORMAL_MASK_PX_SCR_TRANSP(x + 1)
547                             MAP_NORMAL_MASK_PX_SCR_TRANSP(x + 2)
548                             MAP_NORMAL_MASK_PX_SCR_TRANSP(x + 3)
549 #else
550                             MAP_NORMAL_MASK_PX(x)
551                             MAP_NORMAL_MASK_PX(x + 1)
552                             MAP_NORMAL_MASK_PX(x + 2)
553                             MAP_NORMAL_MASK_PX(x + 3)
554 #endif
555                         }
556                     }
557                     mask32++;
558                 }
559 
560                 mask_tmp_x = (const lv_opa_t *)mask32;
561                 for(; x < w ; x++) {
562 #if LV_COLOR_SCREEN_TRANSP
563                     MAP_NORMAL_MASK_PX_SCR_TRANSP(x)
564 #else
565                     MAP_NORMAL_MASK_PX(x)
566 #endif
567                 }
568 #endif
569                 dest_buf += dest_stride;
570                 src_buf += src_stride;
571                 mask += mask_stride;
572             }
573         }
574         /*Handle opa and mask values too*/
575         else {
576             for(y = 0; y < h; y++) {
577                 for(x = 0; x < w; x++) {
578                     if(mask[x]) {
579                         lv_opa_t opa_tmp = mask[x] >= LV_OPA_MAX ? opa : ((opa * mask[x]) >> 8);
580 #if LV_COLOR_SCREEN_TRANSP
581                         if(disp->driver->screen_transp) {
582                             lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, src_buf[x], opa_tmp,
583                                                     &dest_buf[x], &dest_buf[x].ch.alpha);
584                         }
585                         else
586 #endif
587                         {
588                             dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], opa_tmp);
589                         }
590                     }
591                 }
592                 dest_buf += dest_stride;
593                 src_buf += src_stride;
594                 mask += mask_stride;
595             }
596         }
597     }
598 }
599 #if LV_DRAW_COMPLEX
map_blended(lv_color_t * dest_buf,const lv_area_t * dest_area,lv_coord_t dest_stride,const lv_color_t * src_buf,lv_coord_t src_stride,lv_opa_t opa,const lv_opa_t * mask,lv_coord_t mask_stride,lv_blend_mode_t blend_mode)600 static void map_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
601                         const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa,
602                         const lv_opa_t * mask, lv_coord_t mask_stride, lv_blend_mode_t blend_mode)
603 {
604 
605     int32_t w = lv_area_get_width(dest_area);
606     int32_t h = lv_area_get_height(dest_area);
607 
608     int32_t x;
609     int32_t y;
610 
611     lv_color_t (*blend_fp)(lv_color_t, lv_color_t, lv_opa_t);
612     switch(blend_mode) {
613         case LV_BLEND_MODE_ADDITIVE:
614             blend_fp = color_blend_true_color_additive;
615             break;
616         case LV_BLEND_MODE_SUBTRACTIVE:
617             blend_fp = color_blend_true_color_subtractive;
618             break;
619         case LV_BLEND_MODE_MULTIPLY:
620             blend_fp = color_blend_true_color_multiply;
621             break;
622         default:
623             LV_LOG_WARN("fill_blended: unsupported blend mode");
624             return;
625     }
626 
627     /*Simple fill (maybe with opacity), no masking*/
628     if(mask == NULL) {
629         /*The map will be indexed from `draw_area->x1` so compensate it.*/
630 
631         for(y = 0; y < h; y++) {
632             for(x = 0; x < w; x++) {
633                 dest_buf[x] = blend_fp(src_buf[x], dest_buf[x], opa);
634             }
635             dest_buf += dest_stride;
636             src_buf += src_stride;
637         }
638     }
639     /*Masked*/
640     else {
641         for(y = 0; y < h; y++) {
642             for(x = 0; x < w; x++) {
643                 if(mask[x] == 0) continue;
644                 lv_opa_t opa_tmp = mask[x] >= LV_OPA_MAX ? opa : ((opa * mask[x]) >> 8);
645                 dest_buf[x] = blend_fp(src_buf[x], dest_buf[x], opa_tmp);
646             }
647             dest_buf += dest_stride;
648             src_buf += src_stride;
649             mask += mask_stride;
650         }
651     }
652 }
653 
color_blend_true_color_additive(lv_color_t fg,lv_color_t bg,lv_opa_t opa)654 static inline lv_color_t color_blend_true_color_additive(lv_color_t fg, lv_color_t bg, lv_opa_t opa)
655 {
656 
657     if(opa <= LV_OPA_MIN) return bg;
658 
659     uint32_t tmp;
660 #if LV_COLOR_DEPTH == 1
661     tmp = bg.full + fg.full;
662     fg.full = LV_MIN(tmp, 1);
663 #else
664     tmp = bg.ch.red + fg.ch.red;
665 #if LV_COLOR_DEPTH == 8
666     fg.ch.red = LV_MIN(tmp, 7);
667 #elif LV_COLOR_DEPTH == 16
668     fg.ch.red = LV_MIN(tmp, 31);
669 #elif LV_COLOR_DEPTH == 32
670     fg.ch.red = LV_MIN(tmp, 255);
671 #endif
672 
673 #if LV_COLOR_DEPTH == 8
674     tmp = bg.ch.green + fg.ch.green;
675     fg.ch.green = LV_MIN(tmp, 7);
676 #elif LV_COLOR_DEPTH == 16
677 #if LV_COLOR_16_SWAP == 0
678     tmp = bg.ch.green + fg.ch.green;
679     fg.ch.green = LV_MIN(tmp, 63);
680 #else
681     tmp = (bg.ch.green_h << 3) + bg.ch.green_l + (fg.ch.green_h << 3) + fg.ch.green_l;
682     tmp = LV_MIN(tmp, 63);
683     fg.ch.green_h = tmp >> 3;
684     fg.ch.green_l = tmp & 0x7;
685 #endif
686 
687 #elif LV_COLOR_DEPTH == 32
688     tmp = bg.ch.green + fg.ch.green;
689     fg.ch.green = LV_MIN(tmp, 255);
690 #endif
691 
692     tmp = bg.ch.blue + fg.ch.blue;
693 #if LV_COLOR_DEPTH == 8
694     fg.ch.blue = LV_MIN(tmp, 4);
695 #elif LV_COLOR_DEPTH == 16
696     fg.ch.blue = LV_MIN(tmp, 31);
697 #elif LV_COLOR_DEPTH == 32
698     fg.ch.blue = LV_MIN(tmp, 255);
699 #endif
700 #endif
701 
702     if(opa == LV_OPA_COVER) return fg;
703 
704     return lv_color_mix(fg, bg, opa);
705 }
706 
color_blend_true_color_subtractive(lv_color_t fg,lv_color_t bg,lv_opa_t opa)707 static inline lv_color_t color_blend_true_color_subtractive(lv_color_t fg, lv_color_t bg, lv_opa_t opa)
708 {
709     if(opa <= LV_OPA_MIN) return bg;
710 
711     int32_t tmp;
712     tmp = bg.ch.red - fg.ch.red;
713     fg.ch.red = LV_MAX(tmp, 0);
714 
715 #if LV_COLOR_16_SWAP == 0
716     tmp = bg.ch.green - fg.ch.green;
717     fg.ch.green = LV_MAX(tmp, 0);
718 #else
719     tmp = (bg.ch.green_h << 3) + bg.ch.green_l + (fg.ch.green_h << 3) + fg.ch.green_l;
720     tmp = LV_MAX(tmp, 0);
721     fg.ch.green_h = tmp >> 3;
722     fg.ch.green_l = tmp & 0x7;
723 #endif
724 
725     tmp = bg.ch.blue - fg.ch.blue;
726     fg.ch.blue = LV_MAX(tmp, 0);
727 
728     if(opa == LV_OPA_COVER) return fg;
729 
730     return lv_color_mix(fg, bg, opa);
731 }
732 
color_blend_true_color_multiply(lv_color_t fg,lv_color_t bg,lv_opa_t opa)733 static inline lv_color_t color_blend_true_color_multiply(lv_color_t fg, lv_color_t bg, lv_opa_t opa)
734 {
735     if(opa <= LV_OPA_MIN) return bg;
736 
737 #if LV_COLOR_DEPTH == 32
738     fg.ch.red = (fg.ch.red * bg.ch.red) >> 8;
739     fg.ch.green = (fg.ch.green * bg.ch.green) >> 8;
740     fg.ch.blue = (fg.ch.blue * bg.ch.blue) >> 8;
741 #elif LV_COLOR_DEPTH == 16
742     fg.ch.red = (fg.ch.red * bg.ch.red) >> 5;
743     fg.ch.blue = (fg.ch.blue * bg.ch.blue) >> 5;
744     LV_COLOR_SET_G(fg, (LV_COLOR_GET_G(fg) * LV_COLOR_GET_G(bg)) >> 6);
745 #elif LV_COLOR_DEPTH == 8
746     fg.ch.red = (fg.ch.red * bg.ch.red) >> 3;
747     fg.ch.green = (fg.ch.green * bg.ch.green) >> 3;
748     fg.ch.blue = (fg.ch.blue * bg.ch.blue) >> 2;
749 #endif
750 
751     if(opa == LV_OPA_COVER) return fg;
752 
753     return lv_color_mix(fg, bg, opa);
754 }
755 
756 #endif
757 
758