]> source.dussan.org Git - rspamd.git/commitdiff
[Project] Html/CSS: Add transform from a CSS rule to html block
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 10 Jun 2021 14:15:45 +0000 (15:15 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 11 Jun 2021 14:09:10 +0000 (15:09 +0100)
src/libserver/css/css_rule.cxx
src/libserver/css/css_rule.hxx
src/libserver/css/css_tokeniser.cxx
src/libserver/css/css_tokeniser.hxx
src/libserver/css/css_value.cxx
src/libserver/html/html_block.hxx

index 2e84aaa1c251a75d1d98c524bef0e04642e9e93b..d06f0aec0ac3834cee8da4cadb2f710d7edec5c1 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "css_rule.hxx"
 #include "css.hxx"
+#include "libserver/html/html_block.hxx"
 #include <limits>
 
 #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);
index 3353382e7e497325e695145474679d46b0682c54..b29bf298fb83ce3cde8c16bce3a7c8c648193a64 100644 (file)
 #include <vector>
 #include <memory>
 
+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<rule_shared_ptr, rule_shared_hash, rule_shared_eq> rules;
 };
index 0b1467d8fe6824f4f40feb6d7dbdcb1e39d01532..f31fdc009d087f73f86236009f26fb1c0a2a21a9 100644 (file)
@@ -75,7 +75,7 @@ auto make_token<css_parser_token::token_type::delim_token, char>(const char &c)
 }
 
 template<>
-auto make_token<css_parser_token::token_type::number_token, double>(const double &d)
+auto make_token<css_parser_token::token_type::number_token, float>(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<frozen::string, css_dimension_data, max_dims> di
 auto
 css_parser_token::adjust_dim(const css_parser_token &dim_token) -> bool
 {
-       if (!std::holds_alternative<double>(value) ||
+       if (!std::holds_alternative<float>(value) ||
                !std::holds_alternative<std::string_view>(dim_token.value)) {
                /* Invalid tokens */
                return false;
        }
 
-       auto num = std::get<double>(value);
+       auto num = std::get<float>(value);
        auto sv = std::get<std::string_view>(dim_token.value);
 
        auto dim_found = dimensions_map.find(sv);
index a45e56f3f4046cdb1d0f29503f2bb80b8d478f24..021284989382f42d4bfc1de0911f4913fe737a56 100644 (file)
@@ -80,7 +80,7 @@ struct css_parser_token {
 
        using value_type = std::variant<std::string_view, /* For strings and string like tokens */
                        char, /* For delimiters (might need to move to unicode point) */
-                       double, /* For numeric stuff */
+                       float, /* For numeric stuff */
                        css_parser_token_placeholder /* For general no token stuff */
        >;
 
@@ -119,9 +119,9 @@ struct css_parser_token {
                return (char)-1;
        }
 
-       auto get_number_or_default(double def) const -> double {
-               if (std::holds_alternative<double>(value)) {
-                       auto dbl = std::get<double>(value);
+       auto get_number_or_default(float def) const -> float {
+               if (std::holds_alternative<float>(value)) {
+                       auto dbl = std::get<float>(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<double>(value)) {
-                       auto dbl = std::get<double>(value);
+       auto get_normal_number_or_default(float def) const -> float {
+               if (std::holds_alternative<float>(value)) {
+                       auto dbl = std::get<float>(value);
 
                        if (flags & css_parser_token::number_percent) {
                                dbl /= 100.0;
index 9f1f4dd7f86de299533eb3b2285a8f3bd945bcd7..f573e38beccb741a9ad4e99cb498825163a2a5de 100644 (file)
@@ -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<double>(tok.value);
+               auto dbl = std::get<float>(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<double>(tok.value);
+               auto dbl = std::get<float>(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<double>(tok.value);
+               auto dbl = std::get<float>(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<css_value> {
-       if (std::holds_alternative<double>(tok.value)) {
-               auto dbl = std::get<double>(tok.value);
+       if (std::holds_alternative<float>(tok.value)) {
+               auto dbl = std::get<float>(tok.value);
                css_dimension dim;
 
                dim.dim = dbl;
index bc912a007c34af6b2b1e9c4872b76ea9204cd4f0..3978bcf1ed97f9cd4d0166883ed53fa53f513bcf 100644 (file)
@@ -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;
                }