]> mj.ucw.cz Git - leo.git/blob - css.c
TODO
[leo.git] / css.c
1 /*
2  *      Hic Est Leo -- MapCSS Stylesheets
3  *
4  *      (c) 2014--2015 Martin Mares <mj@ucw.cz>
5  */
6
7 #include "leo.h"
8 #include "style.h"
9 #include "css.h"
10 #include "expr.h"
11
12 #include <ucw/mempool.h>
13
14 #include <stdio.h>
15
16 void css_dump(struct css_sheet *ss)
17 {
18   printf("Style sheet <%s>:\n", ss->filename);
19   CLIST_FOR_EACH(struct css_rule *, r, ss->rules)
20     css_dump_rule(r);
21 }
22
23 void css_dump_rule(struct css_rule *r)
24 {
25   printf("Rule:\n");
26   CLIST_FOR_EACH(struct css_selector *, s, r->selectors)
27     css_dump_selector(s);
28   CLIST_FOR_EACH(struct css_action *, a, r->actions)
29     css_dump_action(a);
30 }
31
32 void css_dump_selector(struct css_selector *s)
33 {
34   printf("\tSelector:\n");
35   CLIST_FOR_EACH(struct css_path *, p, s->path)
36     {
37       printf("\t\tMatch type=%u layer=%u role=%u mod=%u\n", p->type, p->layer, p->role, p->modifiers);
38       CLIST_FOR_EACH(struct css_condition *, c, p->conditions)
39         {
40           printf("\t\t\tCondition %u key=%s val=%s\n", c->op, osm_key_decode(c->key), osm_val_decode(c->val));
41         }
42     }
43 }
44
45 void css_dump_action(struct css_action *a)
46 {
47   printf("\tAction: ");
48   switch (a->type)
49     {
50     case CSS_ACTION_SET:
51       style_dump_prop(&a->prop);
52       break;
53     case CSS_ACTION_EXPR:
54       printf("<expr>\n");
55     default:
56       ASSERT(0);
57     }
58 }
59
60 static bool css_match_condition(struct css_condition *c, struct osm_object *o)
61 {
62   osm_val_t val = osm_obj_find_tag(o, c->key);
63
64   switch (c->op)
65     {
66     case COND_OP_EQ:
67       return (val == c->val);   // FIXME: Case sensitivity?
68     case COND_OP_NE:
69       return (val != c->val);
70     case COND_OP_LT:
71       // FIXME
72       return 0;
73     case COND_OP_GT:
74       // FIXME
75       return 0;
76     case COND_OP_LE:
77       // FIXME
78       return 0;
79     case COND_OP_GE:
80       // FIXME
81       return 0;
82     case COND_OP_IS_SET:
83       return val;
84     case COND_OP_IS_UNSET:
85       return !val;
86     case COND_OP_IS_TRUE:
87       return (val == VALUE_1 || val == VALUE_YES || val == VALUE_TRUE);
88     case COND_OP_IS_FALSE:
89       return !(val == VALUE_1 || val == VALUE_YES || val == VALUE_TRUE);
90     default:
91       ASSERT(0);
92     }
93 }
94
95 static bool css_match_path_component(struct css_path *p, struct osm_object *o)
96 {
97   switch (p->type)
98     {
99     case CSS_TYPE_ANY:
100       break;
101     case CSS_TYPE_NODE:
102     case CSS_TYPE_WAY:
103     case CSS_TYPE_RELATION:
104       if (o->type != p->type)
105         return 0;
106       break;
107     case CSS_TYPE_AREA:
108       if (o->type == OSM_TYPE_WAY && osm_way_cyclic_p((struct osm_way *) o))
109         break;
110       if (o->type == OSM_TYPE_MULTIPOLYGON)
111         break;
112       return 0;
113     default:
114       return 0;
115     }
116
117   if (p->modifiers & PATH_MOD_NEVER)
118     return 0;
119
120   CLIST_FOR_EACH(struct css_condition *, c, p->conditions)
121     if (!css_match_condition(c, o))
122       return 0;
123
124   return 1;
125 }
126
127 static bool css_match_path(struct css_selector *s, struct css_path *p, struct osm_object *o);
128
129 static bool css_match_path_subtree(struct css_selector *s, struct css_path *p, struct osm_object *o)
130 {
131   CLIST_FOR_EACH(struct osm_ref *, ref, o->backrefs)
132     if (css_match_path(s, p, ref->o))
133       return 1;
134
135   CLIST_FOR_EACH(struct osm_ref *, ref, o->backrefs)
136     if (css_match_path_subtree(s, p, ref->o))
137       return 1;
138
139   return 0;
140 }
141
142 static bool css_match_path(struct css_selector *s, struct css_path *p, struct osm_object *o)
143 {
144   if (!css_match_path_component(p, o))
145     return 0;
146
147   p = clist_prev(&s->path, &p->n);
148   if (!p)
149     return 1;
150
151   return css_match_path_subtree(s, p, o);
152 }
153
154 static bool css_match_selector(struct css_selector *s, struct style_results *r)
155 {
156   struct css_path *p = clist_tail(&s->path);
157   ASSERT(p);
158   return css_match_path(s, p, r->obj);
159 }
160
161 static void css_apply_action(struct css_action *sa, struct style_results *r, layer_t layer)
162 {
163   switch (sa->type)
164     {
165     case CSS_ACTION_SET:
166       style_set_by_layer(r, layer, &sa->prop);
167       break;
168     case CSS_ACTION_EXPR:
169       expr_execute(sa, r, layer);
170       break;
171     default:
172       ASSERT(0);
173     }
174 }
175
176 void css_apply(struct css_sheet *ss, struct style_results *r)
177 {
178   CLIST_FOR_EACH(struct css_rule *, sr, ss->rules)
179     {
180       layer_t last_layer = ~0U;
181       CLIST_FOR_EACH(struct css_selector *, sel, sr->selectors)
182         {
183           if (css_match_selector(sel, r))
184             {
185               // XXX: Rules with selectors in multiple layers could be further optimized
186               struct css_path *cp = clist_tail(&sel->path);
187               layer_t layer = cp ? cp->layer : STYLE_LAYER_DEFAULT;
188               if (layer != last_layer)
189                 {
190                   last_layer = layer;
191                   CLIST_FOR_EACH(struct css_action *, sa, sr->actions)
192                     css_apply_action(sa, r, layer);
193                 }
194             }
195         }
196     }
197 }