From 871d08390a74cd210bc16011b066e86509c7e8c9 Mon Sep 17 00:00:00 2001 From: MichelCalonder Date: Fri, 8 Dec 2023 15:36:50 +0100 Subject: [PATCH 01/10] basic implementaion for css counters --- include/litehtml/html_tag.h | 12 ++++++++- include/litehtml/string_id.h | 3 +++ src/el_before_after.cpp | 1 + src/html_tag.cpp | 50 ++++++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) diff --git a/include/litehtml/html_tag.h b/include/litehtml/html_tag.h index 71b9cb345..a1a0d6805 100644 --- a/include/litehtml/html_tag.h +++ b/include/litehtml/html_tag.h @@ -22,6 +22,7 @@ namespace litehtml friend class line_box; public: typedef std::shared_ptr ptr; + protected: string_id m_tag; string_id m_id; @@ -31,7 +32,10 @@ namespace litehtml string_map m_attrs; std::vector m_pseudo_classes; - void select_all(const css_selector& selector, elements_vector& res) override; + void select_all(const css_selector& selector, elements_vector& res) override; + + private: + std::map m_counter_values; public: explicit html_tag(const std::shared_ptr& doc); @@ -122,6 +126,12 @@ namespace litehtml string get_list_marker_text(int index); element::ptr get_element_before(const style& style, bool create); element::ptr get_element_after(const style& style, bool create); + string get_counter_value(const string& counter_name); + + private: + void handle_counter_properties(); + void increment_counter(const string& counter_name); + void reset_counter(const string& counter_name); }; /************************************************************************/ diff --git a/include/litehtml/string_id.h b/include/litehtml/string_id.h index 340ac7fbc..1a1dbdd13 100644 --- a/include/litehtml/string_id.h +++ b/include/litehtml/string_id.h @@ -287,6 +287,9 @@ STRING_ID( _flex_grow_, _flex_shrink_, _flex_basis_, + + _counter_reset_, + _counter_increment_, ); #undef STRING_ID extern const string_id empty_id; // _id("") diff --git a/src/el_before_after.cpp b/src/el_before_after.cpp index 4455642e8..655ea1bf3 100644 --- a/src/el_before_after.cpp +++ b/src/el_before_after.cpp @@ -155,6 +155,7 @@ void litehtml::el_before_after_base::add_function( const string& fnc, const stri break; // counter case 1: + add_text(get_counter_value(params)); break; // url case 2: diff --git a/src/html_tag.cpp b/src/html_tag.cpp index aed162de0..bfe282671 100644 --- a/src/html_tag.cpp +++ b/src/html_tag.cpp @@ -1531,9 +1531,59 @@ litehtml::element::ptr litehtml::html_tag::get_element_after(const style& style, return nullptr; } +litehtml::string litehtml::html_tag::get_counter_value(const string& counter_name) +{ + html_tag::ptr current = std::dynamic_pointer_cast(shared_from_this()); + while (current != nullptr) { + auto i = current->m_counter_values.find(counter_name); + if (i != current->m_counter_values.end()) { + return std::to_string(i->second); + } + current = std::dynamic_pointer_cast(current->parent()); + } + return "0"; +} + +void litehtml::html_tag::handle_counter_properties() +{ + const auto& reset_property = m_style.get_property(string_id::_counter_reset_); + if (reset_property.m_type != prop_type_invalid) { + reset_counter(reset_property.m_string); + return; + } + + const auto& inc_property = m_style.get_property(string_id::_counter_increment_); + if (inc_property.m_type != prop_type_invalid) { + increment_counter(inc_property.m_string); + return; + } +} + +void litehtml::html_tag::increment_counter(const string& counter_name) +{ + html_tag::ptr current = std::dynamic_pointer_cast(shared_from_this()); + while (current != nullptr) { + auto i = current->m_counter_values.find(counter_name); + if (i != current->m_counter_values.end()) { + current->m_counter_values[counter_name] = i->second + 1; + return; + } + current = std::dynamic_pointer_cast(current->parent()); + } + + // if counter is not found, initialize one on this element + m_counter_values[counter_name] = 1; +} + +void litehtml::html_tag::reset_counter(const string& counter_name) +{ + m_counter_values[counter_name] = 0; +} + void litehtml::html_tag::add_style(const style& style) { m_style.combine(style); + handle_counter_properties(); } void litehtml::html_tag::refresh_styles() From c6faa2e6c7b869ca0fcef54490a6e29403e9db2b Mon Sep 17 00:00:00 2001 From: MichelCalonder Date: Fri, 8 Dec 2023 19:33:26 +0100 Subject: [PATCH 02/10] fixed issue after merge (due to beautifying, type change from elements-vector to elements-list was not auto-merged) --- include/litehtml/element.h | 4 ++-- include/litehtml/html_tag.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/litehtml/element.h b/include/litehtml/element.h index e330b5c01..4a3bcad84 100644 --- a/include/litehtml/element.h +++ b/include/litehtml/element.h @@ -33,8 +33,8 @@ namespace litehtml std::list> m_renders; used_selector::vector m_used_styles; - virtual void select_all(const css_selector& selector, elements_list& res); - element::ptr _add_before_after(int type, const style& style); + virtual void select_all(const css_selector& selector, elements_list& res); + element::ptr _add_before_after(int type, const style& style); public: explicit element(const std::shared_ptr& doc); virtual ~element() = default; diff --git a/include/litehtml/html_tag.h b/include/litehtml/html_tag.h index f76d34f9a..e7a6df6c2 100644 --- a/include/litehtml/html_tag.h +++ b/include/litehtml/html_tag.h @@ -32,7 +32,7 @@ namespace litehtml string_map m_attrs; std::vector m_pseudo_classes; - void select_all(const css_selector& selector, elements_vector& res) override; + void select_all(const css_selector& selector, elements_list& res) override; private: std::map m_counter_values; @@ -86,7 +86,7 @@ namespace litehtml size_vector get_size_vector_property (string_id name, bool inherited, const size_vector& default_value, uint_ptr css_properties_member_offset) const override; string get_custom_property(string_id name, const string& default_value) const override; - elements_list& children(); + elements_list& children(); int select(const string& selector) override; int select(const css_selector& selector, bool apply_pseudo = true) override; From 28f72f8a323632dc540af8de1db67039776ad607 Mon Sep 17 00:00:00 2001 From: MichelCalonder Date: Wed, 13 Dec 2023 07:41:16 +0100 Subject: [PATCH 03/10] moved isnumber to html helper functions for later reuse --- include/litehtml/html.h | 4 +++- src/html.cpp | 11 +++++++++++ src/style.cpp | 14 +------------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/include/litehtml/html.h b/include/litehtml/html.h index b184ac30a..cbd0d26b7 100644 --- a/include/litehtml/html.h +++ b/include/litehtml/html.h @@ -36,7 +36,9 @@ namespace litehtml int t_strcasecmp(const char *s1, const char *s2); int t_strncasecmp(const char *s1, const char *s2, size_t n); - + + bool is_number(const string& string, const bool allow_dot = 1); + inline int t_isdigit(int c) { return (c >= '0' && c <= '9'); diff --git a/src/html.cpp b/src/html.cpp index 9695180a7..4c25b9f3d 100644 --- a/src/html.cpp +++ b/src/html.cpp @@ -277,3 +277,14 @@ litehtml::string litehtml::get_escaped_string(const string& in_str) } return ret; } + +bool litehtml::is_number(const string& string, const bool allow_dot) { + for (auto ch : string) + { + if (!(t_isdigit(ch) || (allow_dot && ch == '.'))) + { + return false; + } + } + return true; +} diff --git a/src/style.cpp b/src/style.cpp index 5642d36c4..3c1d37d29 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -992,18 +992,6 @@ void style::parse_font(const string& val, bool important) void style::parse_flex(const string& val, bool important) { - auto is_number = [](const string& val) - { - for (auto ch : val) - { - if ((ch < '0' || ch > '9') && ch != '.') - { - return false; - } - } - return true; - }; - css_length _auto = css_length::predef_value(flex_basis_auto); if (val == "initial") @@ -1046,7 +1034,7 @@ void style::parse_flex(const string& val, bool important) float grow = t_strtof(tokens[0]); add_parsed_property(_flex_grow_, property_value(grow, important)); - if (is_number(tokens[1])) + if (litehtml::is_number(tokens[1])) { float shrink = t_strtof(tokens[1]); add_parsed_property(_flex_shrink_, property_value(shrink, important)); From 391e71a6effc81d5310f50d5985734aa4440f135 Mon Sep 17 00:00:00 2001 From: MichelCalonder Date: Wed, 13 Dec 2023 07:42:41 +0100 Subject: [PATCH 04/10] started support int values for counter-reset and counter-increment --- include/litehtml/html_tag.h | 6 ++++-- src/html_tag.cpp | 40 ++++++++++++++++++++++++++++--------- src/style.cpp | 9 +++++++++ 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/include/litehtml/html_tag.h b/include/litehtml/html_tag.h index e7a6df6c2..9a1033e4f 100644 --- a/include/litehtml/html_tag.h +++ b/include/litehtml/html_tag.h @@ -10,6 +10,7 @@ #include "stylesheet.h" #include "line_box.h" #include "table.h" +#include "types.h" namespace litehtml { @@ -126,9 +127,10 @@ namespace litehtml string get_counter_value(const string& counter_name); private: + void parse_counter_tokens(const string_vector& tokens, const int default_value, std::function handler) const; void handle_counter_properties(); - void increment_counter(const string& counter_name); - void reset_counter(const string& counter_name); + void increment_counter(const string& counter_name, const int increment = 1); + void reset_counter(const string& counter_name, const int value = 0); }; /************************************************************************/ diff --git a/src/html_tag.cpp b/src/html_tag.cpp index fe7febdd9..2eb87b9f5 100644 --- a/src/html_tag.cpp +++ b/src/html_tag.cpp @@ -1561,40 +1561,62 @@ litehtml::string litehtml::html_tag::get_counter_value(const string& counter_nam return "0"; } +void litehtml::html_tag::parse_counter_tokens(const string_vector& tokens, const int default_value, std::function handler) const{ + int pos = 0; + while (pos < tokens.size()) { + string name = tokens[pos]; + int value = default_value; + if (pos < tokens.size() - 1 && litehtml::is_number(tokens[pos + 1], 0)) { + value = atoi(tokens[pos + 1].c_str()); + pos += 2; + } + else { + pos += 1; + } + handler(name, value); + } +} + void litehtml::html_tag::handle_counter_properties() { const auto& reset_property = m_style.get_property(string_id::_counter_reset_); - if (reset_property.m_type != prop_type_invalid) { - reset_counter(reset_property.m_string); + if (reset_property.m_type == prop_type_string_vector) { + auto reset_function = [&](const string&name, const int value) { + reset_counter(name, value); + }; + parse_counter_tokens(reset_property.m_string_vector, 0, reset_function); return; } const auto& inc_property = m_style.get_property(string_id::_counter_increment_); - if (inc_property.m_type != prop_type_invalid) { - increment_counter(inc_property.m_string); + if (inc_property.m_type == prop_type_string_vector) { + auto inc_function = [&](const string&name, const int value) { + increment_counter(name, value); + }; + parse_counter_tokens(inc_property.m_string_vector, 1, inc_function); return; } } -void litehtml::html_tag::increment_counter(const string& counter_name) +void litehtml::html_tag::increment_counter(const string& counter_name, const int increment) { html_tag::ptr current = std::dynamic_pointer_cast(shared_from_this()); while (current != nullptr) { auto i = current->m_counter_values.find(counter_name); if (i != current->m_counter_values.end()) { - current->m_counter_values[counter_name] = i->second + 1; + current->m_counter_values[counter_name] = i->second + increment; return; } current = std::dynamic_pointer_cast(current->parent()); } // if counter is not found, initialize one on this element - m_counter_values[counter_name] = 1; + m_counter_values[counter_name] = increment; } -void litehtml::html_tag::reset_counter(const string& counter_name) +void litehtml::html_tag::reset_counter(const string& counter_name, const int value) { - m_counter_values[counter_name] = 0; + m_counter_values[counter_name] = value; } void litehtml::html_tag::add_style(const style& style) diff --git a/src/style.cpp b/src/style.cpp index 3c1d37d29..2e462f486 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -536,6 +536,15 @@ void style::add_property(string_id name, const string& val, const string& baseur add_parsed_property(_flex_basis_, property_value(length, important)); break; + case _counter_increment_: + case _counter_reset_: + { + string_vector tokens; + split_string(val, tokens, " "); + add_parsed_property(name, property_value(tokens, important)); + break; + } + default: add_parsed_property(name, property_value(val, important)); } From 08bf1aa685882b8018e104cf2c7560b338a2636e Mon Sep 17 00:00:00 2001 From: MichelCalonder Date: Wed, 20 Dec 2023 06:51:15 +0100 Subject: [PATCH 05/10] moved m_counter_values and corresponding functions to element.h --- include/litehtml/element.h | 11 ++++++++ include/litehtml/html_tag.h | 8 +----- src/element.cpp | 50 +++++++++++++++++++++++++++++++++++++ src/html_tag.cpp | 48 ----------------------------------- 4 files changed, 62 insertions(+), 55 deletions(-) diff --git a/include/litehtml/element.h b/include/litehtml/element.h index 4a3bcad84..3da9ed9fe 100644 --- a/include/litehtml/element.h +++ b/include/litehtml/element.h @@ -35,6 +35,10 @@ namespace litehtml virtual void select_all(const css_selector& selector, elements_list& res); element::ptr _add_before_after(int type, const style& style); + + private: + std::map m_counter_values; + public: explicit element(const std::shared_ptr& doc); virtual ~element() = default; @@ -142,6 +146,13 @@ namespace litehtml { return _add_before_after(1, style); } + + string get_counter_value(const string& counter_name); + void increment_counter(const string& counter_name, const int increment = 1); + void reset_counter(const string& counter_name, const int value = 0); + + private: + void parse_counter_tokens(const string_vector& tokens, const int default_value, std::function handler) const; }; ////////////////////////////////////////////////////////////////////////// diff --git a/include/litehtml/html_tag.h b/include/litehtml/html_tag.h index 9a1033e4f..bae21ddc5 100644 --- a/include/litehtml/html_tag.h +++ b/include/litehtml/html_tag.h @@ -35,9 +35,6 @@ namespace litehtml void select_all(const css_selector& selector, elements_list& res) override; - private: - std::map m_counter_values; - public: explicit html_tag(const std::shared_ptr& doc); // constructor for anonymous wrapper boxes @@ -124,13 +121,10 @@ namespace litehtml string get_list_marker_text(int index); element::ptr get_element_before(const style& style, bool create); element::ptr get_element_after(const style& style, bool create); - string get_counter_value(const string& counter_name); private: - void parse_counter_tokens(const string_vector& tokens, const int default_value, std::function handler) const; void handle_counter_properties(); - void increment_counter(const string& counter_name, const int increment = 1); - void reset_counter(const string& counter_name, const int value = 0); + }; /************************************************************************/ diff --git a/src/element.cpp b/src/element.cpp index 1d0a509b1..64cd414a9 100644 --- a/src/element.cpp +++ b/src/element.cpp @@ -288,6 +288,56 @@ bool element::is_block_formatting_context() const return false; } +litehtml::string litehtml::element::get_counter_value(const string& counter_name) +{ + element::ptr current = shared_from_this(); + while (current != nullptr) { + auto i = current->m_counter_values.find(counter_name); + if (i != current->m_counter_values.end()) { + return std::to_string(i->second); + } + current = current->parent(); + } + return "0"; +} + +void litehtml::element::parse_counter_tokens(const string_vector& tokens, const int default_value, std::function handler) const { + int pos = 0; + while (pos < tokens.size()) { + string name = tokens[pos]; + int value = default_value; + if (pos < tokens.size() - 1 && litehtml::is_number(tokens[pos + 1], 0)) { + value = atoi(tokens[pos + 1].c_str()); + pos += 2; + } + else { + pos += 1; + } + handler(name, value); + } +} + +void litehtml::element::increment_counter(const string& counter_name, const int increment) +{ + element::ptr current = shared_from_this(); + while (current != nullptr) { + auto i = current->m_counter_values.find(counter_name); + if (i != current->m_counter_values.end()) { + current->m_counter_values[counter_name] = i->second + increment; + return; + } + current = current->parent(); + } + + // if counter is not found, initialize one on this element + m_counter_values[counter_name] = increment; +} + +void litehtml::element::reset_counter(const string& counter_name, const int value) +{ + m_counter_values[counter_name] = value; +} + const background* element::get_background(bool own_only) LITEHTML_RETURN_FUNC(nullptr) void element::add_style( const style& style) LITEHTML_EMPTY_FUNC void element::select_all(const css_selector& selector, elements_list& res) LITEHTML_EMPTY_FUNC diff --git a/src/html_tag.cpp b/src/html_tag.cpp index 2eb87b9f5..b27d6eb6d 100644 --- a/src/html_tag.cpp +++ b/src/html_tag.cpp @@ -1548,34 +1548,6 @@ litehtml::element::ptr litehtml::html_tag::get_element_after(const style& style, return nullptr; } -litehtml::string litehtml::html_tag::get_counter_value(const string& counter_name) -{ - html_tag::ptr current = std::dynamic_pointer_cast(shared_from_this()); - while (current != nullptr) { - auto i = current->m_counter_values.find(counter_name); - if (i != current->m_counter_values.end()) { - return std::to_string(i->second); - } - current = std::dynamic_pointer_cast(current->parent()); - } - return "0"; -} - -void litehtml::html_tag::parse_counter_tokens(const string_vector& tokens, const int default_value, std::function handler) const{ - int pos = 0; - while (pos < tokens.size()) { - string name = tokens[pos]; - int value = default_value; - if (pos < tokens.size() - 1 && litehtml::is_number(tokens[pos + 1], 0)) { - value = atoi(tokens[pos + 1].c_str()); - pos += 2; - } - else { - pos += 1; - } - handler(name, value); - } -} void litehtml::html_tag::handle_counter_properties() { @@ -1598,26 +1570,6 @@ void litehtml::html_tag::handle_counter_properties() } } -void litehtml::html_tag::increment_counter(const string& counter_name, const int increment) -{ - html_tag::ptr current = std::dynamic_pointer_cast(shared_from_this()); - while (current != nullptr) { - auto i = current->m_counter_values.find(counter_name); - if (i != current->m_counter_values.end()) { - current->m_counter_values[counter_name] = i->second + increment; - return; - } - current = std::dynamic_pointer_cast(current->parent()); - } - - // if counter is not found, initialize one on this element - m_counter_values[counter_name] = increment; -} - -void litehtml::html_tag::reset_counter(const string& counter_name, const int value) -{ - m_counter_values[counter_name] = value; -} void litehtml::html_tag::add_style(const style& style) { From ff6aa5fcc5280ae22a7ea9bff645fb0b41872211 Mon Sep 17 00:00:00 2001 From: MichelCalonder Date: Thu, 21 Dec 2023 18:42:48 +0100 Subject: [PATCH 06/10] included siblings in search so exapmple 2 (H1/H2, not nested) works too --- include/litehtml/element.h | 6 ++-- src/element.cpp | 66 +++++++++++++++++++++++++++++--------- 2 files changed, 54 insertions(+), 18 deletions(-) diff --git a/include/litehtml/element.h b/include/litehtml/element.h index 3da9ed9fe..e9cfbafd6 100644 --- a/include/litehtml/element.h +++ b/include/litehtml/element.h @@ -37,7 +37,7 @@ namespace litehtml element::ptr _add_before_after(int type, const style& style); private: - std::map m_counter_values; + std::map m_counter_values; public: explicit element(const std::shared_ptr& doc); @@ -152,7 +152,9 @@ namespace litehtml void reset_counter(const string& counter_name, const int value = 0); private: - void parse_counter_tokens(const string_vector& tokens, const int default_value, std::function handler) const; + std::vector get_siblings_before() const; + bool find_counter(const string& counter_name, std::map::iterator& map_iterator); + void parse_counter_tokens(const string_vector& tokens, const int default_value, std::function handler) const; }; ////////////////////////////////////////////////////////////////////////// diff --git a/src/element.cpp b/src/element.cpp index 64cd414a9..310b5e59d 100644 --- a/src/element.cpp +++ b/src/element.cpp @@ -290,17 +290,55 @@ bool element::is_block_formatting_context() const litehtml::string litehtml::element::get_counter_value(const string& counter_name) { + std::map::iterator i; + if (find_counter(counter_name, i)) + { + return std::to_string(i->second); + } + return "0"; +} + +bool litehtml::element::find_counter(const string& counter_name, std::map::iterator& map_iterator) { element::ptr current = shared_from_this(); - while (current != nullptr) { - auto i = current->m_counter_values.find(counter_name); - if (i != current->m_counter_values.end()) { - return std::to_string(i->second); + + // search upwards + while (current != nullptr) + { + map_iterator = current->m_counter_values.find(counter_name); + if (map_iterator != current->m_counter_values.end()) { + return true; + } + + // on each level, search previous siblings too + std::vector siblings = current->get_siblings_before(); + std::reverse(siblings.begin(), siblings.end()); + for (const element::ptr& sibling : siblings) { + map_iterator = sibling->m_counter_values.find(counter_name); + if (map_iterator != sibling->m_counter_values.end()) { + return true; + } } current = current->parent(); } - return "0"; + + return false; } +std::vector litehtml::element::get_siblings_before() const +{ + std::vector siblings; + if (parent() != nullptr) { + for (const element::ptr& sybling : parent()->children()) { + if (sybling == shared_from_this()) { + break; + } + siblings.push_back(sybling); + } + } + return siblings; +} + + void litehtml::element::parse_counter_tokens(const string_vector& tokens, const int default_value, std::function handler) const { int pos = 0; while (pos < tokens.size()) { @@ -319,18 +357,14 @@ void litehtml::element::parse_counter_tokens(const string_vector& tokens, const void litehtml::element::increment_counter(const string& counter_name, const int increment) { - element::ptr current = shared_from_this(); - while (current != nullptr) { - auto i = current->m_counter_values.find(counter_name); - if (i != current->m_counter_values.end()) { - current->m_counter_values[counter_name] = i->second + increment; - return; - } - current = current->parent(); + std::map::iterator i; + if (find_counter(counter_name, i)) { + i->second = i->second + increment; + } + else { + // if counter is not found, initialize one on this element + m_counter_values[counter_name] = increment; } - - // if counter is not found, initialize one on this element - m_counter_values[counter_name] = increment; } void litehtml::element::reset_counter(const string& counter_name, const int value) From b9368a4bc14e98b486f277cfaef37ee0785dfda0 Mon Sep 17 00:00:00 2001 From: MichelCalonder Date: Mon, 25 Dec 2023 11:18:00 +0100 Subject: [PATCH 07/10] support for counter_s_ --- include/litehtml/element.h | 1 + include/litehtml/html.h | 2 +- src/el_before_after.cpp | 12 ++++++++++-- src/element.cpp | 33 +++++++++++++++++++++++++++++++++ src/html.cpp | 6 +++--- 5 files changed, 48 insertions(+), 6 deletions(-) diff --git a/include/litehtml/element.h b/include/litehtml/element.h index e9cfbafd6..27177993e 100644 --- a/include/litehtml/element.h +++ b/include/litehtml/element.h @@ -148,6 +148,7 @@ namespace litehtml } string get_counter_value(const string& counter_name); + string get_counters_value(const string_vector& parameters); void increment_counter(const string& counter_name, const int increment = 1); void reset_counter(const string& counter_name, const int value = 0); diff --git a/include/litehtml/html.h b/include/litehtml/html.h index cbd0d26b7..818d5ce56 100644 --- a/include/litehtml/html.h +++ b/include/litehtml/html.h @@ -23,7 +23,7 @@ namespace litehtml { - void trim(string &s); + void trim(string &s, const string& chars_to_trim = " \n\r\t"); void lcase(string &s); int value_index(const string& val, const string& strings, int defValue = -1, char delim = ';'); string index_value(int index, const string& strings, char delim = ';'); diff --git a/src/el_before_after.cpp b/src/el_before_after.cpp index 7f1ddf277..c7c2d680b 100644 --- a/src/el_before_after.cpp +++ b/src/el_before_after.cpp @@ -133,7 +133,7 @@ void litehtml::el_before_after_base::add_text( const string& txt ) void litehtml::el_before_after_base::add_function( const string& fnc, const string& params ) { - int idx = value_index(fnc, "attr;counter;url"); + int idx = value_index(fnc, "attr;counter;counters;url"); switch(idx) { // attr @@ -157,8 +157,16 @@ void litehtml::el_before_after_base::add_function( const string& fnc, const stri case 1: add_text(get_counter_value(params)); break; - // url + // counters case 2: + { + string_vector tokens; + split_string(params, tokens, ","); + add_text(get_counters_value(tokens)); + } + break; + // url + case 3: { string p_url = params; trim(p_url); diff --git a/src/element.cpp b/src/element.cpp index 310b5e59d..07efba7b5 100644 --- a/src/element.cpp +++ b/src/element.cpp @@ -298,6 +298,39 @@ litehtml::string litehtml::element::get_counter_value(const string& counter_name return "0"; } +string litehtml::element::get_counters_value(const string_vector& parameters) +{ + string result = ""; + if (parameters.size() >= 2) { + const string& counter_name = parameters[0]; + string delims = parameters[1]; + litehtml::trim(delims, "\"'"); + + string_vector values; + + element::ptr current = shared_from_this(); + while (current != nullptr) + { + auto map_iterator = current->m_counter_values.find(counter_name); + if (map_iterator != current->m_counter_values.end()) { + values.push_back(std::to_string(map_iterator->second)); + } + current = current->parent(); + } + if (values.empty()) { + // if no counter is found, instancieate one with value '0' + shared_from_this()->m_counter_values[counter_name] = 0; + result = "0"; + } + else { + std::reverse(values.begin(), values.end()); + litehtml::join_string(result, values, delims); + } + } + return result; +} + + bool litehtml::element::find_counter(const string& counter_name, std::map::iterator& map_iterator) { element::ptr current = shared_from_this(); diff --git a/src/html.cpp b/src/html.cpp index 4c25b9f3d..ee8ddad8d 100644 --- a/src/html.cpp +++ b/src/html.cpp @@ -2,9 +2,9 @@ #include "types.h" #include "utf8_strings.h" -void litehtml::trim(string &s) +void litehtml::trim(string &s, const string& chars_to_trim) { - string::size_type pos = s.find_first_not_of(" \n\r\t"); + string::size_type pos = s.find_first_not_of(chars_to_trim); if(pos != string::npos) { s.erase(s.begin(), s.begin() + pos); @@ -14,7 +14,7 @@ void litehtml::trim(string &s) s = ""; return; } - pos = s.find_last_not_of(" \n\r\t"); + pos = s.find_last_not_of(chars_to_trim); if(pos != string::npos) { s.erase(s.begin() + pos + 1, s.end()); From 05ae1051ee30fc8d71a44d3b65ce69748cbf0509 Mon Sep 17 00:00:00 2001 From: MichelCalonder Date: Tue, 26 Dec 2023 07:15:55 +0100 Subject: [PATCH 08/10] used string_id instead of string --- include/litehtml/element.h | 10 +++++----- src/element.cpp | 34 +++++++++++++++++----------------- src/html_tag.cpp | 8 ++++---- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/include/litehtml/element.h b/include/litehtml/element.h index 27177993e..d2bc372e9 100644 --- a/include/litehtml/element.h +++ b/include/litehtml/element.h @@ -37,7 +37,7 @@ namespace litehtml element::ptr _add_before_after(int type, const style& style); private: - std::map m_counter_values; + std::map m_counter_values; public: explicit element(const std::shared_ptr& doc); @@ -149,13 +149,13 @@ namespace litehtml string get_counter_value(const string& counter_name); string get_counters_value(const string_vector& parameters); - void increment_counter(const string& counter_name, const int increment = 1); - void reset_counter(const string& counter_name, const int value = 0); + void increment_counter(const string_id& counter_name_id, const int increment = 1); + void reset_counter(const string_id& counter_name_id, const int value = 0); private: std::vector get_siblings_before() const; - bool find_counter(const string& counter_name, std::map::iterator& map_iterator); - void parse_counter_tokens(const string_vector& tokens, const int default_value, std::function handler) const; + bool find_counter(const string_id& counter_name_id, std::map::iterator& map_iterator); + void parse_counter_tokens(const string_vector& tokens, const int default_value, std::function handler) const; }; ////////////////////////////////////////////////////////////////////////// diff --git a/src/element.cpp b/src/element.cpp index 07efba7b5..f0184592d 100644 --- a/src/element.cpp +++ b/src/element.cpp @@ -290,8 +290,8 @@ bool element::is_block_formatting_context() const litehtml::string litehtml::element::get_counter_value(const string& counter_name) { - std::map::iterator i; - if (find_counter(counter_name, i)) + std::map::iterator i; + if (find_counter(_id(counter_name), i)) { return std::to_string(i->second); } @@ -302,7 +302,7 @@ string litehtml::element::get_counters_value(const string_vector& parameters) { string result = ""; if (parameters.size() >= 2) { - const string& counter_name = parameters[0]; + const string_id counter_name_id = _id(parameters[0]); string delims = parameters[1]; litehtml::trim(delims, "\"'"); @@ -311,15 +311,15 @@ string litehtml::element::get_counters_value(const string_vector& parameters) element::ptr current = shared_from_this(); while (current != nullptr) { - auto map_iterator = current->m_counter_values.find(counter_name); + auto map_iterator = current->m_counter_values.find(counter_name_id); if (map_iterator != current->m_counter_values.end()) { values.push_back(std::to_string(map_iterator->second)); } current = current->parent(); } if (values.empty()) { - // if no counter is found, instancieate one with value '0' - shared_from_this()->m_counter_values[counter_name] = 0; + // if no counter is found, instanciate one with value '0' + shared_from_this()->m_counter_values[counter_name_id] = 0; result = "0"; } else { @@ -331,13 +331,13 @@ string litehtml::element::get_counters_value(const string_vector& parameters) } -bool litehtml::element::find_counter(const string& counter_name, std::map::iterator& map_iterator) { +bool litehtml::element::find_counter(const string_id& counter_name_id, std::map::iterator& map_iterator) { element::ptr current = shared_from_this(); // search upwards while (current != nullptr) { - map_iterator = current->m_counter_values.find(counter_name); + map_iterator = current->m_counter_values.find(counter_name_id); if (map_iterator != current->m_counter_values.end()) { return true; } @@ -346,7 +346,7 @@ bool litehtml::element::find_counter(const string& counter_name, std::map siblings = current->get_siblings_before(); std::reverse(siblings.begin(), siblings.end()); for (const element::ptr& sibling : siblings) { - map_iterator = sibling->m_counter_values.find(counter_name); + map_iterator = sibling->m_counter_values.find(counter_name_id); if (map_iterator != sibling->m_counter_values.end()) { return true; } @@ -372,7 +372,7 @@ std::vector litehtml::element::get_siblings_before() const } -void litehtml::element::parse_counter_tokens(const string_vector& tokens, const int default_value, std::function handler) const { +void litehtml::element::parse_counter_tokens(const string_vector& tokens, const int default_value, std::function handler) const { int pos = 0; while (pos < tokens.size()) { string name = tokens[pos]; @@ -384,25 +384,25 @@ void litehtml::element::parse_counter_tokens(const string_vector& tokens, const else { pos += 1; } - handler(name, value); + handler(_id(name), value); } } -void litehtml::element::increment_counter(const string& counter_name, const int increment) +void litehtml::element::increment_counter(const string_id& counter_name_id, const int increment) { - std::map::iterator i; - if (find_counter(counter_name, i)) { + std::map::iterator i; + if (find_counter(counter_name_id, i)) { i->second = i->second + increment; } else { // if counter is not found, initialize one on this element - m_counter_values[counter_name] = increment; + m_counter_values[counter_name_id] = increment; } } -void litehtml::element::reset_counter(const string& counter_name, const int value) +void litehtml::element::reset_counter(const string_id& counter_name_id, const int value) { - m_counter_values[counter_name] = value; + m_counter_values[counter_name_id] = value; } const background* element::get_background(bool own_only) LITEHTML_RETURN_FUNC(nullptr) diff --git a/src/html_tag.cpp b/src/html_tag.cpp index b27d6eb6d..ab2c45e99 100644 --- a/src/html_tag.cpp +++ b/src/html_tag.cpp @@ -1553,8 +1553,8 @@ void litehtml::html_tag::handle_counter_properties() { const auto& reset_property = m_style.get_property(string_id::_counter_reset_); if (reset_property.m_type == prop_type_string_vector) { - auto reset_function = [&](const string&name, const int value) { - reset_counter(name, value); + auto reset_function = [&](const string_id&name_id, const int value) { + reset_counter(name_id, value); }; parse_counter_tokens(reset_property.m_string_vector, 0, reset_function); return; @@ -1562,8 +1562,8 @@ void litehtml::html_tag::handle_counter_properties() const auto& inc_property = m_style.get_property(string_id::_counter_increment_); if (inc_property.m_type == prop_type_string_vector) { - auto inc_function = [&](const string&name, const int value) { - increment_counter(name, value); + auto inc_function = [&](const string_id&name_id, const int value) { + increment_counter(name_id, value); }; parse_counter_tokens(inc_property.m_string_vector, 1, inc_function); return; From 683a0ab1086358497bc12c0d884cc5347026f052 Mon Sep 17 00:00:00 2001 From: MichelCalonder Date: Thu, 28 Dec 2023 19:27:42 +0100 Subject: [PATCH 09/10] Added tests for css counters --- test/render/counter.htm | 79 ++++++++++++++++++++++++++++++++++++ test/render/counter.htm.png | Bin 0 -> 3300 bytes 2 files changed, 79 insertions(+) create mode 100644 test/render/counter.htm create mode 100644 test/render/counter.htm.png diff --git a/test/render/counter.htm b/test/render/counter.htm new file mode 100644 index 000000000..bd24d157c --- /dev/null +++ b/test/render/counter.htm @@ -0,0 +1,79 @@ + + + + + css counters + + + + +

