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