aboutsummaryrefslogtreecommitdiffstats
path: root/src/libserver/css/css.cxx
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2021-03-23 15:14:07 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2021-03-23 15:14:07 +0000
commit61d518bf1d96f079f2eed66dd3101cac64d83e00 (patch)
tree3c149dbb8d210e9b35942af19df56512e6bcaa8a /src/libserver/css/css.cxx
parentec88225473072493a0fad76864d25240e75bb5f4 (diff)
downloadrspamd-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.cxx76
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