summaryrefslogtreecommitdiff
path: root/libs/litehtml/src/element.cpp
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2024-03-18 12:13:54 +0300
committerGeorge Hazan <george.hazan@gmail.com>2024-03-18 12:13:54 +0300
commit705c4d24c9c61edffc82864bf9c24384dc29a8d7 (patch)
tree4d21f87671db36b99402da3221d45b64c257c1fe /libs/litehtml/src/element.cpp
parent5784fc3a62b9136c6690ed45ec7b505f35512e08 (diff)
litehtml - lightweight html renderer
Diffstat (limited to 'libs/litehtml/src/element.cpp')
-rw-r--r--libs/litehtml/src/element.cpp478
1 files changed, 478 insertions, 0 deletions
diff --git a/libs/litehtml/src/element.cpp b/libs/litehtml/src/element.cpp
new file mode 100644
index 0000000000..e2b732ff1b
--- /dev/null
+++ b/libs/litehtml/src/element.cpp
@@ -0,0 +1,478 @@
+#include "html.h"
+#include "element.h"
+#include "document.h"
+#include "render_item.h"
+#include "render_flex.h"
+#include "render_inline.h"
+#include "render_table.h"
+#include "el_before_after.h"
+
+namespace litehtml
+{
+
+#define LITEHTML_EMPTY_FUNC {}
+#define LITEHTML_RETURN_FUNC(ret) {return ret;}
+
+element::element(const document::ptr& doc) : m_doc(doc)
+{
+}
+
+position element::get_placement() const
+{
+ position pos;
+ bool is_first = true;
+ for(const auto& ri_el : m_renders)
+ {
+ auto ri = ri_el.lock();
+ if(ri)
+ {
+ position ri_pos = ri_el.lock()->get_placement();
+ if(is_first)
+ {
+ is_first = false;
+ pos = ri_pos;
+ } else
+ {
+ if(pos.x < ri_pos.x)
+ {
+ pos.x = ri_pos.x;
+ }
+ if(pos.y < ri_pos.y)
+ {
+ pos.y = ri_pos.y;
+ }
+ }
+ }
+ }
+ return pos;
+}
+
+bool element::is_inline() const
+{
+ if( css().get_display() == display_inline ||
+ css().get_display() == display_inline_table ||
+ css().get_display() == display_inline_block ||
+ css().get_display() == display_inline_text ||
+ css().get_display() == display_inline_flex)
+ {
+ return true;
+ }
+ return false;
+}
+
+bool element::is_inline_box() const
+{
+ if( css().get_display() == display_inline_table ||
+ css().get_display() == display_inline_block ||
+ css().get_display() == display_inline_flex)
+ {
+ return true;
+ }
+ return false;
+}
+
+bool element::is_ancestor(const ptr &el) const
+{
+ element::ptr el_parent = parent();
+ while(el_parent && el_parent != el)
+ {
+ el_parent = el_parent->parent();
+ }
+ if(el_parent)
+ {
+ return true;
+ }
+ return false;
+}
+
+bool element::is_table_skip() const
+{
+ return is_space() || is_comment() || css().get_display() == display_none;
+}
+
+string element::dump_get_name()
+{
+ return "element";
+}
+
+std::vector<std::tuple<string, string>> element::dump_get_attrs()
+{
+ return m_css.dump_get_attrs();
+}
+
+void element::dump(dumper& cout)
+{
+ cout.begin_node(dump_get_name());
+
+ auto attrs = dump_get_attrs();
+ if(!attrs.empty())
+ {
+ cout.begin_attrs_group("attributes");
+ for (const auto &attr: attrs)
+ {
+ cout.add_attr(std::get<0>(attr), std::get<1>(attr));
+ }
+ cout.end_attrs_group();
+ }
+
+ if(!m_children.empty())
+ {
+ cout.begin_attrs_group("children");
+ for (const auto &el: m_children)
+ {
+ el->dump(cout);
+ }
+ cout.end_attrs_group();
+ }
+
+ cout.end_node();
+}
+
+std::shared_ptr<render_item> element::create_render_item(const std::shared_ptr<render_item>& parent_ri)
+{
+ std::shared_ptr<render_item> ret;
+
+ if(css().get_display() == display_table_column ||
+ css().get_display() == display_table_column_group ||
+ css().get_display() == display_table_footer_group ||
+ css().get_display() == display_table_header_group ||
+ css().get_display() == display_table_row_group)
+ {
+ ret = std::make_shared<render_item_table_part>(shared_from_this());
+ } else if(css().get_display() == display_table_row)
+ {
+ ret = std::make_shared<render_item_table_row>(shared_from_this());
+ } else if(css().get_display() == display_block ||
+ css().get_display() == display_table_cell ||
+ css().get_display() == display_table_caption ||
+ css().get_display() == display_list_item ||
+ css().get_display() == display_inline_block)
+ {
+ ret = std::make_shared<render_item_block>(shared_from_this());
+ } else if(css().get_display() == display_table || css().get_display() == display_inline_table)
+ {
+ ret = std::make_shared<render_item_table>(shared_from_this());
+ } else if(css().get_display() == display_inline || css().get_display() == display_inline_text)
+ {
+ ret = std::make_shared<render_item_inline>(shared_from_this());
+ } else if(css().get_display() == display_flex || css().get_display() == display_inline_flex)
+ {
+ ret = std::make_shared<render_item_flex>(shared_from_this());
+ }
+ if(ret)
+ {
+ if (css().get_display() == display_table ||
+ css().get_display() == display_inline_table ||
+ css().get_display() == display_table_caption ||
+ css().get_display() == display_table_cell ||
+ css().get_display() == display_table_column ||
+ css().get_display() == display_table_column_group ||
+ css().get_display() == display_table_footer_group ||
+ css().get_display() == display_table_header_group ||
+ css().get_display() == display_table_row ||
+ css().get_display() == display_table_row_group)
+ {
+ get_document()->add_tabular(ret);
+ }
+
+ ret->parent(parent_ri);
+ for(const auto& el : m_children)
+ {
+ auto ri = el->create_render_item(ret);
+ if(ri)
+ {
+ ret->add_child(ri);
+ }
+ }
+ }
+ return ret;
+}
+
+bool element::requires_styles_update()
+{
+ for (const auto& used_style : m_used_styles)
+ {
+ if(used_style->m_selector->is_media_valid())
+ {
+ int res = select(*(used_style->m_selector), true);
+ if( (res == select_no_match && used_style->m_used) || (res == select_match && !used_style->m_used) )
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void element::add_render(const std::shared_ptr<render_item>& ri)
+{
+ m_renders.push_back(ri);
+}
+
+bool element::find_styles_changes( position::vector& redraw_boxes)
+{
+ if(css().get_display() == display_inline_text)
+ {
+ return false;
+ }
+
+ bool ret = false;
+
+ if(requires_styles_update())
+ {
+ auto fetch_boxes = [&](const std::shared_ptr<element>& el)
+ {
+ for(const auto& weak_ri : el->m_renders)
+ {
+ auto ri = weak_ri.lock();
+ if(ri)
+ {
+ position::vector boxes;
+ ri->get_rendering_boxes(boxes);
+ for (auto &box: boxes)
+ {
+ redraw_boxes.push_back(box);
+ }
+ }
+ }
+ };
+ fetch_boxes(shared_from_this());
+ for (auto& el : m_children)
+ {
+ fetch_boxes(el);
+ }
+
+ refresh_styles();
+ compute_styles();
+ ret = true;
+ }
+ for (auto& el : m_children)
+ {
+ if(el->find_styles_changes(redraw_boxes))
+ {
+ ret = true;
+ }
+ }
+ return ret;
+}
+
+element::ptr element::_add_before_after(int type, const style& /*style*/)
+{
+ element::ptr el;
+ if(type == 0)
+ {
+ el = std::make_shared<el_before>(get_document());
+ m_children.insert(m_children.begin(), el);
+ } else
+ {
+ el = std::make_shared<el_after>(get_document());
+ m_children.insert(m_children.end(), el);
+ }
+ el->parent(shared_from_this());
+ return el;
+}
+
+bool element::is_block_formatting_context() const
+{
+ if(m_css.get_display() == display_block)
+ {
+ auto par = parent();
+ if(par && (par->css().get_display() == display_inline_flex || par->css().get_display() == display_flex))
+ {
+ return true;
+ }
+ }
+ if( m_css.get_display() == display_inline_block ||
+ m_css.get_display() == display_table_cell ||
+ m_css.get_display() == display_inline_flex ||
+ m_css.get_display() == display_flex ||
+ m_css.get_display() == display_table_caption ||
+ is_root() ||
+ m_css.get_float() != float_none ||
+ m_css.get_position() == element_position_absolute ||
+ m_css.get_position() == element_position_fixed ||
+ m_css.get_overflow() > overflow_visible)
+ {
+ return true;
+ }
+ return false;
+}
+
+litehtml::string litehtml::element::get_counter_value(const string& counter_name)
+{
+ std::map<string_id, int>::iterator i;
+ if (find_counter(_id(counter_name), i))
+ {
+ return std::to_string(i->second);
+ }
+ return "0";
+}
+
+string litehtml::element::get_counters_value(const string_vector& parameters)
+{
+ string result;
+ if (parameters.size() >= 2) {
+ const string_id counter_name_id = _id(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_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, instance one with value '0'
+ shared_from_this()->m_counter_values[counter_name_id] = 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_id& counter_name_id, std::map<string_id, int>::iterator& map_iterator) {
+ element::ptr current = shared_from_this();
+
+ while (current != nullptr)
+ {
+ map_iterator = current->m_counter_values.find(counter_name_id);
+ if (map_iterator != current->m_counter_values.end()) {
+ return true;
+ }
+
+ // on each level, search previous siblings too
+ std::vector<element::ptr> 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_id);
+ if (map_iterator != sibling->m_counter_values.end()) {
+ return true;
+ }
+ }
+ current = current->parent();
+ }
+
+ return false;
+}
+
+std::vector<element::ptr> litehtml::element::get_siblings_before() const
+{
+ std::vector<element::ptr> 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<void(const string_id&, const int)> handler) const {
+ int pos = 0;
+ while (pos < (int) tokens.size()) {
+ string name = tokens[pos];
+ int value = default_value;
+ if (pos < (int) tokens.size() - 1 && litehtml::is_number(tokens[pos + 1], false)) {
+ value = atoi(tokens[pos + 1].c_str());
+ pos += 2;
+ }
+ else {
+ pos += 1;
+ }
+ handler(_id(name), value);
+ }
+}
+
+void litehtml::element::increment_counter(const string_id& counter_name_id, const int increment)
+{
+ std::map<string_id, int>::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_id] = increment;
+ }
+}
+
+void litehtml::element::reset_counter(const string_id& counter_name_id, const int value)
+{
+ m_counter_values[counter_name_id] = 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
+elements_list element::select_all(const css_selector& /*selector*/) LITEHTML_RETURN_FUNC(elements_list())
+elements_list element::select_all(const string& /*selector*/) LITEHTML_RETURN_FUNC(elements_list())
+element::ptr element::select_one( const css_selector& /*selector*/ ) LITEHTML_RETURN_FUNC(nullptr)
+element::ptr element::select_one( const string& /*selector*/ ) LITEHTML_RETURN_FUNC(nullptr)
+element::ptr element::find_adjacent_sibling(const element::ptr& /*el*/, const css_selector& /*selector*/, bool /*apply_pseudo*/ /*= true*/, bool* /*is_pseudo*/ /*= 0*/) LITEHTML_RETURN_FUNC(nullptr)
+element::ptr element::find_sibling(const element::ptr& /*el*/, const css_selector& /*selector*/, bool /*apply_pseudo*/ /*= true*/, bool* /*is_pseudo*/ /*= 0*/) LITEHTML_RETURN_FUNC(nullptr)
+bool element::is_nth_last_child(const element::ptr& /*el*/, int /*num*/, int /*off*/, bool /*of_type*/) const LITEHTML_RETURN_FUNC(false)
+bool element::is_nth_child(const element::ptr&, int /*num*/, int /*off*/, bool /*of_type*/) const LITEHTML_RETURN_FUNC(false)
+bool element::is_only_child(const element::ptr& /*el*/, bool /*of_type*/) const LITEHTML_RETURN_FUNC(false)
+void element::get_content_size( size& /*sz*/, int /*max_width*/ ) LITEHTML_EMPTY_FUNC
+bool element::appendChild(const ptr &/*el*/) LITEHTML_RETURN_FUNC(false)
+bool element::removeChild(const ptr &/*el*/) LITEHTML_RETURN_FUNC(false)
+void element::clearRecursive() LITEHTML_EMPTY_FUNC
+string_id element::id() const LITEHTML_RETURN_FUNC(empty_id)
+string_id element::tag() const LITEHTML_RETURN_FUNC(empty_id)
+const char* element::get_tagName() const LITEHTML_RETURN_FUNC("")
+void element::set_tagName( const char* /*tag*/ ) LITEHTML_EMPTY_FUNC
+void element::set_data( const char* /*data*/ ) LITEHTML_EMPTY_FUNC
+void element::set_attr( const char* /*name*/, const char* /*val*/ ) LITEHTML_EMPTY_FUNC
+void element::apply_stylesheet( const litehtml::css& /*stylesheet*/ ) LITEHTML_EMPTY_FUNC
+void element::refresh_styles() LITEHTML_EMPTY_FUNC
+void element::on_click() LITEHTML_EMPTY_FUNC
+void element::compute_styles( bool /*recursive*/ ) LITEHTML_EMPTY_FUNC
+const char* element::get_attr( const char* /*name*/, const char* def /*= 0*/ ) const LITEHTML_RETURN_FUNC(def)
+bool element::is_white_space() const LITEHTML_RETURN_FUNC(false)
+bool element::is_space() const LITEHTML_RETURN_FUNC(false)
+bool element::is_comment() const LITEHTML_RETURN_FUNC(false)
+bool element::is_body() const LITEHTML_RETURN_FUNC(false)
+bool element::is_break() const LITEHTML_RETURN_FUNC(false)
+bool element::is_text() const LITEHTML_RETURN_FUNC(false)
+
+bool element::on_mouse_over() LITEHTML_RETURN_FUNC(false)
+bool element::on_mouse_leave() LITEHTML_RETURN_FUNC(false)
+bool element::on_lbutton_down() LITEHTML_RETURN_FUNC(false)
+bool element::on_lbutton_up() LITEHTML_RETURN_FUNC(false)
+bool element::set_pseudo_class( string_id /*cls*/, bool /*add*/ ) LITEHTML_RETURN_FUNC(false)
+bool element::set_class( const char* /*pclass*/, bool /*add*/ ) LITEHTML_RETURN_FUNC(false)
+bool element::is_replaced() const LITEHTML_RETURN_FUNC(false)
+void element::draw(uint_ptr /*hdc*/, int /*x*/, int /*y*/, const position */*clip*/, const std::shared_ptr<render_item> &/*ri*/) LITEHTML_EMPTY_FUNC
+void element::draw_background(uint_ptr /*hdc*/, int /*x*/, int /*y*/, const position */*clip*/, const std::shared_ptr<render_item> &/*ri*/) LITEHTML_EMPTY_FUNC
+int element::get_enum_property (string_id /*name*/, bool /*inherited*/, int /*defval*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC(0)
+int element::get_int_property (string_id /*name*/, bool /*inherited*/, int /*defval*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC(0)
+css_length element::get_length_property (string_id /*name*/, bool /*inherited*/, css_length /*defval*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC(0)
+web_color element::get_color_property (string_id /*name*/, bool /*inherited*/, web_color /*defval*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC(web_color())
+string element::get_string_property (string_id /*name*/, bool /*inherited*/, const string& /*defval*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC("")
+float element::get_number_property (string_id /*name*/, bool /*inherited*/, float /*defval*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC(0)
+string_vector element::get_string_vector_property (string_id /*name*/, bool /*inherited*/, const string_vector& /*default_value*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC({})
+int_vector element::get_int_vector_property (string_id /*name*/, bool /*inherited*/, const int_vector& /*default_value*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC({})
+length_vector element::get_length_vector_property (string_id /*name*/, bool /*inherited*/, const length_vector& /*default_value*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC({})
+size_vector element::get_size_vector_property (string_id /*name*/, bool /*inherited*/, const size_vector& /*default_value*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC({})
+string element::get_custom_property (string_id /*name*/, const string& /*defval*/) const LITEHTML_RETURN_FUNC("")
+void element::get_text( string& /*text*/ ) LITEHTML_EMPTY_FUNC
+void element::parse_attributes() LITEHTML_EMPTY_FUNC
+int element::select(const string& /*selector*/) LITEHTML_RETURN_FUNC(select_no_match)
+int element::select(const css_selector& /*selector*/, bool /*apply_pseudo*/) LITEHTML_RETURN_FUNC(select_no_match)
+int element::select( const css_element_selector& /*selector*/, bool /*apply_pseudo*/ /*= true*/ ) LITEHTML_RETURN_FUNC(select_no_match)
+element::ptr element::find_ancestor(const css_selector& /*selector*/, bool /*apply_pseudo*/, bool* /*is_pseudo*/) LITEHTML_RETURN_FUNC(nullptr)
+
+} // namespace litehtml \ No newline at end of file