commit b35db77b68eba8e68edeb5cb53824123dad7764e parent d4170e674a04910babb0e592e93441f5af53429f Author: Jonathan Boeing <jonathan@claws-mail.org> Date: Sat, 21 Oct 2023 02:22:33 -0700 Update LiteHTML sources Sync with upstream commit 42632777fbb047e15cb6a4f661a3304f993671ec Diffstat:
41 files changed, 1194 insertions(+), 1100 deletions(-)
diff --git a/src/plugins/litehtml_viewer/litehtml/Makefile.am b/src/plugins/litehtml_viewer/litehtml/Makefile.am @@ -76,13 +76,14 @@ liblitehtml_la_SOURCES = \ el_title.h \ el_tr.cpp \ el_tr.h \ + formatting_context.cpp \ + formatting_context.h \ html.cpp \ html.h \ html_tag.cpp \ html_tag.h \ iterators.cpp \ iterators.h \ - LICENSE \ line_box.cpp \ line_box.h \ litehtml.h \ @@ -93,16 +94,22 @@ liblitehtml_la_SOURCES = \ num_cvt.cpp \ num_cvt.h \ os_types.h \ - README.md \ render_block_context.cpp \ + render_block_context.h \ render_block.cpp \ + render_block.h \ render_flex.cpp \ + render_flex.h \ render_image.cpp \ + render_image.h \ render_inline_context.cpp \ + render_inline_context.h \ render_inline.cpp \ + render_inline.h \ render_item.cpp \ render_item.h \ render_table.cpp \ + render_table.h \ string_id.cpp \ string_id.h \ strtod.cpp \ diff --git a/src/plugins/litehtml_viewer/litehtml/README.md b/src/plugins/litehtml_viewer/litehtml/README.md @@ -1,5 +1,3 @@ -[](https://travis-ci.org/litehtml/litehtml) - # What is litehtml? **litehtml** is the lightweight HTML rendering engine with CSS2/CSS3 support. Note that **litehtml** itself does not draw any text, pictures or other graphics and that **litehtml** does not depend on any image/draw/font library. You are free to use any library to draw images, fonts and any other graphics. **litehtml** just parses HTML/CSS and places the HTML elements into the correct positions (renders HTML). To draw the HTML elements you have to implement the simple callback interface [document_container](https://github.com/litehtml/litehtml/wiki/document_container). This interface is really simple, check it out! The [document_container](https://github.com/litehtml/litehtml/wiki/document_container) implementation is required to render HTML correctly. @@ -14,7 +12,7 @@ ## Compatibility -**litehtml** is compatible with any platform suported by C++ and STL. For Windows MS Visual Studio 2013 is recommended. **litehtml** supports both UTF-8 and Unicode strings on Windows and UTF-8 strings on Linux and Haiku. +**litehtml** is compatible with any platform supported by C++ and STL. For Windows MS Visual Studio 2013 is recommended. **litehtml** supports only UTF-8 strings. ## Support for HTML and CSS standards @@ -34,12 +32,7 @@ The litebrowser source codes are available on GitHub: **litehtml** is distributed under [New BSD License](https://opensource.org/licenses/BSD-3-Clause). The **gumbo-parser** is disributed under [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) -## Support litehtml project - -If you like the work **litehtml** is doing please consider a small donation: - -[  ](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UHBQG6EAFCRBA) [  ](https://www.patreon.com/tordex) - -Bitcoin: **1CS1174GVSLbP33TBp8RFwqPS6KmQK6kLY** +## Links - + * [source code](https://github.com/litehtml/litehtml) + * [website](http://www.litehtml.com/) diff --git a/src/plugins/litehtml_viewer/litehtml/css_properties.cpp b/src/plugins/litehtml_viewer/litehtml/css_properties.cpp @@ -1,5 +1,6 @@ #include "html.h" #include "css_properties.h" +#include <cmath> #define offset(member) ((uint_ptr)&this->member - (uint_ptr)this) @@ -20,6 +21,7 @@ void litehtml::css_properties::compute(const element* el, const document::ptr& d m_vertical_align = (vertical_align) el->get_enum_property( _vertical_align_, false, va_baseline, offset(m_vertical_align)); m_text_transform = (text_transform) el->get_enum_property( _text_transform_, true, text_transform_none, offset(m_text_transform)); m_white_space = (white_space) el->get_enum_property( _white_space_, true, white_space_normal, offset(m_white_space)); + m_caption_side = (caption_side) el->get_enum_property( _caption_side_, true, caption_side_top, offset(m_caption_side)); // https://www.w3.org/TR/CSS22/visuren.html#dis-pos-flo if (m_display == display_none) @@ -221,7 +223,7 @@ void litehtml::css_properties::compute(const element* el, const document::ptr& d m_line_height = m_font_metrics.height; } else if(m_css_line_height.units() == css_units_none) { - m_line_height = (int) (m_css_line_height.val() * font_size); + m_line_height = (int) std::nearbyint(m_css_line_height.val() * font_size); } else { m_line_height = doc->to_pixels(m_css_line_height, font_size, font_size); diff --git a/src/plugins/litehtml_viewer/litehtml/css_properties.h b/src/plugins/litehtml_viewer/litehtml/css_properties.h @@ -70,6 +70,8 @@ namespace litehtml flex_align_self m_flex_align_self; flex_align_content m_flex_align_content; + caption_side m_caption_side; + private: void compute_font(const element* el, const std::shared_ptr<document>& doc); void compute_background(const element* el, const std::shared_ptr<document>& doc); @@ -238,6 +240,9 @@ namespace litehtml const css_length& get_border_spacing_y() const; void set_border_spacing_y(const css_length& mBorderSpacingY); + caption_side get_caption_side() const; + void set_caption_side(caption_side side); + float get_flex_grow() const; float get_flex_shrink() const; const css_length& get_flex_basis() const; @@ -638,6 +643,16 @@ namespace litehtml { return m_flex_align_content; } + + inline caption_side css_properties::get_caption_side() const + { + return m_caption_side; + } + inline void css_properties::set_caption_side(caption_side side) + { + m_caption_side = side; + } + } #endif //LITEHTML_CSS_PROPERTIES_H diff --git a/src/plugins/litehtml_viewer/litehtml/css_selector.cpp b/src/plugins/litehtml_viewer/litehtml/css_selector.cpp @@ -183,6 +183,11 @@ void litehtml::css_element_selector::parse( const string& txt ) string::size_type pos2 = txt.find_first_of('\"', pos + 1); attribute.val = txt.substr(pos + 1, pos2 == string::npos ? pos2 : (pos2 - pos - 1)); pos = pos2 == string::npos ? pos2 : (pos2 + 1); + } else if(txt[pos] == '\'') + { + string::size_type pos2 = txt.find_first_of('\'', pos + 1); + attribute.val = txt.substr(pos + 1, pos2 == string::npos ? pos2 : (pos2 - pos - 1)); + pos = pos2 == string::npos ? pos2 : (pos2 + 1); } else if(txt[pos] == ']') { pos ++; diff --git a/src/plugins/litehtml_viewer/litehtml/document.cpp b/src/plugins/litehtml_viewer/litehtml/document.cpp @@ -27,6 +27,8 @@ #include "gumbo.h" #include "utf8_strings.h" #include "render_item.h" +#include "render_table.h" +#include "render_block.h" litehtml::document::document(document_container* objContainer) { @@ -54,7 +56,7 @@ litehtml::document::ptr litehtml::document::createFromString( const char* str, d document::ptr doc = std::make_shared<document>(objPainter); // Create litehtml::elements. - elements_vector root_elements; + elements_list root_elements; doc->create_node(output->root, root_elements, true); if (!root_elements.empty()) { @@ -304,7 +306,7 @@ int litehtml::document::render( int max_width, render_type rt ) m_root_render->render_positioned(rt); } else { - ret = m_root_render->render(0, 0, cb_context); + ret = m_root_render->render(0, 0, cb_context, nullptr); if(m_root_render->fetch_positioned()) { m_fixed_boxes.clear(); @@ -718,7 +720,7 @@ void litehtml::document::add_media_list( const media_query_list::ptr& list ) } } -void litehtml::document::create_node(void* gnode, elements_vector& elements, bool parseTextNode) +void litehtml::document::create_node(void* gnode, elements_list& elements, bool parseTextNode) { auto* node = (GumboNode*)gnode; switch (node->type) @@ -756,7 +758,7 @@ void litehtml::document::create_node(void* gnode, elements_vector& elements, boo } if (ret) { - elements_vector child; + elements_list child; for (unsigned int i = 0; i < node->v.element.children.length; i++) { child.clear(); @@ -1018,7 +1020,7 @@ void litehtml::document::append_children_from_string(element& parent, const char GumboOutput* output = gumbo_parse(str); // Create litehtml::elements. - elements_vector child_elements; + elements_list child_elements; create_node(output->root, child_elements, true); // Destroy GumboOutput diff --git a/src/plugins/litehtml_viewer/litehtml/document.h b/src/plugins/litehtml_viewer/litehtml/document.h @@ -111,7 +111,7 @@ namespace litehtml private: uint_ptr add_font(const char* name, int size, const char* weight, const char* style, const char* decoration, font_metrics* fm); - void create_node(void* gnode, elements_vector& elements, bool parseTextNode); + void create_node(void* gnode, elements_list& elements, bool parseTextNode); bool update_media_lists(const media_features& features); void fix_tables_layout(); void fix_table_children(const std::shared_ptr<render_item>& el_ptr, style_display disp, const char* disp_str); diff --git a/src/plugins/litehtml_viewer/litehtml/el_before_after.cpp b/src/plugins/litehtml_viewer/litehtml/el_before_after.cpp @@ -109,7 +109,7 @@ void litehtml::el_before_after_base::add_text( const string& txt ) word.clear(); } word += chr; - element::ptr el = std::make_shared<el_text>(word.c_str(), get_document()); + element::ptr el = std::make_shared<el_space>(word.c_str(), get_document()); appendChild(el); word.clear(); } else @@ -197,8 +197,3 @@ litehtml::string litehtml::el_before_after_base::convert_escape( const char* txt u_str[1] = 0; return litehtml::string(litehtml_from_wchar(u_str)); } - -void litehtml::el_before_after_base::apply_stylesheet( const litehtml::css& stylesheet ) -{ - -} diff --git a/src/plugins/litehtml_viewer/litehtml/el_before_after.h b/src/plugins/litehtml_viewer/litehtml/el_before_after.h @@ -11,7 +11,6 @@ namespace litehtml el_before_after_base(const std::shared_ptr<document>& doc, bool before); void add_style(const style& style) override; - void apply_stylesheet(const litehtml::css& stylesheet) override; private: void add_text(const string& txt); void add_function(const string& fnc, const string& params); diff --git a/src/plugins/litehtml_viewer/litehtml/el_image.cpp b/src/plugins/litehtml_viewer/litehtml/el_image.cpp @@ -1,6 +1,6 @@ #include "html.h" #include "el_image.h" -#include "render_item.h" +#include "render_image.h" litehtml::el_image::el_image(const document::ptr& doc) : html_tag(doc) { diff --git a/src/plugins/litehtml_viewer/litehtml/el_style.h b/src/plugins/litehtml_viewer/litehtml/el_style.h @@ -7,7 +7,7 @@ namespace litehtml { class el_style : public element { - elements_vector m_children; + elements_list m_children; public: explicit el_style(const std::shared_ptr<document>& doc); diff --git a/src/plugins/litehtml_viewer/litehtml/el_table.cpp b/src/plugins/litehtml_viewer/litehtml/el_table.cpp @@ -30,23 +30,6 @@ void litehtml::el_table::parse_attributes() m_style.add_property(_width_, str); } - str = get_attr("align"); - if(str) - { - int align = value_index(str, "left;center;right"); - switch(align) - { - case 1: - m_style.add_property(_margin_left_, "auto"); - m_style.add_property(_margin_right_, "auto"); - break; - case 2: - m_style.add_property(_margin_left_, "auto"); - m_style.add_property(_margin_right_, "0"); - break; - } - } - str = get_attr("cellspacing"); if(str) { diff --git a/src/plugins/litehtml_viewer/litehtml/element.cpp b/src/plugins/litehtml_viewer/litehtml/element.cpp @@ -2,6 +2,9 @@ #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 @@ -44,7 +47,7 @@ position element::get_placement() const return pos; } -bool element::is_inline_box() const +bool element::is_inline() const { if( css().get_display() == display_inline || css().get_display() == display_inline_table || @@ -57,6 +60,17 @@ bool element::is_inline_box() const 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(); @@ -244,30 +258,41 @@ bool element::find_styles_changes( position::vector& redraw_boxes) element::ptr element::_add_before_after(int type, const style& style) { - if(style.get_property(_content_).m_type != prop_type_invalid) + element::ptr el; + if(type == 0) { - 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; + 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); } - return nullptr; + el->parent(shared_from_this()); + return el; } +bool element::is_block_formatting_context() const +{ + if( m_css.get_display() == display_inline_block || + m_css.get_display() == display_table_cell || + 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; +} 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_vector& res) LITEHTML_EMPTY_FUNC -elements_vector element::select_all(const css_selector& selector) LITEHTML_RETURN_FUNC(elements_vector()) -elements_vector element::select_all(const string& selector) LITEHTML_RETURN_FUNC(elements_vector()) +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) @@ -275,10 +300,6 @@ element::ptr element::find_sibling(const element::ptr& el, const css_selector& s 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) -element::ptr element::get_child( int idx ) const LITEHTML_RETURN_FUNC(nullptr) -size_t element::get_children_count() const LITEHTML_RETURN_FUNC(0) -void element::update_floats(int dy, const ptr &parent) LITEHTML_EMPTY_FUNC -bool element::is_floats_holder() 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) diff --git a/src/plugins/litehtml_viewer/litehtml/element.h b/src/plugins/litehtml_viewer/litehtml/element.h @@ -28,12 +28,12 @@ namespace litehtml protected: std::weak_ptr<element> m_parent; std::weak_ptr<document> m_doc; - elements_vector m_children; + elements_list m_children; css_properties m_css; std::list<std::weak_ptr<render_item>> m_renders; used_selector::vector m_used_styles; - virtual void select_all(const css_selector& selector, elements_vector& res); + 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<document>& doc); @@ -43,13 +43,14 @@ namespace litehtml css_properties& css_w(); bool in_normal_flow() const; - bool is_inline_box() const; + bool is_inline() const; // returns true if element is inline + bool is_inline_box() const; // returns true if element is inline box (inline-table, inline-box, inline-flex) bool is_block_box() const; position get_placement() const; bool is_positioned() const; bool is_float() const; + bool is_block_formatting_context() const; - bool have_parent() const; bool is_root() const; element::ptr parent() const; void parent(const element::ptr& par); @@ -57,9 +58,10 @@ namespace litehtml bool is_table_skip() const; std::shared_ptr<document> get_document() const; + const std::list<std::shared_ptr<element>>& children() const; - virtual elements_vector select_all(const string& selector); - virtual elements_vector select_all(const css_selector& selector); + virtual elements_list select_all(const string& selector); + virtual elements_list select_all(const css_selector& selector); virtual element::ptr select_one(const string& selector); virtual element::ptr select_one(const css_selector& selector); @@ -73,8 +75,6 @@ namespace litehtml virtual const char* get_tagName() const; virtual void set_tagName(const char* tag); virtual void set_data(const char* data); - virtual size_t get_children_count() const; - virtual element::ptr get_child(int idx) const; virtual void set_attr(const char* name, const char* val); virtual const char* get_attr(const char* name, const char* def = nullptr) const; @@ -119,8 +119,6 @@ namespace litehtml virtual element::ptr find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = nullptr); virtual element::ptr find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = nullptr); virtual void get_content_size(size& sz, int max_width); - virtual bool is_floats_holder() const; - virtual void update_floats(int dy, const ptr &parent); virtual bool is_nth_child(const element::ptr& el, int num, int off, bool of_type) const; virtual bool is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const; virtual bool is_only_child(const element::ptr& el, bool of_type) const; @@ -211,6 +209,11 @@ namespace litehtml } return false; } + + inline const std::list<std::shared_ptr<element>>& element::children() const + { + return m_children; + } } #endif // LH_ELEMENT_H diff --git a/src/plugins/litehtml_viewer/litehtml/formatting_context.cpp b/src/plugins/litehtml_viewer/litehtml/formatting_context.cpp @@ -0,0 +1,441 @@ +#include "html.h" +#include "render_item.h" +#include "formatting_context.h" + +void litehtml::formatting_context::add_float(const std::shared_ptr<render_item> &el, int min_width, int context) +{ + floated_box fb; + fb.pos.x = el->left() + m_current_left; + fb.pos.y = el->top() + m_current_top; + fb.pos.width = el->width(); + fb.pos.height = el->height(); + fb.float_side = el->src_el()->css().get_float(); + fb.clear_floats = el->src_el()->css().get_clear(); + fb.el = el; + fb.context = context; + fb.min_width = min_width; + + if(fb.float_side == float_left) + { + if(m_floats_left.empty()) + { + m_floats_left.push_back(fb); + } else + { + bool inserted = false; + for(auto i = m_floats_left.begin(); i != m_floats_left.end(); i++) + { + if(fb.pos.right() > i->pos.right()) + { + m_floats_left.insert(i, std::move(fb)); + inserted = true; + break; + } + } + if(!inserted) + { + m_floats_left.push_back(std::move(fb)); + } + } + m_cache_line_left.invalidate(); + } else if(fb.float_side == float_right) + { + if(m_floats_right.empty()) + { + m_floats_right.push_back(std::move(fb)); + } else + { + bool inserted = false; + for(auto i = m_floats_right.begin(); i != m_floats_right.end(); i++) + { + if(fb.pos.left() < i->pos.left()) + { + m_floats_right.insert(i, std::move(fb)); + inserted = true; + break; + } + } + if(!inserted) + { + m_floats_right.push_back(fb); + } + } + m_cache_line_right.invalidate(); + } +} + +int litehtml::formatting_context::get_floats_height(element_float el_float) const +{ + int h = 0; + + for(const auto& fb : m_floats_left) + { + bool process = false; + switch(el_float) + { + case float_none: + process = true; + break; + case float_left: + if (fb.clear_floats == clear_left || fb.clear_floats == clear_both) + { + process = true; + } + break; + case float_right: + if (fb.clear_floats == clear_right || fb.clear_floats == clear_both) + { + process = true; + } + break; + } + if(process) + { + if(el_float == float_none) + { + h = std::max(h, fb.pos.bottom()); + } else + { + h = std::max(h, fb.pos.top()); + } + } + } + + + for(const auto& fb : m_floats_right) + { + int process = false; + switch(el_float) + { + case float_none: + process = true; + break; + case float_left: + if (fb.clear_floats == clear_left || fb.clear_floats == clear_both) + { + process = true; + } + break; + case float_right: + if (fb.clear_floats == clear_right || fb.clear_floats == clear_both) + { + process = true; + } + break; + } + if(process) + { + if(el_float == float_none) + { + h = std::max(h, fb.pos.bottom()); + } else + { + h = std::max(h, fb.pos.top()); + } + } + } + + return h - m_current_top; +} + +int litehtml::formatting_context::get_left_floats_height() const +{ + int h = 0; + if(!m_floats_left.empty()) + { + for (const auto& fb : m_floats_left) + { + h = std::max(h, fb.pos.bottom()); + } + } + return h - m_current_top; +} + +int litehtml::formatting_context::get_right_floats_height() const +{ + int h = 0; + if(!m_floats_right.empty()) + { + for(const auto& fb : m_floats_right) + { + h = std::max(h, fb.pos.bottom()); + } + } + return h - m_current_top; +} + +int litehtml::formatting_context::get_line_left(int y ) +{ + y += m_current_top; + + if(m_cache_line_left.is_valid && m_cache_line_left.hash == y) + { + if(m_cache_line_left.val - m_current_left < 0) + { + return 0; + } + return m_cache_line_left.val - m_current_left; + } + + int w = 0; + for(const auto& fb : m_floats_left) + { + if (y >= fb.pos.top() && y < fb.pos.bottom()) + { + w = std::max(w, fb.pos.right()); + if (w < fb.pos.right()) + { + break; + } + } + } + m_cache_line_left.set_value(y, w); + w -= m_current_left; + if(w < 0) return 0; + return w; +} + +int litehtml::formatting_context::get_line_right(int y, int def_right ) +{ + y += m_current_top; + def_right += m_current_left; + if(m_cache_line_right.is_valid && m_cache_line_right.hash == y) + { + if(m_cache_line_right.is_default) + { + return def_right - m_current_left; + } else + { + int w = std::min(m_cache_line_right.val, def_right) - m_current_left; + if(w < 0) return 0; + return w; + } + } + + int w = def_right; + m_cache_line_right.is_default = true; + for(const auto& fb : m_floats_right) + { + if(y >= fb.pos.top() && y < fb.pos.bottom()) + { + w = std::min(w, fb.pos.left()); + m_cache_line_right.is_default = false; + if(w > fb.pos.left()) + { + break; + } + } + } + m_cache_line_right.set_value(y, w); + w -= m_current_left; + if(w < 0) return 0; + return w; +} + + +void litehtml::formatting_context::clear_floats(int context) +{ + auto iter = m_floats_left.begin(); + while(iter != m_floats_left.end()) + { + if(iter->context >= context) + { + iter = m_floats_left.erase(iter); + m_cache_line_left.invalidate(); + } else + { + iter++; + } + } + + iter = m_floats_right.begin(); + while(iter != m_floats_right.end()) + { + if(iter->context >= context) + { + iter = m_floats_right.erase(iter); + m_cache_line_right.invalidate(); + } else + { + iter++; + } + } +} + +int litehtml::formatting_context::get_cleared_top(const std::shared_ptr<render_item> &el, int line_top) const +{ + switch(el->src_el()->css().get_clear()) + { + case clear_left: + { + int fh = get_left_floats_height(); + if(fh && fh > line_top) + { + line_top = fh; + } + } + break; + case clear_right: + { + int fh = get_right_floats_height(); + if(fh && fh > line_top) + { + line_top = fh; + } + } + break; + case clear_both: + { + int fh = get_floats_height(float_none); + if(fh && fh > line_top) + { + line_top = fh; + } + } + break; + default: + if(el->src_el()->css().get_float() != float_none) + { + int fh = get_floats_height(el->src_el()->css().get_float()); + if(fh && fh > line_top) + { + line_top = fh; + } + } + break; + } + return line_top; +} + +int litehtml::formatting_context::find_next_line_top(int top, int width, int def_right ) +{ + top += m_current_top; + def_right += m_current_left; + + int new_top = top; + int_vector points; + + for(const auto& fb : m_floats_left) + { + if(fb.pos.top() >= top) + { + if(find(points.begin(), points.end(), fb.pos.top()) == points.end()) + { + points.push_back(fb.pos.top()); + } + } + if (fb.pos.bottom() >= top) + { + if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end()) + { + points.push_back(fb.pos.bottom()); + } + } + } + + for (const auto& fb : m_floats_right) + { + if (fb.pos.top() >= top) + { + if (find(points.begin(), points.end(), fb.pos.top()) == points.end()) + { + points.push_back(fb.pos.top()); + } + } + if (fb.pos.bottom() >= top) + { + if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end()) + { + points.push_back(fb.pos.bottom()); + } + } + } + + if(!points.empty()) + { + sort(points.begin(), points.end(), std::less<int>( )); + new_top = points.back(); + + for(auto pt : points) + { + int pos_left = 0; + int pos_right = def_right; + get_line_left_right(pt - m_current_top, def_right - m_current_left, pos_left, pos_right); + + if(pos_right - pos_left >= width) + { + new_top = pt; + break; + } + } + } + return new_top - m_current_top; +} + +void litehtml::formatting_context::update_floats(int dy, const std::shared_ptr<render_item> &parent) +{ + bool reset_cache = false; + for(auto fb = m_floats_left.rbegin(); fb != m_floats_left.rend(); fb++) + { + if(fb->el->src_el()->is_ancestor(parent->src_el())) + { + reset_cache = true; + fb->pos.y += dy; + } + } + if(reset_cache) + { + m_cache_line_left.invalidate(); + } + reset_cache = false; + for(auto fb = m_floats_right.rbegin(); fb != m_floats_right.rend(); fb++) + { + if(fb->el->src_el()->is_ancestor(parent->src_el())) + { + reset_cache = true; + fb->pos.y += dy; + } + } + if(reset_cache) + { + m_cache_line_right.invalidate(); + } +} + +void litehtml::formatting_context::apply_relative_shift(const containing_block_context &containing_block_size) +{ + for (const auto& fb : m_floats_left) + { + fb.el->apply_relative_shift(containing_block_size); + } +} + +int litehtml::formatting_context::find_min_left(int y, int context_idx) +{ + y += m_current_top; + int min_left = m_current_left; + for(const auto& fb : m_floats_left) + { + if (y >= fb.pos.top() && y < fb.pos.bottom() && fb.context == context_idx) + { + min_left += fb.min_width; + } + } + if(min_left < m_current_left) return 0; + return min_left - m_current_left; +} + +int litehtml::formatting_context::find_min_right(int y, int right, int context_idx) +{ + y += m_current_top; + int min_right = right + m_current_left; + for(const auto& fb : m_floats_right) + { + if (y >= fb.pos.top() && y < fb.pos.bottom() && fb.context == context_idx) + { + min_right -= fb.min_width; + } + } + if(min_right < m_current_left) return 0; + return min_right - m_current_left; +} diff --git a/src/plugins/litehtml_viewer/litehtml/formatting_context.h b/src/plugins/litehtml_viewer/litehtml/formatting_context.h @@ -0,0 +1,54 @@ +#ifndef LITEHTML_FLOATS_HOLDER_H +#define LITEHTML_FLOATS_HOLDER_H + +#include <list> +#include "types.h" + +namespace litehtml +{ + class formatting_context + { + private: + std::list<floated_box> m_floats_left; + std::list<floated_box> m_floats_right; + int_int_cache m_cache_line_left; + int_int_cache m_cache_line_right; + int m_current_top; + int m_current_left; + + public: + formatting_context() : m_current_top(0), m_current_left(0) {} + + void push_position(int x, int y) + { + m_current_left += x; + m_current_top += y; + } + void pop_position(int x, int y) + { + m_current_left -= x; + m_current_top -= y; + } + + void add_float(const std::shared_ptr<render_item> &el, int min_width, int context); + void clear_floats(int context); + int find_next_line_top( int top, int width, int def_right ); + int get_floats_height(element_float el_float = float_none) const; + int get_left_floats_height() const; + int get_right_floats_height() const; + int get_line_left( int y ); + void get_line_left_right( int y, int def_right, int& ln_left, int& ln_right ) + { + ln_left = get_line_left(y); + ln_right = get_line_right(y, def_right); + } + int get_line_right( int y, int def_right ); + int get_cleared_top(const std::shared_ptr<render_item> &el, int line_top) const; + void update_floats(int dy, const std::shared_ptr<render_item> &parent); + void apply_relative_shift(const containing_block_context &containing_block_size); + int find_min_left(int y, int context_idx); + int find_min_right(int y, int right, int context_idx); + }; +} + +#endif //LITEHTML_FLOATS_HOLDER_H diff --git a/src/plugins/litehtml_viewer/litehtml/html_tag.cpp b/src/plugins/litehtml_viewer/litehtml/html_tag.cpp @@ -121,7 +121,7 @@ const char* litehtml::html_tag::get_attr( const char* name, const char* def ) co return def; } -litehtml::elements_vector litehtml::html_tag::select_all( const string& selector ) +litehtml::elements_list litehtml::html_tag::select_all(const string& selector ) { css_selector sel; sel.parse(selector); @@ -129,14 +129,14 @@ litehtml::elements_vector litehtml::html_tag::select_all( const string& selector return select_all(sel); } -litehtml::elements_vector litehtml::html_tag::select_all( const css_selector& selector ) +litehtml::elements_list litehtml::html_tag::select_all(const css_selector& selector ) { - litehtml::elements_vector res; + litehtml::elements_list res; select_all(selector, res); return res; } -void litehtml::html_tag::select_all(const css_selector& selector, elements_vector& res) +void litehtml::html_tag::select_all(const css_selector& selector, elements_list& res) { if(select(selector)) { @@ -178,6 +178,11 @@ litehtml::element::ptr litehtml::html_tag::select_one( const css_selector& selec void litehtml::html_tag::apply_stylesheet( const litehtml::css& stylesheet ) { + if(is_root()) + { + int i = 0; + i++; + } for(const auto& sel : stylesheet.selectors()) { // optimization @@ -203,45 +208,59 @@ void litehtml::html_tag::apply_stylesheet( const litehtml::css& stylesheet ) if(sel->is_media_valid()) { - if(apply & select_match_pseudo_class) - { - if(select(*sel, true)) + auto apply_before_after = [&]() { + const auto& content_property = sel->m_style->get_property(_content_); + bool content_none = content_property.m_type == prop_type_string && content_property.m_string == "none"; + bool create = !content_none && (sel->m_right.m_attrs.size() > 1 || sel->m_right.m_tag != star_id); + + element::ptr el; if(apply & select_match_with_after) { - element::ptr el = get_element_after(*sel->m_style, true); - if(el) + el = get_element_after(*sel->m_style, create); + } else if(apply & select_match_with_before) + { + el = get_element_before(*sel->m_style, create); + } else + { + return; + } + if(el) + { + if(!content_none) { el->add_style(*sel->m_style); + } else + { + el->parent()->removeChild(el); } - } else if(apply & select_match_with_before) + } else { - element::ptr el = get_element_before(*sel->m_style, true); - if(el) + if(!content_none) { - el->add_style(*sel->m_style); + add_style(*sel->m_style); } } - else + us->m_used = true; + }; + + + if(apply & select_match_pseudo_class) + { + if(select(*sel, true)) + { + if((apply & (select_match_with_after | select_match_with_before))) + { + apply_before_after(); + } else { add_style(*sel->m_style); us->m_used = true; } } - } else if(apply & select_match_with_after) + } else if((apply & (select_match_with_after | select_match_with_before))) { - element::ptr el = get_element_after(*sel->m_style, true); - if(el) - { - el->add_style(*sel->m_style); - } - } else if(apply & select_match_with_before) - { - element::ptr el = get_element_before(*sel->m_style, true); - if(el) - { - el->add_style(*sel->m_style); - } + apply_before_after(); } else { add_style(*sel->m_style); @@ -537,9 +556,17 @@ int litehtml::html_tag::select(const css_element_selector& selector, bool apply_ case select_pseudo_element: if(attr.name == _after_) { + if(selector.m_attrs.size() == 1 && selector.m_tag == star_id && m_tag != __tag_after_) + { + return select_no_match; + } res |= select_match_with_after; } else if(attr.name == _before_) { + if(selector.m_attrs.size() == 1 && selector.m_tag == star_id && m_tag != __tag_before_) + { + return select_no_match; + } res |= select_match_with_before; } else { @@ -1063,32 +1090,6 @@ bool litehtml::html_tag::is_replaced() const return false; } -bool litehtml::html_tag::is_floats_holder() const -{ - if( m_css.get_display() == display_inline_block || - m_css.get_display() == display_table_cell || - 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; -} - -size_t litehtml::html_tag::get_children_count() const -{ - return m_children.size(); -} - -litehtml::element::ptr litehtml::html_tag::get_child( int idx ) const -{ - return m_children[idx]; -} - - void litehtml::html_tag::init_background_paint(position pos, std::vector<background_paint>& bg_paint, const background* bg, const std::shared_ptr<render_item>& ri) { bg_paint = { background_paint() }; diff --git a/src/plugins/litehtml_viewer/litehtml/html_tag.h b/src/plugins/litehtml_viewer/litehtml/html_tag.h @@ -31,7 +31,7 @@ namespace litehtml string_map m_attrs; std::vector<string_id> 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; public: explicit html_tag(const std::shared_ptr<document>& doc); @@ -46,8 +46,6 @@ namespace litehtml const char* get_tagName() const override; void set_tagName(const char* tag) override; void set_data(const char* data) override; - size_t get_children_count() const override; - element::ptr get_child(int idx) const override; void set_attr(const char* name, const char* val) override; const char* get_attr(const char* name, const char* def = nullptr) const override; @@ -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_vector& children(); + elements_list& children(); int select(const string& selector) override; int select(const css_selector& selector, bool apply_pseudo = true) override; @@ -92,8 +90,8 @@ namespace litehtml int select_pseudoclass(const css_attribute_selector& sel); int select_attribute(const css_attribute_selector& sel); - elements_vector select_all(const string& selector) override; - elements_vector select_all(const css_selector& selector) override; + elements_list select_all(const string& selector) override; + elements_list select_all(const css_selector& selector) override; element::ptr select_one(const string& selector) override; element::ptr select_one(const css_selector& selector) override; @@ -105,7 +103,6 @@ namespace litehtml void parse_attributes() override; void get_content_size(size& sz, int max_width) override; - bool is_floats_holder() const override; void add_style(const style& style) override; bool is_nth_child(const element::ptr& el, int num, int off, bool of_type) const override; @@ -128,7 +125,7 @@ namespace litehtml /* Inline Functions */ /************************************************************************/ - inline elements_vector& litehtml::html_tag::children() + inline elements_list& litehtml::html_tag::children() { return m_children; } diff --git a/src/plugins/litehtml_viewer/litehtml/line_box.cpp b/src/plugins/litehtml_viewer/litehtml/line_box.cpp @@ -551,7 +551,7 @@ std::shared_ptr<litehtml::render_item> litehtml::line_box::get_last_text_part() bool litehtml::line_box::can_hold(const std::unique_ptr<line_box_item>& item, white_space ws) const { - if(!item->get_el()->src_el()->is_inline_box()) return false; + if(!item->get_el()->src_el()->is_inline()) return false; if(item->get_type() == line_box_item::type_text_part) { diff --git a/src/plugins/litehtml_viewer/litehtml/master_css.h b/src/plugins/litehtml_viewer/litehtml/master_css.h @@ -224,6 +224,19 @@ table[border|=0] td, table[border|=0] th { border-style:none; } +table[align=left] { + float: left; +} + +table[align=right] { + float: right; +} + +table[align=center] { + margin-left: auto; + margin-right: auto; +} + caption { display: table-caption; } @@ -347,5 +360,17 @@ sup { font-size: smaller; } +figure { + display: block; + margin-top: 1em; + margin-bottom: 1em; + margin-left: 40px; + margin-right: 40px; +} + +figcaption { + display: block; +} + )##"; } #endif // LH_MASTER_CSS_H diff --git a/src/plugins/litehtml_viewer/litehtml/media_query.cpp b/src/plugins/litehtml_viewer/litehtml/media_query.cpp @@ -31,7 +31,7 @@ litehtml::media_query::ptr litehtml::media_query::create_from_string(const strin } else if(token.at(0) == '(') { token.erase(0, 1); - if(token.at(token.length() - 1) == ')') + if(!token.empty() && token.at(token.length() - 1) == ')') { token.erase(token.length() - 1, 1); } diff --git a/src/plugins/litehtml_viewer/litehtml/render_block.cpp b/src/plugins/litehtml_viewer/litehtml/render_block.cpp @@ -1,557 +1,55 @@ #include "html.h" -#include "render_item.h" +#include "render_block.h" +#include "render_inline_context.h" +#include "render_block_context.h" #include "document.h" -int litehtml::render_item_block::place_float(const std::shared_ptr<render_item> &el, int top, const containing_block_context &self_size) +int litehtml::render_item_block::place_float(const std::shared_ptr<render_item> &el, int top, const containing_block_context &self_size, formatting_context* fmt_ctx) { - int line_top = get_cleared_top(el, top); + int line_top = fmt_ctx->get_cleared_top(el, top); int line_left = 0; int line_right = self_size.render_width; - get_line_left_right(line_top, self_size.render_width, line_left, line_right); + fmt_ctx->get_line_left_right(line_top, self_size.render_width, line_left, line_right); int ret_width = 0; + int min_rendered_width = el->render(line_left, line_top, self_size.new_width(line_right), fmt_ctx); + if(min_rendered_width < el->width() && el->src_el()->css().get_width().is_predefined()) + { + el->render(line_left, line_top, self_size.new_width(min_rendered_width), fmt_ctx); + } + if (el->src_el()->css().get_float() == float_left) { - el->render(line_left, line_top, self_size.new_width(line_right)); if(el->right() > line_right) { - int new_top = find_next_line_top(el->top(), el->width(), self_size.render_width); - el->pos().x = get_line_left(new_top) + el->content_offset_left(); - el->pos().y = new_top + el->content_offset_top(); + line_top = fmt_ctx->find_next_line_top(el->top(), el->width(), self_size.render_width); + el->pos().x = fmt_ctx->get_line_left(line_top) + el->content_offset_left(); + el->pos().y = line_top + el->content_offset_top(); } - add_float(el, 0, 0, self_size.context_idx); - fix_line_width(float_left, self_size); - ret_width = el->right(); + fmt_ctx->add_float(el, min_rendered_width, self_size.context_idx); + fix_line_width(float_left, self_size, fmt_ctx); + + ret_width = fmt_ctx->find_min_left(line_top, self_size.context_idx); } else if (el->src_el()->css().get_float() == float_right) { - el->render(0, line_top, self_size.new_width(line_right)); - if(line_left + el->width() > line_right) { - int new_top = find_next_line_top(el->top(), el->width(), self_size.render_width); - el->pos().x = get_line_right(new_top, self_size.render_width) - el->width() + el->content_offset_left(); + int new_top = fmt_ctx->find_next_line_top(el->top(), el->width(), self_size.render_width); + el->pos().x = fmt_ctx->get_line_right(new_top, self_size.render_width) - el->width() + el->content_offset_left(); el->pos().y = new_top + el->content_offset_top(); } else { el->pos().x = line_right - el->width() + el->content_offset_left(); } - add_float(el, 0, 0, self_size.context_idx); - fix_line_width(float_right, self_size); - line_left = 0; - line_right = self_size.render_width; - get_line_left_right(line_top, self_size.render_width, line_left, line_right); - - ret_width = ret_width + (self_size.render_width - line_right); + fmt_ctx->add_float(el, min_rendered_width, self_size.context_idx); + fix_line_width(float_right, self_size, fmt_ctx); + line_right = fmt_ctx->find_min_right(line_top, self_size.render_width, self_size.context_idx); + ret_width = self_size.render_width - line_right; } return ret_width; } -int litehtml::render_item_block::get_floats_height(element_float el_float) const -{ - if(src_el()->is_floats_holder()) - { - int h = 0; - - for(const auto& fb : m_floats_left) - { - bool process = false; - switch(el_float) - { - case float_none: - process = true; - break; - case float_left: - if (fb.clear_floats == clear_left || fb.clear_floats == clear_both) - { - process = true; - } - break; - case float_right: - if (fb.clear_floats == clear_right || fb.clear_floats == clear_both) - { - process = true; - } - break; - } - if(process) - { - if(el_float == float_none) - { - h = std::max(h, fb.pos.bottom()); - } else - { - h = std::max(h, fb.pos.top()); - } - } - } - - - for(const auto& fb : m_floats_right) - { - int process = false; - switch(el_float) - { - case float_none: - process = true; - break; - case float_left: - if (fb.clear_floats == clear_left || fb.clear_floats == clear_both) - { - process = true; - } - break; - case float_right: - if (fb.clear_floats == clear_right || fb.clear_floats == clear_both) - { - process = true; - } - break; - } - if(process) - { - if(el_float == float_none) - { - h = std::max(h, fb.pos.bottom()); - } else - { - h = std::max(h, fb.pos.top()); - } - } - } - - return h; - } - auto el_parent = parent(); - if (el_parent) - { - int h = el_parent->get_floats_height(el_float); - return h - m_pos.y; - } - return 0; -} - -int litehtml::render_item_block::get_left_floats_height() const -{ - if(src_el()->is_floats_holder()) - { - int h = 0; - if(!m_floats_left.empty()) - { - for (const auto& fb : m_floats_left) - { - h = std::max(h, fb.pos.bottom()); - } - } - return h; - } - auto el_parent = parent(); - if (el_parent) - { - int h = el_parent->get_left_floats_height(); - return h - m_pos.y; - } - return 0; -} - -int litehtml::render_item_block::get_right_floats_height() const -{ - if(src_el()->is_floats_holder()) - { - int h = 0; - if(!m_floats_right.empty()) - { - for(const auto& fb : m_floats_right) - { - h = std::max(h, fb.pos.bottom()); - } - } - return h; - } - auto el_parent = parent(); - if (el_parent) - { - int h = el_parent->get_right_floats_height(); - return h - m_pos.y; - } - return 0; -} - -int litehtml::render_item_block::get_line_left( int y ) -{ - if(src_el()->is_floats_holder()) - { - if(m_cache_line_left.is_valid && m_cache_line_left.hash == y) - { - return m_cache_line_left.val; - } - - int w = 0; - for(const auto& fb : m_floats_left) - { - if (y >= fb.pos.top() && y < fb.pos.bottom()) - { - w = std::max(w, fb.pos.right()); - if (w < fb.pos.right()) - { - break; - } - } - } - m_cache_line_left.set_value(y, w); - return w; - } - auto el_parent = parent(); - if (el_parent) - { - int w = el_parent->get_line_left(y + m_pos.y); - if (w < 0) - { - w = 0; - } - return w - (w ? m_pos.x : 0); - } - return 0; -} - -int litehtml::render_item_block::get_line_right( int y, int def_right ) -{ - if(src_el()->is_floats_holder()) - { - if(m_cache_line_right.is_valid && m_cache_line_right.hash == y) - { - if(m_cache_line_right.is_default) - { - return def_right; - } else - { - return std::min(m_cache_line_right.val, def_right); - } - } - - int w = def_right; - m_cache_line_right.is_default = true; - for(const auto& fb : m_floats_right) - { - if(y >= fb.pos.top() && y < fb.pos.bottom()) - { - w = std::min(w, fb.pos.left()); - m_cache_line_right.is_default = false; - if(w > fb.pos.left()) - { - break; - } - } - } - m_cache_line_right.set_value(y, w); - return w; - } - auto el_parent = parent(); - if (el_parent) - { - int w = el_parent->get_line_right(y + m_pos.y, def_right + m_pos.x); - return w - m_pos.x; - } - return 0; -} - - -void litehtml::render_item_block::get_line_left_right( int y, int def_right, int& ln_left, int& ln_right ) -{ - if(src_el()->is_floats_holder()) - { - ln_left = get_line_left(y); - ln_right = get_line_right(y, def_right); - } else - { - auto el_parent = parent(); - if (el_parent) - { - el_parent->get_line_left_right(y + m_pos.y, def_right + m_pos.x, ln_left, ln_right); - } - ln_right -= m_pos.x; - - if(ln_left < 0) - { - ln_left = 0; - } else if (ln_left > 0) - { - ln_left -= m_pos.x; - if (ln_left < 0) - { - ln_left = 0; - } - } - } -} - -void litehtml::render_item_block::clear_floats(int context) -{ - if(src_el()->is_floats_holder()) - { - auto iter = m_floats_left.begin(); - while(iter != m_floats_left.end()) - { - if(iter->context >= context) - { - iter = m_floats_left.erase(iter); - m_cache_line_left.invalidate(); - } else - { - iter++; - } - } - - iter = m_floats_right.begin(); - while(iter != m_floats_right.end()) - { - if(iter->context >= context) - { - iter = m_floats_right.erase(iter); - m_cache_line_right.invalidate(); - } else - { - iter++; - } - } - } else - { - auto el_parent = parent(); - if (el_parent) - { - el_parent->clear_floats(context); - } - } -} - -void litehtml::render_item_block::add_float(const std::shared_ptr<render_item> &el, int x, int y, int context) -{ - if(src_el()->is_floats_holder()) - { - floated_box fb; - fb.pos.x = el->left() + x; - fb.pos.y = el->top() + y; - fb.pos.width = el->width(); - fb.pos.height = el->height(); - fb.float_side = el->src_el()->css().get_float(); - fb.clear_floats = el->src_el()->css().get_clear(); - fb.el = el; - fb.context = context; - - if(fb.float_side == float_left) - { - if(m_floats_left.empty()) - { - m_floats_left.push_back(fb); - } else - { - bool inserted = false; - for(auto i = m_floats_left.begin(); i != m_floats_left.end(); i++) - { - if(fb.pos.right() > i->pos.right()) - { - m_floats_left.insert(i, std::move(fb)); - inserted = true; - break; - } - } - if(!inserted) - { - m_floats_left.push_back(std::move(fb)); - } - } - m_cache_line_left.invalidate(); - } else if(fb.float_side == float_right) - { - if(m_floats_right.empty()) - { - m_floats_right.push_back(std::move(fb)); - } else - { - bool inserted = false; - for(auto i = m_floats_right.begin(); i != m_floats_right.end(); i++) - { - if(fb.pos.left() < i->pos.left()) - { - m_floats_right.insert(i, std::move(fb)); - inserted = true; - break; - } - } - if(!inserted) - { - m_floats_right.push_back(fb); - } - } - m_cache_line_right.invalidate(); - } - } else - { - auto el_parent = parent(); - if (el_parent) - { - el_parent->add_float(el, x + m_pos.x, y + m_pos.y, context); - } - } -} - -int litehtml::render_item_block::get_cleared_top(const std::shared_ptr<render_item> &el, int line_top) const -{ - switch(el->src_el()->css().get_clear()) - { - case clear_left: - { - int fh = get_left_floats_height(); - if(fh && fh > line_top) - { - line_top = fh; - } - } - break; - case clear_right: - { - int fh = get_right_floats_height(); - if(fh && fh > line_top) - { - line_top = fh; - } - } - break; - case clear_both: - { - int fh = get_floats_height(float_none); - if(fh && fh > line_top) - { - line_top = fh; - } - } - break; - default: - if(el->src_el()->css().get_float() != float_none) - { - int fh = get_floats_height(el->src_el()->css().get_float()); - if(fh && fh > line_top) - { - line_top = fh; - } - } - break; - } - return line_top; -} - -int litehtml::render_item_block::find_next_line_top( int top, int width, int def_right ) -{ - if(src_el()->is_floats_holder()) - { - int new_top = top; - int_vector points; - - for(const auto& fb : m_floats_left) - { - if(fb.pos.top() >= top) - { - if(find(points.begin(), points.end(), fb.pos.top()) == points.end()) - { - points.push_back(fb.pos.top()); - } - } - if (fb.pos.bottom() >= top) - { - if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end()) - { - points.push_back(fb.pos.bottom()); - } - } - } - - for (const auto& fb : m_floats_right) - { - if (fb.pos.top() >= top) - { - if (find(points.begin(), points.end(), fb.pos.top()) == points.end()) - { - points.push_back(fb.pos.top()); - } - } - if (fb.pos.bottom() >= top) - { - if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end()) - { - points.push_back(fb.pos.bottom()); - } - } - } - - if(!points.empty()) - { - sort(points.begin(), points.end(), std::less<int>( )); - new_top = points.back(); - - for(auto pt : points) - { - int pos_left = 0; - int pos_right = def_right; - get_line_left_right(pt, def_right, pos_left, pos_right); - - if(pos_right - pos_left >= width) - { - new_top = pt; - break; - } - } - } - return new_top; - } - auto el_parent = parent(); - if (el_parent) - { - int new_top = el_parent->find_next_line_top(top + m_pos.y, width, def_right + m_pos.x); - return new_top - m_pos.y; - } - return 0; -} - -void litehtml::render_item_block::update_floats(int dy, const std::shared_ptr<render_item> &_parent) -{ - if(src_el()->is_floats_holder()) - { - bool reset_cache = false; - for(auto fb = m_floats_left.rbegin(); fb != m_floats_left.rend(); fb++) - { - if(fb->el->src_el()->is_ancestor(_parent->src_el())) - { - reset_cache = true; - fb->pos.y += dy; - } - } - if(reset_cache) - { - m_cache_line_left.invalidate(); - } - reset_cache = false; - for(auto fb = m_floats_right.rbegin(); fb != m_floats_right.rend(); fb++) - { - if(fb->el->src_el()->is_ancestor(_parent->src_el())) - { - reset_cache = true; - fb->pos.y += dy; - } - } - if(reset_cache) - { - m_cache_line_right.invalidate(); - } - } else - { - auto el_parent = parent(); - if (el_parent) - { - el_parent->update_floats(dy, _parent); - } - } -} - std::shared_ptr<litehtml::render_item> litehtml::render_item_block::init() { { @@ -571,9 +69,8 @@ std::shared_ptr<litehtml::render_item> litehtml::render_item_block::init() if (auto p = src_el()->parent()) { int val = atoi(p->get_attr("start", "1")); - for (int i = 0; i < (int)p->get_children_count(); i++) + for(const auto &child : p->children()) { - auto child = p->get_child(i); if (child == src_el()) { src_el()->set_attr("list_index", std::to_string(val).c_str()); @@ -618,7 +115,7 @@ std::shared_ptr<litehtml::render_item> litehtml::render_item_block::init() if (el->src_el()->is_block_box()) { has_block_level = true; - } else if (el->src_el()->is_inline_box()) + } else if (el->src_el()->is_inline()) { has_inlines = true; } @@ -637,7 +134,7 @@ std::shared_ptr<litehtml::render_item> litehtml::render_item_block::init() bool not_ws_added = false; for (const auto& el : m_children) { - if(el->src_el()->is_inline_box()) + if(el->src_el()->is_inline()) { inlines.push_back(el); if(!el->src_el()->is_white_space()) @@ -698,28 +195,14 @@ std::shared_ptr<litehtml::render_item> litehtml::render_item_block::init() return ret; } -int litehtml::render_item_block::render(int x, int y, const containing_block_context &containing_block_size, bool second_pass) +int litehtml::render_item_block::_render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) { - int ret_width = 0; - calc_outlines(containing_block_size.width); - - m_pos.clear(); - m_pos.move_to(x, y); - - m_pos.x += content_offset_left(); - m_pos.y += content_offset_top(); - - m_floats_left.clear(); - m_floats_right.clear(); - m_cache_line_left.invalidate(); - m_cache_line_right.invalidate(); - containing_block_context self_size = calculate_containing_block_context(containing_block_size); //***************************************** // Render content //***************************************** - ret_width = _render_content(x, y, second_pass, ret_width, self_size); + int ret_width = _render_content(x, y, second_pass, self_size, fmt_ctx); //***************************************** bool requires_rerender = false; // when true, the second pass for content rendering is required @@ -733,22 +216,7 @@ int litehtml::render_item_block::render(int x, int y, const containing_block_con m_pos.width = self_size.render_width; } else { - if(src_el()->is_inline_box() || - src_el()->css().get_float() != float_none || - src_el()->css().get_display() == display_table_cell || - src_el()->css().get_display() == display_table_caption || - src_el()->css().get_position() > element_position_relative) - { - m_pos.width = ret_width; - if(ret_width < self_size.render_width && !second_pass) - { - // We have to render content again with new max_width - requires_rerender = true; - } - } else - { - m_pos.width = self_size.render_width; - } + m_pos.width = self_size.render_width; } // Fix width with min-width attribute @@ -774,32 +242,32 @@ int litehtml::render_item_block::render(int x, int y, const containing_block_con // re-render content with new width if required if (requires_rerender && !second_pass && !is_root()) { - if(src_el()->is_floats_holder()) + if(src_el()->is_block_formatting_context()) { - m_floats_left.clear(); - m_floats_right.clear(); + fmt_ctx->clear_floats(-1); } else { - clear_floats(self_size.context_idx); + fmt_ctx->clear_floats(self_size.context_idx); } - m_cache_line_left.invalidate(); - m_cache_line_right.invalidate(); - _render_content(x, y, true, ret_width, self_size.new_width(m_pos.width)); + _render_content(x, y, true, self_size.new_width(m_pos.width), fmt_ctx); } // Set block height if (self_size.height.type != containing_block_context::cbc_value_type_auto) { - m_pos.height = self_size.height; + if(self_size.height > 0) + { + m_pos.height = self_size.height; + } if(src_el()->css().get_box_sizing() == box_sizing_border_box) { m_pos.height -= box_sizing_height(); } - } else if (src_el()->is_floats_holder()) + } else if (src_el()->is_block_formatting_context()) { // add the floats' height to the block height - int floats_height = get_floats_height(); + int floats_height = fmt_ctx->get_floats_height(); if (floats_height > m_pos.height) { m_pos.height = floats_height; @@ -845,12 +313,5 @@ int litehtml::render_item_block::render(int x, int y, const containing_block_con } - if (src_el()->is_floats_holder() && !second_pass) - { - for (const auto& fb : m_floats_left) - { - fb.el->apply_relative_shift(containing_block_size); - } - } return ret_width + content_offset_width(); } diff --git a/src/plugins/litehtml_viewer/litehtml/render_block.h b/src/plugins/litehtml_viewer/litehtml/render_block.h @@ -0,0 +1,40 @@ +#ifndef LITEHTML_RENDER_BLOCK_H +#define LITEHTML_RENDER_BLOCK_H + +#include "render_item.h" + +namespace litehtml +{ + class render_item_block : public render_item + { + protected: + /** + * Render block content. + * + * @param x - horizontal position of the content + * @param y - vertical position of the content + * @param second_pass - true is this is the second pass. + * @param ret_width - input minimal width. + * @param self_size - defines calculated size of block + * @return return value is the minimal width of the content in block. Must be greater or equal to ret_width parameter + */ + virtual int _render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) {return 0;} + int _render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) override; + int place_float(const std::shared_ptr<render_item> &el, int top, const containing_block_context &self_size, formatting_context* fmt_ctx); + virtual void fix_line_width(element_float flt, + const containing_block_context &containing_block_size, formatting_context* fmt_ctx) + {} + + public: + explicit render_item_block(std::shared_ptr<element> src_el) : render_item(std::move(src_el)) + {} + + std::shared_ptr<render_item> clone() override + { + return std::make_shared<render_item_block>(src_el()); + } + std::shared_ptr<render_item> init() override; + }; +} + +#endif //LITEHTML_RENDER_BLOCK_H diff --git a/src/plugins/litehtml_viewer/litehtml/render_block_context.cpp b/src/plugins/litehtml_viewer/litehtml/render_block_context.cpp @@ -1,12 +1,12 @@ #include "html.h" -#include "render_item.h" +#include "render_block_context.h" #include "document.h" -int litehtml::render_item_block_context::_render_content(int x, int y, bool second_pass, int ret_width, - const containing_block_context &self_size) +int litehtml::render_item_block_context::_render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) { element_position el_position; + int ret_width = 0; int child_top = 0; int last_margin = 0; std::shared_ptr<render_item> last_margin_el; @@ -22,7 +22,7 @@ int litehtml::render_item_block_context::_render_content(int x, int y, bool seco if(el->src_el()->css().get_float() != float_none) { - int rw = place_float(el, child_top, self_size); + int rw = place_float(el, child_top, self_size, fmt_ctx); if (rw > ret_width) { ret_width = rw; @@ -31,10 +31,14 @@ int litehtml::render_item_block_context::_render_content(int x, int y, bool seco { if(el->src_el()->css().get_position() == element_position_absolute || el->src_el()->css().get_position() == element_position_fixed) { - el->render(0, child_top, self_size); + int min_rendered_width = el->render(0, child_top, self_size, fmt_ctx); + if(min_rendered_width < el->width() && el->src_el()->css().get_width().is_predefined()) + { + el->render(0, child_top, self_size.new_width(min_rendered_width), fmt_ctx); + } } else { - child_top = get_cleared_top(el, child_top); + child_top = fmt_ctx->get_cleared_top(el, child_top); int child_x = 0; int child_width = self_size.render_width; @@ -59,11 +63,11 @@ int litehtml::render_item_block_context::_render_content(int x, int y, bool seco } } - if(el->src_el()->is_replaced() || el->src_el()->is_floats_holder() || el->src_el()->css().get_display() == display_table) + if(el->src_el()->is_replaced() || el->src_el()->is_block_formatting_context() || el->src_el()->css().get_display() == display_table) { int ln_left = 0; int ln_right = child_width; - get_line_left_right(child_top, child_width, ln_left, ln_right); + fmt_ctx->get_line_left_right(child_top, child_width, ln_left, ln_right); child_x = ln_left; child_width = ln_right - ln_left; @@ -72,11 +76,11 @@ int litehtml::render_item_block_context::_render_content(int x, int y, bool seco el->pos().height = el->src_el()->css().get_height().calc_percent(el_parent ? el_parent->pos().height : 0); } - int rw = el->render(child_x, child_top, self_size.new_width(child_width)); + int rw = el->render(child_x, child_top, self_size.new_width(child_width), fmt_ctx); // Render table with "width: auto" into returned width if(el->src_el()->css().get_display() == display_table && rw < child_width && el->src_el()->css().get_width().is_predefined()) { - el->render(child_x, child_top, self_size.new_width(rw)); + el->render(child_x, child_top, self_size.new_width(rw), fmt_ctx); } int auto_margin = el->calc_auto_margins(child_width); if(auto_margin) diff --git a/src/plugins/litehtml_viewer/litehtml/render_block_context.h b/src/plugins/litehtml_viewer/litehtml/render_block_context.h @@ -0,0 +1,29 @@ +#ifndef LITEHTML_RENDER_BLOCK_CONTEXT_H +#define LITEHTML_RENDER_BLOCK_CONTEXT_H + +#include "render_block.h" + +namespace litehtml +{ + /** + * In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a + * containing block. + * https://www.w3.org/TR/CSS22/visuren.html#block-formatting + */ + class render_item_block_context : public render_item_block + { + protected: + int _render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) override; + + public: + explicit render_item_block_context(std::shared_ptr<element> src_el) : render_item_block(std::move(src_el)) + {} + + std::shared_ptr<render_item> clone() override + { + return std::make_shared<render_item_block_context>(src_el()); + } + }; +} + +#endif //LITEHTML_RENDER_BLOCK_CONTEXT_H diff --git a/src/plugins/litehtml_viewer/litehtml/render_flex.cpp b/src/plugins/litehtml_viewer/litehtml/render_flex.cpp @@ -1,9 +1,8 @@ #include "html.h" -#include "render_item.h" #include "types.h" +#include "render_flex.h" -int litehtml::render_item_flex::_render_content(int x, int y, bool second_pass, int ret_width, - const containing_block_context &self_size) +int litehtml::render_item_flex::_render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) { return 0; } diff --git a/src/plugins/litehtml_viewer/litehtml/render_flex.h b/src/plugins/litehtml_viewer/litehtml/render_flex.h @@ -0,0 +1,46 @@ +#ifndef LITEHTML_RENDER_FLEX_H +#define LITEHTML_RENDER_FLEX_H + +#include "render_block.h" + +namespace litehtml +{ + class render_item_flex : public render_item_block + { + struct flex_item + { + std::shared_ptr<render_item> el; + int base_size; + int main_size; + int min_width; + int max_width; + int line; + + explicit flex_item(std::shared_ptr<render_item> _el) : + el(std::move(_el)), + min_width(0), + max_width(0), + line(0), + base_size(0), + main_size(0) + {} + }; + protected: + std::list<std::unique_ptr<flex_item>> m_flex_items; + + int _render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) override; + + public: + explicit render_item_flex(std::shared_ptr<element> src_el) : render_item_block(std::move(src_el)) + {} + + std::shared_ptr<render_item> clone() override + { + return std::make_shared<render_item_flex>(src_el()); + } + void draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override; + std::shared_ptr<render_item> init() override; + }; +} + +#endif //LITEHTML_RENDER_FLEX_H diff --git a/src/plugins/litehtml_viewer/litehtml/render_image.cpp b/src/plugins/litehtml_viewer/litehtml/render_image.cpp @@ -1,9 +1,8 @@ #include "html.h" -#include "render_item.h" +#include "render_image.h" #include "document.h" -int -litehtml::render_item_image::render(int x, int y, const containing_block_context &containing_block_size, bool second_pass) +int litehtml::render_item_image::_render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) { int parent_width = containing_block_size.width; diff --git a/src/plugins/litehtml_viewer/litehtml/render_image.h b/src/plugins/litehtml_viewer/litehtml/render_image.h @@ -0,0 +1,25 @@ +#ifndef LITEHTML_RENDER_IMAGE_H +#define LITEHTML_RENDER_IMAGE_H + +#include "render_item.h" + +namespace litehtml +{ + class render_item_image : public render_item + { + protected: + int calc_max_height(int image_height, int containing_block_height); + int _render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) override; + + public: + explicit render_item_image(std::shared_ptr<element> src_el) : render_item(std::move(src_el)) + {} + + std::shared_ptr<render_item> clone() override + { + return std::make_shared<render_item_image>(src_el()); + } + }; +} + +#endif //LITEHTML_RENDER_IMAGE_H diff --git a/src/plugins/litehtml_viewer/litehtml/render_inline.h b/src/plugins/litehtml_viewer/litehtml/render_inline.h @@ -0,0 +1,30 @@ +#ifndef LITEHTML_RENDER_INLINE_H +#define LITEHTML_RENDER_INLINE_H + +#include "render_item.h" + +namespace litehtml +{ + class render_item_inline : public render_item + { + protected: + position::vector m_boxes; + + public: + explicit render_item_inline(std::shared_ptr<element> src_el) : render_item(std::move(src_el)) + {} + + void get_inline_boxes( position::vector& boxes ) const override { boxes = m_boxes; } + void set_inline_boxes( position::vector& boxes ) override { m_boxes = boxes; } + void add_inline_box( const position& box ) override { m_boxes.emplace_back(box); }; + void clear_inline_boxes() override { m_boxes.clear(); } + int get_base_line() override { return src_el()->css().get_font_metrics().base_line(); } + + std::shared_ptr<render_item> clone() override + { + return std::make_shared<render_item_inline>(src_el()); + } + }; +} + +#endif //LITEHTML_RENDER_INLINE_H diff --git a/src/plugins/litehtml_viewer/litehtml/render_inline_context.cpp b/src/plugins/litehtml_viewer/litehtml/render_inline_context.cpp @@ -1,10 +1,9 @@ #include "html.h" -#include "render_item.h" +#include "render_inline_context.h" #include "document.h" #include "iterators.h" -int litehtml::render_item_inline_context::_render_content(int x, int y, bool second_pass, int ret_width, - const containing_block_context &self_size) +int litehtml::render_item_inline_context::_render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) { m_line_boxes.clear(); m_max_line_width = 0; @@ -50,20 +49,20 @@ int litehtml::render_item_inline_context::_render_content(int x, int y, bool sec } } // place element into rendering flow - place_inline(std::unique_ptr<line_box_item>(new line_box_item(el)), self_size); + place_inline(std::unique_ptr<line_box_item>(new line_box_item(el)), self_size, fmt_ctx); } break; case iterator_item_type_start_parent: { el->clear_inline_boxes(); - place_inline(std::unique_ptr<lbi_start>(new lbi_start(el)), self_size); + place_inline(std::unique_ptr<lbi_start>(new lbi_start(el)), self_size, fmt_ctx); } break; case iterator_item_type_end_parent: { - place_inline(std::unique_ptr<lbi_end>(new lbi_end(el)), self_size); + place_inline(std::unique_ptr<lbi_end>(new lbi_end(el)), self_size, fmt_ctx); } break; } @@ -79,7 +78,7 @@ int litehtml::render_item_inline_context::_render_content(int x, int y, bool sec m_margins.top = std::max(m_line_boxes.front()->top_margin(), m_margins.top); if (m_margins.top != old_top) { - update_floats(m_margins.top - old_top, shared_from_this()); + fmt_ctx->update_floats(m_margins.top - old_top, shared_from_this()); } } if (collapse_bottom_margin()) @@ -93,13 +92,13 @@ int litehtml::render_item_inline_context::_render_content(int x, int y, bool sec } } - return std::max(ret_width, m_max_line_width); + return m_max_line_width; } void litehtml::render_item_inline_context::fix_line_width(element_float flt, - const containing_block_context &self_size) + const containing_block_context &self_size, + formatting_context* fmt_ctx) { - int ret_width = 0; if(!m_line_boxes.empty()) { auto el_front = m_line_boxes.back()->get_first_text_part(); @@ -128,7 +127,7 @@ void litehtml::render_item_inline_context::fix_line_width(element_float flt, for(auto& item : items) { - place_inline(std::move(item), self_size); + place_inline(std::move(item), self_size, fmt_ctx); } } else { @@ -137,7 +136,7 @@ void litehtml::render_item_inline_context::fix_line_width(element_float flt, int line_left = 0; int line_right = self_size.render_width; - get_line_left_right(line_top, self_size.render_width, line_left, line_right); + fmt_ctx->get_line_left_right(line_top, self_size.render_width, line_left, line_right); if(m_line_boxes.size() == 1) { @@ -157,7 +156,7 @@ void litehtml::render_item_inline_context::fix_line_width(element_float flt, auto items = m_line_boxes.back()->new_width(line_left, line_right); for(auto& item : items) { - place_inline(std::move(item), self_size); + place_inline(std::move(item), self_size, fmt_ctx); } } } @@ -183,7 +182,7 @@ std::list<std::unique_ptr<litehtml::line_box_item> > litehtml::render_item_inlin return ret; } -int litehtml::render_item_inline_context::new_box(const std::unique_ptr<line_box_item>& el, line_context& line_ctx, const containing_block_context &self_size) +int litehtml::render_item_inline_context::new_box(const std::unique_ptr<line_box_item>& el, line_context& line_ctx, const containing_block_context &self_size, formatting_context* fmt_ctx) { auto items = finish_last_box(false, self_size); int line_top = 0; @@ -191,22 +190,22 @@ int litehtml::render_item_inline_context::new_box(const std::unique_ptr<line_box { line_top = m_line_boxes.back()->bottom(); } - line_ctx.top = get_cleared_top(el->get_el(), line_top); + line_ctx.top = fmt_ctx->get_cleared_top(el->get_el(), line_top); line_ctx.left = 0; line_ctx.right = self_size.render_width; line_ctx.fix_top(); - get_line_left_right(line_ctx.top, self_size.render_width, line_ctx.left, line_ctx.right); + fmt_ctx->get_line_left_right(line_ctx.top, self_size.render_width, line_ctx.left, line_ctx.right); - if(el->get_el()->src_el()->is_inline_box() || el->get_el()->src_el()->is_floats_holder()) + if(el->get_el()->src_el()->is_inline() || el->get_el()->src_el()->is_block_formatting_context()) { if (el->get_el()->width() > line_ctx.right - line_ctx.left) { - line_ctx.top = find_next_line_top(line_ctx.top, el->get_el()->width(), self_size.render_width); + line_ctx.top = fmt_ctx->find_next_line_top(line_ctx.top, el->get_el()->width(), self_size.render_width); line_ctx.left = 0; line_ctx.right = self_size.render_width; line_ctx.fix_top(); - get_line_left_right(line_ctx.top, self_size.render_width, line_ctx.left, line_ctx.right); + fmt_ctx->get_line_left_right(line_ctx.top, self_size.render_width, line_ctx.left, line_ctx.right); } } @@ -241,7 +240,7 @@ int litehtml::render_item_inline_context::new_box(const std::unique_ptr<line_box return line_ctx.top; } -void litehtml::render_item_inline_context::place_inline(std::unique_ptr<line_box_item> item, const containing_block_context &self_size) +void litehtml::render_item_inline_context::place_inline(std::unique_ptr<line_box_item> item, const containing_block_context &self_size, formatting_context* fmt_ctx) { if(item->get_el()->src_el()->css().get_display() == display_none) return; @@ -252,7 +251,7 @@ void litehtml::render_item_inline_context::place_inline(std::unique_ptr<line_box { line_top = m_line_boxes.back()->top(); } - int ret = place_float(item->get_el(), line_top, self_size); + int ret = place_float(item->get_el(), line_top, self_size, fmt_ctx); if(ret > m_max_line_width) { m_max_line_width = ret; @@ -269,24 +268,24 @@ void litehtml::render_item_inline_context::place_inline(std::unique_ptr<line_box line_ctx.left = 0; line_ctx.right = self_size.render_width; line_ctx.fix_top(); - get_line_left_right(line_ctx.top, self_size.render_width, line_ctx.left, line_ctx.right); + fmt_ctx->get_line_left_right(line_ctx.top, self_size.render_width, line_ctx.left, line_ctx.right); if(item->get_type() == line_box_item::type_text_part) { - switch (item->get_el()->src_el()->css().get_display()) + if(item->get_el()->src_el()->is_inline_box()) { - case display_inline_block: - case display_inline_table: - item->set_rendered_min_width(item->get_el()->render(line_ctx.left, line_ctx.top, self_size.new_width(line_ctx.right))); - break; - case display_inline_text: + int min_rendered_width = item->get_el()->render(line_ctx.left, line_ctx.top, self_size.new_width(line_ctx.right), fmt_ctx); + if(min_rendered_width < item->get_el()->width() && item->get_el()->src_el()->css().get_width().is_predefined()) { - litehtml::size sz; - item->get_el()->src_el()->get_content_size(sz, line_ctx.right); - item->get_el()->pos() = sz; - item->set_rendered_min_width(sz.width); + item->get_el()->render(line_ctx.left, line_ctx.top, self_size.new_width(min_rendered_width), fmt_ctx); } - break; + item->set_rendered_min_width(min_rendered_width); + } else if(item->get_el()->src_el()->css().get_display() == display_inline_text) + { + litehtml::size sz; + item->get_el()->src_el()->get_content_size(sz, line_ctx.right); + item->get_el()->pos() = sz; + item->set_rendered_min_width(sz.width); } } @@ -300,7 +299,7 @@ void litehtml::render_item_inline_context::place_inline(std::unique_ptr<line_box } if(add_box) { - new_box(item, line_ctx, self_size); + new_box(item, line_ctx, self_size, fmt_ctx); } else if(!m_line_boxes.empty()) { line_ctx.top = m_line_boxes.back()->top(); @@ -311,10 +310,10 @@ void litehtml::render_item_inline_context::place_inline(std::unique_ptr<line_box line_ctx.left = 0; line_ctx.right = self_size.render_width; line_ctx.fix_top(); - get_line_left_right(line_ctx.top, self_size.render_width, line_ctx.left, line_ctx.right); + fmt_ctx->get_line_left_right(line_ctx.top, self_size.render_width, line_ctx.left, line_ctx.right); } - if(!item->get_el()->src_el()->is_inline_box()) + if(!item->get_el()->src_el()->is_inline()) { if(m_line_boxes.size() == 1) { diff --git a/src/plugins/litehtml_viewer/litehtml/render_inline_context.h b/src/plugins/litehtml_viewer/litehtml/render_inline_context.h @@ -0,0 +1,55 @@ +#ifndef LITEHTML_RENDER_INLINE_CONTEXT_H +#define LITEHTML_RENDER_INLINE_CONTEXT_H + +#include "render_block.h" + +namespace litehtml +{ + /** + * An inline formatting context is established by a block container box that contains no block-level boxes. + * https://www.w3.org/TR/CSS22/visuren.html#inline-formatting + */ + class render_item_inline_context : public render_item_block + { + /** + * Structure contains elements with display: inline + * members: + * - element: render_item with display: inline + * - boxes: rectangles represented inline element content. There are can be many boxes if content + * is split into some lines + * - start_box: the start position of currently calculated box + */ + struct inlines_item + { + std::shared_ptr<render_item> element; + position::vector boxes; + position start_box; + + explicit inlines_item(const std::shared_ptr<render_item>& el) : element(el) {} + }; + protected: + std::vector<std::unique_ptr<litehtml::line_box> > m_line_boxes; + int m_max_line_width; + + int _render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) override; + void fix_line_width(element_float flt, + const containing_block_context &self_size, formatting_context* fmt_ctx) override; + + std::list<std::unique_ptr<line_box_item> > finish_last_box(bool end_of_render, const containing_block_context &self_size); + void place_inline(std::unique_ptr<line_box_item> item, const containing_block_context &self_size, formatting_context* fmt_ctx); + int new_box(const std::unique_ptr<line_box_item>& el, line_context& line_ctx, const containing_block_context &self_size, formatting_context* fmt_ctx); + void apply_vertical_align() override; + public: + explicit render_item_inline_context(std::shared_ptr<element> src_el) : render_item_block(std::move(src_el)), m_max_line_width(0) + {} + + std::shared_ptr<render_item> clone() override + { + return std::make_shared<render_item_inline_context>(src_el()); + } + + int get_base_line() override; + }; +} + +#endif //LITEHTML_RENDER_INLINE_CONTEXT_H diff --git a/src/plugins/litehtml_viewer/litehtml/render_item.cpp b/src/plugins/litehtml_viewer/litehtml/render_item.cpp @@ -27,6 +27,36 @@ litehtml::render_item::render_item(std::shared_ptr<element> _src_el) : m_borders.bottom = doc->to_pixels(src_el()->css().get_borders().bottom.width, fnt_size); } +int litehtml::render_item::render(int x, int y, const containing_block_context& containing_block_size, formatting_context* fmt_ctx, bool second_pass) +{ + int ret; + + calc_outlines(containing_block_size.width); + + m_pos.clear(); + m_pos.move_to(x, y); + + int content_left = content_offset_left(); + int content_top = content_offset_top(); + + m_pos.x += content_left; + m_pos.y += content_top; + + + if(src_el()->is_block_formatting_context() || ! fmt_ctx) + { + formatting_context fmt; + fmt.push_position(content_left, content_top); + ret = _render(x, y, containing_block_size, &fmt, second_pass); + fmt.apply_relative_shift(containing_block_size); + } else + { + fmt_ctx->push_position(x + content_left, y + content_top); + ret = _render(x, y, containing_block_size, fmt_ctx, second_pass); + fmt_ctx->pop_position(x + content_left, y + content_top); + } + return ret; +} void litehtml::render_item::calc_outlines( int parent_width ) { @@ -119,10 +149,10 @@ bool litehtml::render_item::get_predefined_height(int& p_height, int containing_ if(h.units() == css_units_percentage) { p_height = h.calc_percent(containing_block_height); - return containing_block_height != 0; + return containing_block_height > 0; } p_height = src_el()->get_document()->to_pixels(h, src_el()->css().get_font_size()); - return true; + return p_height > 0; } int litehtml::render_item::calc_width(int defVal, int containing_block_width) const @@ -438,7 +468,7 @@ void litehtml::render_item::render_positioned(render_type rt) if(need_render) { position pos = el->m_pos; - el->render(el->left(), el->top(), containing_block_size.new_width(el->width()), true); + el->render(el->left(), el->top(), containing_block_size.new_width(el->width()), nullptr, true); el->m_pos = pos; } @@ -632,7 +662,7 @@ void litehtml::render_item::draw_children(uint_ptr hdc, int x, int y, const posi } break; case draw_block: - if (!el->src_el()->is_inline_box() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned()) + if (!el->src_el()->is_inline() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned()) { el->src_el()->draw(hdc, pos.x, pos.y, clip, el); } @@ -646,7 +676,7 @@ void litehtml::render_item::draw_children(uint_ptr hdc, int x, int y, const posi } break; case draw_inlines: - if (el->src_el()->is_inline_box() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned()) + if (el->src_el()->is_inline() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned()) { el->src_el()->draw(hdc, pos.x, pos.y, clip, el); if (el->src_el()->css().get_display() == display_inline_block) @@ -734,7 +764,7 @@ std::shared_ptr<litehtml::element> litehtml::render_item::get_child_by_point(in } break; case draw_block: - if(!el->src_el()->is_inline_box() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned()) + if(!el->src_el()->is_inline() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned()) { if(el->is_point_inside(el_pos.x, el_pos.y)) { @@ -755,7 +785,7 @@ std::shared_ptr<litehtml::element> litehtml::render_item::get_child_by_point(in } break; case draw_inlines: - if(el->src_el()->is_inline_box() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned()) + if(el->src_el()->is_inline() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned()) { if(el->src_el()->css().get_display() == display_inline_block || el->src_el()->css().get_display() == display_inline_table || @@ -1056,21 +1086,3 @@ litehtml::containing_block_context litehtml::render_item::calculate_containing_b } return ret; } - -void litehtml::render_item_table_row::get_inline_boxes( position::vector& boxes ) const -{ - position pos; - for(auto& el : m_children) - { - if(el->src_el()->css().get_display() == display_table_cell) - { - pos.x = el->left() + el->margin_left(); - pos.y = el->top() - m_padding.top - m_borders.top; - - pos.width = el->right() - pos.x - el->margin_right() - el->margin_left(); - pos.height = el->height() + m_padding.top + m_padding.bottom + m_borders.top + m_borders.bottom; - - boxes.push_back(pos); - } - } -} diff --git a/src/plugins/litehtml_viewer/litehtml/render_item.h b/src/plugins/litehtml_viewer/litehtml/render_item.h @@ -8,6 +8,7 @@ #include "types.h" #include "line_box.h" #include "table.h" +#include "formatting_context.h" namespace litehtml { @@ -28,6 +29,10 @@ namespace litehtml containing_block_context calculate_containing_block_context(const containing_block_context& cb_context); void calc_cb_length(const css_length& len, int percent_base, containing_block_context::typed_int& out_value) const; + virtual int _render(int x, int y, const containing_block_context& containing_block_size, formatting_context* fmt_ctx, bool second_pass = false) + { + return 0; + } public: explicit render_item(std::shared_ptr<element> src_el); @@ -268,11 +273,6 @@ namespace litehtml ri->parent(shared_from_this()); } - virtual int render(int x, int y, const containing_block_context& containing_block_size, bool second_pass = false) - { - return 0; - } - bool is_root() const { return m_parent.expired(); @@ -303,6 +303,7 @@ namespace litehtml return !(m_skip || src_el()->css().get_display() == display_none || src_el()->css().get_visibility() != visibility_visible); } + int render(int x, int y, const containing_block_context& containing_block_size, formatting_context* fmt_ctx, bool second_pass = false); int calc_width(int defVal, int containing_block_width) const; bool get_predefined_height(int& p_height, int containing_block_height) const; void apply_relative_shift(const containing_block_context &containing_block_size); @@ -345,255 +346,7 @@ namespace litehtml * @return */ void get_rendering_boxes( position::vector& redraw_boxes); - - virtual void get_line_left_right( int y, int def_right, int& ln_left, int& ln_right ) {} - virtual int get_line_left( int y ) { return 0; } - virtual int get_line_right( int y, int def_right ) { return 0; } - virtual int get_left_floats_height() const { return 0; } - virtual int get_right_floats_height() const { return 0; } - virtual int get_floats_height(element_float el_float = float_none) const { return 0; } - virtual int find_next_line_top( int top, int width, int def_right ) { return 0; } - virtual void add_float(const std::shared_ptr<render_item> &el, int x, int y, int context) {} - virtual void clear_floats(int context) {} - virtual void update_floats(int dy, const std::shared_ptr<render_item> &_parent) {} }; - - class render_item_block : public render_item - { - protected: - std::list<floated_box> m_floats_left; - std::list<floated_box> m_floats_right; - int_int_cache m_cache_line_left; - int_int_cache m_cache_line_right; - - /** - * Render block content. - * - * @param x - horizontal position of the content - * @param y - vertical position of the content - * @param second_pass - true is this is the second pass. - * @param ret_width - input minimal width. - * @param self_size - defines calculated size of block - * @return return value is the minimal width of the content in block. Must be greater or equal to ret_width parameter - */ - virtual int _render_content(int x, int y, bool second_pass, int ret_width, const containing_block_context &self_size) {return ret_width;} - int render(int x, int y, const containing_block_context &containing_block_size, bool second_pass) override; - - int place_float(const std::shared_ptr<render_item> &el, int top, const containing_block_context &self_size); - int get_floats_height(element_float el_float = float_none) const override; - int get_left_floats_height() const override; - int get_right_floats_height() const override; - int get_line_left( int y ) override; - int get_line_right( int y, int def_right ) override; - void get_line_left_right( int y, int def_right, int& ln_left, int& ln_right ) override; - void add_float(const std::shared_ptr<render_item> &el, int x, int y, int context) override; - void clear_floats(int context) override; - int get_cleared_top(const std::shared_ptr<render_item> &el, int line_top) const; - int find_next_line_top( int top, int width, int def_right ) override; - virtual void fix_line_width(element_float flt, - const containing_block_context &containing_block_size) - {} - void update_floats(int dy, const std::shared_ptr<render_item> &_parent) override; - public: - explicit render_item_block(std::shared_ptr<element> src_el) : render_item(std::move(src_el)) - {} - - std::shared_ptr<render_item> clone() override - { - return std::make_shared<render_item_block>(src_el()); - } - std::shared_ptr<render_item> init() override; - }; - - /** - * In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a - * containing block. - * https://www.w3.org/TR/CSS22/visuren.html#block-formatting - */ - class render_item_block_context : public render_item_block - { - protected: - int _render_content(int x, int y, bool second_pass, int ret_width, - const containing_block_context &self_size) override; - - public: - explicit render_item_block_context(std::shared_ptr<element> src_el) : render_item_block(std::move(src_el)) - {} - - std::shared_ptr<render_item> clone() override - { - return std::make_shared<render_item_block_context>(src_el()); - } - }; - - /** - * An inline formatting context is established by a block container box that contains no block-level boxes. - * https://www.w3.org/TR/CSS22/visuren.html#inline-formatting - */ - class render_item_inline_context : public render_item_block - { - /** - * Structure contains elements with display: inline - * members: - * - element: render_item with display: inline - * - boxes: rectangles represented inline element content. There are can be many boxes if content - * is split into some lines - * - start_box: the start position of currently calculated box - */ - struct inlines_item - { - std::shared_ptr<render_item> element; - position::vector boxes; - position start_box; - - explicit inlines_item(const std::shared_ptr<render_item>& el) : element(el) {} - }; - protected: - std::vector<std::unique_ptr<litehtml::line_box> > m_line_boxes; - int m_max_line_width; - - int _render_content(int x, int y, bool second_pass, int ret_width, - const containing_block_context &self_size) override; - void fix_line_width(element_float flt, - const containing_block_context &self_size) override; - - std::list<std::unique_ptr<line_box_item> > finish_last_box(bool end_of_render, const containing_block_context &self_size); - void place_inline(std::unique_ptr<line_box_item> item, const containing_block_context &self_size); - int new_box(const std::unique_ptr<line_box_item>& el, line_context& line_ctx, const containing_block_context &self_size); - void apply_vertical_align() override; - public: - explicit render_item_inline_context(std::shared_ptr<element> src_el) : render_item_block(std::move(src_el)), m_max_line_width(0) - {} - - std::shared_ptr<render_item> clone() override - { - return std::make_shared<render_item_inline_context>(src_el()); - } - - int get_base_line() override; - }; - - class render_item_table : public render_item - { - protected: - // data for table rendering - std::unique_ptr<table_grid> m_grid; - int m_border_spacing_x; - int m_border_spacing_y; - - public: - explicit render_item_table(std::shared_ptr<element> src_el); - - std::shared_ptr<render_item> clone() override - { - return std::make_shared<render_item_table>(src_el()); - } - int render(int x, int y, const containing_block_context &containing_block_size, bool second_pass) override; - void draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override; - int get_draw_vertical_offset() override; - std::shared_ptr<render_item> init() override; - }; - - class render_item_table_part : public render_item - { - public: - explicit render_item_table_part(std::shared_ptr<element> src_el) : render_item(std::move(src_el)) - {} - - std::shared_ptr<render_item> clone() override - { - return std::make_shared<render_item_table_part>(src_el()); - } - }; - - class render_item_table_row : public render_item - { - public: - explicit render_item_table_row(std::shared_ptr<element> src_el) : render_item(std::move(src_el)) - {} - - std::shared_ptr<render_item> clone() override - { - return std::make_shared<render_item_table_row>(src_el()); - } - void get_inline_boxes( position::vector& boxes ) const override; - }; - - class render_item_inline : public render_item - { - protected: - position::vector m_boxes; - - public: - explicit render_item_inline(std::shared_ptr<element> src_el) : render_item(std::move(src_el)) - {} - - void get_inline_boxes( position::vector& boxes ) const override { boxes = m_boxes; } - void set_inline_boxes( position::vector& boxes ) override { m_boxes = boxes; } - void add_inline_box( const position& box ) override { m_boxes.emplace_back(box); }; - void clear_inline_boxes() override { m_boxes.clear(); } - int get_base_line() override { return src_el()->css().get_font_metrics().base_line(); } - - std::shared_ptr<render_item> clone() override - { - return std::make_shared<render_item_inline>(src_el()); - } - }; - - class render_item_image : public render_item - { - protected: - int calc_max_height(int image_height, int containing_block_height); - - public: - explicit render_item_image(std::shared_ptr<element> src_el) : render_item(std::move(src_el)) - {} - - int render(int x, int y, const containing_block_context &containing_block_size, bool second_pass) override; - std::shared_ptr<render_item> clone() override - { - return std::make_shared<render_item_image>(src_el()); - } - }; - - class render_item_flex : public render_item_block - { - struct flex_item - { - std::shared_ptr<render_item> el; - int base_size; - int main_size; - int min_width; - int max_width; - int line; - - explicit flex_item(std::shared_ptr<render_item> _el) : - el(std::move(_el)), - min_width(0), - max_width(0), - line(0), - base_size(0), - main_size(0) - {} - }; - protected: - std::list<std::unique_ptr<flex_item>> m_flex_items; - - int _render_content(int x, int y, bool second_pass, int ret_width, - const containing_block_context &self_size) override; - - public: - explicit render_item_flex(std::shared_ptr<element> src_el) : render_item_block(std::move(src_el)) - {} - - std::shared_ptr<render_item> clone() override - { - return std::make_shared<render_item_flex>(src_el()); - } - void draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override; - std::shared_ptr<render_item> init() override; - }; - } #endif //LH_RENDER_ITEM_H diff --git a/src/plugins/litehtml_viewer/litehtml/render_table.cpp b/src/plugins/litehtml_viewer/litehtml/render_table.cpp @@ -1,5 +1,5 @@ #include "html.h" -#include "render_item.h" +#include "render_table.h" #include "document.h" #include "iterators.h" @@ -11,30 +11,12 @@ litehtml::render_item_table::render_item_table(std::shared_ptr<element> _src_el) { } -int litehtml::render_item_table::render(int x, int y, const containing_block_context &containing_block_size, bool second_pass) +int litehtml::render_item_table::_render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) { if (!m_grid) return 0; - calc_outlines(containing_block_size.width); - - m_pos.clear(); - m_pos.move_to(x, y); - - m_pos.x += content_offset_left(); - m_pos.y += content_offset_top(); - containing_block_context self_size = calculate_containing_block_context(containing_block_size); -/* if(cb_size.width_type == containing_block_context::cbc_value_type_auto) - { - max_width -= content_offset_left() + content_offset_right(); - } else - { - max_width -= m_padding.width() + m_borders.width(); - } - if(max_width < 0) max_width = 0; - max_width = std::min(max_width, cb_size.width); -*/ // Calculate table spacing int table_width_spacing = 0; if (src_el()->css().get_border_collapse() == border_collapse_separate) @@ -71,7 +53,7 @@ int litehtml::render_item_table::render(int x, int y, const containing_block_con table_cell* cell = m_grid->cell(0, row); if (cell && cell->el) { - cell->min_width = cell->max_width = cell->el->render(0, 0, self_size.new_width(self_size.render_width - table_width_spacing)); + cell->min_width = cell->max_width = cell->el->render(0, 0, self_size.new_width(self_size.render_width - table_width_spacing), fmt_ctx); cell->el->pos().width = cell->min_width - cell->el->content_offset_left() - cell->el->content_offset_right(); } @@ -89,7 +71,7 @@ int litehtml::render_item_table::render(int x, int y, const containing_block_con if (!m_grid->column(col).css_width.is_predefined() && m_grid->column(col).css_width.units() != css_units_percentage) { int css_w = m_grid->column(col).css_width.calc_percent(self_size.width); - int el_w = cell->el->render(0, 0, self_size.new_width(css_w)); + int el_w = cell->el->render(0, 0, self_size.new_width(css_w),fmt_ctx); cell->min_width = cell->max_width = std::max(css_w, el_w); cell->el->pos().width = cell->min_width - cell->el->content_offset_left() - cell->el->content_offset_right(); @@ -97,9 +79,9 @@ int litehtml::render_item_table::render(int x, int y, const containing_block_con else { // calculate minimum content width - cell->min_width = cell->el->render(0, 0, self_size.new_width(cell->el->content_offset_width())); + cell->min_width = cell->el->render(0, 0, self_size.new_width(cell->el->content_offset_width()), fmt_ctx); // calculate maximum content width - cell->max_width = cell->el->render(0, 0, self_size.new_width(self_size.render_width - table_width_spacing)); + cell->max_width = cell->el->render(0, 0, self_size.new_width(self_size.render_width - table_width_spacing), fmt_ctx); } } } @@ -201,7 +183,7 @@ int litehtml::render_item_table::render(int x, int y, const containing_block_con //if (cell->el->pos().width != cell_width - cell->el->content_offset_left() - // cell->el->content_offset_right()) { - cell->el->render(m_grid->column(col).left, 0, self_size.new_width(cell_width), true); + cell->el->render(m_grid->column(col).left, 0, self_size.new_width(cell_width), fmt_ctx, true); cell->el->pos().width = cell_width - cell->el->content_offset_left() - cell->el->content_offset_right(); } @@ -339,40 +321,54 @@ int litehtml::render_item_table::render(int x, int y, const containing_block_con // Render table captions // Table border doesn't round the caption, so we have to start caption in the border position - int captions_height = -border_top(); + int top_captions = -border_top(); for (auto& caption : m_grid->captions()) { - caption->render(-border_left(), captions_height, self_size.new_width(table_width + border_left() + border_right())); - captions_height += caption->height(); + if(caption->css().get_caption_side() == caption_side_top) + { + caption->render(-border_left(), top_captions, self_size.new_width(table_width + border_left() + border_right()), fmt_ctx); + top_captions += caption->height(); + } } - if (captions_height) + if (top_captions) { // Add border height to get the top of cells - captions_height += border_top(); + top_captions += border_top(); // Save caption height for draw_background - m_grid->captions_height(captions_height); + m_grid->top_captions_height(top_captions); // Move table cells to the bottom side for (int row = 0; row < m_grid->rows_count(); row++) { - m_grid->row(row).el_row->pos().y += captions_height; + m_grid->row(row).el_row->pos().y += top_captions; for (int col = 0; col < m_grid->cols_count(); col++) { table_cell* cell = m_grid->cell(col, row); if (cell->el) { - cell->el->pos().y += captions_height; + cell->el->pos().y += top_captions; } } } } + int bottom_captions = 0; + + for (auto& caption : m_grid->captions()) + { + if(caption->css().get_caption_side() == caption_side_bottom) + { + caption->render(-border_left(), table_height + top_captions + bottom_captions, self_size.new_width(table_width + border_left() + border_right()), fmt_ctx); + bottom_captions += caption->height(); + } + } + m_pos.move_to(x + content_offset_left(), y + content_offset_top()); m_pos.width = table_width; - m_pos.height = table_height + captions_height; + m_pos.height = table_height + top_captions + bottom_captions; if(self_size.width.type != containing_block_context::cbc_value_type_absolute) { @@ -476,7 +472,25 @@ int litehtml::render_item_table::get_draw_vertical_offset() { if(m_grid) { - return m_grid->captions_height(); + return m_grid->top_captions_height(); } return 0; } + +void litehtml::render_item_table_row::get_inline_boxes( position::vector& boxes ) const +{ + position pos; + for(auto& el : m_children) + { + if(el->src_el()->css().get_display() == display_table_cell) + { + pos.x = el->left() + el->margin_left(); + pos.y = el->top() - m_padding.top - m_borders.top; + + pos.width = el->right() - pos.x - el->margin_right() - el->margin_left(); + pos.height = el->height() + m_padding.top + m_padding.bottom + m_borders.top + m_borders.bottom; + + boxes.push_back(pos); + } + } +} diff --git a/src/plugins/litehtml_viewer/litehtml/render_table.h b/src/plugins/litehtml_viewer/litehtml/render_table.h @@ -0,0 +1,56 @@ +#ifndef LITEHTML_RENDER_TABLE_H +#define LITEHTML_RENDER_TABLE_H + +#include "render_item.h" + +namespace litehtml +{ + class render_item_table : public render_item + { + protected: + // data for table rendering + std::unique_ptr<table_grid> m_grid; + int m_border_spacing_x; + int m_border_spacing_y; + + int _render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) override; + + public: + explicit render_item_table(std::shared_ptr<element> src_el); + + std::shared_ptr<render_item> clone() override + { + return std::make_shared<render_item_table>(src_el()); + } + void draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override; + int get_draw_vertical_offset() override; + std::shared_ptr<render_item> init() override; + }; + + class render_item_table_part : public render_item + { + public: + explicit render_item_table_part(std::shared_ptr<element> src_el) : render_item(std::move(src_el)) + {} + + std::shared_ptr<render_item> clone() override + { + return std::make_shared<render_item_table_part>(src_el()); + } + }; + + class render_item_table_row : public render_item + { + public: + explicit render_item_table_row(std::shared_ptr<element> src_el) : render_item(std::move(src_el)) + {} + + std::shared_ptr<render_item> clone() override + { + return std::make_shared<render_item_table_row>(src_el()); + } + void get_inline_boxes( position::vector& boxes ) const override; + }; +} + +#endif //LITEHTML_RENDER_TABLE_H diff --git a/src/plugins/litehtml_viewer/litehtml/string_id.h b/src/plugins/litehtml_viewer/litehtml/string_id.h @@ -287,6 +287,8 @@ STRING_ID( _flex_grow_, _flex_shrink_, _flex_basis_, + + _caption_side_, ); #undef STRING_ID extern const string_id empty_id; // _id("") diff --git a/src/plugins/litehtml_viewer/litehtml/style.cpp b/src/plugins/litehtml_viewer/litehtml/style.cpp @@ -44,6 +44,8 @@ std::map<string_id, string> style::m_valid_values = { _align_items_, flex_align_items_strings }, { _align_content_, flex_align_content_strings }, { _align_self_, flex_align_self_strings }, + + { _caption_side_, caption_side_strings }, }; void style::parse(const string& txt, const string& baseurl, document_container* container) @@ -130,6 +132,8 @@ void style::add_property(string_id name, const string& val, const string& baseur case _align_content_: case _align_self_: + case _caption_side_: + idx = value_index(val, m_valid_values[name]); if (idx >= 0) { @@ -238,7 +242,7 @@ void style::add_property(string_id name, const string& val, const string& baseur add_parsed_property(_border_top_width_, width); add_parsed_property(_border_bottom_width_, width); } - else + else if (web_color::is_color(token, container)) { web_color _color = web_color::from_string(token, container); property_value color(_color, important); @@ -271,7 +275,7 @@ void style::add_property(string_id name, const string& val, const string& baseur property_value width(parse_border_width(token), important); add_parsed_property(_id(_s(name) + "-width"), width); } - else + else if (web_color::is_color(token, container)) { web_color color = web_color::from_string(token, container); add_parsed_property(_id(_s(name) + "-color"), property_value(color, important)); @@ -334,11 +338,12 @@ void style::add_property(string_id name, const string& val, const string& baseur case _border_bottom_color_: case _border_left_color_: case _border_right_color_: - { - web_color color = web_color::from_string(val, container); - add_parsed_property(name, property_value(color, important)); + if (web_color::is_color(val, container)) + { + web_color color = web_color::from_string(val, container); + add_parsed_property(name, property_value(color, important)); + } break; - } // Parse border radius shorthand properties case _border_bottom_left_radius_: diff --git a/src/plugins/litehtml_viewer/litehtml/stylesheet.cpp b/src/plugins/litehtml_viewer/litehtml/stylesheet.cpp @@ -13,6 +13,11 @@ void litehtml::css::parse_stylesheet(const char* str, const char* baseurl, const while(c_start != string::npos) { string::size_type c_end = text.find("*/", c_start + 2); + if(c_end == string::npos) + { + text.erase(c_start); + break; + } text.erase(c_start, c_end - c_start + 2); c_start = text.find("/*"); } diff --git a/src/plugins/litehtml_viewer/litehtml/table.h b/src/plugins/litehtml_viewer/litehtml/table.h @@ -204,14 +204,16 @@ namespace litehtml table_column::vector m_columns; table_row::vector m_rows; std::vector<std::shared_ptr<render_item>> m_captions; - int m_captions_height; + int m_top_captions_height; + int m_bottom_captions_height; public: - table_grid() + table_grid() : + m_rows_count(0), + m_cols_count(0), + m_top_captions_height(0), + m_bottom_captions_height(0) { - m_rows_count = 0; - m_cols_count = 0; - m_captions_height = 0; } void clear(); @@ -227,8 +229,10 @@ namespace litehtml int rows_count() const { return m_rows_count; } int cols_count() const { return m_cols_count; } - void captions_height(int height) { m_captions_height = height; } - int captions_height() const { return m_captions_height; } + void top_captions_height(int height) { m_top_captions_height = height; } + int top_captions_height() const { return m_top_captions_height; } + void bottom_captions_height(int height) { m_bottom_captions_height = height; } + int bottom_captions_height() const { return m_bottom_captions_height; } void distribute_max_width(int width, int start, int end); void distribute_min_width(int width, int start, int end); diff --git a/src/plugins/litehtml_viewer/litehtml/types.h b/src/plugins/litehtml_viewer/litehtml/types.h @@ -5,6 +5,7 @@ #include <memory> #include <map> #include <vector> +#include <list> namespace litehtml { @@ -12,7 +13,7 @@ namespace litehtml class element; typedef std::map<string, string> string_map; - typedef std::vector< std::shared_ptr<element> > elements_vector; + typedef std::list< std::shared_ptr<element> > elements_list; typedef std::vector<int> int_vector; typedef std::vector<string> string_vector; @@ -598,6 +599,7 @@ namespace litehtml element_clear clear_floats; std::shared_ptr<render_item> el; int context; + int min_width; floated_box() = default; floated_box(const floated_box& val) @@ -607,6 +609,7 @@ namespace litehtml clear_floats = val.clear_floats; el = val.el; context = val.context; + min_width = val.min_width; } floated_box& operator=(const floated_box& val) { @@ -615,6 +618,7 @@ namespace litehtml clear_floats = val.clear_floats; el = val.el; context = val.context; + min_width = val.min_width; return *this; } floated_box(floated_box&& val) @@ -624,6 +628,7 @@ namespace litehtml clear_floats = val.clear_floats; el = std::move(val.el); context = val.context; + min_width = val.min_width; } void operator=(floated_box&& val) { @@ -632,6 +637,7 @@ namespace litehtml clear_floats = val.clear_floats; el = std::move(val.el); context = val.context; + min_width = val.min_width; } }; @@ -899,6 +905,13 @@ namespace litehtml flex_basis_max_content, }; +#define caption_side_strings "top;bottom" + + enum caption_side + { + caption_side_top, + caption_side_bottom + }; } #endif // LH_TYPES_H