#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> 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 element::create_render_item(const std::shared_ptr& parent_ri)
{
std::shared_ptr 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(shared_from_this());
} else if(css().get_display() == display_table_row)
{
ret = std::make_shared(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(shared_from_this());
} else if(css().get_display() == display_table || css().get_display() == display_inline_table)
{
ret = std::make_shared(shared_from_this());
} else if(css().get_display() == display_inline || css().get_display() == display_inline_text)
{
ret = std::make_shared(shared_from_this());
} else if(css().get_display() == display_flex || css().get_display() == display_inline_flex)
{
ret = std::make_shared(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& 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& 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(get_document());
m_children.insert(m_children.begin(), el);
} else
{
el = std::make_shared(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::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::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 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 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 < (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::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 &/*ri*/) LITEHTML_EMPTY_FUNC
void element::draw_background(uint_ptr /*hdc*/, int /*x*/, int /*y*/, const position */*clip*/, const std::shared_ptr &/*ri*/) LITEHTML_EMPTY_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