diff options
Diffstat (limited to 'libs/litehtml/src/style.cpp')
-rw-r--r-- | libs/litehtml/src/style.cpp | 1220 |
1 files changed, 1220 insertions, 0 deletions
diff --git a/libs/litehtml/src/style.cpp b/libs/litehtml/src/style.cpp new file mode 100644 index 0000000000..727f01aa10 --- /dev/null +++ b/libs/litehtml/src/style.cpp @@ -0,0 +1,1220 @@ +#include "html.h" +#include "style.h" + +namespace litehtml +{ + +std::map<string_id, string> style::m_valid_values = +{ + { _display_, style_display_strings }, + { _visibility_, visibility_strings }, + { _position_, element_position_strings }, + { _float_, element_float_strings }, + { _clear_, element_clear_strings }, + { _overflow_, overflow_strings }, + { _box_sizing_, box_sizing_strings }, + + { _text_align_, text_align_strings }, + { _vertical_align_, vertical_align_strings }, + { _text_transform_, text_transform_strings }, + { _white_space_, white_space_strings }, + + { _font_style_, font_style_strings }, + { _font_variant_, font_variant_strings }, + { _font_weight_, font_weight_strings }, + + { _list_style_type_, list_style_type_strings }, + { _list_style_position_, list_style_position_strings }, + + { _border_left_style_, border_style_strings }, + { _border_right_style_, border_style_strings }, + { _border_top_style_, border_style_strings }, + { _border_bottom_style_, border_style_strings }, + { _border_collapse_, border_collapse_strings }, + + // these 4 properties are comma-separated lists of keywords, see parse_keyword_comma_list + { _background_attachment_, background_attachment_strings }, + { _background_repeat_, background_repeat_strings }, + { _background_clip_, background_box_strings }, + { _background_origin_, background_box_strings }, + + { _flex_direction_, flex_direction_strings }, + { _flex_wrap_, flex_wrap_strings }, + { _justify_content_, flex_justify_content_strings }, + { _align_items_, flex_align_items_strings }, + { _align_content_, flex_align_content_strings }, + { _align_self_, flex_align_items_strings }, + + { _caption_side_, caption_side_strings }, +}; + +void style::parse(const string& txt, const string& baseurl, document_container* container) +{ + std::vector<string> properties; + split_string(txt, properties, ";", "", "\"'"); + + for(const auto & property : properties) + { + parse_property(property, baseurl, container); + } +} + +void style::parse_property(const string& txt, const string& baseurl, document_container* container) +{ + string::size_type pos = txt.find_first_of(':'); + if(pos != string::npos) + { + string name = txt.substr(0, pos); + string val = txt.substr(pos + 1); + + trim(name); lcase(name); + trim(val); + + if(!name.empty() && !val.empty()) + { + string_vector vals; + split_string(val, vals, "!"); + if(vals.size() == 1) + { + add_property(_id(name), val, baseurl, false, container); + } else if(vals.size() > 1) + { + trim(vals[0]); + lcase(vals[1]); + add_property(_id(name), vals[0], baseurl, vals[1] == "important", container); + } + } + } +} + +void style::add_property(string_id name, const string& val, const string& baseurl, bool important, document_container* container) +{ + if (val.find("var(") != string::npos) return add_parsed_property(name, property_value(val, important, prop_type_var)); + if (val == "inherit" && name != _font_) return add_parsed_property(name, property_value(important, prop_type_inherit)); + + int idx; + string url; + css_length len[4], length; + + switch (name) + { + // keyword-only properties + case _display_: + case _visibility_: + case _position_: + case _float_: + case _clear_: + case _box_sizing_: + case _overflow_: + + case _text_align_: + case _vertical_align_: + case _text_transform_: + case _white_space_: + + case _font_style_: + case _font_variant_: + case _font_weight_: + + case _list_style_type_: + case _list_style_position_: + + case _border_top_style_: + case _border_bottom_style_: + case _border_left_style_: + case _border_right_style_: + case _border_collapse_: + + case _flex_direction_: + case _flex_wrap_: + case _justify_content_: + case _align_content_: + + case _caption_side_: + + idx = value_index(val, m_valid_values[name]); + if (idx >= 0) + { + add_parsed_property(name, property_value(idx, important)); + } + break; + + case _align_items_: + case _align_self_: + parse_align_self(name, val, important); + break; + + // <length> + case _text_indent_: + case _padding_left_: + case _padding_right_: + case _padding_top_: + case _padding_bottom_: + length.fromString(val); + add_parsed_property(name, property_value(length, important)); + break; + + // <length> | auto + case _left_: + case _right_: + case _top_: + case _bottom_: + case _z_index_: // <integer> | auto + case _width_: + case _height_: + case _min_width_: + case _min_height_: + case _margin_left_: + case _margin_right_: + case _margin_top_: + case _margin_bottom_: + length.fromString(val, "auto", -1); + add_parsed_property(name, property_value(length, important)); + break; + + // <length> | none + case _max_width_: + case _max_height_: + length.fromString(val, "none", -1); + add_parsed_property(name, property_value(length, important)); + break; + + case _line_height_: + length.fromString(val, "normal", -1); + add_parsed_property(name, property_value(length, important)); + break; + + case _font_size_: + length.fromString(val, font_size_strings, -1); + add_parsed_property(name, property_value(length, important)); + break; + + // Parse background shorthand properties + case _background_: + parse_background(val, baseurl, important, container); + break; + + case _background_image_: + parse_background_image(val, baseurl, important); + break; + + case _background_attachment_: + case _background_repeat_: + case _background_clip_: + case _background_origin_: + parse_keyword_comma_list(name, val, important); + break; + + case _background_position_: + parse_background_position(val, important); + break; + + case _background_size_: + parse_background_size(val, important); + break; + + // Parse border spacing properties + case _border_spacing_: + parse_two_lengths(val, len); + add_parsed_property(__litehtml_border_spacing_x_, property_value(len[0], important)); + add_parsed_property(__litehtml_border_spacing_y_, property_value(len[1], important)); + break; + + // Parse borders shorthand properties + case _border_: + { + string_vector tokens; + split_string(val, tokens, " ", "", "("); + for (const auto& token : tokens) + { + int idx = value_index(token, border_style_strings); + if (idx >= 0) + { + property_value style(idx, important); + add_parsed_property(_border_left_style_, style); + add_parsed_property(_border_right_style_, style); + add_parsed_property(_border_top_style_, style); + add_parsed_property(_border_bottom_style_, style); + } + else if (t_isdigit(token[0]) || token[0] == '.' || + value_in_list(token, border_width_strings)) + { + property_value width(parse_border_width(token), important); + add_parsed_property(_border_left_width_, width); + add_parsed_property(_border_right_width_, width); + add_parsed_property(_border_top_width_, width); + add_parsed_property(_border_bottom_width_, width); + } + else if (web_color::is_color(token, container)) + { + web_color _color = web_color::from_string(token, container); + property_value color(_color, important); + add_parsed_property(_border_left_color_, color); + add_parsed_property(_border_right_color_, color); + add_parsed_property(_border_top_color_, color); + add_parsed_property(_border_bottom_color_, color); + } + } + break; + } + + case _border_left_: + case _border_right_: + case _border_top_: + case _border_bottom_: + { + string_vector tokens; + split_string(val, tokens, " ", "", "("); + for (const auto& token : tokens) + { + int idx = value_index(token, border_style_strings); + if (idx >= 0) + { + add_parsed_property(_id(_s(name) + "-style"), property_value(idx, important)); + } + else if (t_isdigit(token[0]) || token[0] == '.' || + value_in_list(token, border_width_strings)) + { + property_value width(parse_border_width(token), important); + add_parsed_property(_id(_s(name) + "-width"), width); + } + else if (web_color::is_color(token, container)) + { + web_color color = web_color::from_string(token, container); + add_parsed_property(_id(_s(name) + "-color"), property_value(color, important)); + } + } + break; + } + + // Parse border-width/style/color shorthand properties + case _border_width_: + case _border_style_: + case _border_color_: + { + string prop = name == _border_width_ ? "-width" : name == _border_style_ ? "-style" : "-color"; + + string_vector tokens; + split_string(val, tokens, " "); + if (tokens.size() == 4) + { + add_property(_id("border-top" + prop), tokens[0], baseurl, important, container); + add_property(_id("border-right" + prop), tokens[1], baseurl, important, container); + add_property(_id("border-bottom" + prop), tokens[2], baseurl, important, container); + add_property(_id("border-left" + prop), tokens[3], baseurl, important, container); + } + else if (tokens.size() == 3) + { + add_property(_id("border-top" + prop), tokens[0], baseurl, important, container); + add_property(_id("border-right" + prop), tokens[1], baseurl, important, container); + add_property(_id("border-left" + prop), tokens[1], baseurl, important, container); + add_property(_id("border-bottom" + prop), tokens[2], baseurl, important, container); + } + else if (tokens.size() == 2) + { + add_property(_id("border-top" + prop), tokens[0], baseurl, important, container); + add_property(_id("border-bottom" + prop), tokens[0], baseurl, important, container); + add_property(_id("border-right" + prop), tokens[1], baseurl, important, container); + add_property(_id("border-left" + prop), tokens[1], baseurl, important, container); + } + else if (tokens.size() == 1) + { + add_property(_id("border-top" + prop), tokens[0], baseurl, important, container); + add_property(_id("border-bottom" + prop), tokens[0], baseurl, important, container); + add_property(_id("border-right" + prop), tokens[0], baseurl, important, container); + add_property(_id("border-left" + prop), tokens[0], baseurl, important, container); + } + break; + } + + case _border_top_width_: + case _border_bottom_width_: + case _border_left_width_: + case _border_right_width_: + length = parse_border_width(val); + add_parsed_property(name, property_value(length, important)); + break; + + case _color_: + case _background_color_: + case _border_top_color_: + case _border_bottom_color_: + case _border_left_color_: + case _border_right_color_: + if (web_color::is_color(val, container)) + { + web_color color = web_color::from_string(val, container); + add_parsed_property(name, property_value(color, important)); + } + break; + + // Parse border radius shorthand properties + case _border_bottom_left_radius_: + case _border_bottom_right_radius_: + case _border_top_right_radius_: + case _border_top_left_radius_: + parse_two_lengths(val, len); + add_parsed_property(_id(_s(name) + "-x"), property_value(len[0], important)); + add_parsed_property(_id(_s(name) + "-y"), property_value(len[1], important)); + break; + + // Parse border-radius shorthand properties + case _border_radius_: + { + string_vector tokens; + split_string(val, tokens, "/"); + if (tokens.size() == 1) + { + add_property(_border_radius_x_, tokens[0], baseurl, important, container); + add_property(_border_radius_y_, tokens[0], baseurl, important, container); + } + else if (tokens.size() >= 2) + { + add_property(_border_radius_x_, tokens[0], baseurl, important, container); + add_property(_border_radius_y_, tokens[1], baseurl, important, container); + } + break; + } + case _border_radius_x_: + case _border_radius_y_: + { + string_id top_left, top_right, bottom_right, bottom_left; + if (name == _border_radius_x_) + { + top_left = _border_top_left_radius_x_; + top_right = _border_top_right_radius_x_; + bottom_right = _border_bottom_right_radius_x_; + bottom_left = _border_bottom_left_radius_x_; + } + else + { + top_left = _border_top_left_radius_y_; + top_right = _border_top_right_radius_y_; + bottom_right = _border_bottom_right_radius_y_; + bottom_left = _border_bottom_left_radius_y_; + } + + switch (parse_four_lengths(val, len)) + { + case 1: + add_parsed_property(top_left, property_value(len[0], important)); + add_parsed_property(top_right, property_value(len[0], important)); + add_parsed_property(bottom_right, property_value(len[0], important)); + add_parsed_property(bottom_left, property_value(len[0], important)); + break; + case 2: + add_parsed_property(top_left, property_value(len[0], important)); + add_parsed_property(top_right, property_value(len[1], important)); + add_parsed_property(bottom_right, property_value(len[0], important)); + add_parsed_property(bottom_left, property_value(len[1], important)); + break; + case 3: + add_parsed_property(top_left, property_value(len[0], important)); + add_parsed_property(top_right, property_value(len[1], important)); + add_parsed_property(bottom_right, property_value(len[2], important)); + add_parsed_property(bottom_left, property_value(len[1], important)); + break; + case 4: + add_parsed_property(top_left, property_value(len[0], important)); + add_parsed_property(top_right, property_value(len[1], important)); + add_parsed_property(bottom_right, property_value(len[2], important)); + add_parsed_property(bottom_left, property_value(len[3], important)); + break; + } + break; + } + + // Parse list-style shorthand properties + case _list_style_: + { + add_parsed_property(_list_style_type_, property_value(list_style_type_disc, important)); + add_parsed_property(_list_style_position_, property_value(list_style_position_outside, important)); + add_parsed_property(_list_style_image_, property_value("", important)); + add_parsed_property(_list_style_image_baseurl_, property_value("", important)); + + string_vector tokens; + split_string(val, tokens, " ", "", "("); + for (const auto& token : tokens) + { + int idx = value_index(token, list_style_type_strings); + if (idx >= 0) + { + add_parsed_property(_list_style_type_, property_value(idx, important)); + } + else + { + idx = value_index(token, list_style_position_strings); + if (idx >= 0) + { + add_parsed_property(_list_style_position_, property_value(idx, important)); + } + else if (!strncmp(token.c_str(), "url", 3)) + { + css::parse_css_url(token, url); + add_parsed_property(_list_style_image_, property_value(url, important)); + add_parsed_property(_list_style_image_baseurl_, property_value(baseurl, important)); + } + } + } + break; + } + + case _list_style_image_: + css::parse_css_url(val, url); + add_parsed_property(_list_style_image_, property_value(url, important)); + add_parsed_property(_list_style_image_baseurl_, property_value(baseurl, important)); + break; + + // Parse margin and padding shorthand properties + case _margin_: + case _padding_: + { + switch (parse_four_lengths(val, len)) + { + case 4: + add_parsed_property(_id(_s(name) + "-top"), property_value(len[0], important)); + add_parsed_property(_id(_s(name) + "-right"), property_value(len[1], important)); + add_parsed_property(_id(_s(name) + "-bottom"), property_value(len[2], important)); + add_parsed_property(_id(_s(name) + "-left"), property_value(len[3], important)); + break; + case 3: + add_parsed_property(_id(_s(name) + "-top"), property_value(len[0], important)); + add_parsed_property(_id(_s(name) + "-right"), property_value(len[1], important)); + add_parsed_property(_id(_s(name) + "-left"), property_value(len[1], important)); + add_parsed_property(_id(_s(name) + "-bottom"), property_value(len[2], important)); + break; + case 2: + add_parsed_property(_id(_s(name) + "-top"), property_value(len[0], important)); + add_parsed_property(_id(_s(name) + "-bottom"), property_value(len[0], important)); + add_parsed_property(_id(_s(name) + "-right"), property_value(len[1], important)); + add_parsed_property(_id(_s(name) + "-left"), property_value(len[1], important)); + break; + case 1: + add_parsed_property(_id(_s(name) + "-top"), property_value(len[0], important)); + add_parsed_property(_id(_s(name) + "-bottom"), property_value(len[0], important)); + add_parsed_property(_id(_s(name) + "-right"), property_value(len[0], important)); + add_parsed_property(_id(_s(name) + "-left"), property_value(len[0], important)); + break; + } + break; + } + + // Parse font shorthand properties + case _font_: + parse_font(val, important); + break; + + // Parse flex-flow shorthand properties + case _flex_flow_: + { + string_vector tokens; + split_string(val, tokens, " "); + for (const auto& tok : tokens) + { + int idx; + if ((idx = value_index(tok, flex_direction_strings)) >= 0) + { + add_parsed_property(_flex_direction_, property_value(idx, important)); + } + else if ((idx = value_index(tok, flex_wrap_strings)) >= 0) + { + add_parsed_property(_flex_wrap_, property_value(idx, important)); + } + } + break; + } + + // Parse flex shorthand properties + case _flex_: + parse_flex(val, important); + break; + + case _flex_grow_: + case _flex_shrink_: + add_parsed_property(name, property_value(t_strtof(val), important)); + break; + + case _flex_basis_: + length.fromString(val, flex_basis_strings, -1); + add_parsed_property(_flex_basis_, property_value(length, important)); + break; + + case _order_: // <integer> + { + char* end; + int int_val = (int) strtol(val.c_str(), &end, 10); + if(end[0] == '\0') + { + add_parsed_property(name, property_value(int_val, important)); + } + } + break; + case _counter_increment_: + case _counter_reset_: + { + string_vector tokens; + split_string(val, tokens, " "); + add_parsed_property(name, property_value(tokens, important)); + break; + } + + default: + add_parsed_property(name, property_value(val, important)); + } +} + +css_length style::parse_border_width(const string& str) +{ + css_length len; + if (t_isdigit(str[0]) || str[0] == '.') + { + len.fromString(str); + } + else + { + int idx = value_index(str, border_width_strings); + if (idx >= 0) + { + len.set_value(border_width_values[idx], css_units_px); + } + } + return len; +} + +void style::parse_two_lengths(const string& str, css_length len[2]) +{ + string_vector tokens; + split_string(str, tokens, " "); + if (tokens.size() == 1) + { + css_length length; + length.fromString(tokens[0]); + len[0] = len[1] = length; + } + else if (tokens.size() == 2) + { + len[0].fromString(tokens[0]); + len[1].fromString(tokens[1]); + } +} + +int style::parse_four_lengths(const string& str, css_length len[4]) +{ + string_vector tokens; + split_string(str, tokens, " "); + if (tokens.size() == 0 || tokens.size() > 4) + { + return 0; + } + for (size_t i = 0; i < tokens.size(); i++) + { + len[i].fromString(tokens[i]); + } + return (int)tokens.size(); +} + +void style::parse_background(const string& val, const string& baseurl, bool important, document_container* container) +{ + string_vector tokens; + split_string(val, tokens, ",", "", "("); + if (tokens.empty()) return; + + web_color color; + string_vector images; + int_vector repeats, origins, clips, attachments; + length_vector x_positions, y_positions; + size_vector sizes; + + for (const auto& token : tokens) + { + background bg; + if (!parse_one_background(token, container, bg)) + return; + + color = bg.m_color; + images.push_back(bg.m_image[0]); + repeats.push_back(bg.m_repeat[0]); + origins.push_back(bg.m_origin[0]); + clips.push_back(bg.m_clip[0]); + attachments.push_back(bg.m_attachment[0]); + x_positions.push_back(bg.m_position_x[0]); + y_positions.push_back(bg.m_position_y[0]); + sizes.push_back(bg.m_size[0]); + } + + add_parsed_property(_background_color_, property_value(color, important)); + add_parsed_property(_background_image_, property_value(images, important)); + add_parsed_property(_background_image_baseurl_, property_value(baseurl, important)); + add_parsed_property(_background_repeat_, property_value(repeats, important)); + add_parsed_property(_background_origin_, property_value(origins, important)); + add_parsed_property(_background_clip_, property_value(clips, important)); + add_parsed_property(_background_attachment_, property_value(attachments, important)); + add_parsed_property(_background_position_x_, property_value(x_positions, important)); + add_parsed_property(_background_position_y_, property_value(y_positions, important)); + add_parsed_property(_background_size_, property_value(sizes, important)); +} + +bool style::parse_one_background(const string& val, document_container* container, background& bg) +{ + bg.m_color = web_color::transparent; + bg.m_image = {""}; + bg.m_repeat = { background_repeat_repeat }; + bg.m_origin = { background_box_padding }; + bg.m_clip = { background_box_border }; + bg.m_attachment = { background_attachment_scroll }; + bg.m_position_x = { css_length(0, css_units_percentage) }; + bg.m_position_y = { css_length(0, css_units_percentage) }; + bg.m_size = { css_size(css_length::predef_value(background_size_auto), css_length::predef_value(background_size_auto)) }; + + if(val == "none") + { + return true; + } + + string_vector tokens; + split_string(val, tokens, " \t\n\r", "", "("); + + bool color_found = false; + bool image_found = false; + bool origin_found = false; + bool clip_found = false; + bool repeat_found = false; + bool attachment_found = false; + + string position; + for(const auto& token : tokens) + { + int idx; + if(token.substr(0, 3) == "url") + { + if (image_found) return false; + string url; + css::parse_css_url(token, url); + bg.m_image = { url }; + image_found = true; + } else if( (idx = value_index(token, background_repeat_strings)) >= 0 ) + { + if (repeat_found) return false; + bg.m_repeat = { idx }; + repeat_found = true; + } else if( (idx = value_index(token, background_attachment_strings)) >= 0 ) + { + if (attachment_found) return false; + bg.m_attachment = { idx }; + attachment_found = true; + } else if( (idx = value_index(token, background_box_strings)) >= 0 ) + { + if(!origin_found) + { + bg.m_origin = { idx }; + origin_found = true; + } else + { + if (clip_found) return false; + bg.m_clip = { idx }; + clip_found = true; + } + } else if( value_in_list(token, background_position_strings) || + token.find('/') != string::npos || + t_isdigit(token[0]) || + token[0] == '+' || + token[0] == '-' || + token[0] == '.' ) + { + position += " " + token; + } else if (web_color::is_color(token, container)) + { + if (color_found) return false; + bg.m_color = web_color::from_string(token, container); + color_found = true; + } + else + { + return false; + } + } + + if (position != "") + { + string_vector tokens; + split_string(position, tokens, "/"); + + if (tokens.size() > 2) return false; + + if (tokens.size() == 2 && !parse_one_background_size(tokens[1], bg.m_size[0])) + return false; + + if (tokens.size() > 0 && !parse_one_background_position(tokens[0], bg.m_position_x[0], bg.m_position_y[0])) + return false; + } + + return true; +} + +void style::parse_background_image(const string& val, const string& baseurl, bool important) +{ + string_vector tokens; + split_string(val, tokens, ",", "", "("); + if (tokens.empty()) return; + + string_vector images; + + for (const auto& token : tokens) + { + string url; + css::parse_css_url(token, url); + images.push_back(url); + } + + add_parsed_property(_background_image_, property_value(images, important)); + add_parsed_property(_background_image_baseurl_, property_value(baseurl, important)); +} + +void style::parse_keyword_comma_list(string_id name, const string& val, bool important) +{ + string_vector tokens; + split_string(val, tokens, ","); + if (tokens.empty()) return; + + int_vector vec; + + for (auto& token : tokens) + { + trim(token); + int idx = value_index(token, m_valid_values[name]); + if (idx == -1) return; + vec.push_back(idx); + } + + add_parsed_property(name, property_value(vec, important)); +} + +void style::parse_background_position(const string& val, bool important) +{ + string_vector tokens; + split_string(val, tokens, ","); + if (tokens.empty()) return; + + length_vector x_positions, y_positions; + + for (const auto& token : tokens) + { + css_length x, y; + if(!parse_one_background_position(token, x, y)) return; + x_positions.push_back(x); + y_positions.push_back(y); + } + + add_parsed_property(_background_position_x_, property_value(x_positions, important)); + add_parsed_property(_background_position_y_, property_value(y_positions, important)); +} + +bool style::parse_one_background_position(const string& val, css_length& x, css_length& y) +{ + string_vector pos; + split_string(val, pos, " \t"); + + if (pos.empty() || pos.size() > 2) + { + return false; + } + + if (pos.size() == 1) + { + if (value_in_list(pos[0], "left;right;center")) + { + x.fromString(pos[0], "left;right;center"); + y.set_value(50, css_units_percentage); + } + else if (value_in_list(pos[0], "top;bottom;center")) + { + y.fromString(pos[0], "top;bottom;center"); + x.set_value(50, css_units_percentage); + } + else + { + x.fromString(pos[0], "left;right;center"); + y.set_value(50, css_units_percentage); + } + } + else if (pos.size() == 2) + { + if (value_in_list(pos[0], "left;right")) + { + x.fromString(pos[0], "left;right;center"); + y.fromString(pos[1], "top;bottom;center"); + } + else if (value_in_list(pos[0], "top;bottom")) + { + x.fromString(pos[1], "left;right;center"); + y.fromString(pos[0], "top;bottom;center"); + } + else if (value_in_list(pos[1], "left;right")) + { + x.fromString(pos[1], "left;right;center"); + y.fromString(pos[0], "top;bottom;center"); + } + else if (value_in_list(pos[1], "top;bottom")) + { + x.fromString(pos[0], "left;right;center"); + y.fromString(pos[1], "top;bottom;center"); + } + else + { + x.fromString(pos[0], "left;right;center"); + y.fromString(pos[1], "top;bottom;center"); + } + } + + if (x.is_predefined()) + { + switch (x.predef()) + { + case 0: + x.set_value(0, css_units_percentage); + break; + case 1: + x.set_value(100, css_units_percentage); + break; + case 2: + x.set_value(50, css_units_percentage); + break; + } + } + if (y.is_predefined()) + { + switch (y.predef()) + { + case 0: + y.set_value(0, css_units_percentage); + break; + case 1: + y.set_value(100, css_units_percentage); + break; + case 2: + y.set_value(50, css_units_percentage); + break; + } + } + return true; +} + +void style::parse_background_size(const string& val, bool important) +{ + string_vector tokens; + split_string(val, tokens, ","); + if (tokens.empty()) return; + + size_vector sizes; + + for (const auto& token : tokens) + { + css_size size; + if (!parse_one_background_size(token, size)) return; + sizes.push_back(size); + } + + add_parsed_property(_background_size_, property_value(sizes, important)); +} + +bool style::parse_one_background_size(const string& val, css_size& size) +{ + string_vector res; + split_string(val, res, " \t"); + if (res.empty()) + { + return false; + } + + size.width.fromString(res[0], background_size_strings); + if (res.size() > 1) + { + size.height.fromString(res[1], background_size_strings); + } + else + { + size.height.predef(background_size_auto); + } + return true; +} + +void style::parse_font(const string& val, bool important) +{ + if (val == "inherit") + { + add_parsed_property(_font_style_, property_value(important, prop_type_inherit)); + add_parsed_property(_font_variant_, property_value(important, prop_type_inherit)); + add_parsed_property(_font_weight_, property_value(important, prop_type_inherit)); + add_parsed_property(_font_size_, property_value(important, prop_type_inherit)); + add_parsed_property(_line_height_, property_value(important, prop_type_inherit)); + return; + } else + { + add_parsed_property(_font_style_, property_value(font_style_normal, important)); + add_parsed_property(_font_variant_, property_value(font_variant_normal, important)); + add_parsed_property(_font_weight_, property_value(font_weight_normal, important)); + add_parsed_property(_font_size_, property_value(font_size_medium, important)); + add_parsed_property(_line_height_, property_value(line_height_normal, important)); + } + + string_vector tokens; + split_string(val, tokens, " ", "", "\""); + + int idx; + bool is_family = false; + string font_family; + for(const auto& token : tokens) + { + if(is_family) + { + font_family += token; + continue; + } + + if((idx = value_index(token, font_style_strings)) >= 0) + { + if(idx == 0) + { + add_parsed_property(_font_style_, property_value(font_style_normal, important)); + add_parsed_property(_font_variant_, property_value(font_variant_normal, important)); + add_parsed_property(_font_weight_, property_value(font_weight_normal, important)); + } else + { + add_parsed_property(_font_style_, property_value(idx, important)); + } + } else if((idx = value_index(token, font_weight_strings)) >= 0) + { + add_parsed_property(_font_weight_, property_value(idx, important)); + } else if((idx = value_index(token, font_variant_strings)) >= 0) + { + add_parsed_property(_font_variant_, property_value(idx, important)); + } + else if(t_isdigit(token[0]) || token[0] == '.' || + value_in_list(token, font_size_strings) || token.find('/') != string::npos) + { + string_vector szlh; + split_string(token, szlh, "/"); + if(!szlh.empty()) + { + auto size = css_length::from_string(szlh[0], font_size_strings, -1); + add_parsed_property(_font_size_, property_value(size, important)); + + if (szlh.size() == 2) + { + auto height = css_length::from_string(szlh[1], "normal", -1); + add_parsed_property(_line_height_, property_value(height, important)); + } + } + } else + { + is_family = true; + font_family += token; + } + } + add_parsed_property(_font_family_, property_value(font_family, important)); +} + +void style::parse_flex(const string& val, bool important) +{ + css_length _auto = css_length::predef_value(flex_basis_auto); + + if (val == "initial") + { + // 0 1 auto + add_parsed_property(_flex_grow_, property_value(0.f, important)); + add_parsed_property(_flex_shrink_, property_value(1.f, important)); + add_parsed_property(_flex_basis_, property_value(_auto, important)); + } + else if (val == "auto") + { + // 1 1 auto + add_parsed_property(_flex_grow_, property_value(1.f, important)); + add_parsed_property(_flex_shrink_, property_value(1.f, important)); + add_parsed_property(_flex_basis_, property_value(_auto, important)); + } + else if (val == "none") + { + // 0 0 auto + add_parsed_property(_flex_grow_, property_value(0.f, important)); + add_parsed_property(_flex_shrink_, property_value(0.f, important)); + add_parsed_property(_flex_basis_, property_value(_auto, important)); + } + else + { + string_vector tokens; + split_string(val, tokens, " "); + if (tokens.size() == 3) + { + float grow = t_strtof(tokens[0]); + float shrink = t_strtof(tokens[1]); + auto basis = css_length::from_string(tokens[2], flex_basis_strings, -1); + if(!basis.is_predefined() && basis.units() == css_units_none && basis.val() == 0) + { + basis.set_value(basis.val(), css_units_px); + } + + add_parsed_property(_flex_grow_, property_value(grow, important)); + add_parsed_property(_flex_shrink_, property_value(shrink, important)); + add_parsed_property(_flex_basis_, property_value(basis, important)); + } + else if (tokens.size() == 2) + { + float grow = t_strtof(tokens[0]); + add_parsed_property(_flex_grow_, property_value(grow, important)); + + if (litehtml::is_number(tokens[1])) + { + float shrink = t_strtof(tokens[1]); + add_parsed_property(_flex_shrink_, property_value(shrink, important)); + add_parsed_property(_flex_basis_, property_value(css_length(0), important)); + } + else + { + auto basis = css_length::from_string(tokens[1], flex_basis_strings, -1); + add_parsed_property(_flex_basis_, property_value(basis, important)); + } + } + else if (tokens.size() == 1) + { + if (is_number(tokens[0])) + { + float grow = t_strtof(tokens[0]); + add_parsed_property(_flex_grow_, property_value(grow, important)); + add_parsed_property(_flex_shrink_, property_value(1.f, important)); + add_parsed_property(_flex_basis_, property_value(css_length(0), important)); + } + else + { + auto basis = css_length::from_string(tokens[0], flex_basis_strings, -1); + add_parsed_property(_flex_grow_, property_value(1.f, important)); + add_parsed_property(_flex_shrink_, property_value(1.f, important)); + add_parsed_property(_flex_basis_, property_value(basis, important)); + } + } + } +} + +void style::parse_align_self(string_id name, const string& val, bool important) +{ + string_vector tokens; + split_string(val, tokens, " "); + if(tokens.size() == 1) + { + int idx = value_index(val, m_valid_values[name]); + if (idx >= 0) + { + add_parsed_property(name, property_value(idx, important)); + } + } else + { + int val1 = 0; + int val2 = -1; + for(auto &token : tokens) + { + if(token == "first") + { + val1 |= flex_align_items_first; + } else if(token == "last") + { + val1 |= flex_align_items_last; + } else if(token == "safe") + { + val1 |= flex_align_items_safe; + } else if(token == "unsafe") + { + val1 |= flex_align_items_unsafe; + } else + { + int idx = value_index(token, m_valid_values[name]); + if(idx >= 0) + { + val2 = idx; + } + } + } + if(val2 >= 0) + { + add_parsed_property(name, property_value(val1 | val2, important)); + } + } +} + +void style::add_parsed_property( string_id name, const property_value& propval ) +{ + auto prop = m_properties.find(name); + if (prop != m_properties.end()) + { + if (!prop->second.m_important || (propval.m_important && prop->second.m_important)) + { + prop->second = propval; + } + } + else + { + m_properties[name] = propval; + } +} + +void style::remove_property( string_id name, bool important ) +{ + auto prop = m_properties.find(name); + if(prop != m_properties.end()) + { + if( !prop->second.m_important || (important && prop->second.m_important) ) + { + m_properties.erase(prop); + } + } +} + +void style::combine(const style& src) +{ + for (const auto& property : src.m_properties) + { + add_parsed_property(property.first, property.second); + } +} + +const property_value& style::get_property(string_id name) const +{ + auto it = m_properties.find(name); + if (it != m_properties.end()) + { + return it->second; + } + static property_value dummy; + return dummy; +} + +void style::subst_vars_(string& str, const element* el) +{ + while (true) + { + auto start = str.find("var("); + if (start == string::npos) break; + if (start > 0 && isalnum(str[start - 1])) break; + auto end = str.find(')', start + 4); + if (end == string::npos) break; + auto name = str.substr(start + 4, end - start - 4); + trim(name); + string val = el->get_custom_property(_id(name), ""); + str.replace(start, end - start + 1, val); + } +} + +void style::subst_vars(const element* el) +{ + for (auto& prop : m_properties) + { + if (prop.second.m_type == prop_type_var) + { + subst_vars_(prop.second.m_string, el); + // re-adding the same property + // if it is a custom property it will be readded as a string (currently it is prop_type_var) + // if it is a standard css property it will be parsed and properly added as typed property + add_property(prop.first, prop.second.m_string, "", prop.second.m_important, el->get_document()->container()); + } + } +} + +} // namespace litehtml
\ No newline at end of file |