diff options
author | George Hazan <george.hazan@gmail.com> | 2024-03-18 12:13:54 +0300 |
---|---|---|
committer | George Hazan <george.hazan@gmail.com> | 2024-03-18 12:13:54 +0300 |
commit | 705c4d24c9c61edffc82864bf9c24384dc29a8d7 (patch) | |
tree | 4d21f87671db36b99402da3221d45b64c257c1fe /libs/litehtml/src/element.cpp | |
parent | 5784fc3a62b9136c6690ed45ec7b505f35512e08 (diff) |
litehtml - lightweight html renderer
Diffstat (limited to 'libs/litehtml/src/element.cpp')
-rw-r--r-- | libs/litehtml/src/element.cpp | 478 |
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 |