From b35db77b68eba8e68edeb5cb53824123dad7764e Mon Sep 17 00:00:00 2001 From: Jonathan Boeing Date: Sat, 21 Oct 2023 02:22:33 -0700 Subject: [PATCH] Update LiteHTML sources Sync with upstream commit 42632777fbb047e15cb6a4f661a3304f993671ec --- src/plugins/litehtml_viewer/litehtml/Makefile.am | 11 +- src/plugins/litehtml_viewer/litehtml/README.md | 15 +- .../litehtml_viewer/litehtml/css_properties.cpp | 4 +- .../litehtml_viewer/litehtml/css_properties.h | 15 + .../litehtml_viewer/litehtml/css_selector.cpp | 5 + src/plugins/litehtml_viewer/litehtml/document.cpp | 12 +- src/plugins/litehtml_viewer/litehtml/document.h | 2 +- .../litehtml_viewer/litehtml/el_before_after.cpp | 7 +- .../litehtml_viewer/litehtml/el_before_after.h | 1 - src/plugins/litehtml_viewer/litehtml/el_image.cpp | 2 +- src/plugins/litehtml_viewer/litehtml/el_style.h | 2 +- src/plugins/litehtml_viewer/litehtml/el_table.cpp | 17 - src/plugins/litehtml_viewer/litehtml/element.cpp | 65 +- src/plugins/litehtml_viewer/litehtml/element.h | 23 +- .../litehtml/formatting_context.cpp | 441 ++++++++ .../litehtml_viewer/litehtml/formatting_context.h | 54 + src/plugins/litehtml_viewer/litehtml/html_tag.cpp | 107 +- src/plugins/litehtml_viewer/litehtml/html_tag.h | 13 +- src/plugins/litehtml_viewer/litehtml/line_box.cpp | 2 +- src/plugins/litehtml_viewer/litehtml/master_css.h | 25 + .../litehtml_viewer/litehtml/media_query.cpp | 2 +- .../litehtml_viewer/litehtml/render_block.cpp | 1173 ++++++-------------- .../litehtml_viewer/litehtml/render_block.h | 40 + .../litehtml/render_block_context.cpp | 24 +- .../litehtml/render_block_context.h | 29 + .../litehtml_viewer/litehtml/render_flex.cpp | 5 +- src/plugins/litehtml_viewer/litehtml/render_flex.h | 46 + .../litehtml_viewer/litehtml/render_image.cpp | 5 +- .../litehtml_viewer/litehtml/render_image.h | 25 + .../litehtml_viewer/litehtml/render_inline.h | 30 + .../litehtml/render_inline_context.cpp | 71 +- .../litehtml/render_inline_context.h | 55 + .../litehtml_viewer/litehtml/render_item.cpp | 62 +- src/plugins/litehtml_viewer/litehtml/render_item.h | 259 +---- .../litehtml_viewer/litehtml/render_table.cpp | 84 +- .../litehtml_viewer/litehtml/render_table.h | 56 + src/plugins/litehtml_viewer/litehtml/string_id.h | 2 + src/plugins/litehtml_viewer/litehtml/style.cpp | 17 +- .../litehtml_viewer/litehtml/stylesheet.cpp | 5 + src/plugins/litehtml_viewer/litehtml/table.h | 18 +- src/plugins/litehtml_viewer/litehtml/types.h | 15 +- 41 files changed, 1470 insertions(+), 1376 deletions(-) create mode 100644 src/plugins/litehtml_viewer/litehtml/formatting_context.cpp create mode 100644 src/plugins/litehtml_viewer/litehtml/formatting_context.h rewrite src/plugins/litehtml_viewer/litehtml/render_block.cpp (67%) create mode 100644 src/plugins/litehtml_viewer/litehtml/render_block.h create mode 100644 src/plugins/litehtml_viewer/litehtml/render_block_context.h create mode 100644 src/plugins/litehtml_viewer/litehtml/render_flex.h create mode 100644 src/plugins/litehtml_viewer/litehtml/render_image.h create mode 100644 src/plugins/litehtml_viewer/litehtml/render_inline.h create mode 100644 src/plugins/litehtml_viewer/litehtml/render_inline_context.h create mode 100644 src/plugins/litehtml_viewer/litehtml/render_table.h diff --git a/src/plugins/litehtml_viewer/litehtml/Makefile.am b/src/plugins/litehtml_viewer/litehtml/Makefile.am index 6e103b7ba..e4b5ac94a 100644 --- 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 index 293f591bc..ab897f517 100644 --- a/src/plugins/litehtml_viewer/litehtml/README.md +++ b/src/plugins/litehtml_viewer/litehtml/README.md @@ -1,5 +1,3 @@ -[![Travis Build Status](https://travis-ci.org/litehtml/litehtml.svg?branch=master)](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: - -[ ![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif) ](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UHBQG6EAFCRBA) [ ![Patreon](https://img.shields.io/badge/patreon-Become%20a%20Patron!-red.png?style=for-the-badge&logo=patreon) ](https://www.patreon.com/tordex) - -Bitcoin: **1CS1174GVSLbP33TBp8RFwqPS6KmQK6kLY** +## Links -![BitCoin](https://www.tordex.com/assets/images/litehtml-bitcoin.png) + * [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 index 1efccb609..2696ae28f 100644 --- 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 #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 index 0eed09d9a..739e35fc2 100644 --- 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& doc); void compute_background(const element* el, const std::shared_ptr& 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 index 6ace9bb07..5843cb1a6 100644 --- 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 index 8623bff41..ec336613d 100644 --- 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(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 index 11322f899..b4b268ba8 100644 --- 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& 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 index 4455642e8..8c24eec98 100644 --- 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(word.c_str(), get_document()); + element::ptr el = std::make_shared(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 index ac966f395..eed5f3dad 100644 --- 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& 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 index 34b8a7aef..9cf8146b4 100644 --- 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 index b6258932d..62f154625 100644 --- 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& doc); diff --git a/src/plugins/litehtml_viewer/litehtml/el_table.cpp b/src/plugins/litehtml_viewer/litehtml/el_table.cpp index d0c711c4d..0bb864843 100644 --- 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 index 2438b1325..1d0a509b1 100644 --- 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(get_document()); - m_children.insert(m_children.begin(), el); - } else - { - el = std::make_shared(get_document()); - m_children.insert(m_children.end(), el); - } - el->parent(shared_from_this()); - return el; + el = std::make_shared(get_document()); + m_children.insert(m_children.begin(), el); + } else + { + el = std::make_shared(get_document()); + m_children.insert(m_children.end(), el); } - 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 index 2fa160c2c..e330b5c01 100644 --- 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 m_parent; std::weak_ptr m_doc; - elements_vector m_children; + elements_list m_children; css_properties m_css; std::list> 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& 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 get_document() const; + const std::list>& 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>& 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 new file mode 100644 index 000000000..4e41c7b5f --- /dev/null +++ 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 &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 &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( )); + 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 &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 new file mode 100644 index 000000000..eee481dc4 --- /dev/null +++ b/src/plugins/litehtml_viewer/litehtml/formatting_context.h @@ -0,0 +1,54 @@ +#ifndef LITEHTML_FLOATS_HOLDER_H +#define LITEHTML_FLOATS_HOLDER_H + +#include +#include "types.h" + +namespace litehtml +{ + class formatting_context + { + private: + std::list m_floats_left; + std::list 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 &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 &el, int line_top) const; + void update_floats(int dy, const std::shared_ptr &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 index d1e7302e4..0b978f56a 100644 --- 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& bg_paint, const background* bg, const std::shared_ptr& 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 index 71b9cb345..9148031b2 100644 --- 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 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& 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 index 269dd4672..1ca9c85d7 100644 --- 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::line_box::get_last_text_part() bool litehtml::line_box::can_hold(const std::unique_ptr& 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 index b5c7f3f03..0e7b0ca4e 100644 --- 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 index 763620367..7cddb15a2 100644 --- 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 dissimilarity index 67% index 8e1d107b4..d653f3114 100644 --- a/src/plugins/litehtml_viewer/litehtml/render_block.cpp +++ b/src/plugins/litehtml_viewer/litehtml/render_block.cpp @@ -1,856 +1,317 @@ -#include "html.h" -#include "render_item.h" -#include "document.h" - -int litehtml::render_item_block::place_float(const std::shared_ptr &el, int top, const containing_block_context &self_size) -{ - int line_top = 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); - - int ret_width = 0; - - 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(); - } - add_float(el, 0, 0, self_size.context_idx); - fix_line_width(float_left, self_size); - ret_width = el->right(); - } 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(); - 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); - } - 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 &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 &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( )); - 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 &_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_block::init() -{ - { - css_selector sel; - sel.parse(".inline_rating"); - if(src_el()->select(sel)) - { - int i = 0; - i++; - } - } - std::shared_ptr ret; - - // Initialize indexes for list items - if(src_el()->css().get_display() == display_list_item && src_el()->css().get_list_style_type() >= list_style_type_armenian) - { - 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++) - { - auto child = p->get_child(i); - if (child == src_el()) - { - src_el()->set_attr("list_index", std::to_string(val).c_str()); - break; - } - else if (child->css().get_display() == display_list_item) - val++; - } - } - } - // Split inline blocks with box blocks inside - auto iter = m_children.begin(); - while (iter != m_children.end()) - { - const auto& el = *iter; - if(el->src_el()->css().get_display() == display_inline && !el->children().empty()) - { - auto split_el = el->split_inlines(); - if(std::get<0>(split_el)) - { - iter = m_children.erase(iter); - iter = m_children.insert(iter, std::get<2>(split_el)); - iter = m_children.insert(iter, std::get<1>(split_el)); - iter = m_children.insert(iter, std::get<0>(split_el)); - - std::get<0>(split_el)->parent(shared_from_this()); - std::get<1>(split_el)->parent(shared_from_this()); - std::get<2>(split_el)->parent(shared_from_this()); - continue; - } - } - ++iter; - } - - bool has_block_level = false; - bool has_inlines = false; - bool has_floats = false; - for (const auto& el : m_children) - { - if(!el->src_el()->is_float()) - { - if (el->src_el()->is_block_box()) - { - has_block_level = true; - } else if (el->src_el()->is_inline_box()) - { - has_inlines = true; - } - } - if(has_block_level && has_inlines) - break; - } - if(has_block_level) - { - ret = std::make_shared(src_el()); - ret->parent(parent()); - - auto doc = src_el()->get_document(); - decltype(m_children) new_children; - decltype(m_children) inlines; - bool not_ws_added = false; - for (const auto& el : m_children) - { - if(el->src_el()->is_inline_box()) - { - inlines.push_back(el); - if(!el->src_el()->is_white_space()) - not_ws_added = true; - } else - { - if(not_ws_added) - { - auto anon_el = std::make_shared(src_el()); - auto anon_ri = std::make_shared(anon_el); - for(const auto& inl : inlines) - { - anon_ri->add_child(inl); - } - - not_ws_added = false; - new_children.push_back(anon_ri); - anon_ri->parent(ret); - } - new_children.push_back(el); - el->parent(ret); - inlines.clear(); - } - } - if(!inlines.empty() && not_ws_added) - { - auto anon_el = std::make_shared(src_el()); - auto anon_ri = std::make_shared(anon_el); - for(const auto& inl : inlines) - { - anon_ri->add_child(inl); - } - - new_children.push_back(anon_ri); - anon_ri->parent(ret); - } - ret->children() = new_children; - } - - if(!ret) - { - ret = std::make_shared(src_el()); - ret->parent(parent()); - ret->children() = children(); - for (const auto &el: ret->children()) - { - el->parent(ret); - } - } - - ret->src_el()->add_render(ret); - - for(auto& el : ret->children()) - { - el = el->init(); - } - - return ret; -} - -int litehtml::render_item_block::render(int x, int y, const containing_block_context &containing_block_size, 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); - //***************************************** - - bool requires_rerender = false; // when true, the second pass for content rendering is required - - // Set block width - if(self_size.width.type == containing_block_context::cbc_value_type_absolute) - { - ret_width = m_pos.width = self_size.render_width; - } else if(self_size.width.type == containing_block_context::cbc_value_type_percentage) - { - 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; - } - } - - // Fix width with min-width attribute - if(self_size.min_width.type != containing_block_context::cbc_value_type_none) - { - if(m_pos.width < self_size.min_width) - { - m_pos.width = self_size.min_width; - requires_rerender = true; - } - } - - // Fix width with max-width attribute - if(self_size.max_width.type != containing_block_context::cbc_value_type_none) - { - if(m_pos.width > self_size.max_width) - { - m_pos.width = self_size.max_width; - requires_rerender = true; - } - } - - // re-render content with new width if required - if (requires_rerender && !second_pass && !is_root()) - { - if(src_el()->is_floats_holder()) - { - m_floats_left.clear(); - m_floats_right.clear(); - } else - { - 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)); - } - - // Set block height - if (self_size.height.type != containing_block_context::cbc_value_type_auto) - { - 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()) - { - // add the floats' height to the block height - int floats_height = get_floats_height(); - if (floats_height > m_pos.height) - { - m_pos.height = floats_height; - } - } - - // Fix height with min-height attribute - if(self_size.min_height.type != containing_block_context::cbc_value_type_none) - { - if(m_pos.height < self_size.min_height) - { - m_pos.height = self_size.min_height; - } - } - - // Fix width with max-width attribute - if(self_size.max_height.type != containing_block_context::cbc_value_type_none) - { - if(m_pos.height > self_size.max_height) - { - m_pos.height = self_size.max_height; - } - } - - // calculate the final position - m_pos.move_to(x, y); - m_pos.x += content_offset_left(); - m_pos.y += content_offset_top(); - - if (src_el()->css().get_display() == display_list_item) - { - string list_image = src_el()->css().get_list_style_image(); - if (!list_image.empty()) - { - size sz; - string list_image_baseurl = src_el()->css().get_list_style_image_baseurl(); - src_el()->get_document()->container()->get_image_size(list_image.c_str(), list_image_baseurl.c_str(), sz); - if (m_pos.height < sz.height) - { - m_pos.height = sz.height; - } - } - - } - - 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(); -} +#include "html.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 &el, int top, const containing_block_context &self_size, formatting_context* fmt_ctx) +{ + int line_top = fmt_ctx->get_cleared_top(el, top); + int line_left = 0; + int line_right = self_size.render_width; + 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) + { + if(el->right() > line_right) + { + 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(); + } + 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) + { + if(line_left + el->width() > line_right) + { + 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(); + } + 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; +} + +std::shared_ptr litehtml::render_item_block::init() +{ + { + css_selector sel; + sel.parse(".inline_rating"); + if(src_el()->select(sel)) + { + int i = 0; + i++; + } + } + std::shared_ptr ret; + + // Initialize indexes for list items + if(src_el()->css().get_display() == display_list_item && src_el()->css().get_list_style_type() >= list_style_type_armenian) + { + if (auto p = src_el()->parent()) + { + int val = atoi(p->get_attr("start", "1")); + for(const auto &child : p->children()) + { + if (child == src_el()) + { + src_el()->set_attr("list_index", std::to_string(val).c_str()); + break; + } + else if (child->css().get_display() == display_list_item) + val++; + } + } + } + // Split inline blocks with box blocks inside + auto iter = m_children.begin(); + while (iter != m_children.end()) + { + const auto& el = *iter; + if(el->src_el()->css().get_display() == display_inline && !el->children().empty()) + { + auto split_el = el->split_inlines(); + if(std::get<0>(split_el)) + { + iter = m_children.erase(iter); + iter = m_children.insert(iter, std::get<2>(split_el)); + iter = m_children.insert(iter, std::get<1>(split_el)); + iter = m_children.insert(iter, std::get<0>(split_el)); + + std::get<0>(split_el)->parent(shared_from_this()); + std::get<1>(split_el)->parent(shared_from_this()); + std::get<2>(split_el)->parent(shared_from_this()); + continue; + } + } + ++iter; + } + + bool has_block_level = false; + bool has_inlines = false; + bool has_floats = false; + for (const auto& el : m_children) + { + if(!el->src_el()->is_float()) + { + if (el->src_el()->is_block_box()) + { + has_block_level = true; + } else if (el->src_el()->is_inline()) + { + has_inlines = true; + } + } + if(has_block_level && has_inlines) + break; + } + if(has_block_level) + { + ret = std::make_shared(src_el()); + ret->parent(parent()); + + auto doc = src_el()->get_document(); + decltype(m_children) new_children; + decltype(m_children) inlines; + bool not_ws_added = false; + for (const auto& el : m_children) + { + if(el->src_el()->is_inline()) + { + inlines.push_back(el); + if(!el->src_el()->is_white_space()) + not_ws_added = true; + } else + { + if(not_ws_added) + { + auto anon_el = std::make_shared(src_el()); + auto anon_ri = std::make_shared(anon_el); + for(const auto& inl : inlines) + { + anon_ri->add_child(inl); + } + + not_ws_added = false; + new_children.push_back(anon_ri); + anon_ri->parent(ret); + } + new_children.push_back(el); + el->parent(ret); + inlines.clear(); + } + } + if(!inlines.empty() && not_ws_added) + { + auto anon_el = std::make_shared(src_el()); + auto anon_ri = std::make_shared(anon_el); + for(const auto& inl : inlines) + { + anon_ri->add_child(inl); + } + + new_children.push_back(anon_ri); + anon_ri->parent(ret); + } + ret->children() = new_children; + } + + if(!ret) + { + ret = std::make_shared(src_el()); + ret->parent(parent()); + ret->children() = children(); + for (const auto &el: ret->children()) + { + el->parent(ret); + } + } + + ret->src_el()->add_render(ret); + + for(auto& el : ret->children()) + { + el = el->init(); + } + + return ret; +} + +int litehtml::render_item_block::_render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) +{ + containing_block_context self_size = calculate_containing_block_context(containing_block_size); + + //***************************************** + // Render content + //***************************************** + 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 + + // Set block width + if(self_size.width.type == containing_block_context::cbc_value_type_absolute) + { + ret_width = m_pos.width = self_size.render_width; + } else if(self_size.width.type == containing_block_context::cbc_value_type_percentage) + { + m_pos.width = self_size.render_width; + } else + { + m_pos.width = self_size.render_width; + } + + // Fix width with min-width attribute + if(self_size.min_width.type != containing_block_context::cbc_value_type_none) + { + if(m_pos.width < self_size.min_width) + { + m_pos.width = self_size.min_width; + requires_rerender = true; + } + } + + // Fix width with max-width attribute + if(self_size.max_width.type != containing_block_context::cbc_value_type_none) + { + if(m_pos.width > self_size.max_width) + { + m_pos.width = self_size.max_width; + requires_rerender = true; + } + } + + // re-render content with new width if required + if (requires_rerender && !second_pass && !is_root()) + { + if(src_el()->is_block_formatting_context()) + { + fmt_ctx->clear_floats(-1); + } else + { + fmt_ctx->clear_floats(self_size.context_idx); + } + + _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) + { + 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_block_formatting_context()) + { + // add the floats' height to the block height + int floats_height = fmt_ctx->get_floats_height(); + if (floats_height > m_pos.height) + { + m_pos.height = floats_height; + } + } + + // Fix height with min-height attribute + if(self_size.min_height.type != containing_block_context::cbc_value_type_none) + { + if(m_pos.height < self_size.min_height) + { + m_pos.height = self_size.min_height; + } + } + + // Fix width with max-width attribute + if(self_size.max_height.type != containing_block_context::cbc_value_type_none) + { + if(m_pos.height > self_size.max_height) + { + m_pos.height = self_size.max_height; + } + } + + // calculate the final position + m_pos.move_to(x, y); + m_pos.x += content_offset_left(); + m_pos.y += content_offset_top(); + + if (src_el()->css().get_display() == display_list_item) + { + string list_image = src_el()->css().get_list_style_image(); + if (!list_image.empty()) + { + size sz; + string list_image_baseurl = src_el()->css().get_list_style_image_baseurl(); + src_el()->get_document()->container()->get_image_size(list_image.c_str(), list_image_baseurl.c_str(), sz); + if (m_pos.height < sz.height) + { + m_pos.height = sz.height; + } + } + + } + + 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 new file mode 100644 index 000000000..eb058c618 --- /dev/null +++ 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 &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 src_el) : render_item(std::move(src_el)) + {} + + std::shared_ptr clone() override + { + return std::make_shared(src_el()); + } + std::shared_ptr 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 index b0aa444d7..7591378c2 100644 --- 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 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 new file mode 100644 index 000000000..3b5192261 --- /dev/null +++ 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 src_el) : render_item_block(std::move(src_el)) + {} + + std::shared_ptr clone() override + { + return std::make_shared(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 index c9cf8e538..2cab59e04 100644 --- 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 new file mode 100644 index 000000000..5d31bc9bf --- /dev/null +++ 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 el; + int base_size; + int main_size; + int min_width; + int max_width; + int line; + + explicit flex_item(std::shared_ptr _el) : + el(std::move(_el)), + min_width(0), + max_width(0), + line(0), + base_size(0), + main_size(0) + {} + }; + protected: + std::list> 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 src_el) : render_item_block(std::move(src_el)) + {} + + std::shared_ptr clone() override + { + return std::make_shared(src_el()); + } + void draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override; + std::shared_ptr 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 index 38f576bc1..63e622d7b 100644 --- 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 new file mode 100644 index 000000000..e85f487ca --- /dev/null +++ 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 src_el) : render_item(std::move(src_el)) + {} + + std::shared_ptr clone() override + { + return std::make_shared(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 new file mode 100644 index 000000000..476011563 --- /dev/null +++ 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 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 clone() override + { + return std::make_shared(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 index b348a8cf7..2d8f2e173 100644 --- 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(new line_box_item(el)), self_size); + place_inline(std::unique_ptr(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(new lbi_start(el)), self_size); + place_inline(std::unique_ptr(new lbi_start(el)), self_size, fmt_ctx); } break; case iterator_item_type_end_parent: { - place_inline(std::unique_ptr(new lbi_end(el)), self_size); + place_inline(std::unique_ptr(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 > litehtml::render_item_inlin return ret; } -int litehtml::render_item_inline_context::new_box(const std::unique_ptr& el, line_context& line_ctx, const containing_block_context &self_size) +int litehtml::render_item_inline_context::new_box(const std::unique_ptr& 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_ptrbottom(); } - 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 item, const containing_block_context &self_size) +void litehtml::render_item_inline_context::place_inline(std::unique_ptr 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_ptrtop(); } - 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_ptrget_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_ptrtop(); @@ -311,10 +310,10 @@ void litehtml::render_item_inline_context::place_inline(std::unique_ptrget_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 new file mode 100644 index 000000000..894cfe989 --- /dev/null +++ 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 element; + position::vector boxes; + position start_box; + + explicit inlines_item(const std::shared_ptr& el) : element(el) {} + }; + protected: + std::vector > 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 > finish_last_box(bool end_of_render, const containing_block_context &self_size); + void place_inline(std::unique_ptr item, const containing_block_context &self_size, formatting_context* fmt_ctx); + int new_box(const std::unique_ptr& 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 src_el) : render_item_block(std::move(src_el)), m_max_line_width(0) + {} + + std::shared_ptr clone() override + { + return std::make_shared(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 index 2fc8e99c7..4eb25757d 100644 --- 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 _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::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::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 index f3575778f..9d4561e5a 100644 --- 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 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 &el, int x, int y, int context) {} - virtual void clear_floats(int context) {} - virtual void update_floats(int dy, const std::shared_ptr &_parent) {} }; - - class render_item_block : public render_item - { - protected: - std::list m_floats_left; - std::list 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 &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 &el, int x, int y, int context) override; - void clear_floats(int context) override; - int get_cleared_top(const std::shared_ptr &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 &_parent) override; - public: - explicit render_item_block(std::shared_ptr src_el) : render_item(std::move(src_el)) - {} - - std::shared_ptr clone() override - { - return std::make_shared(src_el()); - } - std::shared_ptr 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 src_el) : render_item_block(std::move(src_el)) - {} - - std::shared_ptr clone() override - { - return std::make_shared(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 element; - position::vector boxes; - position start_box; - - explicit inlines_item(const std::shared_ptr& el) : element(el) {} - }; - protected: - std::vector > 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 > finish_last_box(bool end_of_render, const containing_block_context &self_size); - void place_inline(std::unique_ptr item, const containing_block_context &self_size); - int new_box(const std::unique_ptr& 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 src_el) : render_item_block(std::move(src_el)), m_max_line_width(0) - {} - - std::shared_ptr clone() override - { - return std::make_shared(src_el()); - } - - int get_base_line() override; - }; - - class render_item_table : public render_item - { - protected: - // data for table rendering - std::unique_ptr m_grid; - int m_border_spacing_x; - int m_border_spacing_y; - - public: - explicit render_item_table(std::shared_ptr src_el); - - std::shared_ptr clone() override - { - return std::make_shared(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 init() override; - }; - - class render_item_table_part : public render_item - { - public: - explicit render_item_table_part(std::shared_ptr src_el) : render_item(std::move(src_el)) - {} - - std::shared_ptr clone() override - { - return std::make_shared(src_el()); - } - }; - - class render_item_table_row : public render_item - { - public: - explicit render_item_table_row(std::shared_ptr src_el) : render_item(std::move(src_el)) - {} - - std::shared_ptr clone() override - { - return std::make_shared(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 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 clone() override - { - return std::make_shared(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 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 clone() override - { - return std::make_shared(src_el()); - } - }; - - class render_item_flex : public render_item_block - { - struct flex_item - { - std::shared_ptr el; - int base_size; - int main_size; - int min_width; - int max_width; - int line; - - explicit flex_item(std::shared_ptr _el) : - el(std::move(_el)), - min_width(0), - max_width(0), - line(0), - base_size(0), - main_size(0) - {} - }; - protected: - std::list> 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 src_el) : render_item_block(std::move(src_el)) - {} - - std::shared_ptr clone() override - { - return std::make_shared(src_el()); - } - void draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override; - std::shared_ptr 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 index 2ec048a98..1a3859641 100644 --- 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 _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 new file mode 100644 index 000000000..57fe435df --- /dev/null +++ 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 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 src_el); + + std::shared_ptr clone() override + { + return std::make_shared(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 init() override; + }; + + class render_item_table_part : public render_item + { + public: + explicit render_item_table_part(std::shared_ptr src_el) : render_item(std::move(src_el)) + {} + + std::shared_ptr clone() override + { + return std::make_shared(src_el()); + } + }; + + class render_item_table_row : public render_item + { + public: + explicit render_item_table_row(std::shared_ptr src_el) : render_item(std::move(src_el)) + {} + + std::shared_ptr clone() override + { + return std::make_shared(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 index 340ac7fbc..60d30f5e4 100644 --- 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 index ca6b18f06..5642d36c4 100644 --- a/src/plugins/litehtml_viewer/litehtml/style.cpp +++ b/src/plugins/litehtml_viewer/litehtml/style.cpp @@ -44,6 +44,8 @@ std::map 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 index 12bfd721d..8c4b78431 100644 --- 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 index edd5f055e..d738b63eb 100644 --- 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> 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 index 7946a3f08..b1feeeea6 100644 --- a/src/plugins/litehtml_viewer/litehtml/types.h +++ b/src/plugins/litehtml_viewer/litehtml/types.h @@ -5,6 +5,7 @@ #include #include #include +#include namespace litehtml { @@ -12,7 +13,7 @@ namespace litehtml class element; typedef std::map string_map; - typedef std::vector< std::shared_ptr > elements_vector; + typedef std::list< std::shared_ptr > elements_list; typedef std::vector int_vector; typedef std::vector string_vector; @@ -598,6 +599,7 @@ namespace litehtml element_clear clear_floats; std::shared_ptr 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 -- 2.11.4.GIT