1 /**
2 * @file lv_style.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_obj.h"
10 #include "../lv_misc/lv_mem.h"
11 #include "../lv_misc/lv_anim.h"
12
13 /*********************
14 * DEFINES
15 *********************/
16 #define STYLE_MIX_MAX 256
17 #define STYLE_MIX_SHIFT 8 /*log2(STYLE_MIX_MAX)*/
18
19 #define VAL_PROP(v1, v2, r) v1 + (((v2 - v1) * r) >> STYLE_MIX_SHIFT)
20 #define STYLE_ATTR_MIX(attr, r) \
21 if(start->attr != end->attr) { \
22 res->attr = VAL_PROP(start->attr, end->attr, r); \
23 } else { \
24 res->attr = start->attr; \
25 }
26
27 #define LV_STYLE_PROP_TO_ID(prop) (prop & 0xFF);
28 #define LV_STYLE_PROP_GET_TYPE(prop) ((prop >> 8) & 0xFF);
29
30 /**********************
31 * TYPEDEFS
32 **********************/
33
34 /**********************
35 * STATIC PROTOTYPES
36 **********************/
37 LV_ATTRIBUTE_FAST_MEM static inline int32_t get_property_index(const lv_style_t * style, lv_style_property_t prop);
38 static lv_style_t * get_alloc_local_style(lv_style_list_t * list);
39 static inline void style_resize(lv_style_t * style, size_t sz);
40 static inline lv_style_property_t get_style_prop(const lv_style_t * style, size_t idx);
41 static inline uint8_t get_style_prop_id(const lv_style_t * style, size_t idx);
42 static inline uint8_t get_style_prop_attr(const lv_style_t * style, size_t idx);
43 static inline size_t get_prop_size(uint8_t prop_id);
44 static inline size_t get_next_prop_index(uint8_t prop_id, size_t id);
45
46 /**********************
47 * GLOABAL VARIABLES
48 **********************/
49
50 /**********************
51 * STATIC VARIABLES
52 **********************/
53
54 /**********************
55 * MACROS
56 **********************/
57
58 /**********************
59 * GLOBAL FUNCTIONS
60 **********************/
61
62 /**
63 * Initialize a style
64 * @param style pointer to a style to initialize
65 */
lv_style_init(lv_style_t * style)66 void lv_style_init(lv_style_t * style)
67 {
68 _lv_memset_00(style, sizeof(lv_style_t));
69 #if LV_USE_ASSERT_STYLE
70 style->sentinel = LV_DEBUG_STYLE_SENTINEL_VALUE;
71 #endif
72 }
73
74 /**
75 * Copy a style with all its properties
76 * @param style_dest pointer to the destination style. (Should be initialized with `lv_style_init()`)
77 * @param style_src pointer to the source (to copy )style
78 */
lv_style_copy(lv_style_t * style_dest,const lv_style_t * style_src)79 void lv_style_copy(lv_style_t * style_dest, const lv_style_t * style_src)
80 {
81 if(style_src == NULL) return;
82
83 LV_ASSERT_STYLE(style_dest);
84 LV_ASSERT_STYLE(style_src);
85
86 if(style_src->map == NULL) return;
87
88 uint16_t size = _lv_style_get_mem_size(style_src);
89 style_dest->map = lv_mem_alloc(size);
90 _lv_memcpy(style_dest->map, style_src->map, size);
91 }
92
93 /**
94 * Remove a property from a style
95 * @param style pointer to a style
96 * @param prop a style property ORed with a state.
97 * E.g. `LV_STYLE_BORDER_WIDTH | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
98 * @return true: the property was found and removed; false: the property wasn't found
99 */
lv_style_remove_prop(lv_style_t * style,lv_style_property_t prop)100 bool lv_style_remove_prop(lv_style_t * style, lv_style_property_t prop)
101 {
102 if(style == NULL) return false;
103 LV_ASSERT_STYLE(style);
104
105 int32_t id = get_property_index(style, prop);
106 /*The property exists but not sure it's state is the same*/
107 if(id >= 0) {
108 lv_style_attr_t attr_found;
109 lv_style_attr_t attr_goal;
110
111 attr_found = get_style_prop_attr(style, id);
112 attr_goal = (prop >> 8) & 0xFFU;
113
114 if(LV_STYLE_ATTR_GET_STATE(attr_found) == LV_STYLE_ATTR_GET_STATE(attr_goal)) {
115 uint32_t map_size = _lv_style_get_mem_size(style);
116 uint8_t prop_size = get_prop_size(prop);
117
118 /*Move the props to fill the space of the property to delete*/
119 uint32_t i;
120 for(i = id; i < map_size - prop_size; i++) {
121 style->map[i] = style->map[i + prop_size];
122 }
123
124 style_resize(style, map_size - prop_size);
125
126 return true;
127 }
128 }
129
130 return false;
131 }
132
133 /**
134 * Initialize a style list
135 * @param list a style list to initialize
136 */
lv_style_list_init(lv_style_list_t * list)137 void lv_style_list_init(lv_style_list_t * list)
138 {
139 _lv_memset_00(list, sizeof(lv_style_list_t));
140 #if LV_USE_ASSERT_STYLE
141 list->sentinel = LV_DEBUG_STYLE_LIST_SENTINEL_VALUE;
142 #endif
143 }
144
145 /**
146 * Copy a style list with all its styles and local style properties
147 * @param list_dest pointer to the destination style list. (should be initialized with `lv_style_list_init()`)
148 * @param list_src pointer to the source (to copy) style list.
149 */
lv_style_list_copy(lv_style_list_t * list_dest,const lv_style_list_t * list_src)150 void lv_style_list_copy(lv_style_list_t * list_dest, const lv_style_list_t * list_src)
151 {
152 LV_ASSERT_STYLE_LIST(list_dest);
153 LV_ASSERT_STYLE_LIST(list_src);
154
155 _lv_style_list_reset(list_dest);
156
157 if(list_src->style_list == NULL) return;
158
159 /*Copy the styles but skip the transitions*/
160 if(list_src->has_local == 0) {
161 if(list_src->has_trans) {
162 list_dest->style_list = lv_mem_alloc((list_src->style_cnt - 1) * sizeof(lv_style_t *));
163 _lv_memcpy(list_dest->style_list, list_src->style_list + 1, (list_src->style_cnt - 1) * sizeof(lv_style_t *));
164 list_dest->style_cnt = list_src->style_cnt - 1;
165 }
166 else {
167 list_dest->style_list = lv_mem_alloc(list_src->style_cnt * sizeof(lv_style_t *));
168 _lv_memcpy(list_dest->style_list, list_src->style_list, list_src->style_cnt * sizeof(lv_style_t *));
169 list_dest->style_cnt = list_src->style_cnt;
170 }
171 }
172 else {
173 if(list_src->has_trans) {
174 list_dest->style_list = lv_mem_alloc((list_src->style_cnt - 2) * sizeof(lv_style_t *));
175 _lv_memcpy(list_dest->style_list, list_src->style_list + 2, (list_src->style_cnt - 2) * sizeof(lv_style_t *));
176 list_dest->style_cnt = list_src->style_cnt - 2;
177 }
178 else {
179 list_dest->style_list = lv_mem_alloc((list_src->style_cnt - 1) * sizeof(lv_style_t *));
180 _lv_memcpy(list_dest->style_list, list_src->style_list + 1, (list_src->style_cnt - 1) * sizeof(lv_style_t *));
181 list_dest->style_cnt = list_src->style_cnt - 1;
182 }
183
184 lv_style_t * local_style = get_alloc_local_style(list_dest);
185 lv_style_copy(local_style, get_alloc_local_style((lv_style_list_t *)list_src));
186 }
187 }
188
189 /**
190 * Add a style to a style list.
191 * Only the the style pointer will be saved so the shouldn't be a local variable.
192 * (It should be static, global or dynamically allocated)
193 * @param list pointer to a style list
194 * @param style pointer to a style to add
195 */
_lv_style_list_add_style(lv_style_list_t * list,lv_style_t * style)196 void _lv_style_list_add_style(lv_style_list_t * list, lv_style_t * style)
197 {
198 LV_ASSERT_STYLE_LIST(list);
199 LV_ASSERT_STYLE(style);
200
201 if(list == NULL) return;
202
203 /*Remove the style first if already exists*/
204 _lv_style_list_remove_style(list, style);
205
206 lv_style_t ** new_classes;
207 if(list->style_cnt == 0) new_classes = lv_mem_alloc(sizeof(lv_style_t *));
208 else new_classes = lv_mem_realloc(list->style_list, sizeof(lv_style_t *) * (list->style_cnt + 1));
209 LV_ASSERT_MEM(new_classes);
210 if(new_classes == NULL) {
211 LV_LOG_WARN("lv_style_list_add_style: couldn't add the class");
212 return;
213 }
214
215 /*Make space for the new style at the beginning. Leave local and trans style if exists*/
216 uint8_t i;
217 uint8_t first_style = 0;
218 if(list->has_trans) first_style++;
219 if(list->has_local) first_style++;
220 for(i = list->style_cnt; i > first_style; i--) {
221 new_classes[i] = new_classes[i - 1];
222 }
223
224 new_classes[first_style] = style;
225 list->style_cnt++;
226 list->style_list = new_classes;
227 }
228
229 /**
230 * Remove a style from a style list
231 * @param style_list pointer to a style list
232 * @param style pointer to a style to remove
233 */
_lv_style_list_remove_style(lv_style_list_t * list,lv_style_t * style)234 void _lv_style_list_remove_style(lv_style_list_t * list, lv_style_t * style)
235 {
236 LV_ASSERT_STYLE_LIST(list);
237 LV_ASSERT_STYLE(style);
238
239 if(list->style_cnt == 0) return;
240
241 /*Check if the style really exists here*/
242 uint8_t i;
243 bool found = false;
244 for(i = 0; i < list->style_cnt; i++) {
245 if(list->style_list[i] == style) {
246 found = true;
247 break;
248 }
249 }
250 if(found == false) return;
251
252 if(list->style_cnt == 1) {
253 lv_mem_free(list->style_list);
254 list->style_list = NULL;
255 list->style_cnt = 0;
256 list->has_local = 0;
257 return;
258 }
259
260 lv_style_t ** new_classes = lv_mem_alloc(sizeof(lv_style_t *) * (list->style_cnt - 1));
261 LV_ASSERT_MEM(new_classes);
262 if(new_classes == NULL) {
263 LV_LOG_WARN("lv_style_list_remove_style: couldn't reallocate class list");
264 return;
265 }
266 uint8_t j;
267 for(i = 0, j = 0; i < list->style_cnt; i++) {
268 if(list->style_list[i] == style) continue;
269 new_classes[j] = list->style_list[i];
270 j++;
271
272 }
273
274 lv_mem_free(list->style_list);
275
276 list->style_cnt--;
277 list->style_list = new_classes;
278 }
279
280 /**
281 * Remove all styles added from style list, clear the local style, transition style and free all allocated memories.
282 * Leave `ignore_trans` flag as it is.
283 * @param list pointer to a style list.
284 */
_lv_style_list_reset(lv_style_list_t * list)285 void _lv_style_list_reset(lv_style_list_t * list)
286 {
287 LV_ASSERT_STYLE_LIST(list);
288
289 if(list == NULL) return;
290
291 if(list->has_local) {
292 lv_style_t * local = lv_style_list_get_local_style(list);
293 if(local) {
294 lv_style_reset(local);
295 lv_mem_free(local);
296 }
297 }
298
299 if(list->has_trans) {
300 lv_style_t * trans = _lv_style_list_get_transition_style(list);
301 if(trans) {
302 lv_style_reset(trans);
303 lv_mem_free(trans);
304 }
305 }
306
307 if(list->style_cnt > 0) lv_mem_free(list->style_list);
308 list->style_list = NULL;
309 list->style_cnt = 0;
310 list->has_local = 0;
311 list->has_trans = 0;
312 list->skip_trans = 0;
313
314 /* Intentionally leave `ignore_trans` as it is,
315 * because it's independent from the styles in the list*/
316 }
317
318 /**
319 * Clear all properties from a style and all allocated memories.
320 * @param style pointer to a style
321 */
lv_style_reset(lv_style_t * style)322 void lv_style_reset(lv_style_t * style)
323 {
324 LV_ASSERT_STYLE(style);
325
326 lv_mem_free(style->map);
327 style->map = NULL;
328 }
329
330 /**
331 * Get the size of the properties in a style in bytes
332 * @param style pointer to a style
333 * @return size of the properties in bytes
334 */
_lv_style_get_mem_size(const lv_style_t * style)335 uint16_t _lv_style_get_mem_size(const lv_style_t * style)
336 {
337 LV_ASSERT_STYLE(style);
338
339 if(style->map == NULL) return 0;
340
341 size_t i = 0;
342 uint8_t prop_id;
343 while((prop_id = get_style_prop_id(style, i)) != _LV_STYLE_CLOSEING_PROP) {
344 i = get_next_prop_index(prop_id, i);
345 }
346
347 return i + sizeof(lv_style_property_t);
348 }
349
350 /**
351 * Set an integer typed property in a style.
352 * @param style pointer to a style where the property should be set
353 * @param prop a style property ORed with a state.
354 * E.g. `LV_STYLE_BORDER_WIDTH | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
355 * @param value the value to set
356 * @note shouldn't be used directly. Use the specific property set functions instead.
357 * For example: `lv_style_set_border_width()`
358 * @note for performance reasons it's not checked if the property really has integer type
359 */
_lv_style_set_int(lv_style_t * style,lv_style_property_t prop,lv_style_int_t value)360 void _lv_style_set_int(lv_style_t * style, lv_style_property_t prop, lv_style_int_t value)
361 {
362 LV_ASSERT_STYLE(style);
363
364 int32_t id = get_property_index(style, prop);
365 /*The property already exists but not sure it's state is the same*/
366 if(id >= 0) {
367 lv_style_attr_t attr_found;
368 lv_style_attr_t attr_goal;
369
370 attr_found = get_style_prop_attr(style, id);
371 attr_goal = (prop >> 8) & 0xFFU;
372
373 if(LV_STYLE_ATTR_GET_STATE(attr_found) == LV_STYLE_ATTR_GET_STATE(attr_goal)) {
374 _lv_memcpy_small(style->map + id + sizeof(lv_style_property_t), &value, sizeof(lv_style_int_t));
375 return;
376 }
377 }
378
379 /*Add new property if not exists yet*/
380 uint8_t new_prop_size = (sizeof(lv_style_property_t) + sizeof(lv_style_int_t));
381 lv_style_property_t end_mark = _LV_STYLE_CLOSEING_PROP;
382 uint8_t end_mark_size = sizeof(end_mark);
383
384 uint16_t size = _lv_style_get_mem_size(style);
385 if(size == 0) size += end_mark_size;
386 size += sizeof(lv_style_property_t) + sizeof(lv_style_int_t);
387 style_resize(style, size);
388 LV_ASSERT_MEM(style->map);
389 if(style == NULL) return;
390
391 _lv_memcpy_small(style->map + size - new_prop_size - end_mark_size, &prop, sizeof(lv_style_property_t));
392 _lv_memcpy_small(style->map + size - sizeof(lv_style_int_t) - end_mark_size, &value, sizeof(lv_style_int_t));
393 _lv_memcpy_small(style->map + size - end_mark_size, &end_mark, sizeof(end_mark));
394 }
395
396 /**
397 * Set a color typed property in a style.
398 * @param style pointer to a style where the property should be set
399 * @param prop a style property ORed with a state.
400 * E.g. `LV_STYLE_BORDER_COLOR | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
401 * @param value the value to set
402 * @note shouldn't be used directly. Use the specific property set functions instead.
403 * For example: `lv_style_set_border_color()`
404 * @note for performance reasons it's not checked if the property really has color type
405 */
_lv_style_set_color(lv_style_t * style,lv_style_property_t prop,lv_color_t color)406 void _lv_style_set_color(lv_style_t * style, lv_style_property_t prop, lv_color_t color)
407 {
408 LV_ASSERT_STYLE(style);
409
410 int32_t id = get_property_index(style, prop);
411 /*The property already exists but not sure it's state is the same*/
412 if(id >= 0) {
413 lv_style_attr_t attr_found;
414 lv_style_attr_t attr_goal;
415
416 attr_found = get_style_prop_attr(style, id);
417 attr_goal = (prop >> 8) & 0xFFU;
418
419 if(LV_STYLE_ATTR_GET_STATE(attr_found) == LV_STYLE_ATTR_GET_STATE(attr_goal)) {
420 _lv_memcpy_small(style->map + id + sizeof(lv_style_property_t), &color, sizeof(lv_color_t));
421 return;
422 }
423 }
424
425 /*Add new property if not exists yet*/
426 uint8_t new_prop_size = (sizeof(lv_style_property_t) + sizeof(lv_color_t));
427 lv_style_property_t end_mark = _LV_STYLE_CLOSEING_PROP;
428 uint8_t end_mark_size = sizeof(end_mark);
429
430 uint16_t size = _lv_style_get_mem_size(style);
431 if(size == 0) size += end_mark_size;
432
433 size += sizeof(lv_style_property_t) + sizeof(lv_color_t);
434 style_resize(style, size);
435 LV_ASSERT_MEM(style->map);
436 if(style == NULL) return;
437
438 _lv_memcpy_small(style->map + size - new_prop_size - end_mark_size, &prop, sizeof(lv_style_property_t));
439 _lv_memcpy_small(style->map + size - sizeof(lv_color_t) - end_mark_size, &color, sizeof(lv_color_t));
440 _lv_memcpy_small(style->map + size - end_mark_size, &end_mark, sizeof(end_mark));
441 }
442
443 /**
444 * Set an opacity typed property in a style.
445 * @param style pointer to a style where the property should be set
446 * @param prop a style property ORed with a state.
447 * E.g. `LV_STYLE_BORDER_OPA | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
448 * @param value the value to set
449 * @note shouldn't be used directly. Use the specific property set functions instead.
450 * For example: `lv_style_set_border_opa()`
451 * @note for performance reasons it's not checked if the property really has opacity type
452 */
_lv_style_set_opa(lv_style_t * style,lv_style_property_t prop,lv_opa_t opa)453 void _lv_style_set_opa(lv_style_t * style, lv_style_property_t prop, lv_opa_t opa)
454 {
455 LV_ASSERT_STYLE(style);
456
457 int32_t id = get_property_index(style, prop);
458 /*The property already exists but not sure it's state is the same*/
459 if(id >= 0) {
460 lv_style_attr_t attr_found;
461 lv_style_attr_t attr_goal;
462
463 attr_found = get_style_prop_attr(style, id);
464 attr_goal = (prop >> 8) & 0xFFU;
465
466 if(LV_STYLE_ATTR_GET_STATE(attr_found) == LV_STYLE_ATTR_GET_STATE(attr_goal)) {
467 _lv_memcpy_small(style->map + id + sizeof(lv_style_property_t), &opa, sizeof(lv_opa_t));
468 return;
469 }
470 }
471
472 /*Add new property if not exists yet*/
473 uint8_t new_prop_size = (sizeof(lv_style_property_t) + sizeof(lv_opa_t));
474 lv_style_property_t end_mark = _LV_STYLE_CLOSEING_PROP;
475 uint8_t end_mark_size = sizeof(end_mark);
476
477 uint16_t size = _lv_style_get_mem_size(style);
478 if(size == 0) size += end_mark_size;
479
480 size += sizeof(lv_style_property_t) + sizeof(lv_opa_t);
481 style_resize(style, size);
482 LV_ASSERT_MEM(style->map);
483 if(style == NULL) return;
484
485 _lv_memcpy_small(style->map + size - new_prop_size - end_mark_size, &prop, sizeof(lv_style_property_t));
486 _lv_memcpy_small(style->map + size - sizeof(lv_opa_t) - end_mark_size, &opa, sizeof(lv_opa_t));
487 _lv_memcpy_small(style->map + size - end_mark_size, &end_mark, sizeof(end_mark));
488 }
489
490 /**
491 * Set a pointer typed property in a style.
492 * @param style pointer to a style where the property should be set
493 * @param prop a style property ORed with a state.
494 * E.g. `LV_STYLE_TEXT_POINTER | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
495 * @param value the value to set
496 * @note shouldn't be used directly. Use the specific property set functions instead.
497 * For example: `lv_style_set_border_width()`
498 * @note for performance reasons it's not checked if the property is really has pointer type
499 */
_lv_style_set_ptr(lv_style_t * style,lv_style_property_t prop,const void * p)500 void _lv_style_set_ptr(lv_style_t * style, lv_style_property_t prop, const void * p)
501 {
502 LV_ASSERT_STYLE(style);
503
504 int32_t id = get_property_index(style, prop);
505 /*The property already exists but not sure it's state is the same*/
506 if(id >= 0) {
507 lv_style_attr_t attr_found;
508 lv_style_attr_t attr_goal;
509
510 attr_found = get_style_prop_attr(style, id);
511 attr_goal = (prop >> 8) & 0xFFU;
512
513 if(LV_STYLE_ATTR_GET_STATE(attr_found) == LV_STYLE_ATTR_GET_STATE(attr_goal)) {
514 _lv_memcpy_small(style->map + id + sizeof(lv_style_property_t), &p, sizeof(const void *));
515 return;
516 }
517 }
518
519 /*Add new property if not exists yet*/
520 uint8_t new_prop_size = (sizeof(lv_style_property_t) + sizeof(const void *));
521 lv_style_property_t end_mark = _LV_STYLE_CLOSEING_PROP;
522 uint8_t end_mark_size = sizeof(end_mark);
523
524 uint16_t size = _lv_style_get_mem_size(style);
525 if(size == 0) size += end_mark_size;
526
527 size += sizeof(lv_style_property_t) + sizeof(const void *);
528 style_resize(style, size);
529 LV_ASSERT_MEM(style->map);
530 if(style == NULL) return;
531
532 _lv_memcpy_small(style->map + size - new_prop_size - end_mark_size, &prop, sizeof(lv_style_property_t));
533 _lv_memcpy_small(style->map + size - sizeof(const void *) - end_mark_size, &p, sizeof(const void *));
534 _lv_memcpy_small(style->map + size - end_mark_size, &end_mark, sizeof(end_mark));
535 }
536
537 /**
538 * Get the a property from a style.
539 * Take into account the style state and return the property which matches the best.
540 * @param style pointer to a style where to search
541 * @param prop the property, might contain ORed style states too
542 * @param res buffer to store the result
543 * @return the weight of the found property (how well it fits to the style state).
544 * Higher number is means better fit
545 * -1 if the not found (`res` will be undefined)
546 */
_lv_style_get_int(const lv_style_t * style,lv_style_property_t prop,void * v_res)547 int16_t _lv_style_get_int(const lv_style_t * style, lv_style_property_t prop, void * v_res)
548 {
549 lv_style_int_t * res = (lv_style_int_t *)v_res;
550 LV_ASSERT_STYLE(style);
551
552 if(style == NULL) return -1;
553 if(style->map == NULL) return -1;
554
555 int32_t id = get_property_index(style, prop);
556 if(id < 0) {
557 return -1;
558 }
559 else {
560 _lv_memcpy_small(res, &style->map[id + sizeof(lv_style_property_t)], sizeof(lv_style_int_t));
561 lv_style_attr_t attr_act;
562 attr_act = get_style_prop_attr(style, id);
563
564 lv_style_attr_t attr_goal;
565 attr_goal = (prop >> 8) & 0xFF;
566
567 return LV_STYLE_ATTR_GET_STATE(attr_act) & LV_STYLE_ATTR_GET_STATE(attr_goal);
568 }
569 }
570
571 /**
572 * Get an opacity typed property from a style.
573 * @param style pointer to a style from where the property should be get
574 * @param prop a style property ORed with a state.
575 * E.g. `LV_STYLE_BORDER_OPA | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
576 * @param res pointer to a buffer to store the result value
577 * @return -1: the property wasn't found in the style.
578 * The matching state bits of the desired state (in `prop`) and the best matching property's state
579 * Higher value means match in higher precedence state.
580 * @note shouldn't be used directly. Use the specific property get functions instead.
581 * For example: `lv_style_get_border_opa()`
582 * @note for performance reasons it's not checked if the property really has opacity type
583 */
_lv_style_get_opa(const lv_style_t * style,lv_style_property_t prop,void * v_res)584 int16_t _lv_style_get_opa(const lv_style_t * style, lv_style_property_t prop, void * v_res)
585 {
586 lv_opa_t * res = (lv_opa_t *)v_res;
587 LV_ASSERT_STYLE(style);
588
589 if(style == NULL) return -1;
590 if(style->map == NULL) return -1;
591
592 int32_t id = get_property_index(style, prop);
593 if(id < 0) {
594 return -1;
595 }
596 else {
597 _lv_memcpy_small(res, &style->map[id + sizeof(lv_style_property_t)], sizeof(lv_opa_t));
598 lv_style_attr_t attr_act;
599 attr_act = get_style_prop_attr(style, id);
600
601 lv_style_attr_t attr_goal;
602 attr_goal = (prop >> 8) & 0xFF;
603
604 return LV_STYLE_ATTR_GET_STATE(attr_act) & LV_STYLE_ATTR_GET_STATE(attr_goal);
605 }
606 }
607
608 /**
609 * Get a color typed property from a style.
610 * @param style pointer to a style from where the property should be get
611 * @param prop a style property ORed with a state.
612 * E.g. `LV_STYLE_BORDER_COLOR | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
613 * @param res pointer to a buffer to store the result value
614 * @return -1: the property wasn't found in the style.
615 * The matching state bits of the desired state (in `prop`) and the best matching property's state
616 * Higher value means match in higher precedence state.
617 * @note shouldn't be used directly. Use the specific property get functions instead.
618 * For example: `lv_style_get_border_color()`
619 * @note for performance reasons it's not checked if the property really has color type
620 */
_lv_style_get_color(const lv_style_t * style,lv_style_property_t prop,void * v_res)621 int16_t _lv_style_get_color(const lv_style_t * style, lv_style_property_t prop, void * v_res)
622 {
623 lv_color_t * res = (lv_color_t *)v_res;
624 if(style == NULL) return -1;
625 if(style->map == NULL) return -1;
626 int32_t id = get_property_index(style, prop);
627 if(id < 0) {
628 return -1;
629 }
630 else {
631 _lv_memcpy_small(res, &style->map[id + sizeof(lv_style_property_t)], sizeof(lv_color_t));
632 lv_style_attr_t attr_act;
633 attr_act = get_style_prop_attr(style, id);
634
635 lv_style_attr_t attr_goal;
636 attr_goal = (prop >> 8) & 0xFF;
637
638 return LV_STYLE_ATTR_GET_STATE(attr_act) & LV_STYLE_ATTR_GET_STATE(attr_goal);
639 }
640 }
641
642 /**
643 * Get a pointer typed property from a style.
644 * @param style pointer to a style from where the property should be get
645 * @param prop a style property ORed with a state.
646 * E.g. `LV_STYLE_TEXT_FONT | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
647 * @param res pointer to a buffer to store the result value
648 * @return -1: the property wasn't found in the style.
649 * The matching state bits of the desired state (in `prop`) and the best matching property's state
650 * Higher value means match in higher precedence state.
651 * @note shouldn't be used directly. Use the specific property get functions instead.
652 * For example: `lv_style_get_text_font()`
653 * @note for performance reasons it's not checked if the property really has pointer type
654 */
_lv_style_get_ptr(const lv_style_t * style,lv_style_property_t prop,void * v_res)655 int16_t _lv_style_get_ptr(const lv_style_t * style, lv_style_property_t prop, void * v_res)
656 {
657 const void ** res = (const void **)v_res;
658 if(style == NULL) return -1;
659 if(style->map == NULL) return -1;
660
661 int32_t id = get_property_index(style, prop);
662 if(id < 0) {
663 return -1;
664 }
665 else {
666 _lv_memcpy_small(res, &style->map[id + sizeof(lv_style_property_t)], sizeof(const void *));
667 lv_style_attr_t attr_act;
668 attr_act = get_style_prop_attr(style, id);
669
670 lv_style_attr_t attr_goal;
671 attr_goal = (prop >> 8) & 0xFF;
672
673 return LV_STYLE_ATTR_GET_STATE(attr_act) & LV_STYLE_ATTR_GET_STATE(attr_goal);
674 }
675 }
676
677 /**
678 * Get the local style of a style list
679 * @param list pointer to a style list where the local property should be set
680 * @return pointer to the local style if exists else `NULL`.
681 */
lv_style_list_get_local_style(lv_style_list_t * list)682 lv_style_t * lv_style_list_get_local_style(lv_style_list_t * list)
683 {
684 LV_ASSERT_STYLE_LIST(list);
685
686 if(!list->has_local) return NULL;
687 if(list->has_trans) return list->style_list[1];
688 else return list->style_list[0];
689 }
690
691 /**
692 * Get the transition style of a style list
693 * @param list pointer to a style list where the local property should be set
694 * @return pointer to the transition style if exists else `NULL`.
695 */
_lv_style_list_get_transition_style(lv_style_list_t * list)696 lv_style_t * _lv_style_list_get_transition_style(lv_style_list_t * list)
697 {
698 LV_ASSERT_STYLE_LIST(list);
699
700 if(!list->has_trans) return NULL;
701 return list->style_list[0];
702 }
703
704 /**
705 * Allocate the transition style in a style list. If already exists simply return it.
706 * @param list pointer to a style list
707 * @return the transition style of a style list
708 */
_lv_style_list_add_trans_style(lv_style_list_t * list)709 lv_style_t * _lv_style_list_add_trans_style(lv_style_list_t * list)
710 {
711 LV_ASSERT_STYLE_LIST(list);
712 if(list->has_trans) return _lv_style_list_get_transition_style(list);
713
714 lv_style_t * trans_style = lv_mem_alloc(sizeof(lv_style_t));
715 LV_ASSERT_MEM(trans_style);
716 if(trans_style == NULL) {
717 LV_LOG_WARN("lv_style_list_add_trans_style: couldn't create transition style");
718 return NULL;
719 }
720
721 lv_style_init(trans_style);
722
723 _lv_style_list_add_style(list, trans_style);
724 list->has_trans = 1;
725
726 /*If the list has local style trans was added after it. But trans should be the first so swap them*/
727 if(list->has_local) {
728 lv_style_t * tmp = list->style_list[0];
729 list->style_list[0] = list->style_list[1];
730 list->style_list[1] = tmp;
731 }
732 return trans_style;
733 }
734
735
736 /**
737 * Set a local integer typed property in a style list.
738 * @param list pointer to a style list where the local property should be set
739 * @param prop a style property ORed with a state.
740 * E.g. `LV_STYLE_BORDER_WIDTH | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
741 * @param value the value to set
742 * @note for performance reasons it's not checked if the property really has integer type
743 */
_lv_style_list_set_local_int(lv_style_list_t * list,lv_style_property_t prop,lv_style_int_t value)744 void _lv_style_list_set_local_int(lv_style_list_t * list, lv_style_property_t prop, lv_style_int_t value)
745 {
746 LV_ASSERT_STYLE_LIST(list);
747
748 lv_style_t * local = get_alloc_local_style(list);
749 _lv_style_set_int(local, prop, value);
750 }
751
752 /**
753 * Set a local opacity typed property in a style list.
754 * @param list pointer to a style list where the local property should be set
755 * @param prop a style property ORed with a state.
756 * E.g. `LV_STYLE_BORDER_OPA | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
757 * @param value the value to set
758 * @note for performance reasons it's not checked if the property really has opacity type
759 */
_lv_style_list_set_local_opa(lv_style_list_t * list,lv_style_property_t prop,lv_opa_t value)760 void _lv_style_list_set_local_opa(lv_style_list_t * list, lv_style_property_t prop, lv_opa_t value)
761 {
762 LV_ASSERT_STYLE_LIST(list);
763
764 lv_style_t * local = get_alloc_local_style(list);
765 _lv_style_set_opa(local, prop, value);
766 }
767
768 /**
769 * Set a local color typed property in a style list.
770 * @param list pointer to a style list where the local property should be set
771 * @param prop a style property ORed with a state.
772 * E.g. `LV_STYLE_BORDER_COLOR | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
773 * @param value the value to set
774 * @note for performance reasons it's not checked if the property really has color type
775 */
_lv_style_list_set_local_color(lv_style_list_t * list,lv_style_property_t prop,lv_color_t value)776 void _lv_style_list_set_local_color(lv_style_list_t * list, lv_style_property_t prop, lv_color_t value)
777 {
778 LV_ASSERT_STYLE_LIST(list);
779
780 lv_style_t * local = get_alloc_local_style(list);
781 _lv_style_set_color(local, prop, value);
782 }
783
784 /**
785 * Set a local pointer typed property in a style list.
786 * @param list pointer to a style list where the local property should be set
787 * @param prop a style property ORed with a state.
788 * E.g. `LV_STYLE_TEXT_FONT | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
789 * @param value the value to set
790 * @note for performance reasons it's not checked if the property really has pointer type
791 */
_lv_style_list_set_local_ptr(lv_style_list_t * list,lv_style_property_t prop,const void * value)792 void _lv_style_list_set_local_ptr(lv_style_list_t * list, lv_style_property_t prop, const void * value)
793 {
794 LV_ASSERT_STYLE_LIST(list);
795
796 lv_style_t * local = get_alloc_local_style(list);
797 _lv_style_set_ptr(local, prop, value);
798 }
799
800
801
802 /**
803 * Get an integer typed property from a style list.
804 * It will return the property which match best with given state.
805 * @param list pointer to a style list from where the property should be get
806 * @param prop a style property ORed with a state.
807 * E.g. `LV_STYLE_BORDER_WIDTH | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
808 * @param res pointer to a buffer to store the result
809 * @return LV_RES_OK: there was a matching property in the list
810 * LV_RES_INV: there was NO matching property in the list
811 * @note for performance reasons it's not checked if the property really has integer type
812 */
_lv_style_list_get_int(lv_style_list_t * list,lv_style_property_t prop,lv_style_int_t * res)813 lv_res_t _lv_style_list_get_int(lv_style_list_t * list, lv_style_property_t prop, lv_style_int_t * res)
814 {
815 LV_ASSERT_STYLE_LIST(list);
816
817 if(list == NULL) return LV_RES_INV;
818 if(list->style_list == NULL) return LV_RES_INV;
819
820 lv_style_attr_t attr;
821 attr = prop >> 8;
822 int16_t weight_goal = attr;
823
824 int16_t weight = -1;
825
826 lv_style_int_t value_act = 0;
827
828 int16_t ci;
829 for(ci = 0; ci < list->style_cnt; ci++) {
830 lv_style_t * class = lv_style_list_get_style(list, ci);
831 int16_t weight_act = _lv_style_get_int(class, prop, &value_act);
832
833 /*On perfect match return the value immediately*/
834 if(weight_act == weight_goal) {
835 *res = value_act;
836 return LV_RES_OK;
837 }
838 else if(list->has_trans && weight_act >= 0 && ci == 0 && !list->skip_trans) {
839 *res = value_act;
840 return LV_RES_OK;
841 }
842 /*If the found ID is better the current candidate then use it*/
843 else if(weight_act > weight) {
844 weight = weight_act;
845 *res = value_act;
846 }
847 }
848
849 if(weight >= 0) return LV_RES_OK;
850 else return LV_RES_INV;
851
852 }
853
854 /**
855 * Get a color typed property from a style list.
856 * It will return the property which match best with given state.
857 * @param list pointer to a style list from where the property should be get
858 * @param prop a style property ORed with a state.
859 * E.g. `LV_STYLE_BORDER_COLOR | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
860 * @param res pointer to a buffer to store the result
861 * @return LV_RES_OK: there was a matching property in the list
862 * LV_RES_INV: there was NO matching property in the list
863 * @note for performance reasons it's not checked if the property really has color type
864 */
_lv_style_list_get_color(lv_style_list_t * list,lv_style_property_t prop,lv_color_t * res)865 lv_res_t _lv_style_list_get_color(lv_style_list_t * list, lv_style_property_t prop, lv_color_t * res)
866 {
867 LV_ASSERT_STYLE_LIST(list);
868
869 if(list == NULL) return LV_RES_INV;
870 if(list->style_list == NULL) return LV_RES_INV;
871
872 lv_style_attr_t attr;
873 attr = prop >> 8;
874 int16_t weight_goal = attr;
875
876 int16_t weight = -1;
877
878 lv_color_t value_act;
879 value_act.full = 0;
880
881 int16_t ci;
882 for(ci = 0; ci < list->style_cnt; ci++) {
883 lv_style_t * class = lv_style_list_get_style(list, ci);
884 int16_t weight_act = _lv_style_get_color(class, prop, &value_act);
885 /*On perfect match return the value immediately*/
886 if(weight_act == weight_goal) {
887 *res = value_act;
888 return LV_RES_OK;
889 }
890 else if(list->has_trans && weight_act >= 0 && ci == 0 && !list->skip_trans) {
891 *res = value_act;
892 return LV_RES_OK;
893 }
894 /*If the found ID is better the current candidate then use it*/
895 else if(weight_act > weight) {
896 weight = weight_act;
897 *res = value_act;
898 }
899 }
900
901 if(weight >= 0) return LV_RES_OK;
902 else return LV_RES_INV;
903 }
904
905 /**
906 * Get an opacity typed property from a style list.
907 * It will return the property which match best with given state.
908 * @param list pointer to a style list from where the property should be get
909 * @param prop a style property ORed with a state.
910 * E.g. `LV_STYLE_BORDER_OPA| (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
911 * @param res pointer to a buffer to store the result
912 * @return LV_RES_OK: there was a matching property in the list
913 * LV_RES_INV: there was NO matching property in the list
914 * @note for performance reasons it's not checked if the property really has opacity type
915 */
_lv_style_list_get_opa(lv_style_list_t * list,lv_style_property_t prop,lv_opa_t * res)916 lv_res_t _lv_style_list_get_opa(lv_style_list_t * list, lv_style_property_t prop, lv_opa_t * res)
917 {
918 LV_ASSERT_STYLE_LIST(list);
919
920 if(list == NULL) return LV_RES_INV;
921 if(list->style_list == NULL) return LV_RES_INV;
922
923 lv_style_attr_t attr;
924 attr = prop >> 8;
925 int16_t weight_goal = attr;
926
927 int16_t weight = -1;
928
929 lv_opa_t value_act = LV_OPA_TRANSP;
930
931 int16_t ci;
932 for(ci = 0; ci < list->style_cnt; ci++) {
933 lv_style_t * class = lv_style_list_get_style(list, ci);
934 int16_t weight_act = _lv_style_get_opa(class, prop, &value_act);
935 /*On perfect match return the value immediately*/
936 if(weight_act == weight_goal) {
937 *res = value_act;
938 return LV_RES_OK;
939 }
940 else if(list->has_trans && weight_act >= 0 && ci == 0 && !list->skip_trans) {
941 *res = value_act;
942 return LV_RES_OK;
943 }
944 /*If the found ID is better the current candidate then use it*/
945 else if(weight_act > weight) {
946 weight = weight_act;
947 *res = value_act;
948 }
949 }
950
951 if(weight >= 0) return LV_RES_OK;
952 else return LV_RES_INV;
953 }
954
955 /**
956 * Get a pointer typed property from a style list.
957 * It will return the property which match best with given state.
958 * @param list pointer to a style list from where the property should be get
959 * @param prop a style property ORed with a state.
960 * E.g. `LV_STYLE_TEXT_FONT | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
961 * @param res pointer to a buffer to store the result
962 * @return LV_RES_OK: there was a matching property in the list
963 * LV_RES_INV: there was NO matching property in the list
964 * @note for performance reasons it's not checked if the property really has pointer type
965 */
_lv_style_list_get_ptr(lv_style_list_t * list,lv_style_property_t prop,const void ** res)966 lv_res_t _lv_style_list_get_ptr(lv_style_list_t * list, lv_style_property_t prop, const void ** res)
967 {
968 LV_ASSERT_STYLE_LIST(list);
969
970 if(list == NULL) return LV_RES_INV;
971 if(list->style_list == NULL) return LV_RES_INV;
972
973 lv_style_attr_t attr;
974 attr = prop >> 8;
975 int16_t weight_goal = attr;
976
977 int16_t weight = -1;
978
979 const void * value_act;
980
981 int16_t ci;
982 for(ci = 0; ci < list->style_cnt; ci++) {
983 lv_style_t * class = lv_style_list_get_style(list, ci);
984 int16_t weight_act = _lv_style_get_ptr(class, prop, &value_act);
985 /*On perfect match return the value immediately*/
986 if(weight_act == weight_goal) {
987 *res = value_act;
988 return LV_RES_OK;
989 }
990 else if(list->has_trans && weight_act >= 0 && ci == 0 && !list->skip_trans) {
991 *res = value_act;
992 return LV_RES_OK;
993 }
994 /*If the found ID is better the current candidate then use it*/
995 else if(weight_act > weight) {
996 weight = weight_act;
997 *res = value_act;
998 }
999 }
1000
1001 if(weight >= 0) return LV_RES_OK;
1002 else return LV_RES_INV;
1003 }
1004
1005 /**
1006 * Check whether a style is valid (initialized correctly)
1007 * @param style pointer to a style
1008 * @return true: valid
1009 */
lv_debug_check_style(const lv_style_t * style)1010 bool lv_debug_check_style(const lv_style_t * style)
1011 {
1012 if(style == NULL) return true; /*NULL style is still valid*/
1013
1014 #if LV_USE_ASSERT_STYLE
1015 if(style->sentinel != LV_DEBUG_STYLE_SENTINEL_VALUE) {
1016 LV_LOG_WARN("Invalid style (local variable or not initialized?)");
1017 return false;
1018 }
1019 #endif
1020
1021 return true;
1022 }
1023
1024 /**
1025 * Check whether a style list is valid (initialized correctly)
1026 * @param style pointer to a style
1027 * @return true: valid
1028 */
lv_debug_check_style_list(const lv_style_list_t * list)1029 bool lv_debug_check_style_list(const lv_style_list_t * list)
1030 {
1031 if(list == NULL) return true; /*NULL list is still valid*/
1032
1033 #if LV_USE_ASSERT_STYLE
1034 if(list->sentinel != LV_DEBUG_STYLE_LIST_SENTINEL_VALUE) {
1035 LV_LOG_WARN("Invalid style (local variable or not initialized?)");
1036 return false;
1037 }
1038 #endif
1039
1040 return true;
1041 }
1042
1043 /**********************
1044 * STATIC FUNCTIONS
1045 **********************/
1046
1047 /**
1048 * Get a property's index (byte index in `style->map`) from a style.
1049 * Return best matching property's index considering the state of `prop`
1050 * @param style pointer to a style
1051 * @param prop a style property ORed with a state.
1052 * E.g. `LV_STYLE_TEXT_FONT | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
1053 * @return
1054 */
get_property_index(const lv_style_t * style,lv_style_property_t prop)1055 LV_ATTRIBUTE_FAST_MEM static inline int32_t get_property_index(const lv_style_t * style, lv_style_property_t prop)
1056 {
1057 LV_ASSERT_STYLE(style);
1058
1059 if(style->map == NULL) return -1;
1060
1061 uint8_t id_to_find = prop & 0xFF;
1062 lv_style_attr_t attr;
1063 attr = (prop >> 8) & 0xFF;
1064
1065 int16_t weight = -1;
1066 int16_t id_guess = -1;
1067
1068 size_t i = 0;
1069
1070 uint8_t prop_id;
1071 while((prop_id = get_style_prop_id(style, i)) != _LV_STYLE_CLOSEING_PROP) {
1072 if(prop_id == id_to_find) {
1073 lv_style_attr_t attr_i;
1074 attr_i = get_style_prop_attr(style, i);
1075
1076 /*If the state perfectly matches return this property*/
1077 if(LV_STYLE_ATTR_GET_STATE(attr_i) == LV_STYLE_ATTR_GET_STATE(attr)) {
1078 return i;
1079 }
1080 /* Be sure the property not specifies other state than the requested.
1081 * E.g. For HOVER+PRESS, HOVER only is OK, but HOVER+FOCUS not*/
1082 else if((LV_STYLE_ATTR_GET_STATE(attr_i) & (~LV_STYLE_ATTR_GET_STATE(attr))) == 0) {
1083 /* Use this property if it describes better the requested state than the current candidate.
1084 * E.g. for HOVER+FOCUS+PRESS prefer HOVER+FOCUS over FOCUS*/
1085 if(LV_STYLE_ATTR_GET_STATE(attr_i) > weight) {
1086 weight = LV_STYLE_ATTR_GET_STATE(attr_i);
1087 id_guess = i;
1088 }
1089 }
1090 }
1091
1092 i = get_next_prop_index(prop_id, i);
1093 }
1094
1095 return id_guess;
1096 }
1097
1098 /**
1099 * Get he local style from a style list. Allocate it if not exists yet.
1100 * @param list pointer to a style list
1101 * @return pointer to the local style
1102 */
get_alloc_local_style(lv_style_list_t * list)1103 static lv_style_t * get_alloc_local_style(lv_style_list_t * list)
1104 {
1105 LV_ASSERT_STYLE_LIST(list);
1106
1107 if(list->has_local) return lv_style_list_get_style(list, list->has_trans ? 1 : 0);
1108
1109 lv_style_t * local_style = lv_mem_alloc(sizeof(lv_style_t));
1110 LV_ASSERT_MEM(local_style);
1111 if(local_style == NULL) {
1112 LV_LOG_WARN("get_local_style: couldn't create local style");
1113 return NULL;
1114 }
1115 lv_style_init(local_style);
1116
1117 /*Add the local style to the first place*/
1118 _lv_style_list_add_style(list, local_style);
1119 list->has_local = 1;
1120
1121 return local_style;
1122 }
1123
1124 /**
1125 * Resizes a style map. Useful entry point for debugging.
1126 * @param style pointer to the style to be resized.
1127 * @param size new size
1128 */
style_resize(lv_style_t * style,size_t sz)1129 static inline void style_resize(lv_style_t * style, size_t sz)
1130 {
1131 style->map = lv_mem_realloc(style->map, sz);
1132 }
1133
1134 /**
1135 * Get style property in index.
1136 * @param style pointer to style.
1137 * @param idx index of the style in style->map
1138 * @return property in style->map + idx
1139 */
get_style_prop(const lv_style_t * style,size_t idx)1140 static inline lv_style_property_t get_style_prop(const lv_style_t * style, size_t idx)
1141 {
1142 lv_style_property_t prop;
1143 uint8_t * prop_p = (uint8_t *)∝
1144 prop_p[0] = style->map[idx];
1145 prop_p[1] = style->map[idx + 1];
1146 return prop;
1147 }
1148
1149 /**
1150 * Get style property id in index.
1151 * @param style pointer to style.
1152 * @param idx index of the style in style->map
1153 * @return id of property in style->map + idx
1154 */
get_style_prop_id(const lv_style_t * style,size_t idx)1155 static inline uint8_t get_style_prop_id(const lv_style_t * style, size_t idx)
1156 {
1157 return get_style_prop(style, idx) & 0xFF;
1158 }
1159
1160 /**
1161 * Get style property attributes for index.
1162 * @param style pointer to style.
1163 * @param idx index of the style in style->map
1164 * @return attribute of property in style->map + idx
1165 */
get_style_prop_attr(const lv_style_t * style,size_t idx)1166 static inline uint8_t get_style_prop_attr(const lv_style_t * style, size_t idx)
1167 {
1168 return ((get_style_prop(style, idx) >> 8) & 0xFFU);
1169 }
1170
1171
1172 /**
1173 * Get property size.
1174 * @param prop_id property id.
1175 * @param idx index of the style in style->map
1176 * @return attribute of property in style->map + idx
1177 */
get_prop_size(uint8_t prop_id)1178 static inline size_t get_prop_size(uint8_t prop_id)
1179 {
1180 prop_id &= 0xF;
1181 size_t size = sizeof(lv_style_property_t);
1182 if(prop_id < LV_STYLE_ID_COLOR) size += sizeof(lv_style_int_t);
1183 else if(prop_id < LV_STYLE_ID_OPA) size += sizeof(lv_color_t);
1184 else if(prop_id < LV_STYLE_ID_PTR) size += sizeof(lv_opa_t);
1185 else size += sizeof(const void *);
1186 return size;
1187 }
1188
1189 /**
1190 * Get next property index, given current property and index.
1191 * @param prop_id property id.
1192 * @param idx index of the style in style->map
1193 * @return index of next property in style->map
1194 */
get_next_prop_index(uint8_t prop_id,size_t idx)1195 static inline size_t get_next_prop_index(uint8_t prop_id, size_t idx)
1196 {
1197 return idx + get_prop_size(prop_id);
1198 }
1199