From 9b2fb6ce7e647bdf719c6598098ecd0f112cb016 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Thu, 10 Jun 2021 15:15:45 +0100 Subject: [PATCH] [Project] Html/CSS: Add transform from a CSS rule to html block --- src/libserver/css/css_rule.cxx | 119 +++++++++++++++++++++++++++- src/libserver/css/css_rule.hxx | 12 +++ src/libserver/css/css_tokeniser.cxx | 6 +- src/libserver/css/css_tokeniser.hxx | 14 ++-- src/libserver/css/css_value.cxx | 10 +-- src/libserver/html/html_block.hxx | 9 ++- 6 files changed, 150 insertions(+), 20 deletions(-) diff --git a/src/libserver/css/css_rule.cxx b/src/libserver/css/css_rule.cxx index 2e84aaa1c..d06f0aec0 100644 --- a/src/libserver/css/css_rule.cxx +++ b/src/libserver/css/css_rule.cxx @@ -16,6 +16,7 @@ #include "css_rule.hxx" #include "css.hxx" +#include "libserver/html/html_block.hxx" #include #define DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL @@ -349,10 +350,11 @@ auto process_declaration_tokens(rspamd_mempool_t *pool, } auto -css_declarations_block::merge_block(const css_declarations_block &other, merge_type how) --> void { +css_declarations_block::merge_block(const css_declarations_block &other, merge_type how) -> void +{ const auto &other_rules = other.get_rules(); + for (auto &rule : other_rules) { auto &&found_it = rules.find(rule); @@ -379,6 +381,119 @@ css_declarations_block::merge_block(const css_declarations_block &other, merge_t } } +auto +css_declarations_block::compile_to_block(rspamd_mempool_t *pool) const -> rspamd::html::html_block * +{ + auto *block = rspamd_mempool_alloc0_type(pool, rspamd::html::html_block); + auto opacity = -1; + const css_rule *font_rule = nullptr, *background_rule = nullptr; + + for (const auto &rule : rules) { + auto prop = rule->get_prop().type; + const auto &vals = rule->get_values(); + + if (vals.empty()) { + continue; + } + + switch (prop) { + case css_property_type::PROPERTY_VISIBILITY: + case css_property_type::PROPERTY_DISPLAY: { + auto disp = vals.back().to_display().value_or(css_display_value::DISPLAY_NORMAL); + block->set_display(disp); + break; + } + case css_property_type::PROPERTY_FONT_SIZE: { + auto fs = vals.back().to_dimension(); + if (fs) { + block->set_font_size(fs.value().dim, fs.value().is_percent); + } + } + case css_property_type::PROPERTY_OPACITY: { + opacity = vals.back().to_number().value_or(opacity); + break; + } + case css_property_type::PROPERTY_FONT_COLOR: { + auto color = vals.back().to_color(); + if (color) { + block->set_fgcolor(color.value()); + } + break; + } + case css_property_type::PROPERTY_BGCOLOR: { + auto color = vals.back().to_color(); + if (color) { + block->set_bgcolor(color.value()); + } + break; + } + case css_property_type::PROPERTY_HEIGHT: { + auto w = vals.back().to_dimension(); + if (w) { + block->set_width(w.value().dim, w.value().is_percent); + } + break; + } + case css_property_type::PROPERTY_WIDTH: { + auto h = vals.back().to_dimension(); + if (h) { + block->set_width(h.value().dim, h.value().is_percent); + } + break; + } + /* Optional attributes */ + case css_property_type::PROPERTY_FONT: + font_rule = rule.get(); + break; + case css_property_type::PROPERTY_BACKGROUND: + background_rule = rule.get(); + break; + default: + /* Do nothing for now */ + break; + } + } + + /* Optional properties */ + if (!(block->mask & rspamd::html::html_block::fg_color_mask) && font_rule) { + auto &vals = font_rule->get_values(); + + for (const auto &val : vals) { + auto maybe_color = val.to_color(); + + if (maybe_color) { + block->set_fgcolor(maybe_color.value()); + } + } + } + + if (!(block->mask & rspamd::html::html_block::font_size_mask) && font_rule) { + auto &vals = font_rule->get_values(); + + for (const auto &val : vals) { + auto maybe_dim = val.to_dimension(); + + if (maybe_dim) { + block->set_font_size(maybe_dim.value().dim, maybe_dim.value().is_percent); + } + } + } + + if (!(block->mask & rspamd::html::html_block::bg_color_mask) && background_rule) { + auto &vals = background_rule->get_values(); + + for (const auto &val : vals) { + auto maybe_color = val.to_color(); + + if (maybe_color) { + block->set_bgcolor(maybe_color.value()); + } + } + } + + return block; +} + void css_rule::add_value(const css_value &value) { values.push_back(value); diff --git a/src/libserver/css/css_rule.hxx b/src/libserver/css/css_rule.hxx index 3353382e7..b29bf298f 100644 --- a/src/libserver/css/css_rule.hxx +++ b/src/libserver/css/css_rule.hxx @@ -26,6 +26,11 @@ #include #include +namespace rspamd::html { +/* Forward declaration */ +struct html_block; +} + namespace rspamd::css { class css_rule { @@ -107,6 +112,13 @@ public: return (rules.find(css_rule{prop}) != rules.end()); } + /** + * Compile CSS declaration to the html block + * @param pool used to carry memory requred for html_block + * @return html block structure + */ + auto compile_to_block(rspamd_mempool_t *pool) const -> rspamd::html::html_block *; + private: robin_hood::unordered_flat_set rules; }; diff --git a/src/libserver/css/css_tokeniser.cxx b/src/libserver/css/css_tokeniser.cxx index 0b1467d8f..f31fdc009 100644 --- a/src/libserver/css/css_tokeniser.cxx +++ b/src/libserver/css/css_tokeniser.cxx @@ -75,7 +75,7 @@ auto make_token(const char &c) } template<> -auto make_token(const double &d) +auto make_token(const float &d) -> css_parser_token { return css_parser_token{css_parser_token::token_type::number_token, d}; @@ -145,13 +145,13 @@ constexpr frozen::unordered_map di auto css_parser_token::adjust_dim(const css_parser_token &dim_token) -> bool { - if (!std::holds_alternative(value) || + if (!std::holds_alternative(value) || !std::holds_alternative(dim_token.value)) { /* Invalid tokens */ return false; } - auto num = std::get(value); + auto num = std::get(value); auto sv = std::get(dim_token.value); auto dim_found = dimensions_map.find(sv); diff --git a/src/libserver/css/css_tokeniser.hxx b/src/libserver/css/css_tokeniser.hxx index a45e56f3f..021284989 100644 --- a/src/libserver/css/css_tokeniser.hxx +++ b/src/libserver/css/css_tokeniser.hxx @@ -80,7 +80,7 @@ struct css_parser_token { using value_type = std::variant; @@ -119,9 +119,9 @@ struct css_parser_token { return (char)-1; } - auto get_number_or_default(double def) const -> double { - if (std::holds_alternative(value)) { - auto dbl = std::get(value); + auto get_number_or_default(float def) const -> float { + if (std::holds_alternative(value)) { + auto dbl = std::get(value); if (flags & css_parser_token::number_percent) { dbl /= 100.0; @@ -133,9 +133,9 @@ struct css_parser_token { return def; } - auto get_normal_number_or_default(double def) const -> double { - if (std::holds_alternative(value)) { - auto dbl = std::get(value); + auto get_normal_number_or_default(float def) const -> float { + if (std::holds_alternative(value)) { + auto dbl = std::get(value); if (flags & css_parser_token::number_percent) { dbl /= 100.0; diff --git a/src/libserver/css/css_value.cxx b/src/libserver/css/css_value.cxx index 9f1f4dd7f..f573e38be 100644 --- a/src/libserver/css/css_value.cxx +++ b/src/libserver/css/css_value.cxx @@ -98,7 +98,7 @@ constexpr static inline auto rgb_color_component_convert(const css_parser_token std::uint8_t ret = 0; if (tok.type == css_parser_token::token_type::number_token) { - auto dbl = std::get(tok.value); + auto dbl = std::get(tok.value); if (tok.flags & css_parser_token::number_percent) { if (dbl > 100) { @@ -129,7 +129,7 @@ constexpr static inline auto alpha_component_convert(const css_parser_token &tok double ret = 1.0; if (tok.type == css_parser_token::token_type::number_token) { - auto dbl = std::get(tok.value); + auto dbl = std::get(tok.value); if (tok.flags & css_parser_token::number_percent) { if (dbl > 100) { @@ -160,7 +160,7 @@ constexpr static inline auto h_component_convert(const css_parser_token &tok) double ret = 0.0; if (tok.type == css_parser_token::token_type::number_token) { - auto dbl = std::get(tok.value); + auto dbl = std::get(tok.value); if (tok.flags & css_parser_token::number_percent) { if (dbl > 100) { @@ -276,8 +276,8 @@ auto css_value::maybe_color_from_function(const css_consumed_block::css_function auto css_value::maybe_dimension_from_number(const css_parser_token &tok) -> std::optional { - if (std::holds_alternative(tok.value)) { - auto dbl = std::get(tok.value); + if (std::holds_alternative(tok.value)) { + auto dbl = std::get(tok.value); css_dimension dim; dim.dim = dbl; diff --git a/src/libserver/html/html_block.hxx b/src/libserver/html/html_block.hxx index bc912a007..3978bcf1e 100644 --- a/src/libserver/html/html_block.hxx +++ b/src/libserver/html/html_block.hxx @@ -49,7 +49,8 @@ struct html_block { bg_color = c; mask |= bg_color_mask; } - auto set_height(float h) -> void { + auto set_height(float h, bool is_percent = false) -> void { + h = is_percent ? (-h) : h; if (h < INT16_MIN) { /* Negative numbers encode percents... */ height = -100; @@ -62,7 +63,8 @@ struct html_block { } mask |= height_mask; } - auto set_width(double w) -> void { + auto set_width(float w, bool is_percent = false) -> void { + w = is_percent ? (-w) : w; if (w < INT16_MIN) { width = INT16_MIN; } @@ -87,7 +89,8 @@ struct html_block { display = v; mask |= display_mask; } - auto set_font_size(float fs) -> void { + auto set_font_size(float fs, bool is_percent = false) -> void { + fs = is_percent ? (-fs) : fs; if (fs < INT8_MIN) { font_size = -100; } -- 2.39.5