libcss
Loading...
Searching...
No Matches
mq.h
Go to the documentation of this file.
1/*
2 * This file is part of LibCSS
3 * Licensed under the MIT License,
4 * http://www.opensource.org/licenses/mit-license.php
5 *
6 * Copyright 2018 Michael Drake <tlsa@netsurf-browser.org>
7 */
8
9#ifndef css_select_mq_h_
10#define css_select_mq_h_
11
12#include "select/helpers.h"
13#include "select/strings.h"
14#include "select/unit.h"
15
16static inline bool mq_match_feature_range_length_op1(
18 const css_mq_value *value,
19 const css_fixed client_len,
20 const css_unit_ctx *unit_ctx)
21{
22 css_fixed v;
23
24 if (value->type != CSS_MQ_VALUE_TYPE_DIM) {
25 return false;
26 }
27
28 if (value->data.dim.unit != UNIT_PX) {
29 v = css_unit_len2px_mq(unit_ctx,
30 value->data.dim.len,
31 css__to_css_unit(value->data.dim.unit));
32 } else {
33 v = value->data.dim.len;
34 }
35
36 switch (op) {
37 case CSS_MQ_FEATURE_OP_BOOL: return false;
38 case CSS_MQ_FEATURE_OP_LT: return v < client_len;
39 case CSS_MQ_FEATURE_OP_LTE: return v <= client_len;
40 case CSS_MQ_FEATURE_OP_EQ: return v == client_len;
41 case CSS_MQ_FEATURE_OP_GTE: return v >= client_len;
42 case CSS_MQ_FEATURE_OP_GT: return v > client_len;
43 default:
44 return false;
45 }
46}
47
48static inline bool mq_match_feature_range_length_op2(
50 const css_mq_value *value,
51 const css_fixed client_len,
52 const css_unit_ctx *unit_ctx)
53{
54 css_fixed v;
55
56 if (op == CSS_MQ_FEATURE_OP_UNUSED) {
57 return true;
58 }
59 if (value->type != CSS_MQ_VALUE_TYPE_DIM) {
60 return false;
61 }
62
63 if (value->data.dim.unit != UNIT_PX) {
64 v = css_unit_len2px_mq(unit_ctx,
65 value->data.dim.len,
66 css__to_css_unit(value->data.dim.unit));
67 } else {
68 v = value->data.dim.len;
69 }
70
71 switch (op) {
72 case CSS_MQ_FEATURE_OP_LT: return client_len < v;
73 case CSS_MQ_FEATURE_OP_LTE: return client_len <= v;
74 case CSS_MQ_FEATURE_OP_EQ: return client_len == v;
75 case CSS_MQ_FEATURE_OP_GTE: return client_len >= v;
76 case CSS_MQ_FEATURE_OP_GT: return client_len > v;
77 default:
78 return false;
79 }
80}
81
82static inline bool mq_match_feature_eq_ident_op1(
84 const css_mq_value *value,
85 const lwc_string *client_value)
86{
87 bool is_match;
88
89 if (value->type != CSS_MQ_VALUE_TYPE_IDENT) {
90 return false;
91 }
92
93 if (value->data.ident == NULL || client_value == NULL) {
94 return false;
95 }
96
97 switch (op) {
99 return (lwc_string_isequal(value->data.ident,
100 client_value, &is_match) == lwc_error_ok) &&
101 is_match;
102 default:
103 return false;
104 }
105}
106
115static inline bool mq_match_feature(
116 const css_mq_feature *feat,
117 const css_unit_ctx *unit_ctx,
118 const css_media *media,
119 const css_select_strings *str)
120{
121 bool match;
122
123 /* TODO: Use interned string for comparison. */
124 if (lwc_string_isequal(feat->name,
125 str->width, &match) == lwc_error_ok &&
126 match == true) {
127 if (!mq_match_feature_range_length_op1(feat->op, &feat->value,
128 media->width, unit_ctx)) {
129 return false;
130 }
131 return mq_match_feature_range_length_op2(feat->op2,
132 &feat->value2, media->width, unit_ctx);
133
134 } else if (lwc_string_isequal(feat->name,
135 str->height, &match) == lwc_error_ok &&
136 match == true) {
137 if (!mq_match_feature_range_length_op1(feat->op, &feat->value,
138 media->height, unit_ctx)) {
139 return false;
140 }
141
142 return mq_match_feature_range_length_op2(feat->op2,
143 &feat->value2, media->height, unit_ctx);
144
145 } else if (lwc_string_isequal(feat->name,
146 str->prefers_color_scheme, &match) == lwc_error_ok &&
147 match == true) {
148 if (mq_match_feature_eq_ident_op1(feat->op, &feat->value,
149 media->prefers_color_scheme) ||
150 feat->op == CSS_MQ_FEATURE_OP_BOOL) {
151 return true;
152 }
153
154 return false;
155 }
156
157 /* TODO: Look at other feature names. */
158
159 return false;
160}
161
170static inline bool mq_match_condition(
171 const css_mq_cond *cond,
172 const css_unit_ctx *unit_ctx,
173 const css_media *media,
174 const css_select_strings *str)
175{
176 bool matched = !cond->op;
177
178 for (uint32_t i = 0; i < cond->nparts; i++) {
179 bool part_matched;
180 if (cond->parts[i]->type == CSS_MQ_FEATURE) {
181 part_matched = mq_match_feature(
182 cond->parts[i]->data.feat,
183 unit_ctx, media, str);
184 } else {
185 assert(cond->parts[i]->type == CSS_MQ_COND);
186 part_matched = mq_match_condition(
187 cond->parts[i]->data.cond,
188 unit_ctx, media, str);
189 }
190
191 if (cond->op) {
192 /* OR */
193 matched |= part_matched;
194 if (matched) {
195 break; /* Short-circuit */
196 }
197 } else {
198 /* AND */
199 matched &= part_matched;
200 if (!matched) {
201 break; /* Short-circuit */
202 }
203 }
204 }
205
206 return matched != cond->negate;
207}
208
220static inline bool mq__list_match(
221 const css_mq_query *m,
222 const css_unit_ctx *unit_ctx,
223 const css_media *media,
224 const css_select_strings *str)
225{
226 for (; m != NULL; m = m->next) {
227 /* Check type */
228 if (!!(m->type & media->type) != m->negate_type) {
229 if (m->cond == NULL ||
230 mq_match_condition(m->cond,
231 unit_ctx, media, str)) {
232 /* We have a match, no need to look further. */
233 return true;
234 }
235 }
236 }
237
238 return false;
239}
240
249static inline bool mq_rule_good_for_media(
250 const css_rule *rule,
251 const css_unit_ctx *unit_ctx,
252 const css_media *media,
253 const css_select_strings *str)
254{
255 bool applies = true;
256 const css_rule *ancestor = rule;
257
258 while (ancestor != NULL) {
259 const css_rule_media *m = (const css_rule_media *) ancestor;
260
261 if (ancestor->type == CSS_RULE_MEDIA) {
262 applies = mq__list_match(m->media,
263 unit_ctx, media, str);
264 if (applies == false) {
265 break;
266 }
267 }
268
269 if (ancestor->ptype != CSS_RULE_PARENT_STYLESHEET) {
270 ancestor = ancestor->parent;
271 } else {
272 ancestor = NULL;
273 }
274 }
275
276 return applies;
277}
278
279#endif
@ UNIT_PX
Definition bytecode.h:51
int32_t css_fixed
Definition fpmath.h:23
css_mq_feature_op
Definition mq.h:38
@ CSS_MQ_FEATURE_OP_EQ
Definition mq.h:44
@ CSS_MQ_FEATURE_OP_GTE
Definition mq.h:45
@ CSS_MQ_FEATURE_OP_BOOL
Definition mq.h:39
@ CSS_MQ_FEATURE_OP_UNUSED
Definition mq.h:40
@ CSS_MQ_FEATURE_OP_LT
Definition mq.h:42
@ CSS_MQ_FEATURE_OP_GT
Definition mq.h:46
@ CSS_MQ_FEATURE_OP_LTE
Definition mq.h:43
@ CSS_RULE_MEDIA
Definition stylesheet.h:103
@ CSS_RULE_PARENT_STYLESHEET
Definition stylesheet.h:109
Definition types.h:204
lwc_string * prefers_color_scheme
Definition types.h:228
css_fixed height
Definition types.h:210
css_media_type type
Definition types.h:206
css_fixed width
Definition types.h:209
css_mq_feature * feat
Definition mq.h:73
union css_mq_cond_or_feature::@15 data
css_mq_cond * cond
Definition mq.h:72
enum css_mq_cond_or_feature::@14 type
Definition mq.h:59
css_mq_cond_or_feature ** parts
Definition mq.h:63
uint32_t op
Definition mq.h:61
uint32_t negate
Definition mq.h:60
uint32_t nparts
Definition mq.h:62
Definition mq.h:49
css_mq_value value2
Definition mq.h:54
css_mq_feature_op op2
Definition mq.h:52
css_mq_feature_op op
Definition mq.h:51
lwc_string * name
Definition mq.h:50
css_mq_value value
Definition mq.h:53
Definition mq.h:77
uint64_t type
Definition mq.h:81
struct css_mq_query * next
Definition mq.h:78
css_mq_cond * cond
Definition mq.h:83
uint32_t negate_type
Definition mq.h:80
Definition mq.h:14
uint32_t unit
Definition mq.h:25
lwc_string * ident
Definition mq.h:27
struct css_mq_value::@12::@13 dim
enum css_mq_value::@11 type
css_fixed len
Definition mq.h:24
union css_mq_value::@12 data
Definition stylesheet.h:133
css_mq_query * media
Definition stylesheet.h:136
Definition stylesheet.h:113
uint8_t ptype
Definition stylesheet.h:123
void * parent
Definition stylesheet.h:114
uint8_t type
Definition stylesheet.h:122
Definition strings.h:14
lwc_string * height
Definition strings.h:44
lwc_string * width
Definition strings.h:43
lwc_string * prefers_color_scheme
Definition strings.h:45
Definition unit.h:39
#define assert(expr)
Definition testutils.h:32
css_fixed css_unit_len2px_mq(const css_unit_ctx *ctx, const css_fixed length, const css_unit unit)
Definition unit.c:281