commit a1bad64aaad057f57d64116b306d84c0bbddfef1 parent ae4519307d4133281f8f706c3a83a6b738007a59 Author: Jonathan Boeing <jonathan@claws-mail.org> Date: Sun, 12 Sep 2021 20:40:02 -0700 Sync with upstream litehtml Sync with commit 294780d910607850e91f3a066561bbbce03d1aaf Diffstat:
25 files changed, 512 insertions(+), 126 deletions(-)
diff --git a/src/plugins/litehtml_viewer/litehtml/Makefile.am b/src/plugins/litehtml_viewer/litehtml/Makefile.am @@ -36,6 +36,7 @@ liblitehtml_la_SOURCES = \ element.cpp element.h \ el_font.cpp el_font.h \ el_image.cpp el_image.h \ + el_li.cpp el_li.h \ el_link.cpp el_link.h \ el_para.cpp el_para.h \ el_script.cpp el_script.h \ @@ -51,6 +52,7 @@ liblitehtml_la_SOURCES = \ iterators.cpp iterators.h \ litehtml.h \ media_query.cpp media_query.h \ + num_cvt.cpp num_cvt.h \ os_types.h \ style.cpp style.h \ stylesheet.cpp stylesheet.h \ diff --git a/src/plugins/litehtml_viewer/litehtml/README.md b/src/plugins/litehtml_viewer/litehtml/README.md @@ -1,42 +1,45 @@ -#What is litehtml? - -**litehtml** is the lightweight HTML rendering engine with CSS2/CSS3 support. Note, **litehtml** itself does not draw any text, pictures or other graphics and **litehtml** does not depend of 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 right position (renders HTML). To draw the html elemens 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! Note, the [document_container](https://github.com/litehtml/litehtml/wiki/document_container) implementation is required to render HTML correctly. - -#Where litehtml can be used - -**litehtml** can be used when you need to show the html-formated texts or even to create a mini-browser, but the using full-featured html engine is not possible. Usually you don't need something like WebKit to show some html tooltips or html-formated text, **litehtml** is much better for these. - -##HTML Parser - -**litehtml** uses the [gumbo-parser](https://github.com/google/gumbo-parser) to parse HTML. Gumbo is an implementation of the HTML5 parsing algorithm implemented as a pure C99 library with no outside dependencies. It's designed to serve as a building block for other tools and libraries such as linters, validators, templating languages, and refactoring and analysis tools. - -##Compatibility - -**litehtml** is compatible with any platform suported C++ and STL. For Windows the MS Visual Studio 2013 is recommended. **litehtml** supports both utf-8 and unicode strings on Windows and utf-8 strings on Linux. - -##Support for HTML and CSS standards - -Unfortunately **litehtml** is not fully compatible with HTML/CSS standards. There are lots of work to do to make **litehtml** as well as modern browsers. But **litehtml** supports most HTML tags and CSS properties. You can find the list of supported CSS properties in [this table](https://docs.google.com/spreadsheet/ccc?key=0AvHXl5n24PuhdHdELUdhaUl4OGlncXhDcDJuM1JpMnc&usp=sharing). In the most cases the html/css features supported by **litehtml** are enough. Right now **litehtml** supports the pages with very complex html/css designs. As example the pages created with [bootstrap framework](http://getbootstrap.com/) are usually well formated by **litehtml**. - -##Testing litehtml - -You can [download the simple browser](http://www.litehtml.com/download.html) (**litebrowser**) to test the **litehtml** rendering engine. - -The litebrowser source codes are available on GitHub: - * [For Windows](https://github.com/tordex/litebrowser) - * [For Linux](https://github.com/tordex/litebrowser-linux) - -##License - -**litehtml** is distributed under [New BSD License](http://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 think litehtml is amazing please consider a small donation: - -[  ](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UHBQG6EAFCRBA) - -Bitcoin: **1CS1174GVSLbP33TBp8RFwqPS6KmQK6kLY** - - +[](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. + +# Where litehtml can be used + +**litehtml** can be used when you need to show HTML formatted text or even to create a mini-browser, but using it as a full-featured HTML engine is not recommended. Usually you don't need something like WebKit to show simple HTML tooltips or HTML-formatted text, **litehtml** is much better for these as it's more lightweight and easier to integrate into your application. + +## HTML Parser + +**litehtml** uses the [gumbo-parser](https://github.com/google/gumbo-parser) to parse HTML. Gumbo is an implementation of the HTML5 parsing algorithm implemented as a pure C99 library with no outside dependencies. It's designed to serve as a building block for other tools and libraries such as linters, validators, templating languages, and refactoring and analysis tools. + +## 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. + +## Support for HTML and CSS standards + +Unfortunately **litehtml** is not fully compatible with HTML/CSS standards. There is lots of work to do to make **litehtml** work as well as modern browsers. But **litehtml** supports most HTML tags and CSS properties. You can find the list of supported CSS properties in [this table](https://docs.google.com/spreadsheet/ccc?key=0AvHXl5n24PuhdHdELUdhaUl4OGlncXhDcDJuM1JpMnc&usp=sharing). For most simple usecases the HTML/CSS features supported by **litehtml** are enough. Right now **litehtml** supports even some pages with very complex HTML/CSS designs. As an example the pages created with [bootstrap framework](http://getbootstrap.com/) are usually well formatted by **litehtml**. + +## Testing litehtml + +You can [download the simple browser](http://www.litehtml.com/download.html) (**litebrowser**) to test the **litehtml** rendering engine. + +The litebrowser source codes are available on GitHub: + * [For Windows](https://github.com/litehtml/litebrowser) + * [For Linux](https://github.com/litehtml/litebrowser-linux) + * [For Haiku](https://github.com/adamfowleruk/litebrowser-haiku) + +## License + +**litehtml** is distributed under [New BSD License](https://opensource.org/licenses/BSD-3-Clause). +The **gumbo-parser** is disributed under [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + +## Support litehtml project + +If you like the work **litehtml** is doing please consider a small donation: + +[  ](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UHBQG6EAFCRBA) [  ](https://www.patreon.com/tordex) + +Bitcoin: **1CS1174GVSLbP33TBp8RFwqPS6KmQK6kLY** + + diff --git a/src/plugins/litehtml_viewer/litehtml/borders.h b/src/plugins/litehtml_viewer/litehtml/borders.h @@ -148,6 +148,7 @@ namespace litehtml if (top_left_x < 0) top_left_x = 0; if (top_left_y < 0) top_left_y = 0; if (top_right_x < 0) top_right_x = 0; + if (top_right_y < 0) top_right_y = 0; if (bottom_right_x < 0) bottom_right_x = 0; if (bottom_right_y < 0) bottom_right_y = 0; if (bottom_left_x < 0) bottom_left_x = 0; diff --git a/src/plugins/litehtml_viewer/litehtml/css_selector.cpp b/src/plugins/litehtml_viewer/litehtml/css_selector.cpp @@ -7,6 +7,7 @@ void litehtml::css_element_selector::parse( const tstring& txt ) tstring::size_type el_end = txt.find_first_of(_t(".#[:")); m_tag = txt.substr(0, el_end); litehtml::lcase(m_tag); + m_attrs.clear(); while(el_end != tstring::npos) { if(txt[el_end] == _t('.')) diff --git a/src/plugins/litehtml_viewer/litehtml/document.cpp b/src/plugins/litehtml_viewer/litehtml/document.cpp @@ -21,6 +21,7 @@ #include "el_div.h" #include "el_font.h" #include "el_tr.h" +#include "el_li.h" #include <math.h> #include <stdio.h> #include <algorithm> @@ -60,7 +61,7 @@ litehtml::document::ptr litehtml::document::createFromUTF8(const char* str, lite // Create litehtml::elements. elements_vector root_elements; - doc->create_node(output->root, root_elements); + doc->create_node(output->root, root_elements, true); if (!root_elements.empty()) { doc->m_root = root_elements.back(); @@ -226,7 +227,7 @@ litehtml::uint_ptr litehtml::document::get_font( const tchar_t* name, int size, if(!size) { - size = container()->get_default_font_size(); + size = m_container->get_default_font_size(); } tchar_t strSize[20]; @@ -346,6 +347,10 @@ int litehtml::document::cvt_units( css_length& val, int fontSize, int size ) con case css_units_vmax: ret = (int)((double)std::max(m_media.height, m_media.width) * (double)val.val() / 100.0); break; + case css_units_rem: + ret = (int) ((double) m_root->get_font_size() * (double) val.val()); + val.set_value((float) ret, css_units_px); + break; default: ret = (int) val.val(); break; @@ -552,6 +557,9 @@ litehtml::element::ptr litehtml::document::create_element(const tchar_t* tag_nam } else if(!t_strcmp(tag_name, _t("font"))) { newTag = std::make_shared<litehtml::el_font>(this_doc); + } else if(!t_strcmp(tag_name, _t("li"))) + { + newTag = std::make_shared<litehtml::el_li>(this_doc); } else { newTag = std::make_shared<litehtml::html_tag>(this_doc); @@ -640,8 +648,9 @@ void litehtml::document::add_media_list( media_query_list::ptr list ) } } -void litehtml::document::create_node(GumboNode* node, elements_vector& elements) +void litehtml::document::create_node(void* gnode, elements_vector& elements, bool parseTextNode) { + GumboNode* node = (GumboNode*)gnode; switch (node->type) { case GUMBO_NODE_ELEMENT: @@ -671,13 +680,17 @@ void litehtml::document::create_node(GumboNode* node, elements_vector& elements) ret = create_element(litehtml_from_utf8(strA.c_str()), attrs); } } + if (!strcmp(tag, "script")) + { + parseTextNode = false; + } if (ret) { elements_vector child; for (unsigned int i = 0; i < node->v.element.children.length; i++) { child.clear(); - create_node(static_cast<GumboNode*> (node->v.element.children.data[i]), child); + create_node(static_cast<GumboNode*> (node->v.element.children.data[i]), child, parseTextNode); std::for_each(child.begin(), child.end(), [&ret](element::ptr& el) { @@ -693,6 +706,11 @@ void litehtml::document::create_node(GumboNode* node, elements_vector& elements) { std::wstring str; std::wstring str_in = (const wchar_t*) (utf8_to_wchar(node->v.text.text)); + if (!parseTextNode) + { + elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str_in.c_str()), shared_from_this())); + break; + } ucode_t c; for (size_t i = 0; i < str_in.length(); i++) { @@ -775,8 +793,15 @@ void litehtml::document::fix_tables_layout() case display_table_footer_group: case display_table_row_group: case display_table_header_group: - fix_table_parent(el_ptr, display_table, _t("table")); - fix_table_children(el_ptr, display_table_row, _t("table-row")); + { + element::ptr parent = el_ptr->parent(); + if (parent) + { + if (parent->get_display() != display_inline_table) + fix_table_parent(el_ptr, display_table, _t("table")); + } + fix_table_children(el_ptr, display_table_row, _t("table-row")); + } break; case display_table_row: fix_table_parent(el_ptr, display_table_row_group, _t("table-row-group")); @@ -928,3 +953,54 @@ void litehtml::document::fix_table_parent(element::ptr& el_ptr, style_display di } } } + +void litehtml::document::append_children_from_string(element& parent, const tchar_t* str) +{ + append_children_from_utf8(parent, litehtml_to_utf8(str)); +} + +void litehtml::document::append_children_from_utf8(element& parent, const char* str) +{ + // parent must belong to this document + if (parent.get_document().get() != this) + { + return; + } + + // parse document into GumboOutput + GumboOutput* output = gumbo_parse((const char*) str); + + // Create litehtml::elements. + elements_vector child_elements; + create_node(output->root, child_elements, true); + + // Destroy GumboOutput + gumbo_destroy_output(&kGumboDefaultOptions, output); + + // Let's process created elements tree + for (litehtml::element::ptr child : child_elements) + { + // Add the child element to parent + parent.appendChild(child); + + // apply master CSS + child->apply_stylesheet(m_context->master_css()); + + // parse elements attributes + child->parse_attributes(); + + // Apply parsed styles. + child->apply_stylesheet(m_styles); + + // Parse applied styles in the elements + child->parse_styles(); + + // Now the m_tabular_elements is filled with tabular elements. + // We have to check the tabular elements for missing table elements + // and create the anonymous boxes in visual table layout + fix_tables_layout(); + + // Fanaly initialize elements + child->init(); + } +} +\ No newline at end of file diff --git a/src/plugins/litehtml_viewer/litehtml/document.h b/src/plugins/litehtml_viewer/litehtml/document.h @@ -4,7 +4,6 @@ #include "style.h" #include "types.h" #include "context.h" -#include "gumbo.h" namespace litehtml { @@ -90,7 +89,6 @@ namespace litehtml bool on_mouse_leave(position::vector& redraw_boxes); litehtml::element::ptr create_element(const tchar_t* tag_name, const string_map& attributes); element::ptr root(); - const element::ptr over_element() const; void get_fixed_boxes(position::vector& fixed_boxes); void add_fixed_box(const position& pos); void add_media_list(media_query_list::ptr list); @@ -98,6 +96,10 @@ namespace litehtml bool lang_changed(); bool match_lang(const tstring & lang); void add_tabular(const element::ptr& el); + const element::const_ptr get_over_element() const { return m_over_element; } + + void append_children_from_string(element& parent, const tchar_t* str); + void append_children_from_utf8(element& parent, const char* str); static litehtml::document::ptr createFromString(const tchar_t* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles = 0); static litehtml::document::ptr createFromUTF8(const char* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles = 0); @@ -105,7 +107,7 @@ namespace litehtml private: litehtml::uint_ptr add_font(const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm); - void create_node(GumboNode* node, elements_vector& elements); + void create_node(void* gnode, elements_vector& elements, bool parseTextNode); bool update_media_lists(const media_features& features); void fix_tables_layout(); void fix_table_children(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str); @@ -116,10 +118,6 @@ namespace litehtml { return m_root; } - inline const element::ptr document::over_element() const - { - return m_over_element; - } inline void document::add_tabular(const element::ptr& el) { m_tabular_elements.push_back(el); diff --git a/src/plugins/litehtml_viewer/litehtml/el_image.cpp b/src/plugins/litehtml_viewer/litehtml/el_image.cpp @@ -17,6 +17,24 @@ void litehtml::el_image::get_content_size( size& sz, int max_width ) get_document()->container()->get_image_size(m_src.c_str(), 0, sz); } +int litehtml::el_image::calc_max_height(int image_height) +{ + document::ptr doc = get_document(); + int percentSize = 0; + if (m_css_max_height.units() == css_units_percentage) + { + auto el_parent = parent(); + if (el_parent) + { + if (!el_parent->get_predefined_height(percentSize)) + { + return image_height; + } + } + } + return doc->cvt_units(m_css_max_height, m_font_size, percentSize); +} + int litehtml::el_image::line_height() const { return height(); @@ -48,7 +66,7 @@ int litehtml::el_image::render( int x, int y, int max_width, bool second_pass ) m_pos.height = sz.height; m_pos.width = sz.width; - // check for max-height + // check for max-width if(!m_css_max_width.is_predefined()) { int max_width = doc->cvt_units(m_css_max_width, m_font_size, parent_width); @@ -68,7 +86,7 @@ int litehtml::el_image::render( int x, int y, int max_width, bool second_pass ) // check for max-height if(!m_css_max_height.is_predefined()) { - int max_height = doc->cvt_units(m_css_max_height, m_font_size); + int max_height = calc_max_height(sz.height); if(m_pos.height > max_height) { m_pos.height = max_height; @@ -91,7 +109,7 @@ int litehtml::el_image::render( int x, int y, int max_width, bool second_pass ) // check for max-height if(!m_css_max_height.is_predefined()) { - int max_height = doc->cvt_units(m_css_max_height, m_font_size); + int max_height = calc_max_height(sz.height); if(m_pos.height > max_height) { m_pos.height = max_height; @@ -138,7 +156,7 @@ int litehtml::el_image::render( int x, int y, int max_width, bool second_pass ) // check for max-height if(!m_css_max_height.is_predefined()) { - int max_height = doc->cvt_units(m_css_max_height, m_font_size); + int max_height = calc_max_height(sz.height); if(m_pos.height > max_height) { m_pos.height = max_height; diff --git a/src/plugins/litehtml_viewer/litehtml/el_image.h b/src/plugins/litehtml_viewer/litehtml/el_image.h @@ -20,6 +20,8 @@ namespace litehtml virtual void parse_styles(bool is_reparse = false) override; virtual void draw(uint_ptr hdc, int x, int y, const position* clip) override; virtual void get_content_size(size& sz, int max_width) override; + private: + int calc_max_height(int image_height); }; } diff --git a/src/plugins/litehtml_viewer/litehtml/el_li.cpp b/src/plugins/litehtml_viewer/litehtml/el_li.cpp @@ -0,0 +1,38 @@ +#include "html.h" +#include "el_li.h" +#include "document.h" + +litehtml::el_li::el_li(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc) +{ +} + +litehtml::el_li::~el_li() +{ + +} + +int litehtml::el_li::render(int x, int y, int max_width, bool second_pass) +{ + if (m_list_style_type >= list_style_type_armenian && !m_index_initialized) + { + if (auto p = parent()) + { + tchar_t val[2] = { 1, 0 }; + for (int i = 0, n = (int)p->get_children_count(); i < n; ++i) + { + auto child = p->get_child(i); + if (child.get() == this) + { + set_attr(_t("list_index"), val); + break; + } + else if (!t_strcmp(child->get_tagName(), _t("li"))) + ++val[0]; + } + } + + m_index_initialized = true; + } + + return html_tag::render(x, y, max_width, second_pass); +} diff --git a/src/plugins/litehtml_viewer/litehtml/el_li.h b/src/plugins/litehtml_viewer/litehtml/el_li.h @@ -0,0 +1,21 @@ +#ifndef LH_EL_LI_H +#define LH_EL_LI_H + +#include "html_tag.h" + +namespace litehtml +{ + class el_li : public html_tag + { + public: + el_li(const std::shared_ptr<litehtml::document>& doc); + virtual ~el_li(); + + virtual int render(int x, int y, int max_width, bool second_pass = false) override; + + private: + bool m_index_initialized = false; + }; +} + +#endif // LH_EL_LI_H diff --git a/src/plugins/litehtml_viewer/litehtml/element.cpp b/src/plugins/litehtml_viewer/litehtml/element.cpp @@ -73,6 +73,7 @@ bool litehtml::element::is_inline_box() const { style_display d = get_display(); if( d == display_inline || + d == display_inline_table || d == display_inline_block || d == display_inline_text) { @@ -376,7 +377,7 @@ void litehtml::element::on_click() LITEHTML_EMPTY_FUNC void litehtml::element::init_font() LITEHTML_EMPTY_FUNC void litehtml::element::get_inline_boxes( position::vector& boxes ) LITEHTML_EMPTY_FUNC void litehtml::element::parse_styles( bool is_reparse /*= false*/ ) LITEHTML_EMPTY_FUNC -const litehtml::tchar_t* litehtml::element::get_attr( const tchar_t* name, const tchar_t* def /*= 0*/ ) LITEHTML_RETURN_FUNC(def) +const litehtml::tchar_t* litehtml::element::get_attr( const tchar_t* name, const tchar_t* def /*= 0*/ ) const LITEHTML_RETURN_FUNC(def) bool litehtml::element::is_white_space() const LITEHTML_RETURN_FUNC(false) bool litehtml::element::is_body() const LITEHTML_RETURN_FUNC(false) bool litehtml::element::is_break() const LITEHTML_RETURN_FUNC(false) diff --git a/src/plugins/litehtml_viewer/litehtml/element.h b/src/plugins/litehtml_viewer/litehtml/element.h @@ -17,8 +17,9 @@ namespace litehtml friend class el_table; friend class document; public: - typedef std::shared_ptr<litehtml::element> ptr; - typedef std::weak_ptr<litehtml::element> weak_ptr; + typedef std::shared_ptr<litehtml::element> ptr; + typedef std::shared_ptr<const litehtml::element> const_ptr; + typedef std::weak_ptr<litehtml::element> weak_ptr; protected: std::weak_ptr<element> m_parent; std::weak_ptr<litehtml::document> m_doc; @@ -130,7 +131,7 @@ namespace litehtml virtual css_length get_css_height() const; virtual void set_attr(const tchar_t* name, const tchar_t* val); - virtual const tchar_t* get_attr(const tchar_t* name, const tchar_t* def = 0); + virtual const tchar_t* get_attr(const tchar_t* name, const tchar_t* def = 0) const; virtual void apply_stylesheet(const litehtml::css& stylesheet); virtual void refresh_styles(); virtual bool is_white_space() const; diff --git a/src/plugins/litehtml_viewer/litehtml/html.cpp b/src/plugins/litehtml_viewer/litehtml/html.cpp @@ -7,12 +7,12 @@ void litehtml::trim(tstring &s) tstring::size_type pos = s.find_first_not_of(_t(" \n\r\t")); if(pos != tstring::npos) { - s.erase(s.begin(), s.begin() + pos); + s.erase(s.begin(), s.begin() + pos); } pos = s.find_last_not_of(_t(" \n\r\t")); if(pos != tstring::npos) { - s.erase(s.begin() + pos + 1, s.end()); + s.erase(s.begin() + pos + 1, s.end()); } } diff --git a/src/plugins/litehtml_viewer/litehtml/html.h b/src/plugins/litehtml_viewer/litehtml/html.h @@ -26,6 +26,8 @@ namespace litehtml list_style_type marker_type; web_color color; position pos; + int index; + uint_ptr font; }; // call back interface to draw text, images and other elements diff --git a/src/plugins/litehtml_viewer/litehtml/html_tag.cpp b/src/plugins/litehtml_viewer/litehtml/html_tag.cpp @@ -7,6 +7,7 @@ #include <algorithm> #include <locale> #include "el_before_after.h" +#include "num_cvt.h" litehtml::html_tag::html_tag(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc) { @@ -81,10 +82,9 @@ void litehtml::html_tag::set_attr( const tchar_t* name, const tchar_t* val ) if(name && val) { tstring s_val = name; - std::locale lc = std::locale::global(std::locale("")); for(size_t i = 0; i < s_val.length(); i++) { - s_val[i] = std::tolower(s_val[i], lc); + s_val[i] = std::tolower(s_val[i], std::locale::classic()); } m_attrs[s_val] = val; @@ -96,7 +96,7 @@ void litehtml::html_tag::set_attr( const tchar_t* name, const tchar_t* val ) } } -const litehtml::tchar_t* litehtml::html_tag::get_attr( const tchar_t* name, const tchar_t* def ) +const litehtml::tchar_t* litehtml::html_tag::get_attr( const tchar_t* name, const tchar_t* def ) const { string_map::const_iterator attr = m_attrs.find(name); if(attr != m_attrs.end()) @@ -353,6 +353,7 @@ void litehtml::html_tag::parse_styles(bool is_reparse) } } else if (m_display == display_table || + m_display == display_inline_table || m_display == display_table_caption || m_display == display_table_cell || m_display == display_table_column || @@ -1179,12 +1180,18 @@ void litehtml::html_tag::get_line_left_right( int y, int def_right, int& ln_left el_parent->get_line_left_right(y + m_pos.y, def_right + m_pos.x, ln_left, ln_right); } ln_right -= m_pos.x; - ln_left -= 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; + } + } } } @@ -2017,10 +2024,9 @@ bool litehtml::html_tag::is_break() const void litehtml::html_tag::set_tagName( const tchar_t* tag ) { tstring s_val = tag; - std::locale lc = std::locale::global(std::locale("")); for(size_t i = 0; i < s_val.length(); i++) { - s_val[i] = std::tolower(s_val[i], lc); + s_val[i] = std::tolower(s_val[i], std::locale::classic()); } m_tag = s_val; } @@ -2306,6 +2312,7 @@ int litehtml::html_tag::place_element(const element::ptr &el, int max_width) switch(el->get_display()) { case display_inline_block: + case display_inline_table: ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.right); break; case display_block: @@ -2942,13 +2949,26 @@ void litehtml::html_tag::draw_list_marker( uint_ptr hdc, const position &pos ) lm.baseurl = 0; } - int ln_height = line_height(); int sz_font = get_font_size(); lm.pos.x = pos.x; - lm.pos.width = sz_font - sz_font * 2 / 3; - lm.pos.height = sz_font - sz_font * 2 / 3; - lm.pos.y = pos.y + ln_height / 2 - lm.pos.height / 2; + lm.pos.width = sz_font - sz_font * 2 / 3; + lm.color = get_color(_t("color"), true, web_color(0, 0, 0)); + lm.marker_type = m_list_style_type; + lm.font = get_font(); + + if (m_list_style_type >= list_style_type_armenian) + { + lm.pos.y = pos.y; + lm.pos.height = pos.height; + lm.index = get_attr(_t("list_index"), _t(""))[0]; + } + else + { + lm.pos.height = sz_font - sz_font * 2 / 3; + lm.pos.y = pos.y + ln_height / 2 - lm.pos.height / 2; + lm.index = -1; + } if(img_size.width && img_size.height) { @@ -2964,14 +2984,88 @@ void litehtml::html_tag::draw_list_marker( uint_ptr hdc, const position &pos ) lm.pos.width = img_size.width; lm.pos.height = img_size.height; } - if(m_list_style_position == list_style_position_outside) + + if (m_list_style_position == list_style_position_outside) { - lm.pos.x -= sz_font; + if (m_list_style_type >= list_style_type_armenian) + { + auto tw_space = get_document()->container()->text_width(_t(" "), lm.font); + lm.pos.x = pos.x - tw_space * 2; + lm.pos.width = tw_space; + } + else + { + lm.pos.x -= sz_font; + } } - lm.color = get_color(_t("color"), true, web_color(0, 0, 0)); - lm.marker_type = m_list_style_type; - get_document()->container()->draw_list_marker(hdc, lm); + if (m_list_style_type >= list_style_type_armenian) + { + auto marker_text = get_list_marker_text(lm.index); + lm.pos.height = ln_height; + if (marker_text.empty()) + { + get_document()->container()->draw_list_marker(hdc, lm); + } + else + { + marker_text += _t("."); + auto tw = get_document()->container()->text_width(marker_text.c_str(), lm.font); + auto text_pos = lm.pos; + text_pos.move_to(text_pos.right() - tw, text_pos.y); + text_pos.width = tw; + get_document()->container()->draw_text(hdc, marker_text.c_str(), lm.font, lm.color, text_pos); + } + } + else + { + get_document()->container()->draw_list_marker(hdc, lm); + } +} + +litehtml::tstring litehtml::html_tag::get_list_marker_text(int index) +{ + switch (m_list_style_type) + { + case litehtml::list_style_type_decimal: + return t_to_string(index); + case litehtml::list_style_type_decimal_leading_zero: + { + auto txt = t_to_string(index); + if (txt.length() == 1) + { + txt = _t("0") + txt; + } + return txt; + } + case litehtml::list_style_type_lower_latin: + case litehtml::list_style_type_lower_alpha: + return num_cvt::to_latin_lower(index); + case litehtml::list_style_type_lower_greek: + return num_cvt::to_greek_lower(index); + case litehtml::list_style_type_upper_alpha: + case litehtml::list_style_type_upper_latin: + return num_cvt::to_latin_upper(index); + case litehtml::list_style_type_lower_roman: + return num_cvt::to_roman_lower(index); + case litehtml::list_style_type_upper_roman: + return num_cvt::to_roman_upper(index); + case litehtml::list_style_type_armenian: + break; + case litehtml::list_style_type_georgian: + break; + case litehtml::list_style_type_hebrew: + break; + case litehtml::list_style_type_hiragana: + break; + case litehtml::list_style_type_hiragana_iroha: + break; + case litehtml::list_style_type_katakana: + break; + case litehtml::list_style_type_katakana_iroha: + break; + } + return _t(""); } void litehtml::html_tag::draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex ) @@ -3920,9 +4014,6 @@ int litehtml::html_tag::render_box(int x, int y, int max_width, bool second_pass { int parent_width = max_width; - if (max_width <= 0) - return 0; - calc_outlines(parent_width); m_pos.clear(); @@ -4160,12 +4251,12 @@ int litehtml::html_tag::render_box(int x, int y, int max_width, bool second_pass if (ret_width < max_width && !second_pass && have_parent()) { if (m_display == display_inline_block || - m_css_width.is_predefined() && + (m_css_width.is_predefined() && (m_float != float_none || m_display == display_table || m_el_position == element_position_absolute || m_el_position == element_position_fixed - ) + )) ) { render(x, y, ret_width, true); diff --git a/src/plugins/litehtml_viewer/litehtml/html_tag.h b/src/plugins/litehtml_viewer/litehtml/html_tag.h @@ -138,7 +138,7 @@ namespace litehtml virtual overflow get_overflow() const override; virtual void set_attr(const tchar_t* name, const tchar_t* val) override; - virtual const tchar_t* get_attr(const tchar_t* name, const tchar_t* def = 0) override; + virtual const tchar_t* get_attr(const tchar_t* name, const tchar_t* def = 0) const override; virtual void apply_stylesheet(const litehtml::css& stylesheet) override; virtual void refresh_styles() override; @@ -229,6 +229,7 @@ namespace litehtml void parse_background(); void init_background_paint( position pos, background_paint &bg_paint, const background* bg ); void draw_list_marker( uint_ptr hdc, const position &pos ); + tstring get_list_marker_text(int index); void parse_nth_child_params( tstring param, int &num, int &off ); void remove_before_after(); litehtml::element::ptr get_element_before(); diff --git a/src/plugins/litehtml_viewer/litehtml/litehtml.h b/src/plugins/litehtml_viewer/litehtml/litehtml.h @@ -1,10 +1,10 @@ #ifndef LITEHTML_H #define LITEHTML_H -#include "litehtml/html.h" -#include "litehtml/document.h" -#include "litehtml/html_tag.h" -#include "litehtml/stylesheet.h" -#include "litehtml/element.h" +#include <litehtml/html.h> +#include <litehtml/document.h> +#include <litehtml/html_tag.h> +#include <litehtml/stylesheet.h> +#include <litehtml/element.h> #endif // LITEHTML_H diff --git a/src/plugins/litehtml_viewer/litehtml/media_query.cpp b/src/plugins/litehtml_viewer/litehtml/media_query.cpp @@ -245,7 +245,7 @@ bool litehtml::media_query_expression::check( const media_features& features ) c } break; case media_feature_min_device_height: - if(features.device_height <= val) + if(features.device_height >= val) { return true; } diff --git a/src/plugins/litehtml_viewer/litehtml/num_cvt.cpp b/src/plugins/litehtml_viewer/litehtml/num_cvt.cpp @@ -0,0 +1,109 @@ +#include "num_cvt.h" +#include "types.h" +#include "utf8_strings.h" +#include <vector> + +static std::vector<litehtml::tchar_t> latin_lower = { _t('a'), _t('b'), _t('c'), _t('d'), _t('e'), _t('f'), _t('g'), _t('h'), _t('i'), _t('j'), _t('k'), _t('l'), _t('m'), _t('n'), _t('o'), _t('p'), _t('q'), _t('r'), _t('s'), _t('t'), _t('u'), _t('v'), _t('w'), _t('x'), _t('y'), _t('z') }; +static std::vector<litehtml::tchar_t> latin_upper = { _t('A'), _t('B'), _t('C'), _t('D'), _t('E'), _t('F'), _t('G'), _t('H'), _t('I'), _t('J'), _t('K'), _t('L'), _t('M'), _t('N'), _t('O'), _t('P'), _t('Q'), _t('R'), _t('S'), _t('T'), _t('U'), _t('V'), _t('W'), _t('X'), _t('Y'), _t('Z') }; +static std::vector<std::wstring> greek_lower = { L"α", L"β", L"γ", L"δ", L"ε", L"ζ", L"η", L"θ", L"ι", L"κ", L"λ", L"μ", L"ν", L"ξ", L"ο", L"π", L"ρ", L"σ", L"τ", L"υ", L"φ", L"χ", L"ψ", L"ω" }; + +static litehtml::tstring to_mapped_alpha(int num, const std::vector<litehtml::tchar_t>& map) +{ + int dividend = num; + litehtml::tstring out; + int modulo; + + while (dividend > 0) + { + modulo = (dividend - 1) % map.size(); + out = map[modulo] + out; + dividend = (int)((dividend - modulo) / map.size()); + } + + return out; +} + +static litehtml::tstring to_mapped_alpha(int num, const std::vector<std::wstring>& map) +{ + int dividend = num; + litehtml::tstring out; + int modulo; + + while (dividend > 0) + { + modulo = (dividend - 1) % map.size(); + out = litehtml_from_wchar(map[modulo]).c_str() + out; + dividend = (int)((dividend - modulo) / map.size()); + } + + return out; +} + +litehtml::tstring litehtml::num_cvt::to_latin_lower(int val) +{ + return to_mapped_alpha(val, latin_lower); +} + +litehtml::tstring litehtml::num_cvt::to_latin_upper(int val) +{ + return to_mapped_alpha(val, latin_upper); +} + +litehtml::tstring litehtml::num_cvt::to_greek_lower(int val) +{ + return to_mapped_alpha(val, greek_lower); +} + +litehtml::tstring litehtml::num_cvt::to_roman_lower(int value) +{ + struct romandata_t { int value; const litehtml::tchar_t* numeral; }; + const struct romandata_t romandata[] = + { + { 1000, _t("m") }, { 900, _t("cm" )}, + { 500, _t("d") }, { 400, _t("cd") }, + { 100, _t("c") }, { 90, _t("xc") }, + { 50, _t("l") }, { 40, _t("xl") }, + { 10, _t("x") }, { 9, _t("ix") }, + { 5, _t("v") }, { 4, _t("iv") }, + { 1, _t("i") }, + { 0, NULL } // end marker + }; + + litehtml::tstring result; + for (const romandata_t* current = romandata; current->value > 0; ++current) + { + while (value >= current->value) + { + result += current->numeral; + value -= current->value; + } + } + return result; +} + +litehtml::tstring litehtml::num_cvt::to_roman_upper(int value) +{ + struct romandata_t { int value; const litehtml::tchar_t* numeral; }; + const struct romandata_t romandata[] = + { + { 1000, _t("M") }, { 900, _t("CM") }, + { 500, _t("D") }, { 400, _t("CD") }, + { 100, _t("C") }, { 90, _t("XC") }, + { 50, _t("L") }, { 40, _t("XL") }, + { 10, _t("X") }, { 9, _t("IX") }, + { 5, _t("V") }, { 4, _t("IV") }, + { 1, _t("I") }, + { 0, NULL } // end marker + }; + + litehtml::tstring result; + for (const romandata_t* current = romandata; current->value > 0; ++current) + { + while (value >= current->value) + { + result += current->numeral; + value -= current->value; + } + } + return result; +} diff --git a/src/plugins/litehtml_viewer/litehtml/num_cvt.h b/src/plugins/litehtml_viewer/litehtml/num_cvt.h @@ -0,0 +1,19 @@ +#ifndef NUM_CVT_H +#define NUM_CVT_H + +#include <string> +#include "os_types.h" + +namespace litehtml +{ + namespace num_cvt + { + litehtml::tstring to_latin_lower(int val); + litehtml::tstring to_latin_upper(int val); + litehtml::tstring to_greek_lower(int val); + litehtml::tstring to_roman_lower(int value); + litehtml::tstring to_roman_upper(int value); + } +} + +#endif // NUM_CVT_H +\ No newline at end of file diff --git a/src/plugins/litehtml_viewer/litehtml/os_types.h b/src/plugins/litehtml_viewer/litehtml/os_types.h @@ -3,7 +3,7 @@ namespace litehtml { -#if defined( WIN32 ) || defined( WINCE ) +#if defined( WIN32 ) || defined( _WIN32 ) || defined( WINCE ) #ifndef LITEHTML_UTF8 @@ -25,6 +25,7 @@ namespace litehtml #define t_strstr wcsstr #define t_tolower towlower #define t_isdigit iswdigit + #define t_to_string(val) std::to_wstring(val) #else @@ -46,22 +47,22 @@ namespace litehtml #define t_strstr strstr #define t_tolower tolower #define t_isdigit isdigit + #define t_to_string(val) std::to_string(val) #endif -// #ifdef _WIN64 -// typedef unsigned __int64 uint_ptr; -// #else -// typedef unsigned int uint_ptr; -// #endif - typedef void* uint_ptr; + #ifdef _WIN64 + typedef unsigned __int64 uint_ptr; + #else + typedef unsigned int uint_ptr; + #endif #else #define LITEHTML_UTF8 typedef std::string tstring; typedef char tchar_t; - typedef void* uint_ptr; + typedef std::uintptr_t uint_ptr; typedef std::stringstream tstringstream; #define _t(quote) quote @@ -80,6 +81,7 @@ namespace litehtml #define t_strstr strstr #define t_tolower tolower #define t_isdigit isdigit + #define t_to_string(val) std::to_string(val) #endif } diff --git a/src/plugins/litehtml_viewer/litehtml/style.cpp b/src/plugins/litehtml_viewer/litehtml/style.cpp @@ -28,7 +28,7 @@ litehtml::style::~style() void litehtml::style::parse( const tchar_t* txt, const tchar_t* baseurl ) { std::vector<tstring> properties; - split_string(txt, properties, _t(";")); + split_string(txt, properties, _t(";"), _t(""), _t("\"'")); for(std::vector<tstring>::const_iterator i = properties.begin(); i != properties.end(); i++) { @@ -41,14 +41,12 @@ void litehtml::style::parse_property( const tstring& txt, const tchar_t* baseurl tstring::size_type pos = txt.find_first_of(_t(":")); if(pos != tstring::npos) { - tstring name = txt.substr(0, pos); + tstring name = txt.substr(0, pos); tstring val = txt.substr(pos + 1); - trim(name); + trim(name); lcase(name); trim(val); - lcase(name); - if(!name.empty() && !val.empty()) { string_vector vals; @@ -60,13 +58,7 @@ void litehtml::style::parse_property( const tstring& txt, const tchar_t* baseurl { trim(vals[0]); lcase(vals[1]); - if(vals[1] == _t("important")) - { - add_property(name.c_str(), vals[0].c_str(), baseurl, true); - } else - { - add_property(name.c_str(), vals[0].c_str(), baseurl, false); - } + add_property(name.c_str(), vals[0].c_str(), baseurl, vals[1] == _t("important")); } } } @@ -104,12 +96,12 @@ void litehtml::style::add_property( const tchar_t* name, const tchar_t* val, con split_string(val, tokens, _t(" ")); if(tokens.size() == 1) { - add_property(_t("-litehtml-border-spacing-x"), tokens[0].c_str(), baseurl, important); - add_property(_t("-litehtml-border-spacing-y"), tokens[0].c_str(), baseurl, important); + add_parsed_property(_t("-litehtml-border-spacing-x"), tokens[0].c_str(), important); + add_parsed_property(_t("-litehtml-border-spacing-y"), tokens[0].c_str(), important); } else if(tokens.size() == 2) { - add_property(_t("-litehtml-border-spacing-x"), tokens[0].c_str(), baseurl, important); - add_property(_t("-litehtml-border-spacing-y"), tokens[1].c_str(), baseurl, important); + add_parsed_property(_t("-litehtml-border-spacing-x"), tokens[0].c_str(), important); + add_parsed_property(_t("-litehtml-border-spacing-y"), tokens[1].c_str(), important); } } else @@ -315,7 +307,7 @@ void litehtml::style::add_property( const tchar_t* name, const tchar_t* val, con add_property(_t("border-bottom-left-radius-y"), tokens[3].c_str(), baseurl, important); } } - + else // Parse list-style shorthand properties if(!t_strcmp(name, _t("list-style"))) diff --git a/src/plugins/litehtml_viewer/litehtml/types.h b/src/plugins/litehtml_viewer/litehtml/types.h @@ -182,7 +182,7 @@ namespace litehtml draw_positioned, }; -#define style_display_strings _t("none;block;inline;inline-block;inline-table;list-item;table;table-caption;table-cell;table-column;table-column-group;table-footer-group;table-header-group;table-row;table-row-group") +#define style_display_strings _t("none;block;inline;inline-block;inline-table;list-item;table;table-caption;table-cell;table-column;table-column-group;table-footer-group;table-header-group;table-row;table-row-group;inline-text") enum style_display { @@ -246,7 +246,7 @@ namespace litehtml font_variant_italic }; -#define font_weight_strings _t("normal;bold;bolder;lighter100;200;300;400;500;600;700") +#define font_weight_strings _t("normal;bold;bolder;lighter;100;200;300;400;500;600;700") enum font_weight { @@ -356,7 +356,7 @@ namespace litehtml clear_both }; -#define css_units_strings _t("none;%;in;cm;mm;em;ex;pt;pc;px;dpi;dpcm;vw;vh;vmin;vmax") +#define css_units_strings _t("none;%;in;cm;mm;em;ex;pt;pc;px;dpi;dpcm;vw;vh;vmin;vmax;rem") enum css_units { @@ -376,6 +376,7 @@ namespace litehtml css_units_vh, css_units_vmin, css_units_vmax, + css_units_rem, }; #define background_attachment_strings _t("scroll;fixed") diff --git a/src/plugins/litehtml_viewer/litehtml/utf8_strings.cpp b/src/plugins/litehtml_viewer/litehtml/utf8_strings.cpp @@ -61,7 +61,7 @@ litehtml::ucode_t litehtml::utf8_to_wchar::get_char() return '?'; } -litehtml::wchar_to_utf8::wchar_to_utf8(const wchar_t* val) +litehtml::wchar_to_utf8::wchar_to_utf8(const std::wstring& val) { unsigned int code; for (int i = 0; val[i]; i++) diff --git a/src/plugins/litehtml_viewer/litehtml/utf8_strings.h b/src/plugins/litehtml_viewer/litehtml/utf8_strings.h @@ -30,21 +30,26 @@ namespace litehtml { std::string m_str; public: - wchar_to_utf8(const wchar_t* val); + wchar_to_utf8(const std::wstring& val); operator const char*() const { return m_str.c_str(); } + + const char* c_str() const + { + return m_str.c_str(); + } }; #ifdef LITEHTML_UTF8 #define litehtml_from_utf8(str) str #define litehtml_to_utf8(str) str -#define litehtml_from_wchar(str) wchar_to_utf8(str) +#define litehtml_from_wchar(str) litehtml::wchar_to_utf8(str) #else -#define litehtml_from_utf8(str) utf8_to_wchar(str) +#define litehtml_from_utf8(str) litehtml::utf8_to_wchar(str) #define litehtml_from_wchar(str) str -#define litehtml_to_utf8(str) wchar_to_utf8(str) +#define litehtml_to_utf8(str) litehtml::wchar_to_utf8(str) #endif }