]> source.dussan.org Git - rspamd.git/commitdiff
[Project] Css: Add colors conversion functions
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 3 Mar 2021 12:42:45 +0000 (12:42 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 3 Mar 2021 12:42:45 +0000 (12:42 +0000)
src/libserver/css/css_value.cxx
src/libserver/css/css_value.hxx

index 520127da8f6e55f074682831f37dcaef673f54e2..ac65c7422b306d3ed6ea6c7c21a0c1d05f3efe54 100644 (file)
@@ -34,9 +34,252 @@ auto css_value::maybe_color_from_string(const std::string_view &input)
        auto found_it = css_colors_map.find(input);
 
        if (found_it != css_colors_map.end()) {
+               return css_value{found_it->second};
+       }
+
+       return std::nullopt;
+}
+
+constexpr static inline auto hexpair_decode(char c1, char c2) -> std::uint8_t
+{
+       std::uint8_t ret = 0;
+
+       if      (c1 >= '0' && c1 <= '9') ret = c1 - '0';
+       else if (c1 >= 'A' && c1 <= 'F') ret = c1 - 'A' + 10;
+       else if (c1 >= 'a' && c1 <= 'f') ret = c1 - 'a' + 10;
+
+       ret *= 16;
+
+       if      (c2 >= '0' && c2 <= '9') ret += c2 - '0';
+       else if (c2 >= 'A' && c2 <= 'F') ret += c2 - 'A' + 10;
+       else if (c2 >= 'a' && c2 <= 'f') ret += c2 - 'a' + 10;
 
+       return ret;
+}
+
+auto css_value::maybe_color_from_hex(const std::string_view &input)
+       -> std::optional<css_value>
+{
+       if (input.length() == 6) {
+               /* Plain RGB */
+               css_color col(hexpair_decode(input[0], input[1]),
+                               hexpair_decode(input[2], input[3]),
+                               hexpair_decode(input[4], input[5]));
+               return css_value(col);
+       }
+       else if (input.length() == 8) {
+               /* RGBA */
+               css_color col(hexpair_decode(input[0], input[1]),
+                               hexpair_decode(input[2], input[3]),
+                               hexpair_decode(input[4], input[5]),
+                               hexpair_decode(input[6], input[7]));
+               return css_value(col);
        }
 
        return std::nullopt;
 }