HTML/CSS Tutorials

+

HTML

+

CSS

+

Bootstrap

+

W3.CSS

+ +

Scripting Tutorials

+

JavaScript

+

jQuery

+

React

+ +

Programming Tutorials

+

Python

+

Java

+

C++

+
    +
  1. item
  2. +
  3. item +
      +
    1. item
    2. +
    3. item
    4. +
    5. item +
        +
      1. item
      2. +
      3. item
      4. +
      5. item
      6. +
      +
    6. +
    7. item
    8. +
    +
  4. +
  5. item
  6. +
  7. item
  8. +
+ +
    +
  1. item
  2. +
  3. item
  4. +
+ + + diff --git a/test/render/counter.htm.png b/test/render/counter.htm.png new file mode 100644 index 0000000000000000000000000000000000000000..ae151ac44d77d872bbf905a6354b3f92d675f59a GIT binary patch literal 3300 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 Q()aHR0dodj3S5Z$I}rZymH+?% literal 0 HcmV?d00001 From c6954248d6e09ca0f479247d9554fca9a9d03b39 Mon Sep 17 00:00:00 2001 From: MichelCalonder Date: Thu, 28 Dec 2023 19:40:26 +0100 Subject: [PATCH 10/10] reverted whitespace-only changes --- include/litehtml/element.h | 4 ++-- include/litehtml/html_tag.h | 6 ++---- src/element.cpp | 1 - 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/include/litehtml/element.h b/include/litehtml/element.h index d2bc372e9..c09fa2b3c 100644 --- a/include/litehtml/element.h +++ b/include/litehtml/element.h @@ -33,8 +33,8 @@ namespace litehtml std::list> m_renders; used_selector::vector m_used_styles; - virtual void select_all(const css_selector& selector, elements_list& res); - element::ptr _add_before_after(int type, const style& style); + virtual void select_all(const css_selector& selector, elements_list& res); + element::ptr _add_before_after(int type, const style& style); private: std::map m_counter_values; diff --git a/include/litehtml/html_tag.h b/include/litehtml/html_tag.h index bae21ddc5..9578d383f 100644 --- a/include/litehtml/html_tag.h +++ b/include/litehtml/html_tag.h @@ -10,7 +10,6 @@ #include "stylesheet.h" #include "line_box.h" #include "table.h" -#include "types.h" namespace litehtml { @@ -23,7 +22,6 @@ namespace litehtml friend class line_box; public: typedef std::shared_ptr ptr; - protected: string_id m_tag; string_id m_id; @@ -33,7 +31,7 @@ namespace litehtml string_map m_attrs; std::vector m_pseudo_classes; - void select_all(const css_selector& selector, elements_list& res) override; + void select_all(const css_selector& selector, elements_list& res) override; public: explicit html_tag(const std::shared_ptr& doc); @@ -84,7 +82,7 @@ namespace litehtml size_vector get_size_vector_property (string_id name, bool inherited, const size_vector& default_value, uint_ptr css_properties_member_offset) const override; string get_custom_property(string_id name, const string& default_value) const override; - elements_list& children(); + elements_list& children(); int select(const string& selector) override; int select(const css_selector& selector, bool apply_pseudo = true) override; diff --git a/src/element.cpp b/src/element.cpp index f0184592d..5fa68cac6 100644 --- a/src/element.cpp +++ b/src/element.cpp @@ -334,7 +334,6 @@ string litehtml::element::get_counters_value(const string_vector& parameters) bool litehtml::element::find_counter(const string_id& counter_name_id, std::map::iterator& map_iterator) { element::ptr current = shared_from_this(); - // search upwards while (current != nullptr) { map_iterator = current->m_counter_values.find(counter_name_id);