diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2021-03-23 15:14:07 +0000 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2021-03-23 15:14:07 +0000 |
commit | 61d518bf1d96f079f2eed66dd3101cac64d83e00 (patch) | |
tree | 3c149dbb8d210e9b35942af19df56512e6bcaa8a /src/libserver/css/css.cxx | |
parent | ec88225473072493a0fad76864d25240e75bb5f4 (diff) | |
download | rspamd-61d518bf1d96f079f2eed66dd3101cac64d83e00.tar.gz rspamd-61d518bf1d96f079f2eed66dd3101cac64d83e00.zip |
[Project] Css: Add preliminary stylesheet support
Diffstat (limited to 'src/libserver/css/css.cxx')
-rw-r--r-- | src/libserver/css/css.cxx | 76 |
1 files changed, 67 insertions, 9 deletions
diff --git a/src/libserver/css/css.cxx b/src/libserver/css/css.cxx index 4587085a8..bd26cee1e 100644 --- a/src/libserver/css/css.cxx +++ b/src/libserver/css/css.cxx @@ -16,7 +16,7 @@ #include "css.h" #include "css.hxx" -#include "css_style.hxx" +#include "contrib/robin-hood/robin_hood.h" #include "css_parser.hxx" #define DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL #define DOCTEST_CONFIG_IMPLEMENT @@ -28,8 +28,6 @@ rspamd_css_parse_style (rspamd_mempool_t *pool, const guchar *begin, gsize len, { auto parse_res = rspamd::css::parse_css(pool, {(const char* )begin, len}); -#if 0 - /* Return once semantical parsing is done */ if (parse_res.has_value()) { return reinterpret_cast<rspamd_css>(parse_res.value().release()); } @@ -39,9 +37,6 @@ rspamd_css_parse_style (rspamd_mempool_t *pool, const guchar *begin, gsize len, "parse error"); return nullptr; } -#else - return nullptr; -#endif } namespace rspamd::css { @@ -49,10 +44,73 @@ namespace rspamd::css { INIT_LOG_MODULE_PUBLIC(css); class css_style_sheet::impl { - +public: + using selector_ptr = std::unique_ptr<css_selector>; + using selectors_hash = robin_hood::unordered_flat_map<selector_ptr, css_declarations_block_ptr>; + using universal_selector_t = std::pair<selector_ptr, css_declarations_block_ptr>; + selectors_hash tags_selector; + selectors_hash class_selectors; + selectors_hash id_selectors; + std::optional<universal_selector_t> universal_selector; }; -css_style_sheet::css_style_sheet () : pimpl(new impl) {} -css_style_sheet::~css_style_sheet () {} +css_style_sheet::css_style_sheet(rspamd_mempool_t *pool) + : pool(pool), pimpl(new impl) {} +css_style_sheet::~css_style_sheet() {} + +auto +css_style_sheet::add_selector_rule(std::unique_ptr<css_selector> &&selector, + css_declarations_block_ptr decls) -> void +{ + impl::selectors_hash *target_hash = nullptr; + + switch(selector->type) { + case css_selector::selector_type::SELECTOR_ALL: + if (pimpl->universal_selector) { + /* Another universal selector */ + msg_debug_css("redefined universal selector, merging rules"); + pimpl->universal_selector->second->merge_block(*decls); + } + else { + msg_debug_css("added universal selector"); + pimpl->universal_selector = std::make_pair(std::move(selector), + decls); + } + break; + case css_selector::selector_type::SELECTOR_CLASS: + target_hash = &pimpl->class_selectors; + break; + case css_selector::selector_type::SELECTOR_ID: + target_hash = &pimpl->id_selectors; + break; + case css_selector::selector_type::SELECTOR_ELEMENT: + target_hash = &pimpl->tags_selector; + break; + } + + if (target_hash) { + auto found_it = target_hash->find(selector); + + if (found_it == target_hash->end()) { + /* Easy case, new element */ + target_hash->insert({std::move(selector), decls}); + } + else { + /* The problem with merging is actually in how to handle selectors chains + * For example, we have 2 selectors: + * 1. class id tag -> meaning that we first match class, then we ensure that + * id is also the same and finally we check the tag + * 2. tag class id -> it means that we check first tag, then class and then id + * So we have somehow equal path in the xpath terms. + * I suppose now, that we merely check parent stuff and handle duplicates + * merging when finally resolving paths. + */ + auto sel_str = selector->to_string().value_or("unknown"); + msg_debug_css("found duplicate selector: %*s", (int)sel_str.size(), + sel_str.data()); + found_it->second->merge_block(*decls); + } + } +} }
\ No newline at end of file |