+
+constexpr static inline auto rgb_color_component_convert(const css_parser_token &tok)
+       -> std::uint8_t
+{
+       std::uint8_t ret = 0;
+
+       if (tok.type == css_parser_token::token_type::number_token) {
+               auto dbl = std::get<double>(tok.value);
+
+               if (tok.flags & css_parser_token::number_percent) {
+                       if (dbl > 100) {
+                               dbl = 100;
+                       }
+                       else if (dbl < 0) {
+                               dbl = 0;
+                       }
+                       ret = (std::uint8_t)(dbl / 100.0 * 255.0);
+               }
+               else {
+                       if (dbl > 1) {
+                               dbl = 1;
+                       }
+                       else if (dbl < 0) {
+                               dbl = 0;
+                       }
+
+                       ret = (std::uint8_t)(dbl * 255.0);
+               }
+       }
+
+       return ret;
+}
+
+constexpr static inline auto alpha_component_convert(const css_parser_token &tok)
+       -> std::uint8_t
+{
+       double ret = 1.0;
+
+       if (tok.type == css_parser_token::token_type::number_token) {
+               auto dbl = std::get<double>(tok.value);
+
+               if (tok.flags & css_parser_token::number_percent) {
+                       if (dbl > 100) {
+                               dbl = 100;
+                       }
+                       else if (dbl < 0) {
+                               dbl = 0;
+                       }
+                       ret = (dbl / 100.0);
+               }
+               else {
+                       if (dbl > 255) {
+                               dbl = 255;
+                       }
+                       else if (dbl < 0) {
+                               dbl = 0;
+                       }
+
+                       ret = dbl / 255.0;
+               }
+       }
+
+       return (std::uint8_t)(ret * 255.0);
+}
+
+constexpr static inline auto h_component_convert(const css_parser_token &tok)
+       -> double
+{
+       double ret = 0.0;
+
+       if (tok.type == css_parser_token::token_type::number_token) {
+               auto dbl = std::get<double>(tok.value);
+
+               if (tok.flags & css_parser_token::number_percent) {
+                       if (dbl > 100) {
+                               dbl = 100;
+                       }
+                       else if (dbl < 0) {
+                               dbl = 0;
+                       }
+                       ret = (dbl / 100.0) * 360.0;
+               }
+               else {
+                       if (dbl > 360) {
+                               dbl = 360;
+                       }
+                       else if (dbl < 0) {
+                               dbl = 0;
+                       }
+
+                       ret = dbl;
+               }
+       }
+
+       return ret;
+}
+
+constexpr static inline auto sl_component_convert(const css_parser_token &tok)
+       -> double
+{
+       double ret = 0.0;
+
+       if (tok.type == css_parser_token::token_type::number_token) {
+               auto dbl = std::get<double>(tok.value);
+
+               if (tok.flags & css_parser_token::number_percent) {
+                       if (dbl > 100) {
+                               dbl = 100;
+                       }
+                       else if (dbl < 0) {
+                               dbl = 0;
+                       }
+                       ret = (dbl / 100.0);
+               }
+               else {
+                       if (dbl > 1) {
+                               dbl = 1;
+                       }
+                       else if (dbl < 0) {
+                               dbl = 0;
+                       }
+
+                       ret = (dbl);
+               }
+       }
+
+       return ret;
+}
+
+static inline auto hsl_to_rgb(double h, double s, double l)
+       -> css_color
+{
+       constexpr auto hue2rgb = [](auto p, auto q, auto t) -> auto {
+               if (t < 0.0) {
+                       t += 1.0;
+               }
+               if (t > 1.0) {
+                       t -= 1.0;
+               }
+               if (t < 1.0/6.0) {
+                       return p + (q - p) * 6.0 * t;
+               }
+               if (t < 0.5) {
+                       return q;
+               }
+               if (t < 2.0/3.0) {
+                       return p + (q - p) * (2.0/3.0 - t) * 6.0;
+               }
+               return p * 255.0;
+       };
+
+       css_color ret;
+
+       auto q = l < 0.5 ? l * (1.0 + s) : l + s - l * s;
+       auto p = 2.0 * l - q;
+       ret.r = (std::uint8_t)hue2rgb(p, q, h + 1.0/3.0);
+       ret.g = (std::uint8_t)hue2rgb(p, q, h);
+       ret.b = (std::uint8_t)hue2rgb(p, q, h - 1.0/3.0);
+
+       return ret;
+}
+
+auto css_value::maybe_color_from_function(const std::string_view &func,
+                                                                         const std::vector<css_parser_token> &args)
+       -> std::optional<css_value>
+{
+       if (func == "rgb" && args.size() == 3) {
+               css_color col{rgb_color_component_convert(args[0]),
+                                         rgb_color_component_convert(args[1]),
+                                         rgb_color_component_convert(args[2])};
+
+               return css_value(col);
+       }
+       else if (func == "rgba" && args.size() == 4) {
+               css_color col{rgb_color_component_convert(args[0]),
+                                         rgb_color_component_convert(args[1]),
+                                         rgb_color_component_convert(args[2]),
+                                         alpha_component_convert(args[3])};
+
+               return css_value(col);
+       }
+       else if (func == "hsl" && args.size() == 3) {
+               auto h = h_component_convert(args[0]);
+               auto s = sl_component_convert(args[1]);
+               auto l = sl_component_convert(args[2]);
+
+               auto col = hsl_to_rgb(h, s, l);
+
+               return css_value(col);
+       }
+       else if (func == "hsla" && args.size() == 4) {
+               auto h = h_component_convert(args[0]);
+               auto s = sl_component_convert(args[1]);
+               auto l = sl_component_convert(args[2]);
+
+               auto col = hsl_to_rgb(h, s, l);
+               col.alpha = alpha_component_convert(args[3]);
+
+               return css_value(col);
+       }
+
+       return std::nullopt;
+}
+
 }
index 882abf9905cebd38d173ee83baf8d480d847496b..90ee4533d078ad0ea85121d533735d8bc197201e 100644 (file)
 #ifndef RSPAMD_CSS_VALUE_HXX
 #define RSPAMD_CSS_VALUE_HXX
 
-#include "libserver/html.h"
 #include <string>
 #include <variant>
 #include <optional>
+#include <vector>
 #include "parse_error.hxx"
 #include "css_parser.hxx"
 #include "contrib/expected/expected.hpp"
@@ -38,6 +38,7 @@ struct alignas(int) css_color {
 
        constexpr css_color(std::uint8_t _r, std::uint8_t _g, std::uint8_t _b, std::uint8_t _alpha = 255) :
                r(_r), g(_g), b(_b), alpha(_alpha) {}
+       css_color() = default;
 };
 
 /*
@@ -73,7 +74,13 @@ struct css_value {
        std::variant<css_color,
                        double,
                        css_display_value,
-                       css_flag_value> value;
+                       css_flag_value,
+                       std::monostate> value;
+
+       css_value(const css_color &color) :
+                       type(css_value_type::CSS_VALUE_COLOR), value(color) {}
+       css_value(double sz) :
+                       type(css_value_type::CSS_VALUE_SIZE), value(sz) {}
 
        constexpr std::optional<css_color> to_color(void) const {
                if (type == css_value_type::CSS_VALUE_COLOR) {
@@ -115,6 +122,11 @@ struct css_value {
 
        static auto maybe_color_from_string(const std::string_view &input)
                -> std::optional<css_value>;
+       static auto maybe_color_from_hex(const std::string_view &input)
+               -> std::optional<css_value>;
+       static auto maybe_color_from_function(const std::string_view &func,
+                                                                          const std::vector<css_parser_token> &args)
+               -> std::optional<css_value>;
 };
 
 }