1 /**
2  * @file lv_obj_draw.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_obj_draw_private.h"
10 #include "lv_obj_private.h"
11 #include "lv_obj_style.h"
12 #include "../display/lv_display.h"
13 #include "../indev/lv_indev.h"
14 #include "../stdlib/lv_string.h"
15 #include "../draw/lv_draw_arc.h"
16 
17 /*********************
18  *      DEFINES
19  *********************/
20 #define MY_CLASS (&lv_obj_class)
21 
22 /**********************
23  *      TYPEDEFS
24  **********************/
25 
26 /**********************
27  *  STATIC PROTOTYPES
28  **********************/
29 
30 static inline lv_opa_t get_layer_opa(const lv_obj_t * obj, lv_part_t part, const lv_draw_dsc_base_t * base_dsc);
31 
32 /**********************
33  *  STATIC VARIABLES
34  **********************/
35 
36 /**********************
37  *      MACROS
38  **********************/
39 
40 /**********************
41  *   GLOBAL FUNCTIONS
42  **********************/
43 
lv_obj_init_draw_rect_dsc(lv_obj_t * obj,lv_part_t part,lv_draw_rect_dsc_t * draw_dsc)44 void lv_obj_init_draw_rect_dsc(lv_obj_t * obj, lv_part_t part, lv_draw_rect_dsc_t * draw_dsc)
45 {
46     LV_PROFILER_DRAW_BEGIN;
47     draw_dsc->base.obj = obj;
48     draw_dsc->base.part = part;
49 
50     lv_opa_t opa = get_layer_opa(obj, part, &draw_dsc->base);
51     if(part != LV_PART_MAIN) {
52         if(opa <= LV_OPA_MIN) {
53             draw_dsc->bg_opa = LV_OPA_TRANSP;
54             draw_dsc->bg_image_opa = LV_OPA_TRANSP;
55             draw_dsc->border_opa = LV_OPA_TRANSP;
56             draw_dsc->outline_opa = LV_OPA_TRANSP;
57             draw_dsc->shadow_opa = LV_OPA_TRANSP;
58             LV_PROFILER_DRAW_END;
59             return;
60         }
61     }
62 
63     draw_dsc->radius = lv_obj_get_style_radius(obj, part);
64 
65     if(draw_dsc->bg_opa != LV_OPA_TRANSP) {
66         draw_dsc->bg_opa = lv_obj_get_style_bg_opa(obj, part);
67         if(draw_dsc->bg_opa > LV_OPA_MIN) {
68             draw_dsc->bg_color = lv_obj_get_style_bg_color_filtered(obj, part);
69             const lv_grad_dsc_t * grad = lv_obj_get_style_bg_grad(obj, part);
70             if(grad && grad->dir != LV_GRAD_DIR_NONE) {
71                 lv_memcpy(&draw_dsc->bg_grad, grad, sizeof(*grad));
72             }
73             else {
74                 draw_dsc->bg_grad.dir = lv_obj_get_style_bg_grad_dir(obj, part);
75                 if(draw_dsc->bg_grad.dir != LV_GRAD_DIR_NONE) {
76                     draw_dsc->bg_grad.stops[0].color = lv_obj_get_style_bg_color_filtered(obj, part);
77                     draw_dsc->bg_grad.stops[1].color = lv_obj_get_style_bg_grad_color_filtered(obj, part);
78                     draw_dsc->bg_grad.stops[0].frac = lv_obj_get_style_bg_main_stop(obj, part);
79                     draw_dsc->bg_grad.stops[1].frac = lv_obj_get_style_bg_grad_stop(obj, part);
80                     draw_dsc->bg_grad.stops[0].opa = lv_obj_get_style_bg_main_opa(obj, part);
81                     draw_dsc->bg_grad.stops[1].opa = lv_obj_get_style_bg_grad_opa(obj, part);
82                 }
83             }
84         }
85     }
86 
87     if(draw_dsc->border_opa != LV_OPA_TRANSP) {
88         draw_dsc->border_width = lv_obj_get_style_border_width(obj, part);
89         if(draw_dsc->border_width) {
90             draw_dsc->border_opa = lv_obj_get_style_border_opa(obj, part);
91             if(draw_dsc->border_opa > LV_OPA_MIN) {
92                 draw_dsc->border_side = lv_obj_get_style_border_side(obj, part);
93                 draw_dsc->border_color = lv_obj_get_style_border_color_filtered(obj, part);
94             }
95         }
96     }
97 
98     if(draw_dsc->outline_opa != LV_OPA_TRANSP) {
99         draw_dsc->outline_width = lv_obj_get_style_outline_width(obj, part);
100         if(draw_dsc->outline_width) {
101             draw_dsc->outline_opa = lv_obj_get_style_outline_opa(obj, part);
102             if(draw_dsc->outline_opa > LV_OPA_MIN) {
103                 draw_dsc->outline_pad = lv_obj_get_style_outline_pad(obj, part);
104                 draw_dsc->outline_color = lv_obj_get_style_outline_color_filtered(obj, part);
105             }
106         }
107     }
108 
109     if(draw_dsc->bg_image_opa != LV_OPA_TRANSP) {
110         draw_dsc->bg_image_src = lv_obj_get_style_bg_image_src(obj, part);
111         if(draw_dsc->bg_image_src) {
112             draw_dsc->bg_image_opa = lv_obj_get_style_bg_image_opa(obj, part);
113             if(draw_dsc->bg_image_opa > LV_OPA_MIN) {
114                 if(lv_image_src_get_type(draw_dsc->bg_image_src) == LV_IMAGE_SRC_SYMBOL) {
115                     draw_dsc->bg_image_symbol_font = lv_obj_get_style_text_font(obj, part);
116                     draw_dsc->bg_image_recolor = lv_obj_get_style_text_color_filtered(obj, part);
117                 }
118                 else {
119                     draw_dsc->bg_image_recolor = lv_obj_get_style_bg_image_recolor_filtered(obj, part);
120                     draw_dsc->bg_image_recolor_opa = lv_obj_get_style_bg_image_recolor_opa(obj, part);
121                     draw_dsc->bg_image_tiled = lv_obj_get_style_bg_image_tiled(obj, part);
122                 }
123             }
124         }
125     }
126 
127     if(draw_dsc->shadow_opa) {
128         draw_dsc->shadow_width = lv_obj_get_style_shadow_width(obj, part);
129         if(draw_dsc->shadow_width) {
130             if(draw_dsc->shadow_opa > LV_OPA_MIN) {
131                 draw_dsc->shadow_opa = lv_obj_get_style_shadow_opa(obj, part);
132                 if(draw_dsc->shadow_opa > LV_OPA_MIN) {
133                     draw_dsc->shadow_offset_x = lv_obj_get_style_shadow_offset_x(obj, part);
134                     draw_dsc->shadow_offset_y = lv_obj_get_style_shadow_offset_y(obj, part);
135                     draw_dsc->shadow_spread = lv_obj_get_style_shadow_spread(obj, part);
136                     draw_dsc->shadow_color = lv_obj_get_style_shadow_color_filtered(obj, part);
137                 }
138             }
139         }
140     }
141 
142     if(opa < LV_OPA_MAX) {
143         draw_dsc->bg_opa = LV_OPA_MIX2(draw_dsc->bg_opa, opa);
144         draw_dsc->bg_image_opa = LV_OPA_MIX2(draw_dsc->bg_image_opa, opa);
145         draw_dsc->border_opa = LV_OPA_MIX2(draw_dsc->border_opa, opa);
146         draw_dsc->shadow_opa = LV_OPA_MIX2(draw_dsc->shadow_opa, opa);
147         draw_dsc->outline_opa = LV_OPA_MIX2(draw_dsc->outline_opa, opa);
148     }
149 
150     LV_PROFILER_DRAW_END;
151 }
152 
lv_obj_init_draw_label_dsc(lv_obj_t * obj,lv_part_t part,lv_draw_label_dsc_t * draw_dsc)153 void lv_obj_init_draw_label_dsc(lv_obj_t * obj, lv_part_t part, lv_draw_label_dsc_t * draw_dsc)
154 {
155     LV_PROFILER_DRAW_BEGIN;
156     draw_dsc->base.obj = obj;
157     draw_dsc->base.part = part;
158 
159     draw_dsc->opa = lv_obj_get_style_text_opa(obj, part);
160     if(draw_dsc->opa <= LV_OPA_MIN) {
161         LV_PROFILER_DRAW_END;
162         return;
163     }
164 
165     lv_opa_t opa = get_layer_opa(obj, part, &draw_dsc->base);
166     if(opa < LV_OPA_MAX) {
167         draw_dsc->opa = LV_OPA_MIX2(draw_dsc->opa, opa);
168     }
169     if(draw_dsc->opa <= LV_OPA_MIN) {
170         LV_PROFILER_DRAW_END;
171         return;
172     }
173 
174     draw_dsc->color = lv_obj_get_style_text_color_filtered(obj, part);
175     draw_dsc->letter_space = lv_obj_get_style_text_letter_space(obj, part);
176     draw_dsc->line_space = lv_obj_get_style_text_line_space(obj, part);
177     draw_dsc->decor = lv_obj_get_style_text_decor(obj, part);
178     if(part != LV_PART_MAIN) draw_dsc->blend_mode = lv_obj_get_style_blend_mode(obj, part);
179 
180     draw_dsc->font = lv_obj_get_style_text_font(obj, part);
181 
182 #if LV_USE_BIDI
183     draw_dsc->bidi_dir = lv_obj_get_style_base_dir(obj, LV_PART_MAIN);
184 #endif
185 
186     draw_dsc->align = lv_obj_get_style_text_align(obj, part);
187 
188     LV_PROFILER_DRAW_END;
189 }
190 
lv_obj_init_draw_image_dsc(lv_obj_t * obj,lv_part_t part,lv_draw_image_dsc_t * draw_dsc)191 void lv_obj_init_draw_image_dsc(lv_obj_t * obj, lv_part_t part, lv_draw_image_dsc_t * draw_dsc)
192 {
193     LV_PROFILER_DRAW_BEGIN;
194     draw_dsc->base.obj = obj;
195     draw_dsc->base.part = part;
196 
197     draw_dsc->opa = lv_obj_get_style_image_opa(obj, part);
198     if(draw_dsc->opa <= LV_OPA_MIN) {
199         LV_PROFILER_DRAW_END;
200         return;
201     }
202 
203     lv_opa_t opa = get_layer_opa(obj, part, &draw_dsc->base);
204     if(opa < LV_OPA_MAX) {
205         draw_dsc->opa = LV_OPA_MIX2(draw_dsc->opa, opa);
206     }
207     if(draw_dsc->opa <= LV_OPA_MIN) {
208         LV_PROFILER_DRAW_END;
209         return;
210     }
211 
212     draw_dsc->rotation = 0;
213     draw_dsc->scale_x = LV_SCALE_NONE;
214     draw_dsc->scale_y = LV_SCALE_NONE;
215     draw_dsc->pivot.x = lv_area_get_width(&obj->coords) / 2;
216     draw_dsc->pivot.y = lv_area_get_height(&obj->coords) / 2;
217 
218     draw_dsc->recolor_opa = lv_obj_get_style_image_recolor_opa(obj, part);
219     draw_dsc->recolor = lv_obj_get_style_image_recolor_filtered(obj, part);
220 
221     if(part != LV_PART_MAIN) draw_dsc->blend_mode = lv_obj_get_style_blend_mode(obj, part);
222 
223     LV_PROFILER_DRAW_END;
224 }
225 
lv_obj_init_draw_line_dsc(lv_obj_t * obj,lv_part_t part,lv_draw_line_dsc_t * draw_dsc)226 void lv_obj_init_draw_line_dsc(lv_obj_t * obj, lv_part_t part, lv_draw_line_dsc_t * draw_dsc)
227 {
228     LV_PROFILER_DRAW_BEGIN;
229     draw_dsc->base.obj = obj;
230     draw_dsc->base.part = part;
231 
232     draw_dsc->opa = lv_obj_get_style_line_opa(obj, part);
233     if(draw_dsc->opa <= LV_OPA_MIN) {
234         LV_PROFILER_DRAW_END;
235         return;
236     }
237 
238     lv_opa_t opa = get_layer_opa(obj, part, &draw_dsc->base);
239     if(opa < LV_OPA_MAX) {
240         draw_dsc->opa = LV_OPA_MIX2(draw_dsc->opa, opa);
241     }
242     if(draw_dsc->opa <= LV_OPA_MIN) {
243         LV_PROFILER_DRAW_END;
244         return;
245     }
246 
247     draw_dsc->width = lv_obj_get_style_line_width(obj, part);
248     if(draw_dsc->width == 0) {
249         LV_PROFILER_DRAW_END;
250         return;
251     }
252 
253     draw_dsc->color = lv_obj_get_style_line_color_filtered(obj, part);
254 
255     draw_dsc->dash_width = lv_obj_get_style_line_dash_width(obj, part);
256     if(draw_dsc->dash_width) {
257         draw_dsc->dash_gap = lv_obj_get_style_line_dash_gap(obj, part);
258     }
259 
260     draw_dsc->round_start = lv_obj_get_style_line_rounded(obj, part);
261     draw_dsc->round_end = draw_dsc->round_start;
262 
263     if(part != LV_PART_MAIN) draw_dsc->blend_mode = lv_obj_get_style_blend_mode(obj, part);
264     LV_PROFILER_DRAW_END;
265 }
266 
lv_obj_init_draw_arc_dsc(lv_obj_t * obj,lv_part_t part,lv_draw_arc_dsc_t * draw_dsc)267 void lv_obj_init_draw_arc_dsc(lv_obj_t * obj, lv_part_t part, lv_draw_arc_dsc_t * draw_dsc)
268 {
269     LV_PROFILER_DRAW_BEGIN;
270     draw_dsc->base.obj = obj;
271     draw_dsc->base.part = part;
272 
273     draw_dsc->width = lv_obj_get_style_arc_width(obj, part);
274     if(draw_dsc->width == 0) {
275         LV_PROFILER_DRAW_END;
276         return;
277     }
278 
279     draw_dsc->opa = lv_obj_get_style_arc_opa(obj, part);
280     if(draw_dsc->opa <= LV_OPA_MIN) {
281         LV_PROFILER_DRAW_END;
282         return;
283     }
284 
285     lv_opa_t opa = get_layer_opa(obj, part, &draw_dsc->base);
286     if(opa < LV_OPA_MAX) {
287         draw_dsc->opa = LV_OPA_MIX2(draw_dsc->opa, opa);
288     }
289     if(draw_dsc->opa <= LV_OPA_MIN) {
290         LV_PROFILER_DRAW_END;
291         return;
292     }
293 
294     draw_dsc->color = lv_obj_get_style_arc_color_filtered(obj, part);
295     draw_dsc->img_src = lv_obj_get_style_arc_image_src(obj, part);
296 
297     draw_dsc->rounded = lv_obj_get_style_arc_rounded(obj, part);
298     LV_PROFILER_DRAW_END;
299 }
300 
lv_obj_calculate_ext_draw_size(lv_obj_t * obj,lv_part_t part)301 int32_t lv_obj_calculate_ext_draw_size(lv_obj_t * obj, lv_part_t part)
302 {
303     LV_PROFILER_DRAW_BEGIN;
304     int32_t s = 0;
305 
306     int32_t sh_width = lv_obj_get_style_shadow_width(obj, part);
307     if(sh_width) {
308         lv_opa_t sh_opa = lv_obj_get_style_shadow_opa(obj, part);
309         if(sh_opa > LV_OPA_MIN) {
310             sh_width = sh_width / 2 + 1;    /*The blur adds only half width*/
311             sh_width += lv_obj_get_style_shadow_spread(obj, part);
312             int32_t sh_ofs_x = lv_obj_get_style_shadow_offset_x(obj, part);
313             int32_t sh_ofs_y = lv_obj_get_style_shadow_offset_y(obj, part);
314             sh_width += LV_MAX(LV_ABS(sh_ofs_x), LV_ABS(sh_ofs_y));
315             s = LV_MAX(s, sh_width);
316         }
317     }
318 
319     int32_t outline_width = lv_obj_get_style_outline_width(obj, part);
320     if(outline_width) {
321         lv_opa_t outline_opa = lv_obj_get_style_outline_opa(obj, part);
322         if(outline_opa > LV_OPA_MIN) {
323             int32_t outline_pad = lv_obj_get_style_outline_pad(obj, part);
324             s = LV_MAX(s, outline_pad + outline_width);
325         }
326     }
327 
328     int32_t w = lv_obj_get_style_transform_width(obj, part);
329     int32_t h = lv_obj_get_style_transform_height(obj, part);
330     int32_t wh = LV_MAX(w, h);
331     if(wh > 0) s += wh;
332 
333     LV_PROFILER_DRAW_END;
334     return s;
335 }
336 
lv_obj_refresh_ext_draw_size(lv_obj_t * obj)337 void lv_obj_refresh_ext_draw_size(lv_obj_t * obj)
338 {
339     LV_PROFILER_DRAW_BEGIN;
340     LV_ASSERT_OBJ(obj, MY_CLASS);
341 
342     int32_t s_old = lv_obj_get_ext_draw_size(obj);
343     int32_t s_new = 0;
344     lv_obj_send_event(obj, LV_EVENT_REFR_EXT_DRAW_SIZE, &s_new);
345 
346     /*Store the result if the special attrs already allocated*/
347     if(obj->spec_attr) {
348         obj->spec_attr->ext_draw_size = s_new;
349     }
350     /*Allocate spec. attrs. only if the result is not zero.
351      *Zero is the default value if the spec. attr. are not defined.*/
352     else if(s_new != 0) {
353         lv_obj_allocate_spec_attr(obj);
354         obj->spec_attr->ext_draw_size = s_new;
355     }
356 
357     if(s_new != s_old) lv_obj_invalidate(obj);
358     LV_PROFILER_DRAW_END;
359 }
360 
lv_obj_get_ext_draw_size(const lv_obj_t * obj)361 int32_t lv_obj_get_ext_draw_size(const lv_obj_t * obj)
362 {
363     if(obj->spec_attr) return obj->spec_attr->ext_draw_size;
364     else return 0;
365 }
366 
lv_obj_get_layer_type(const lv_obj_t * obj)367 lv_layer_type_t lv_obj_get_layer_type(const lv_obj_t * obj)
368 {
369 
370     if(obj->spec_attr) return (lv_layer_type_t)obj->spec_attr->layer_type;
371     else return LV_LAYER_TYPE_NONE;
372 }
373 
374 /**********************
375  *   STATIC FUNCTIONS
376  **********************/
377 
get_layer_opa(const lv_obj_t * obj,lv_part_t part,const lv_draw_dsc_base_t * base_dsc)378 static inline lv_opa_t get_layer_opa(const lv_obj_t * obj, lv_part_t part, const lv_draw_dsc_base_t * base_dsc)
379 {
380     if(base_dsc->layer) {
381         /* Accessing the layer opa directly is faster than using get style opa recursive */
382         return base_dsc->layer->opa;
383     }
384 
385     /* fallback to old recursive style opa */
386     return lv_obj_get_style_opa_recursive(obj, part);
387 }
388