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