2 * Hic Est Leo -- Styling
4 * (c) 2014 Martin Mares <mj@ucw.cz>
11 #include <ucw/mempool.h>
15 struct dict style_prop_dict, style_layer_dict;
17 static const char * const style_wk_props[] = {
19 #define P(x,y) [PROP_##x] = y,
20 #include "dict-props.h"
25 static const char * const style_wk_layers[] = {
31 void styles_init(void)
33 dict_init(&style_prop_dict, style_wk_props);
34 dict_init(&style_layer_dict, style_wk_layers);
37 #define HASH_NODE struct style_prop
38 #define HASH_PREFIX(x) style_prop_##x
39 #define HASH_KEY_ATOMIC key
40 #define HASH_WANT_FIND
41 #define HASH_WANT_LOOKUP
42 #define HASH_GIVE_ALLOC
43 // FIXME: Make <ucw/hashtable.h> accept our pool
44 #define HASH_ZERO_FILL
45 #define HASH_TABLE_DYNAMIC
46 #define HASH_TABLE_ALLOC
47 #define HASH_TABLE_VARS struct mempool *pool;
48 static void *style_prop_alloc(struct style_prop_table *table, uns size);
49 static inline void style_prop_free(struct style_prop_table *table UNUSED, void *x UNUSED) { }
50 #include <ucw/hashtable.h>
52 static void *style_prop_alloc(struct style_prop_table *table, uns size)
54 return mp_alloc_fast(table->pool, size);
57 void style_init(struct style_results *r)
59 r->pool = mp_new(4096);
60 r->num_layers = dict_size(&style_layer_dict);
61 r->layers = mp_alloc_zero(r->pool, r->num_layers * sizeof(struct style_info *));
62 r->num_active_layers = 0;
63 r->active_layers = mp_alloc_zero(r->pool, r->num_layers * sizeof(layer_t));
66 void style_cleanup(struct style_results *r)
71 void style_begin(struct style_results *r, struct osm_object *o)
73 ASSERT(!r->num_active_layers);
78 void style_end(struct style_results *r)
80 for (uns i=0; i<r->num_active_layers; i++)
81 r->layers[r->active_layers[i]] = NULL;
83 r->num_active_layers = 0;
87 static inline void style_assign(struct style_prop *dest, struct style_prop *src)
89 dest->type = src->type;
93 static struct style_info *style_get_info(struct style_results *r, layer_t layer)
95 ASSERT(layer < r->num_layers);
96 if (!r->layers[layer])
98 struct style_info *si = mp_alloc_zero(r->pool, sizeof(*si));
99 r->layers[layer] = si;
100 si->hash = mp_alloc_zero(r->pool, sizeof(struct style_prop_table));
101 si->hash->pool = r->pool;
102 style_prop_init(si->hash);
104 if (layer != STYLE_LAYER_ALL)
106 r->active_layers[r->num_active_layers++] = layer;
108 // Copy all properties which have been set for all layers
109 struct style_info *si_all = r->layers[STYLE_LAYER_ALL];
113 * CAVEAT: This is probably wrong. When no properties are set explicitly
114 * set for a layer, all-layer properties are not propagated. Hopefully harmless.
116 HASH_FOR_ALL_DYNAMIC(style_prop, si_all->hash, s)
118 style_assign(style_prop_lookup(si->hash, s->key), s);
124 return r->layers[layer];
127 void style_enable_default_layer(struct style_results *r)
129 style_get_info(r, STYLE_LAYER_DEFAULT);
132 void style_set_by_layer(struct style_results *r, layer_t layer, struct style_prop *p)
134 if (layer == STYLE_LAYER_ALL)
136 // Set in all existing layers
137 for (uns i=0; i < r->num_active_layers; i++)
138 style_assign(style_prop_lookup(r->layers[r->active_layers[i]]->hash, p->key), p);
139 // ... and let it propagate to STYLE_LAYER_ALL
142 struct style_info *si = style_get_info(r, layer);
143 style_assign(style_prop_lookup(si->hash, p->key), p);
146 struct style_prop *style_get_by_layer(struct style_results *r, layer_t layer, prop_t key)
148 struct style_info *si = style_get_info(r, layer);
149 return style_get(si, key);
152 void style_set(struct style_info *si, struct style_prop *p)
154 style_assign(style_prop_lookup(si->hash, p->key), p);
157 struct style_prop *style_get(struct style_info *si, prop_t key)
159 return style_prop_find(si->hash, key);
162 struct style_prop *style_get_and_check(struct style_info *si, prop_t key, uns allowed_types)
164 struct style_prop *p = style_prop_find(si->hash, key);
167 if (!(allowed_types & (1 << p->type)))
169 // XXX: Better diagnostics?
170 msg(L_WARN, "Style property %s set to invalid type #%u", style_prop_decode(p->key), p->type);
176 osm_val_t style_get_ident(struct style_info *si, prop_t key)
178 struct style_prop *p = style_get_and_check(si, key, 1 << PROP_TYPE_IDENT);
179 return p ? p->val.id : 0;
182 osm_val_t style_get_string(struct style_info *si, prop_t key)
184 struct style_prop *p = style_get_and_check(si, key, (1 << PROP_TYPE_STRING) | (1 << PROP_TYPE_IDENT));
185 return p ? p->val.id : 0;
188 bool style_get_number(struct style_info *si, prop_t key, double *dp)
190 struct style_prop *p = style_get_and_check(si, key, 1 << PROP_TYPE_NUMBER);
197 bool style_get_color(struct style_info *si, prop_t key, color_t *colorp)
199 struct style_prop *p = style_get_and_check(si, key, 1 << PROP_TYPE_COLOR);
202 *colorp = p->val.color;
206 void style_dump(struct style_results *r)
208 for (uns i=0; i < r->num_active_layers; i++)
210 layer_t layer = r->active_layers[i];
211 printf("Layer %s (%u)\n", style_layer_decode(layer), layer);
212 struct style_info *si = r->layers[layer];
213 HASH_FOR_ALL_DYNAMIC(style_prop, si->hash, s)
222 static void style_dump_val(struct style_prop *s)
228 case PROP_TYPE_STRING:
229 printf("%s [string]", osm_val_decode(s->val.id));
231 case PROP_TYPE_IDENT:
232 printf("%s [ident]", osm_val_decode(s->val.id));
234 case PROP_TYPE_NUMBER:
235 printf("%.6g [number]", s->val.number);
237 case PROP_TYPE_COLOR:
238 printf("%06x [color]", s->val.color);
242 CLIST_FOR_EACH(struct style_val_list_entry *, e, *s->val.list)
246 style_dump_val(&e->val);
251 printf("[unknown type %u]", s->type);
255 void style_dump_prop(struct style_prop *s)
257 printf("%s = ", style_prop_decode(s->key));
262 void style_scale(struct style_info *si, double *wp, double *hp, prop_t width_prop, prop_t height_prop)
265 bool got_width = style_get_number(si, width_prop, &w);
266 bool got_height = style_get_number(si, height_prop, &h);
268 if (got_width + got_height == 2)
273 else if (got_width + got_height == 1)