1 /**
2  * @file lv_draw_rect.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_draw_rect_private.h"
10 #include "lv_draw_private.h"
11 #include "../core/lv_obj.h"
12 #include "../misc/lv_assert.h"
13 #include "../core/lv_obj_event.h"
14 #include "../stdlib/lv_string.h"
15 
16 /*********************
17  *      DEFINES
18  *********************/
19 
20 /**********************
21  *      TYPEDEFS
22  **********************/
23 
24 /**********************
25  *  STATIC PROTOTYPES
26  **********************/
27 
28 /**********************
29  *  STATIC VARIABLES
30  **********************/
31 
32 /**********************
33  *      MACROS
34  **********************/
35 
36 /**********************
37  *   GLOBAL FUNCTIONS
38  **********************/
39 
lv_draw_rect_dsc_init(lv_draw_rect_dsc_t * dsc)40 void LV_ATTRIBUTE_FAST_MEM lv_draw_rect_dsc_init(lv_draw_rect_dsc_t * dsc)
41 {
42     lv_memzero(dsc, sizeof(lv_draw_rect_dsc_t));
43     dsc->bg_color = lv_color_white();
44     dsc->bg_grad.stops[0].color = lv_color_white();
45     dsc->bg_grad.stops[1].color = lv_color_black();
46     dsc->bg_grad.stops[1].frac = 0xFF;
47     dsc->bg_grad.stops_count = 2;
48     dsc->border_color = lv_color_black();
49     dsc->shadow_color = lv_color_black();
50     dsc->bg_image_symbol_font = LV_FONT_DEFAULT;
51     dsc->bg_opa = LV_OPA_COVER;
52     dsc->bg_image_opa = LV_OPA_COVER;
53     dsc->outline_opa = LV_OPA_COVER;
54     dsc->border_opa = LV_OPA_COVER;
55     dsc->shadow_opa = LV_OPA_COVER;
56     dsc->border_side = LV_BORDER_SIDE_FULL;
57 }
58 
lv_draw_fill_dsc_init(lv_draw_fill_dsc_t * dsc)59 void lv_draw_fill_dsc_init(lv_draw_fill_dsc_t * dsc)
60 {
61     lv_memzero(dsc, sizeof(*dsc));
62     dsc->opa = LV_OPA_COVER;
63     dsc->base.dsc_size = sizeof(lv_draw_fill_dsc_t);
64 }
65 
lv_draw_task_get_fill_dsc(lv_draw_task_t * task)66 lv_draw_fill_dsc_t * lv_draw_task_get_fill_dsc(lv_draw_task_t * task)
67 {
68     return task->type == LV_DRAW_TASK_TYPE_FILL ? (lv_draw_fill_dsc_t *)task->draw_dsc : NULL;
69 }
70 
lv_draw_border_dsc_init(lv_draw_border_dsc_t * dsc)71 void lv_draw_border_dsc_init(lv_draw_border_dsc_t * dsc)
72 {
73     lv_memzero(dsc, sizeof(*dsc));
74     dsc->opa = LV_OPA_COVER;
75     dsc->side = LV_BORDER_SIDE_FULL;
76     dsc->base.dsc_size = sizeof(lv_draw_border_dsc_t);
77 }
78 
lv_draw_task_get_border_dsc(lv_draw_task_t * task)79 lv_draw_border_dsc_t * lv_draw_task_get_border_dsc(lv_draw_task_t * task)
80 {
81     return task->type == LV_DRAW_TASK_TYPE_BORDER ? (lv_draw_border_dsc_t *)task->draw_dsc : NULL;
82 }
83 
lv_draw_box_shadow_dsc_init(lv_draw_box_shadow_dsc_t * dsc)84 void lv_draw_box_shadow_dsc_init(lv_draw_box_shadow_dsc_t * dsc)
85 {
86     lv_memzero(dsc, sizeof(*dsc));
87     dsc->opa = LV_OPA_COVER;
88     dsc->base.dsc_size = sizeof(lv_draw_box_shadow_dsc_t);
89 }
90 
lv_draw_task_get_box_shadow_dsc(lv_draw_task_t * task)91 lv_draw_box_shadow_dsc_t * lv_draw_task_get_box_shadow_dsc(lv_draw_task_t * task)
92 {
93     return task->type == LV_DRAW_TASK_TYPE_BOX_SHADOW ? (lv_draw_box_shadow_dsc_t *)task->draw_dsc : NULL;
94 }
95 
lv_draw_rect(lv_layer_t * layer,const lv_draw_rect_dsc_t * dsc,const lv_area_t * coords)96 void lv_draw_rect(lv_layer_t * layer, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords)
97 {
98 
99     LV_PROFILER_DRAW_BEGIN;
100     bool has_shadow;
101     bool has_fill;
102     bool has_border;
103     bool has_outline;
104     bool has_bg_img;
105 
106     if(dsc->shadow_width == 0 ||
107        dsc->shadow_opa <= LV_OPA_MIN ||
108        (dsc->shadow_width == 1 && dsc->shadow_spread <= 0 &&
109         dsc->shadow_offset_x == 0 && dsc->shadow_offset_y == 0)) {
110         has_shadow = false;
111     }
112     else {
113         has_shadow = true;
114     }
115 
116     if(dsc->bg_opa <= LV_OPA_MIN) has_fill = false;
117     else has_fill = true;
118 
119     if(dsc->bg_image_opa <= LV_OPA_MIN || dsc->bg_image_src == NULL) has_bg_img = false;
120     else has_bg_img = true;
121 
122     if(dsc->border_opa <= LV_OPA_MIN
123        || dsc->border_width == 0
124        || dsc->border_post == true
125        || dsc->border_side == LV_BORDER_SIDE_NONE) has_border = false;
126     else has_border = true;
127 
128     if(dsc->outline_opa <= LV_OPA_MIN || dsc->outline_width == 0) has_outline = false;
129     else has_outline = true;
130 
131     bool bg_cover = true;
132     if(dsc->bg_opa < LV_OPA_COVER) bg_cover = false;
133     else if(dsc->bg_grad.dir != LV_GRAD_DIR_NONE) {
134         uint32_t s;
135         for(s = 0; s < dsc->bg_grad.stops_count; s++) {
136             if(dsc->bg_grad.stops[s].opa != LV_OPA_COVER) {
137                 bg_cover = false;
138                 break;
139             }
140         }
141     }
142 
143     lv_draw_task_t * t;
144 
145     /*Shadow*/
146     if(has_shadow) {
147         /*Check whether the shadow is visible*/
148         t = lv_draw_add_task(layer, coords);
149         lv_draw_box_shadow_dsc_t * shadow_dsc = lv_malloc(sizeof(lv_draw_box_shadow_dsc_t));
150         LV_ASSERT_MALLOC(shadow_dsc);
151         t->draw_dsc = shadow_dsc;
152         lv_area_increase(&t->_real_area, dsc->shadow_spread, dsc->shadow_spread);
153         lv_area_increase(&t->_real_area, dsc->shadow_width, dsc->shadow_width);
154         lv_area_move(&t->_real_area, dsc->shadow_offset_x, dsc->shadow_offset_y);
155         shadow_dsc->base = dsc->base;
156         shadow_dsc->base.dsc_size = sizeof(lv_draw_box_shadow_dsc_t);
157         shadow_dsc->radius = dsc->radius;
158         shadow_dsc->color = dsc->shadow_color;
159         shadow_dsc->width = dsc->shadow_width;
160         shadow_dsc->spread = dsc->shadow_spread;
161         shadow_dsc->opa = dsc->shadow_opa;
162         shadow_dsc->ofs_x = dsc->shadow_offset_x;
163         shadow_dsc->ofs_y = dsc->shadow_offset_y;
164         shadow_dsc->bg_cover = bg_cover;
165         t->type = LV_DRAW_TASK_TYPE_BOX_SHADOW;
166         lv_draw_finalize_task_creation(layer, t);
167     }
168 
169     /*Background*/
170     if(has_fill) {
171         lv_area_t bg_coords = *coords;
172         /*If the border fully covers make the bg area 1px smaller to avoid artifacts on the corners*/
173         if(dsc->border_width > 1 && dsc->border_opa >= LV_OPA_MAX && dsc->radius != 0) {
174             bg_coords.x1 += (dsc->border_side & LV_BORDER_SIDE_LEFT) ? 1 : 0;
175             bg_coords.y1 += (dsc->border_side & LV_BORDER_SIDE_TOP) ? 1 : 0;
176             bg_coords.x2 -= (dsc->border_side & LV_BORDER_SIDE_RIGHT) ? 1 : 0;
177             bg_coords.y2 -= (dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? 1 : 0;
178         }
179 
180         t = lv_draw_add_task(layer, &bg_coords);
181         lv_draw_fill_dsc_t * bg_dsc = lv_malloc(sizeof(lv_draw_fill_dsc_t));
182         LV_ASSERT_MALLOC(bg_dsc);
183         lv_draw_fill_dsc_init(bg_dsc);
184         t->draw_dsc = bg_dsc;
185         bg_dsc->base = dsc->base;
186         bg_dsc->base.dsc_size = sizeof(lv_draw_fill_dsc_t);
187         bg_dsc->radius = dsc->radius;
188         bg_dsc->color = dsc->bg_color;
189         bg_dsc->grad = dsc->bg_grad;
190         bg_dsc->opa = dsc->bg_opa;
191         t->type = LV_DRAW_TASK_TYPE_FILL;
192 
193         lv_draw_finalize_task_creation(layer, t);
194     }
195 
196     /*Background image*/
197     if(has_bg_img) {
198         lv_image_src_t src_type = lv_image_src_get_type(dsc->bg_image_src);
199         lv_result_t res = LV_RESULT_OK;
200         lv_image_header_t header;
201         if(src_type == LV_IMAGE_SRC_VARIABLE || src_type == LV_IMAGE_SRC_FILE) {
202             res  = lv_image_decoder_get_info(dsc->bg_image_src, &header);
203         }
204         else {
205             lv_memzero(&header, sizeof(header));
206 
207             if(src_type == LV_IMAGE_SRC_UNKNOWN) {
208                 res = LV_RESULT_INVALID;
209             }
210         }
211 
212         if(res == LV_RESULT_OK) {
213             if(src_type == LV_IMAGE_SRC_VARIABLE || src_type == LV_IMAGE_SRC_FILE) {
214 
215                 if(dsc->bg_image_tiled) {
216                     t = lv_draw_add_task(layer, coords);
217                 }
218                 else {
219                     lv_area_t a = {0, 0, header.w - 1, header.h - 1};
220                     lv_area_align(coords, &a, LV_ALIGN_CENTER, 0, 0);
221                     t = lv_draw_add_task(layer, &a);
222                 }
223 
224                 lv_draw_image_dsc_t * bg_image_dsc = lv_malloc(sizeof(lv_draw_image_dsc_t));
225                 LV_ASSERT_MALLOC(bg_image_dsc);
226                 lv_draw_image_dsc_init(bg_image_dsc);
227                 t->draw_dsc = bg_image_dsc;
228                 bg_image_dsc->base = dsc->base;
229                 bg_image_dsc->base.dsc_size = sizeof(lv_draw_image_dsc_t);
230                 bg_image_dsc->src = dsc->bg_image_src;
231                 bg_image_dsc->opa = dsc->bg_image_opa;
232                 bg_image_dsc->recolor = dsc->bg_image_recolor;
233                 bg_image_dsc->recolor_opa = dsc->bg_image_recolor_opa;
234                 bg_image_dsc->tile = dsc->bg_image_tiled;
235                 bg_image_dsc->header = header;
236                 bg_image_dsc->clip_radius = dsc->radius;
237                 bg_image_dsc->image_area = *coords;
238                 t->type = LV_DRAW_TASK_TYPE_IMAGE;
239                 lv_draw_finalize_task_creation(layer, t);
240             }
241             else {
242                 lv_point_t s;
243                 lv_text_get_size(&s, dsc->bg_image_src, dsc->bg_image_symbol_font, 0, 0, LV_COORD_MAX, LV_TEXT_FLAG_NONE);
244 
245                 lv_area_t a = {0, 0, s.x - 1, s.y - 1};
246                 lv_area_align(coords, &a, LV_ALIGN_CENTER, 0, 0);
247                 t = lv_draw_add_task(layer, &a);
248 
249                 lv_draw_label_dsc_t * bg_label_dsc = lv_malloc(sizeof(lv_draw_label_dsc_t));
250                 LV_ASSERT_MALLOC(bg_label_dsc);
251                 lv_draw_label_dsc_init(bg_label_dsc);
252                 t->draw_dsc = bg_label_dsc;
253                 bg_label_dsc->base = dsc->base;
254                 bg_label_dsc->base.dsc_size = sizeof(lv_draw_label_dsc_t);
255                 bg_label_dsc->color = dsc->bg_image_recolor;
256                 bg_label_dsc->font = dsc->bg_image_symbol_font;
257                 bg_label_dsc->text = dsc->bg_image_src;
258                 t->type = LV_DRAW_TASK_TYPE_LABEL;
259                 lv_draw_finalize_task_creation(layer, t);
260             }
261         }
262     }
263 
264     /*Border*/
265     if(has_border) {
266         t = lv_draw_add_task(layer, coords);
267         lv_draw_border_dsc_t * border_dsc = lv_malloc(sizeof(lv_draw_border_dsc_t));
268         LV_ASSERT_MALLOC(border_dsc);
269         t->draw_dsc = border_dsc;
270         border_dsc->base = dsc->base;
271         border_dsc->base.dsc_size = sizeof(lv_draw_border_dsc_t);
272         border_dsc->radius = dsc->radius;
273         border_dsc->color = dsc->border_color;
274         border_dsc->opa = dsc->border_opa;
275         border_dsc->width = dsc->border_width;
276         border_dsc->side = dsc->border_side;
277         t->type = LV_DRAW_TASK_TYPE_BORDER;
278         lv_draw_finalize_task_creation(layer, t);
279     }
280 
281     /*Outline*/
282     if(has_outline) {
283         lv_area_t outline_coords = *coords;
284         lv_area_increase(&outline_coords, dsc->outline_width + dsc->outline_pad, dsc->outline_width + dsc->outline_pad);
285         t = lv_draw_add_task(layer, &outline_coords);
286         lv_draw_border_dsc_t * outline_dsc = lv_malloc(sizeof(lv_draw_border_dsc_t));
287         LV_ASSERT_MALLOC(outline_dsc);
288         t->draw_dsc = outline_dsc;
289         lv_area_increase(&t->_real_area, dsc->outline_width, dsc->outline_width);
290         lv_area_increase(&t->_real_area, dsc->outline_pad, dsc->outline_pad);
291         outline_dsc->base = dsc->base;
292         outline_dsc->base.dsc_size = sizeof(lv_draw_border_dsc_t);
293         outline_dsc->radius = dsc->radius == LV_RADIUS_CIRCLE ? LV_RADIUS_CIRCLE : dsc->radius + dsc->outline_width +
294                               dsc->outline_pad;
295         outline_dsc->color = dsc->outline_color;
296         outline_dsc->opa = dsc->outline_opa;
297         outline_dsc->width = dsc->outline_width;
298         outline_dsc->side = LV_BORDER_SIDE_FULL;
299         t->type = LV_DRAW_TASK_TYPE_BORDER;
300         lv_draw_finalize_task_creation(layer, t);
301     }
302 
303     LV_ASSERT_MEM_INTEGRITY();
304 
305     LV_PROFILER_DRAW_END;
306 }
307 
308 /**********************
309  *   STATIC FUNCTIONS
310  **********************/
311