#include "html.h" #include "media_query.h" #include "document.h" litehtml::media_query::media_query() { m_media_type = media_type_all; m_not = false; } litehtml::media_query::media_query( const media_query& val ) { m_not = val.m_not; m_expressions = val.m_expressions; m_media_type = val.m_media_type; } litehtml::media_query::ptr litehtml::media_query::create_from_string(const string& str, const std::shared_ptr& doc) { media_query::ptr query = std::make_shared(); string_vector tokens; split_string(str, tokens, " \t\r\n", "", "("); for(auto & token : tokens) { if(token == "not") { query->m_not = true; } else if(token.at(0) == '(') { token.erase(0, 1); if(!token.empty() && token.at(token.length() - 1) == ')') { token.erase(token.length() - 1, 1); } media_query_expression expr; string_vector expr_tokens; split_string(token, expr_tokens, ":"); if(!expr_tokens.empty()) { trim(expr_tokens[0]); expr.feature = (media_feature) value_index(expr_tokens[0], media_feature_strings, media_feature_none); if(expr.feature != media_feature_none) { if(expr_tokens.size() == 1) { expr.check_as_bool = true; } else { trim(expr_tokens[1]); expr.check_as_bool = false; if(expr.feature == media_feature_orientation) { expr.val = value_index(expr_tokens[1], media_orientation_strings, media_orientation_landscape); } else { string::size_type slash_pos = expr_tokens[1].find('/'); if( slash_pos != string::npos ) { string val1 = expr_tokens[1].substr(0, slash_pos); string val2 = expr_tokens[1].substr(slash_pos + 1); trim(val1); trim(val2); expr.val = atoi(val1.c_str()); expr.val2 = atoi(val2.c_str()); } else { css_length length; length.fromString(expr_tokens[1]); if(length.units() == css_units_dpcm || length.units() == css_units_dpi) { expr.val = (int) (length.val() * 2.54); } else { if(doc) { doc->cvt_units(length, doc->container()->get_default_font_size()); } expr.val = (int) length.val(); } } } } query->m_expressions.push_back(expr); } } } else { query->m_media_type = (media_type) value_index(token, media_type_strings, media_type_none); } } return query; } bool litehtml::media_query::check( const media_features& features ) const { bool res = false; if(m_media_type == media_type_all || m_media_type == features.type) { res = true; for(auto expression : m_expressions) { if(!expression.check(features)) { res = false; break; } } } if(m_not) { res = !res; } return res; } ////////////////////////////////////////////////////////////////////////// litehtml::media_query_list::ptr litehtml::media_query_list::create_from_string(const string& str, const std::shared_ptr& doc) { media_query_list::ptr list = std::make_shared(); string_vector tokens; split_string(str, tokens, ","); for(auto & token : tokens) { trim(token); lcase(token); litehtml::media_query::ptr query = media_query::create_from_string(token, doc); if(query) { list->m_queries.push_back(query); } } if(list->m_queries.empty()) { list = nullptr; } return list; } bool litehtml::media_query_list::apply_media_features( const media_features& features ) { bool apply = false; for(auto & query : m_queries) { if(query->check(features)) { apply = true; break; } } bool ret = (apply != m_is_used); m_is_used = apply; return ret; } bool litehtml::media_query_expression::check( const media_features& features ) const { switch(feature) { case media_feature_width: if(check_as_bool) { return (features.width != 0); } else if(features.width == val) { return true; } break; case media_feature_min_width: if(features.width >= val) { return true; } break; case media_feature_max_width: if(features.width <= val) { return true; } break; case media_feature_height: if(check_as_bool) { return (features.height != 0); } else if(features.height == val) { return true; } break; case media_feature_min_height: if(features.height >= val) { return true; } break; case media_feature_max_height: if(features.height <= val) { return true; } break; case media_feature_device_width: if(check_as_bool) { return (features.device_width != 0); } else if(features.device_width == val) { return true; } break; case media_feature_min_device_width: if(features.device_width >= val) { return true; } break; case media_feature_max_device_width: if(features.device_width <= val) { return true; } break; case media_feature_device_height: if(check_as_bool) { return (features.device_height != 0); } else if(features.device_height == val) { return true; } break; case media_feature_min_device_height: if(features.device_height >= val) { return true; } break; case media_feature_max_device_height: if(features.device_height <= val) { return true; } break; case media_feature_orientation: if(features.height >= features.width) { if(val == media_orientation_portrait) { return true; } } else { if(val == media_orientation_landscape) { return true; } } break; case media_feature_aspect_ratio: if(features.height && val2) { int ratio_this = round_d( (double) val / (double) val2 * 100 ); int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 ); if(ratio_this == ratio_feat) { return true; } } break; case media_feature_min_aspect_ratio: if(features.height && val2) { int ratio_this = round_d( (double) val / (double) val2 * 100 ); int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 ); if(ratio_feat >= ratio_this) { return true; } } break; case media_feature_max_aspect_ratio: if(features.height && val2) { int ratio_this = round_d( (double) val / (double) val2 * 100 ); int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 ); if(ratio_feat <= ratio_this) { return true; } } break; case media_feature_device_aspect_ratio: if(features.device_height && val2) { int ratio_this = round_d( (double) val / (double) val2 * 100 ); int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 ); if(ratio_feat == ratio_this) { return true; } } break; case media_feature_min_device_aspect_ratio: if(features.device_height && val2) { int ratio_this = round_d( (double) val / (double) val2 * 100 ); int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 ); if(ratio_feat >= ratio_this) { return true; } } break; case media_feature_max_device_aspect_ratio: if(features.device_height && val2) { int ratio_this = round_d( (double) val / (double) val2 * 100 ); int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 ); if(ratio_feat <= ratio_this) { return true; } } break; case media_feature_color: if(check_as_bool) { return (features.color != 0); } else if(features.color == val) { return true; } break; case media_feature_min_color: if(features.color >= val) { return true; } break; case media_feature_max_color: if(features.color <= val) { return true; } break; case media_feature_color_index: if(check_as_bool) { return (features.color_index != 0); } else if(features.color_index == val) { return true; } break; case media_feature_min_color_index: if(features.color_index >= val) { return true; } break; case media_feature_max_color_index: if(features.color_index <= val) { return true; } break; case media_feature_monochrome: if(check_as_bool) { return (features.monochrome != 0); } else if(features.monochrome == val) { return true; } break; case media_feature_min_monochrome: if(features.monochrome >= val) { return true; } break; case media_feature_max_monochrome: if(features.monochrome <= val) { return true; } break; case media_feature_resolution: if(features.resolution == val) { return true; } break; case media_feature_min_resolution: if(features.resolution >= val) { return true; } break; case media_feature_max_resolution: if(features.resolution <= val) { return true; } break; default: return false; } return false; }