1 #include "html.h"
2 #include "media_query.h"
3 #include "document.h"
4
5
media_query()6 litehtml::media_query::media_query()
7 {
8 m_media_type = media_type_all;
9 m_not = false;
10 }
11
media_query(const media_query & val)12 litehtml::media_query::media_query( const media_query& val )
13 {
14 m_not = val.m_not;
15 m_expressions = val.m_expressions;
16 m_media_type = val.m_media_type;
17 }
18
create_from_string(const tstring & str,const std::shared_ptr<document> & doc)19 litehtml::media_query::ptr litehtml::media_query::create_from_string(const tstring& str, const std::shared_ptr<document>& doc)
20 {
21 media_query::ptr query = std::make_shared<media_query>();
22
23 string_vector tokens;
24 split_string(str, tokens, _t(" \t\r\n"), _t(""), _t("("));
25
26 for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
27 {
28 if((*tok) == _t("not"))
29 {
30 query->m_not = true;
31 } else if(tok->at(0) == _t('('))
32 {
33 tok->erase(0, 1);
34 if(tok->at(tok->length() - 1) == _t(')'))
35 {
36 tok->erase(tok->length() - 1, 1);
37 }
38 media_query_expression expr;
39 string_vector expr_tokens;
40 split_string((*tok), expr_tokens, _t(":"));
41 if(!expr_tokens.empty())
42 {
43 trim(expr_tokens[0]);
44 expr.feature = (media_feature) value_index(expr_tokens[0], media_feature_strings, media_feature_none);
45 if(expr.feature != media_feature_none)
46 {
47 if(expr_tokens.size() == 1)
48 {
49 expr.check_as_bool = true;
50 } else
51 {
52 trim(expr_tokens[1]);
53 expr.check_as_bool = false;
54 if(expr.feature == media_feature_orientation)
55 {
56 expr.val = value_index(expr_tokens[1], media_orientation_strings, media_orientation_landscape);
57 } else
58 {
59 tstring::size_type slash_pos = expr_tokens[1].find(_t('/'));
60 if( slash_pos != tstring::npos )
61 {
62 tstring val1 = expr_tokens[1].substr(0, slash_pos);
63 tstring val2 = expr_tokens[1].substr(slash_pos + 1);
64 trim(val1);
65 trim(val2);
66 expr.val = t_atoi(val1.c_str());
67 expr.val2 = t_atoi(val2.c_str());
68 } else
69 {
70 css_length length;
71 length.fromString(expr_tokens[1]);
72 if(length.units() == css_units_dpcm)
73 {
74 expr.val = (int) (length.val() * 2.54);
75 } else if(length.units() == css_units_dpi)
76 {
77 expr.val = (int) (length.val() * 2.54);
78 } else
79 {
80 if(doc)
81 {
82 doc->cvt_units(length, doc->container()->get_default_font_size());
83 }
84 expr.val = (int) length.val();
85 }
86 }
87 }
88 }
89 query->m_expressions.push_back(expr);
90 }
91 }
92 } else
93 {
94 query->m_media_type = (media_type) value_index((*tok), media_type_strings, media_type_all);
95
96 }
97 }
98
99 return query;
100 }
101
check(const media_features & features) const102 bool litehtml::media_query::check( const media_features& features ) const
103 {
104 bool res = false;
105 if(m_media_type == media_type_all || m_media_type == features.type)
106 {
107 res = true;
108 for(media_query_expression::vector::const_iterator expr = m_expressions.begin(); expr != m_expressions.end() && res; expr++)
109 {
110 if(!expr->check(features))
111 {
112 res = false;
113 }
114 }
115 }
116
117 if(m_not)
118 {
119 res = !res;
120 }
121
122 return res;
123 }
124
125 //////////////////////////////////////////////////////////////////////////
126
create_from_string(const tstring & str,const std::shared_ptr<document> & doc)127 litehtml::media_query_list::ptr litehtml::media_query_list::create_from_string(const tstring& str, const std::shared_ptr<document>& doc)
128 {
129 media_query_list::ptr list = std::make_shared<media_query_list>();
130
131 string_vector tokens;
132 split_string(str, tokens, _t(","));
133
134 for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
135 {
136 trim(*tok);
137 lcase(*tok);
138
139 litehtml::media_query::ptr query = media_query::create_from_string(*tok, doc);
140 if(query)
141 {
142 list->m_queries.push_back(query);
143 }
144 }
145 if(list->m_queries.empty())
146 {
147 list = 0;
148 }
149
150 return list;
151 }
152
apply_media_features(const media_features & features)153 bool litehtml::media_query_list::apply_media_features( const media_features& features )
154 {
155 bool apply = false;
156
157 for(media_query::vector::iterator iter = m_queries.begin(); iter != m_queries.end() && !apply; iter++)
158 {
159 if((*iter)->check(features))
160 {
161 apply = true;
162 }
163 }
164
165 bool ret = (apply != m_is_used);
166 m_is_used = apply;
167 return ret;
168 }
169
check(const media_features & features) const170 bool litehtml::media_query_expression::check( const media_features& features ) const
171 {
172 switch(feature)
173 {
174 case media_feature_width:
175 if(check_as_bool)
176 {
177 return (features.width != 0);
178 } else if(features.width == val)
179 {
180 return true;
181 }
182 break;
183 case media_feature_min_width:
184 if(features.width >= val)
185 {
186 return true;
187 }
188 break;
189 case media_feature_max_width:
190 if(features.width <= val)
191 {
192 return true;
193 }
194 break;
195 case media_feature_height:
196 if(check_as_bool)
197 {
198 return (features.height != 0);
199 } else if(features.height == val)
200 {
201 return true;
202 }
203 break;
204 case media_feature_min_height:
205 if(features.height >= val)
206 {
207 return true;
208 }
209 break;
210 case media_feature_max_height:
211 if(features.height <= val)
212 {
213 return true;
214 }
215 break;
216
217 case media_feature_device_width:
218 if(check_as_bool)
219 {
220 return (features.device_width != 0);
221 } else if(features.device_width == val)
222 {
223 return true;
224 }
225 break;
226 case media_feature_min_device_width:
227 if(features.device_width >= val)
228 {
229 return true;
230 }
231 break;
232 case media_feature_max_device_width:
233 if(features.device_width <= val)
234 {
235 return true;
236 }
237 break;
238 case media_feature_device_height:
239 if(check_as_bool)
240 {
241 return (features.device_height != 0);
242 } else if(features.device_height == val)
243 {
244 return true;
245 }
246 break;
247 case media_feature_min_device_height:
248 if(features.device_height <= val)
249 {
250 return true;
251 }
252 break;
253 case media_feature_max_device_height:
254 if(features.device_height <= val)
255 {
256 return true;
257 }
258 break;
259
260 case media_feature_orientation:
261 if(features.height >= features.width)
262 {
263 if(val == media_orientation_portrait)
264 {
265 return true;
266 }
267 } else
268 {
269 if(val == media_orientation_landscape)
270 {
271 return true;
272 }
273 }
274 break;
275 case media_feature_aspect_ratio:
276 if(features.height && val2)
277 {
278 int ratio_this = round_d( (double) val / (double) val2 * 100 );
279 int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );
280 if(ratio_this == ratio_feat)
281 {
282 return true;
283 }
284 }
285 break;
286 case media_feature_min_aspect_ratio:
287 if(features.height && val2)
288 {
289 int ratio_this = round_d( (double) val / (double) val2 * 100 );
290 int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );
291 if(ratio_feat >= ratio_this)
292 {
293 return true;
294 }
295 }
296 break;
297 case media_feature_max_aspect_ratio:
298 if(features.height && val2)
299 {
300 int ratio_this = round_d( (double) val / (double) val2 * 100 );
301 int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 );
302 if(ratio_feat <= ratio_this)
303 {
304 return true;
305 }
306 }
307 break;
308
309 case media_feature_device_aspect_ratio:
310 if(features.device_height && val2)
311 {
312 int ratio_this = round_d( (double) val / (double) val2 * 100 );
313 int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );
314 if(ratio_feat == ratio_this)
315 {
316 return true;
317 }
318 }
319 break;
320 case media_feature_min_device_aspect_ratio:
321 if(features.device_height && val2)
322 {
323 int ratio_this = round_d( (double) val / (double) val2 * 100 );
324 int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );
325 if(ratio_feat >= ratio_this)
326 {
327 return true;
328 }
329 }
330 break;
331 case media_feature_max_device_aspect_ratio:
332 if(features.device_height && val2)
333 {
334 int ratio_this = round_d( (double) val / (double) val2 * 100 );
335 int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 );
336 if(ratio_feat <= ratio_this)
337 {
338 return true;
339 }
340 }
341 break;
342
343 case media_feature_color:
344 if(check_as_bool)
345 {
346 return (features.color != 0);
347 } else if(features.color == val)
348 {
349 return true;
350 }
351 break;
352 case media_feature_min_color:
353 if(features.color >= val)
354 {
355 return true;
356 }
357 break;
358 case media_feature_max_color:
359 if(features.color <= val)
360 {
361 return true;
362 }
363 break;
364
365 case media_feature_color_index:
366 if(check_as_bool)
367 {
368 return (features.color_index != 0);
369 } else if(features.color_index == val)
370 {
371 return true;
372 }
373 break;
374 case media_feature_min_color_index:
375 if(features.color_index >= val)
376 {
377 return true;
378 }
379 break;
380 case media_feature_max_color_index:
381 if(features.color_index <= val)
382 {
383 return true;
384 }
385 break;
386
387 case media_feature_monochrome:
388 if(check_as_bool)
389 {
390 return (features.monochrome != 0);
391 } else if(features.monochrome == val)
392 {
393 return true;
394 }
395 break;
396 case media_feature_min_monochrome:
397 if(features.monochrome >= val)
398 {
399 return true;
400 }
401 break;
402 case media_feature_max_monochrome:
403 if(features.monochrome <= val)
404 {
405 return true;
406 }
407 break;
408
409 case media_feature_resolution:
410 if(features.resolution == val)
411 {
412 return true;
413 }
414 break;
415 case media_feature_min_resolution:
416 if(features.resolution >= val)
417 {
418 return true;
419 }
420 break;
421 case media_feature_max_resolution:
422 if(features.resolution <= val)
423 {
424 return true;
425 }
426 break;
427 default:
428 return false;
429 }
430
431 return false;
432 }
433