commit 9b2fb6c: [Project] Html/CSS: Add transform from a CSS rule to html block

Vsevolod Stakhov vsevolod at highsecure.ru
Fri Jun 11 14:14:06 UTC 2021


Author: Vsevolod Stakhov
Date: 2021-06-10 15:15:45 +0100
URL: https://github.com/rspamd/rspamd/commit/9b2fb6ce7e647bdf719c6598098ecd0f112cb016

[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 <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);
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 <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;
 };
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<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);
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<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;
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<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;
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;
 		}


More information about the Commits mailing list