[Commits] [SCM] claws branch, master, updated. 4.1.1-94-gcf2e2a323

jonathan at claws-mail.org jonathan at claws-mail.org
Sun Oct 22 11:51:33 UTC 2023


The branch, master has been updated
       via  cf2e2a3236893511b498412b0f1f79f91c962d29 (commit)
      from  99db9602c30d19ba5e68b5c87b45c41166c74d46 (commit)

Summary of changes:
 src/plugins/litehtml_viewer/litehtml/Makefile.am   |  143 +-
 src/plugins/litehtml_viewer/litehtml/attributes.h  |   35 -
 .../litehtml_viewer/litehtml/background.cpp        |   79 -
 src/plugins/litehtml_viewer/litehtml/background.h  |   51 +-
 src/plugins/litehtml_viewer/litehtml/borders.h     |   28 +-
 src/plugins/litehtml_viewer/litehtml/box.cpp       |  434 --
 src/plugins/litehtml_viewer/litehtml/box.h         |  120 -
 src/plugins/litehtml_viewer/litehtml/codepoint.cpp |   82 +
 src/plugins/litehtml_viewer/litehtml/codepoint.h   |   51 +
 src/plugins/litehtml_viewer/litehtml/context.cpp   |   12 -
 src/plugins/litehtml_viewer/litehtml/context.h     |   20 -
 .../litehtml_viewer/litehtml/css_borders.cpp       |    7 +
 .../litehtml_viewer/litehtml/css_length.cpp        |   47 +-
 src/plugins/litehtml_viewer/litehtml/css_length.h  |   42 +-
 src/plugins/litehtml_viewer/litehtml/css_margins.h |   13 +-
 src/plugins/litehtml_viewer/litehtml/css_offsets.h |   13 +-
 .../litehtml_viewer/litehtml/css_position.h        |   29 +-
 .../litehtml_viewer/litehtml/css_properties.cpp    |  456 ++
 .../litehtml_viewer/litehtml/css_properties.h      |  643 +++
 .../litehtml_viewer/litehtml/css_selector.cpp      |  261 +-
 .../litehtml_viewer/litehtml/css_selector.h        |   56 +-
 src/plugins/litehtml_viewer/litehtml/document.cpp  |  586 +--
 src/plugins/litehtml_viewer/litehtml/document.h    |   95 +-
 .../litehtml/document_container.cpp                |   44 +
 .../litehtml_viewer/litehtml/document_container.h  |   71 +
 src/plugins/litehtml_viewer/litehtml/el_anchor.cpp |   11 +-
 src/plugins/litehtml_viewer/litehtml/el_anchor.h   |    7 +-
 src/plugins/litehtml_viewer/litehtml/el_base.cpp   |    9 +-
 src/plugins/litehtml_viewer/litehtml/el_base.h     |    5 +-
 .../litehtml_viewer/litehtml/el_before_after.cpp   |  146 +-
 .../litehtml_viewer/litehtml/el_before_after.h     |   17 +-
 src/plugins/litehtml_viewer/litehtml/el_body.cpp   |    5 -
 src/plugins/litehtml_viewer/litehtml/el_body.h     |    5 +-
 src/plugins/litehtml_viewer/litehtml/el_break.cpp  |    5 -
 src/plugins/litehtml_viewer/litehtml/el_break.h    |    7 +-
 src/plugins/litehtml_viewer/litehtml/el_cdata.cpp  |   13 +-
 src/plugins/litehtml_viewer/litehtml/el_cdata.h    |    9 +-
 .../litehtml_viewer/litehtml/el_comment.cpp        |   12 +-
 src/plugins/litehtml_viewer/litehtml/el_comment.h  |   15 +-
 src/plugins/litehtml_viewer/litehtml/el_div.cpp    |   11 +-
 src/plugins/litehtml_viewer/litehtml/el_div.h      |    5 +-
 src/plugins/litehtml_viewer/litehtml/el_font.cpp   |   33 +-
 src/plugins/litehtml_viewer/litehtml/el_font.h     |    5 +-
 src/plugins/litehtml_viewer/litehtml/el_image.cpp  |  233 +-
 src/plugins/litehtml_viewer/litehtml/el_image.h    |   23 +-
 src/plugins/litehtml_viewer/litehtml/el_li.cpp     |   38 -
 src/plugins/litehtml_viewer/litehtml/el_li.h       |   21 -
 src/plugins/litehtml_viewer/litehtml/el_link.cpp   |   19 +-
 src/plugins/litehtml_viewer/litehtml/el_link.h     |    5 +-
 src/plugins/litehtml_viewer/litehtml/el_para.cpp   |   11 +-
 src/plugins/litehtml_viewer/litehtml/el_para.h     |    5 +-
 src/plugins/litehtml_viewer/litehtml/el_script.cpp |   16 +-
 src/plugins/litehtml_viewer/litehtml/el_script.h   |   12 +-
 src/plugins/litehtml_viewer/litehtml/el_space.cpp  |   23 +-
 src/plugins/litehtml_viewer/litehtml/el_space.h    |    9 +-
 src/plugins/litehtml_viewer/litehtml/el_style.cpp  |   20 +-
 src/plugins/litehtml_viewer/litehtml/el_style.h    |   10 +-
 src/plugins/litehtml_viewer/litehtml/el_table.cpp  |   80 +-
 src/plugins/litehtml_viewer/litehtml/el_table.h    |    8 +-
 src/plugins/litehtml_viewer/litehtml/el_td.cpp     |   32 +-
 src/plugins/litehtml_viewer/litehtml/el_td.h       |    5 +-
 src/plugins/litehtml_viewer/litehtml/el_text.cpp   |  166 +-
 src/plugins/litehtml_viewer/litehtml/el_text.h     |   27 +-
 src/plugins/litehtml_viewer/litehtml/el_title.cpp  |   10 +-
 src/plugins/litehtml_viewer/litehtml/el_title.h    |    5 +-
 src/plugins/litehtml_viewer/litehtml/el_tr.cpp     |   37 +-
 src/plugins/litehtml_viewer/litehtml/el_tr.h       |    6 +-
 src/plugins/litehtml_viewer/litehtml/element.cpp   |  552 +--
 src/plugins/litehtml_viewer/litehtml/element.h     |  398 +-
 src/plugins/litehtml_viewer/litehtml/html.cpp      |  198 +-
 src/plugins/litehtml_viewer/litehtml/html.h        |   95 +-
 src/plugins/litehtml_viewer/litehtml/html_tag.cpp  | 4948 ++++----------------
 src/plugins/litehtml_viewer/litehtml/html_tag.h    |  302 +-
 src/plugins/litehtml_viewer/litehtml/iterators.cpp |  111 +-
 src/plugins/litehtml_viewer/litehtml/iterators.h   |   88 +-
 src/plugins/litehtml_viewer/litehtml/line_box.cpp  |  698 +++
 src/plugins/litehtml_viewer/litehtml/line_box.h    |  170 +
 src/plugins/litehtml_viewer/litehtml/litehtml.h    |    1 +
 src/plugins/litehtml_viewer/litehtml/master_css.h  |  351 ++
 .../litehtml_viewer/litehtml/media_query.cpp       |   61 +-
 src/plugins/litehtml_viewer/litehtml/media_query.h |    4 +-
 src/plugins/litehtml_viewer/litehtml/num_cvt.cpp   |   63 +-
 src/plugins/litehtml_viewer/litehtml/num_cvt.h     |   11 +-
 src/plugins/litehtml_viewer/litehtml/os_types.h    |   86 +-
 .../litehtml_viewer/litehtml/render_block.cpp      |  856 ++++
 .../litehtml/render_block_context.cpp              |  125 +
 .../litehtml_viewer/litehtml/render_flex.cpp       |   91 +
 .../litehtml_viewer/litehtml/render_image.cpp      |  148 +
 .../litehtml_viewer/litehtml/render_inline.cpp     |    3 +
 .../litehtml/render_inline_context.cpp             |  403 ++
 .../litehtml_viewer/litehtml/render_item.cpp       | 1076 +++++
 src/plugins/litehtml_viewer/litehtml/render_item.h |  599 +++
 .../litehtml_viewer/litehtml/render_table.cpp      |  482 ++
 src/plugins/litehtml_viewer/litehtml/string_id.cpp |   54 +
 src/plugins/litehtml_viewer/litehtml/string_id.h   |  300 ++
 src/plugins/litehtml_viewer/litehtml/strtod.cpp    |  275 ++
 src/plugins/litehtml_viewer/litehtml/style.cpp     | 1433 ++++--
 src/plugins/litehtml_viewer/litehtml/style.h       |  215 +-
 .../litehtml_viewer/litehtml/stylesheet.cpp        |  123 +-
 src/plugins/litehtml_viewer/litehtml/stylesheet.h  |   23 +-
 src/plugins/litehtml_viewer/litehtml/table.cpp     |   97 +-
 src/plugins/litehtml_viewer/litehtml/table.h       |   65 +-
 .../litehtml_viewer/litehtml/tstring_view.cpp      |   46 +
 .../litehtml_viewer/litehtml/tstring_view.h        |  136 +
 src/plugins/litehtml_viewer/litehtml/types.h       |  363 +-
 src/plugins/litehtml_viewer/litehtml/url.cpp       |  163 +
 src/plugins/litehtml_viewer/litehtml/url.h         |  139 +
 src/plugins/litehtml_viewer/litehtml/url_path.cpp  |   86 +
 src/plugins/litehtml_viewer/litehtml/url_path.h    |   51 +
 .../litehtml_viewer/litehtml/utf8_strings.cpp      |    2 +
 .../litehtml_viewer/litehtml/utf8_strings.h        |   12 +-
 src/plugins/litehtml_viewer/litehtml/web_color.cpp |  382 +-
 src/plugins/litehtml_viewer/litehtml/web_color.h   |   50 +-
 113 files changed, 12329 insertions(+), 8165 deletions(-)
 delete mode 100644 src/plugins/litehtml_viewer/litehtml/attributes.h
 delete mode 100644 src/plugins/litehtml_viewer/litehtml/background.cpp
 delete mode 100644 src/plugins/litehtml_viewer/litehtml/box.cpp
 delete mode 100644 src/plugins/litehtml_viewer/litehtml/box.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/codepoint.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/codepoint.h
 delete mode 100644 src/plugins/litehtml_viewer/litehtml/context.cpp
 delete mode 100644 src/plugins/litehtml_viewer/litehtml/context.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/css_borders.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/css_properties.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/css_properties.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/document_container.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/document_container.h
 delete mode 100644 src/plugins/litehtml_viewer/litehtml/el_li.cpp
 delete mode 100644 src/plugins/litehtml_viewer/litehtml/el_li.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/line_box.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/line_box.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/master_css.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/render_block.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/render_block_context.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/render_flex.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/render_image.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/render_inline.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/render_inline_context.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/render_item.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/render_item.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/render_table.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/string_id.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/string_id.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/strtod.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/tstring_view.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/tstring_view.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/url.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/url.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/url_path.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/url_path.h


- Log -----------------------------------------------------------------
commit cf2e2a3236893511b498412b0f1f79f91c962d29
Author: Jonathan Boeing <jonathan at claws-mail.org>
Date:   Mon Oct 9 00:28:03 2023 -0700

    Sync with litehtml v0.7

diff --git a/src/plugins/litehtml_viewer/litehtml/Makefile.am b/src/plugins/litehtml_viewer/litehtml/Makefile.am
index 7a539fecd..6e103b7ba 100644
--- a/src/plugins/litehtml_viewer/litehtml/Makefile.am
+++ b/src/plugins/litehtml_viewer/litehtml/Makefile.am
@@ -16,50 +16,113 @@ endif
 liblitehtml_la_CXXFLAGS = -std=c++11
 
 liblitehtml_la_SOURCES = \
-	attributes.h \
-	background.cpp background.h \
+	background.h \
 	borders.h \
-	box.cpp box.h \
-	context.cpp context.h \
-	css_length.cpp css_length.h \
-	css_margins.h css_offsets.h css_position.h \
-	css_selector.cpp css_selector.h \
-	document.cpp document.h \
-	el_anchor.cpp el_anchor.h \
-	el_base.cpp el_base.h \
-	el_before_after.cpp el_before_after.h \
-	el_body.cpp el_body.h \
-	el_break.cpp el_break.h \
-	el_cdata.cpp el_cdata.h \
-	el_comment.cpp el_comment.h \
-	el_div.cpp el_div.h \
-	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 \
-	el_space.cpp el_space.h \
-	el_style.cpp el_style.h \
-	el_table.cpp el_table.h \
-	el_td.cpp el_td.h \
-	el_text.cpp el_text.h \
-	el_title.cpp el_title.h \
-	el_tr.cpp el_tr.h \
-	html.cpp html.h \
-	html_tag.cpp html_tag.h \
-	iterators.cpp iterators.h \
+	codepoint.cpp \
+	codepoint.h \
+	css_borders.cpp \
+	css_length.cpp \
+	css_length.h \
+	css_margins.h \
+	css_offsets.h \
+	css_position.h \
+	css_properties.cpp \
+	css_properties.h \
+	css_selector.cpp \
+	css_selector.h \
+	document_container.cpp \
+	document_container.h \
+	document.cpp \
+	document.h \
+	el_anchor.cpp \
+	el_anchor.h \
+	el_base.cpp \
+	el_base.h \
+	el_before_after.cpp \
+	el_before_after.h \
+	el_body.cpp \
+	el_body.h \
+	el_break.cpp \
+	el_break.h \
+	el_cdata.cpp \
+	el_cdata.h \
+	el_comment.cpp \
+	el_comment.h \
+	el_div.cpp \
+	el_div.h \
+	element.cpp \
+	element.h \
+	el_font.cpp \
+	el_font.h \
+	el_image.cpp \
+	el_image.h \
+	el_link.cpp \
+	el_link.h \
+	el_para.cpp \
+	el_para.h \
+	el_script.cpp \
+	el_script.h \
+	el_space.cpp \
+	el_space.h \
+	el_style.cpp \
+	el_style.h \
+	el_table.cpp \
+	el_table.h \
+	el_td.cpp \
+	el_td.h \
+	el_text.cpp \
+	el_text.h \
+	el_title.cpp \
+	el_title.h \
+	el_tr.cpp \
+	el_tr.h \
+	html.cpp \
+	html.h \
+	html_tag.cpp \
+	html_tag.h \
+	iterators.cpp \
+	iterators.h \
+	LICENSE \
+	line_box.cpp \
+	line_box.h \
 	litehtml.h \
-	media_query.cpp media_query.h \
-	num_cvt.cpp num_cvt.h \
+	Makefile.am \
+	master_css.h \
+	media_query.cpp \
+	media_query.h \
+	num_cvt.cpp \
+	num_cvt.h \
 	os_types.h \
-	style.cpp style.h \
-	stylesheet.cpp stylesheet.h \
-	table.cpp table.h \
+	README.md \
+	render_block_context.cpp \
+	render_block.cpp \
+	render_flex.cpp \
+	render_image.cpp \
+	render_inline_context.cpp \
+	render_inline.cpp \
+	render_item.cpp \
+	render_item.h \
+	render_table.cpp \
+	string_id.cpp \
+	string_id.h \
+	strtod.cpp \
+	style.cpp \
+	style.h \
+	stylesheet.cpp \
+	stylesheet.h \
+	table.cpp \
+	table.h \
+	tstring_view.cpp \
+	tstring_view.h \
 	types.h \
-	utf8_strings.cpp utf8_strings.h \
-	web_color.cpp web_color.h
+	url.cpp \
+	url.h \
+	url_path.cpp \
+	url_path.h \
+	utf8_strings.cpp \
+	utf8_strings.h \
+	web_color.cpp \
+	web_color.h
 
 liblitehtml_la_LDFLAGS = \
         -avoid-version -module \
diff --git a/src/plugins/litehtml_viewer/litehtml/attributes.h b/src/plugins/litehtml_viewer/litehtml/attributes.h
deleted file mode 100644
index 98487f02e..000000000
--- a/src/plugins/litehtml_viewer/litehtml/attributes.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef LH_ATTRIBUTES_H
-#define LH_ATTRIBUTES_H
-
-namespace litehtml
-{
-	struct attr_color
-	{
-		unsigned char    rgbBlue;
-		unsigned char    rgbGreen;
-		unsigned char    rgbRed;
-		unsigned char    rgbAlpha;
-		attr_color()
-		{
-			rgbAlpha	= 255;
-			rgbBlue		= 0;
-			rgbGreen	= 0;
-			rgbRed		= 0;
-		}
-	};
-
-	struct attr_border
-	{
-		style_border	border;
-		int				width;
-		attr_color		color;
-
-		attr_border()
-		{
-			border	= borderNone;
-			width	= 0;
-		}
-	};
-}
-
-#endif  // LH_ATTRIBUTES_H
diff --git a/src/plugins/litehtml_viewer/litehtml/background.cpp b/src/plugins/litehtml_viewer/litehtml/background.cpp
deleted file mode 100644
index 1c65e3042..000000000
--- a/src/plugins/litehtml_viewer/litehtml/background.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-#include "html.h"
-#include "background.h"
-
-litehtml::background::background(void)
-{
-	m_attachment	= background_attachment_scroll;
-	m_repeat		= background_repeat_repeat;
-	m_clip			= background_box_border;
-	m_origin		= background_box_padding;
-	m_color.alpha	= 0;
-	m_color.red		= 0;
-	m_color.green	= 0;
-	m_color.blue	= 0;
-}
-
-litehtml::background::background( const background& val )
-{
-	m_image			= val.m_image;
-	m_baseurl		= val.m_baseurl;
-	m_color			= val.m_color;
-	m_attachment	= val.m_attachment;
-	m_position		= val.m_position;
-	m_repeat		= val.m_repeat;
-	m_clip			= val.m_clip;
-	m_origin		= val.m_origin;
-}
-
-litehtml::background::~background(void)
-{
-}
-
-litehtml::background& litehtml::background::operator=( const background& val )
-{
-	m_image			= val.m_image;
-	m_baseurl		= val.m_baseurl;
-	m_color			= val.m_color;
-	m_attachment	= val.m_attachment;
-	m_position		= val.m_position;
-	m_repeat		= val.m_repeat;
-	m_clip			= val.m_clip;
-	m_origin		= val.m_origin;
-	return *this;
-}
-
-
-litehtml::background_paint::background_paint() : color(0, 0, 0, 0)
-{
-	position_x		= 0;
-	position_y		= 0;
-	attachment		= background_attachment_scroll;
-	repeat			= background_repeat_repeat;
-	is_root			= false;
-}
-
-litehtml::background_paint::background_paint( const background_paint& val )
-{
-	image			= val.image;
-	baseurl			= val.baseurl;
-	attachment		= val.attachment;
-	repeat			= val.repeat;
-	color			= val.color;
-	clip_box		= val.clip_box;
-	origin_box		= val.origin_box;
-	border_box		= val.border_box;
-	border_radius	= val.border_radius;
-	image_size		= val.image_size;
-	position_x		= val.position_x;
-	position_y		= val.position_y;
-	is_root			= val.is_root;
-}
-
-void litehtml::background_paint::operator=( const background& val )
-{
-	attachment	= val.m_attachment;
-	baseurl		= val.m_baseurl;
-	image		= val.m_image;
-	repeat		= val.m_repeat;
-	color		= val.m_color;
-}
diff --git a/src/plugins/litehtml_viewer/litehtml/background.h b/src/plugins/litehtml_viewer/litehtml/background.h
index ce0b69a63..c56443d54 100644
--- a/src/plugins/litehtml_viewer/litehtml/background.h
+++ b/src/plugins/litehtml_viewer/litehtml/background.h
@@ -2,7 +2,6 @@
 #define LH_BACKGROUND_H
 
 #include "types.h"
-#include "attributes.h"
 #include "css_length.h"
 #include "css_position.h"
 #include "web_color.h"
@@ -13,29 +12,34 @@ namespace litehtml
 	class background
 	{
 	public:
-		tstring					m_image;
-		tstring					m_baseurl;
+		string_vector			m_image;
+		string					m_baseurl;
 		web_color				m_color;
-		background_attachment	m_attachment;
-		css_position			m_position;
-		background_repeat		m_repeat;
-		background_box			m_clip;
-		background_box			m_origin;
-		css_border_radius		m_radius;
+		int_vector				m_attachment;
+		length_vector			m_position_x;
+		length_vector			m_position_y;
+		size_vector				m_size;
+		int_vector				m_repeat;
+		int_vector				m_clip;
+		int_vector				m_origin;
 
-	public:
-		background(void);
-		background(const background& val);
-		~background(void);
-
-		background& operator=(const background& val);
+		bool is_empty() const
+		{
+			if(m_color.alpha != 0) return false;
+			if(m_image.empty()) return true;
+			for(const auto& img : m_image)
+			{
+				if(!img.empty()) return false;
+			}
+			return true;
+		}
 	};
 
 	class background_paint
 	{
 	public:
-		tstring					image;
-		tstring					baseurl;
+		string					image;
+		string					baseurl;
 		background_attachment	attachment;
 		background_repeat		repeat;
 		web_color				color;
@@ -47,10 +51,17 @@ namespace litehtml
 		int						position_x;
 		int						position_y;
 		bool					is_root;
+
 	public:
-		background_paint();
-		background_paint(const background_paint& val);
-		void operator=(const background& val);
+		background_paint()
+		{
+			attachment		= background_attachment_scroll;
+			repeat			= background_repeat_repeat;
+			color			= web_color::transparent;
+			position_x		= 0;
+			position_y		= 0;
+			is_root			= false;
+		}
 	};
 
 }
diff --git a/src/plugins/litehtml_viewer/litehtml/borders.h b/src/plugins/litehtml_viewer/litehtml/borders.h
index 9956a2a35..e690db6d3 100644
--- a/src/plugins/litehtml_viewer/litehtml/borders.h
+++ b/src/plugins/litehtml_viewer/litehtml/borders.h
@@ -3,6 +3,7 @@
 
 #include "css_length.h"
 #include "types.h"
+#include "web_color.h"
 
 namespace litehtml
 {
@@ -31,6 +32,8 @@ namespace litehtml
 			color	= val.color;
 			return *this;
 		}
+
+		string to_string() const;
 	};
 
 	struct border
@@ -199,7 +202,7 @@ namespace litehtml
 			bottom_right_y	= val.bottom_right_y;
 			return *this;
 		}
-		border_radiuses calc_percents(int width, int height)
+		border_radiuses calc_percents(int width, int height) const
 		{
 			border_radiuses ret;
 			ret.bottom_left_x = bottom_left_x.calc_percent(width);
@@ -222,9 +225,11 @@ namespace litehtml
 		css_border			bottom;
 		css_border_radius	radius;
 
-		css_borders()
-		{
+		css_borders() = default;
 
+		bool is_visible() const
+		{
+			return left.width.val() != 0 || right.width.val() != 0 || top.width.val() != 0 || bottom.width.val() != 0;
 		}
 
 		css_borders(const css_borders& val)
@@ -245,6 +250,13 @@ namespace litehtml
 			radius	= val.radius;
 			return *this;
 		}
+		string to_string() const
+		{
+			return	"left: " + left.to_string() +
+					", top: " + top.to_string() +
+					", right: " + top.to_string() +
+					", bottom: " + bottom.to_string();
+		}
 	};
 
 	struct borders
@@ -255,10 +267,7 @@ namespace litehtml
 		border			bottom;
 		border_radiuses	radius;
 
-		borders()
-		{
-
-		}
+		borders() = default;
 
 		borders(const borders& val)
 		{
@@ -277,6 +286,11 @@ namespace litehtml
 			bottom = val.bottom;
 		}
 
+		bool is_visible() const
+		{
+			return left.width != 0 || right.width != 0 || top.width != 0 || bottom.width != 0;
+		}
+
 		borders& operator=(const borders& val)
 		{
 			left = val.left;
diff --git a/src/plugins/litehtml_viewer/litehtml/box.cpp b/src/plugins/litehtml_viewer/litehtml/box.cpp
deleted file mode 100644
index 4ad23c529..000000000
--- a/src/plugins/litehtml_viewer/litehtml/box.cpp
+++ /dev/null
@@ -1,434 +0,0 @@
-#include "html.h"
-#include "box.h"
-#include "html_tag.h"
-
-
-litehtml::box_type litehtml::block_box::get_type()
-{
-	return box_block;
-}
-
-int litehtml::block_box::height()
-{
-	return m_element->height();
-}
-
-int litehtml::block_box::width()
-{
-	return m_element->width();
-}
-
-void litehtml::block_box::add_element(const element::ptr &el)
-{
-	m_element = el;
-	el->m_box = this;
-}
-
-void litehtml::block_box::finish(bool last_box)
-{
-	if(!m_element) return;
-	m_element->apply_relative_shift(m_box_right - m_box_left);
-}
-
-bool litehtml::block_box::can_hold(const element::ptr &el, white_space ws)
-{
-	if(m_element || el->is_inline_box())
-	{
-		return false;
-	}
-	return true;
-}
-
-bool litehtml::block_box::is_empty()
-{
-	if(m_element)
-	{
-		return false;
-	}
-	return true;
-}
-
-int litehtml::block_box::baseline()
-{
-	if(m_element)
-	{
-		return m_element->get_base_line();
-	}
-	return 0;
-}
-
-void litehtml::block_box::get_elements( elements_vector& els )
-{
-	els.push_back(m_element);
-}
-
-int litehtml::block_box::top_margin()
-{
-	if(m_element && m_element->collapse_top_margin())
-	{
-		return m_element->m_margins.top;
-	}
-	return 0;
-}
-
-int litehtml::block_box::bottom_margin()
-{
-	if(m_element && m_element->collapse_bottom_margin())
-	{
-		return m_element->m_margins.bottom;
-	}
-	return 0;
-}
-
-void litehtml::block_box::y_shift( int shift )
-{
-	m_box_top += shift;
-	if(m_element)
-	{
-		m_element->m_pos.y += shift;
-	}
-}
-
-void litehtml::block_box::new_width( int left, int right, elements_vector& els )
-{
-
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-litehtml::box_type litehtml::line_box::get_type()
-{
-	return box_line;
-}
-
-int litehtml::line_box::height()
-{
-	return m_height;
-}
-
-int litehtml::line_box::width()
-{
-	return m_width;
-}
-
-void litehtml::line_box::add_element(const element::ptr &el)
-{
-	el->m_skip	= false;
-	el->m_box	= 0;
-	bool add	= true;
-	if( (m_items.empty() && el->is_white_space()) || el->is_break() )
-	{
-		el->m_skip = true;
-	} else if(el->is_white_space())
-	{
-		if (have_last_space())
-		{
-			add = false;
-			el->m_skip = true;
-		}
-	}
-
-	if(add)
-	{
-		el->m_box = this;
-		m_items.push_back(el);
-
-		if(!el->m_skip)
-		{
-			int el_shift_left	= el->get_inline_shift_left();
-			int el_shift_right	= el->get_inline_shift_right();
-
-			el->m_pos.x	= m_box_left + m_width + el_shift_left + el->content_margins_left();
-			el->m_pos.y	= m_box_top + el->content_margins_top();
-			m_width		+= el->width() + el_shift_left + el_shift_right;
-		}
-	}
-}
-
-void litehtml::line_box::finish(bool last_box)
-{
-	if( is_empty() || (!is_empty() && last_box && is_break_only()) )
-	{
-		m_height = 0;
-		return;
-	}
-
-	for(auto i = m_items.rbegin(); i != m_items.rend(); i++)
-	{
-		if((*i)->is_white_space() || (*i)->is_break())
-		{
-			if(!(*i)->m_skip)
-			{
-				(*i)->m_skip = true;
-				m_width -= (*i)->width();
-			}
-		} else
-		{
-			break;
-		}
-	}
-
-	int base_line	= m_font_metrics.base_line();
-	int line_height = m_line_height;
-
-	int add_x = 0;
-	switch(m_text_align)
-	{
-	case text_align_right:
-		if(m_width < (m_box_right - m_box_left))
-		{
-			add_x = (m_box_right - m_box_left) - m_width;
-		}
-		break;
-	case text_align_center:
-		if(m_width < (m_box_right - m_box_left))
-		{
-			add_x = ((m_box_right - m_box_left) - m_width) / 2;
-		}
-		break;
-	default:
-		add_x = 0;
-	}
-
-	m_height = 0;
-	// find line box baseline and line-height
-	for(const auto& el : m_items)
-	{
-		if(el->get_display() == display_inline_text)
-		{
-			font_metrics fm;
-			el->get_font(&fm);
-			base_line	= std::max(base_line,	fm.base_line());
-			line_height = std::max(line_height, el->line_height());
-			m_height = std::max(m_height, fm.height);
-		}
-		el->m_pos.x += add_x;
-	}
-
-	if(m_height)
-	{
-		base_line += (line_height - m_height) / 2;
-	}
-
-	m_height = line_height;
-
-	int y1	= 0;
-	int y2	= m_height;
-
-	for (const auto& el : m_items)
-	{
-		if(el->get_display() == display_inline_text)
-		{
-			font_metrics fm;
-			el->get_font(&fm);
-			el->m_pos.y = m_height - base_line - fm.ascent;
-		} else
-		{
-			switch(el->get_vertical_align())
-			{
-			case va_super:
-			case va_sub:
-			case va_baseline:
-				el->m_pos.y = m_height - base_line - el->height() + el->get_base_line() + el->content_margins_top();
-				break;
-			case va_top:
-				el->m_pos.y = y1 + el->content_margins_top();
-				break;
-			case va_text_top:
-				el->m_pos.y = m_height - base_line - m_font_metrics.ascent + el->content_margins_top();
-				break;
-			case va_middle:
-				el->m_pos.y = m_height - base_line - m_font_metrics.x_height / 2 - el->height() / 2 + el->content_margins_top();
-				break;
-			case va_bottom:
-				el->m_pos.y = y2 - el->height() + el->content_margins_top();
-				break;
-			case va_text_bottom:
-				el->m_pos.y = m_height - base_line + m_font_metrics.descent - el->height() + el->content_margins_top();
-				break;
-			}
-			y1 = std::min(y1, el->top());
-			y2 = std::max(y2, el->bottom());
-		}
-	}
-
-	css_offsets offsets;
-
-	for (const auto& el : m_items)
-	{
-		el->m_pos.y -= y1;
-		el->m_pos.y += m_box_top;
-		if(el->get_display() != display_inline_text)
-		{
-			switch(el->get_vertical_align())
-			{
-			case va_top:
-				el->m_pos.y = m_box_top + el->content_margins_top();
-				break;
-			case va_bottom:
-				el->m_pos.y = m_box_top + (y2 - y1) - el->height() + el->content_margins_top();
-				break;
-			case va_baseline:
-				//TODO: process vertical align "baseline"
-				break;
-			case va_middle:
-				//TODO: process vertical align "middle"
-				break;
-			case va_sub:
-				//TODO: process vertical align "sub"
-				break;
-			case va_super:
-				//TODO: process vertical align "super"
-				break;
-			case va_text_bottom:
-				//TODO: process vertical align "text-bottom"
-				break;
-			case va_text_top:
-				//TODO: process vertical align "text-top"
-				break;
-			}
-		}
-
-		el->apply_relative_shift(m_box_right - m_box_left);
-	}
-	m_height = y2 - y1;
-	m_baseline = (base_line - y1) - (m_height - line_height);
-}
-
-bool litehtml::line_box::can_hold(const element::ptr &el, white_space ws)
-{
-	if(!el->is_inline_box()) return false;
-
-	if(el->is_break())
-	{
-		return false;
-	}
-
-	if(ws == white_space_nowrap || ws == white_space_pre)
-	{
-		return true;
-	}
-
-	if(m_box_left + m_width + el->width() + el->get_inline_shift_left() + el->get_inline_shift_right() > m_box_right)
-	{
-		return false;
-	}
-
-	return true;
-}
-
-bool litehtml::line_box::have_last_space()
-{
-	bool ret = false;
-	for (auto i = m_items.rbegin(); i != m_items.rend() && !ret; i++)
-	{
-		if((*i)->is_white_space() || (*i)->is_break())
-		{
-			ret = true;
-		} else
-		{
-			break;
-		}
-	}
-	return ret;
-}
-
-bool litehtml::line_box::is_empty()
-{
-	if(m_items.empty()) return true;
-	for (auto i = m_items.rbegin(); i != m_items.rend(); i++)
-	{
-		if(!(*i)->m_skip || (*i)->is_break())
-		{
-			return false;
-		}
-	}
-	return true;
-}
-
-int litehtml::line_box::baseline()
-{
-	return m_baseline;
-}
-
-void litehtml::line_box::get_elements( elements_vector& els )
-{
-	els.insert(els.begin(), m_items.begin(), m_items.end());
-}
-
-int litehtml::line_box::top_margin()
-{
-	return 0;
-}
-
-int litehtml::line_box::bottom_margin()
-{
-	return 0;
-}
-
-void litehtml::line_box::y_shift( int shift )
-{
-	m_box_top += shift;
-	for (auto& el : m_items)
-	{
-		el->m_pos.y += shift;
-	}
-}
-
-bool litehtml::line_box::is_break_only()
-{
-	if(m_items.empty()) return true;
-
-	if(m_items.front()->is_break())
-	{
-		for (auto& el : m_items)
-		{
-			if(!el->m_skip)
-			{
-				return false;
-			}
-		}
-		return true;
-	}
-	return false;
-}
-
-void litehtml::line_box::new_width( int left, int right, elements_vector& els )
-{
-	int add = left - m_box_left;
-	if(add)
-	{
-		m_box_left	= left;
-		m_box_right	= right;
-		m_width = 0;
-		auto remove_begin = m_items.end();
-		for (auto i = m_items.begin() + 1; i != m_items.end(); i++)
-		{
-			element::ptr el = (*i);
-
-			if(!el->m_skip)
-			{
-				if(m_box_left + m_width + el->width() + el->get_inline_shift_right() + el->get_inline_shift_left() > m_box_right)
-				{
-					remove_begin = i;
-					break;
-				} else
-				{
-					el->m_pos.x += add;
-					m_width += el->width() + el->get_inline_shift_right() + el->get_inline_shift_left();
-				}
-			}
-		}
-		if(remove_begin != m_items.end())
-		{
-			els.insert(els.begin(), remove_begin, m_items.end());
-			m_items.erase(remove_begin, m_items.end());
-
-			for(const auto& el : els)
-			{
-				el->m_box = 0;
-			}
-		}
-	}
-}
-
diff --git a/src/plugins/litehtml_viewer/litehtml/box.h b/src/plugins/litehtml_viewer/litehtml/box.h
deleted file mode 100644
index eeeea51c8..000000000
--- a/src/plugins/litehtml_viewer/litehtml/box.h
+++ /dev/null
@@ -1,120 +0,0 @@
-#ifndef LH_BOX_H
-#define LH_BOX_H
-
-namespace litehtml
-{
-	class html_tag;
-
-	enum box_type
-	{
-		box_block,
-		box_line
-	};
-
-	class box
-	{
-	public:
-		typedef std::unique_ptr<litehtml::box>	ptr;
-		typedef std::vector< box::ptr >			vector;
-	protected:
-		int		m_box_top;
-		int		m_box_left;
-		int		m_box_right;
-	public:
-		box(int top, int left, int right)
-		{
-			m_box_top	= top;
-			m_box_left	= left;
-			m_box_right	= right;
-		}
-		virtual ~box() {}
-
-		int		bottom()	{ return m_box_top + height();	}
-		int		top()		{ return m_box_top;				}
-		int		right()		{ return m_box_left + width();	}
-		int		left()		{ return m_box_left;			}
-
-		virtual litehtml::box_type	get_type() = 0;
-		virtual int					height() = 0;
-		virtual int					width() = 0;
-		virtual void				add_element(const element::ptr &el) = 0;
-		virtual bool				can_hold(const element::ptr &el, white_space ws) = 0;
-		virtual void				finish(bool last_box = false) = 0;
-		virtual bool				is_empty() = 0;
-		virtual int					baseline() = 0;
-		virtual void				get_elements(elements_vector& els) = 0;
-		virtual int					top_margin() = 0;
-		virtual int					bottom_margin() = 0;
-		virtual void				y_shift(int shift) = 0;
-		virtual void				new_width(int left, int right, elements_vector& els) = 0;
-	};
-
-	//////////////////////////////////////////////////////////////////////////
-
-	class block_box : public box
-	{
-		element::ptr m_element;
-	public:
-		block_box(int top, int left, int right) : box(top, left, right)
-		{
-			m_element = 0;
-		}
-
-		virtual litehtml::box_type	get_type();
-		virtual int					height();
-		virtual int					width();
-		virtual void				add_element(const element::ptr &el);
-		virtual bool				can_hold(const element::ptr &el, white_space ws);
-		virtual void				finish(bool last_box = false);
-		virtual bool				is_empty();
-		virtual int					baseline();
-		virtual void				get_elements(elements_vector& els);
-		virtual int					top_margin();
-		virtual int					bottom_margin();
-		virtual void				y_shift(int shift);
-		virtual void				new_width(int left, int right, elements_vector& els);
-	};
-
-	//////////////////////////////////////////////////////////////////////////
-
-	class line_box : public box
-	{
-		elements_vector			m_items;
-		int						m_height;
-		int						m_width;
-		int						m_line_height;
-		font_metrics			m_font_metrics;
-		int						m_baseline;
-		text_align				m_text_align;
-	public:
-		line_box(int top, int left, int right, int line_height, font_metrics& fm, text_align align) : box(top, left, right)
-		{
-			m_height		= 0;
-			m_width			= 0;
-			m_font_metrics	= fm;
-			m_line_height	= line_height;
-			m_baseline		= 0;
-			m_text_align	= align;
-		}
-
-		virtual litehtml::box_type	get_type();
-		virtual int					height();
-		virtual int					width();
-		virtual void				add_element(const element::ptr &el);
-		virtual bool				can_hold(const element::ptr &el, white_space ws);
-		virtual void				finish(bool last_box = false);
-		virtual bool				is_empty();
-		virtual int					baseline();
-		virtual void				get_elements(elements_vector& els);
-		virtual int					top_margin();
-		virtual int					bottom_margin();
-		virtual void				y_shift(int shift);
-		virtual void				new_width(int left, int right, elements_vector& els);
-
-	private:
-		bool						have_last_space();
-		bool						is_break_only();
-	};
-}
-
-#endif  // LH_BOX_H
diff --git a/src/plugins/litehtml_viewer/litehtml/codepoint.cpp b/src/plugins/litehtml_viewer/litehtml/codepoint.cpp
new file mode 100644
index 000000000..a89057022
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/codepoint.cpp
@@ -0,0 +1,82 @@
+// Copyright (C) 2020-2021 Primate Labs Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the names of the copyright holders nor the names of their
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "codepoint.h"
+
+#include <iostream>
+
+namespace {
+
+bool lookup(const uint32_t* table, char c)
+{
+    return table[c >> 5] & (1 << (c & 0x1f));
+}
+
+} // namespace
+
+namespace litehtml {
+
+bool is_ascii_codepoint(char c)
+{
+    return (c < 128);
+}
+
+// https://datatracker.ietf.org/doc/html/rfc3986#section-2.2
+bool is_url_reserved_codepoint(char c)
+{
+    static const uint32_t reserved_lookup[] = {
+        0x00000000,
+        0xac009fda,
+        0x28000001,
+        0x00000000
+    };
+
+    if (!is_ascii_codepoint(c)) {
+        return false;
+    }
+    return lookup(reserved_lookup, c);
+}
+
+// https://datatracker.ietf.org/doc/html/rfc3986#section-3.1
+bool is_url_scheme_codepoint(char c)
+{
+    static const uint32_t scheme_lookup[] = {
+        0x00000000,
+        0x03ff6800,
+        0x07fffffe,
+        0x07fffffe,
+    };
+
+    if (!is_ascii_codepoint(c)) {
+        return false;
+    }
+    return lookup(scheme_lookup, c);
+}
+
+} // namespace litehtml
diff --git a/src/plugins/litehtml_viewer/litehtml/codepoint.h b/src/plugins/litehtml_viewer/litehtml/codepoint.h
new file mode 100644
index 000000000..52dd49555
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/codepoint.h
@@ -0,0 +1,51 @@
+// Copyright (C) 2020-2021 Primate Labs Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the names of the copyright holders nor the names of their
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef LITEHTML_CODEPOINT_H__
+#define LITEHTML_CODEPOINT_H__
+
+#include <string>
+
+#include "os_types.h"
+
+namespace litehtml {
+
+bool is_ascii_codepoint(char c);
+
+// Returns true if the codepoint is a reserved codepoint for URLs.
+// https://datatracker.ietf.org/doc/html/rfc3986#section-2.2
+bool is_url_reserved_codepoint(char c);
+
+// Returns true if the codepoint is a scheme codepoint for URLs.
+// https://datatracker.ietf.org/doc/html/rfc3986#section-3.1
+bool is_url_scheme_codepoint(char c);
+
+} // namespace litehtml
+
+#endif // LITEHTML_CODEPOINT_H__
diff --git a/src/plugins/litehtml_viewer/litehtml/context.cpp b/src/plugins/litehtml_viewer/litehtml/context.cpp
deleted file mode 100644
index 4cea5d3d8..000000000
--- a/src/plugins/litehtml_viewer/litehtml/context.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-#include "html.h"
-#include "context.h"
-#include "stylesheet.h"
-
-
-void litehtml::context::load_master_stylesheet( const tchar_t* str )
-{
-	media_query_list::ptr media;
-
-	m_master_css.parse_stylesheet(str, 0, std::shared_ptr<litehtml::document>(), media_query_list::ptr());
-	m_master_css.sort_selectors();
-}
diff --git a/src/plugins/litehtml_viewer/litehtml/context.h b/src/plugins/litehtml_viewer/litehtml/context.h
deleted file mode 100644
index b6450f8f5..000000000
--- a/src/plugins/litehtml_viewer/litehtml/context.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef LH_CONTEXT_H
-#define LH_CONTEXT_H
-
-#include "stylesheet.h"
-
-namespace litehtml
-{
-	class context
-	{
-		litehtml::css	m_master_css;
-	public:
-		void			load_master_stylesheet(const tchar_t* str);
-		litehtml::css&	master_css()
-		{
-			return m_master_css;
-		}
-	};
-}
-
-#endif  // LH_CONTEXT_H
diff --git a/src/plugins/litehtml_viewer/litehtml/css_borders.cpp b/src/plugins/litehtml_viewer/litehtml/css_borders.cpp
new file mode 100644
index 000000000..478e9df5b
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/css_borders.cpp
@@ -0,0 +1,7 @@
+#include "html.h"
+#include "borders.h"
+
+litehtml::string litehtml::css_border::to_string() const
+{
+    return width.to_string() + "/" + index_value(style, border_style_strings) + "/" + color.to_string();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/css_length.cpp b/src/plugins/litehtml_viewer/litehtml/css_length.cpp
index 472cd546b..d1c69d261 100644
--- a/src/plugins/litehtml_viewer/litehtml/css_length.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/css_length.cpp
@@ -1,17 +1,17 @@
 #include "html.h"
 #include "css_length.h"
 
-void litehtml::css_length::fromString( const tstring& str, const tstring& predefs, int defValue )
+void litehtml::css_length::fromString( const string& str, const string& predefs, int defValue )
 {
 	// TODO: Make support for calc
-	if(str.substr(0, 4) == _t("calc"))
+	if(str.substr(0, 4) == "calc")
 	{
 		m_is_predefined = true;
-		m_predef		= 0;
+		m_predef		= defValue;
 		return;
 	}
 
-	int predef = value_index(str.c_str(), predefs.c_str(), -1);
+	int predef = value_index(str, predefs, -1);
 	if(predef >= 0)
 	{
 		m_is_predefined = true;
@@ -20,16 +20,16 @@ void litehtml::css_length::fromString( const tstring& str, const tstring& predef
 	{
 		m_is_predefined = false;
 
-		tstring num;
-		tstring un;
+		string num;
+		string un;
 		bool is_unit = false;
-		for(tstring::const_iterator chr = str.begin(); chr != str.end(); chr++)
+		for(char chr : str)
 		{
 			if(!is_unit)
 			{
-				if(t_isdigit(*chr) || *chr == _t('.') || *chr == _t('+') || *chr == _t('-'))
+				if(t_isdigit(chr) || chr == '.' || chr == '+' || chr == '-')
 				{
-					num += *chr;
+					num += chr;
 				} else
 				{
 					is_unit = true;
@@ -37,13 +37,13 @@ void litehtml::css_length::fromString( const tstring& str, const tstring& predef
 			}
 			if(is_unit)
 			{
-				un += *chr;
+				un += chr;
 			}
 		}
 		if(!num.empty())
 		{
-			m_value = (float) t_strtod(num.c_str(), 0);
-			m_units	= (css_units) value_index(un.c_str(), css_units_strings, css_units_none);
+			m_value = t_strtof(num);
+			m_units	= (css_units) value_index(un, css_units_strings, css_units_none);
 		} else
 		{
 			// not a number so it is predefined
@@ -52,3 +52,26 @@ void litehtml::css_length::fromString( const tstring& str, const tstring& predef
 		}
 	}
 }
+
+litehtml::css_length litehtml::css_length::from_string(const string& str, const string& predefs, int defValue)
+{
+	css_length len;
+	len.fromString(str, predefs, defValue);
+	return len;
+}
+
+litehtml::string litehtml::css_length::to_string() const
+{
+    if(m_is_predefined)
+    {
+        return "def(" + std::to_string(m_predef) + ")";
+    }
+    return std::to_string(m_value) + "{" + index_value(m_units, css_units_strings) + "}";
+}
+
+litehtml::css_length litehtml::css_length::predef_value(int val)
+{
+	css_length len;
+	len.predef(val);
+	return len;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/css_length.h b/src/plugins/litehtml_viewer/litehtml/css_length.h
index 13a3d77b7..ae787105a 100644
--- a/src/plugins/litehtml_viewer/litehtml/css_length.h
+++ b/src/plugins/litehtml_viewer/litehtml/css_length.h
@@ -16,20 +16,24 @@ namespace litehtml
 		bool		m_is_predefined;
 	public:
 		css_length();
-		css_length(const css_length& val);
-
-		css_length&	operator=(const css_length& val);
+		css_length(float val, css_units units = css_units_px);
 		css_length&	operator=(float val);
+
 		bool		is_predefined() const;
 		void		predef(int val);
 		int			predef() const;
+		static css_length predef_value(int val = 0);
 		void		set_value(float val, css_units units);
 		float		val() const;
 		css_units	units() const;
 		int			calc_percent(int width) const;
-		void		fromString(const tstring& str, const tstring& predefs = _t(""), int defValue = 0);
+		void		fromString(const string& str, const string& predefs = "", int defValue = 0);
+		static css_length from_string(const string& str, const string& predefs = "", int defValue = 0);
+		string		to_string() const;
 	};
 
+	using length_vector = std::vector<css_length>;
+
 	// css_length inlines
 
 	inline css_length::css_length()
@@ -40,31 +44,11 @@ namespace litehtml
 		m_is_predefined	= false;
 	}
 
-	inline css_length::css_length(const css_length& val)
+	inline css_length::css_length(float val, css_units units)
 	{
-		if(val.is_predefined())
-		{
-			m_predef	= val.m_predef;
-		} else
-		{
-			m_value		= val.m_value;
-		}
-		m_units			= val.m_units;
-		m_is_predefined	= val.m_is_predefined;
-	}
-
-	inline css_length&	css_length::operator=(const css_length& val)
-	{
-		if(val.is_predefined())
-		{
-			m_predef	= val.m_predef;
-		} else
-		{
-			m_value		= val.m_value;
-		}
-		m_units			= val.m_units;
-		m_is_predefined	= val.m_is_predefined;
-		return *this;
+		m_value = val;
+		m_units = units;
+		m_is_predefined = false;
 	}
 
 	inline css_length&	css_length::operator=(float val)
@@ -95,7 +79,7 @@ namespace litehtml
 		return 0;
 	}
 
-	inline void css_length::set_value(float val, css_units units)		
+	inline void css_length::set_value(float val, css_units units)
 	{ 
 		m_value			= val; 
 		m_is_predefined = false;	
diff --git a/src/plugins/litehtml_viewer/litehtml/css_margins.h b/src/plugins/litehtml_viewer/litehtml/css_margins.h
index 5c99a8b26..17dc7698d 100644
--- a/src/plugins/litehtml_viewer/litehtml/css_margins.h
+++ b/src/plugins/litehtml_viewer/litehtml/css_margins.h
@@ -12,10 +12,7 @@ namespace litehtml
 		css_length	top;
 		css_length	bottom;
 
-		css_margins()
-		{
-
-		}
+		css_margins() = default;
 
 		css_margins(const css_margins& val)
 		{
@@ -33,6 +30,14 @@ namespace litehtml
 			bottom	= val.bottom;
 			return *this;
 		}
+
+		string to_string() const
+		{
+			return	"left: " + left.to_string() +
+					", right: " + right.to_string() +
+					", top: " + top.to_string() +
+					", bottom: " + bottom.to_string();
+		}
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/css_offsets.h b/src/plugins/litehtml_viewer/litehtml/css_offsets.h
index 18d7f2652..5ab175ce2 100644
--- a/src/plugins/litehtml_viewer/litehtml/css_offsets.h
+++ b/src/plugins/litehtml_viewer/litehtml/css_offsets.h
@@ -12,10 +12,7 @@ namespace litehtml
 		css_length	right;
 		css_length	bottom;
 
-		css_offsets()
-		{
-
-		}
+		css_offsets() = default;
 
 		css_offsets(const css_offsets& val)
 		{
@@ -33,6 +30,14 @@ namespace litehtml
 			bottom	= val.bottom;
 			return *this;
 		}
+
+		string to_string() const
+		{
+			return	"left: " + left.to_string() +
+					", top: " + top.to_string() +
+					", right: " + right.to_string() +
+					", bottom: " + bottom.to_string();
+		}
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/css_position.h b/src/plugins/litehtml_viewer/litehtml/css_position.h
index 308a14fee..978a81ab5 100644
--- a/src/plugins/litehtml_viewer/litehtml/css_position.h
+++ b/src/plugins/litehtml_viewer/litehtml/css_position.h
@@ -11,29 +11,18 @@ namespace litehtml
 		css_length	y;
 		css_length	width;
 		css_length	height;
+	};
 
-		css_position()
-		{
-
-		}
-
-		css_position(const css_position& val)
-		{
-			x		= val.x;
-			y		= val.y;
-			width	= val.width;
-			height	= val.height;
-		}
+	struct css_size
+	{
+		css_length	width;
+		css_length	height;
 
-		css_position& operator=(const css_position& val)
-		{
-			x		= val.x;
-			y		= val.y;
-			width	= val.width;
-			height	= val.height;
-			return *this;
-		}
+		css_size() = default;
+		css_size(css_length width, css_length height) : width(width), height(height) {}
 	};
+
+	using size_vector = std::vector<css_size>;
 }
 
 #endif  // LH_CSS_POSITION_H
diff --git a/src/plugins/litehtml_viewer/litehtml/css_properties.cpp b/src/plugins/litehtml_viewer/litehtml/css_properties.cpp
new file mode 100644
index 000000000..1efccb609
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/css_properties.cpp
@@ -0,0 +1,456 @@
+#include "html.h"
+#include "css_properties.h"
+
+#define offset(member) ((uint_ptr)&this->member - (uint_ptr)this)
+
+void litehtml::css_properties::compute(const element* el, const document::ptr& doc)
+{
+	compute_font(el, doc);
+	int font_size = get_font_size();
+	m_color = el->get_color_property(_color_, true, web_color::black, offset(m_color));
+
+	m_el_position	 = (element_position) el->get_enum_property( _position_,		false,	element_position_static, offset(m_el_position));
+	m_display		 = (style_display)	  el->get_enum_property( _display_,			false,	display_inline,			 offset(m_display));
+	m_visibility	 = (visibility)		  el->get_enum_property( _visibility_,		true,	visibility_visible,		 offset(m_visibility));
+	m_float			 = (element_float)	  el->get_enum_property( _float_,			false,	float_none,				 offset(m_float));
+	m_clear			 = (element_clear)	  el->get_enum_property( _clear_,			false,	clear_none,				 offset(m_clear));
+	m_box_sizing	 = (box_sizing)		  el->get_enum_property( _box_sizing_,		false,	box_sizing_content_box,	 offset(m_box_sizing));
+	m_overflow		 = (overflow)		  el->get_enum_property( _overflow_,		false,	overflow_visible,		 offset(m_overflow));
+	m_text_align	 = (text_align)		  el->get_enum_property( _text_align_,		true,	text_align_left,		 offset(m_text_align));
+	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));
+
+	// https://www.w3.org/TR/CSS22/visuren.html#dis-pos-flo
+	if (m_display == display_none)
+	{
+		// 1. If 'display' has the value 'none', then 'position' and 'float' do not apply. In this case, the element
+		//    generates no box.
+		m_float = float_none;
+	} else
+	{
+		// 2. Otherwise, if 'position' has the value 'absolute' or 'fixed', the box is absolutely positioned,
+		//    the computed value of 'float' is 'none', and display is set according to the table below.
+		//    The position of the box will be determined by the 'top', 'right', 'bottom' and 'left' properties
+		//    and the box's containing block.
+		if (m_el_position == element_position_absolute || m_el_position == element_position_fixed)
+		{
+			m_float = float_none;
+
+			if (m_display == display_inline_table)
+			{
+				m_display = display_table;
+			} else if (m_display == display_inline ||
+					   m_display == display_table_row_group ||
+					   m_display == display_table_column ||
+					   m_display == display_table_column_group ||
+					   m_display == display_table_header_group ||
+					   m_display == display_table_footer_group ||
+					   m_display == display_table_row ||
+					   m_display == display_table_cell ||
+					   m_display == display_table_caption ||
+					   m_display == display_inline_block)
+			{
+				m_display = display_block;
+			}
+		} else if (m_float != float_none)
+		{
+			// 3. Otherwise, if 'float' has a value other than 'none', the box is floated and 'display' is set
+			//    according to the table below.
+			if (m_display == display_inline_table)
+			{
+				m_display = display_table;
+			} else if (m_display == display_inline ||
+					   m_display == display_table_row_group ||
+					   m_display == display_table_column ||
+					   m_display == display_table_column_group ||
+					   m_display == display_table_header_group ||
+					   m_display == display_table_footer_group ||
+					   m_display == display_table_row ||
+					   m_display == display_table_cell ||
+					   m_display == display_table_caption ||
+					   m_display == display_inline_block)
+			{
+				m_display = display_block;
+			}
+		} else if(el->is_root())
+		{
+			// 4. Otherwise, if the element is the root element, 'display' is set according to the table below,
+			//    except that it is undefined in CSS 2.2 whether a specified value of 'list-item' becomes a
+			//    computed value of 'block' or 'list-item'.
+			if (m_display == display_inline_table)
+			{
+				m_display = display_table;
+			} else if (m_display == display_inline ||
+				m_display == display_table_row_group ||
+				m_display == display_table_column ||
+				m_display == display_table_column_group ||
+				m_display == display_table_header_group ||
+				m_display == display_table_footer_group ||
+				m_display == display_table_row ||
+				m_display == display_table_cell ||
+				m_display == display_table_caption ||
+				m_display == display_inline_block ||
+				m_display == display_list_item)
+			{
+				m_display = display_block;
+			}
+		}
+	}
+	// 5. Otherwise, the remaining 'display' property values apply as specified.
+
+	const css_length _auto = css_length::predef_value(0);
+	const css_length none = _auto, normal = _auto;
+
+	m_css_width      = el->get_length_property(_width_,      false, _auto, offset(m_css_width));
+	m_css_height     = el->get_length_property(_height_,     false, _auto, offset(m_css_height));
+
+	m_css_min_width  = el->get_length_property(_min_width_,  false, _auto, offset(m_css_min_width));
+	m_css_min_height = el->get_length_property(_min_height_, false, _auto, offset(m_css_min_height));
+
+	m_css_max_width  = el->get_length_property(_max_width_,  false, none, offset(m_css_max_width));
+	m_css_max_height = el->get_length_property(_max_height_, false, none, offset(m_css_max_height));
+
+	doc->cvt_units(m_css_width, font_size);
+	doc->cvt_units(m_css_height, font_size);
+
+	doc->cvt_units(m_css_min_width, font_size);
+	doc->cvt_units(m_css_min_height, font_size);
+
+	doc->cvt_units(m_css_max_width, font_size);
+	doc->cvt_units(m_css_max_height, font_size);
+
+	m_css_margins.left   = el->get_length_property(_margin_left_,   false, 0, offset(m_css_margins.left));
+	m_css_margins.right  = el->get_length_property(_margin_right_,  false, 0, offset(m_css_margins.right));
+	m_css_margins.top    = el->get_length_property(_margin_top_,    false, 0, offset(m_css_margins.top));
+	m_css_margins.bottom = el->get_length_property(_margin_bottom_, false, 0, offset(m_css_margins.bottom));
+
+	doc->cvt_units(m_css_margins.left,	 font_size);
+	doc->cvt_units(m_css_margins.right,	 font_size);
+	doc->cvt_units(m_css_margins.top,	 font_size);
+	doc->cvt_units(m_css_margins.bottom, font_size);
+
+	m_css_padding.left   = el->get_length_property(_padding_left_,   false, 0, offset(m_css_padding.left));
+	m_css_padding.right  = el->get_length_property(_padding_right_,  false, 0, offset(m_css_padding.right));
+	m_css_padding.top    = el->get_length_property(_padding_top_,    false, 0, offset(m_css_padding.top));
+	m_css_padding.bottom = el->get_length_property(_padding_bottom_, false, 0, offset(m_css_padding.bottom));
+
+	doc->cvt_units(m_css_padding.left,	 font_size);
+	doc->cvt_units(m_css_padding.right,	 font_size);
+	doc->cvt_units(m_css_padding.top,	 font_size);
+	doc->cvt_units(m_css_padding.bottom, font_size);
+
+	m_css_borders.left.color   = el->get_color_property(_border_left_color_,   false, m_color, offset(m_css_borders.left.color));
+	m_css_borders.right.color  = el->get_color_property(_border_right_color_,  false, m_color, offset(m_css_borders.right.color));
+	m_css_borders.top.color    = el->get_color_property(_border_top_color_,    false, m_color, offset(m_css_borders.top.color));
+	m_css_borders.bottom.color = el->get_color_property(_border_bottom_color_, false, m_color, offset(m_css_borders.bottom.color));
+
+	m_css_borders.left.style   = (border_style) el->get_enum_property(_border_left_style_,   false, border_style_none, offset(m_css_borders.left.style));
+	m_css_borders.right.style  = (border_style) el->get_enum_property(_border_right_style_,  false, border_style_none, offset(m_css_borders.right.style));
+	m_css_borders.top.style    = (border_style) el->get_enum_property(_border_top_style_,    false, border_style_none, offset(m_css_borders.top.style));
+	m_css_borders.bottom.style = (border_style) el->get_enum_property(_border_bottom_style_, false, border_style_none, offset(m_css_borders.bottom.style));
+
+	m_css_borders.left.width   = el->get_length_property(_border_left_width_,   false, border_width_medium_value, offset(m_css_borders.left.width));
+	m_css_borders.right.width  = el->get_length_property(_border_right_width_,  false, border_width_medium_value, offset(m_css_borders.right.width));
+	m_css_borders.top.width    = el->get_length_property(_border_top_width_,    false, border_width_medium_value, offset(m_css_borders.top.width));
+	m_css_borders.bottom.width = el->get_length_property(_border_bottom_width_, false, border_width_medium_value, offset(m_css_borders.bottom.width));
+
+	if (m_css_borders.left.style == border_style_none || m_css_borders.left.style == border_style_hidden)
+		m_css_borders.left.width = 0;
+	if (m_css_borders.right.style == border_style_none || m_css_borders.right.style == border_style_hidden)
+		m_css_borders.right.width = 0;
+	if (m_css_borders.top.style == border_style_none || m_css_borders.top.style == border_style_hidden)
+		m_css_borders.top.width = 0;
+	if (m_css_borders.bottom.style == border_style_none || m_css_borders.bottom.style == border_style_hidden)
+		m_css_borders.bottom.width = 0;
+
+	doc->cvt_units(m_css_borders.left.width,	font_size);
+	doc->cvt_units(m_css_borders.right.width,	font_size);
+	doc->cvt_units(m_css_borders.top.width,		font_size);
+	doc->cvt_units(m_css_borders.bottom.width,	font_size);
+
+	m_css_borders.radius.top_left_x = el->get_length_property(_border_top_left_radius_x_, false, 0, offset(m_css_borders.radius.top_left_x));
+	m_css_borders.radius.top_left_y = el->get_length_property(_border_top_left_radius_y_, false, 0, offset(m_css_borders.radius.top_left_y));
+
+	m_css_borders.radius.top_right_x = el->get_length_property(_border_top_right_radius_x_, false, 0, offset(m_css_borders.radius.top_right_x));
+	m_css_borders.radius.top_right_y = el->get_length_property(_border_top_right_radius_y_, false, 0, offset(m_css_borders.radius.top_right_y));
+
+	m_css_borders.radius.bottom_left_x = el->get_length_property(_border_bottom_left_radius_x_, false, 0, offset(m_css_borders.radius.bottom_left_x));
+	m_css_borders.radius.bottom_left_y = el->get_length_property(_border_bottom_left_radius_y_, false, 0, offset(m_css_borders.radius.bottom_left_y));
+
+	m_css_borders.radius.bottom_right_x = el->get_length_property(_border_bottom_right_radius_x_, false, 0, offset(m_css_borders.radius.bottom_right_x));
+	m_css_borders.radius.bottom_right_y = el->get_length_property(_border_bottom_right_radius_y_, false, 0, offset(m_css_borders.radius.bottom_right_y));
+
+	doc->cvt_units( m_css_borders.radius.top_left_x,			font_size);
+	doc->cvt_units( m_css_borders.radius.top_left_y,			font_size);
+	doc->cvt_units( m_css_borders.radius.top_right_x,			font_size);
+	doc->cvt_units( m_css_borders.radius.top_right_y,			font_size);
+	doc->cvt_units( m_css_borders.radius.bottom_left_x,			font_size);
+	doc->cvt_units( m_css_borders.radius.bottom_left_y,			font_size);
+	doc->cvt_units( m_css_borders.radius.bottom_right_x,		font_size);
+	doc->cvt_units( m_css_borders.radius.bottom_right_y,		font_size);
+
+	m_border_collapse = (border_collapse) el->get_enum_property(_border_collapse_, true, border_collapse_separate, offset(m_border_collapse));
+
+	m_css_border_spacing_x = el->get_length_property(__litehtml_border_spacing_x_, true, 0, offset(m_css_border_spacing_x));
+	m_css_border_spacing_y = el->get_length_property(__litehtml_border_spacing_y_, true, 0, offset(m_css_border_spacing_y));
+
+	doc->cvt_units(m_css_border_spacing_x, font_size);
+	doc->cvt_units(m_css_border_spacing_y, font_size);
+
+	m_css_offsets.left	 = el->get_length_property(_left_,	false, _auto, offset(m_css_offsets.left));
+	m_css_offsets.right  = el->get_length_property(_right_, false, _auto, offset(m_css_offsets.right));
+	m_css_offsets.top	 = el->get_length_property(_top_,	false, _auto, offset(m_css_offsets.top));
+	m_css_offsets.bottom = el->get_length_property(_bottom_,false, _auto, offset(m_css_offsets.bottom));
+
+	doc->cvt_units(m_css_offsets.left,   font_size);
+	doc->cvt_units(m_css_offsets.right,  font_size);
+	doc->cvt_units(m_css_offsets.top,    font_size);
+	doc->cvt_units(m_css_offsets.bottom, font_size);
+
+	m_z_index = el->get_length_property(_z_index_, false, _auto, offset(m_z_index));
+	m_content = el->get_string_property(_content_, false, "", offset(m_content));
+	m_cursor = el->get_string_property(_cursor_, true, "auto", offset(m_cursor));
+
+	m_css_text_indent = el->get_length_property(_text_indent_, true, 0, offset(m_css_text_indent));
+	doc->cvt_units(m_css_text_indent, font_size);
+
+	m_css_line_height = el->get_length_property(_line_height_, true, normal, offset(m_css_line_height));
+	if(m_css_line_height.is_predefined())
+	{
+		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);
+	} else
+	{
+		m_line_height = doc->to_pixels(m_css_line_height, font_size, font_size);
+		m_css_line_height = (float) m_line_height;
+	}
+
+	m_list_style_type     = (list_style_type)     el->get_enum_property(_list_style_type_,     true, list_style_type_disc,        offset(m_list_style_type));
+	m_list_style_position = (list_style_position) el->get_enum_property(_list_style_position_, true, list_style_position_outside, offset(m_list_style_position));
+
+	m_list_style_image = el->get_string_property(_list_style_image_, true, "", offset(m_list_style_image));
+	if (!m_list_style_image.empty())
+	{
+		m_list_style_image_baseurl = el->get_string_property(_list_style_image_baseurl_, true, "", offset(m_list_style_image_baseurl));
+		doc->container()->load_image(m_list_style_image.c_str(), m_list_style_image_baseurl.c_str(), true);
+	}
+
+	compute_background(el, doc);
+	compute_flex(el, doc);
+}
+
+static const int font_size_table[8][7] =
+{
+		{ 9,    9,     9,     9,    11,    14,    18},
+		{ 9,    9,     9,    10,    12,    15,    20},
+		{ 9,    9,     9,    11,    13,    17,    22},
+		{ 9,    9,    10,    12,    14,    18,    24},
+		{ 9,    9,    10,    13,    16,    20,    26},
+		{ 9,    9,    11,    14,    17,    21,    28},
+		{ 9,   10,    12,    15,    17,    23,    30},
+		{ 9,   10,    13,    16,    18,    24,    32}
+};
+
+void litehtml::css_properties::compute_font(const element* el, const document::ptr& doc)
+{
+	// initialize font size
+	css_length sz = el->get_length_property(_font_size_, true, css_length::predef_value(font_size_medium), offset(m_font_size));
+
+	int parent_sz = 0;
+	int doc_font_size = doc->container()->get_default_font_size();
+	element::ptr el_parent = el->parent();
+	if (el_parent)
+	{
+		parent_sz = el_parent->css().get_font_size();
+	} else
+	{
+		parent_sz = doc_font_size;
+	}
+	
+	int font_size = parent_sz;
+
+	if(sz.is_predefined())
+	{
+		int idx_in_table = doc_font_size - 9;
+		if(idx_in_table >= 0 && idx_in_table <= 7)
+		{
+			if(sz.predef() >= font_size_xx_small && sz.predef() <= font_size_xx_large)
+			{
+				font_size = font_size_table[idx_in_table][sz.predef()];
+			} else if(sz.predef() == font_size_smaller)
+			{
+				font_size = (int) (parent_sz / 1.2);
+			}  else if(sz.predef() == font_size_larger)
+			{
+				font_size = (int) (parent_sz * 1.2);
+			} else
+			{
+				font_size = parent_sz;
+			}
+		} else
+		{
+			switch(sz.predef())
+			{
+				case font_size_xx_small:
+					font_size = doc_font_size * 3 / 5;
+					break;
+				case font_size_x_small:
+					font_size = doc_font_size * 3 / 4;
+					break;
+				case font_size_small:
+					font_size = doc_font_size * 8 / 9;
+					break;
+				case font_size_large:
+					font_size = doc_font_size * 6 / 5;
+					break;
+				case font_size_x_large:
+					font_size = doc_font_size * 3 / 2;
+					break;
+				case font_size_xx_large:
+					font_size = doc_font_size * 2;
+					break;
+				case font_size_smaller:
+					font_size = (int) (parent_sz / 1.2);
+					break;
+				case font_size_larger:
+					font_size = (int) (parent_sz * 1.2);
+					break;
+				default:
+					font_size = parent_sz;
+					break;
+			}
+		}
+	} else
+	{
+		if(sz.units() == css_units_percentage)
+		{
+			font_size = sz.calc_percent(parent_sz);
+		} else
+		{
+			font_size = doc->to_pixels(sz, parent_sz);
+		}
+	}
+	
+	m_font_size = (float)font_size;
+
+	// initialize font
+	m_font_family		=               el->get_string_property(_font_family_,		true, doc->container()->get_default_font_name(),	offset(m_font_family));
+	m_font_weight		= (font_weight) el->get_enum_property(  _font_weight_,		true, font_weight_normal,							offset(m_font_weight));
+	m_font_style		= (font_style)  el->get_enum_property(  _font_style_,		true, font_style_normal,							offset(m_font_style));
+	m_text_decoration	=               el->get_string_property(_text_decoration_,	true, "none",										offset(m_text_decoration));
+
+	m_font = doc->get_font(
+		m_font_family.c_str(), 
+		font_size, 
+		index_value(m_font_weight, font_weight_strings).c_str(), 
+		index_value(m_font_style, font_style_strings).c_str(),
+		m_text_decoration.c_str(), 
+		&m_font_metrics);
+}
+
+void litehtml::css_properties::compute_background(const element* el, const document::ptr& doc)
+{
+	int font_size = get_font_size();
+
+	m_bg.m_color		= el->get_color_property(_background_color_, false, web_color::transparent, offset(m_bg.m_color));
+
+	const css_size auto_auto(css_length::predef_value(background_size_auto), css_length::predef_value(background_size_auto));
+	m_bg.m_position_x	= el->get_length_vector_property(_background_position_x_, false, { css_length(0, css_units_percentage) }, offset(m_bg.m_position_x));
+	m_bg.m_position_y	= el->get_length_vector_property(_background_position_y_, false, { css_length(0, css_units_percentage) }, offset(m_bg.m_position_y));
+	m_bg.m_size			= el->get_size_vector_property  (_background_size_,       false, { auto_auto }, offset(m_bg.m_size));
+
+	for (auto& x : m_bg.m_position_x) doc->cvt_units(x, font_size);
+	for (auto& y : m_bg.m_position_y) doc->cvt_units(y, font_size);
+	for (auto& size : m_bg.m_size)
+	{
+		doc->cvt_units(size.width,  font_size);
+		doc->cvt_units(size.height, font_size);
+	}
+
+	m_bg.m_attachment = el->get_int_vector_property(_background_attachment_, false, { background_attachment_scroll }, offset(m_bg.m_attachment));
+	m_bg.m_repeat     = el->get_int_vector_property(_background_repeat_,     false, { background_repeat_repeat },     offset(m_bg.m_repeat));
+	m_bg.m_clip       = el->get_int_vector_property(_background_clip_,       false, { background_box_border },        offset(m_bg.m_clip));
+	m_bg.m_origin     = el->get_int_vector_property(_background_origin_,     false, { background_box_padding },       offset(m_bg.m_origin));
+
+	m_bg.m_image   = el->get_string_vector_property(_background_image_,  false, {""}, offset(m_bg.m_image));
+	m_bg.m_baseurl = el->get_string_property(_background_image_baseurl_, false, "",   offset(m_bg.m_baseurl));
+
+	for (const auto& image : m_bg.m_image)
+	{
+		if (!image.empty())
+		{
+			doc->container()->load_image(image.c_str(), m_bg.m_baseurl.c_str(), true);
+		}
+	}
+}
+
+void litehtml::css_properties::compute_flex(const element* el, const document::ptr& doc)
+{
+	if (m_display == display_flex)
+	{
+		m_flex_direction = (flex_direction) el->get_enum_property(_flex_direction_, false, flex_direction_row, offset(m_flex_direction));
+		m_flex_wrap = (flex_wrap) el->get_enum_property(_flex_wrap_, false, flex_wrap_nowrap, offset(m_flex_wrap));
+
+		m_flex_justify_content = (flex_justify_content) el->get_enum_property(_justify_content_, false, flex_justify_content_flex_start, offset(m_flex_justify_content));
+		m_flex_align_items = (flex_align_items) el->get_enum_property(_align_items_, false, flex_align_items_stretch, offset(m_flex_align_items));
+		m_flex_align_content = (flex_align_content) el->get_enum_property(_align_content_, false, flex_align_content_stretch, offset(m_flex_align_content));
+	}
+	auto parent = el->parent();
+	if (parent && parent->css().m_display == display_flex)
+	{
+		m_flex_grow = el->get_number_property(_flex_grow_, false, 0, offset(m_flex_grow));
+		m_flex_shrink = el->get_number_property(_flex_shrink_, false, 1, offset(m_flex_shrink));
+		m_flex_align_self = (flex_align_self) el->get_enum_property(_align_self_, false, flex_align_self_auto, offset(m_flex_align_self));
+		m_flex_basis = el->get_length_property(_flex_shrink_, false, css_length::predef_value(flex_basis_auto), offset(m_flex_basis));
+		doc->cvt_units(m_flex_basis, get_font_size());
+		if(m_display == display_inline || m_display == display_inline_block)
+		{
+			m_display = display_block;
+		} else if(m_display == display_inline_table)
+		{
+			m_display = display_table;
+		} else if(m_display == display_inline_flex)
+		{
+			m_display = display_flex;
+		}
+	}
+}
+
+std::vector<std::tuple<litehtml::string, litehtml::string>> litehtml::css_properties::dump_get_attrs()
+{
+	std::vector<std::tuple<string, string>> ret;
+
+	ret.emplace_back(std::make_tuple("display", index_value(m_display, style_display_strings)));
+	ret.emplace_back(std::make_tuple("el_position", index_value(m_el_position, element_position_strings)));
+	ret.emplace_back(std::make_tuple("text_align", index_value(m_text_align, text_align_strings)));
+	ret.emplace_back(std::make_tuple("font_size", m_font_size.to_string()));
+	ret.emplace_back(std::make_tuple("overflow", index_value(m_overflow, overflow_strings)));
+	ret.emplace_back(std::make_tuple("white_space", index_value(m_white_space, white_space_strings)));
+	ret.emplace_back(std::make_tuple("visibility", index_value(m_visibility, visibility_strings)));
+	ret.emplace_back(std::make_tuple("box_sizing", index_value(m_box_sizing, box_sizing_strings)));
+	ret.emplace_back(std::make_tuple("z_index", m_z_index.to_string()));
+	ret.emplace_back(std::make_tuple("vertical_align", index_value(m_vertical_align, vertical_align_strings)));
+	ret.emplace_back(std::make_tuple("float", index_value(m_float, element_float_strings)));
+	ret.emplace_back(std::make_tuple("clear", index_value(m_clear, element_clear_strings)));
+	ret.emplace_back(std::make_tuple("margins", m_css_margins.to_string()));
+	ret.emplace_back(std::make_tuple("padding", m_css_padding.to_string()));
+	ret.emplace_back(std::make_tuple("borders", m_css_borders.to_string()));
+	ret.emplace_back(std::make_tuple("width", m_css_width.to_string()));
+	ret.emplace_back(std::make_tuple("height", m_css_height.to_string()));
+	ret.emplace_back(std::make_tuple("min_width", m_css_min_width.to_string()));
+	ret.emplace_back(std::make_tuple("min_height", m_css_min_width.to_string()));
+	ret.emplace_back(std::make_tuple("max_width", m_css_max_width.to_string()));
+	ret.emplace_back(std::make_tuple("max_height", m_css_max_width.to_string()));
+	ret.emplace_back(std::make_tuple("offsets", m_css_offsets.to_string()));
+	ret.emplace_back(std::make_tuple("text_indent", m_css_text_indent.to_string()));
+	ret.emplace_back(std::make_tuple("line_height", std::to_string(m_line_height)));
+	ret.emplace_back(std::make_tuple("list_style_type", index_value(m_list_style_type, list_style_type_strings)));
+	ret.emplace_back(std::make_tuple("list_style_position", index_value(m_list_style_position, list_style_position_strings)));
+	ret.emplace_back(std::make_tuple("border_spacing_x", m_css_border_spacing_x.to_string()));
+	ret.emplace_back(std::make_tuple("border_spacing_y", m_css_border_spacing_y.to_string()));
+
+	return ret;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/css_properties.h b/src/plugins/litehtml_viewer/litehtml/css_properties.h
new file mode 100644
index 000000000..0eed09d9a
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/css_properties.h
@@ -0,0 +1,643 @@
+#ifndef LITEHTML_CSS_PROPERTIES_H
+#define LITEHTML_CSS_PROPERTIES_H
+
+#include "os_types.h"
+#include "types.h"
+#include "css_margins.h"
+#include "borders.h"
+#include "css_offsets.h"
+#include "background.h"
+
+namespace litehtml
+{
+	class element;
+	class document;
+
+	class css_properties
+	{
+	private:
+		element_position		m_el_position;
+		text_align				m_text_align;
+		overflow				m_overflow;
+		white_space				m_white_space;
+		style_display			m_display;
+		visibility				m_visibility;
+		box_sizing				m_box_sizing;
+		css_length				m_z_index;
+		vertical_align			m_vertical_align;
+		element_float			m_float;
+		element_clear			m_clear;
+		css_margins				m_css_margins;
+		css_margins				m_css_padding;
+		css_borders				m_css_borders;
+		css_length				m_css_width;
+		css_length				m_css_height;
+		css_length				m_css_min_width;
+		css_length				m_css_min_height;
+		css_length				m_css_max_width;
+		css_length				m_css_max_height;
+		css_offsets				m_css_offsets;
+		css_length				m_css_text_indent;
+		css_length				m_css_line_height;
+		int						m_line_height;
+		list_style_type			m_list_style_type;
+		list_style_position		m_list_style_position;
+		string					m_list_style_image;
+		string					m_list_style_image_baseurl;
+		background				m_bg;
+		uint_ptr				m_font;
+		css_length				m_font_size;
+		string					m_font_family;
+		font_weight				m_font_weight;
+		font_style				m_font_style;
+		string					m_text_decoration;
+		font_metrics			m_font_metrics;
+		text_transform			m_text_transform;
+		web_color				m_color;
+		string					m_cursor;
+		string					m_content;
+		border_collapse			m_border_collapse;
+		css_length				m_css_border_spacing_x;
+		css_length				m_css_border_spacing_y;
+
+		float					m_flex_grow;
+		float					m_flex_shrink;
+		css_length				m_flex_basis;
+		flex_direction			m_flex_direction;
+		flex_wrap				m_flex_wrap;
+		flex_justify_content	m_flex_justify_content;
+		flex_align_items		m_flex_align_items;
+		flex_align_self			m_flex_align_self;
+		flex_align_content		m_flex_align_content;
+
+	private:
+		void compute_font(const element* el, const std::shared_ptr<document>& doc);
+		void compute_background(const element* el, const std::shared_ptr<document>& doc);
+		void compute_flex(const element* el, const std::shared_ptr<document>& doc);
+
+	public:
+		css_properties() :
+				m_el_position(element_position_static),
+				m_text_align(text_align_left),
+				m_overflow(overflow_visible),
+				m_white_space(white_space_normal),
+				m_display(display_inline),
+				m_visibility(visibility_visible),
+				m_box_sizing(box_sizing_content_box),
+				m_z_index(0),
+				m_vertical_align(va_baseline),
+				m_float(float_none),
+				m_clear(clear_none),
+				m_css_margins(),
+				m_css_padding(),
+				m_css_borders(),
+				m_css_width(),
+				m_css_height(),
+				m_css_min_width(),
+				m_css_min_height(),
+				m_css_max_width(),
+				m_css_max_height(),
+				m_css_offsets(),
+				m_css_text_indent(),
+				m_css_line_height(0),
+				m_line_height(0),
+				m_list_style_type(list_style_type_none),
+				m_list_style_position(list_style_position_outside),
+				m_bg(),
+				m_font_size(0),
+				m_font(0),
+				m_font_metrics(),
+				m_text_transform(text_transform_none),
+				m_border_collapse(border_collapse_separate),
+				m_css_border_spacing_x(),
+				m_css_border_spacing_y(),
+				m_flex_grow(0),
+				m_flex_shrink(1),
+				m_flex_direction(flex_direction_row),
+				m_flex_wrap(flex_wrap_nowrap),
+				m_flex_justify_content(flex_justify_content_flex_start),
+				m_flex_align_items(flex_align_items_stretch),
+				m_flex_align_self(flex_align_self_auto),
+				m_flex_align_content(flex_align_content_stretch)
+		{}
+
+		void compute(const element* el, const std::shared_ptr<document>& doc);
+		std::vector<std::tuple<string, string>> dump_get_attrs();
+
+		element_position get_position() const;
+		void set_position(element_position mElPosition);
+
+		text_align get_text_align() const;
+		void set_text_align(text_align mTextAlign);
+
+		overflow get_overflow() const;
+		void set_overflow(overflow mOverflow);
+
+		white_space get_white_space() const;
+		void set_white_space(white_space mWhiteSpace);
+
+		style_display get_display() const;
+		void set_display(style_display mDisplay);
+
+		visibility get_visibility() const;
+		void set_visibility(visibility mVisibility);
+
+		box_sizing get_box_sizing() const;
+		void set_box_sizing(box_sizing mBoxSizing);
+
+		int get_z_index() const;
+		void set_z_index(int mZIndex);
+
+		vertical_align get_vertical_align() const;
+		void set_vertical_align(vertical_align mVerticalAlign);
+
+		element_float get_float() const;
+		void set_float(element_float mFloat);
+
+		element_clear get_clear() const;
+		void set_clear(element_clear mClear);
+
+		const css_margins &get_margins() const;
+		void set_margins(const css_margins &mCssMargins);
+
+		const css_margins &get_padding() const;
+		void set_padding(const css_margins &mCssPadding);
+
+		const css_borders &get_borders() const;
+		void set_borders(const css_borders &mCssBorders);
+
+		const css_length &get_width() const;
+		void set_width(const css_length &mCssWidth);
+
+		const css_length &get_height() const;
+		void set_height(const css_length &mCssHeight);
+
+		const css_length &get_min_width() const;
+		void set_min_width(const css_length &mCssMinWidth);
+
+		const css_length &get_min_height() const;
+		void set_min_height(const css_length &mCssMinHeight);
+
+		const css_length &get_max_width() const;
+		void set_max_width(const css_length &mCssMaxWidth);
+
+		const css_length &get_max_height() const;
+		void set_max_height(const css_length &mCssMaxHeight);
+
+		const css_offsets &get_offsets() const;
+		void set_offsets(const css_offsets &mCssOffsets);
+
+		const css_length &get_text_indent() const;
+		void set_text_indent(const css_length &mCssTextIndent);
+
+		int get_line_height() const;
+		void set_line_height(int mLineHeight);
+
+		list_style_type get_list_style_type() const;
+		void set_list_style_type(list_style_type mListStyleType);
+
+		list_style_position get_list_style_position() const;
+		void set_list_style_position(list_style_position mListStylePosition);
+
+		string get_list_style_image() const;
+		void set_list_style_image(const string& url);
+
+		string get_list_style_image_baseurl() const;
+		void set_list_style_image_baseurl(const string& url);
+
+		const background &get_bg() const;
+		void set_bg(const background &mBg);
+
+		int get_font_size() const;
+		void set_font_size(int mFontSize);
+
+		uint_ptr get_font() const;
+		void set_font(uint_ptr mFont);
+
+		const font_metrics& get_font_metrics() const;
+		void set_font_metrics(const font_metrics& mFontMetrics);
+
+		text_transform get_text_transform() const;
+		void set_text_transform(text_transform mTextTransform);
+
+		web_color get_color() const;
+		void set_color(web_color color);
+
+		string get_cursor() const;
+		void set_cursor(const string& cursor);
+
+		string get_content() const;
+		void set_content(const string& content);
+
+		border_collapse get_border_collapse() const;
+		void set_border_collapse(border_collapse mBorderCollapse);
+
+		const css_length& get_border_spacing_x() const ;
+		void set_border_spacing_x(const css_length& mBorderSpacingX);
+
+		const css_length& get_border_spacing_y() const;
+		void set_border_spacing_y(const css_length& mBorderSpacingY);
+
+		float get_flex_grow() const;
+		float get_flex_shrink() const;
+		const css_length& get_flex_basis() const;
+		flex_direction get_flex_direction() const;
+		flex_wrap get_flex_wrap() const;
+		flex_justify_content get_flex_justify_content() const;
+		flex_align_items get_flex_align_items() const;
+		flex_align_self get_flex_align_self() const;
+		flex_align_content get_flex_align_content() const;
+	};
+
+	inline element_position css_properties::get_position() const
+	{
+		return m_el_position;
+	}
+
+	inline void css_properties::set_position(element_position mElPosition)
+	{
+		m_el_position = mElPosition;
+	}
+
+	inline text_align css_properties::get_text_align() const
+	{
+		return m_text_align;
+	}
+
+	inline void css_properties::set_text_align(text_align mTextAlign)
+	{
+		m_text_align = mTextAlign;
+	}
+
+	inline overflow css_properties::get_overflow() const
+	{
+		return m_overflow;
+	}
+
+	inline void css_properties::set_overflow(overflow mOverflow)
+	{
+		m_overflow = mOverflow;
+	}
+
+	inline white_space css_properties::get_white_space() const
+	{
+		return m_white_space;
+	}
+
+	inline void css_properties::set_white_space(white_space mWhiteSpace)
+	{
+		m_white_space = mWhiteSpace;
+	}
+
+	inline style_display css_properties::get_display() const
+	{
+		return m_display;
+	}
+
+	inline void css_properties::set_display(style_display mDisplay)
+	{
+		m_display = mDisplay;
+	}
+
+	inline visibility css_properties::get_visibility() const
+	{
+		return m_visibility;
+	}
+
+	inline void css_properties::set_visibility(visibility mVisibility)
+	{
+		m_visibility = mVisibility;
+	}
+
+	inline box_sizing css_properties::get_box_sizing() const
+	{
+		return m_box_sizing;
+	}
+
+	inline void css_properties::set_box_sizing(box_sizing mBoxSizing)
+	{
+		m_box_sizing = mBoxSizing;
+	}
+
+	inline int css_properties::get_z_index() const
+	{
+		return (int)m_z_index.val();
+	}
+
+	inline void css_properties::set_z_index(int mZIndex)
+	{
+		m_z_index.set_value((float)mZIndex, css_units_none);
+	}
+
+	inline vertical_align css_properties::get_vertical_align() const
+	{
+		return m_vertical_align;
+	}
+
+	inline void css_properties::set_vertical_align(vertical_align mVerticalAlign)
+	{
+		m_vertical_align = mVerticalAlign;
+	}
+
+	inline element_float css_properties::get_float() const
+	{
+		return m_float;
+	}
+
+	inline void css_properties::set_float(element_float mFloat)
+	{
+		m_float = mFloat;
+	}
+
+	inline element_clear css_properties::get_clear() const
+	{
+		return m_clear;
+	}
+
+	inline void css_properties::set_clear(element_clear mClear)
+	{
+		m_clear = mClear;
+	}
+
+	inline const css_margins &css_properties::get_margins() const
+	{
+		return m_css_margins;
+	}
+
+	inline void css_properties::set_margins(const css_margins &mCssMargins)
+	{
+		m_css_margins = mCssMargins;
+	}
+
+	inline const css_margins &css_properties::get_padding() const
+	{
+		return m_css_padding;
+	}
+
+	inline void css_properties::set_padding(const css_margins &mCssPadding)
+	{
+		m_css_padding = mCssPadding;
+	}
+
+	inline const css_borders &css_properties::get_borders() const
+	{
+		return m_css_borders;
+	}
+
+	inline void css_properties::set_borders(const css_borders &mCssBorders)
+	{
+		m_css_borders = mCssBorders;
+	}
+
+	inline const css_length &css_properties::get_width() const
+	{
+		return m_css_width;
+	}
+
+	inline void css_properties::set_width(const css_length &mCssWidth)
+	{
+		m_css_width = mCssWidth;
+	}
+
+	inline const css_length &css_properties::get_height() const
+	{
+		return m_css_height;
+	}
+
+	inline void css_properties::set_height(const css_length &mCssHeight)
+	{
+		m_css_height = mCssHeight;
+	}
+
+	inline const css_length &css_properties::get_min_width() const
+	{
+		return m_css_min_width;
+	}
+
+	inline void css_properties::set_min_width(const css_length &mCssMinWidth)
+	{
+		m_css_min_width = mCssMinWidth;
+	}
+
+	inline const css_length &css_properties::get_min_height() const
+	{
+		return m_css_min_height;
+	}
+
+	inline void css_properties::set_min_height(const css_length &mCssMinHeight)
+	{
+		m_css_min_height = mCssMinHeight;
+	}
+
+	inline const css_length &css_properties::get_max_width() const
+	{
+		return m_css_max_width;
+	}
+
+	inline void css_properties::set_max_width(const css_length &mCssMaxWidth)
+	{
+		m_css_max_width = mCssMaxWidth;
+	}
+
+	inline const css_length &css_properties::get_max_height() const
+	{
+		return m_css_max_height;
+	}
+
+	inline void css_properties::set_max_height(const css_length &mCssMaxHeight)
+	{
+		m_css_max_height = mCssMaxHeight;
+	}
+
+	inline const css_offsets &css_properties::get_offsets() const
+	{
+		return m_css_offsets;
+	}
+
+	inline void css_properties::set_offsets(const css_offsets &mCssOffsets)
+	{
+		m_css_offsets = mCssOffsets;
+	}
+
+	inline const css_length &css_properties::get_text_indent() const
+	{
+		return m_css_text_indent;
+	}
+
+	inline void css_properties::set_text_indent(const css_length &mCssTextIndent)
+	{
+		m_css_text_indent = mCssTextIndent;
+	}
+
+	inline int css_properties::get_line_height() const
+	{
+		return m_line_height;
+	}
+
+	inline void css_properties::set_line_height(int mLineHeight)
+	{
+		m_line_height = mLineHeight;
+	}
+
+	inline list_style_type css_properties::get_list_style_type() const
+	{
+		return m_list_style_type;
+	}
+
+	inline void css_properties::set_list_style_type(list_style_type mListStyleType)
+	{
+		m_list_style_type = mListStyleType;
+	}
+
+	inline list_style_position css_properties::get_list_style_position() const
+	{
+		return m_list_style_position;
+	}
+
+	inline void css_properties::set_list_style_position(list_style_position mListStylePosition)
+	{
+		m_list_style_position = mListStylePosition;
+	}
+
+	inline string css_properties::get_list_style_image() const { return m_list_style_image; }
+	inline void css_properties::set_list_style_image(const string& url) { m_list_style_image = url; }
+
+	inline string css_properties::get_list_style_image_baseurl() const { return m_list_style_image_baseurl; }
+	inline void css_properties::set_list_style_image_baseurl(const string& url) { m_list_style_image_baseurl = url; }
+
+	inline const background &css_properties::get_bg() const
+	{
+		return m_bg;
+	}
+
+	inline void css_properties::set_bg(const background &mBg)
+	{
+		m_bg = mBg;
+	}
+
+	inline int css_properties::get_font_size() const
+	{
+		return (int)m_font_size.val();
+	}
+
+	inline void css_properties::set_font_size(int mFontSize)
+	{
+		m_font_size = (float)mFontSize;
+	}
+
+	inline uint_ptr css_properties::get_font() const
+	{
+		return m_font;
+	}
+
+	inline void css_properties::set_font(uint_ptr mFont)
+	{
+		m_font = mFont;
+	}
+
+	inline const font_metrics& css_properties::get_font_metrics() const
+	{
+		return m_font_metrics;
+	}
+
+	inline void css_properties::set_font_metrics(const font_metrics& mFontMetrics)
+	{
+		m_font_metrics = mFontMetrics;
+	}
+
+	inline text_transform css_properties::get_text_transform() const
+	{
+		return m_text_transform;
+	}
+
+	inline void css_properties::set_text_transform(text_transform mTextTransform)
+	{
+		m_text_transform = mTextTransform;
+	}
+
+	inline web_color css_properties::get_color() const { return m_color; }
+	inline void css_properties::set_color(web_color color) { m_color = color; }
+
+	inline string css_properties::get_cursor() const { return m_cursor; }
+	inline void css_properties::set_cursor(const string& cursor) { m_cursor = cursor; }
+
+	inline string css_properties::get_content() const { return m_content; }
+	inline void css_properties::set_content(const string& content) { m_content = content; }
+
+	inline border_collapse css_properties::get_border_collapse() const
+	{
+		return m_border_collapse;
+	}
+
+	inline void css_properties::set_border_collapse(border_collapse mBorderCollapse)
+	{
+		m_border_collapse = mBorderCollapse;
+	}
+
+	inline const css_length& css_properties::get_border_spacing_x() const
+	{
+		return m_css_border_spacing_x;
+	}
+
+	inline void css_properties::set_border_spacing_x(const css_length& mBorderSpacingX)
+	{
+		m_css_border_spacing_x = mBorderSpacingX;
+	}
+
+	inline const css_length& css_properties::get_border_spacing_y() const
+	{
+		return m_css_border_spacing_y;
+	}
+
+	inline void css_properties::set_border_spacing_y(const css_length& mBorderSpacingY)
+	{
+		m_css_border_spacing_y = mBorderSpacingY;
+	}
+
+	inline float css_properties::get_flex_grow() const
+	{
+		return m_flex_grow;
+	}
+
+	inline float css_properties::get_flex_shrink() const
+	{
+		return m_flex_shrink;
+	}
+
+	inline const css_length& css_properties::get_flex_basis() const
+	{
+		return m_flex_basis;
+	}
+
+	inline flex_direction css_properties::get_flex_direction() const
+	{
+		return m_flex_direction;
+	}
+
+	inline flex_wrap css_properties::get_flex_wrap() const
+	{
+		return m_flex_wrap;
+	}
+
+	inline flex_justify_content css_properties::get_flex_justify_content() const
+	{
+		return m_flex_justify_content;
+	}
+
+	inline flex_align_items css_properties::get_flex_align_items() const
+	{
+		return m_flex_align_items;
+	}
+
+	inline flex_align_self css_properties::get_flex_align_self() const
+	{
+		return m_flex_align_self;
+	}
+
+	inline flex_align_content css_properties::get_flex_align_content() const
+	{
+		return m_flex_align_content;
+	}
+}
+
+#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 e0a7ed445..6ace9bb07 100644
--- a/src/plugins/litehtml_viewer/litehtml/css_selector.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/css_selector.cpp
@@ -2,190 +2,245 @@
 #include "css_selector.h"
 #include "document.h"
 
-void litehtml::css_element_selector::parse( const tstring& txt )
+void litehtml::css_element_selector::parse_nth_child_params(const string& param, int& num, int& off)
 {
-	tstring::size_type el_end = txt.find_first_of(_t(".#[:"));
-	m_tag = txt.substr(0, el_end);
-	litehtml::lcase(m_tag);
+	if (param == "odd")
+	{
+		num = 2;
+		off = 1;
+	}
+	else if (param == "even")
+	{
+		num = 2;
+		off = 0;
+	}
+	else
+	{
+		string_vector tokens;
+		split_string(param, tokens, " n", "n");
+
+		string s_num;
+		string s_off;
+
+		string s_int;
+		for (const auto& token : tokens)
+		{
+			if (token == "n")
+			{
+				s_num = s_int;
+				s_int.clear();
+			}
+			else
+			{
+				s_int += token;
+			}
+		}
+		s_off = s_int;
+
+		num = atoi(s_num.c_str());
+		off = atoi(s_off.c_str());
+	}
+}
+
+void litehtml::css_element_selector::parse( const string& txt )
+{
+	string::size_type el_end = txt.find_first_of(".#[:");
+	string tag = txt.substr(0, el_end);
+	litehtml::lcase(tag);
+	if (tag == "") tag = "*";
+	m_tag = _id(tag);
+
 	m_attrs.clear();
-	while(el_end != tstring::npos)
+	while(el_end != string::npos)
 	{
-		if(txt[el_end] == _t('.'))
+		if(txt[el_end] == '.')
+		{
+			css_attribute_selector attribute;
+
+			attribute.type = select_class;
+			string::size_type pos = txt.find_first_of(".#[:", el_end + 1);
+			string name		= txt.substr(el_end + 1, pos - el_end - 1);
+			litehtml::lcase(name);
+			attribute.name = _id(name);
+			m_attrs.push_back(attribute);
+			el_end = pos;
+		} else if(txt[el_end] == '#')
 		{
 			css_attribute_selector attribute;
 
-			tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);
-			attribute.val		= txt.substr(el_end + 1, pos - el_end - 1);
-			split_string( attribute.val, attribute.class_val, _t(" ") );
-			attribute.condition	= select_equal;
-			attribute.attribute	= _t("class");
+			attribute.type = select_id;
+			string::size_type pos = txt.find_first_of(".#[:", el_end + 1);
+			string name		= txt.substr(el_end + 1, pos - el_end - 1);
+			litehtml::lcase(name);
+			attribute.name = _id(name);
 			m_attrs.push_back(attribute);
 			el_end = pos;
-		} else if(txt[el_end] == _t(':'))
+		} else if(txt[el_end] == ':')
 		{
 			css_attribute_selector attribute;
 
-			if(txt[el_end + 1] == _t(':'))
+			if(txt[el_end + 1] == ':')
 			{
-				tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 2);
-				attribute.val		= txt.substr(el_end + 2, pos - el_end - 2);
-				attribute.condition	= select_pseudo_element;
-				litehtml::lcase(attribute.val);
-				attribute.attribute	= _t("pseudo-el");
+				attribute.type = select_pseudo_element;
+				string::size_type pos = txt.find_first_of(".#[:", el_end + 2);
+				string name		= txt.substr(el_end + 2, pos - el_end - 2);
+				litehtml::lcase(name);
+				attribute.name = _id(name);
 				m_attrs.push_back(attribute);
 				el_end = pos;
 			} else
 			{
-				tstring::size_type pos = txt.find_first_of(_t(".#[:("), el_end + 1);
-				if(pos != tstring::npos && txt.at(pos) == _t('('))
+				string::size_type pos = txt.find_first_of(".#[:(", el_end + 1);
+				string name = txt.substr(el_end + 1, pos - el_end - 1);
+				lcase(name);
+				attribute.name = _id(name);
+				if(attribute.name == _after_ || attribute.name == _before_)
 				{
-					pos = find_close_bracket(txt, pos);
-					if(pos != tstring::npos)
-					{
-						pos++;
-					} else
-					{
-						int iii = 0;
-						iii++;
-					}
-				}
-				if(pos != tstring::npos)
-				{
-					attribute.val		= txt.substr(el_end + 1, pos - el_end - 1);
+					attribute.type	= select_pseudo_element;
 				} else
 				{
-					attribute.val		= txt.substr(el_end + 1);
+					attribute.type	= select_pseudo_class;
 				}
-				litehtml::lcase(attribute.val);
-				if(attribute.val == _t("after") || attribute.val == _t("before"))
+
+				string val;
+				if(pos != string::npos && txt.at(pos) == '(')
 				{
-					attribute.condition	= select_pseudo_element;
-				} else
+					auto end = find_close_bracket(txt, pos);
+					val = txt.substr(pos + 1, end - pos - 1);
+					if (end != string::npos) pos = end + 1;
+				}
+
+				switch (attribute.name)
 				{
-					attribute.condition	= select_pseudo_class;
+				case _nth_child_:
+				case _nth_of_type_:
+				case _nth_last_child_:
+				case _nth_last_of_type_:
+					lcase(val);
+					parse_nth_child_params(val, attribute.a, attribute.b);
+					break;
+				case _not_:
+					attribute.sel = std::make_shared<css_element_selector>();
+					attribute.sel->parse(val);
+					break;
+				case _lang_:
+					trim(val);
+					lcase(val);
+					attribute.val = val;
+					break;
 				}
-				attribute.attribute	= _t("pseudo");
+
 				m_attrs.push_back(attribute);
 				el_end = pos;
 			}
-		} else if(txt[el_end] == _t('#'))
+		} else if(txt[el_end] == '[')
 		{
 			css_attribute_selector attribute;
 
-			tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);
-			attribute.val		= txt.substr(el_end + 1, pos - el_end - 1);
-			attribute.condition	= select_equal;
-			attribute.attribute	= _t("id");
-			m_attrs.push_back(attribute);
-			el_end = pos;
-		} else if(txt[el_end] == _t('['))
-		{
-			css_attribute_selector attribute;
-
-			tstring::size_type pos = txt.find_first_of(_t("]~=|$*^"), el_end + 1);
-			tstring attr = txt.substr(el_end + 1, pos - el_end - 1);
+			string::size_type pos = txt.find_first_of("]~=|$*^", el_end + 1);
+			string attr = txt.substr(el_end + 1, pos - el_end - 1);
 			trim(attr);
 			litehtml::lcase(attr);
-			if(pos != tstring::npos)
+			if(pos != string::npos)
 			{
-				if(txt[pos] == _t(']'))
+				if(txt[pos] == ']')
 				{
-					attribute.condition = select_exists;
-				} else if(txt[pos] == _t('='))
+					attribute.type = select_exists;
+				} else if(txt[pos] == '=')
 				{
-					attribute.condition = select_equal;
+					attribute.type = select_equal;
 					pos++;
-				} else if(txt.substr(pos, 2) == _t("~="))
+				} else if(txt.substr(pos, 2) == "~=")
 				{
-					attribute.condition = select_contain_str;
+					attribute.type = select_contain_str;
 					pos += 2;
-				} else if(txt.substr(pos, 2) == _t("|="))
+				} else if(txt.substr(pos, 2) == "|=")
 				{
-					attribute.condition = select_start_str;
+					attribute.type = select_start_str;
 					pos += 2;
-				} else if(txt.substr(pos, 2) == _t("^="))
+				} else if(txt.substr(pos, 2) == "^=")
 				{
-					attribute.condition = select_start_str;
+					attribute.type = select_start_str;
 					pos += 2;
-				} else if(txt.substr(pos, 2) == _t("$="))
+				} else if(txt.substr(pos, 2) == "$=")
 				{
-					attribute.condition = select_end_str;
+					attribute.type = select_end_str;
 					pos += 2;
-				} else if(txt.substr(pos, 2) == _t("*="))
+				} else if(txt.substr(pos, 2) == "*=")
 				{
-					attribute.condition = select_contain_str;
+					attribute.type = select_contain_str;
 					pos += 2;
 				} else
 				{
-					attribute.condition = select_exists;
+					attribute.type = select_exists;
 					pos += 1;
 				}
-				pos = txt.find_first_not_of(_t(" \t"), pos);
-				if(pos != tstring::npos)
+				pos = txt.find_first_not_of(" \t", pos);
+				if(pos != string::npos)
 				{
-					if(txt[pos] == _t('"'))
+					if(txt[pos] == '"')
 					{
-						tstring::size_type pos2 = txt.find_first_of(_t("\""), pos + 1);
-						attribute.val = txt.substr(pos + 1, pos2 == tstring::npos ? pos2 : (pos2 - pos - 1));
-						pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);
-					} else if(txt[pos] == _t(']'))
+						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 ++;
 					} else
 					{
-						tstring::size_type pos2 = txt.find_first_of(_t("]"), pos + 1);
-						attribute.val = txt.substr(pos, pos2 == tstring::npos ? pos2 : (pos2 - pos));
+						string::size_type pos2 = txt.find_first_of(']', pos + 1);
+						attribute.val = txt.substr(pos, pos2 == string::npos ? pos2 : (pos2 - pos));
 						trim(attribute.val);
-						pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);
+						pos = pos2 == string::npos ? pos2 : (pos2 + 1);
 					}
 				}
 			} else
 			{
-				attribute.condition = select_exists;
+				attribute.type = select_exists;
 			}
-			attribute.attribute	= attr;
+			attribute.name = _id(attr);
 			m_attrs.push_back(attribute);
 			el_end = pos;
 		} else
 		{
 			el_end++;
 		}
-		el_end = txt.find_first_of(_t(".#[:"), el_end);
+		el_end = txt.find_first_of(".#[:", el_end);
 	}
 }
 
 
-bool litehtml::css_selector::parse( const tstring& text )
+bool litehtml::css_selector::parse( const string& text )
 {
 	if(text.empty())
 	{
 		return false;
 	}
 	string_vector tokens;
-	split_string(text, tokens, _t(""), _t(" \t>+~"), _t("(["));
+	split_string(text, tokens, "", " \t>+~", "([");
 
 	if(tokens.empty())
 	{
 		return false;
 	}
 
-	tstring left;
-	tstring right = tokens.back();
-	tchar_t combinator = 0;
+	string left;
+	string right = tokens.back();
+	char combinator = 0;
 
 	tokens.pop_back();
-	while(!tokens.empty() && (tokens.back() == _t(" ") || tokens.back() == _t("\t") || tokens.back() == _t("+") || tokens.back() == _t("~") || tokens.back() == _t(">")))
+	while(!tokens.empty() && (tokens.back() == " " || tokens.back() == "\t" || tokens.back() == "+" || tokens.back() == "~" || tokens.back() == ">"))
 	{
-		if(combinator == _t(' ') || combinator == 0)
+		if(combinator == ' ' || combinator == 0)
 		{
 			combinator = tokens.back()[0];
 		}
 		tokens.pop_back();
 	}
 
-	for(string_vector::const_iterator i = tokens.begin(); i != tokens.end(); i++)
+	for(const auto & token : tokens)
 	{
-		left += *i;
+		left += token;
 	}
 
 	trim(left);
@@ -200,13 +255,13 @@ bool litehtml::css_selector::parse( const tstring& text )
 
 	switch(combinator)
 	{
-	case _t('>'):
+	case '>':
 		m_combinator	= combinator_child;
 		break;
-	case _t('+'):
+	case '+':
 		m_combinator	= combinator_adjacent_sibling;
 		break;
-	case _t('~'):
+	case '~':
 		m_combinator	= combinator_general_sibling;
 		break;
 	default:
@@ -214,11 +269,11 @@ bool litehtml::css_selector::parse( const tstring& text )
 		break;
 	}
 
-	m_left = 0;
+	m_left = nullptr;
 
 	if(!left.empty())
 	{
-		m_left = std::make_shared<css_selector>(media_query_list::ptr(0));
+		m_left = std::make_shared<css_selector>();
 		if(!m_left->parse(left))
 		{
 			return false;
@@ -230,24 +285,18 @@ bool litehtml::css_selector::parse( const tstring& text )
 
 void litehtml::css_selector::calc_specificity()
 {
-	if(!m_right.m_tag.empty() && m_right.m_tag != _t("*"))
+	if(m_right.m_tag != star_id)
 	{
 		m_specificity.d = 1;
 	}
-	for(css_attribute_selector::vector::iterator i = m_right.m_attrs.begin(); i != m_right.m_attrs.end(); i++)
+	for(const auto& attr : m_right.m_attrs)
 	{
-		if(i->attribute == _t("id"))
+		if(attr.type == select_id)
 		{
 			m_specificity.b++;
 		} else
 		{
-			if(i->attribute == _t("class"))
-			{
-				m_specificity.c += (int) i->class_val.size();
-			} else
-			{
-				m_specificity.c++;
-			}
+			m_specificity.c++;
 		}	
 	}
 	if(m_left)
diff --git a/src/plugins/litehtml_viewer/litehtml/css_selector.h b/src/plugins/litehtml_viewer/litehtml/css_selector.h
index d9a027464..4fe7db9e5 100644
--- a/src/plugins/litehtml_viewer/litehtml/css_selector.h
+++ b/src/plugins/litehtml_viewer/litehtml/css_selector.h
@@ -15,7 +15,7 @@ namespace litehtml
 		int		c;
 		int		d;
 
-		selector_specificity(int va = 0, int vb = 0, int vc = 0, int vd = 0)
+		explicit selector_specificity(int va = 0, int vb = 0, int vc = 0, int vd = 0)
 		{
 			a	= va;
 			b	= vb;
@@ -117,31 +117,41 @@ namespace litehtml
 
 	//////////////////////////////////////////////////////////////////////////
 
-	enum attr_select_condition
+	enum attr_select_type
 	{
+		select_class,
+		select_id,
+
 		select_exists,
 		select_equal,
 		select_contain_str,
 		select_start_str,
 		select_end_str,
+
 		select_pseudo_class,
 		select_pseudo_element,
 	};
 
 	//////////////////////////////////////////////////////////////////////////
 
+	class css_element_selector;
+
 	struct css_attribute_selector
 	{
 		typedef std::vector<css_attribute_selector>	vector;
 
-		tstring					attribute;
-		tstring					val;
-		string_vector			class_val;
-		attr_select_condition	condition;
+		attr_select_type	type;
+		string_id			name; // .name, #name, [name], :name
+		string				val;  // [name=val], :lang(val)
+
+		std::shared_ptr<css_element_selector> sel; // :not(sel)
+		int a, b; // :nth-child(an+b)
 
 		css_attribute_selector()
 		{
-			condition = select_exists;
+			type = select_class;
+			name = empty_id;
+			a = b = 0;
 		}
 	};
 
@@ -150,11 +160,12 @@ namespace litehtml
 	class css_element_selector
 	{
 	public:
-		tstring							m_tag;
+		string_id						m_tag;
 		css_attribute_selector::vector	m_attrs;
 	public:
 
-		void parse(const tstring& txt);
+		void parse(const string& txt);
+		static void parse_nth_child_params(const string& param, int& num, int& off);
 	};
 
 	//////////////////////////////////////////////////////////////////////////
@@ -183,26 +194,24 @@ namespace litehtml
 		int						m_order;
 		media_query_list::ptr	m_media_query;
 	public:
-		css_selector(media_query_list::ptr media)
+		explicit css_selector(const media_query_list::ptr& media = nullptr)
 		{
 			m_media_query	= media;
 			m_combinator	= combinator_descendant;
 			m_order			= 0;
 		}
 
-		~css_selector()
-		{
-		}
+		~css_selector() = default;
 
 		css_selector(const css_selector& val)
 		{
 			m_right			= val.m_right;
 			if(val.m_left)
 			{
-				m_left			= std::make_shared<css_selector>(*val.m_left);
+				m_left = std::make_shared<css_selector>(*val.m_left);
 			} else
 			{
-				m_left = 0;
+				m_left = nullptr;
 			}
 			m_combinator	= val.m_combinator;
 			m_specificity	= val.m_specificity;
@@ -210,7 +219,7 @@ namespace litehtml
 			m_media_query	= val.m_media_query;
 		}
 
-		bool parse(const tstring& text);
+		bool parse(const string& text);
 		void calc_specificity();
 		bool is_media_valid() const;
 		void add_media_to_doc(document* doc) const;
@@ -246,7 +255,7 @@ namespace litehtml
 		return (v1.m_specificity < v2.m_specificity);
 	}
 
-	inline bool operator >(const css_selector::ptr& v1, const css_selector::ptr& v2)
+	inline bool operator > (const css_selector::ptr& v1, const css_selector::ptr& v2)
 	{
 		return (*v1 > *v2);
 	}
@@ -272,6 +281,19 @@ namespace litehtml
 			m_used		= used;
 			m_selector	= selector;
 		}
+
+		used_selector(const used_selector& val)
+		{
+			m_used = val.m_used;
+			m_selector = val.m_selector;
+		}
+
+		used_selector& operator=(const used_selector& val)
+		{
+			m_used = val.m_used;
+			m_selector = val.m_selector;
+			return *this;
+		}
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/document.cpp b/src/plugins/litehtml_viewer/litehtml/document.cpp
index 245411bf4..8623bff41 100644
--- a/src/plugins/litehtml_viewer/litehtml/document.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/document.cpp
@@ -21,43 +21,37 @@
 #include "el_div.h"
 #include "el_font.h"
 #include "el_tr.h"
-#include "el_li.h"
-#include <math.h>
-#include <stdio.h>
+#include <cmath>
+#include <cstdio>
 #include <algorithm>
 #include "gumbo.h"
 #include "utf8_strings.h"
+#include "render_item.h"
 
-litehtml::document::document(litehtml::document_container* objContainer, litehtml::context* ctx)
+litehtml::document::document(document_container* objContainer)
 {
 	m_container	= objContainer;
-	m_context	= ctx;
 }
 
 litehtml::document::~document()
 {
-	m_over_element = 0;
+	m_over_element = nullptr;
 	if(m_container)
 	{
-		for(fonts_map::iterator f = m_fonts.begin(); f != m_fonts.end(); f++)
+		for(auto& font : m_fonts)
 		{
-			m_container->delete_font(f->second.font);
+			m_container->delete_font(font.second.font);
 		}
 	}
 }
 
-litehtml::document::ptr litehtml::document::createFromString( const tchar_t* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles)
-{
-	return createFromUTF8(litehtml_to_utf8(str), objPainter, ctx, user_styles);
-}
-
-litehtml::document::ptr litehtml::document::createFromUTF8(const char* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles)
+litehtml::document::ptr litehtml::document::createFromString( const char* str, document_container* objPainter, const char* master_styles, const char* user_styles )
 {
 	// parse document into GumboOutput
-	GumboOutput* output = gumbo_parse((const char*) str);
+	GumboOutput* output = gumbo_parse(str);
 
 	// Create litehtml::document
-	litehtml::document::ptr doc = std::make_shared<litehtml::document>(objPainter, ctx);
+	document::ptr doc = std::make_shared<document>(objPainter);
 
 	// Create litehtml::elements.
 	elements_vector root_elements;
@@ -69,30 +63,43 @@ litehtml::document::ptr litehtml::document::createFromUTF8(const char* str, lite
 	// Destroy GumboOutput
 	gumbo_destroy_output(&kGumboDefaultOptions, output);
 
+	if (master_styles && *master_styles)
+	{
+		doc->m_master_css.parse_stylesheet(master_styles, nullptr, doc, nullptr);
+		doc->m_master_css.sort_selectors();
+	}
+	if (user_styles && *user_styles)
+	{
+		doc->m_user_css.parse_stylesheet(user_styles, nullptr, doc, nullptr);
+		doc->m_user_css.sort_selectors();
+	}
+
 	// Let's process created elements tree
 	if (doc->m_root)
 	{
 		doc->container()->get_media_features(doc->m_media);
 
+		doc->m_root->set_pseudo_class(_root_, true);
+
 		// apply master CSS
-		doc->m_root->apply_stylesheet(ctx->master_css());
+		doc->m_root->apply_stylesheet(doc->m_master_css);
 
 		// parse elements attributes
 		doc->m_root->parse_attributes();
 
 		// parse style sheets linked in document
 		media_query_list::ptr media;
-		for (css_text::vector::iterator css = doc->m_css.begin(); css != doc->m_css.end(); css++)
+		for (const auto& css : doc->m_css)
 		{
-			if (!css->media.empty())
+			if (!css.media.empty())
 			{
-				media = media_query_list::create_from_string(css->media, doc);
+				media = media_query_list::create_from_string(css.media, doc);
 			}
 			else
 			{
-				media = 0;
+				media = nullptr;
 			}
-			doc->m_styles.parse_stylesheet(css->text.c_str(), css->baseurl.c_str(), doc, media);
+			doc->m_styles.parse_stylesheet(css.text.c_str(), css.baseurl.c_str(), doc, media);
 		}
 		// Sort css selectors using CSS rules.
 		doc->m_styles.sort_selectors();
@@ -107,77 +114,100 @@ litehtml::document::ptr litehtml::document::createFromUTF8(const char* str, lite
 		doc->m_root->apply_stylesheet(doc->m_styles);
 
 		// Apply user styles if any
-		if (user_styles)
-		{
-			doc->m_root->apply_stylesheet(*user_styles);
-		}
+		doc->m_root->apply_stylesheet(doc->m_user_css);
 
-		// Parse applied styles in the elements
-		doc->m_root->parse_styles();
+		// Initialize m_css
+		doc->m_root->compute_styles();
+
+		// Create rendering tree
+		doc->m_root_render = doc->m_root->create_render_item(nullptr);
 
 		// 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
 		doc->fix_tables_layout();
 
-		// Fanaly initialize elements
-		doc->m_root->init();
+		// Finally initialize elements
+		// init() return pointer to the render_init element because it can change its type
+		doc->m_root_render = doc->m_root_render->init();
 	}
 
 	return doc;
 }
 
-litehtml::uint_ptr litehtml::document::add_font( const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm )
+litehtml::uint_ptr litehtml::document::add_font( const char* name, int size, const char* weight, const char* style, const char* decoration, font_metrics* fm )
 {
 	uint_ptr ret = 0;
 
-	if( !name || (name && !t_strcasecmp(name, _t("inherit"))) )
+	if(!name)
 	{
 		name = m_container->get_default_font_name();
 	}
 
-	if(!size)
-	{
-		size = container()->get_default_font_size();
-	}
-
-	tchar_t strSize[20];
+	char strSize[20];
 	t_itoa(size, strSize, 20, 10);
 
-	tstring key = name;
-	key += _t(":");
+	string key = name;
+	key += ":";
 	key += strSize;
-	key += _t(":");
+	key += ":";
 	key += weight;
-	key += _t(":");
+	key += ":";
 	key += style;
-	key += _t(":");
+	key += ":";
 	key += decoration;
 
 	if(m_fonts.find(key) == m_fonts.end())
 	{
-		font_style fs = (font_style) value_index(style, font_style_strings, fontStyleNormal);
+		font_style fs = (font_style) value_index(style, font_style_strings, font_style_normal);
 		int	fw = value_index(weight, font_weight_strings, -1);
 		if(fw >= 0)
 		{
 			switch(fw)
 			{
-			case litehtml::fontWeightBold:
+			case litehtml::font_weight_bold:
 				fw = 700;
 				break;
-			case litehtml::fontWeightBolder:
+			case litehtml::font_weight_bolder:
 				fw = 600;
 				break;
-			case litehtml::fontWeightLighter:
+			case litehtml::font_weight_lighter:
+				fw = 300;
+				break;
+			case litehtml::font_weight_normal:
+				fw = 400;
+				break;
+			case litehtml::font_weight_100:
+				fw = 100;
+				break;
+			case litehtml::font_weight_200:
+				fw = 200;
+				break;
+			case litehtml::font_weight_300:
 				fw = 300;
 				break;
-			default:
+			case litehtml::font_weight_400:
 				fw = 400;
 				break;
+			case litehtml::font_weight_500:
+				fw = 500;
+				break;
+			case litehtml::font_weight_600:
+				fw = 600;
+				break;
+			case litehtml::font_weight_700:
+				fw = 700;
+				break;
+			case litehtml::font_weight_800:
+				fw = 800;
+				break;
+			case litehtml::font_weight_900:
+				fw = 900;
+				break;
 			}
 		} else
 		{
-			fw = t_atoi(weight);
+			fw = atoi(weight);
 			if(fw < 100)
 			{
 				fw = 400;
@@ -188,17 +218,17 @@ litehtml::uint_ptr litehtml::document::add_font( const tchar_t* name, int size,
 
 		if(decoration)
 		{
-			std::vector<tstring> tokens;
-			split_string(decoration, tokens, _t(" "));
-			for(std::vector<tstring>::iterator i = tokens.begin(); i != tokens.end(); i++)
+			std::vector<string> tokens;
+			split_string(decoration, tokens, " ");
+			for(auto & token : tokens)
 			{
-				if(!t_strcasecmp(i->c_str(), _t("underline")))
+				if(!t_strcasecmp(token.c_str(), "underline"))
 				{
 					decor |= font_decoration_underline;
-				} else if(!t_strcasecmp(i->c_str(), _t("line-through")))
+				} else if(!t_strcasecmp(token.c_str(), "line-through"))
 				{
 					decor |= font_decoration_linethrough;
-				} else if(!t_strcasecmp(i->c_str(), _t("overline")))
+				} else if(!t_strcasecmp(token.c_str(), "overline"))
 				{
 					decor |= font_decoration_overline;
 				}
@@ -218,32 +248,31 @@ litehtml::uint_ptr litehtml::document::add_font( const tchar_t* name, int size,
 	return ret;
 }
 
-litehtml::uint_ptr litehtml::document::get_font( const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm )
+litehtml::uint_ptr litehtml::document::get_font( const char* name, int size, const char* weight, const char* style, const char* decoration, font_metrics* fm )
 {
-	if( !name || (name && !t_strcasecmp(name, _t("inherit"))) )
+	if(!size)
 	{
-		name = m_container->get_default_font_name();
+		return 0;
 	}
-
-	if(!size)
+	if(!name)
 	{
-		size = m_container->get_default_font_size();
+		name = m_container->get_default_font_name();
 	}
 
-	tchar_t strSize[20];
+	char strSize[20];
 	t_itoa(size, strSize, 20, 10);
 
-	tstring key = name;
-	key += _t(":");
+	string key = name;
+	key += ":";
 	key += strSize;
-	key += _t(":");
+	key += ":";
 	key += weight;
-	key += _t(":");
+	key += ":";
 	key += style;
-	key += _t(":");
+	key += ":";
 	key += decoration;
 
-	fonts_map::iterator el = m_fonts.find(key);
+	auto el = m_fonts.find(key);
 
 	if(el != m_fonts.end())
 	{
@@ -261,21 +290,31 @@ int litehtml::document::render( int max_width, render_type rt )
 	int ret = 0;
 	if(m_root)
 	{
+		position client_rc;
+		m_container->get_client_rect(client_rc);
+		containing_block_context cb_context;
+		cb_context.width = max_width;
+		cb_context.width.type = containing_block_context::cbc_value_type_absolute;
+		cb_context.height = client_rc.height;
+		cb_context.height.type = containing_block_context::cbc_value_type_absolute;
+
 		if(rt == render_fixed_only)
 		{
 			m_fixed_boxes.clear();
-			m_root->render_positioned(rt);
+			m_root_render->render_positioned(rt);
 		} else
 		{
-			ret = m_root->render(0, 0, max_width);
-			if(m_root->fetch_positioned())
+			ret = m_root_render->render(0, 0, cb_context);
+			if(m_root_render->fetch_positioned())
 			{
 				m_fixed_boxes.clear();
-				m_root->render_positioned(rt);
+				m_root_render->render_positioned(rt);
 			}
 			m_size.width	= 0;
 			m_size.height	= 0;
-			m_root->calc_document_size(m_size);
+			m_content_size.width = 0;
+			m_content_size.height = 0;
+			m_root_render->calc_document_size(m_size, m_content_size);
 		}
 	}
 	return ret;
@@ -283,14 +322,14 @@ int litehtml::document::render( int max_width, render_type rt )
 
 void litehtml::document::draw( uint_ptr hdc, int x, int y, const position* clip )
 {
-	if(m_root)
+	if(m_root && m_root_render)
 	{
-		m_root->draw(hdc, x, y, clip);
-		m_root->draw_stacking_context(hdc, x, y, clip, true);
+		m_root->draw(hdc, x, y, clip, m_root_render);
+		m_root_render->draw_stacking_context(hdc, x, y, clip, true);
 	}
 }
 
-int litehtml::document::cvt_units( const tchar_t* str, int fontSize, bool* is_percent/*= 0*/ ) const
+int litehtml::document::to_pixels( const char* str, int fontSize, bool* is_percent/*= 0*/ ) const
 {
 	if(!str)	return 0;
 	
@@ -300,40 +339,35 @@ int litehtml::document::cvt_units( const tchar_t* str, int fontSize, bool* is_pe
 	{
 		*is_percent = true;
 	}
-	return cvt_units(val, fontSize);
+	return to_pixels(val, fontSize);
 }
 
-int litehtml::document::cvt_units( css_length& val, int fontSize, int size ) const
+int litehtml::document::to_pixels( const css_length& val, int fontSize, int size ) const
 {
 	if(val.is_predefined())
 	{
 		return 0;
 	}
-	int ret = 0;
+	int ret;
 	switch(val.units())
 	{
 	case css_units_percentage:
 		ret = val.calc_percent(size);
 		break;
 	case css_units_em:
-		ret = round_f(val.val() * fontSize);
-		val.set_value((float) ret, css_units_px);
+		ret = round_f(val.val() * (float) fontSize);
 		break;
 	case css_units_pt:
 		ret = m_container->pt_to_px((int) val.val());
-		val.set_value((float) ret, css_units_px);
 		break;
 	case css_units_in:
 		ret = m_container->pt_to_px((int) (val.val() * 72));
-		val.set_value((float) ret, css_units_px);
 		break;
 	case css_units_cm:
 		ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72));
-		val.set_value((float) ret, css_units_px);
 		break;
 	case css_units_mm:
 		ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72) / 10);
-		val.set_value((float) ret, css_units_px);
 		break;
 	case css_units_vw:
 		ret = (int)((double)m_media.width * (double)val.val() / 100.0);
@@ -348,8 +382,7 @@ int litehtml::document::cvt_units( css_length& val, int fontSize, int size ) con
 		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);
+		ret = (int) ((double) m_root->css().get_font_size() * (double) val.val());
 		break;
 	default:
 		ret = (int) val.val();
@@ -358,6 +391,38 @@ int litehtml::document::cvt_units( css_length& val, int fontSize, int size ) con
 	return ret;
 }
 
+void litehtml::document::cvt_units( css_length& val, int fontSize, int size ) const
+{
+	if(val.is_predefined())
+	{
+		return;
+	}
+	int ret;
+	switch(val.units())
+	{
+		case css_units_em:
+			ret = round_f(val.val() * (float) fontSize);
+			val.set_value((float) ret, css_units_px);
+			break;
+		case css_units_pt:
+			ret = m_container->pt_to_px((int) val.val());
+			val.set_value((float) ret, css_units_px);
+			break;
+		case css_units_in:
+			ret = m_container->pt_to_px((int) (val.val() * 72));
+			val.set_value((float) ret, css_units_px);
+			break;
+		case css_units_cm:
+			ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72));
+			val.set_value((float) ret, css_units_px);
+			break;
+		case css_units_mm:
+			ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72) / 10);
+			val.set_value((float) ret, css_units_px);
+			break;
+	}
+}
+
 int litehtml::document::width() const
 {
 	return m_size.width;
@@ -368,7 +433,18 @@ int litehtml::document::height() const
 	return m_size.height;
 }
 
-void litehtml::document::add_stylesheet( const tchar_t* str, const tchar_t* baseurl, const tchar_t* media )
+int litehtml::document::content_width() const
+{
+	return m_content_size.width;
+}
+
+int litehtml::document::content_height() const
+{
+	return m_content_size.height;
+}
+
+
+void litehtml::document::add_stylesheet( const char* str, const char* baseurl, const char* media )
 {
 	if(str && str[0])
 	{
@@ -378,12 +454,12 @@ void litehtml::document::add_stylesheet( const tchar_t* str, const tchar_t* base
 
 bool litehtml::document::on_mouse_over( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
 {
-	if(!m_root)
+	if(!m_root || !m_root_render)
 	{
 		return false;
 	}
 
-	element::ptr over_el = m_root->get_element_by_point(x, y, client_x, client_y);
+	element::ptr over_el = m_root_render->get_element_by_point(x, y, client_x, client_y);
 
 	bool state_was_changed = false;
 
@@ -399,7 +475,7 @@ bool litehtml::document::on_mouse_over( int x, int y, int client_x, int client_y
 		m_over_element = over_el;
 	}
 
-	const tchar_t* cursor = 0;
+	string cursor;
 
 	if(m_over_element)
 	{
@@ -407,21 +483,21 @@ bool litehtml::document::on_mouse_over( int x, int y, int client_x, int client_y
 		{
 			state_was_changed = true;
 		}
-		cursor = m_over_element->get_cursor();
+		cursor = m_over_element->css().get_cursor();
 	}
 	
-	m_container->set_cursor(cursor ? cursor : _t("auto"));
+	m_container->set_cursor(cursor.c_str());
 	
 	if(state_was_changed)
 	{
-		return m_root->find_styles_changes(redraw_boxes, 0, 0);
+		return m_root->find_styles_changes(redraw_boxes);
 	}
 	return false;
 }
 
 bool litehtml::document::on_mouse_leave( position::vector& redraw_boxes )
 {
-	if(!m_root)
+	if(!m_root || !m_root_render)
 	{
 		return false;
 	}
@@ -429,7 +505,7 @@ bool litehtml::document::on_mouse_leave( position::vector& redraw_boxes )
 	{
 		if(m_over_element->on_mouse_leave())
 		{
-			return m_root->find_styles_changes(redraw_boxes, 0, 0);
+			return m_root->find_styles_changes(redraw_boxes);
 		}
 	}
 	return false;
@@ -437,12 +513,12 @@ bool litehtml::document::on_mouse_leave( position::vector& redraw_boxes )
 
 bool litehtml::document::on_lbutton_down( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
 {
-	if(!m_root)
+	if(!m_root || !m_root_render)
 	{
 		return false;
 	}
 
-	element::ptr over_el = m_root->get_element_by_point(x, y, client_x, client_y);
+	element::ptr over_el = m_root_render->get_element_by_point(x, y, client_x, client_y);
 
 	bool state_was_changed = false;
 
@@ -465,7 +541,7 @@ bool litehtml::document::on_lbutton_down( int x, int y, int client_x, int client
 		}
 	}
 
-	const tchar_t* cursor = 0;
+	string cursor;
 
 	if(m_over_element)
 	{
@@ -473,14 +549,14 @@ bool litehtml::document::on_lbutton_down( int x, int y, int client_x, int client
 		{
 			state_was_changed = true;
 		}
-		cursor = m_over_element->get_cursor();
+		cursor = m_over_element->css().get_cursor();
 	}
 
-	m_container->set_cursor(cursor ? cursor : _t("auto"));
+	m_container->set_cursor(cursor.c_str());
 
 	if(state_was_changed)
 	{
-		return m_root->find_styles_changes(redraw_boxes, 0, 0);
+		return m_root->find_styles_changes(redraw_boxes);
 	}
 
 	return false;
@@ -488,7 +564,7 @@ bool litehtml::document::on_lbutton_down( int x, int y, int client_x, int client
 
 bool litehtml::document::on_lbutton_up( int x, int y, int client_x, int client_y, position::vector& redraw_boxes )
 {
-	if(!m_root)
+	if(!m_root || !m_root_render)
 	{
 		return false;
 	}
@@ -496,13 +572,13 @@ bool litehtml::document::on_lbutton_up( int x, int y, int client_x, int client_y
 	{
 		if(m_over_element->on_lbutton_up())
 		{
-			return m_root->find_styles_changes(redraw_boxes, 0, 0);
+			return m_root->find_styles_changes(redraw_boxes);
 		}
 	}
 	return false;
 }
 
-litehtml::element::ptr litehtml::document::create_element(const tchar_t* tag_name, const string_map& attributes)
+litehtml::element::ptr litehtml::document::create_element(const char* tag_name, const string_map& attributes)
 {
 	element::ptr newTag;
 	document::ptr this_doc = shared_from_this();
@@ -512,54 +588,51 @@ litehtml::element::ptr litehtml::document::create_element(const tchar_t* tag_nam
 	}
 	if(!newTag)
 	{
-		if(!t_strcmp(tag_name, _t("br")))
+		if(!strcmp(tag_name, "br"))
 		{
 			newTag = std::make_shared<litehtml::el_break>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("p")))
+		} else if(!strcmp(tag_name, "p"))
 		{
 			newTag = std::make_shared<litehtml::el_para>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("img")))
+		} else if(!strcmp(tag_name, "img"))
 		{
 			newTag = std::make_shared<litehtml::el_image>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("table")))
+		} else if(!strcmp(tag_name, "table"))
 		{
 			newTag = std::make_shared<litehtml::el_table>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("td")) || !t_strcmp(tag_name, _t("th")))
+		} else if(!strcmp(tag_name, "td") || !strcmp(tag_name, "th"))
 		{
 			newTag = std::make_shared<litehtml::el_td>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("link")))
+		} else if(!strcmp(tag_name, "link"))
 		{
 			newTag = std::make_shared<litehtml::el_link>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("title")))
+		} else if(!strcmp(tag_name, "title"))
 		{
 			newTag = std::make_shared<litehtml::el_title>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("a")))
+		} else if(!strcmp(tag_name, "a"))
 		{
 			newTag = std::make_shared<litehtml::el_anchor>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("tr")))
+		} else if(!strcmp(tag_name, "tr"))
 		{
 			newTag = std::make_shared<litehtml::el_tr>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("style")))
+		} else if(!strcmp(tag_name, "style"))
 		{
 			newTag = std::make_shared<litehtml::el_style>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("base")))
+		} else if(!strcmp(tag_name, "base"))
 		{
 			newTag = std::make_shared<litehtml::el_base>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("body")))
+		} else if(!strcmp(tag_name, "body"))
 		{
 			newTag = std::make_shared<litehtml::el_body>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("div")))
+		} else if(!strcmp(tag_name, "div"))
 		{
 			newTag = std::make_shared<litehtml::el_div>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("script")))
+		} else if(!strcmp(tag_name, "script"))
 		{
 			newTag = std::make_shared<litehtml::el_script>(this_doc);
-		} else if(!t_strcmp(tag_name, _t("font")))
+		} else if(!strcmp(tag_name, "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);
@@ -569,9 +642,9 @@ litehtml::element::ptr litehtml::document::create_element(const tchar_t* tag_nam
 	if(newTag)
 	{
 		newTag->set_tagName(tag_name);
-		for (string_map::const_iterator iter = attributes.begin(); iter != attributes.end(); iter++)
+		for (const auto & attribute : attributes)
 		{
-			newTag->set_attr(iter->first.c_str(), iter->second.c_str());
+			newTag->set_attr(attribute.first.c_str(), attribute.second.c_str());
 		}
 	}
 
@@ -590,15 +663,12 @@ void litehtml::document::add_fixed_box( const position& pos )
 
 bool litehtml::document::media_changed()
 {
-	if(!m_media_lists.empty())
+	container()->get_media_features(m_media);
+	if (update_media_lists(m_media))
 	{
-		container()->get_media_features(m_media);
-		if (update_media_lists(m_media))
-		{
-			m_root->refresh_styles();
-			m_root->parse_styles();
-			return true;
-		}
+		m_root->refresh_styles();
+		m_root->compute_styles();
+		return true;
 	}
 	return false;
 }
@@ -607,18 +677,18 @@ bool litehtml::document::lang_changed()
 {
 	if(!m_media_lists.empty())
 	{
-		tstring culture;
+		string culture;
 		container()->get_language(m_lang, culture);
 		if(!culture.empty())
 		{
-			m_culture = m_lang + _t('-') + culture;
+			m_culture = m_lang + '-' + culture;
 		}
 		else
 		{
 			m_culture.clear();
 		}
 		m_root->refresh_styles();
-		m_root->parse_styles();
+		m_root->compute_styles();
 		return true;
 	}
 	return false;
@@ -627,9 +697,9 @@ bool litehtml::document::lang_changed()
 bool litehtml::document::update_media_lists(const media_features& features)
 {
 	bool update_styles = false;
-	for(media_query_list::vector::iterator iter = m_media_lists.begin(); iter != m_media_lists.end(); iter++)
+	for(auto & m_media_list : m_media_lists)
 	{
-		if((*iter)->apply_media_features(features))
+		if(m_media_list->apply_media_features(features))
 		{
 			update_styles = true;
 		}
@@ -637,7 +707,7 @@ bool litehtml::document::update_media_lists(const media_features& features)
 	return update_styles;
 }
 
-void litehtml::document::add_media_list( media_query_list::ptr list )
+void litehtml::document::add_media_list( const media_query_list::ptr& list )
 {
 	if(list)
 	{
@@ -650,7 +720,7 @@ void litehtml::document::add_media_list( media_query_list::ptr list )
 
 void litehtml::document::create_node(void* gnode, elements_vector& elements, bool parseTextNode)
 {
-	GumboNode* node = (GumboNode*)gnode;
+	auto* node = (GumboNode*)gnode;
 	switch (node->type)
 	{
 	case GUMBO_NODE_ELEMENT:
@@ -660,7 +730,7 @@ void litehtml::document::create_node(void* gnode, elements_vector& elements, boo
 			for (unsigned int i = 0; i < node->v.element.attributes.length; i++)
 			{
 				attr = (GumboAttribute*)node->v.element.attributes.data[i];
-				attrs[tstring(litehtml_from_utf8(attr->name))] = litehtml_from_utf8(attr->value);
+				attrs[attr->name] = attr->value;
 			}
 
 
@@ -668,7 +738,7 @@ void litehtml::document::create_node(void* gnode, elements_vector& elements, boo
 			const char* tag = gumbo_normalized_tagname(node->v.element.tag);
 			if (tag[0])
 			{
-				ret = create_element(litehtml_from_utf8(tag), attrs);
+				ret = create_element(tag, attrs);
 			}
 			else
 			{
@@ -677,7 +747,7 @@ void litehtml::document::create_node(void* gnode, elements_vector& elements, boo
 					std::string strA;
 					gumbo_tag_from_original_text(&node->v.element.original_tag);
 					strA.append(node->v.element.original_tag.data, node->v.element.original_tag.length);
-					ret = create_element(litehtml_from_utf8(strA.c_str()), attrs);
+					ret = create_element(strA.c_str(), attrs);
 				}
 			}
 			if (!strcmp(tag, "script"))
@@ -704,68 +774,35 @@ void litehtml::document::create_node(void* gnode, elements_vector& elements, boo
 		break;
 	case GUMBO_NODE_TEXT:
 		{
-			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;
+				elements.push_back(std::make_shared<el_text>(node->v.text.text, shared_from_this()));
 			}
-			ucode_t c;
-			for (size_t i = 0; i < str_in.length(); i++)
-			{
-				c = (ucode_t) str_in[i];
-				if (c <= ' ' && (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f'))
-				{
-					if (!str.empty())
-					{
-						elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
-						str.clear();
-					}
-					str += c;
-					elements.push_back(std::make_shared<el_space>(litehtml_from_wchar(str.c_str()), shared_from_this()));
-					str.clear();
-				}
-				// CJK character range
-				else if (c >= 0x4E00 && c <= 0x9FCC)
-				{
-					if (!str.empty())
-					{
-						elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
-						str.clear();
-					}
-					str += c;
-					elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
-					str.clear();
-				}
-				else
-				{
-					str += c;
-				}
-			}
-			if (!str.empty())
+			else
 			{
-				elements.push_back(std::make_shared<el_text>(litehtml_from_wchar(str.c_str()), shared_from_this()));
+				m_container->split_text(node->v.text.text,
+					[this, &elements](const char* text) { elements.push_back(std::make_shared<el_text>(text, shared_from_this())); },
+					[this, &elements](const char* text) { elements.push_back(std::make_shared<el_space>(text, shared_from_this())); });
 			}
 		}
 		break;
 	case GUMBO_NODE_CDATA:
 		{
 			element::ptr ret = std::make_shared<el_cdata>(shared_from_this());
-			ret->set_data(litehtml_from_utf8(node->v.text.text));
+			ret->set_data(node->v.text.text);
 			elements.push_back(ret);
 		}
 		break;
 	case GUMBO_NODE_COMMENT:
 		{
 			element::ptr ret = std::make_shared<el_comment>(shared_from_this());
-			ret->set_data(litehtml_from_utf8(node->v.text.text));
+			ret->set_data(node->v.text.text);
 			elements.push_back(ret);
 		}
 		break;
 	case GUMBO_NODE_WHITESPACE:
 		{
-			tstring str = litehtml_from_utf8(node->v.text.text);
+			string str = node->v.text.text;
 			for (size_t i = 0; i < str.length(); i++)
 			{
 				elements.push_back(std::make_shared<el_space>(str.substr(i, 1).c_str(), shared_from_this()));
@@ -779,36 +816,33 @@ void litehtml::document::create_node(void* gnode, elements_vector& elements, boo
 
 void litehtml::document::fix_tables_layout()
 {
-	size_t i = 0;
-	while (i < m_tabular_elements.size())
+	for (const auto& el_ptr : m_tabular_elements)
 	{
-		element::ptr el_ptr = m_tabular_elements[i];
-
-		switch (el_ptr->get_display())
+		switch (el_ptr->src_el()->css().get_display())
 		{
 		case display_inline_table:
 		case display_table:
-			fix_table_children(el_ptr, display_table_row_group, _t("table-row-group"));
+			fix_table_children(el_ptr, display_table_row_group, "table-row-group");
 			break;
 		case display_table_footer_group:
 		case display_table_row_group:
 		case display_table_header_group:
 			{
-				element::ptr parent = el_ptr->parent();
+				auto parent = el_ptr->parent();
 				if (parent)
 				{
-					if (parent->get_display() != display_inline_table)
-						fix_table_parent(el_ptr, display_table, _t("table"));
+					if (parent->src_el()->css().get_display() != display_inline_table)
+						fix_table_parent(el_ptr, display_table, "table");
 				}
-				fix_table_children(el_ptr, display_table_row, _t("table-row"));
+				fix_table_children(el_ptr, display_table_row, "table-row");
 			}
 			break;
 		case display_table_row:
-			fix_table_parent(el_ptr, display_table_row_group, _t("table-row-group"));
-			fix_table_children(el_ptr, display_table_cell, _t("table-cell"));
+			fix_table_parent(el_ptr, display_table_row_group, "table-row-group");
+			fix_table_children(el_ptr, display_table_cell, "table-cell");
 			break;
 		case display_table_cell:
-			fix_table_parent(el_ptr, display_table_row, _t("table-row"));
+			fix_table_parent(el_ptr, display_table_row, "table-row");
 			break;
 		// TODO: make table layout fix for table-caption, table-column etc. elements
 		case display_table_caption:
@@ -817,51 +851,61 @@ void litehtml::document::fix_tables_layout()
 		default:
 			break;
 		}
-		i++;
 	}
 }
 
-void litehtml::document::fix_table_children(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str)
+void litehtml::document::fix_table_children(const std::shared_ptr<render_item>& el_ptr, style_display disp, const char* disp_str)
 {
-	elements_vector tmp;
-	elements_vector::iterator first_iter = el_ptr->m_children.begin();
-	elements_vector::iterator cur_iter = el_ptr->m_children.begin();
+	std::list<std::shared_ptr<render_item>> tmp;
+	auto first_iter = el_ptr->children().begin();
+	auto cur_iter = el_ptr->children().begin();
 
 	auto flush_elements = [&]()
 	{
-		element::ptr annon_tag = std::make_shared<html_tag>(shared_from_this());
-		style st;
-		st.add_property(_t("display"), disp_str, 0, false);
-		annon_tag->add_style(st);
-		annon_tag->parent(el_ptr);
-		annon_tag->parse_styles();
-		std::for_each(tmp.begin(), tmp.end(),
-			[&annon_tag](element::ptr& el)
-			{
-				annon_tag->appendChild(el);
-			}
-		);
-		first_iter = el_ptr->m_children.insert(first_iter, annon_tag);
-		cur_iter = first_iter + 1;
-		while (cur_iter != el_ptr->m_children.end() && (*cur_iter)->parent() != el_ptr)
+		element::ptr annon_tag = std::make_shared<html_tag>(el_ptr->src_el(), string("display:") + disp_str);
+		std::shared_ptr<render_item> annon_ri;
+		if(annon_tag->css().get_display() == display_table_cell)
+		{
+			annon_tag->set_tagName("table_cell");
+			annon_ri = std::make_shared<render_item_block>(annon_tag);
+		} else if(annon_tag->css().get_display() == display_table_row)
+		{
+			annon_ri = std::make_shared<render_item_table_row>(annon_tag);
+		} else
+		{
+			annon_ri = std::make_shared<render_item_table_part>(annon_tag);
+		}
+		for(const auto& el : tmp)
+		{
+			annon_ri->add_child(el);
+		}
+		// add annon item as tabular for future processing
+		add_tabular(annon_ri);
+		annon_ri->parent(el_ptr);
+		first_iter = el_ptr->children().insert(first_iter, annon_ri);
+		cur_iter = std::next(first_iter);
+		while (cur_iter != el_ptr->children().end() && (*cur_iter)->parent() != el_ptr)
 		{
-			cur_iter = el_ptr->m_children.erase(cur_iter);
+			cur_iter = el_ptr->children().erase(cur_iter);
 		}
 		first_iter = cur_iter;
 		tmp.clear();
 	};
 
-	while (cur_iter != el_ptr->m_children.end())
+	while (cur_iter != el_ptr->children().end())
 	{
-		if ((*cur_iter)->get_display() != disp)
+		if ((*cur_iter)->src_el()->css().get_display() != disp)
 		{
-			if (!(*cur_iter)->is_white_space() || ((*cur_iter)->is_white_space() && !tmp.empty()))
+			if (!(*cur_iter)->src_el()->is_table_skip() || ((*cur_iter)->src_el()->is_table_skip() && !tmp.empty()))
 			{
-				if (tmp.empty())
+				if (disp != display_table_row_group || (*cur_iter)->src_el()->css().get_display() != display_table_caption)
 				{
-					first_iter = cur_iter;
+					if (tmp.empty())
+					{
+						first_iter = cur_iter;
+					}
+					tmp.push_back((*cur_iter));
 				}
-				tmp.push_back((*cur_iter));
 			}
 			cur_iter++;
 		}
@@ -880,14 +924,14 @@ void litehtml::document::fix_table_children(element::ptr& el_ptr, style_display
 	}
 }
 
-void litehtml::document::fix_table_parent(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str)
+void litehtml::document::fix_table_parent(const std::shared_ptr<render_item>& el_ptr, style_display disp, const char* disp_str)
 {
-	element::ptr parent = el_ptr->parent();
+	auto parent = el_ptr->parent();
 
-	if (parent->get_display() != disp)
+	if (parent->src_el()->css().get_display() != disp)
 	{
-		elements_vector::iterator this_element = std::find_if(parent->m_children.begin(), parent->m_children.end(),
-			[&](element::ptr& el)
+		auto this_element = std::find_if(parent->children().begin(), parent->children().end(),
+			[&](const std::shared_ptr<render_item>& el)
 			{
 				if (el == el_ptr)
 				{
@@ -896,19 +940,19 @@ void litehtml::document::fix_table_parent(element::ptr& el_ptr, style_display di
 				return false;
 			}
 		);
-		if (this_element != parent->m_children.end())
+		if (this_element != parent->children().end())
 		{
-			style_display el_disp = el_ptr->get_display();
-			elements_vector::iterator first = this_element;
-			elements_vector::iterator last = this_element;
-			elements_vector::iterator cur = this_element;
+			style_display el_disp = el_ptr->src_el()->css().get_display();
+			auto first = this_element;
+			auto last = this_element;
+			auto cur = this_element;
 
 			// find first element with same display
 			while (true)
 			{
-				if (cur == parent->m_children.begin()) break;
+				if (cur == parent->children().begin()) break;
 				cur--;
-				if ((*cur)->is_white_space() || (*cur)->get_display() == el_disp)
+				if ((*cur)->src_el()->is_table_skip() || (*cur)->src_el()->css().get_display() == el_disp)
 				{
 					first = cur;
 				}
@@ -923,9 +967,9 @@ void litehtml::document::fix_table_parent(element::ptr& el_ptr, style_display di
 			while (true)
 			{
 				cur++;
-				if (cur == parent->m_children.end()) break;
+				if (cur == parent->children().end()) break;
 
-				if ((*cur)->is_white_space() || (*cur)->get_display() == el_disp)
+				if ((*cur)->src_el()->is_table_skip() || (*cur)->src_el()->css().get_display() == el_disp)
 				{
 					last = cur;
 				}
@@ -936,30 +980,33 @@ void litehtml::document::fix_table_parent(element::ptr& el_ptr, style_display di
 			}
 
 			// extract elements with the same display and wrap them with anonymous object
-			element::ptr annon_tag = std::make_shared<html_tag>(shared_from_this());
-			style st;
-			st.add_property(_t("display"), disp_str, 0, false);
-			annon_tag->add_style(st);
-			annon_tag->parent(parent);
-			annon_tag->parse_styles();
-			std::for_each(first, last + 1,
-				[&annon_tag](element::ptr& el)
+			element::ptr annon_tag = std::make_shared<html_tag>(parent->src_el(), string("display:") + disp_str);
+			std::shared_ptr<render_item> annon_ri;
+			if(annon_tag->css().get_display() == display_table || annon_tag->css().get_display() == display_inline_table)
+			{
+				annon_ri = std::make_shared<render_item_table>(annon_tag);
+			} else if(annon_tag->css().get_display() == display_table_row)
+			{
+				annon_ri = std::make_shared<render_item_table_row>(annon_tag);
+			} else
+			{
+				annon_ri = std::make_shared<render_item_table_part>(annon_tag);
+			}
+			std::for_each(first, std::next(last, 1),
+				[&annon_ri](std::shared_ptr<render_item>& el)
 				{
-					annon_tag->appendChild(el);
+					annon_ri->add_child(el);
 				}
 			);
-			first = parent->m_children.erase(first, last + 1);
-			parent->m_children.insert(first, annon_tag);
+			first = parent->children().erase(first, std::next(last));
+			parent->children().insert(first, annon_ri);
+			add_tabular(annon_ri);
+			annon_ri->parent(parent);
 		}
 	}
 }
 
-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)
+void litehtml::document::append_children_from_string(element& parent, const char* str)
 {
 	// parent must belong to this document
 	if (parent.get_document().get() != this)
@@ -968,7 +1015,7 @@ void litehtml::document::append_children_from_utf8(element& parent, const char*
 	}
 
 	// parse document into GumboOutput
-	GumboOutput* output = gumbo_parse((const char*) str);
+	GumboOutput* output = gumbo_parse(str);
 
 	// Create litehtml::elements.
 	elements_vector child_elements;
@@ -978,13 +1025,13 @@ void litehtml::document::append_children_from_utf8(element& parent, const char*
 	gumbo_destroy_output(&kGumboDefaultOptions, output);
 
 	// Let's process created elements tree
-	for (litehtml::element::ptr child : child_elements)
+	for (const auto& child : child_elements)
 	{
 		// Add the child element to parent
 		parent.appendChild(child);
 
 		// apply master CSS
-		child->apply_stylesheet(m_context->master_css());
+		child->apply_stylesheet(m_master_css);
 
 		// parse elements attributes
 		child->parse_attributes();
@@ -992,15 +1039,26 @@ void litehtml::document::append_children_from_utf8(element& parent, const char*
 		// Apply parsed styles.
 		child->apply_stylesheet(m_styles);
 
-		// Parse applied styles in the elements
-		child->parse_styles();
+		// Apply user styles if any
+		child->apply_stylesheet(m_user_css);
+
+		// Initialize m_css
+		child->compute_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();
+		// Finally initialize elements
+		//child->init();
 	}
-}
\ No newline at end of file
+}
+
+void litehtml::document::dump(dumper& cout)
+{
+	if(m_root_render)
+	{
+		m_root_render->dump(cout);
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/document.h b/src/plugins/litehtml_viewer/litehtml/document.h
index cb297e991..11322f899 100644
--- a/src/plugins/litehtml_viewer/litehtml/document.h
+++ b/src/plugins/litehtml_viewer/litehtml/document.h
@@ -3,7 +3,7 @@
 
 #include "style.h"
 #include "types.h"
-#include "context.h"
+#include "master_css.h"
 
 namespace litehtml
 {
@@ -11,19 +11,17 @@ namespace litehtml
 	{
 		typedef std::vector<css_text>	vector;
 
-		tstring	text;
-		tstring	baseurl;
-		tstring	media;
+		string	text;
+		string	baseurl;
+		string	media;
 		
-		css_text()
-		{
-		}
+		css_text() = default;
 
-		css_text(const tchar_t* txt, const tchar_t* url, const tchar_t* media_str)
+		css_text(const char* txt, const char* url, const char* media_str)
 		{
-			text	= txt ? txt : _t("");
-			baseurl	= url ? url : _t("");
-			media	= media_str ? media_str : _t("");
+			text	= txt ? txt : "";
+			baseurl	= url ? url : "";
+			media	= media_str ? media_str : "";
 		}
 
 		css_text(const css_text& val)
@@ -34,19 +32,19 @@ namespace litehtml
 		}
 	};
 
-	struct stop_tags_t
-	{
-		const litehtml::tchar_t*	tags;
-		const litehtml::tchar_t*	stop_parent;
-	};
-
-	struct ommited_end_tags_t
-	{
-		const litehtml::tchar_t*	tag;
-		const litehtml::tchar_t*	followed_tags;
-	};
+    class dumper
+    {
+    public:
+        virtual ~dumper() {}
+        virtual void begin_node(const litehtml::string& descr) = 0;
+        virtual void end_node() = 0;
+        virtual void begin_attrs_group(const litehtml::string& descr) = 0;
+        virtual void end_attrs_group() = 0;
+        virtual void add_attr(const litehtml::string& name, const litehtml::string& value) = 0;
+    };
 
 	class html_tag;
+    class render_item;
 
 	class document : public std::enable_shared_from_this<document>
 	{
@@ -55,64 +53,69 @@ namespace litehtml
 		typedef std::weak_ptr<document>		weak_ptr;
 	private:
 		std::shared_ptr<element>			m_root;
+		std::shared_ptr<render_item>		m_root_render;
 		document_container*					m_container;
 		fonts_map							m_fonts;
 		css_text::vector					m_css;
 		litehtml::css						m_styles;
 		litehtml::web_color					m_def_color;
-		litehtml::context*					m_context;
+        litehtml::css						m_master_css;
+        litehtml::css						m_user_css;
 		litehtml::size						m_size;
+		litehtml::size						m_content_size;
 		position::vector					m_fixed_boxes;
 		media_query_list::vector			m_media_lists;
 		element::ptr						m_over_element;
-		elements_vector						m_tabular_elements;
+		std::list<std::shared_ptr<render_item>>		m_tabular_elements;
 		media_features						m_media;
-		tstring                             m_lang;
-		tstring                             m_culture;
+		string								m_lang;
+		string								m_culture;
 	public:
-		document(litehtml::document_container* objContainer, litehtml::context* ctx);
+		document(document_container* objContainer);
 		virtual ~document();
 
-		litehtml::document_container*	container()	{ return m_container; }
-		uint_ptr						get_font(const tchar_t* name, int size, const tchar_t* weight, const tchar_t* style, const tchar_t* decoration, font_metrics* fm);
+		document_container*				container()	{ return m_container; }
+		uint_ptr						get_font(const char* name, int size, const char* weight, const char* style, const char* decoration, font_metrics* fm);
 		int								render(int max_width, render_type rt = render_all);
 		void							draw(uint_ptr hdc, int x, int y, const position* clip);
 		web_color						get_def_color()	{ return m_def_color; }
-		int								cvt_units(const tchar_t* str, int fontSize, bool* is_percent = 0) const;
-		int								cvt_units(css_length& val, int fontSize, int size = 0) const;
+		int								to_pixels(const char* str, int fontSize, bool* is_percent = nullptr) const;
+		void 							cvt_units(css_length& val, int fontSize, int size = 0) const;
+		int								to_pixels(const css_length& val, int fontSize, int size = 0) const;
 		int								width() const;
 		int								height() const;
-		void							add_stylesheet(const tchar_t* str, const tchar_t* baseurl, const tchar_t* media);
+		int								content_width() const;
+		int								content_height() const;
+		void							add_stylesheet(const char* str, const char* baseurl, const char* media);
 		bool							on_mouse_over(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);
 		bool							on_lbutton_down(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);
 		bool							on_lbutton_up(int x, int y, int client_x, int client_y, position::vector& redraw_boxes);
 		bool							on_mouse_leave(position::vector& redraw_boxes);
-		litehtml::element::ptr			create_element(const tchar_t* tag_name, const string_map& attributes);
+		element::ptr					create_element(const char* 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);
+		void							add_media_list(const media_query_list::ptr& list);
 		bool							media_changed();
 		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; }
+		bool							match_lang(const string& lang);
+		void							add_tabular(const std::shared_ptr<render_item>& el);
+		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);
+		void							append_children_from_string(element& parent, const char* str);
+		void							dump(dumper& cout);
 
-		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);
+		static litehtml::document::ptr	createFromString(const char* str, litehtml::document_container* objPainter, const char* master_styles = litehtml::master_css, const char* user_styles = "");
 	
 	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);
+		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);
 		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);
-		void fix_table_parent(element::ptr& el_ptr, style_display disp, const tchar_t* disp_str);
+		void fix_table_children(const std::shared_ptr<render_item>& el_ptr, style_display disp, const char* disp_str);
+		void fix_table_parent(const std::shared_ptr<render_item> & el_ptr, style_display disp, const char* disp_str);
 	};
 
 	inline element::ptr document::root()
@@ -123,11 +126,11 @@ namespace litehtml
 	{
 		return m_over_element;
 	}
-	inline void document::add_tabular(const element::ptr& el)
+	inline void document::add_tabular(const std::shared_ptr<render_item>& el)
 	{
 		m_tabular_elements.push_back(el);
 	}
-	inline bool document::match_lang(const tstring & lang)
+	inline bool document::match_lang(const string& lang)
 	{
 		return lang == m_lang || lang == m_culture;
 	}
diff --git a/src/plugins/litehtml_viewer/litehtml/document_container.cpp b/src/plugins/litehtml_viewer/litehtml/document_container.cpp
new file mode 100644
index 000000000..d3802473e
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/document_container.cpp
@@ -0,0 +1,44 @@
+#include "html.h"
+#include "document_container.h"
+
+void litehtml::document_container::split_text(const char* text, const std::function<void(const char*)>& on_word, const std::function<void(const char*)>& on_space)
+{
+	std::wstring str;
+	std::wstring str_in = (const wchar_t*)utf8_to_wchar(text);
+	ucode_t c;
+	for (size_t i = 0; i < str_in.length(); i++)
+	{
+		c = (ucode_t)str_in[i];
+		if (c <= ' ' && (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f'))
+		{
+			if (!str.empty())
+			{
+				on_word(wchar_to_utf8(str.c_str()));
+				str.clear();
+			}
+			str += c;
+			on_space(wchar_to_utf8(str.c_str()));
+			str.clear();
+		}
+		// CJK character range
+		else if (c >= 0x4E00 && c <= 0x9FCC)
+		{
+			if (!str.empty())
+			{
+				on_word(wchar_to_utf8(str.c_str()));
+				str.clear();
+			}
+			str += c;
+			on_word(wchar_to_utf8(str.c_str()));
+			str.clear();
+		}
+		else
+		{
+			str += c;
+		}
+	}
+	if (!str.empty())
+	{
+		on_word(wchar_to_utf8(str.c_str()));
+	}
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/document_container.h b/src/plugins/litehtml_viewer/litehtml/document_container.h
new file mode 100644
index 000000000..391873c1a
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/document_container.h
@@ -0,0 +1,71 @@
+#ifndef LH_DOCUMENT_CONTAINER_H
+#define LH_DOCUMENT_CONTAINER_H
+
+#include "os_types.h"
+#include "types.h"
+#include "web_color.h"
+#include "background.h"
+#include "borders.h"
+#include "element.h"
+#include <memory>
+#include <functional>
+
+namespace litehtml
+{
+	struct list_marker
+	{
+		string			image;
+		const char*		baseurl;
+		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
+	class document_container
+	{
+	public:
+		virtual litehtml::uint_ptr	create_font(const char* faceName, int size, int weight, litehtml::font_style italic, unsigned int decoration, litehtml::font_metrics* fm) = 0;
+		virtual void				delete_font(litehtml::uint_ptr hFont) = 0;
+		virtual int					text_width(const char* text, litehtml::uint_ptr hFont) = 0;
+		virtual void				draw_text(litehtml::uint_ptr hdc, const char* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos) = 0;
+		virtual int					pt_to_px(int pt) const = 0;
+		virtual int					get_default_font_size() const = 0;
+		virtual const char*			get_default_font_name() const = 0;
+		virtual void				draw_list_marker(litehtml::uint_ptr hdc, const litehtml::list_marker& marker) = 0;
+		virtual void				load_image(const char* src, const char* baseurl, bool redraw_on_ready) = 0;
+		virtual void				get_image_size(const char* src, const char* baseurl, litehtml::size& sz) = 0;
+		// Note: regular <img> images are also drawn with draw_background
+		// bg is guaranteed to have at least one item.
+		// backgrounds in bg are in CSS order - the last one is the farthest from the user.
+		// only the last background has valid background-color.
+		virtual void				draw_background(litehtml::uint_ptr hdc, const std::vector<litehtml::background_paint>& bg) = 0;
+		virtual void				draw_borders(litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root) = 0;
+
+		virtual	void				set_caption(const char* caption) = 0;
+		virtual	void				set_base_url(const char* base_url) = 0;
+		virtual void				link(const std::shared_ptr<litehtml::document>& doc, const litehtml::element::ptr& el) = 0;
+		virtual void				on_anchor_click(const char* url, const litehtml::element::ptr& el) = 0;
+		virtual	void				set_cursor(const char* cursor) = 0;
+		virtual	void				transform_text(litehtml::string& text, litehtml::text_transform tt) = 0;
+		virtual void				import_css(litehtml::string& text, const litehtml::string& url, litehtml::string& baseurl) = 0;
+		virtual void				set_clip(const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius) = 0;
+		virtual void				del_clip() = 0;
+		virtual void				get_client_rect(litehtml::position& client) const = 0;
+		virtual litehtml::element::ptr	create_element( const char* tag_name,
+														const litehtml::string_map& attributes,
+														const std::shared_ptr<litehtml::document>& doc) = 0;
+
+		virtual void				get_media_features(litehtml::media_features& media) const = 0;
+		virtual void				get_language(litehtml::string& language, litehtml::string& culture) const = 0;
+		virtual litehtml::string	resolve_color(const litehtml::string& /*color*/) const { return litehtml::string(); }
+		virtual void				split_text(const char* text, const std::function<void(const char*)>& on_word, const std::function<void(const char*)>& on_space);
+
+	protected:
+		~document_container() = default;
+	};
+}
+
+#endif  // LH_DOCUMENT_CONTAINER_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_anchor.cpp b/src/plugins/litehtml_viewer/litehtml/el_anchor.cpp
index a120eb15d..372e4afb5 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_anchor.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_anchor.cpp
@@ -6,14 +6,9 @@ litehtml::el_anchor::el_anchor(const std::shared_ptr<litehtml::document>& doc) :
 {
 }
 
-litehtml::el_anchor::~el_anchor()
-{
-
-}
-
 void litehtml::el_anchor::on_click()
 {
-	const tchar_t* href = get_attr(_t("href"));
+	const char* href = get_attr("href");
 
 	if(href)
 	{
@@ -23,9 +18,9 @@ void litehtml::el_anchor::on_click()
 
 void litehtml::el_anchor::apply_stylesheet( const litehtml::css& stylesheet )
 {
-	if( get_attr(_t("href")) )
+	if( get_attr("href") )
 	{
-		m_pseudo_classes.push_back(_t("link"));
+		m_pseudo_classes.push_back(_link_);
 	}
 	html_tag::apply_stylesheet(stylesheet);
 }
diff --git a/src/plugins/litehtml_viewer/litehtml/el_anchor.h b/src/plugins/litehtml_viewer/litehtml/el_anchor.h
index 140d19508..b33794c52 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_anchor.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_anchor.h
@@ -8,11 +8,10 @@ namespace litehtml
 	class el_anchor : public html_tag
 	{
 	public:
-		el_anchor(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_anchor();
+		explicit el_anchor(const std::shared_ptr<litehtml::document>& doc);
 
-		virtual void	on_click() override;
-		virtual void	apply_stylesheet(const litehtml::css& stylesheet) override;
+		void	on_click() override;
+		void	apply_stylesheet(const litehtml::css& stylesheet) override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/el_base.cpp b/src/plugins/litehtml_viewer/litehtml/el_base.cpp
index dffc6afd0..baf025653 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_base.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_base.cpp
@@ -2,17 +2,12 @@
 #include "el_base.h"
 #include "document.h"
 
-litehtml::el_base::el_base(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+litehtml::el_base::el_base(const std::shared_ptr<document>& doc) : html_tag(doc)
 {
 	
 }
 
-litehtml::el_base::~el_base()
-{
-
-}
-
 void litehtml::el_base::parse_attributes()
 {
-	get_document()->container()->set_base_url(get_attr(_t("href")));
+	get_document()->container()->set_base_url(get_attr("href"));
 }
diff --git a/src/plugins/litehtml_viewer/litehtml/el_base.h b/src/plugins/litehtml_viewer/litehtml/el_base.h
index 57ba87d4f..d7efb8064 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_base.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_base.h
@@ -8,10 +8,9 @@ namespace litehtml
 	class el_base : public html_tag
 	{
 	public:
-		el_base(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_base();
+		explicit el_base(const std::shared_ptr<litehtml::document>& doc);
 
-		virtual void	parse_attributes() override;
+		void parse_attributes() override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/el_before_after.cpp b/src/plugins/litehtml_viewer/litehtml/el_before_after.cpp
index bf0127d2f..4455642e8 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_before_after.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_before_after.cpp
@@ -3,90 +3,104 @@
 #include "el_text.h"
 #include "el_space.h"
 #include "el_image.h"
+#include "utf8_strings.h"
 
-litehtml::el_before_after_base::el_before_after_base(const std::shared_ptr<litehtml::document>& doc, bool before) : html_tag(doc)
+litehtml::el_before_after_base::el_before_after_base(const std::shared_ptr<document>& doc, bool before) : html_tag(doc)
 {
-	if(before)
-	{
-		set_tagName(_t("::before"));
-	} else
-	{
-		set_tagName(_t("::after"));
-	}
+	m_tag = before ? __tag_before_ : __tag_after_;
 }
 
-litehtml::el_before_after_base::~el_before_after_base()
+void litehtml::el_before_after_base::add_style(const style& style)
 {
+	html_tag::add_style(style);
 
-}
-
-void litehtml::el_before_after_base::add_style(const litehtml::style& st)
-{
-	html_tag::add_style(st);
+	auto children = m_children;
+	m_children.clear();
 
-	tstring content = get_style_property(_t("content"), false, _t(""));
-	if(!content.empty())
+	const auto& content_property = style.get_property(_content_);
+	if(content_property.m_type == prop_type_string && !content_property.m_string.empty())
 	{
-		int idx = value_index(content.c_str(), content_property_string);
+		int idx = value_index(content_property.m_string, content_property_string);
 		if(idx < 0)
 		{
-			tstring fnc;
-			tstring::size_type i = 0;
-			while(i < content.length() && i != tstring::npos)
+			string fnc;
+			string::size_type i = 0;
+			while(i < content_property.m_string.length() && i != string::npos)
 			{
-				if(content.at(i) == _t('"'))
+				if(content_property.m_string.at(i) == '"' || content_property.m_string.at(i) == '\'')
 				{
+                    auto chr = content_property.m_string.at(i);
 					fnc.clear();
 					i++;
-					tstring::size_type pos = content.find(_t('"'), i);
-					tstring txt;
-					if(pos == tstring::npos)
+					string::size_type pos = content_property.m_string.find(chr, i);
+					string txt;
+					if(pos == string::npos)
 					{
-						txt = content.substr(i);
-						i = tstring::npos;
+						txt = content_property.m_string.substr(i);
+						i = string::npos;
 					} else
 					{
-						txt = content.substr(i, pos - i);
+						txt = content_property.m_string.substr(i, pos - i);
 						i = pos + 1;
 					}
 					add_text(txt);
-				} else if(content.at(i) == _t('('))
+				} else if(content_property.m_string.at(i) == '(')
 				{
 					i++;
 					litehtml::trim(fnc);
 					litehtml::lcase(fnc);
-					tstring::size_type pos = content.find(_t(')'), i);
-					tstring params;
-					if(pos == tstring::npos)
+					string::size_type pos = content_property.m_string.find(')', i);
+					string params;
+					if(pos == string::npos)
 					{
-						params = content.substr(i);
-						i = tstring::npos;
+						params = content_property.m_string.substr(i);
+						i = string::npos;
 					} else
 					{
-						params = content.substr(i, pos - i);
+						params = content_property.m_string.substr(i, pos - i);
 						i = pos + 1;
 					}
 					add_function(fnc, params);
 					fnc.clear();
 				} else
 				{
-					fnc += content.at(i);
+					fnc += content_property.m_string.at(i);
 					i++;
 				}
 			}
 		}
 	}
+
+	if(m_children.empty())
+	{
+		m_children = children;
+	}
 }
 
-void litehtml::el_before_after_base::add_text( const tstring& txt )
+void litehtml::el_before_after_base::add_text( const string& txt )
 {
-	tstring word;
-	tstring esc;
-	for(tstring::size_type i = 0; i < txt.length(); i++)
+	string word;
+	string esc;
+
+	for(auto chr : txt)
 	{
-		if( (txt.at(i) == _t(' ')) || (txt.at(i) == _t('\t')) || (txt.at(i) == _t('\\') && !esc.empty()) )
+		if(chr == '\\' ||
+			!esc.empty() && esc.length() < 5 && (chr >= '0' && chr <= '9' || chr >= 'A' && chr <= 'Z' || chr >= 'a' && chr <= 'z'))
+		{
+			if(!esc.empty() && chr == '\\')
+			{
+				word += convert_escape(esc.c_str() + 1);
+				esc.clear();
+			}
+			esc += chr;
+		} else
 		{
-			if(esc.empty())
+			if(!esc.empty())
+			{
+				word += convert_escape(esc.c_str() + 1);
+				esc.clear();
+			}
+			if(isspace(chr))
 			{
 				if(!word.empty())
 				{
@@ -94,26 +108,13 @@ void litehtml::el_before_after_base::add_text( const tstring& txt )
 					appendChild(el);
 					word.clear();
 				}
-
-				element::ptr el = std::make_shared<el_space>(txt.substr(i, 1).c_str(), get_document());
+				word += chr;
+				element::ptr el = std::make_shared<el_text>(word.c_str(), get_document());
 				appendChild(el);
+				word.clear();
 			} else
 			{
-				word += convert_escape(esc.c_str() + 1);
-				esc.clear();
-				if(txt.at(i) == _t('\\'))
-				{
-					esc += txt.at(i);
-				}
-			}
-		} else
-		{
-			if(!esc.empty() || txt.at(i) == _t('\\'))
-			{
-				esc += txt.at(i);
-			} else
-			{
-				word += txt.at(i);
+				word += chr;
 			}
 		}
 	}
@@ -130,21 +131,21 @@ void litehtml::el_before_after_base::add_text( const tstring& txt )
 	}
 }
 
-void litehtml::el_before_after_base::add_function( const tstring& fnc, const tstring& params )
+void litehtml::el_before_after_base::add_function( const string& fnc, const string& params )
 {
-	int idx = value_index(fnc.c_str(), _t("attr;counter;url"));
+	int idx = value_index(fnc, "attr;counter;url");
 	switch(idx)
 	{
 	// attr
 	case 0:
 		{
-			tstring p_name = params;
+			string p_name = params;
 			trim(p_name);
 			lcase(p_name);
 			element::ptr el_parent = parent();
 			if (el_parent)
 			{
-				const tchar_t* attr_value = el_parent->get_attr(p_name.c_str());
+				const char* attr_value = el_parent->get_attr(p_name.c_str());
 				if (attr_value)
 				{
 					add_text(attr_value);
@@ -158,18 +159,18 @@ void litehtml::el_before_after_base::add_function( const tstring& fnc, const tst
 	// url
 	case 2:
 		{
-			tstring p_url = params;
+			string p_url = params;
 			trim(p_url);
 			if(!p_url.empty())
 			{
-				if(p_url.at(0) == _t('\'') || p_url.at(0) == _t('\"'))
+				if(p_url.at(0) == '\'' || p_url.at(0) == '\"')
 				{
 					p_url.erase(0, 1);
 				}
 			}
 			if(!p_url.empty())
 			{
-				if(p_url.at(p_url.length() - 1) == _t('\'') || p_url.at(p_url.length() - 1) == _t('\"'))
+				if(p_url.at(p_url.length() - 1) == '\'' || p_url.at(p_url.length() - 1) == '\"')
 				{
 					p_url.erase(p_url.length() - 1, 1);
 				}
@@ -177,9 +178,9 @@ void litehtml::el_before_after_base::add_function( const tstring& fnc, const tst
 			if(!p_url.empty())
 			{
 				element::ptr el = std::make_shared<el_image>(get_document());
-				el->set_attr(_t("src"), p_url.c_str());
-				el->set_attr(_t("style"), _t("display:inline-block"));
-				el->set_tagName(_t("img"));
+				el->set_attr("src", p_url.c_str());
+				el->set_attr("style", "display:inline-block");
+				el->set_tagName("img");
 				appendChild(el);
 				el->parse_attributes();
 			}
@@ -188,10 +189,13 @@ void litehtml::el_before_after_base::add_function( const tstring& fnc, const tst
 	}
 }
 
-litehtml::tchar_t litehtml::el_before_after_base::convert_escape( const tchar_t* txt )
+litehtml::string litehtml::el_before_after_base::convert_escape( const char* txt )
 {
-	tchar_t* sss = 0;
-	return (tchar_t) t_strtol(txt, &sss, 16);
+    char* str_end;
+	wchar_t u_str[2];
+    u_str[0] = (wchar_t) strtol(txt, &str_end, 16);
+    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 1bb55f315..ac966f395 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_before_after.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_before_after.h
@@ -8,21 +8,20 @@ namespace litehtml
 	class el_before_after_base : public html_tag
 	{
 	public:
-		el_before_after_base(const std::shared_ptr<litehtml::document>& doc, bool before);
-		virtual ~el_before_after_base();
+		el_before_after_base(const std::shared_ptr<document>& doc, bool before);
 
-		virtual void add_style(const litehtml::style& st) override;
-		virtual void apply_stylesheet(const litehtml::css& stylesheet) override;
+		void add_style(const style& style) override;
+		void apply_stylesheet(const litehtml::css& stylesheet) override;
 	private:
-		void	add_text(const tstring& txt);
-		void	add_function(const tstring& fnc, const tstring& params);
-		tchar_t convert_escape(const tchar_t* txt);
+		void	add_text(const string& txt);
+		void	add_function(const string& fnc, const string& params);
+		static string convert_escape(const char* txt);
 	};
 
 	class el_before : public el_before_after_base
 	{
 	public:
-		el_before(const std::shared_ptr<litehtml::document>& doc) : el_before_after_base(doc, true)
+		explicit el_before(const std::shared_ptr<document>& doc) : el_before_after_base(doc, true)
 		{
 
 		}
@@ -31,7 +30,7 @@ namespace litehtml
 	class el_after : public el_before_after_base
 	{
 	public:
-		el_after(const std::shared_ptr<litehtml::document>& doc) : el_before_after_base(doc, false)
+		explicit el_after(const std::shared_ptr<document>& doc) : el_before_after_base(doc, false)
 		{
 
 		}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_body.cpp b/src/plugins/litehtml_viewer/litehtml/el_body.cpp
index 61376d5d4..3d35f8f75 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_body.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_body.cpp
@@ -6,11 +6,6 @@ litehtml::el_body::el_body(const std::shared_ptr<litehtml::document>& doc) : lit
 {
 }
 
-litehtml::el_body::~el_body()
-{
-
-}
-
 bool litehtml::el_body::is_body()  const
 {
 	return true;
diff --git a/src/plugins/litehtml_viewer/litehtml/el_body.h b/src/plugins/litehtml_viewer/litehtml/el_body.h
index d03d5df34..fb30e0c51 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_body.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_body.h
@@ -8,10 +8,9 @@ namespace litehtml
 	class el_body : public html_tag
 	{
 	public:
-		el_body(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_body();
+		explicit el_body(const std::shared_ptr<litehtml::document>& doc);
 
-		virtual bool is_body() const override;
+		bool is_body() const override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/el_break.cpp b/src/plugins/litehtml_viewer/litehtml/el_break.cpp
index 5523b4111..f13b2e3cf 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_break.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_break.cpp
@@ -6,11 +6,6 @@ litehtml::el_break::el_break(const std::shared_ptr<litehtml::document>& doc) : h
 
 }
 
-litehtml::el_break::~el_break()
-{
-
-}
-
 bool litehtml::el_break::is_break() const
 {
 	return true;
diff --git a/src/plugins/litehtml_viewer/litehtml/el_break.h b/src/plugins/litehtml_viewer/litehtml/el_break.h
index 70fab321d..2a4d8fe45 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_break.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_break.h
@@ -8,11 +8,10 @@ namespace litehtml
 	class el_break : public html_tag
 	{
 	public:
-		el_break(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_break();
+		explicit el_break(const std::shared_ptr<litehtml::document>& doc);
 
-		virtual bool is_break() const override;
-	};
+		bool is_break() const override;
+    };
 }
 
 #endif  // LH_EL_BREAK_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_cdata.cpp b/src/plugins/litehtml_viewer/litehtml/el_cdata.cpp
index bb21eab10..e5948bff1 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_cdata.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_cdata.cpp
@@ -1,22 +1,17 @@
 #include "html.h"
 #include "el_cdata.h"
 
-litehtml::el_cdata::el_cdata(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+litehtml::el_cdata::el_cdata(const std::shared_ptr<document>& doc) : element(doc)
 {
-	m_skip = true;
+	//m_skip = true;
 }
 
-litehtml::el_cdata::~el_cdata()
-{
-
-}
-
-void litehtml::el_cdata::get_text( tstring& text )
+void litehtml::el_cdata::get_text( string& text )
 {
 	text += m_text;
 }
 
-void litehtml::el_cdata::set_data( const tchar_t* data )
+void litehtml::el_cdata::set_data( const char* data )
 {
 	if(data)
 	{
diff --git a/src/plugins/litehtml_viewer/litehtml/el_cdata.h b/src/plugins/litehtml_viewer/litehtml/el_cdata.h
index 33bdfe311..838cd92b1 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_cdata.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_cdata.h
@@ -7,13 +7,12 @@ namespace litehtml
 {
 	class el_cdata : public element
 	{
-		tstring	m_text;
+		string	m_text;
 	public:
-		el_cdata(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_cdata();
+		explicit el_cdata(const std::shared_ptr<document>& doc);
 
-		virtual void	get_text(tstring& text) override;
-		virtual void	set_data(const tchar_t* data) override;
+		void get_text(string& text) override;
+		void set_data(const char* data) override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/el_comment.cpp b/src/plugins/litehtml_viewer/litehtml/el_comment.cpp
index 638c960f7..1ec934d04 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_comment.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_comment.cpp
@@ -1,22 +1,22 @@
 #include "html.h"
 #include "el_comment.h"
 
-litehtml::el_comment::el_comment(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+litehtml::el_comment::el_comment(const std::shared_ptr<document>& doc) : element(doc)
 {
-	m_skip = true;
+	//m_skip = true;
 }
 
-litehtml::el_comment::~el_comment()
+bool litehtml::el_comment::is_comment() const
 {
-
+	return true;
 }
 
-void litehtml::el_comment::get_text( tstring& text )
+void litehtml::el_comment::get_text( string& text )
 {
 	text += m_text;
 }
 
-void litehtml::el_comment::set_data( const tchar_t* data )
+void litehtml::el_comment::set_data( const char* data )
 {
 	if(data)
 	{
diff --git a/src/plugins/litehtml_viewer/litehtml/el_comment.h b/src/plugins/litehtml_viewer/litehtml/el_comment.h
index ceffd2c05..454ee4787 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_comment.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_comment.h
@@ -7,13 +7,18 @@ namespace litehtml
 {
 	class el_comment : public element
 	{
-		tstring	m_text;
+		string	m_text;
 	public:
-		el_comment(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_comment();
+		explicit el_comment(const std::shared_ptr<document>& doc);
 
-		virtual void	get_text(tstring& text) override;
-		virtual void	set_data(const tchar_t* data) override;
+		bool is_comment() const override;
+		void get_text(string& text) override;
+		void set_data(const char* data) override;
+        std::shared_ptr<render_item> create_render_item(const std::shared_ptr<render_item>& parent_ri) override
+        {
+            // Comments are not rendered
+            return nullptr;
+        }
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/el_div.cpp b/src/plugins/litehtml_viewer/litehtml/el_div.cpp
index c4ee3c0db..983d45ab2 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_div.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_div.cpp
@@ -2,22 +2,17 @@
 #include "el_div.h"
 
 
-litehtml::el_div::el_div(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
-{
-
-}
-
-litehtml::el_div::~el_div()
+litehtml::el_div::el_div(const document::ptr& doc) : html_tag(doc)
 {
 
 }
 
 void litehtml::el_div::parse_attributes()
 {
-	const tchar_t* str = get_attr(_t("align"));
+	const char* str = get_attr("align");
 	if(str)
 	{
-		m_style.add_property(_t("text-align"), str, 0, false);
+		m_style.add_property(_text_align_, str);
 	}
 	html_tag::parse_attributes();
 }
diff --git a/src/plugins/litehtml_viewer/litehtml/el_div.h b/src/plugins/litehtml_viewer/litehtml/el_div.h
index ece762f51..a2d031a32 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_div.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_div.h
@@ -8,10 +8,9 @@ namespace litehtml
 	class el_div : public html_tag
 	{
 	public:
-		el_div(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_div();
+		explicit el_div(const std::shared_ptr<litehtml::document>& doc);
 
-		virtual void parse_attributes() override;
+		void parse_attributes() override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/el_font.cpp b/src/plugins/litehtml_viewer/litehtml/el_font.cpp
index da6bae984..3d5f6d9f7 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_font.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_font.cpp
@@ -2,55 +2,52 @@
 #include "el_font.h"
 
 
-litehtml::el_font::el_font(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
-{
-
-}
-
-litehtml::el_font::~el_font()
+litehtml::el_font::el_font(const std::shared_ptr<document>& doc) : html_tag(doc)
 {
 
 }
 
 void litehtml::el_font::parse_attributes()
 {
-	const tchar_t* str = get_attr(_t("color"));
+	const char* str = get_attr("color");
 	if(str)
 	{
-		m_style.add_property(_t("color"), str, 0, false);
+		m_style.add_property(_color_, str, "", false, get_document()->container());
 	}
 
-	str = get_attr(_t("face"));
+	str = get_attr("face");
 	if(str)
 	{
-		m_style.add_property(_t("font-face"), str, 0, false);
+		m_style.add_property(_font_family_, str);
 	}
 
-	str = get_attr(_t("size"));
+	str = get_attr("size");
 	if(str)
 	{
-		int sz = t_atoi(str);
+		int sz = atoi(str);
+		if(*str == '+' || *str == '-') sz = 3 + sz; // relative size
+
 		if(sz <= 1)
 		{
-			m_style.add_property(_t("font-size"), _t("x-small"), 0, false);
+			m_style.add_property(_font_size_, "x-small");
 		} else if(sz >= 6)
 		{
-			m_style.add_property(_t("font-size"), _t("xx-large"), 0, false);
+			m_style.add_property(_font_size_, "xx-large");
 		} else
 		{
 			switch(sz)
 			{
 			case 2:
-				m_style.add_property(_t("font-size"), _t("small"), 0, false);
+				m_style.add_property(_font_size_, "small");
 				break;
 			case 3:
-				m_style.add_property(_t("font-size"), _t("medium"), 0, false);
+				m_style.add_property(_font_size_, "medium");
 				break;
 			case 4:
-				m_style.add_property(_t("font-size"), _t("large"), 0, false);
+				m_style.add_property(_font_size_, "large");
 				break;
 			case 5:
-				m_style.add_property(_t("font-size"), _t("x-large"), 0, false);
+				m_style.add_property(_font_size_, "x-large");
 				break;
 			}
 		}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_font.h b/src/plugins/litehtml_viewer/litehtml/el_font.h
index a0f391ec2..ccb894512 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_font.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_font.h
@@ -8,10 +8,9 @@ namespace litehtml
 	class el_font : public html_tag
 	{
 	public:
-		el_font(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_font();
+		explicit el_font(const std::shared_ptr<litehtml::document>& doc);
 
-		virtual void parse_attributes() override;
+		void parse_attributes() override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/el_image.cpp b/src/plugins/litehtml_viewer/litehtml/el_image.cpp
index 62b3c4437..34b8a7aef 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_image.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_image.cpp
@@ -1,15 +1,10 @@
 #include "html.h"
 #include "el_image.h"
-#include "document.h"
+#include "render_item.h"
 
-litehtml::el_image::el_image(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+litehtml::el_image::el_image(const document::ptr& doc) : html_tag(doc)
 {
-	m_display = display_inline_block;
-}
-
-litehtml::el_image::~el_image( void )
-{
-
+	m_css.set_display(display_inline_block);
 }
 
 void litehtml::el_image::get_content_size( size& sz, int max_width )
@@ -17,196 +12,36 @@ 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();
-}
-
 bool litehtml::el_image::is_replaced() const
 {
 	return true;
 }
 
-int litehtml::el_image::render( int x, int y, int max_width, bool second_pass )
-{
-	int parent_width = max_width;
-
-	calc_outlines(parent_width);
-
-	m_pos.move_to(x, y);
-
-	document::ptr doc = get_document();
-
-	litehtml::size sz;
-	doc->container()->get_image_size(m_src.c_str(), 0, sz);
-
-	m_pos.width		= sz.width;
-	m_pos.height	= sz.height;
-
-	if(m_css_height.is_predefined() && m_css_width.is_predefined())
-	{
-		m_pos.height	= sz.height;
-		m_pos.width		= sz.width;
-
-		// 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);
-			if(m_pos.width > max_width)
-			{
-				m_pos.width = max_width;
-			}
-			if(sz.width)
-			{
-				m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);
-			} else
-			{
-				m_pos.height = sz.height;
-			}
-		}
-
-		// check for max-height
-		if(!m_css_max_height.is_predefined())
-		{
-			int max_height = calc_max_height(sz.height);
-			if(m_pos.height > max_height)
-			{
-				m_pos.height = max_height;
-			}
-			if(sz.height)
-			{
-				m_pos.width = (int) (m_pos.height * (float)sz.width / (float)sz.height);
-			} else
-			{
-				m_pos.width = sz.width;
-			}
-		}
-	} else if(!m_css_height.is_predefined() && m_css_width.is_predefined())
-	{
-		if (!get_predefined_height(m_pos.height))
-		{
-			m_pos.height = (int)m_css_height.val();
-		}
-
-		// check for max-height
-		if(!m_css_max_height.is_predefined())
-		{
-			int max_height = calc_max_height(sz.height);
-			if(m_pos.height > max_height)
-			{
-				m_pos.height = max_height;
-			}
-		}
-
-		if(sz.height)
-		{
-			m_pos.width = (int) (m_pos.height * (float)sz.width / (float)sz.height);
-		} else
-		{
-			m_pos.width = sz.width;
-		}
-	} else if(m_css_height.is_predefined() && !m_css_width.is_predefined())
-	{
-		m_pos.width = (int) m_css_width.calc_percent(parent_width);
-
-		// 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);
-			if(m_pos.width > max_width)
-			{
-				m_pos.width = max_width;
-			}
-		}
-
-		if(sz.width)
-		{
-			m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);
-		} else
-		{
-			m_pos.height = sz.height;
-		}
-	} else
-	{
-		m_pos.width		= (int) m_css_width.calc_percent(parent_width);
-		m_pos.height	= 0;
-		if (!get_predefined_height(m_pos.height))
-		{
-			m_pos.height = (int)m_css_height.val();
-		}
-
-		// check for max-height
-		if(!m_css_max_height.is_predefined())
-		{
-			int max_height = calc_max_height(sz.height);
-			if(m_pos.height > max_height)
-			{
-				m_pos.height = max_height;
-			}
-		}
-
-		// check for max-height
-		if(!m_css_max_width.is_predefined())
-		{
-			int max_width = doc->cvt_units(m_css_max_width, m_font_size, parent_width);
-			if(m_pos.width > max_width)
-			{
-				m_pos.width = max_width;
-			}
-		}
-	}
-
-	calc_auto_margins(parent_width);
-
-	m_pos.x	+= content_margins_left();
-	m_pos.y += content_margins_top();
-
-	return m_pos.width + content_margins_left() + content_margins_right();
-}
-
 void litehtml::el_image::parse_attributes()
 {
-	m_src = get_attr(_t("src"), _t(""));
+	m_src = get_attr("src", "");
 
-	const tchar_t* attr_height = get_attr(_t("height"));
+	const char* attr_height = get_attr("height");
 	if(attr_height)
 	{
-		m_style.add_property(_t("height"), attr_height, 0, false);
+		m_style.add_property(_height_, attr_height);
 	}
-	const tchar_t* attr_width = get_attr(_t("width"));
+	const char* attr_width = get_attr("width");
 	if(attr_width)
 	{
-		m_style.add_property(_t("width"), attr_width, 0, false);
+		m_style.add_property(_width_, attr_width);
 	}
 }
 
-void litehtml::el_image::draw( uint_ptr hdc, int x, int y, const position* clip )
+void litehtml::el_image::draw(uint_ptr hdc, int x, int y, const position *clip, const std::shared_ptr<render_item> &ri)
 {
-	position pos = m_pos;
+	position pos = ri->pos();
 	pos.x += x;
 	pos.y += y;
 
 	position el_pos = pos;
-	el_pos += m_padding;
-	el_pos += m_borders;
+	el_pos += ri->get_paddings();
+	el_pos += ri->get_borders();
 
 	// draw standard background here
 	if (el_pos.does_intersect(clip))
@@ -214,8 +49,8 @@ void litehtml::el_image::draw( uint_ptr hdc, int x, int y, const position* clip
 		const background* bg = get_background();
 		if (bg)
 		{
-			background_paint bg_paint;
-			init_background_paint(pos, bg_paint, bg);
+			std::vector<background_paint> bg_paint;
+			init_background_paint(pos, bg_paint, bg, ri);
 
 			get_document()->container()->draw_background(hdc, bg_paint);
 		}
@@ -230,15 +65,15 @@ void litehtml::el_image::draw( uint_ptr hdc, int x, int y, const position* clip
 			bg.clip_box				= pos;
 			bg.origin_box			= pos;
 			bg.border_box			= pos;
-			bg.border_box			+= m_padding;
-			bg.border_box			+= m_borders;
+			bg.border_box			+= ri->get_paddings();
+			bg.border_box			+= ri->get_borders();
 			bg.repeat				= background_repeat_no_repeat;
 			bg.image_size.width		= pos.width;
 			bg.image_size.height	= pos.height;
-			bg.border_radius		= m_css_borders.radius.calc_percents(bg.border_box.width, bg.border_box.height);
+			bg.border_radius		= css().get_borders().radius.calc_percents(bg.border_box.width, bg.border_box.height);
 			bg.position_x			= pos.x;
 			bg.position_y			= pos.y;
-			get_document()->container()->draw_background(hdc, bg);
+			get_document()->container()->draw_background(hdc, {bg});
 		}
 	}
 
@@ -246,28 +81,40 @@ void litehtml::el_image::draw( uint_ptr hdc, int x, int y, const position* clip
 	if (el_pos.does_intersect(clip))
 	{
 		position border_box = pos;
-		border_box += m_padding;
-		border_box += m_borders;
+		border_box += ri->get_paddings();
+		border_box += ri->get_borders();
 
-		borders bdr = m_css_borders;
-		bdr.radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
+		borders bdr = css().get_borders();
+		bdr.radius = css().get_borders().radius.calc_percents(border_box.width, border_box.height);
 
-		get_document()->container()->draw_borders(hdc, bdr, border_box, have_parent() ? false : true);
+		get_document()->container()->draw_borders(hdc, bdr, border_box, is_root());
 	}
 }
 
-void litehtml::el_image::parse_styles( bool is_reparse /*= false*/ )
+void litehtml::el_image::compute_styles(bool recursive)
 {
-	html_tag::parse_styles(is_reparse);
+	html_tag::compute_styles(recursive);
 
 	if(!m_src.empty())
 	{
-		if(!m_css_height.is_predefined() && !m_css_width.is_predefined())
+		if(!css().get_height().is_predefined() && !css().get_width().is_predefined())
 		{
-			get_document()->container()->load_image(m_src.c_str(), 0, true);
+			get_document()->container()->load_image(m_src.c_str(), nullptr, true);
 		} else
 		{
-			get_document()->container()->load_image(m_src.c_str(), 0, false);
+			get_document()->container()->load_image(m_src.c_str(), nullptr, false);
 		}
 	}
 }
+
+litehtml::string litehtml::el_image::dump_get_name()
+{
+    return "img src=\"" + m_src + "\"";
+}
+
+std::shared_ptr<litehtml::render_item> litehtml::el_image::create_render_item(const std::shared_ptr<render_item>& parent_ri)
+{
+    auto ret = std::make_shared<render_item_image>(shared_from_this());
+    ret->parent(parent_ri);
+    return ret;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_image.h b/src/plugins/litehtml_viewer/litehtml/el_image.h
index fa13d3c1d..2b7394081 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_image.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_image.h
@@ -8,20 +8,21 @@ namespace litehtml
 
 	class el_image : public html_tag
 	{
-		tstring	m_src;
+		string	m_src;
 	public:
-		el_image(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_image(void);
+		el_image(const document::ptr& doc);
+
+		bool	is_replaced() const override;
+		void	parse_attributes() override;
+		void	compute_styles(bool recursive = true) override;
+		void	draw(uint_ptr hdc, int x, int y, const position *clip, const std::shared_ptr<render_item> &ri) override;
+		void	get_content_size(size& sz, int max_width) override;
+		string	dump_get_name() override;
+
+		std::shared_ptr<render_item> create_render_item(const std::shared_ptr<render_item>& parent_ri) override;
 
-		virtual int		line_height() const override;
-		virtual bool	is_replaced() const override;
-		virtual int		render(int x, int y, int max_width, bool second_pass = false) override;
-		virtual void	parse_attributes() override;
-		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);
+//		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
deleted file mode 100644
index 9f2f484fe..000000000
--- a/src/plugins/litehtml_viewer/litehtml/el_li.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#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
deleted file mode 100644
index 3451c4f1d..000000000
--- a/src/plugins/litehtml_viewer/litehtml/el_li.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#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/el_link.cpp b/src/plugins/litehtml_viewer/litehtml/el_link.cpp
index 01561ab6c..aa3bc7659 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_link.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_link.cpp
@@ -3,12 +3,7 @@
 #include "document.h"
 
 
-litehtml::el_link::el_link(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
-{
-
-}
-
-litehtml::el_link::~el_link()
+litehtml::el_link::el_link(const std::shared_ptr<document>& doc) : litehtml::html_tag(doc)
 {
 
 }
@@ -19,15 +14,15 @@ void litehtml::el_link::parse_attributes()
 
 	document::ptr doc = get_document();
 
-	const tchar_t* rel = get_attr(_t("rel"));
-	if(rel && !t_strcmp(rel, _t("stylesheet")))
+	const char* rel = get_attr("rel");
+	if(rel && !strcmp(rel, "stylesheet"))
 	{
-		const tchar_t* media	= get_attr(_t("media"));
-		const tchar_t* href		= get_attr(_t("href"));
+		const char* media	= get_attr("media");
+		const char* href	= get_attr("href");
 		if(href && href[0])
 		{
-			tstring css_text;
-			tstring css_baseurl;
+			string css_text;
+			string css_baseurl;
 			doc->container()->import_css(css_text, href, css_baseurl);
 			if(!css_text.empty())
 			{
diff --git a/src/plugins/litehtml_viewer/litehtml/el_link.h b/src/plugins/litehtml_viewer/litehtml/el_link.h
index 6795760ba..0da3513dc 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_link.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_link.h
@@ -8,11 +8,10 @@ namespace litehtml
 	class el_link : public html_tag
 	{
 	public:
-		el_link(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_link();
+		explicit el_link(const std::shared_ptr<litehtml::document>& doc);
 
 	protected:
-		virtual void	parse_attributes() override;
+		void parse_attributes() override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/el_para.cpp b/src/plugins/litehtml_viewer/litehtml/el_para.cpp
index 0986e5c73..5d7915135 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_para.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_para.cpp
@@ -2,21 +2,16 @@
 #include "el_para.h"
 #include "document.h"
 
-litehtml::el_para::el_para(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
+litehtml::el_para::el_para(const std::shared_ptr<document>& doc) : html_tag(doc)
 {
 }
 
-litehtml::el_para::~el_para()
-{
-
-}
-
 void litehtml::el_para::parse_attributes()
 {
-	const tchar_t* str = get_attr(_t("align"));
+	const char* str = get_attr("align");
 	if(str)
 	{
-		m_style.add_property(_t("text-align"), str, 0, false);
+		m_style.add_property(_text_align_, str);
 	}
 
 	html_tag::parse_attributes();
diff --git a/src/plugins/litehtml_viewer/litehtml/el_para.h b/src/plugins/litehtml_viewer/litehtml/el_para.h
index 82e964ba1..32ad53758 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_para.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_para.h
@@ -8,10 +8,9 @@ namespace litehtml
 	class el_para : public html_tag
 	{
 	public:
-		el_para(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_para();
+		explicit el_para(const std::shared_ptr<litehtml::document>& doc);
 
-		virtual void	parse_attributes() override;
+		void parse_attributes() override;
 
 	};
 }
diff --git a/src/plugins/litehtml_viewer/litehtml/el_script.cpp b/src/plugins/litehtml_viewer/litehtml/el_script.cpp
index 603a46d58..4b598a137 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_script.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_script.cpp
@@ -3,12 +3,7 @@
 #include "document.h"
 
 
-litehtml::el_script::el_script(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
-{
-
-}
-
-litehtml::el_script::~el_script()
+litehtml::el_script::el_script(const std::shared_ptr<document>& doc) : element(doc)
 {
 
 }
@@ -24,7 +19,12 @@ bool litehtml::el_script::appendChild(const ptr &el)
 	return true;
 }
 
-const litehtml::tchar_t* litehtml::el_script::get_tagName() const
+litehtml::string_id litehtml::el_script::tag() const
+{
+	return _script_;
+}
+
+const char* litehtml::el_script::get_tagName() const
 {
-	return _t("script");
+	return "script";
 }
diff --git a/src/plugins/litehtml_viewer/litehtml/el_script.h b/src/plugins/litehtml_viewer/litehtml/el_script.h
index b8fed3697..e0a037405 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_script.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_script.h
@@ -7,14 +7,14 @@ namespace litehtml
 {
 	class el_script : public element
 	{
-		tstring m_text;
+		string m_text;
 	public:
-		el_script(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_script();
+		explicit el_script(const std::shared_ptr<document>& doc);
 
-		virtual void			parse_attributes() override;
-		virtual bool			appendChild(const ptr &el) override;
-		virtual const tchar_t*	get_tagName() const override;
+		void parse_attributes() override;
+		bool appendChild(const ptr &el) override;
+		string_id tag() const override;
+		const char*	get_tagName() const override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/el_space.cpp b/src/plugins/litehtml_viewer/litehtml/el_space.cpp
index 5178255f1..f5e3818ca 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_space.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_space.cpp
@@ -2,18 +2,13 @@
 #include "document.h"
 #include "el_space.h"
 
-litehtml::el_space::el_space(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc) : el_text(text, doc)
+litehtml::el_space::el_space(const char* text, const std::shared_ptr<document>& doc) : el_text(text, doc)
 {
 }
 
-litehtml::el_space::~el_space()
-{
-
-}
-
 bool litehtml::el_space::is_white_space() const
 {
-	white_space ws = get_white_space();
+	white_space ws = css().get_white_space();
 	if(	ws == white_space_normal || 
 		ws == white_space_nowrap ||
 		ws == white_space_pre_line )
@@ -25,15 +20,25 @@ bool litehtml::el_space::is_white_space() const
 
 bool litehtml::el_space::is_break() const
 {
-	white_space ws = get_white_space();
+	white_space ws = css().get_white_space();
 	if(	ws == white_space_pre ||
 		ws == white_space_pre_line ||
 		ws == white_space_pre_wrap)
 	{
-		if(m_text == _t("\n"))
+		if(m_text == "\n")
 		{
 			return true;
 		}
 	}
 	return false;
 }
+
+bool litehtml::el_space::is_space() const
+{
+    return true;
+}
+
+litehtml::string litehtml::el_space::dump_get_name()
+{
+    return "space: \"" + get_escaped_string(m_text) + "\"";
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/el_space.h b/src/plugins/litehtml_viewer/litehtml/el_space.h
index 35ce88512..46a292ebc 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_space.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_space.h
@@ -9,11 +9,12 @@ namespace litehtml
 	class el_space : public el_text
 	{
 	public:
-		el_space(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_space();
+		el_space(const char* text, const std::shared_ptr<document>& doc);
 
-		virtual bool	is_white_space() const override;
-		virtual bool	is_break() const override;
+		bool is_white_space() const override;
+		bool is_break() const override;
+        bool is_space() const override;
+        string dump_get_name() override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/el_style.cpp b/src/plugins/litehtml_viewer/litehtml/el_style.cpp
index 1b1bb0e0f..cc2f0bab6 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_style.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_style.cpp
@@ -3,25 +3,20 @@
 #include "document.h"
 
 
-litehtml::el_style::el_style(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
-{
-
-}
-
-litehtml::el_style::~el_style()
+litehtml::el_style::el_style(const std::shared_ptr<document>& doc) : element(doc)
 {
 
 }
 
 void litehtml::el_style::parse_attributes()
 {
-	tstring text;
+	string text;
 
 	for(auto& el : m_children)
 	{
 		el->get_text(text);
 	}
-	get_document()->add_stylesheet( text.c_str(), 0, get_attr(_t("media")) );
+	get_document()->add_stylesheet( text.c_str(), nullptr, get_attr("media") );
 }
 
 bool litehtml::el_style::appendChild(const ptr &el)
@@ -30,7 +25,12 @@ bool litehtml::el_style::appendChild(const ptr &el)
 	return true;
 }
 
-const litehtml::tchar_t* litehtml::el_style::get_tagName() const
+litehtml::string_id litehtml::el_style::tag() const
+{
+	return _style_;
+}
+
+const char* litehtml::el_style::get_tagName() const
 {
-	return _t("style");
+	return "style";
 }
diff --git a/src/plugins/litehtml_viewer/litehtml/el_style.h b/src/plugins/litehtml_viewer/litehtml/el_style.h
index 8407b4b91..b6258932d 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_style.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_style.h
@@ -9,12 +9,12 @@ namespace litehtml
 	{
 		elements_vector		m_children;
 	public:
-		el_style(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_style();
+		explicit el_style(const std::shared_ptr<document>& doc);
 
-		virtual void			parse_attributes() override;
-		virtual bool			appendChild(const ptr &el) override;
-		virtual const tchar_t*	get_tagName() const override;
+		void			parse_attributes() override;
+		bool			appendChild(const ptr &el) override;
+		string_id		tag() const override;
+		const char*		get_tagName() const override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/el_table.cpp b/src/plugins/litehtml_viewer/litehtml/el_table.cpp
index 06d77be7d..d0c711c4d 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_table.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_table.cpp
@@ -2,106 +2,70 @@
 #include "el_table.h"
 #include "document.h"
 #include "iterators.h"
-#include <algorithm>
 
 
-litehtml::el_table::el_table(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
+litehtml::el_table::el_table(const std::shared_ptr<document>& doc) : html_tag(doc)
 {
-	m_border_spacing_x	= 0;
-	m_border_spacing_y	= 0;
-	m_border_collapse	= border_collapse_separate;
 }
 
 
-litehtml::el_table::~el_table()
-{
-
-}
-
-bool litehtml::el_table::appendChild(const litehtml::element::ptr& el)
+bool litehtml::el_table::appendChild(const element::ptr& el)
 {
 	if(!el)	return false;
-	if(!t_strcmp(el->get_tagName(), _t("tbody")) || !t_strcmp(el->get_tagName(), _t("thead")) || !t_strcmp(el->get_tagName(), _t("tfoot")))
+	if( el->tag() == _tbody_ ||
+		el->tag() == _thead_ ||
+		el->tag() == _tfoot_ ||
+		el->tag() == _caption_)
 	{
 		return html_tag::appendChild(el);
 	}
 	return false;
 }
 
-void litehtml::el_table::parse_styles(bool is_reparse)
-{
-	html_tag::parse_styles(is_reparse);
-
-	m_border_collapse = (border_collapse) value_index(get_style_property(_t("border-collapse"), true, _t("separate")), border_collapse_strings, border_collapse_separate);
-
-	if(m_border_collapse == border_collapse_separate)
-	{
-		m_css_border_spacing_x.fromString(get_style_property(_t("-litehtml-border-spacing-x"), true, _t("0px")));
-		m_css_border_spacing_y.fromString(get_style_property(_t("-litehtml-border-spacing-y"), true, _t("0px")));
-
-		int fntsz = get_font_size();
-		document::ptr doc = get_document();
-		m_border_spacing_x = doc->cvt_units(m_css_border_spacing_x, fntsz);
-		m_border_spacing_y = doc->cvt_units(m_css_border_spacing_y, fntsz);
-	} else
-	{
-		m_border_spacing_x	= 0;
-		m_border_spacing_y	= 0;
-		m_padding.bottom	= 0;
-		m_padding.top		= 0;
-		m_padding.left		= 0;
-		m_padding.right		= 0;
-		m_css_padding.bottom.set_value(0, css_units_px);
-		m_css_padding.top.set_value(0, css_units_px);
-		m_css_padding.left.set_value(0, css_units_px);
-		m_css_padding.right.set_value(0, css_units_px);
-	}
-}
-
 void litehtml::el_table::parse_attributes()
 {
-	const tchar_t* str = get_attr(_t("width"));
+	const char* str = get_attr("width");
 	if(str)
 	{
-		m_style.add_property(_t("width"), str, 0, false);
+		m_style.add_property(_width_, str);
 	}
 
-	str = get_attr(_t("align"));
+	str = get_attr("align");
 	if(str)
 	{
-		int align = value_index(str, _t("left;center;right"));
+		int align = value_index(str, "left;center;right");
 		switch(align)
 		{
 		case 1:
-			m_style.add_property(_t("margin-left"), _t("auto"), 0, false);
-			m_style.add_property(_t("margin-right"), _t("auto"), 0, false);
+			m_style.add_property(_margin_left_, "auto");
+			m_style.add_property(_margin_right_, "auto");
 			break;
 		case 2:
-			m_style.add_property(_t("margin-left"), _t("auto"), 0, false);
-			m_style.add_property(_t("margin-right"), _t("0"), 0, false);
+			m_style.add_property(_margin_left_, "auto");
+			m_style.add_property(_margin_right_, "0");
 			break;
 		}
 	}
 
-	str = get_attr(_t("cellspacing"));
+	str = get_attr("cellspacing");
 	if(str)
 	{
-		tstring val = str;
-		val += _t(" ");
+		string val = str;
+		val += " ";
 		val += str;
-		m_style.add_property(_t("border-spacing"), val.c_str(), 0, false);
+		m_style.add_property(_border_spacing_, val);
 	}
 	
-	str = get_attr(_t("border"));
+	str = get_attr("border");
 	if(str)
 	{
-		m_style.add_property(_t("border-width"), str, 0, false);
+		m_style.add_property(_border_width_, str);
 	}
 
-	str = get_attr(_t("bgcolor"));
+	str = get_attr("bgcolor");
 	if (str)
 	{
-		m_style.add_property(_t("background-color"), str, 0, false);
+		m_style.add_property(_background_color_, str, "", false, get_document()->container());
 	}
 
 	html_tag::parse_attributes();
diff --git a/src/plugins/litehtml_viewer/litehtml/el_table.h b/src/plugins/litehtml_viewer/litehtml/el_table.h
index f1ef97315..38352503b 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_table.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_table.h
@@ -15,12 +15,10 @@ namespace litehtml
 	class el_table : public html_tag
 	{
 	public:
-		el_table(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_table();
+		explicit el_table(const std::shared_ptr<litehtml::document>& doc);
 
-		virtual bool	appendChild(const litehtml::element::ptr& el) override;
-		virtual void	parse_styles(bool is_reparse = false) override;
-		virtual void	parse_attributes() override;
+		bool appendChild(const litehtml::element::ptr& el) override;
+		void parse_attributes() override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/el_td.cpp b/src/plugins/litehtml_viewer/litehtml/el_td.cpp
index ca214402d..679d9212a 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_td.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_td.cpp
@@ -2,48 +2,42 @@
 #include "el_td.h"
 
 
-litehtml::el_td::el_td(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
-{
-
-}
-
-litehtml::el_td::~el_td()
+litehtml::el_td::el_td(const std::shared_ptr<document>& doc) : html_tag(doc)
 {
 
 }
 
 void litehtml::el_td::parse_attributes()
 {
-	const tchar_t* str = get_attr(_t("width"));
+	const char* str = get_attr("width");
 	if(str)
 	{
-		m_style.add_property(_t("width"), str, 0, false);
+		m_style.add_property(_width_, str);
 	}
-	str = get_attr(_t("background"));
+	str = get_attr("background");
 	if(str)
 	{
-		tstring url = _t("url('");
+		string url = "url('";
 		url += str;
-		url += _t("')");
-		m_style.add_property(_t("background-image"), url.c_str(), 0, false);
+		url += "')";
+		m_style.add_property(_background_image_, url);
 	}
-	str = get_attr(_t("align"));
+	str = get_attr("align");
 	if(str)
 	{
-		m_style.add_property(_t("text-align"), str, 0, false);
+		m_style.add_property(_text_align_, str);
 	}
 
-	str = get_attr(_t("bgcolor"));
+	str = get_attr("bgcolor");
 	if (str)
 	{
-		m_style.add_property(_t("background-color"), str, 0, false);
+		m_style.add_property(_background_color_, str, "", false, get_document()->container());
 	}
 
-	str = get_attr(_t("valign"));
+	str = get_attr("valign");
 	if(str)
 	{
-		m_style.add_property(_t("vertical-align"), str, 0, false);
+		m_style.add_property(_vertical_align_, str);
 	}
 	html_tag::parse_attributes();
 }
-
diff --git a/src/plugins/litehtml_viewer/litehtml/el_td.h b/src/plugins/litehtml_viewer/litehtml/el_td.h
index 5dce950a4..03d21c1c7 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_td.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_td.h
@@ -8,10 +8,9 @@ namespace litehtml
 	class el_td : public html_tag
 	{
 	public:
-		el_td(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_td();
+		explicit el_td(const std::shared_ptr<litehtml::document>& doc);
 
-		virtual void parse_attributes() override;
+		void parse_attributes() override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/el_text.cpp b/src/plugins/litehtml_viewer/litehtml/el_text.cpp
index 9fad2a45a..a22224a35 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_text.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_text.cpp
@@ -1,21 +1,16 @@
 #include "html.h"
 #include "el_text.h"
-#include "document.h"
+#include "render_item.h"
 
-litehtml::el_text::el_text(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc) : element(doc)
+litehtml::el_text::el_text(const char* text, const document::ptr& doc) : element(doc)
 {
 	if(text)
 	{
 		m_text = text;
 	}
-	m_text_transform	= text_transform_none;
 	m_use_transformed	= false;
 	m_draw_spaces		= true;
-}
-
-litehtml::el_text::~el_text()
-{
-
+    css_w().set_display(display_inline_text);
 }
 
 void litehtml::el_text::get_content_size( size& sz, int max_width )
@@ -23,60 +18,77 @@ void litehtml::el_text::get_content_size( size& sz, int max_width )
 	sz = m_size;
 }
 
-void litehtml::el_text::get_text( tstring& text )
+void litehtml::el_text::get_text( string& text )
 {
 	text += m_text;
 }
 
-const litehtml::tchar_t* litehtml::el_text::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )
-{
-	if(inherited)
-	{
-		element::ptr el_parent = parent();
-		if (el_parent)
-		{
-			return el_parent->get_style_property(name, inherited, def);
-		}
-	}
-	return def;
-}
-
-void litehtml::el_text::parse_styles(bool is_reparse)
+void litehtml::el_text::compute_styles(bool recursive)
 {
-	m_text_transform	= (text_transform)	value_index(get_style_property(_t("text-transform"), true,	_t("none")),	text_transform_strings,	text_transform_none);
-	if(m_text_transform != text_transform_none)
+    element::ptr el_parent = parent();
+    if (el_parent)
+    {
+        css_w().set_line_height(el_parent->css().get_line_height());
+        css_w().set_font(el_parent->css().get_font());
+        css_w().set_font_metrics(el_parent->css().get_font_metrics());
+        css_w().set_white_space(el_parent->css().get_white_space());
+		css_w().set_text_transform(el_parent->css().get_text_transform());
+    }
+    css_w().set_display(display_inline_text);
+    css_w().set_float(float_none);
+
+	if(m_css.get_text_transform() != text_transform_none)
 	{
 		m_transformed_text	= m_text;
 		m_use_transformed = true;
-		get_document()->container()->transform_text(m_transformed_text, m_text_transform);
+		get_document()->container()->transform_text(m_transformed_text, m_css.get_text_transform());
+	} else
+	{
+		m_use_transformed = false;
 	}
 
+    element::ptr p = parent();
+    while(p && p->css().get_display() == display_inline)
+    {
+        if(p->css().get_position() == element_position_relative)
+        {
+            css_w().set_offsets(p->css().get_offsets());
+            css_w().set_position(element_position_relative);
+            break;
+        }
+        p = p->parent();
+    }
+    if(p)
+    {
+        css_w().set_position(element_position_static);
+    }
+
 	if(is_white_space())
 	{
-		m_transformed_text = _t(" ");
+		m_transformed_text = " ";
 		m_use_transformed = true;
 	} else
 	{
-		if(m_text == _t("\t"))
+		if(m_text == "\t")
 		{
-			m_transformed_text = _t("    ");
+			m_transformed_text = "    ";
 			m_use_transformed = true;
 		}
-		if(m_text == _t("\n") || m_text == _t("\r"))
+		if(m_text == "\n" || m_text == "\r")
 		{
-			m_transformed_text = _t("");
+			m_transformed_text = "";
 			m_use_transformed = true;
 		}
 	}
 
 	font_metrics fm;
 	uint_ptr font = 0;
-	element::ptr el_parent = parent();
 	if (el_parent)
 	{
-		font = el_parent->get_font(&fm);
+		font = el_parent->css().get_font();
+        fm = el_parent->css().get_font_metrics();
 	}
-	if(is_break())
+	if(is_break() || !font)
 	{
 		m_size.height	= 0;
 		m_size.width	= 0;
@@ -88,24 +100,14 @@ void litehtml::el_text::parse_styles(bool is_reparse)
 	m_draw_spaces = fm.draw_spaces;
 }
 
-int litehtml::el_text::get_base_line()
-{
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		return el_parent->get_base_line();
-	}
-	return 0;
-}
-
-void litehtml::el_text::draw( uint_ptr hdc, int x, int y, const position* clip )
+void litehtml::el_text::draw(uint_ptr hdc, int x, int y, const position *clip, const std::shared_ptr<render_item> &ri)
 {
 	if(is_white_space() && !m_draw_spaces)
 	{
 		return;
 	}
 
-	position pos = m_pos;
+	position pos = ri->pos();
 	pos.x	+= x;
 	pos.y	+= y;
 
@@ -116,73 +118,23 @@ void litehtml::el_text::draw( uint_ptr hdc, int x, int y, const position* clip )
 		{
 			document::ptr doc = get_document();
 
-			uint_ptr font = el_parent->get_font();
-			litehtml::web_color color = el_parent->get_color(_t("color"), true, doc->get_def_color());
-			doc->container()->draw_text(hdc, m_use_transformed ? m_transformed_text.c_str() : m_text.c_str(), font, color, pos);
+			uint_ptr font = el_parent->css().get_font();
+			if(font)
+			{
+				web_color color = el_parent->css().get_color();
+				doc->container()->draw_text(hdc, m_use_transformed ? m_transformed_text.c_str() : m_text.c_str(), font,
+											color, pos);
+			}
 		}
 	}
 }
 
-int litehtml::el_text::line_height() const
-{
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		return el_parent->line_height();
-	}
-	return 0;
-}
-
-litehtml::uint_ptr litehtml::el_text::get_font( font_metrics* fm /*= 0*/ )
-{
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		return el_parent->get_font(fm);
-	}
-	return 0;
-}
-
-litehtml::style_display litehtml::el_text::get_display() const
-{
-	return display_inline_text;
-}
-
-litehtml::white_space litehtml::el_text::get_white_space() const
+litehtml::string litehtml::el_text::dump_get_name()
 {
-	element::ptr el_parent = parent();
-	if (el_parent) return el_parent->get_white_space();
-	return white_space_normal;
+    return "text: \"" + get_escaped_string(m_text) + "\"";
 }
 
-litehtml::element_position litehtml::el_text::get_element_position(css_offsets* offsets) const
+std::vector<std::tuple<litehtml::string, litehtml::string>> litehtml::el_text::dump_get_attrs()
 {
-	element::ptr p = parent();
-	while(p && p->get_display() == display_inline)
-	{
-		if(p->get_element_position() == element_position_relative)
-		{
-			if(offsets)
-			{
-				*offsets = p->get_css_offsets();
-			}
-			return element_position_relative;
-		}
-		p = p->parent();
-	}
-	return element_position_static;
-}
-
-litehtml::css_offsets litehtml::el_text::get_css_offsets() const
-{
-	element::ptr p = parent();
-	while(p && p->get_display() == display_inline)
-	{
-		if(p->get_element_position() == element_position_relative)
-		{
-			return p->get_css_offsets();
-		}
-		p = p->parent();
-	}
-	return css_offsets();
+    return std::vector<std::tuple<string, string>>();
 }
diff --git a/src/plugins/litehtml_viewer/litehtml/el_text.h b/src/plugins/litehtml_viewer/litehtml/el_text.h
index d2149deb2..4b8a442f3 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_text.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_text.h
@@ -8,30 +8,23 @@ namespace litehtml
 	class el_text : public element
 	{
 	protected:
-		tstring			m_text;
-		tstring			m_transformed_text;
+		string			m_text;
+		string			m_transformed_text;
 		size			m_size;
-		text_transform	m_text_transform;
 		bool			m_use_transformed;
 		bool			m_draw_spaces;
 	public:
-		el_text(const tchar_t* text, const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_text();
+		el_text(const char* text, const document::ptr& doc);
 
-		virtual void				get_text(tstring& text) override;
-		virtual const tchar_t*		get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0) override;
-		virtual void				parse_styles(bool is_reparse) override;
-		virtual int					get_base_line() override;
-		virtual void				draw(uint_ptr hdc, int x, int y, const position* clip) override;
-		virtual int					line_height() const override;
-		virtual uint_ptr			get_font(font_metrics* fm = 0) override;
-		virtual style_display		get_display() const override;
-		virtual white_space			get_white_space() const override;
-		virtual element_position	get_element_position(css_offsets* offsets = 0) const override;
-		virtual css_offsets			get_css_offsets() const override;
+		void				get_text(string& text) override;
+		void				compute_styles(bool recursive) override;
+        bool				is_text() const override { return true; }
 
+        void draw(uint_ptr hdc, int x, int y, const position *clip, const std::shared_ptr<render_item> &ri) override;
+        string             dump_get_name() override;
+        std::vector<std::tuple<string, string>> dump_get_attrs() override;
 	protected:
-		virtual void				get_content_size(size& sz, int max_width) override;
+		void				get_content_size(size& sz, int max_width) override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/el_title.cpp b/src/plugins/litehtml_viewer/litehtml/el_title.cpp
index 7a9590d18..f0e42311b 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_title.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_title.cpp
@@ -2,19 +2,15 @@
 #include "el_title.h"
 #include "document.h"
 
-litehtml::el_title::el_title(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc)
-{
-
-}
-
-litehtml::el_title::~el_title()
+litehtml::el_title::el_title(const std::shared_ptr<document>& doc) : html_tag(doc)
 {
 
 }
 
 void litehtml::el_title::parse_attributes()
 {
-	tstring text;
+	string text;
 	get_text(text);
 	get_document()->container()->set_caption(text.c_str());
 }
+
diff --git a/src/plugins/litehtml_viewer/litehtml/el_title.h b/src/plugins/litehtml_viewer/litehtml/el_title.h
index 20dc8cdd6..201186a4a 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_title.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_title.h
@@ -8,11 +8,10 @@ namespace litehtml
 	class el_title : public html_tag
 	{
 	public:
-		el_title(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_title();
+		explicit el_title(const std::shared_ptr<litehtml::document>& doc);
 
 	protected:
-		virtual void	parse_attributes() override;
+		void parse_attributes() override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/el_tr.cpp b/src/plugins/litehtml_viewer/litehtml/el_tr.cpp
index 0ef0675b5..f10997654 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_tr.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_tr.cpp
@@ -2,50 +2,27 @@
 #include "el_tr.h"
 
 
-litehtml::el_tr::el_tr(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc)
-{
-
-}
-
-litehtml::el_tr::~el_tr()
+litehtml::el_tr::el_tr(const std::shared_ptr<document>& doc) : html_tag(doc)
 {
 
 }
 
 void litehtml::el_tr::parse_attributes()
 {
-	const tchar_t* str = get_attr(_t("align"));
+	const char* str = get_attr("align");
 	if(str)
 	{
-		m_style.add_property(_t("text-align"), str, 0, false);
+		m_style.add_property(_text_align_, str);
 	}
-	str = get_attr(_t("valign"));
+	str = get_attr("valign");
 	if(str)
 	{
-		m_style.add_property(_t("vertical-align"), str, 0, false);
+		m_style.add_property(_vertical_align_, str);
 	}
-	str = get_attr(_t("bgcolor"));
+	str = get_attr("bgcolor");
 	if (str)
 	{
-		m_style.add_property(_t("background-color"), str, 0, false);
+		m_style.add_property(_background_color_, str, "", false, get_document()->container());
 	}
 	html_tag::parse_attributes();
 }
-
-void litehtml::el_tr::get_inline_boxes( position::vector& boxes )
-{
-	position pos;
-	for(auto& el : m_children)
-	{
-		if(el->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/el_tr.h b/src/plugins/litehtml_viewer/litehtml/el_tr.h
index 0fbb6c28d..49c0b9a9b 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_tr.h
+++ b/src/plugins/litehtml_viewer/litehtml/el_tr.h
@@ -8,11 +8,9 @@ namespace litehtml
 	class el_tr : public html_tag
 	{
 	public:
-		el_tr(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~el_tr();
+		explicit el_tr(const std::shared_ptr<litehtml::document>& doc);
 
-		virtual void	parse_attributes() override;
-		virtual void	get_inline_boxes(position::vector& boxes) override;
+		void parse_attributes() override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/element.cpp b/src/plugins/litehtml_viewer/litehtml/element.cpp
index 67a500236..2438b1325 100644
--- a/src/plugins/litehtml_viewer/litehtml/element.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/element.cpp
@@ -1,410 +1,330 @@
 #include "html.h"
 #include "element.h"
 #include "document.h"
+#include "render_item.h"
+#include "el_before_after.h"
+
+namespace litehtml
+{
 
 #define LITEHTML_EMPTY_FUNC			{}
 #define LITEHTML_RETURN_FUNC(ret)	{return ret;}
 
-litehtml::element::element(const std::shared_ptr<litehtml::document>& doc) : m_doc(doc)
+element::element(const document::ptr& doc) : m_doc(doc)
 {
-	m_box		= 0;
-	m_skip		= false;
 }
 
-litehtml::element::~element()
+position element::get_placement() const
 {
-
-}
-
-
-bool litehtml::element::is_point_inside( int x, int y )
-{
-	if(get_display() != display_inline && get_display() != display_table_row)
+	position pos;
+	bool is_first = true;
+	for(const auto& ri_el : m_renders)
 	{
-		position pos = m_pos;
-		pos += m_padding;
-		pos += m_borders;
-		if(pos.is_point_inside(x, y))
-		{
-			return true;
-		} else
+		auto ri = ri_el.lock();
+		if(ri)
 		{
-			return false;
-		}
-	} else
-	{
-		position::vector boxes;
-		get_inline_boxes(boxes);
-		for(position::vector::iterator box = boxes.begin(); box != boxes.end(); box++)
-		{
-			if(box->is_point_inside(x, y))
+			position ri_pos = ri_el.lock()->get_placement();
+			if(is_first)
 			{
-				return true;
+				is_first = false;
+				pos = ri_pos;
+			} else
+			{
+				if(pos.x < ri_pos.x)
+				{
+					pos.x = ri_pos.x;
+				}
+				if(pos.y < ri_pos.y)
+				{
+					pos.y = ri_pos.y;
+				}
 			}
 		}
 	}
-	return false;
+	return pos;
 }
 
-litehtml::web_color litehtml::element::get_color( const tchar_t* prop_name, bool inherited, const litehtml::web_color& def_color )
+bool element::is_inline_box() const
 {
-	const tchar_t* clrstr = get_style_property(prop_name, inherited, 0);
-	if(!clrstr)
+	if(	css().get_display() == display_inline ||
+		   css().get_display() == display_inline_table ||
+		   css().get_display() == display_inline_block ||
+		   css().get_display() == display_inline_text ||
+		   css().get_display() == display_inline_flex)
 	{
-		return def_color;
+		return true;
 	}
-	return web_color::from_string(clrstr, get_document()->container());
+	return false;
 }
 
-litehtml::position litehtml::element::get_placement() const
+bool element::is_ancestor(const ptr &el) const
 {
-	litehtml::position pos = m_pos;
-	element::ptr cur_el = parent();
-	while(cur_el)
+	element::ptr el_parent = parent();
+	while(el_parent && el_parent != el)
 	{
-		pos.x += cur_el->m_pos.x;
-		pos.y += cur_el->m_pos.y;
-		cur_el = cur_el->parent();
+		el_parent = el_parent->parent();
 	}
-	return pos;
-}
-
-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)
+	if(el_parent)
 	{
 		return true;
 	}
 	return false;
 }
 
-bool litehtml::element::collapse_top_margin() const
+bool element::is_table_skip() const
 {
-	if(!m_borders.top && !m_padding.top && in_normal_flow() && get_float() == float_none && m_margins.top >= 0 && have_parent())
-	{
-		return true;
-	}
-	return false;
+	return is_space() || is_comment() || css().get_display() == display_none;
 }
 
-bool litehtml::element::collapse_bottom_margin() const
+string element::dump_get_name()
 {
-	if(!m_borders.bottom && !m_padding.bottom && in_normal_flow() && get_float() == float_none && m_margins.bottom >= 0 && have_parent())
-	{
-		return true;
-	}
-	return false;
+	return "element";
 }
 
-bool litehtml::element::get_predefined_height(int& p_height) const
+std::vector<std::tuple<string, string>> element::dump_get_attrs()
 {
-	css_length h = get_css_height();
-	if(h.is_predefined())
-	{
-		p_height = m_pos.height;
-		return false;
-	}
-	if(h.units() == css_units_percentage)
-	{
-		element::ptr el_parent = parent();
-		if (!el_parent)
-		{
-			position client_pos;
-			get_document()->container()->get_client_rect(client_pos);
-			p_height = h.calc_percent(client_pos.height);
-			return true;
-		} else
-		{
-			int ph = 0;
-			if (el_parent->get_predefined_height(ph))
-			{
-				p_height = h.calc_percent(ph);
-				if (is_body())
-				{
-					p_height -= content_margins_height();
-				}
-				return true;
-			} else
-			{
-				p_height = m_pos.height;
-				return false;
-			}
-		}
-	}
-	p_height = get_document()->cvt_units(h, get_font_size());
-	return true;
+	return m_css.dump_get_attrs();
 }
 
-void litehtml::element::calc_document_size( litehtml::size& sz, int x /*= 0*/, int y /*= 0*/ )
+void element::dump(dumper& cout)
 {
-	if(is_visible())
+	cout.begin_node(dump_get_name());
+
+	auto attrs = dump_get_attrs();
+	if(!attrs.empty())
 	{
-		sz.width	= std::max(sz.width,	x + right());
-		sz.height	= std::max(sz.height,	y + bottom());
+		cout.begin_attrs_group("attributes");
+		for (const auto &attr: attrs)
+		{
+			cout.add_attr(std::get<0>(attr), std::get<1>(attr));
+		}
+		cout.end_attrs_group();
 	}
-}
 
-void litehtml::element::get_redraw_box(litehtml::position& pos, int x /*= 0*/, int y /*= 0*/)
-{
-	if(is_visible())
+	if(!m_children.empty())
 	{
-		int p_left		= std::min(pos.left(),	x + m_pos.left() - m_padding.left - m_borders.left);
-		int p_right		= std::max(pos.right(), x + m_pos.right() + m_padding.left + m_borders.left);
-		int p_top		= std::min(pos.top(), y + m_pos.top() - m_padding.top - m_borders.top);
-		int p_bottom	= std::max(pos.bottom(), y + m_pos.bottom() + m_padding.bottom + m_borders.bottom);
-
-		pos.x = p_left;
-		pos.y = p_top;
-		pos.width	= p_right - p_left;
-		pos.height	= p_bottom - p_top;
+		cout.begin_attrs_group("children");
+		for (const auto &el: m_children)
+		{
+			el->dump(cout);
+		}
+		cout.end_attrs_group();
 	}
+
+	cout.end_node();
 }
 
-int litehtml::element::calc_width(int defVal) const
+std::shared_ptr<render_item> element::create_render_item(const std::shared_ptr<render_item>& parent_ri)
 {
-	css_length w = get_css_width();
-	if(w.is_predefined())
+	std::shared_ptr<render_item> ret;
+
+	if(css().get_display() == display_table_column ||
+	   css().get_display() == display_table_column_group ||
+	   css().get_display() == display_table_footer_group ||
+	   css().get_display() == display_table_header_group ||
+	   css().get_display() == display_table_row_group)
+	{
+		ret = std::make_shared<render_item_table_part>(shared_from_this());
+	} else if(css().get_display() == display_table_row)
 	{
-		return defVal;
+		ret = std::make_shared<render_item_table_row>(shared_from_this());
+	} else if(css().get_display() == display_block ||
+				css().get_display() == display_table_cell ||
+				css().get_display() == display_table_caption ||
+				css().get_display() == display_list_item ||
+				css().get_display() == display_inline_block)
+	{
+		ret = std::make_shared<render_item_block>(shared_from_this());
+	} else if(css().get_display() == display_table || css().get_display() == display_inline_table)
+	{
+		ret = std::make_shared<render_item_table>(shared_from_this());
+	} else if(css().get_display() == display_inline || css().get_display() == display_inline_text)
+	{
+		ret = std::make_shared<render_item_inline>(shared_from_this());
+	} else if(css().get_display() == display_flex || css().get_display() == display_inline_flex)
+	{
+		ret = std::make_shared<render_item_flex>(shared_from_this());
 	}
-	if(w.units() == css_units_percentage)
+	if(ret)
 	{
-		element::ptr el_parent = parent();
-		if (!el_parent)
+		if (css().get_display() == display_table ||
+			css().get_display() == display_inline_table ||
+			css().get_display() == display_table_caption ||
+			css().get_display() == display_table_cell ||
+			css().get_display() == display_table_column ||
+			css().get_display() == display_table_column_group ||
+			css().get_display() == display_table_footer_group ||
+			css().get_display() == display_table_header_group ||
+			css().get_display() == display_table_row ||
+			css().get_display() == display_table_row_group)
 		{
-			position client_pos;
-			get_document()->container()->get_client_rect(client_pos);
-			return w.calc_percent(client_pos.width);
-		} else
+			get_document()->add_tabular(ret);
+		}
+
+		ret->parent(parent_ri);
+		for(const auto& el : m_children)
 		{
-			int pw = el_parent->calc_width(defVal);
-			if (is_body())
+			auto ri = el->create_render_item(ret);
+			if(ri)
 			{
-				pw -= content_margins_width();
+				ret->add_child(ri);
 			}
-			return w.calc_percent(pw);
 		}
 	}
-	return 	get_document()->cvt_units(w, get_font_size());
-}
-
-bool litehtml::element::is_ancestor(const ptr &el) const
-{
-	element::ptr el_parent = parent();
-	while(el_parent && el_parent != el)
-	{
-		el_parent = el_parent->parent();
-	}
-	if(el_parent)
-	{
-		return true;
-	}
-	return false;
+	return ret;
 }
 
-int litehtml::element::get_inline_shift_left()
+bool element::requires_styles_update()
 {
-	int ret = 0;
-	element::ptr el_parent = parent();
-	if (el_parent)
+	for (const auto& used_style : m_used_styles)
 	{
-		if (el_parent->get_display() == display_inline)
+		if(used_style->m_selector->is_media_valid())
 		{
-			style_display disp = get_display();
-
-			if (disp == display_inline_text || disp == display_inline_block)
+			int res = select(*(used_style->m_selector), true);
+			if( (res == select_no_match && used_style->m_used) || (res == select_match && !used_style->m_used) )
 			{
-				element::ptr el = shared_from_this();
-				while (el_parent && el_parent->get_display() == display_inline)
-				{
-					if (el_parent->is_first_child_inline(el))
-					{
-						ret += el_parent->padding_left() + el_parent->border_left() + el_parent->margin_left();
-					}
-					el = el_parent;
-					el_parent = el_parent->parent();
-				}
+				return true;
 			}
 		}
 	}
+	return false;
+}
 
-	return ret;
+void element::add_render(const std::shared_ptr<render_item>& ri)
+{
+	m_renders.push_back(ri);
 }
 
-int litehtml::element::get_inline_shift_right()
+bool element::find_styles_changes( position::vector& redraw_boxes)
 {
-	int ret = 0;
-	element::ptr el_parent = parent();
-	if (el_parent)
+	if(css().get_display() == display_inline_text)
 	{
-		if (el_parent->get_display() == display_inline)
-		{
-			style_display disp = get_display();
+		return false;
+	}
+
+	bool ret = false;
 
-			if (disp == display_inline_text || disp == display_inline_block)
+	if(requires_styles_update())
+	{
+		auto fetch_boxes = [&](const std::shared_ptr<element>& el)
 			{
-				element::ptr el = shared_from_this();
-				while (el_parent && el_parent->get_display() == display_inline)
+				for(const auto& weak_ri : el->m_renders)
 				{
-					if (el_parent->is_last_child_inline(el))
+					auto ri = weak_ri.lock();
+					if(ri)
 					{
-						ret += el_parent->padding_right() + el_parent->border_right() + el_parent->margin_right();
+						position::vector boxes;
+						ri->get_rendering_boxes(boxes);
+						for (auto &box: boxes)
+						{
+							redraw_boxes.push_back(box);
+						}
 					}
-					el = el_parent;
-					el_parent = el_parent->parent();
 				}
-			}
+			};
+		fetch_boxes(shared_from_this());
+		for (auto& el : m_children)
+		{
+			fetch_boxes(el);
 		}
-	}
 
+		refresh_styles();
+		compute_styles();
+		ret = true;
+	}
+	for (auto& el : m_children)
+	{
+		if(el->find_styles_changes(redraw_boxes))
+		{
+			ret = true;
+		}
+	}
 	return ret;
 }
 
-void litehtml::element::apply_relative_shift(int parent_width)
+element::ptr element::_add_before_after(int type, const style& style)
 {
-	css_offsets offsets;
-	if (get_element_position(&offsets) == element_position_relative)
+	if(style.get_property(_content_).m_type != prop_type_invalid)
 	{
-		element::ptr parent_ptr = parent();
-		if (!offsets.left.is_predefined())
+		element::ptr el;
+		if(type == 0)
 		{
-			m_pos.x += offsets.left.calc_percent(parent_width);
-		}
-		else if (!offsets.right.is_predefined())
+			el = std::make_shared<el_before>(get_document());
+			m_children.insert(m_children.begin(), el);
+		} else
 		{
-			m_pos.x -= offsets.right.calc_percent(parent_width);
+			el = std::make_shared<el_after>(get_document());
+			m_children.insert(m_children.end(), el);
 		}
-		if (!offsets.top.is_predefined())
-		{
-			int h = 0;
-
-			if (offsets.top.units() == css_units_percentage)
-			{
-				element::ptr el_parent = parent();
-				if (el_parent)
-				{
-					el_parent->get_predefined_height(h);
-				}
-			}
+		el->parent(shared_from_this());
+		return el;
+	}
+	return nullptr;
+}
 
-			m_pos.y += offsets.top.calc_percent(h);
-		}
-		else if (!offsets.bottom.is_predefined())
-		{
-			int h = 0;
 
-			if (offsets.top.units() == css_units_percentage)
-			{
-				element::ptr el_parent = parent();
-				if (el_parent)
-				{
-					el_parent->get_predefined_height(h);
-				}
-			}
+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())
+element::ptr element::select_one( const css_selector& selector )				LITEHTML_RETURN_FUNC(nullptr)
+element::ptr element::select_one( const string& selector )						LITEHTML_RETURN_FUNC(nullptr)
+element::ptr element::find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/) LITEHTML_RETURN_FUNC(nullptr)
+element::ptr element::find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/) LITEHTML_RETURN_FUNC(nullptr)
+bool element::is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const		LITEHTML_RETURN_FUNC(false)
+bool element::is_nth_child(const element::ptr&, int num, int off, bool of_type) const		LITEHTML_RETURN_FUNC(false)
+bool element::is_only_child(const element::ptr& el, bool of_type)	 const	LITEHTML_RETURN_FUNC(false)
+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)
+void element::clearRecursive()										LITEHTML_EMPTY_FUNC
+string_id element::id() const										LITEHTML_RETURN_FUNC(empty_id)
+string_id element::tag() const										LITEHTML_RETURN_FUNC(empty_id)
+const char* element::get_tagName() const							LITEHTML_RETURN_FUNC("")
+void element::set_tagName( const char* tag )						LITEHTML_EMPTY_FUNC
+void element::set_data( const char* data )							LITEHTML_EMPTY_FUNC
+void element::set_attr( const char* name, const char* val )			LITEHTML_EMPTY_FUNC
+void element::apply_stylesheet( const litehtml::css& stylesheet )	LITEHTML_EMPTY_FUNC
+void element::refresh_styles()										LITEHTML_EMPTY_FUNC
+void element::on_click()											LITEHTML_EMPTY_FUNC
+void element::compute_styles( bool recursive )						LITEHTML_EMPTY_FUNC
+const char* element::get_attr( const char* name, const char* def /*= 0*/ ) const LITEHTML_RETURN_FUNC(def)
+bool element::is_white_space() const								LITEHTML_RETURN_FUNC(false)
+bool element::is_space() const										LITEHTML_RETURN_FUNC(false)
+bool element::is_comment() const									LITEHTML_RETURN_FUNC(false)
+bool element::is_body() const										LITEHTML_RETURN_FUNC(false)
+bool element::is_break() const										LITEHTML_RETURN_FUNC(false)
+bool element::is_text() const										LITEHTML_RETURN_FUNC(false)
 
-			m_pos.y -= offsets.bottom.calc_percent(h);
-		}
-	}
-}
+bool element::on_mouse_over()										LITEHTML_RETURN_FUNC(false)
+bool element::on_mouse_leave()										LITEHTML_RETURN_FUNC(false)
+bool element::on_lbutton_down()										LITEHTML_RETURN_FUNC(false)
+bool element::on_lbutton_up()										LITEHTML_RETURN_FUNC(false)
+bool element::set_pseudo_class( string_id cls, bool add )			LITEHTML_RETURN_FUNC(false)
+bool element::set_class( const char* pclass, bool add )				LITEHTML_RETURN_FUNC(false)
+bool element::is_replaced() const									LITEHTML_RETURN_FUNC(false)
+void element::draw(uint_ptr hdc, int x, int y, const position *clip, const std::shared_ptr<render_item> &ri) LITEHTML_EMPTY_FUNC
+void element::draw_background(uint_ptr hdc, int x, int y, const position *clip, const std::shared_ptr<render_item> &ri) LITEHTML_EMPTY_FUNC
+int				element::get_enum_property			(string_id name, bool inherited, int defval, uint_ptr css_properties_member_offset) const LITEHTML_RETURN_FUNC(0)
+css_length		element::get_length_property		(string_id name, bool inherited, css_length defval, uint_ptr css_properties_member_offset) const LITEHTML_RETURN_FUNC(0)
+web_color		element::get_color_property			(string_id name, bool inherited, web_color defval, uint_ptr css_properties_member_offset) const LITEHTML_RETURN_FUNC(web_color())
+string			element::get_string_property		(string_id name, bool inherited, const string& defval, uint_ptr css_properties_member_offset) const LITEHTML_RETURN_FUNC("")
+float			element::get_number_property		(string_id name, bool inherited, float defval, uint_ptr css_properties_member_offset) const LITEHTML_RETURN_FUNC(0)
+string_vector	element::get_string_vector_property	(string_id name, bool inherited, const string_vector& default_value, uint_ptr css_properties_member_offset) const LITEHTML_RETURN_FUNC({})
+int_vector		element::get_int_vector_property	(string_id name, bool inherited, const int_vector& default_value, uint_ptr css_properties_member_offset) const LITEHTML_RETURN_FUNC({})
+length_vector	element::get_length_vector_property	(string_id name, bool inherited, const length_vector& default_value, uint_ptr css_properties_member_offset) const LITEHTML_RETURN_FUNC({})
+size_vector		element::get_size_vector_property	(string_id name, bool inherited, const size_vector& default_value, uint_ptr css_properties_member_offset) const LITEHTML_RETURN_FUNC({})
+string			element::get_custom_property		(string_id name, const string& defval) const LITEHTML_RETURN_FUNC("")
+void element::get_text( string& text )									LITEHTML_EMPTY_FUNC
+void element::parse_attributes()										LITEHTML_EMPTY_FUNC
+int element::select(const string& selector)								LITEHTML_RETURN_FUNC(select_no_match)
+int element::select(const css_selector& selector, bool apply_pseudo)	LITEHTML_RETURN_FUNC(select_no_match)
+int element::select( const css_element_selector& selector, bool apply_pseudo /*= true*/ )	LITEHTML_RETURN_FUNC(select_no_match)
+element::ptr element::find_ancestor(const css_selector& selector, bool apply_pseudo, bool* is_pseudo)	LITEHTML_RETURN_FUNC(nullptr)
 
-void litehtml::element::calc_auto_margins(int parent_width)							LITEHTML_EMPTY_FUNC
-const litehtml::background* litehtml::element::get_background(bool own_only)		LITEHTML_RETURN_FUNC(0)
-litehtml::element::ptr litehtml::element::get_element_by_point(int x, int y, int client_x, int client_y)	LITEHTML_RETURN_FUNC(0)
-litehtml::element::ptr litehtml::element::get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex) LITEHTML_RETURN_FUNC(0)
-void litehtml::element::get_line_left_right( int y, int def_right, int& ln_left, int& ln_right ) LITEHTML_EMPTY_FUNC
-void litehtml::element::add_style( const litehtml::style& st )						LITEHTML_EMPTY_FUNC
-void litehtml::element::select_all(const css_selector& selector, litehtml::elements_vector& res)	LITEHTML_EMPTY_FUNC
-litehtml::elements_vector litehtml::element::select_all(const litehtml::css_selector& selector)	 LITEHTML_RETURN_FUNC(litehtml::elements_vector())
-litehtml::elements_vector litehtml::element::select_all(const litehtml::tstring& selector)			 LITEHTML_RETURN_FUNC(litehtml::elements_vector())
-litehtml::element::ptr litehtml::element::select_one( const css_selector& selector ) LITEHTML_RETURN_FUNC(0)
-litehtml::element::ptr litehtml::element::select_one( const tstring& selector )		LITEHTML_RETURN_FUNC(0)
-litehtml::element::ptr litehtml::element::find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/) LITEHTML_RETURN_FUNC(0)
-litehtml::element::ptr litehtml::element::find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/) LITEHTML_RETURN_FUNC(0)
-bool litehtml::element::is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const		LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::is_nth_child(const element::ptr&, int num, int off, bool of_type) const		LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::is_only_child(const element::ptr& el, bool of_type)	 const	LITEHTML_RETURN_FUNC(false)
-litehtml::overflow litehtml::element::get_overflow() const							LITEHTML_RETURN_FUNC(overflow_visible)
-void litehtml::element::draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex ) LITEHTML_EMPTY_FUNC
-void litehtml::element::draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned ) LITEHTML_EMPTY_FUNC
-void litehtml::element::render_positioned(render_type rt)							LITEHTML_EMPTY_FUNC
-int litehtml::element::get_zindex() const											LITEHTML_RETURN_FUNC(0)
-bool litehtml::element::fetch_positioned()											LITEHTML_RETURN_FUNC(false)
-litehtml::visibility litehtml::element::get_visibility() const						LITEHTML_RETURN_FUNC(visibility_visible)
-void litehtml::element::apply_vertical_align()										LITEHTML_EMPTY_FUNC
-void litehtml::element::set_css_width( css_length& w )								LITEHTML_EMPTY_FUNC
-litehtml::element::ptr litehtml::element::get_child( int idx ) const				LITEHTML_RETURN_FUNC(0)
-size_t litehtml::element::get_children_count() const								LITEHTML_RETURN_FUNC(0)
-void litehtml::element::calc_outlines( int parent_width )							LITEHTML_EMPTY_FUNC
-litehtml::css_length litehtml::element::get_css_width() const						LITEHTML_RETURN_FUNC(css_length())
-litehtml::css_length litehtml::element::get_css_height() const						LITEHTML_RETURN_FUNC(css_length())
-litehtml::element_clear litehtml::element::get_clear() const						LITEHTML_RETURN_FUNC(clear_none)
-litehtml::css_length litehtml::element::get_css_left() const						LITEHTML_RETURN_FUNC(css_length())
-litehtml::css_length litehtml::element::get_css_right() const						LITEHTML_RETURN_FUNC(css_length())
-litehtml::css_length litehtml::element::get_css_top() const							LITEHTML_RETURN_FUNC(css_length())
-litehtml::css_length litehtml::element::get_css_bottom() const						LITEHTML_RETURN_FUNC(css_length())
-litehtml::css_offsets litehtml::element::get_css_offsets() const					LITEHTML_RETURN_FUNC(css_offsets())
-litehtml::vertical_align litehtml::element::get_vertical_align() const				LITEHTML_RETURN_FUNC(va_baseline)
-int litehtml::element::place_element(const ptr &el, int max_width)					LITEHTML_RETURN_FUNC(0)
-int litehtml::element::render_inline(const ptr &container, int max_width)			LITEHTML_RETURN_FUNC(0)
-void litehtml::element::add_positioned(const ptr &el)							LITEHTML_EMPTY_FUNC
-int litehtml::element::find_next_line_top( int top, int width, int def_right )		LITEHTML_RETURN_FUNC(0)
-litehtml::element_float litehtml::element::get_float() const						LITEHTML_RETURN_FUNC(float_none)
-void litehtml::element::add_float(const ptr &el, int x, int y)					LITEHTML_EMPTY_FUNC
-void litehtml::element::update_floats(int dy, const ptr &parent)					LITEHTML_EMPTY_FUNC
-int litehtml::element::get_line_left( int y )										LITEHTML_RETURN_FUNC(0)
-int litehtml::element::get_line_right( int y, int def_right )						LITEHTML_RETURN_FUNC(def_right)
-int litehtml::element::get_left_floats_height() const								LITEHTML_RETURN_FUNC(0)
-int litehtml::element::get_right_floats_height() const								LITEHTML_RETURN_FUNC(0)
-int litehtml::element::get_floats_height(element_float el_float) const				LITEHTML_RETURN_FUNC(0)
-bool litehtml::element::is_floats_holder() const									LITEHTML_RETURN_FUNC(false)
-void litehtml::element::get_content_size( size& sz, int max_width )					LITEHTML_EMPTY_FUNC
-void litehtml::element::init()														LITEHTML_EMPTY_FUNC
-int litehtml::element::render( int x, int y, int max_width, bool second_pass )		LITEHTML_RETURN_FUNC(0)
-bool litehtml::element::appendChild(const ptr &el)						LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::removeChild(const ptr &el)						LITEHTML_RETURN_FUNC(false)
-void litehtml::element::clearRecursive()											LITEHTML_EMPTY_FUNC
-const litehtml::tchar_t* litehtml::element::get_tagName() const						LITEHTML_RETURN_FUNC(_t(""))
-void litehtml::element::set_tagName( const tchar_t* tag )							LITEHTML_EMPTY_FUNC
-void litehtml::element::set_data( const tchar_t* data )								LITEHTML_EMPTY_FUNC
-void litehtml::element::set_attr( const tchar_t* name, const tchar_t* val )			LITEHTML_EMPTY_FUNC
-void litehtml::element::apply_stylesheet( const litehtml::css& stylesheet )			LITEHTML_EMPTY_FUNC
-void litehtml::element::refresh_styles()											LITEHTML_EMPTY_FUNC
-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*/ ) 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)
-int litehtml::element::get_base_line()												LITEHTML_RETURN_FUNC(0)
-bool litehtml::element::on_mouse_over()												LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::on_mouse_leave()											LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::on_lbutton_down()											LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::on_lbutton_up()												LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::find_styles_changes( position::vector& redraw_boxes, int x, int y )	LITEHTML_RETURN_FUNC(false)
-const litehtml::tchar_t* litehtml::element::get_cursor()							LITEHTML_RETURN_FUNC(0)
-litehtml::white_space litehtml::element::get_white_space() const					LITEHTML_RETURN_FUNC(white_space_normal)
-litehtml::style_display litehtml::element::get_display() const						LITEHTML_RETURN_FUNC(display_none)
-bool litehtml::element::set_pseudo_class( const tchar_t* pclass, bool add )			LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::set_class( const tchar_t* pclass, bool add )				LITEHTML_RETURN_FUNC(false)
-litehtml::element_position litehtml::element::get_element_position(css_offsets* offsets) const			LITEHTML_RETURN_FUNC(element_position_static)
-bool litehtml::element::is_replaced() const											LITEHTML_RETURN_FUNC(false)
-int litehtml::element::line_height() const											LITEHTML_RETURN_FUNC(0)
-void litehtml::element::draw( uint_ptr hdc, int x, int y, const position* clip )	LITEHTML_EMPTY_FUNC
-void litehtml::element::draw_background( uint_ptr hdc, int x, int y, const position* clip )	LITEHTML_EMPTY_FUNC
-const litehtml::tchar_t* litehtml::element::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )	LITEHTML_RETURN_FUNC(0)
-litehtml::uint_ptr litehtml::element::get_font( font_metrics* fm /*= 0*/ )			LITEHTML_RETURN_FUNC(0)
-int litehtml::element::get_font_size()	const										LITEHTML_RETURN_FUNC(0)
-void litehtml::element::get_text( tstring& text )									LITEHTML_EMPTY_FUNC
-void litehtml::element::parse_attributes()											LITEHTML_EMPTY_FUNC
-int litehtml::element::select( const css_selector& selector, bool apply_pseudo)		LITEHTML_RETURN_FUNC(select_no_match)
-int litehtml::element::select( const css_element_selector& selector, bool apply_pseudo /*= true*/ )	LITEHTML_RETURN_FUNC(select_no_match)
-litehtml::element::ptr litehtml::element::find_ancestor(const css_selector& selector, bool apply_pseudo, bool* is_pseudo)	LITEHTML_RETURN_FUNC(0)
-bool litehtml::element::is_first_child_inline(const element::ptr& el) const			LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::is_last_child_inline(const element::ptr& el)				LITEHTML_RETURN_FUNC(false)
-bool litehtml::element::have_inline_child() const									LITEHTML_RETURN_FUNC(false)
+} // namespace litehtml
\ No newline at end of file
diff --git a/src/plugins/litehtml_viewer/litehtml/element.h b/src/plugins/litehtml_viewer/litehtml/element.h
index 5b91e28a3..2fa160c2c 100644
--- a/src/plugins/litehtml_viewer/litehtml/element.h
+++ b/src/plugins/litehtml_viewer/litehtml/element.h
@@ -2,341 +2,166 @@
 #define LH_ELEMENT_H
 
 #include <memory>
+#include <tuple>
+#include <list>
 #include "stylesheet.h"
 #include "css_offsets.h"
+#include "css_margins.h"
+#include "css_properties.h"
 
 namespace litehtml
 {
-	class box;
+	class line_box;
+	class dumper;
+	class render_item;
 
 	class element : public std::enable_shared_from_this<element>
 	{
-		friend class block_box;
 		friend class line_box;
 		friend class html_tag;
 		friend class el_table;
 		friend class document;
 	public:
-		typedef std::shared_ptr<litehtml::element>			ptr;
-		typedef std::shared_ptr<const litehtml::element>	const_ptr;
-		typedef std::weak_ptr<litehtml::element>			weak_ptr;
+		typedef std::shared_ptr<element>		ptr;
+		typedef std::shared_ptr<const element>	const_ptr;
+		typedef std::weak_ptr<element>			weak_ptr;
 	protected:
-		std::weak_ptr<element>		m_parent;
-		std::weak_ptr<litehtml::document>	m_doc;
-		litehtml::box*				m_box;
-		elements_vector				m_children;
-		position					m_pos;
-		margins						m_margins;
-		margins						m_padding;
-		margins						m_borders;
-		bool						m_skip;
-		
+		std::weak_ptr<element>					m_parent;
+		std::weak_ptr<document>					m_doc;
+		elements_vector							m_children;
+		css_properties							m_css;
+		std::list<std::weak_ptr<render_item>>	m_renders;
+		used_selector::vector					m_used_styles;
+
 		virtual void select_all(const css_selector& selector, elements_vector& res);
+		element::ptr _add_before_after(int type, const style& style);
 	public:
-		element(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~element();
-
-		// returns refer to m_pos member;
-		position&					get_position();
-
-		int							left()						const;
-		int							right()						const;
-		int							top()						const;
-		int							bottom()					const;
-		int							height()					const;
-		int							width()						const;
-
-		int							content_margins_top()		const;
-		int							content_margins_bottom()	const;
-		int							content_margins_left()		const;
-		int							content_margins_right()		const;
-		int							content_margins_width()		const;
-		int							content_margins_height()	const;
+		explicit element(const std::shared_ptr<document>& doc);
+		virtual ~element() = default;
 
-		int							margin_top()				const;
-		int							margin_bottom()				const;
-		int							margin_left()				const;
-		int							margin_right()				const;
-		margins						get_margins()				const;
-
-		int							padding_top()				const;
-		int							padding_bottom()			const;
-		int							padding_left()				const;
-		int							padding_right()				const;
-		margins						get_paddings()				const;
-
-		int							border_top()				const;
-		int							border_bottom()				const;
-		int							border_left()				const;
-		int							border_right()				const;
-		margins						get_borders()				const;
+		const css_properties&		css() const;
+		css_properties&				css_w();
 
 		bool						in_normal_flow()			const;
-		litehtml::web_color			get_color(const tchar_t* prop_name, bool inherited, const litehtml::web_color& def_color = litehtml::web_color());
 		bool						is_inline_box()				const;
+		bool						is_block_box()				const;
 		position					get_placement()				const;
-		bool						collapse_top_margin()		const;
-		bool						collapse_bottom_margin()	const;
 		bool						is_positioned()				const;
+		bool						is_float()					const;
 
-		bool						skip();
-		void						skip(bool val);
 		bool						have_parent() const;
+		bool						is_root() const;
 		element::ptr				parent() const;
-		void						parent(element::ptr par);
-		bool						is_visible() const;
-		int							calc_width(int defVal) const;
-		int							get_inline_shift_left();
-		int							get_inline_shift_right();
-		void						apply_relative_shift(int parent_width);
+		void						parent(const element::ptr& par);
+		// returns true for elements inside a table (but outside cells) that don't participate in table rendering
+		bool						is_table_skip() const;
 
 		std::shared_ptr<document>	get_document() const;
 
-		virtual elements_vector		select_all(const tstring& selector);
+		virtual elements_vector		select_all(const string& selector);
 		virtual elements_vector		select_all(const css_selector& selector);
 
-		virtual element::ptr		select_one(const tstring& selector);
+		virtual element::ptr		select_one(const string& selector);
 		virtual element::ptr		select_one(const css_selector& selector);
 
-		virtual int					render(int x, int y, int max_width, bool second_pass = false);
-		virtual int					render_inline(const ptr &container, int max_width);
-		virtual int					place_element(const ptr &el, int max_width);
-		virtual void				calc_outlines( int parent_width );
-		virtual void				calc_auto_margins(int parent_width);
-		virtual void				apply_vertical_align();
-		virtual bool				fetch_positioned();
-		virtual void				render_positioned(render_type rt = render_all);
-
 		virtual bool				appendChild(const ptr &el);
 		virtual bool				removeChild(const ptr &el);
 		virtual void				clearRecursive();
 
-		virtual const tchar_t*		get_tagName() const;
-		virtual void				set_tagName(const tchar_t* tag);
-		virtual void				set_data(const tchar_t* data);
-		virtual element_float		get_float() const;
-		virtual vertical_align		get_vertical_align() const;
-		virtual element_clear		get_clear() const;
+		virtual string_id			id() const;
+		virtual string_id			tag() const;
+		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 overflow			get_overflow() const;
 
-		virtual css_length			get_css_left() const;
-		virtual css_length			get_css_right() const;
-		virtual css_length			get_css_top() const;
-		virtual css_length			get_css_bottom() const;
-		virtual css_offsets			get_css_offsets() const;
-		virtual css_length			get_css_width() const;
-		virtual void				set_css_width(css_length& w);
-		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) const;
+		virtual void				set_attr(const char* name, const char* val);
+		virtual const char*			get_attr(const char* name, const char* def = nullptr) const;
 		virtual void				apply_stylesheet(const litehtml::css& stylesheet);
 		virtual void				refresh_styles();
 		virtual bool				is_white_space() const;
+		virtual bool				is_space() const;
+		virtual bool				is_comment() const;
 		virtual bool				is_body() const;
 		virtual bool				is_break() const;
-		virtual int					get_base_line();
+		virtual bool				is_text() const;
+
 		virtual bool				on_mouse_over();
 		virtual bool				on_mouse_leave();
 		virtual bool				on_lbutton_down();
 		virtual bool				on_lbutton_up();
 		virtual void				on_click();
-		virtual bool				find_styles_changes(position::vector& redraw_boxes, int x, int y);
-		virtual const tchar_t*		get_cursor();
-		virtual void				init_font();
-		virtual bool				is_point_inside(int x, int y);
-		virtual bool				set_pseudo_class(const tchar_t* pclass, bool add);
-		virtual bool				set_class(const tchar_t* pclass, bool add);
+		virtual bool				set_pseudo_class(string_id cls, bool add);
+		virtual bool				set_class(const char* pclass, bool add);
 		virtual bool				is_replaced() const;
-		virtual int					line_height() const;
-		virtual white_space			get_white_space() const;
-		virtual style_display		get_display() const;
-		virtual visibility			get_visibility() const;
-		virtual element_position	get_element_position(css_offsets* offsets = 0) const;
-		virtual void				get_inline_boxes(position::vector& boxes);
-		virtual void				parse_styles(bool is_reparse = false);
-		virtual void				draw(uint_ptr hdc, int x, int y, const position* clip);
-		virtual void				draw_background( uint_ptr hdc, int x, int y, const position* clip );
-		virtual const tchar_t*		get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0);
-		virtual uint_ptr			get_font(font_metrics* fm = 0);
-		virtual int					get_font_size() const;
-		virtual void				get_text(tstring& text);
+		virtual void				compute_styles(bool recursive = true);
+		virtual void				draw(uint_ptr hdc, int x, int y, const position *clip, const std::shared_ptr<render_item>& ri);
+		virtual void				draw_background(uint_ptr hdc, int x, int y, const position *clip, const std::shared_ptr<render_item> &ri);
+		virtual int					get_enum_property  (string_id name, bool inherited, int           default_value, uint_ptr css_properties_member_offset) const;
+		virtual css_length			get_length_property(string_id name, bool inherited, css_length    default_value, uint_ptr css_properties_member_offset) const;
+		virtual web_color			get_color_property (string_id name, bool inherited, web_color     default_value, uint_ptr css_properties_member_offset) const;
+		virtual string				get_string_property(string_id name, bool inherited, const string& default_value, uint_ptr css_properties_member_offset) const;
+		virtual float				get_number_property(string_id name, bool inherited, float         default_value, uint_ptr css_properties_member_offset) const;
+		virtual string_vector		get_string_vector_property(string_id name, bool inherited, const string_vector& default_value, uint_ptr css_properties_member_offset) const;
+		virtual int_vector			get_int_vector_property   (string_id name, bool inherited, const int_vector&    default_value, uint_ptr css_properties_member_offset) const;
+		virtual length_vector		get_length_vector_property(string_id name, bool inherited, const length_vector& default_value, uint_ptr css_properties_member_offset) const;
+		virtual size_vector			get_size_vector_property  (string_id name, bool inherited, const size_vector&   default_value, uint_ptr css_properties_member_offset) const;
+		virtual string				get_custom_property(string_id name, const string& default_value) const;
+
+		virtual void				get_text(string& text);
 		virtual void				parse_attributes();
+		virtual int					select(const string& selector);
 		virtual int					select(const css_selector& selector, bool apply_pseudo = true);
 		virtual int					select(const css_element_selector& selector, bool apply_pseudo = true);
-		virtual element::ptr		find_ancestor(const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);
+		virtual element::ptr		find_ancestor(const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = nullptr);
 		virtual bool				is_ancestor(const ptr &el) const;
-		virtual element::ptr		find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);
-		virtual element::ptr		find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0);
-		virtual bool				is_first_child_inline(const element::ptr& el) const;
-		virtual bool				is_last_child_inline(const element::ptr& el);
-		virtual bool				have_inline_child() const;
+		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 void				init();
 		virtual bool				is_floats_holder() const;
-		virtual int					get_floats_height(element_float el_float = float_none) const;
-		virtual int					get_left_floats_height() const;
-		virtual int					get_right_floats_height() const;
-		virtual int					get_line_left(int y);
-		virtual int					get_line_right(int y, int def_right);
-		virtual void				get_line_left_right(int y, int def_right, int& ln_left, int& ln_right);
-		virtual void				add_float(const ptr &el, int x, int y);
 		virtual void				update_floats(int dy, const ptr &parent);
-		virtual void				add_positioned(const ptr &el);
-		virtual int					find_next_line_top(int top, int width, int def_right);
-		virtual int					get_zindex() const;
-		virtual void				draw_stacking_context(uint_ptr hdc, int x, int y, const position* clip, bool with_positioned);
-		virtual void				draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex );
 		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;
-		virtual bool				get_predefined_height(int& p_height) const;
-		virtual void				calc_document_size(litehtml::size& sz, int x = 0, int y = 0);
-		virtual void				get_redraw_box(litehtml::position& pos, int x = 0, int y = 0);
-		virtual void				add_style(const litehtml::style& st);
-		virtual element::ptr		get_element_by_point(int x, int y, int client_x, int client_y);
-		virtual element::ptr		get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex);
+		virtual void				add_style(const style& style);
 		virtual const background*	get_background(bool own_only = false);
+
+		virtual string				dump_get_name();
+		virtual std::vector<std::tuple<string, string>> dump_get_attrs();
+		void						dump(litehtml::dumper& cout);
+
+		std::tuple<element::ptr, element::ptr, element::ptr> split_inlines();
+		virtual std::shared_ptr<render_item> create_render_item(const std::shared_ptr<render_item>& parent_ri);
+		bool requires_styles_update();
+		void add_render(const std::shared_ptr<render_item>& ri);
+		bool find_styles_changes( position::vector& redraw_boxes);
+		element::ptr add_pseudo_before(const style& style)
+		{
+			return _add_before_after(0, style);
+		}
+		element::ptr add_pseudo_after(const style& style)
+		{
+			return _add_before_after(1, style);
+		}
 	};
 
 	//////////////////////////////////////////////////////////////////////////
 	//							INLINE FUNCTIONS							//
 	//////////////////////////////////////////////////////////////////////////
 
-	inline int litehtml::element::right() const
-	{
-		return left() + width();
-	}
-
-	inline int litehtml::element::left() const
-	{
-		return m_pos.left() - margin_left() - m_padding.left - m_borders.left;
-	}
-
-	inline int litehtml::element::top() const
-	{
-		return m_pos.top() - margin_top() - m_padding.top - m_borders.top;
-	}
-
-	inline int litehtml::element::bottom() const
-	{
-		return top() + height();
-	}
-
-	inline int litehtml::element::height() const
-	{
-		return m_pos.height + margin_top() + margin_bottom() + m_padding.height() + m_borders.height();
-	}
-
-	inline int litehtml::element::width() const
-	{
-		return m_pos.width + margin_left() + margin_right() + m_padding.width() + m_borders.width();
-	}
-
-	inline int litehtml::element::content_margins_top() const
-	{
-		return margin_top() + m_padding.top + m_borders.top;
-	}
-
-	inline int litehtml::element::content_margins_bottom() const
-	{
-		return margin_bottom() + m_padding.bottom + m_borders.bottom;
-	}
-
-	inline int litehtml::element::content_margins_left() const
-	{
-		return margin_left() + m_padding.left + m_borders.left;
-	}
-
-	inline int litehtml::element::content_margins_right() const
-	{
-		return margin_right() + m_padding.right + m_borders.right;
-	}
-
-	inline int litehtml::element::content_margins_width() const
-	{
-		return content_margins_left() + content_margins_right();
-	}
-
-	inline int litehtml::element::content_margins_height() const
-	{
-		return content_margins_top() + content_margins_bottom();
-	}
-
-	inline litehtml::margins litehtml::element::get_paddings()	const
-	{
-		return m_padding;
-	}
-
-	inline litehtml::margins litehtml::element::get_borders()	const
-	{
-		return m_borders;
-	}
-
-	inline int litehtml::element::padding_top() const
-	{
-		return m_padding.top;
-	}
-
-	inline int litehtml::element::padding_bottom() const
-	{
-		return m_padding.bottom;
-	}
-
-	inline int litehtml::element::padding_left() const
-	{
-		return m_padding.left;
-	}
-
-	inline int litehtml::element::padding_right() const
-	{
-		return m_padding.right;
-	}
-
 	inline bool litehtml::element::in_normal_flow() const
 	{
-		if(get_element_position() != element_position_absolute && get_display() != display_none)
+		if(css().get_position() != element_position_absolute && css().get_display() != display_none)
 		{
 			return true;
 		}
 		return false;
 	}
 
-	inline int litehtml::element::border_top() const
-	{
-		return m_borders.top;
-	}
-
-	inline int litehtml::element::border_bottom() const
-	{
-		return m_borders.bottom;
-	}
-
-	inline int litehtml::element::border_left() const
-	{
-		return m_borders.left;
-	}
-
-	inline int litehtml::element::border_right() const
-	{
-		return m_borders.right;
-	}
-
-	inline bool litehtml::element::skip()
+	inline bool litehtml::element::is_root() const
 	{
-		return m_skip;
-	}
-
-	inline void litehtml::element::skip(bool val)
-	{
-		m_skip = val;
-	}
-
-	inline bool litehtml::element::have_parent() const
-	{
-		return !m_parent.expired();
+		return m_parent.expired();
 	}
 
 	inline element::ptr litehtml::element::parent() const
@@ -344,60 +169,47 @@ namespace litehtml
 		return m_parent.lock();
 	}
 
-	inline void litehtml::element::parent(element::ptr par)
+	inline void litehtml::element::parent(const element::ptr& par)
 	{
 		m_parent = par;
 	}
 
-	inline int litehtml::element::margin_top() const
-	{
-		return m_margins.top;
-	}
-
-	inline int litehtml::element::margin_bottom() const
-	{
-		return m_margins.bottom;
-	}
-
-	inline int litehtml::element::margin_left() const
-	{
-		return m_margins.left;
-	}
-
-	inline int litehtml::element::margin_right() const
+	inline bool litehtml::element::is_positioned()	const
 	{
-		return m_margins.right;
+		return (css().get_position() > element_position_static);
 	}
 
-	inline litehtml::margins litehtml::element::get_margins() const
+	inline bool litehtml::element::is_float()	const
 	{
-		margins ret;
-		ret.left	= margin_left();
-		ret.right	= margin_right();
-		ret.top		= margin_top();
-		ret.bottom	= margin_bottom();
-
-		return ret;
+		return (css().get_float() != float_none);
 	}
 
-	inline bool litehtml::element::is_positioned()	const
+	inline std::shared_ptr<document> element::get_document() const
 	{
-		return (get_element_position() > element_position_static);
+		return m_doc.lock();
 	}
 
-	inline bool litehtml::element::is_visible() const
+	inline const css_properties& element::css() const
 	{
-		return !(m_skip || get_display() == display_none || get_visibility() != visibility_visible);
+		return m_css;
 	}
 
-	inline position& litehtml::element::get_position()
+	inline css_properties& element::css_w()
 	{
-		return m_pos;
+		return m_css;
 	}
 
-	inline std::shared_ptr<document> element::get_document() const
+	inline bool element::is_block_box() const
 	{
-		return m_doc.lock();
+		if (css().get_display() == display_block ||
+			css().get_display() == display_flex ||
+			css().get_display() == display_table ||
+			css().get_display() == display_list_item ||
+			css().get_display() == display_flex)
+		{
+			return true;
+		}
+		return false;
 	}
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/html.cpp b/src/plugins/litehtml_viewer/litehtml/html.cpp
index d61da5dba..9695180a7 100644
--- a/src/plugins/litehtml_viewer/litehtml/html.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/html.cpp
@@ -1,33 +1,38 @@
 #include "html.h"
 #include "types.h"
-#include "html_tag.h"
+#include "utf8_strings.h"
 
-void litehtml::trim(tstring &s) 
+void litehtml::trim(string &s) 
 {
-	tstring::size_type pos = s.find_first_not_of(_t(" \n\r\t"));
-	if(pos != tstring::npos)
+	string::size_type pos = s.find_first_not_of(" \n\r\t");
+	if(pos != string::npos)
 	{
 		s.erase(s.begin(), s.begin() + pos);
 	}
-	pos = s.find_last_not_of(_t(" \n\r\t"));
-	if(pos != tstring::npos)
+	else
+	{
+		s = "";
+		return;
+	}
+	pos = s.find_last_not_of(" \n\r\t");
+	if(pos != string::npos)
 	{
 		s.erase(s.begin() + pos + 1, s.end());
 	}
 }
 
-void litehtml::lcase(tstring &s) 
+void litehtml::lcase(string &s) 
 {
-	for(tstring::iterator i = s.begin(); i != s.end(); i++)
+	for(char & i : s)
 	{
-		(*i) = t_tolower(*i);
+		i = t_tolower(i);
 	}
 }
 
-litehtml::tstring::size_type litehtml::find_close_bracket(const tstring &s, tstring::size_type off, tchar_t open_b, tchar_t close_b)
+litehtml::string::size_type litehtml::find_close_bracket(const string &s, string::size_type off, char open_b, char close_b)
 {
 	int cnt = 0;
-	for(tstring::size_type i = off; i < s.length(); i++)
+	for(string::size_type i = off; i < s.length(); i++)
 	{
 		if(s[i] == open_b)
 		{
@@ -41,10 +46,23 @@ litehtml::tstring::size_type litehtml::find_close_bracket(const tstring &s, tstr
 			}
 		}
 	}
-	return tstring::npos;
+	return string::npos;
+}
+
+litehtml::string litehtml::index_value(int index, const string& strings, char delim)
+{
+	std::vector<string> vals;
+	string delims;
+	delims.push_back(delim);
+	split_string(strings, vals, delims);
+	if(index >= 0 && index < vals.size())
+	{
+		return vals[index];
+	}
+	return std::to_string(index);
 }
 
-int litehtml::value_index( const tstring& val, const tstring& strings, int defValue, tchar_t delim )
+int litehtml::value_index( const string& val, const string& strings, int defValue, char delim )
 {
 	if(val.empty() || strings.empty() || !delim)
 	{
@@ -52,12 +70,12 @@ int litehtml::value_index( const tstring& val, const tstring& strings, int defVa
 	}
 
 	int idx = 0;
-	tstring::size_type delim_start	= 0;
-	tstring::size_type delim_end	= strings.find(delim, delim_start);
-	tstring::size_type item_len		= 0;
+	string::size_type delim_start	= 0;
+	string::size_type delim_end	= strings.find(delim, delim_start);
+	string::size_type item_len;
 	while(true)
 	{
-		if(delim_end == tstring::npos)
+		if(delim_end == string::npos)
 		{
 			item_len = strings.length() - delim_start;
 		} else
@@ -73,7 +91,7 @@ int litehtml::value_index( const tstring& val, const tstring& strings, int defVa
 		}
 		idx++;
 		delim_start = delim_end;
-		if(delim_start == tstring::npos) break;
+		if(delim_start == string::npos) break;
 		delim_start++;
 		if(delim_start == strings.length()) break;
 		delim_end = strings.find(delim, delim_start);
@@ -81,7 +99,7 @@ int litehtml::value_index( const tstring& val, const tstring& strings, int defVa
 	return defValue;
 }
 
-bool litehtml::value_in_list( const tstring& val, const tstring& strings, tchar_t delim )
+bool litehtml::value_in_list( const string& val, const string& strings, char delim )
 {
 	int idx = value_index(val, strings, -1, delim);
 	if(idx >= 0)
@@ -91,45 +109,45 @@ bool litehtml::value_in_list( const tstring& val, const tstring& strings, tchar_
 	return false;
 }
 
-void litehtml::split_string(const tstring& str, string_vector& tokens, const tstring& delims, const tstring& delims_preserve, const tstring& quote)
+void litehtml::split_string(const string& str, string_vector& tokens, const string& delims, const string& delims_preserve, const string& quote)
 {
 	if(str.empty() || (delims.empty() && delims_preserve.empty()))
 	{
 		return;
 	}
 
-	tstring all_delims = delims + delims_preserve + quote;
+	string all_delims = delims + delims_preserve + quote;
 
-	tstring::size_type token_start	= 0;
-	tstring::size_type token_end	= str.find_first_of(all_delims, token_start);
-	tstring::size_type token_len	= 0;
-	tstring token;
+	string::size_type token_start	= 0;
+	string::size_type token_end	= str.find_first_of(all_delims, token_start);
+	string::size_type token_len;
+	string token;
 	while(true)
 	{
-		while( token_end != tstring::npos && quote.find_first_of(str[token_end]) != tstring::npos )
+		while( token_end != string::npos && quote.find_first_of(str[token_end]) != string::npos )
 		{
-			if(str[token_end] == _t('('))
+			if(str[token_end] == '(')
 			{
-				token_end = find_close_bracket(str, token_end, _t('('), _t(')'));
-			} else if(str[token_end] == _t('['))
+				token_end = find_close_bracket(str, token_end, '(', ')');
+			} else if(str[token_end] == '[')
 			{
-				token_end = find_close_bracket(str, token_end, _t('['), _t(']'));
-			} else if(str[token_end] == _t('{'))
+				token_end = find_close_bracket(str, token_end, '[', ']');
+			} else if(str[token_end] == '{')
 			{
-				token_end = find_close_bracket(str, token_end, _t('{'), _t('}'));
+				token_end = find_close_bracket(str, token_end, '{', '}');
 			} else
 			{
 				token_end = str.find_first_of(str[token_end], token_end + 1);
 			}
-			if(token_end != tstring::npos)
+			if(token_end != string::npos)
 			{
 				token_end = str.find_first_of(all_delims, token_end + 1);
 			}
 		}
 
-		if(token_end == tstring::npos)
+		if(token_end == string::npos)
 		{
-			token_len = tstring::npos;
+			token_len = string::npos;
 		} else
 		{
 			token_len = token_end - token_start;
@@ -140,30 +158,122 @@ void litehtml::split_string(const tstring& str, string_vector& tokens, const tst
 		{
 			tokens.push_back( token );
 		}
-		if(token_end != tstring::npos && !delims_preserve.empty() && delims_preserve.find_first_of(str[token_end]) != tstring::npos)
+		if(token_end != string::npos && !delims_preserve.empty() && delims_preserve.find_first_of(str[token_end]) != string::npos)
 		{
 			tokens.push_back( str.substr(token_end, 1) );
 		}
 
 		token_start = token_end;
-		if(token_start == tstring::npos) break;
+		if(token_start == string::npos) break;
 		token_start++;
 		if(token_start == str.length()) break;
 		token_end = str.find_first_of(all_delims, token_start);
 	}
 }
 
-void litehtml::join_string(tstring& str, const string_vector& tokens, const tstring& delims)
+void litehtml::join_string(string& str, const string_vector& tokens, const string& delims)
 {
-	tstringstream ss;
-	for(size_t i=0; i<tokens.size(); ++i)
+	str = "";
+	for (size_t i = 0; i < tokens.size(); i++)
 	{
-		if(i != 0)
+		if (i != 0)
 		{
-			ss << delims;
+			str += delims;
 		}
-		ss << tokens[i];
+		str += tokens[i];
+	}
+}
+
+int litehtml::t_strcasecmp(const char *s1, const char *s2)
+{
+	int i, d, c;
+
+	for (i = 0;; i++)
+	{
+		c = t_tolower((unsigned char)s1[i]);
+		d = c - t_tolower((unsigned char)s2[i]);
+		if (d < 0)
+			return -1;
+		else if (d > 0)
+			return 1;
+		else if (c == 0)
+			return 0;
+	}
+}
+
+int litehtml::t_strncasecmp(const char *s1, const char *s2, size_t n)
+{
+	int i, d, c;
+
+	for (i = 0; i < n; i++)
+	{
+		c = t_tolower((unsigned char)s1[i]);
+		d = c - t_tolower((unsigned char)s2[i]);
+		if (d < 0)
+			return -1;
+		else if (d > 0)
+			return 1;
+		else if (c == 0)
+			return 0;
 	}
 
-	str = ss.str();
+	return 0;
+}
+
+litehtml::string litehtml::get_escaped_string(const string& in_str)
+{
+	string ret;
+	for (auto ch : in_str)
+	{
+		switch (ch)
+		{
+			case '\'':
+				ret += "\\'";
+				break;
+
+			case '\"':
+				ret += "\\\"";
+				break;
+
+			case '\?':
+				ret += "\\?";
+				break;
+
+			case '\\':
+				ret += "\\\\";
+				break;
+
+			case '\a':
+				ret += "\\a";
+				break;
+
+			case '\b':
+				ret += "\\b";
+				break;
+
+			case '\f':
+				ret += "\\f";
+				break;
+
+			case '\n':
+				ret += "\\n";
+				break;
+
+			case '\r':
+				ret += "\\r";
+				break;
+
+			case '\t':
+				ret += "\\t";
+				break;
+
+			case '\v':
+				ret += "\\v";
+				break;
+
+			default:
+				ret += ch;
+		}
+	}
+	return ret;
 }
diff --git a/src/plugins/litehtml_viewer/litehtml/html.h b/src/plugins/litehtml_viewer/litehtml/html.h
index 20457f155..b184ac30a 100644
--- a/src/plugins/litehtml_viewer/litehtml/html.h
+++ b/src/plugins/litehtml_viewer/litehtml/html.h
@@ -8,73 +8,50 @@
 #include <map>
 #include <cstring>
 #include <algorithm>
-#include <sstream>
-#include <cstdint>
+#include <functional>
 #include "os_types.h"
+#include "string_id.h"
 #include "types.h"
+#include "utf8_strings.h"
 #include "background.h"
 #include "borders.h"
-#include "html_tag.h"
 #include "web_color.h"
 #include "media_query.h"
+#include "html_tag.h"
+#include "document_container.h"
+#include "document.h"
 
 namespace litehtml
 {
-	struct list_marker
-	{
-		tstring			image;
-		const tchar_t*	baseurl;
-		list_style_type	marker_type;
-		web_color		color;
-		position		pos;
-		int				index;
-		uint_ptr		font;
-	};
+	void trim(string &s);
+	void lcase(string &s);
+	int	 value_index(const string& val, const string& strings, int defValue = -1, char delim = ';');
+    string index_value(int index, const string& strings, char delim = ';');
+	bool value_in_list(const string& val, const string& strings, char delim = ';');
+	string::size_type find_close_bracket(const string &s, string::size_type off, char open_b = '(', char close_b = ')');
+	void split_string(const string& str, string_vector& tokens, const string& delims, const string& delims_preserve = "", const string& quote = "\"");
+	void join_string(string& str, const string_vector& tokens, const string& delims);
+    double t_strtod(const char* string, char** endPtr = nullptr);
+    string get_escaped_string(const string& in_str);
 
-	// call back interface to draw text, images and other elements
-	class document_container
+	int t_strcasecmp(const char *s1, const char *s2);
+	int t_strncasecmp(const char *s1, const char *s2, size_t n);
+	
+	inline int t_isdigit(int c)
 	{
-	public:
-		virtual litehtml::uint_ptr	create_font(const litehtml::tchar_t* faceName, int size, int weight, litehtml::font_style italic, unsigned int decoration, litehtml::font_metrics* fm) = 0;
-		virtual void				delete_font(litehtml::uint_ptr hFont) = 0;
-		virtual int					text_width(const litehtml::tchar_t* text, litehtml::uint_ptr hFont) = 0;
-		virtual void				draw_text(litehtml::uint_ptr hdc, const litehtml::tchar_t* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos) = 0;
-		virtual int					pt_to_px(int pt) = 0;
-		virtual int					get_default_font_size() const = 0;
-		virtual const litehtml::tchar_t*	get_default_font_name() const = 0;
-		virtual void				draw_list_marker(litehtml::uint_ptr hdc, const litehtml::list_marker& marker) = 0;
-		virtual void				load_image(const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, bool redraw_on_ready) = 0;
-		virtual void				get_image_size(const litehtml::tchar_t* src, const litehtml::tchar_t* baseurl, litehtml::size& sz) = 0;
-		virtual void				draw_background(litehtml::uint_ptr hdc, const litehtml::background_paint& bg) = 0;
-		virtual void				draw_borders(litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root) = 0;
-
-		virtual	void				set_caption(const litehtml::tchar_t* caption) = 0;
-		virtual	void				set_base_url(const litehtml::tchar_t* base_url) = 0;
-		virtual void				link(const std::shared_ptr<litehtml::document>& doc, const litehtml::element::ptr& el) = 0;
-		virtual void				on_anchor_click(const litehtml::tchar_t* url, const litehtml::element::ptr& el) = 0;
-		virtual	void				set_cursor(const litehtml::tchar_t* cursor) = 0;
-		virtual	void				transform_text(litehtml::tstring& text, litehtml::text_transform tt) = 0;
-		virtual void				import_css(litehtml::tstring& text, const litehtml::tstring& url, litehtml::tstring& baseurl) = 0;
-		virtual void				set_clip(const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius, bool valid_x, bool valid_y) = 0;
-		virtual void				del_clip() = 0;
-		virtual void				get_client_rect(litehtml::position& client) const = 0;
-		virtual std::shared_ptr<litehtml::element>	create_element(const litehtml::tchar_t *tag_name,
-																	 const litehtml::string_map &attributes,
-																	 const std::shared_ptr<litehtml::document> &doc) = 0;
-
-		virtual void				get_media_features(litehtml::media_features& media) const = 0;
-		virtual void				get_language(litehtml::tstring& language, litehtml::tstring & culture) const = 0;
-		virtual litehtml::tstring	resolve_color(const litehtml::tstring& color) const  { return litehtml::tstring(); }
-	};
+		return (c >= '0' && c <= '9');
+	}
 
-	void trim(tstring &s);
-	void lcase(tstring &s);
-	int	 value_index(const tstring& val, const tstring& strings, int defValue = -1, tchar_t delim = _t(';'));
-	bool value_in_list(const tstring& val, const tstring& strings, tchar_t delim = _t(';'));
-	tstring::size_type find_close_bracket(const tstring &s, tstring::size_type off, tchar_t open_b = _t('('), tchar_t close_b = _t(')'));
-	void split_string(const tstring& str, string_vector& tokens, const tstring& delims, const tstring& delims_preserve = _t(""), const tstring& quote = _t("\""));
-	void join_string(tstring& str, const string_vector& tokens, const tstring& delims);
+	inline int t_isalpha(int c)
+	{
+		return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
+	}
 
+	inline int t_tolower(int c)
+	{
+		return (c >= 'A' && c <= 'Z' ? c + 'a' - 'A' : c);
+	}
+	
 	inline int round_f(float val)
 	{
 		int int_val = (int) val;
@@ -94,6 +71,16 @@ namespace litehtml
 		}
 		return int_val;
 	}
+
+	inline float t_strtof(const string& str, char** endPtr = nullptr)
+	{
+		return (float)t_strtod(str.c_str(), endPtr);
+	}
+
+	inline int baseline_align(int line_height, int line_base_line, int height, int baseline)
+	{
+		return (line_height - line_base_line) - (height - baseline);
+	}
 }
 
 #endif  // LH_HTML_H
diff --git a/src/plugins/litehtml_viewer/litehtml/html_tag.cpp b/src/plugins/litehtml_viewer/litehtml/html_tag.cpp
index a992d68a2..d1e7302e4 100644
--- a/src/plugins/litehtml_viewer/litehtml/html_tag.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/html_tag.cpp
@@ -8,35 +8,25 @@
 #include <locale>
 #include "el_before_after.h"
 #include "num_cvt.h"
+#include "line_box.h"
+#include <stack>
+#include "render_item.h"
 
-litehtml::html_tag::html_tag(const std::shared_ptr<litehtml::document>& doc) : litehtml::element(doc)
+litehtml::html_tag::html_tag(const std::shared_ptr<document>& doc) : element(doc)
 {
-	m_box_sizing			= box_sizing_content_box;
-	m_z_index				= 0;
-	m_overflow				= overflow_visible;
-	m_box					= 0;
-	m_text_align			= text_align_left;
-	m_el_position			= element_position_static;
-	m_display				= display_inline;
-	m_vertical_align		= va_baseline;
-	m_list_style_type		= list_style_type_none;
-	m_list_style_position	= list_style_position_outside;
-	m_float					= float_none;
-	m_clear					= clear_none;
-	m_font					= 0;
-	m_font_size				= 0;
-	m_white_space			= white_space_normal;
-	m_lh_predefined			= false;
-	m_line_height			= 0;
-	m_visibility			= visibility_visible;
-	m_border_spacing_x		= 0;
-	m_border_spacing_y		= 0;
-	m_border_collapse		= border_collapse_separate;
+	m_tag = empty_id;
+	m_id = empty_id;
 }
 
-litehtml::html_tag::~html_tag()
+litehtml::html_tag::html_tag(const element::ptr& parent, const string& style) : element(parent->get_document()),
+	m_tag(empty_id),
+	m_id(empty_id)
 {
-
+	litehtml::style st;
+	st.add(style);
+	add_style(st);
+	this->parent(parent);
+	compute_styles();
 }
 
 bool litehtml::html_tag::appendChild(const element::ptr &el)
@@ -71,34 +61,59 @@ void litehtml::html_tag::clearRecursive()
 	m_children.clear();
 }
 
+litehtml::string_id litehtml::html_tag::id() const
+{
+	return m_id;
+}
+
+litehtml::string_id litehtml::html_tag::tag() const
+{
+	return m_tag;
+}
+
+const char* litehtml::html_tag::get_tagName() const
+{
+	return _s(m_tag).c_str();
+}
 
-const litehtml::tchar_t* litehtml::html_tag::get_tagName() const
+void litehtml::html_tag::set_tagName( const char* _tag )
 {
-	return m_tag.c_str();
+	string tag = _tag;
+	lcase(tag);
+	m_tag = _id(tag);
 }
 
-void litehtml::html_tag::set_attr( const tchar_t* name, const tchar_t* val )
+void litehtml::html_tag::set_attr( const char* _name, const char* _val )
 {
-	if(name && val)
+	if(_name && _val)
 	{
-		tstring s_val = name;
-		for(size_t i = 0; i < s_val.length(); i++)
+		string name = _name;
+		lcase(name);
+		m_attrs[name] = _val;
+
+		if( name == "class" )
 		{
-			s_val[i] = std::tolower(s_val[i], std::locale::classic());
+			string val = _val;
+			// class names are matched case-insensitively in quirks mode
+			// we match them case-insensitively in all modes (same for id)
+			lcase(val);
+			m_str_classes.resize( 0 );
+			split_string( val, m_str_classes, " " );
+			m_classes.clear();
+			for (auto& cls : m_str_classes) m_classes.push_back(_id(cls));
 		}
-		m_attrs[s_val] = val;
-
-		if( t_strcasecmp( name, _t("class") ) == 0 )
+		else if (name == "id")
 		{
-			m_class_values.resize( 0 );
-			split_string( val, m_class_values, _t(" ") );
+			string val = _val;
+			lcase(val);
+			m_id = _id(val);
 		}
 	}
 }
 
-const litehtml::tchar_t* litehtml::html_tag::get_attr( const tchar_t* name, const tchar_t* def ) const
+const char* litehtml::html_tag::get_attr( const char* name, const char* def ) const
 {
-	string_map::const_iterator attr = m_attrs.find(name);
+	auto attr = m_attrs.find(name);
 	if(attr != m_attrs.end())
 	{
 		return attr->second.c_str();
@@ -106,9 +121,9 @@ const litehtml::tchar_t* litehtml::html_tag::get_attr( const tchar_t* name, cons
 	return def;
 }
 
-litehtml::elements_vector litehtml::html_tag::select_all( const tstring& selector )
+litehtml::elements_vector litehtml::html_tag::select_all( const string& selector )
 {
-	css_selector sel(media_query_list::ptr(0));
+	css_selector sel;
 	sel.parse(selector);
 	
 	return select_all(sel);
@@ -135,9 +150,9 @@ void litehtml::html_tag::select_all(const css_selector& selector, elements_vecto
 }
 
 
-litehtml::element::ptr litehtml::html_tag::select_one( const tstring& selector )
+litehtml::element::ptr litehtml::html_tag::select_one( const string& selector )
 {
-	css_selector sel(media_query_list::ptr(0));
+	css_selector sel;
 	sel.parse(selector);
 
 	return select_one(sel);
@@ -158,15 +173,28 @@ litehtml::element::ptr litehtml::html_tag::select_one( const css_selector& selec
 			return res;
 		}
 	}
-	return 0;
+	return nullptr;
 }
 
 void litehtml::html_tag::apply_stylesheet( const litehtml::css& stylesheet )
 {
-	remove_before_after();
-
 	for(const auto& sel : stylesheet.selectors())
 	{
+		// optimization
+		{
+			const auto& r = sel->m_right;
+			if (r.m_tag != star_id && r.m_tag != m_tag)
+				continue;
+
+			if (!r.m_attrs.empty())
+			{
+				const auto& attr = r.m_attrs[0];
+				if (attr.type == select_class &&
+					std::find(m_classes.begin(), m_classes.end(), attr.name) == m_classes.end())
+					continue;
+			}
+		}
+
 		int apply = select(*sel, false);
 
 		if(apply != select_no_match)
@@ -181,14 +209,14 @@ void litehtml::html_tag::apply_stylesheet( const litehtml::css& stylesheet )
 					{
 						if(apply & select_match_with_after)
 						{
-							element::ptr el = get_element_after();
+							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();
+							element::ptr el = get_element_before(*sel->m_style, true);
 							if(el)
 							{
 								el->add_style(*sel->m_style);
@@ -202,14 +230,14 @@ void litehtml::html_tag::apply_stylesheet( const litehtml::css& stylesheet )
 					}
 				} else if(apply & select_match_with_after)
 				{
-					element::ptr el = get_element_after();
+					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();
+					element::ptr el = get_element_before(*sel->m_style, true);
 					if(el)
 					{
 						el->add_style(*sel->m_style);
@@ -226,7 +254,7 @@ void litehtml::html_tag::apply_stylesheet( const litehtml::css& stylesheet )
 
 	for(auto& el : m_children)
 	{
-		if(el->get_display() != display_inline_text)
+		if(el->css().get_display() != display_inline_text)
 		{
 			el->apply_stylesheet(stylesheet);
 		}
@@ -236,7 +264,7 @@ void litehtml::html_tag::apply_stylesheet( const litehtml::css& stylesheet )
 void litehtml::html_tag::get_content_size( size& sz, int max_width )
 {
 	sz.height	= 0;
-	if(m_display == display_block)
+	if(m_css.get_display() == display_block)
 	{
 		sz.width	= max_width;
 	} else
@@ -245,351 +273,154 @@ void litehtml::html_tag::get_content_size( size& sz, int max_width )
 	}
 }
 
-void litehtml::html_tag::draw( uint_ptr hdc, int x, int y, const position* clip )
+void litehtml::html_tag::draw(uint_ptr hdc, int x, int y, const position *clip, const std::shared_ptr<render_item> &ri)
 {
-	position pos = m_pos;
+	position pos = ri->pos();
 	pos.x	+= x;
 	pos.y	+= y;
 
-	draw_background(hdc, x, y, clip);
+	draw_background(hdc, x, y, clip, ri);
 
-	if(m_display == display_list_item && m_list_style_type != list_style_type_none)
+	if(m_css.get_display() == display_list_item && m_css.get_list_style_type() != list_style_type_none)
 	{
-		if(m_overflow > overflow_visible)
+		if(m_css.get_overflow() > overflow_visible)
 		{
 			position border_box = pos;
-			border_box += m_padding;
-			border_box += m_borders;
+			border_box += ri->get_paddings();
+			border_box += ri->get_borders();
 
-			border_radiuses bdr_radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
+			border_radiuses bdr_radius = m_css.get_borders().radius.calc_percents(border_box.width, border_box.height);
 
-			bdr_radius -= m_borders;
-			bdr_radius -= m_padding;
+			bdr_radius -= ri->get_borders();
+			bdr_radius -= ri->get_paddings();
 
-			get_document()->container()->set_clip(pos, bdr_radius, true, true);
+			get_document()->container()->set_clip(pos, bdr_radius);
 		}
 
 		draw_list_marker(hdc, pos);
 
-		if(m_overflow > overflow_visible)
+		if(m_css.get_overflow() > overflow_visible)
 		{
 			get_document()->container()->del_clip();
 		}
 	}
 }
 
-litehtml::uint_ptr litehtml::html_tag::get_font(font_metrics* fm)
+litehtml::string litehtml::html_tag::get_custom_property(string_id name, const string& default_value) const
 {
-	if(fm)
-	{
-		*fm = m_font_metrics;
-	}
-	return m_font;
-}
+	const property_value& value = m_style.get_property(name);
 
-const litehtml::tchar_t* litehtml::html_tag::get_style_property( const tchar_t* name, bool inherited, const tchar_t* def /*= 0*/ )
-{
-	const tchar_t* ret = m_style.get_property(name);
-	element::ptr el_parent = parent();
-	if (el_parent)
+	if (value.m_type == prop_type_string)
 	{
-		if ( ( ret && !t_strcasecmp(ret, _t("inherit")) ) || (!ret && inherited) )
-		{
-			ret = el_parent->get_style_property(name, inherited, def);
-		}
+		return value.m_string;
 	}
-
-	if(!ret)
+	else if (auto _parent = parent())
 	{
-		ret = def;
+		return _parent->get_custom_property(name, default_value);
 	}
-
-	return ret;
+	return default_value;
 }
 
-void litehtml::html_tag::parse_styles(bool is_reparse)
+template<class Type, litehtml::property_type property_value_type, Type litehtml::property_value::* property_value_member>
+const Type& litehtml::html_tag::get_property_impl(string_id name, bool inherited, const Type& default_value, uint_ptr css_properties_member_offset) const
 {
-	const tchar_t* style = get_attr(_t("style"));
-
-	if(style)
-	{
-		m_style.add(style, NULL);
-	}
+	const property_value& value = m_style.get_property(name);
 
-	init_font();
-	document::ptr doc = get_document();
-
-	m_el_position	= (element_position)	value_index(get_style_property(_t("position"),		false,	_t("static")),		element_position_strings,	element_position_fixed);
-	m_text_align	= (text_align)			value_index(get_style_property(_t("text-align"),		true,	_t("left")),		text_align_strings,			text_align_left);
-	m_overflow		= (overflow)			value_index(get_style_property(_t("overflow"),		false,	_t("visible")),		overflow_strings,			overflow_visible);
-	m_white_space	= (white_space)			value_index(get_style_property(_t("white-space"),	true,	_t("normal")),		white_space_strings,		white_space_normal);
-	m_display		= (style_display)		value_index(get_style_property(_t("display"),		false,	_t("inline")),		style_display_strings,		display_inline);
-	m_visibility	= (visibility)			value_index(get_style_property(_t("visibility"),	true,	_t("visible")),		visibility_strings,			visibility_visible);
-	m_box_sizing	= (box_sizing)			value_index(get_style_property(_t("box-sizing"),		false,	_t("content-box")),	box_sizing_strings,			box_sizing_content_box);
-
-	if(m_el_position != element_position_static)
-	{
-		const tchar_t* val = get_style_property(_t("z-index"), false, 0);
-		if(val)
-		{
-			m_z_index = t_atoi(val);
-		}
-	}
-
-	const tchar_t* va	= get_style_property(_t("vertical-align"), true,	_t("baseline"));
-	m_vertical_align = (vertical_align) value_index(va, vertical_align_strings, va_baseline);
-
-	const tchar_t* fl	= get_style_property(_t("float"), false,	_t("none"));
-	m_float = (element_float) value_index(fl, element_float_strings, float_none);
-
-	m_clear = (element_clear) value_index(get_style_property(_t("clear"), false, _t("none")), element_clear_strings, clear_none);
-
-	if (m_float != float_none)
-	{
-		// reset display in to block for floating elements
-		if (m_display != display_none)
-		{
-			m_display = display_block;
-		}
-	}
-	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 ||
-		m_display == display_table_column_group ||
-		m_display == display_table_footer_group ||
-		m_display == display_table_header_group ||
-		m_display == display_table_row ||
-		m_display == display_table_row_group)
+	if (value.m_type == property_value_type)
 	{
-		doc->add_tabular(shared_from_this());
+		return value.*property_value_member;
 	}
-	// fix inline boxes with absolute/fixed positions
-	else if (m_display != display_none && is_inline_box())
+	else if (inherited || value.m_type == prop_type_inherit)
 	{
-		if (m_el_position == element_position_absolute || m_el_position == element_position_fixed)
+		if (auto _parent = parent())
 		{
-			m_display = display_block;
+			return *(Type*)((byte*)&_parent->css() + css_properties_member_offset);
 		}
+		return default_value;
 	}
+	// value must be invalid here
+	//assert(value.m_type == prop_type_invalid);
+	return default_value;
+}
 
-	m_css_text_indent.fromString(	get_style_property(_t("text-indent"),	true,	_t("0")),	_t("0"));
-
-	m_css_width.fromString(			get_style_property(_t("width"),			false,	_t("auto")), _t("auto"));
-	m_css_height.fromString(		get_style_property(_t("height"),		false,	_t("auto")), _t("auto"));
-
-	doc->cvt_units(m_css_width, m_font_size);
-	doc->cvt_units(m_css_height, m_font_size);
-
-	m_css_min_width.fromString(		get_style_property(_t("min-width"),		false,	_t("0")));
-	m_css_min_height.fromString(	get_style_property(_t("min-height"),		false,	_t("0")));
-
-	m_css_max_width.fromString(		get_style_property(_t("max-width"),		false,	_t("none")),	_t("none"));
-	m_css_max_height.fromString(	get_style_property(_t("max-height"),		false,	_t("none")),	_t("none"));
-	
-	doc->cvt_units(m_css_min_width, m_font_size);
-	doc->cvt_units(m_css_min_height, m_font_size);
-
-	m_css_offsets.left.fromString(		get_style_property(_t("left"),				false,	_t("auto")), _t("auto"));
-	m_css_offsets.right.fromString(		get_style_property(_t("right"),				false,	_t("auto")), _t("auto"));
-	m_css_offsets.top.fromString(		get_style_property(_t("top"),				false,	_t("auto")), _t("auto"));
-	m_css_offsets.bottom.fromString(	get_style_property(_t("bottom"),			false,	_t("auto")), _t("auto"));
-
-	doc->cvt_units(m_css_offsets.left, m_font_size);
-	doc->cvt_units(m_css_offsets.right, m_font_size);
-	doc->cvt_units(m_css_offsets.top,		m_font_size);
-	doc->cvt_units(m_css_offsets.bottom,	m_font_size);
-
-	m_css_margins.left.fromString(		get_style_property(_t("margin-left"),		false,	_t("0")), _t("auto"));
-	m_css_margins.right.fromString(		get_style_property(_t("margin-right"),		false,	_t("0")), _t("auto"));
-	m_css_margins.top.fromString(		get_style_property(_t("margin-top"),			false,	_t("0")), _t("auto"));
-	m_css_margins.bottom.fromString(	get_style_property(_t("margin-bottom"),		false,	_t("0")), _t("auto"));
-
-	m_css_padding.left.fromString(		get_style_property(_t("padding-left"),		false,	_t("0")), _t(""));
-	m_css_padding.right.fromString(		get_style_property(_t("padding-right"),		false,	_t("0")), _t(""));
-	m_css_padding.top.fromString(		get_style_property(_t("padding-top"),		false,	_t("0")), _t(""));
-	m_css_padding.bottom.fromString(	get_style_property(_t("padding-bottom"),		false,	_t("0")), _t(""));
-
-	m_css_borders.left.width.fromString(	get_style_property(_t("border-left-width"),		false,	_t("medium")), border_width_strings);
-	m_css_borders.right.width.fromString(	get_style_property(_t("border-right-width"),		false,	_t("medium")), border_width_strings);
-	m_css_borders.top.width.fromString(		get_style_property(_t("border-top-width"),		false,	_t("medium")), border_width_strings);
-	m_css_borders.bottom.width.fromString(	get_style_property(_t("border-bottom-width"),	false,	_t("medium")), border_width_strings);
-
-	m_css_borders.left.color = web_color::from_string(get_style_property(_t("border-left-color"),	false,	_t("")), doc->container());
-	m_css_borders.left.style = (border_style) value_index(get_style_property(_t("border-left-style"), false, _t("none")), border_style_strings, border_style_none);
-
-    m_css_borders.right.color = web_color::from_string(get_style_property(_t("border-right-color"), false, _t("")), doc->container());
-	m_css_borders.right.style = (border_style) value_index(get_style_property(_t("border-right-style"), false, _t("none")), border_style_strings, border_style_none);
-
-    m_css_borders.top.color = web_color::from_string(get_style_property(_t("border-top-color"), false, _t("")), doc->container());
-	m_css_borders.top.style = (border_style) value_index(get_style_property(_t("border-top-style"), false, _t("none")), border_style_strings, border_style_none);
-
-    m_css_borders.bottom.color = web_color::from_string(get_style_property(_t("border-bottom-color"), false, _t("")), doc->container());
-	m_css_borders.bottom.style = (border_style) value_index(get_style_property(_t("border-bottom-style"), false, _t("none")), border_style_strings, border_style_none);
-
-	m_css_borders.radius.top_left_x.fromString(get_style_property(_t("border-top-left-radius-x"), false, _t("0")));
-	m_css_borders.radius.top_left_y.fromString(get_style_property(_t("border-top-left-radius-y"), false, _t("0")));
-
-	m_css_borders.radius.top_right_x.fromString(get_style_property(_t("border-top-right-radius-x"), false, _t("0")));
-	m_css_borders.radius.top_right_y.fromString(get_style_property(_t("border-top-right-radius-y"), false, _t("0")));
-
-	m_css_borders.radius.bottom_right_x.fromString(get_style_property(_t("border-bottom-right-radius-x"), false, _t("0")));
-	m_css_borders.radius.bottom_right_y.fromString(get_style_property(_t("border-bottom-right-radius-y"), false, _t("0")));
-
-	m_css_borders.radius.bottom_left_x.fromString(get_style_property(_t("border-bottom-left-radius-x"), false, _t("0")));
-	m_css_borders.radius.bottom_left_y.fromString(get_style_property(_t("border-bottom-left-radius-y"), false, _t("0")));
-
-	doc->cvt_units(m_css_borders.radius.bottom_left_x,			m_font_size);
-	doc->cvt_units(m_css_borders.radius.bottom_left_y,			m_font_size);
-	doc->cvt_units(m_css_borders.radius.bottom_right_x,			m_font_size);
-	doc->cvt_units(m_css_borders.radius.bottom_right_y,			m_font_size);
-	doc->cvt_units(m_css_borders.radius.top_left_x,				m_font_size);
-	doc->cvt_units(m_css_borders.radius.top_left_y,				m_font_size);
-	doc->cvt_units(m_css_borders.radius.top_right_x,				m_font_size);
-	doc->cvt_units(m_css_borders.radius.top_right_y,				m_font_size);
-
-	doc->cvt_units(m_css_text_indent,								m_font_size);
-
-	m_margins.left		= doc->cvt_units(m_css_margins.left,		m_font_size);
-	m_margins.right		= doc->cvt_units(m_css_margins.right,		m_font_size);
-	m_margins.top		= doc->cvt_units(m_css_margins.top,		m_font_size);
-	m_margins.bottom	= doc->cvt_units(m_css_margins.bottom,	m_font_size);
-
-	m_padding.left		= doc->cvt_units(m_css_padding.left,		m_font_size);
-	m_padding.right		= doc->cvt_units(m_css_padding.right,		m_font_size);
-	m_padding.top		= doc->cvt_units(m_css_padding.top,		m_font_size);
-	m_padding.bottom	= doc->cvt_units(m_css_padding.bottom,	m_font_size);
-
-	m_borders.left		= doc->cvt_units(m_css_borders.left.width,	m_font_size);
-	m_borders.right		= doc->cvt_units(m_css_borders.right.width,	m_font_size);
-	m_borders.top		= doc->cvt_units(m_css_borders.top.width,		m_font_size);
-	m_borders.bottom	= doc->cvt_units(m_css_borders.bottom.width,	m_font_size);
-
-	css_length line_height;
-	line_height.fromString(get_style_property(_t("line-height"),	true,	_t("normal")), _t("normal"));
-	if(line_height.is_predefined())
-	{
-		m_line_height = m_font_metrics.height;
-		m_lh_predefined = true;
-	} else if(line_height.units() == css_units_none)
-	{
-		m_line_height = (int) (line_height.val() * m_font_size);
-		m_lh_predefined = false;
-	} else
-	{
-		m_line_height =  doc->cvt_units(line_height,	m_font_size, m_font_size);
-		m_lh_predefined = false;
-	}
-
-
-	if(m_display == display_list_item)
-	{
-		const tchar_t* list_type = get_style_property(_t("list-style-type"), true, _t("disc"));
-		m_list_style_type = (list_style_type) value_index(list_type, list_style_type_strings, list_style_type_disc);
-
-		const tchar_t* list_pos = get_style_property(_t("list-style-position"), true, _t("outside"));
-		m_list_style_position = (list_style_position) value_index(list_pos, list_style_position_strings, list_style_position_outside);
-
-		const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);
-		if(list_image && list_image[0])
-		{
-			tstring url;
-			css::parse_css_url(list_image, url);
-
-			const tchar_t* list_image_baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);
-			doc->container()->load_image(url.c_str(), list_image_baseurl, true);
-		}
+int litehtml::html_tag::get_enum_property(string_id name, bool inherited, int default_value, uint_ptr css_properties_member_offset) const
+{
+	return get_property_impl<int, prop_type_enum_item, &property_value::m_enum_item>(name, inherited, default_value, css_properties_member_offset);
+}
 
-	}
+litehtml::css_length litehtml::html_tag::get_length_property(string_id name, bool inherited, css_length default_value, uint_ptr css_properties_member_offset) const
+{
+	return get_property_impl<css_length, prop_type_length, &property_value::m_length>(name, inherited, default_value, css_properties_member_offset);
+}
 
-	parse_background();
+litehtml::web_color litehtml::html_tag::get_color_property(string_id name, bool inherited, web_color default_value, uint_ptr css_properties_member_offset) const
+{
+	return get_property_impl<web_color, prop_type_color, &property_value::m_color>(name, inherited, default_value, css_properties_member_offset);
+}
 
-	if(!is_reparse)
-	{
-		for(auto& el : m_children)
-		{
-			el->parse_styles();
-		}
-	}
+litehtml::string litehtml::html_tag::get_string_property(string_id name, bool inherited, const string& default_value, uint_ptr css_properties_member_offset) const
+{
+	return get_property_impl<string, prop_type_string, &property_value::m_string>(name, inherited, default_value, css_properties_member_offset);
 }
 
-int litehtml::html_tag::render( int x, int y, int max_width, bool second_pass )
+float litehtml::html_tag::get_number_property(string_id name, bool inherited, float default_value, uint_ptr css_properties_member_offset) const
 {
-	if (m_display == display_table || m_display == display_inline_table)
-	{
-		return render_table(x, y, max_width, second_pass);
-	}
+	return get_property_impl<float, prop_type_number, &property_value::m_number>(name, inherited, default_value, css_properties_member_offset);
+}
 
-	return render_box(x, y, max_width, second_pass);
+litehtml::string_vector litehtml::html_tag::get_string_vector_property(string_id name, bool inherited, const string_vector& default_value, uint_ptr css_properties_member_offset) const
+{
+	return get_property_impl<string_vector, prop_type_string_vector, &property_value::m_string_vector>(name, inherited, default_value, css_properties_member_offset);
 }
 
-bool litehtml::html_tag::is_white_space() const
+litehtml::int_vector litehtml::html_tag::get_int_vector_property(string_id name, bool inherited, const int_vector& default_value, uint_ptr css_properties_member_offset) const
 {
-	return false;
+	return get_property_impl<int_vector, prop_type_enum_item_vector, &property_value::m_enum_item_vector>(name, inherited, default_value, css_properties_member_offset);
 }
 
-int litehtml::html_tag::get_font_size() const
+litehtml::length_vector litehtml::html_tag::get_length_vector_property(string_id name, bool inherited, const length_vector& default_value, uint_ptr css_properties_member_offset) const
 {
-	return m_font_size;
+	return get_property_impl<length_vector, prop_type_length_vector, &property_value::m_length_vector>(name, inherited, default_value, css_properties_member_offset);
 }
 
-int litehtml::html_tag::get_base_line()
+litehtml::size_vector litehtml::html_tag::get_size_vector_property(string_id name, bool inherited, const size_vector& default_value, uint_ptr css_properties_member_offset) const
 {
-	if(is_replaced())
-	{
-		return 0;
-	}
-	int bl = 0;
-	if(!m_boxes.empty())
-	{
-		bl = m_boxes.back()->baseline() + content_margins_bottom();
-	}
-	return bl;
+	return get_property_impl<size_vector, prop_type_size_vector, &property_value::m_size_vector>(name, inherited, default_value, css_properties_member_offset);
 }
 
-void litehtml::html_tag::init()
+void litehtml::html_tag::compute_styles(bool recursive)
 {
-	if (m_display == display_table || m_display == display_inline_table)
+	const char* style = get_attr("style");
+	document::ptr doc = get_document();
+
+	if (style)
 	{
-		if (m_grid)
-		{
-			m_grid->clear();
-		}
-		else
-		{
-			m_grid = std::unique_ptr<table_grid>(new table_grid());
-		}
+		m_style.add(style, "", doc->container());
+	}
 
-		go_inside_table 		table_selector;
-		table_rows_selector		row_selector;
-		table_cells_selector	cell_selector;
+	m_style.subst_vars(this);
 
-		elements_iterator row_iter(shared_from_this(), &table_selector, &row_selector);
+	m_css.compute(this, doc);
 
-		element::ptr row = row_iter.next(false);
-		while (row)
+	if (recursive)
+	{
+		for (const auto& el : m_children)
 		{
-			m_grid->begin_row(row);
-
-			elements_iterator cell_iter(row, &table_selector, &cell_selector);
-			element::ptr cell = cell_iter.next();
-			while (cell)
-			{
-				m_grid->add_cell(cell);
-
-				cell = cell_iter.next(false);
-			}
-			row = row_iter.next(false);
+			el->compute_styles();
 		}
-
-		m_grid->finish();
 	}
+}
 
-	for (auto& el : m_children)
-	{
-		el->init();
-	}
+bool litehtml::html_tag::is_white_space() const
+{
+	return false;
+}
+
+int litehtml::html_tag::select(const string& selector)
+{
+	css_selector sel;
+	sel.parse(selector);
+	return select(sel, true);
 }
 
 int litehtml::html_tag::select(const css_selector& selector, bool apply_pseudo)
@@ -680,107 +511,34 @@ int litehtml::html_tag::select(const css_selector& selector, bool apply_pseudo)
 
 int litehtml::html_tag::select(const css_element_selector& selector, bool apply_pseudo)
 {
-	if(!selector.m_tag.empty() && selector.m_tag != _t("*"))
+	if(selector.m_tag != star_id && selector.m_tag != m_tag)
 	{
-		if(selector.m_tag != m_tag)
-		{
-			return select_no_match;
-		}
+		return select_no_match;
 	}
 
 	int res = select_match;
-	element::ptr el_parent = parent();
 
-	for(css_attribute_selector::vector::const_iterator i = selector.m_attrs.begin(); i != selector.m_attrs.end(); i++)
+	for(const auto& attr : selector.m_attrs)
 	{
-		const tchar_t* attr_value = get_attr(i->attribute.c_str());
-		switch(i->condition)
+		switch(attr.type)
 		{
-		case select_exists:
-			if(!attr_value)
-			{
-				return select_no_match;
-			}
-			break;
-		case select_equal:
-			if(!attr_value)
-			{
-				return select_no_match;
-			} else 
-			{
-				if(i->attribute == _t("class"))
-				{
-					const string_vector & tokens1 = m_class_values;
-					const string_vector & tokens2 = i->class_val;
-					bool found = true;
-					for(string_vector::const_iterator str1 = tokens2.begin(); str1 != tokens2.end() && found; str1++)
-					{
-						bool f = false;
-						for(string_vector::const_iterator str2 = tokens1.begin(); str2 != tokens1.end() && !f; str2++)
-						{
-							if( !t_strcasecmp(str1->c_str(), str2->c_str()) )
-							{
-								f = true;
-							}
-						}
-						if(!f)
-						{
-							found = false;
-						}
-					}
-					if(!found)
-					{
-						return select_no_match;
-					}
-				} else
-				{
-					if( t_strcasecmp(i->val.c_str(), attr_value) )
-					{
-						return select_no_match;
-					}
-				}
-			}
-			break;
-		case select_contain_str:
-			if(!attr_value)
-			{
-				return select_no_match;
-			} else if(!t_strstr(attr_value, i->val.c_str()))
-			{
-				return select_no_match;
-			}
-			break;
-		case select_start_str:
-			if(!attr_value)
-			{
-				return select_no_match;
-			} else if(t_strncmp(attr_value, i->val.c_str(), i->val.length()))
+		case select_class:
+			if (std::find(m_classes.begin(), m_classes.end(), attr.name) == m_classes.end())
 			{
 				return select_no_match;
 			}
 			break;
-		case select_end_str:
-			if(!attr_value)
+		case select_id:
+			if (attr.name != m_id)
 			{
 				return select_no_match;
-			} else if(t_strncmp(attr_value, i->val.c_str(), i->val.length()))
-			{
-				const tchar_t* s = attr_value + t_strlen(attr_value) - i->val.length() - 1;
-				if(s < attr_value)
-				{
-					return select_no_match;
-				}
-				if(i->val != s)
-				{
-					return select_no_match;
-				}
 			}
 			break;
 		case select_pseudo_element:
-			if(i->val == _t("after"))
+			if(attr.name == _after_)
 			{
 				res |= select_match_with_after;
-			} else if(i->val == _t("before"))
+			} else if(attr.name == _before_)
 			{
 				res |= select_match_with_before;
 			} else
@@ -791,3970 +549,1130 @@ int litehtml::html_tag::select(const css_element_selector& selector, bool apply_
 		case select_pseudo_class:
 			if(apply_pseudo)
 			{
-				if (!el_parent) return select_no_match;
-
-				tstring selector_param;
-				tstring	selector_name;
-
-				tstring::size_type begin	= i->val.find_first_of(_t('('));
-				tstring::size_type end		= (begin == tstring::npos) ? tstring::npos : find_close_bracket(i->val, begin);
-				if(begin != tstring::npos && end != tstring::npos)
+				if (select_pseudoclass(attr) == select_no_match)
 				{
-					selector_param = i->val.substr(begin + 1, end - begin - 1);
-				}
-				if(begin != tstring::npos)
-				{
-					selector_name = i->val.substr(0, begin);
-					litehtml::trim(selector_name);
-				} else
-				{
-					selector_name = i->val;
-				}
-
-				int selector = value_index(selector_name.c_str(), pseudo_class_strings);
-				
-				switch(selector)
-				{
-				case pseudo_class_only_child:
-					if (!el_parent->is_only_child(shared_from_this(), false))
-					{
-						return select_no_match;
-					}
-					break;
-				case pseudo_class_only_of_type:
-					if (!el_parent->is_only_child(shared_from_this(), true))
-					{
-						return select_no_match;
-					}
-					break;
-				case pseudo_class_first_child:
-					if (!el_parent->is_nth_child(shared_from_this(), 0, 1, false))
-					{
-						return select_no_match;
-					}
-					break;
-				case pseudo_class_first_of_type:
-					if (!el_parent->is_nth_child(shared_from_this(), 0, 1, true))
-					{
-						return select_no_match;
-					}
-					break;
-				case pseudo_class_last_child:
-					if (!el_parent->is_nth_last_child(shared_from_this(), 0, 1, false))
-					{
-						return select_no_match;
-					}
-					break;
-				case pseudo_class_last_of_type:
-					if (!el_parent->is_nth_last_child(shared_from_this(), 0, 1, true))
-					{
-						return select_no_match;
-					}
-					break;
-				case pseudo_class_nth_child:
-				case pseudo_class_nth_of_type:
-				case pseudo_class_nth_last_child:
-				case pseudo_class_nth_last_of_type:
-					{
-						if(selector_param.empty()) return select_no_match;
-
-						int num = 0;
-						int off = 0;
-
-						parse_nth_child_params(selector_param, num, off);
-						if(!num && !off) return select_no_match;
-						switch(selector)
-						{
-						case pseudo_class_nth_child:
-							if (!el_parent->is_nth_child(shared_from_this(), num, off, false))
-							{
-								return select_no_match;
-							}
-							break;
-						case pseudo_class_nth_of_type:
-							if (!el_parent->is_nth_child(shared_from_this(), num, off, true))
-							{
-								return select_no_match;
-							}
-							break;
-						case pseudo_class_nth_last_child:
-							if (!el_parent->is_nth_last_child(shared_from_this(), num, off, false))
-							{
-								return select_no_match;
-							}
-							break;
-						case pseudo_class_nth_last_of_type:
-							if (!el_parent->is_nth_last_child(shared_from_this(), num, off, true))
-							{
-								return select_no_match;
-							}
-							break;
-						}
-
-					}
-					break;
-				case pseudo_class_not:
-					{
-						css_element_selector sel;
-						sel.parse(selector_param);
-						if(select(sel, apply_pseudo))
-						{
-							return select_no_match;
-						}
-					}
-					break;
-				case pseudo_class_lang:
-					{
-						trim( selector_param );
-
-						if( !get_document()->match_lang( selector_param ) )
-						{
-							return select_no_match;
-						}
-					}
-					break;
-				default:
-					if(std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), i->val) == m_pseudo_classes.end())
-					{
-						return select_no_match;
-					}
-					break;
+					return select_no_match;
 				}
 			} else
 			{
 				res |= select_match_pseudo_class;
 			}
 			break;
+		default:
+			if (select_attribute(attr) == select_no_match)
+			{
+				return select_no_match;
+			}
 		}
 	}
 	return res;
 }
 
-litehtml::element::ptr litehtml::html_tag::find_ancestor(const css_selector& selector, bool apply_pseudo, bool* is_pseudo)
+int litehtml::html_tag::select_pseudoclass(const css_attribute_selector& sel)
 {
 	element::ptr el_parent = parent();
-	if (!el_parent)
-	{
-		return nullptr;
-	}
-	int res = el_parent->select(selector, apply_pseudo);
-	if(res != select_no_match)
+
+	switch (sel.name)
 	{
-		if(is_pseudo)
+	case _only_child_:
+		if (!el_parent || !el_parent->is_only_child(shared_from_this(), false))
 		{
-			if(res & select_match_pseudo_class)
-			{
-				*is_pseudo = true;
-			} else
-			{
-				*is_pseudo = false;
-			}
+			return select_no_match;
 		}
-		return el_parent;
-	}
-	return el_parent->find_ancestor(selector, apply_pseudo, is_pseudo);
-}
-
-int litehtml::html_tag::get_floats_height(element_float el_float) const
-{
-	if(is_floats_holder())
-	{
-		int h = 0;
-
-		bool process = false;
-
-		for(const auto& fb : m_floats_left)
+		break;
+	case _only_of_type_:
+		if (!el_parent || !el_parent->is_only_child(shared_from_this(), true))
 		{
-			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 select_no_match;
+		}
+		break;
+	case _first_child_:
+		if (!el_parent || !el_parent->is_nth_child(shared_from_this(), 0, 1, false))
+		{
+			return select_no_match;
+		}
+		break;
+	case _first_of_type_:
+		if (!el_parent || !el_parent->is_nth_child(shared_from_this(), 0, 1, true))
+		{
+			return select_no_match;
+		}
+		break;
+	case _last_child_:
+		if (!el_parent || !el_parent->is_nth_last_child(shared_from_this(), 0, 1, false))
+		{
+			return select_no_match;
+		}
+		break;
+	case _last_of_type_:
+		if (!el_parent || !el_parent->is_nth_last_child(shared_from_this(), 0, 1, true))
+		{
+			return select_no_match;
 		}
+		break;
+	case _nth_child_:
+	case _nth_of_type_:
+	case _nth_last_child_:
+	case _nth_last_of_type_:
+	{
+		if (!el_parent) return select_no_match;
 
+		int num = sel.a;
+		int off = sel.b;
+		if (!num && !off) return select_no_match;
 
-		for(const auto fb : m_floats_right)
+		switch (sel.name)
 		{
-			process = false;
-			switch(el_float)
+		case _nth_child_:
+			if (!el_parent->is_nth_child(shared_from_this(), num, off, false))
 			{
-			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;
+				return select_no_match;
 			}
-			if(process)
+			break;
+		case _nth_of_type_:
+			if (!el_parent->is_nth_child(shared_from_this(), num, off, true))
 			{
-				if(el_float == float_none)
-				{
-					h = std::max(h, fb.pos.bottom());
-				} else
-				{
-					h = std::max(h, fb.pos.top());
-				}
+				return select_no_match;
 			}
-		}
-
-		return h;
-	}
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		int h = el_parent->get_floats_height(el_float);
-		return h - m_pos.y;
-	}
-	return 0;
-}
-
-int litehtml::html_tag::get_left_floats_height() const
-{
-	if(is_floats_holder())
-	{
-		int h = 0;
-		if(!m_floats_left.empty())
-		{
-			for (const auto& fb : m_floats_left)
+			break;
+		case _nth_last_child_:
+			if (!el_parent->is_nth_last_child(shared_from_this(), num, off, false))
 			{
-				h = std::max(h, fb.pos.bottom());
+				return select_no_match;
 			}
-		}
-		return h;
-	}
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		int h = el_parent->get_left_floats_height();
-		return h - m_pos.y;
-	}
-	return 0;
-}
-
-int litehtml::html_tag::get_right_floats_height() const
-{
-	if(is_floats_holder())
-	{
-		int h = 0;
-		if(!m_floats_right.empty())
-		{
-			for(const auto& fb : m_floats_right)
+			break;
+		case _nth_last_of_type_:
+			if (!el_parent->is_nth_last_child(shared_from_this(), num, off, true))
 			{
-				h = std::max(h, fb.pos.bottom());
+				return select_no_match;
 			}
+			break;
 		}
-		return h;
-	}
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		int h = el_parent->get_right_floats_height();
-		return h - m_pos.y;
-	}
-	return 0;
-}
 
-int litehtml::html_tag::get_line_left( int y )
-{
-	if(is_floats_holder())
-	{
-		if(m_cahe_line_left.is_valid && m_cahe_line_left.hash == y)
+	}
+	break;
+	case _not_:
+		if (select(*sel.sel, true))
 		{
-			return m_cahe_line_left.val;
+			return select_no_match;
 		}
-
-		int w = 0;
-		for(const auto& fb : m_floats_left)
+		break;
+	case _lang_:
+		if (!get_document()->match_lang(sel.val))
 		{
-			if (y >= fb.pos.top() && y < fb.pos.bottom())
-			{
-				w = std::max(w, fb.pos.right());
-				if (w < fb.pos.right())
-				{
-					break;
-				}
-			}
+			return select_no_match;
 		}
-		m_cahe_line_left.set_value(y, w);
-		return w;
-	}
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		int w = el_parent->get_line_left(y + m_pos.y);
-		if (w < 0)
+		break;
+	default:
+		if (std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), sel.name) == m_pseudo_classes.end())
 		{
-			w = 0;
+			return select_no_match;
 		}
-		return w - (w ? m_pos.x : 0);
+		break;
 	}
-	return 0;
+	return select_match;
 }
 
-int litehtml::html_tag::get_line_right( int y, int def_right )
+int litehtml::html_tag::select_attribute(const css_attribute_selector& sel)
 {
-	if(is_floats_holder())
+	const char* attr_value = get_attr(_s(sel.name).c_str());
+
+	switch (sel.type)
 	{
-		if(m_cahe_line_right.is_valid && m_cahe_line_right.hash == y)
+	case select_exists:
+		if (!attr_value)
 		{
-			if(m_cahe_line_right.is_default)
-			{
-				return def_right;
-			} else
-			{
-				return std::min(m_cahe_line_right.val, def_right);
-			}
+			return select_no_match;
 		}
-
-		int w = def_right;
-		m_cahe_line_right.is_default = true;
-		for(const auto& fb : m_floats_right)
+		break;
+	case select_equal:
+		if (!attr_value || strcmp(attr_value, sel.val.c_str()))
 		{
-			if(y >= fb.pos.top() && y < fb.pos.bottom())
-			{
-				w = std::min(w, fb.pos.left());
-				m_cahe_line_right.is_default = false;
-				if(w > fb.pos.left())
-				{
-					break;
-				}
-			}
+			return select_no_match;
 		}
-		m_cahe_line_right.set_value(y, w);
-		return w;
-	}
-	element::ptr 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::html_tag::get_line_left_right( int y, int def_right, int& ln_left, int& ln_right )
-{
-	if(is_floats_holder())
-	{
-		ln_left		= get_line_left(y);
-		ln_right	= get_line_right(y, def_right);
-	} else
-	{
-		element::ptr el_parent = parent();
-		if (el_parent)
+		break;
+	case select_contain_str:
+		if (!attr_value || !strstr(attr_value, sel.val.c_str()))
 		{
-			el_parent->get_line_left_right(y + m_pos.y, def_right + m_pos.x, ln_left, ln_right);
+			return select_no_match;
 		}
-		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;
-			}
-        }
-	}
-}
-
-int litehtml::html_tag::fix_line_width( int max_width, element_float flt )
-{
-	int ret_width = 0;
-	if(!m_boxes.empty())
-	{
-		elements_vector els;
-		m_boxes.back()->get_elements(els);
-		bool was_cleared = false;
-		if(!els.empty() && els.front()->get_clear() != clear_none)
+		break;
+	case select_start_str:
+		if (!attr_value || strncmp(attr_value, sel.val.c_str(), sel.val.length()))
 		{
-			if(els.front()->get_clear() == clear_both)
-			{
-				was_cleared = true;
-			} else
-			{
-				if(	(flt == float_left	&& els.front()->get_clear() == clear_left) ||
-					(flt == float_right	&& els.front()->get_clear() == clear_right) )
-				{
-					was_cleared = true;
-				}
-			}
+			return select_no_match;
 		}
-
-		if(!was_cleared)
+		break;
+	case select_end_str:
+		if (!attr_value)
 		{
-			m_boxes.pop_back();
-
-			for(elements_vector::iterator i = els.begin(); i != els.end(); i++)
-			{
-				int rw = place_element((*i), max_width);
-				if(rw > ret_width)
-				{
-					ret_width = rw;
-				}
-			}
-		} else
+			return select_no_match;
+		}
+		else if (strncmp(attr_value, sel.val.c_str(), sel.val.length()))
 		{
-			int line_top = 0;
-			if(m_boxes.back()->get_type() == box_line)
-			{
-				line_top = m_boxes.back()->top();
-			} else
-			{
-				line_top = m_boxes.back()->bottom();
-			}
-
-			int line_left	= 0;
-			int line_right	= max_width;
-			get_line_left_right(line_top, max_width, line_left, line_right);
-
-			if(m_boxes.back()->get_type() == box_line)
+			const char* s = attr_value + strlen(attr_value) - sel.val.length() - 1;
+			if (s < attr_value)
 			{
-				if(m_boxes.size() == 1 && m_list_style_type != list_style_type_none && m_list_style_position == list_style_position_inside)
-				{
-					int sz_font = get_font_size();
-					line_left += sz_font;
-				}
-
-				if(m_css_text_indent.val() != 0)
-				{
-					bool line_box_found = false;
-					for(box::vector::iterator iter = m_boxes.begin(); iter < m_boxes.end(); iter++)
-					{
-						if((*iter)->get_type() == box_line)
-						{
-							line_box_found = true;
-							break;
-						}
-					}
-					if(!line_box_found)
-					{
-						line_left += m_css_text_indent.calc_percent(max_width);
-					}
-				}
-
+				return select_no_match;
 			}
-
-			elements_vector els;
-			m_boxes.back()->new_width(line_left, line_right, els);
-			for(auto& el : els)
+			if (sel.val != s)
 			{
-				int rw = place_element(el, max_width);
-				if(rw > ret_width)
-				{
-					ret_width = rw;
-				}
+				return select_no_match;
 			}
 		}
+		break;
 	}
-
-	return ret_width;
+	return select_match;
 }
 
-void litehtml::html_tag::add_float(const element::ptr &el, int x, int y)
+litehtml::element::ptr litehtml::html_tag::find_ancestor(const css_selector& selector, bool apply_pseudo, bool* is_pseudo)
 {
-	if(is_floats_holder())
+	element::ptr el_parent = parent();
+	if (!el_parent)
 	{
-		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->get_float();
-		fb.clear_floats	= el->get_clear();
-		fb.el			= el;
-
-		if(fb.float_side == float_left)
-		{
-			if(m_floats_left.empty())
-			{
-				m_floats_left.push_back(fb);
-			} else
-			{
-				bool inserted = false;
-				for(floated_box::vector::iterator 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_cahe_line_left.invalidate();
-		} else if(fb.float_side == float_right)
+		return nullptr;
+	}
+	int res = el_parent->select(selector, apply_pseudo);
+	if(res != select_no_match)
+	{
+		if(is_pseudo)
 		{
-			if(m_floats_right.empty())
+			if(res & select_match_pseudo_class)
 			{
-				m_floats_right.push_back(std::move(fb));
+				*is_pseudo = true;
 			} else
 			{
-				bool inserted = false;
-				for(floated_box::vector::iterator 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);
-				}
+				*is_pseudo = false;
 			}
-			m_cahe_line_right.invalidate();
-		}
-	} else
-	{
-		element::ptr el_parent = parent();
-		if (el_parent)
-		{
-			el_parent->add_float(el, x + m_pos.x, y + m_pos.y);
 		}
+		return el_parent;
 	}
+	return el_parent->find_ancestor(selector, apply_pseudo, is_pseudo);
 }
 
-int litehtml::html_tag::find_next_line_top( int top, int width, int def_right )
+void litehtml::html_tag::parse_attributes()
 {
-	if(is_floats_holder())
+	for(auto& el : m_children)
 	{
-		int new_top = top;
-		int_vector points;
-
-		for(const auto& fb : m_floats_left)
-		{
-			if(fb.pos.top() >= top)
-			{
-				if(find(points.begin(), points.end(), fb.pos.top()) == points.end())
-				{
-					points.push_back(fb.pos.top());
-				}
-			}
-			if (fb.pos.bottom() >= top)
-			{
-				if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end())
-				{
-					points.push_back(fb.pos.bottom());
-				}
-			}
-		}
-
-		for (const auto& fb : m_floats_right)
-		{
-			if (fb.pos.top() >= top)
-			{
-				if (find(points.begin(), points.end(), fb.pos.top()) == points.end())
-				{
-					points.push_back(fb.pos.top());
-				}
-			}
-			if (fb.pos.bottom() >= top)
-			{
-				if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end())
-				{
-					points.push_back(fb.pos.bottom());
-				}
-			}
-		}
-
-		if(!points.empty())
-		{
-			sort(points.begin(), points.end(), std::less<int>( ));
-			new_top = points.back();
-
-			for(auto pt : points)
-			{
-				int pos_left	= 0;
-				int pos_right	= def_right;
-				get_line_left_right(pt, def_right, pos_left, pos_right);
-
-				if(pos_right - pos_left >= width)
-				{
-					new_top = pt;
-					break;
-				}
-			}
-		}
-		return new_top;
+		el->parse_attributes();
 	}
-	element::ptr el_parent = parent();
-	if (el_parent)
+}
+
+void litehtml::html_tag::get_text( string& text )
+{
+	for (auto& el : m_children)
 	{
-		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;
+		el->get_text(text);
 	}
-	return 0;
 }
 
-void litehtml::html_tag::parse_background()
+bool litehtml::html_tag::is_body()  const
 {
-	// parse background-color
-	m_bg.m_color		= get_color(_t("background-color"), false, web_color(0, 0, 0, 0));
-
-	// parse background-position
-	const tchar_t* str = get_style_property(_t("background-position"), false, _t("0% 0%"));
-	if(str)
-	{
-		string_vector res;
-		split_string(str, res, _t(" \t"));
-		if(res.size() > 0)
-		{
-			if(res.size() == 1)
-			{
-				if( value_in_list(res[0].c_str(), _t("left;right;center")) )
-				{
-					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
-					m_bg.m_position.y.set_value(50, css_units_percentage);
-				} else if( value_in_list(res[0].c_str(), _t("top;bottom;center")) )
-				{
-					m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));
-					m_bg.m_position.x.set_value(50, css_units_percentage);
-				} else
-				{
-					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
-					m_bg.m_position.y.set_value(50, css_units_percentage);
-				}
-			} else
-			{
-				if(value_in_list(res[0].c_str(), _t("left;right")))
-				{
-					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
-					m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));
-				} else if(value_in_list(res[0].c_str(), _t("top;bottom")))
-				{
-					m_bg.m_position.x.fromString(res[1], _t("left;right;center"));
-					m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));
-				} else if(value_in_list(res[1].c_str(), _t("left;right")))
-				{
-					m_bg.m_position.x.fromString(res[1], _t("left;right;center"));
-					m_bg.m_position.y.fromString(res[0], _t("top;bottom;center"));
-				}else if(value_in_list(res[1].c_str(), _t("top;bottom")))
-				{
-					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
-					m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));
-				} else
-				{
-					m_bg.m_position.x.fromString(res[0], _t("left;right;center"));
-					m_bg.m_position.y.fromString(res[1], _t("top;bottom;center"));
-				}
-			}
-
-			if(m_bg.m_position.x.is_predefined())
-			{
-				switch(m_bg.m_position.x.predef())
-				{
-				case 0:
-					m_bg.m_position.x.set_value(0, css_units_percentage);
-					break;
-				case 1:
-					m_bg.m_position.x.set_value(100, css_units_percentage);
-					break;
-				case 2:
-					m_bg.m_position.x.set_value(50, css_units_percentage);
-					break;
-				}
-			}
-			if(m_bg.m_position.y.is_predefined())
-			{
-				switch(m_bg.m_position.y.predef())
-				{
-				case 0:
-					m_bg.m_position.y.set_value(0, css_units_percentage);
-					break;
-				case 1:
-					m_bg.m_position.y.set_value(100, css_units_percentage);
-					break;
-				case 2:
-					m_bg.m_position.y.set_value(50, css_units_percentage);
-					break;
-				}
-			}
-		} else
-		{
-			m_bg.m_position.x.set_value(0, css_units_percentage);
-			m_bg.m_position.y.set_value(0, css_units_percentage);
-		}
-	} else
-	{
-		m_bg.m_position.y.set_value(0, css_units_percentage);
-		m_bg.m_position.x.set_value(0, css_units_percentage);
-	}
-
-	str = get_style_property(_t("background-size"), false, _t("auto"));
-	if(str)
-	{
-		string_vector res;
-		split_string(str, res, _t(" \t"));
-		if(!res.empty())
-		{
-			m_bg.m_position.width.fromString(res[0], background_size_strings);
-			if(res.size() > 1)
-			{
-				m_bg.m_position.height.fromString(res[1], background_size_strings);
-			} else
-			{
-				m_bg.m_position.height.predef(background_size_auto);
-			}
-		} else
-		{
-			m_bg.m_position.width.predef(background_size_auto);
-			m_bg.m_position.height.predef(background_size_auto);
-		}
-	}
-
-	document::ptr doc = get_document();
-
-	doc->cvt_units(m_bg.m_position.x,		m_font_size);
-	doc->cvt_units(m_bg.m_position.y,		m_font_size);
-	doc->cvt_units(m_bg.m_position.width,	m_font_size);
-	doc->cvt_units(m_bg.m_position.height,	m_font_size);
-
-	// parse background_attachment
-	m_bg.m_attachment = (background_attachment) value_index(
-		get_style_property(_t("background-attachment"), false, _t("scroll")), 
-		background_attachment_strings, 
-		background_attachment_scroll);
-
-	// parse background_attachment
-	m_bg.m_repeat = (background_repeat) value_index(
-		get_style_property(_t("background-repeat"), false, _t("repeat")), 
-		background_repeat_strings, 
-		background_repeat_repeat);
-
-	// parse background_clip
-	m_bg.m_clip = (background_box) value_index(
-		get_style_property(_t("background-clip"), false, _t("border-box")), 
-		background_box_strings, 
-		background_box_border);
-
-	// parse background_origin
-	m_bg.m_origin = (background_box) value_index(
-		get_style_property(_t("background-origin"), false, _t("padding-box")), 
-		background_box_strings, 
-		background_box_content);
-
-	// parse background-image
-	css::parse_css_url(get_style_property(_t("background-image"), false, _t("")), m_bg.m_image);
-	m_bg.m_baseurl = get_style_property(_t("background-image-baseurl"), false, _t(""));
-
-	if(!m_bg.m_image.empty())
-	{
-		doc->container()->load_image(m_bg.m_image.c_str(), m_bg.m_baseurl.empty() ? 0 : m_bg.m_baseurl.c_str(), true);
-	}
-}
-
-void litehtml::html_tag::add_positioned(const element::ptr &el)
-{
-	if (m_el_position != element_position_static || (!have_parent()))
-	{
-		m_positioned.push_back(el);
-	} else
-	{
-		element::ptr el_parent = parent();
-		if (el_parent)
-		{
-			el_parent->add_positioned(el);
-		}
-	}
-}
-
-void litehtml::html_tag::calc_outlines( int parent_width )
-{
-	m_padding.left	= m_css_padding.left.calc_percent(parent_width);
-	m_padding.right	= m_css_padding.right.calc_percent(parent_width);
-
-	m_borders.left	= m_css_borders.left.width.calc_percent(parent_width);
-	m_borders.right	= m_css_borders.right.width.calc_percent(parent_width);
-
-	m_margins.left	= m_css_margins.left.calc_percent(parent_width);
-	m_margins.right	= m_css_margins.right.calc_percent(parent_width);
-
-	m_margins.top		= m_css_margins.top.calc_percent(parent_width);
-	m_margins.bottom	= m_css_margins.bottom.calc_percent(parent_width);
-
-	m_padding.top		= m_css_padding.top.calc_percent(parent_width);
-	m_padding.bottom	= m_css_padding.bottom.calc_percent(parent_width);
-}
-
-void litehtml::html_tag::calc_auto_margins(int parent_width)
-{
-	if (get_element_position() != element_position_absolute && (m_display == display_block || m_display == display_table))
-	{
-		if (m_css_margins.left.is_predefined() && m_css_margins.right.is_predefined())
-		{
-			int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right;
-			if (el_width <= parent_width)
-			{
-				m_margins.left = (parent_width - el_width) / 2;
-				m_margins.right = (parent_width - el_width) - m_margins.left;
-			}
-			else
-			{
-				m_margins.left = 0;
-				m_margins.right = 0;
-			}
-		}
-		else if (m_css_margins.left.is_predefined() && !m_css_margins.right.is_predefined())
-		{
-			int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.right;
-			m_margins.left = parent_width - el_width;
-			if (m_margins.left < 0) m_margins.left = 0;
-		}
-		else if (!m_css_margins.left.is_predefined() && m_css_margins.right.is_predefined())
-		{
-			int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.left;
-			m_margins.right = parent_width - el_width;
-			if (m_margins.right < 0) m_margins.right = 0;
-		}
-	}
-}
-
-void litehtml::html_tag::parse_attributes()
-{
-	for(auto& el : m_children)
-	{
-		el->parse_attributes();
-	}
-}
-
-void litehtml::html_tag::get_text( tstring& text )
-{
-	for (auto& el : m_children)
-	{
-		el->get_text(text);
-	}
-}
-
-bool litehtml::html_tag::is_body()  const
-{
-	return false;
-}
-
-void litehtml::html_tag::set_data( const tchar_t* data )
-{
-
-}
-
-void litehtml::html_tag::get_inline_boxes( position::vector& boxes )
-{
-	litehtml::box* old_box = 0;
-	position pos;
-	for(auto& el : m_children)
-	{
-		if(!el->skip())
-		{
-			if(el->m_box)
-			{
-				if(el->m_box != old_box)
-				{
-					if(old_box)
-					{
-						if(boxes.empty())
-						{
-							pos.x		-= m_padding.left + m_borders.left;
-							pos.width	+= m_padding.left + m_borders.left;
-						}
-						boxes.push_back(pos);
-					}
-					old_box		= el->m_box;
-					pos.x		= el->left() + el->margin_left();
-					pos.y		= el->top() - m_padding.top - m_borders.top;
-					pos.width	= 0;
-					pos.height	= 0;
-				}
-				pos.width	= el->right() - pos.x - el->margin_right() - el->margin_left();
-				pos.height	= std::max(pos.height, el->height() + m_padding.top + m_padding.bottom + m_borders.top + m_borders.bottom);
-			} else if(el->get_display() == display_inline)
-			{
-				position::vector sub_boxes;
-				el->get_inline_boxes(sub_boxes);
-				if(!sub_boxes.empty())
-				{
-					sub_boxes.rbegin()->width += el->margin_right();
-					if(boxes.empty())
-					{
-						if(m_padding.left + m_borders.left > 0)
-						{
-							position padding_box = (*sub_boxes.begin());
-							padding_box.x		-= m_padding.left + m_borders.left + el->margin_left();
-							padding_box.width	= m_padding.left + m_borders.left + el->margin_left();
-							boxes.push_back(padding_box);
-						}
-					}
-
-					sub_boxes.rbegin()->width += el->margin_right();
-
-					boxes.insert(boxes.end(), sub_boxes.begin(), sub_boxes.end());
-				}
-			}
-		}
-	}
-	if(pos.width || pos.height)
-	{
-		if(boxes.empty())
-		{
-			pos.x		-= m_padding.left + m_borders.left;
-			pos.width	+= m_padding.left + m_borders.left;
-		}
-		boxes.push_back(pos);
-	}
-	if(!boxes.empty())
-	{
-		if(m_padding.right + m_borders.right > 0)
-		{
-			boxes.back().width += m_padding.right + m_borders.right;
-		}
-	}
-}
-
-bool litehtml::html_tag::on_mouse_over()
-{
-	bool ret = false;
-
-	element::ptr el = shared_from_this();
-	while(el)
-	{
-		if(el->set_pseudo_class(_t("hover"), true))
-		{
-			ret = true;
-		}
-		el = el->parent();
-	}
-
-	return ret;
-}
-
-bool litehtml::html_tag::find_styles_changes( position::vector& redraw_boxes, int x, int y )
-{
-	if(m_display == display_inline_text)
-	{
-		return false;
-	}
-
-	bool ret = false;
-	bool apply = false;
-	for (used_selector::vector::iterator iter = m_used_styles.begin(); iter != m_used_styles.end() && !apply; iter++)
-	{
-		if((*iter)->m_selector->is_media_valid())
-		{
-			int res = select(*((*iter)->m_selector), true);
-			if( (res == select_no_match && (*iter)->m_used) || (res == select_match && !(*iter)->m_used) )
-			{
-				apply = true;
-			}
-		}
-	}
-
-	if(apply)
-	{
-		if(m_display == display_inline ||  m_display == display_table_row)
-		{
-			position::vector boxes;
-			get_inline_boxes(boxes);
-			for(position::vector::iterator pos = boxes.begin(); pos != boxes.end(); pos++)
-			{
-				pos->x	+= x;
-				pos->y	+= y;
-				redraw_boxes.push_back(*pos);
-			}
-		} else
-		{
-			position pos = m_pos;
-			if(m_el_position != element_position_fixed)
-			{
-				pos.x += x;
-				pos.y += y;
-			}
-			pos += m_padding;
-			pos += m_borders;
-			redraw_boxes.push_back(pos);
-		}
-
-		ret = true;
-		refresh_styles();
-		parse_styles();
-	}
-	for (auto& el : m_children)
-	{
-		if(!el->skip())
-		{
-			if(m_el_position != element_position_fixed)
-			{
-				if(el->find_styles_changes(redraw_boxes, x + m_pos.x, y + m_pos.y))
-				{
-					ret = true;
-				}
-			} else
-			{
-				if(el->find_styles_changes(redraw_boxes, m_pos.x, m_pos.y))
-				{
-					ret = true;
-				}
-			}
-		}
-	}
-	return ret;
-}
-
-bool litehtml::html_tag::on_mouse_leave()
-{
-	bool ret = false;
-
-	element::ptr el = shared_from_this();
-	while(el)
-	{
-		if(el->set_pseudo_class(_t("hover"), false))
-		{
-			ret = true;
-		}
-		if(el->set_pseudo_class(_t("active"), false))
-		{
-			ret = true;
-		}
-		el = el->parent();
-	}
-
-	return ret;
-}
-
-bool litehtml::html_tag::on_lbutton_down()
-{
-    bool ret = false;
-
-	element::ptr el = shared_from_this();
-    while (el)
-    {
-        if (el->set_pseudo_class(_t("active"), true))
-        {
-            ret = true;
-        }
-        el = el->parent();
-    }
-
-    return ret;
-}
-
-bool litehtml::html_tag::on_lbutton_up()
-{
-	bool ret = false;
-
-	element::ptr el = shared_from_this();
-    while (el)
-    {
-        if (el->set_pseudo_class(_t("active"), false))
-        {
-            ret = true;
-        }
-        el = el->parent();
-    }
-
-    on_click();
-
-	return ret;
-}
-
-void litehtml::html_tag::on_click()
-{
-	if (have_parent())
-	{
-		element::ptr el_parent = parent();
-		if (el_parent)
-		{
-			el_parent->on_click();
-		}
-	}
-}
-
-const litehtml::tchar_t* litehtml::html_tag::get_cursor()
-{
-	return get_style_property(_t("cursor"), true, 0);
-}
-
-static const int font_size_table[8][7] =
-{
-	{ 9,    9,     9,     9,    11,    14,    18},
-	{ 9,    9,     9,    10,    12,    15,    20},
-	{ 9,    9,     9,    11,    13,    17,    22},
-	{ 9,    9,    10,    12,    14,    18,    24},
-	{ 9,    9,    10,    13,    16,    20,    26},
-	{ 9,    9,    11,    14,    17,    21,    28},
-	{ 9,   10,    12,    15,    17,    23,    30},
-	{ 9,   10,    13,    16,    18,    24,    32}
-};
-
-
-void litehtml::html_tag::init_font()
-{
-	// initialize font size
-	const tchar_t* str = get_style_property(_t("font-size"), false, 0);
-
-	int parent_sz = 0;
-	int doc_font_size = get_document()->container()->get_default_font_size();
-	element::ptr el_parent = parent();
-	if (el_parent)
-	{
-		parent_sz = el_parent->get_font_size();
-	} else
-	{
-		parent_sz = doc_font_size;
-	}
-
-
-	if(!str)
-	{
-		m_font_size = parent_sz;
-	} else
-	{
-		m_font_size = parent_sz;
-
-		css_length sz;
-		sz.fromString(str, font_size_strings);
-		if(sz.is_predefined())
-		{
-			int idx_in_table = doc_font_size - 9;
-			if(idx_in_table >= 0 && idx_in_table <= 7)
-			{
-				if(sz.predef() >= fontSize_xx_small && sz.predef() <= fontSize_xx_large)
-				{
-					m_font_size = font_size_table[idx_in_table][sz.predef()];
-				} else
-				{
-					m_font_size = doc_font_size;
-				}
-			} else			
-			{
-				switch(sz.predef())
-				{
-				case fontSize_xx_small:
-					m_font_size = doc_font_size * 3 / 5;
-					break;
-				case fontSize_x_small:
-					m_font_size = doc_font_size * 3 / 4;
-					break;
-				case fontSize_small:
-					m_font_size = doc_font_size * 8 / 9;
-					break;
-				case fontSize_large:
-					m_font_size = doc_font_size * 6 / 5;
-					break;
-				case fontSize_x_large:
-					m_font_size = doc_font_size * 3 / 2;
-					break;
-				case fontSize_xx_large:
-					m_font_size = doc_font_size * 2;
-					break;
-				default:
-					m_font_size = doc_font_size;
-					break;
-				}
-			}
-		} else
-		{
-			if(sz.units() == css_units_percentage)
-			{
-				m_font_size = sz.calc_percent(parent_sz);
-			} else if(sz.units() == css_units_none)
-			{
-				m_font_size = parent_sz;
-			} else
-			{
-				m_font_size = get_document()->cvt_units(sz, parent_sz);
-			}
-		}
-	}
-
-	// initialize font
-	const tchar_t* name			= get_style_property(_t("font-family"),		true,	_t("inherit"));
-	const tchar_t* weight		= get_style_property(_t("font-weight"),		true,	_t("normal"));
-	const tchar_t* style		= get_style_property(_t("font-style"),		true,	_t("normal"));
-	const tchar_t* decoration	= get_style_property(_t("text-decoration"),	true,	_t("none"));
-
-	m_font = get_document()->get_font(name, m_font_size, weight, style, decoration, &m_font_metrics);
-}
-
-bool litehtml::html_tag::is_break() const
-{
-	return false;
-}
-
-void litehtml::html_tag::set_tagName( const tchar_t* tag )
-{
-	tstring s_val = tag;
-	for(size_t i = 0; i < s_val.length(); i++)
-	{
-		s_val[i] = std::tolower(s_val[i], std::locale::classic());
-	}
-	m_tag = s_val;
-}
-
-void litehtml::html_tag::draw_background( uint_ptr hdc, int x, int y, const position* clip )
-{
-	position pos = m_pos;
-	pos.x	+= x;
-	pos.y	+= y;
-
-	position el_pos = pos;
-	el_pos += m_padding;
-	el_pos += m_borders;
-
-	if(m_display != display_inline && m_display != display_table_row)
-	{
-		if(el_pos.does_intersect(clip))
-		{
-			const background* bg = get_background();
-			if(bg)
-			{
-				background_paint bg_paint;
-				init_background_paint(pos, bg_paint, bg);
-
-				get_document()->container()->draw_background(hdc, bg_paint);
-			}
-			position border_box = pos;
-			border_box += m_padding;
-			border_box += m_borders;
-
-			borders bdr = m_css_borders;
-			bdr.radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
-
-			get_document()->container()->draw_borders(hdc, bdr, border_box, have_parent() ? false : true);
-		}
-	} else
-	{
-		const background* bg = get_background();
-
-		position::vector boxes;
-		get_inline_boxes(boxes);
-
-		background_paint bg_paint;
-		position content_box;
-
-		for(position::vector::iterator box = boxes.begin(); box != boxes.end(); box++)
-		{
-			box->x	+= x;
-			box->y	+= y;
-
-			if(box->does_intersect(clip))
-			{
-				content_box = *box;
-				content_box -= m_borders;
-				content_box -= m_padding;
-
-				if(bg)
-				{
-					init_background_paint(content_box, bg_paint, bg);
-				}
-
-				css_borders bdr;
-
-				// set left borders radius for the first box
-				if(box == boxes.begin())
-				{
-					bdr.radius.bottom_left_x	= m_css_borders.radius.bottom_left_x;
-					bdr.radius.bottom_left_y	= m_css_borders.radius.bottom_left_y;
-					bdr.radius.top_left_x		= m_css_borders.radius.top_left_x;
-					bdr.radius.top_left_y		= m_css_borders.radius.top_left_y;
-				}
-
-				// set right borders radius for the last box
-				if(box == boxes.end() - 1)
-				{
-					bdr.radius.bottom_right_x	= m_css_borders.radius.bottom_right_x;
-					bdr.radius.bottom_right_y	= m_css_borders.radius.bottom_right_y;
-					bdr.radius.top_right_x		= m_css_borders.radius.top_right_x;
-					bdr.radius.top_right_y		= m_css_borders.radius.top_right_y;
-				}
-
-				
-				bdr.top		= m_css_borders.top;
-				bdr.bottom	= m_css_borders.bottom;
-				if(box == boxes.begin())
-				{
-					bdr.left	= m_css_borders.left;
-				}
-				if(box == boxes.end() - 1)
-				{
-					bdr.right	= m_css_borders.right;
-				}
-
-
-				if(bg)
-				{
-					bg_paint.border_radius = bdr.radius.calc_percents(bg_paint.border_box.width, bg_paint.border_box.width);
-					get_document()->container()->draw_background(hdc, bg_paint);
-				}
-				borders b = bdr;
-				b.radius = bdr.radius.calc_percents(box->width, box->height);
-				get_document()->container()->draw_borders(hdc, b, *box, false);
-			}
-		}
-	}
-}
-
-int litehtml::html_tag::render_inline(const element::ptr &container, int max_width)
-{
-	int ret_width = 0;
-	int rw = 0;
-
-	white_space ws = get_white_space();
-	bool skip_spaces = false;
-	if (ws == white_space_normal ||
-		ws == white_space_nowrap ||
-		ws == white_space_pre_line)
-	{
-		skip_spaces = true;
-	}
-	bool was_space = false;
-
-	for (auto& el : m_children)
-	{
-		// skip spaces to make rendering a bit faster
-		if (skip_spaces)
-		{
-			if (el->is_white_space())
-			{
-				if (was_space)
-				{
-					el->skip(true);
-					continue;
-				}
-				else
-				{
-					was_space = true;
-				}
-			}
-			else
-			{
-				was_space = false;
-			}
-		}
-
-		rw = container->place_element( el, max_width );
-		if(rw > ret_width)
-		{
-			ret_width = rw;
-		}
-	}
-	return ret_width;
-}
-
-int litehtml::html_tag::place_element(const element::ptr &el, int max_width)
-{
-	if(el->get_display() == display_none) return 0;
-
-	if(el->get_display() == display_inline)
-	{
-		return el->render_inline(shared_from_this(), max_width);
-	}
-
-	element_position el_position = el->get_element_position();
-
-	if(el_position == element_position_absolute || el_position == element_position_fixed)
-	{
-		int line_top = 0;
-		if(!m_boxes.empty())
-		{
-			if(m_boxes.back()->get_type() == box_line)
-			{
-				line_top = m_boxes.back()->top();
-				if(!m_boxes.back()->is_empty())
-				{
-					line_top += line_height();
-				}
-			} else
-			{
-				line_top = m_boxes.back()->bottom();
-			}
-		}
-
-		el->render(0, line_top, max_width);
-		el->m_pos.x	+= el->content_margins_left();
-		el->m_pos.y	+= el->content_margins_top();
-
-		return 0;
-	}
-
-	int ret_width = 0;
-
-	switch(el->get_float())
-	{
-	case float_left:
-		{
-			int line_top = 0;
-			if(!m_boxes.empty())
-			{
-				if(m_boxes.back()->get_type() == box_line)
-				{
-					line_top = m_boxes.back()->top();
-				} else
-				{
-					line_top = m_boxes.back()->bottom();
-				}
-			}
-			line_top		= get_cleared_top(el, line_top);
-			int line_left	= 0;
-			int line_right	= max_width;
-			get_line_left_right(line_top, max_width, line_left, line_right);
-
-			el->render(line_left, line_top, line_right);
-			if(el->right() > line_right)
-			{
-				int new_top = find_next_line_top(el->top(), el->width(), max_width);
-				el->m_pos.x = get_line_left(new_top) + el->content_margins_left();
-				el->m_pos.y = new_top + el->content_margins_top();
-			}
-			add_float(el, 0, 0);
-			ret_width = fix_line_width(max_width, float_left);
-			if(!ret_width)
-			{
-				ret_width = el->right();
-			}
-		}
-		break;
-	case float_right:
-		{
-			int line_top = 0;
-			if(!m_boxes.empty())
-			{
-				if(m_boxes.back()->get_type() == box_line)
-				{
-					line_top = m_boxes.back()->top();
-				} else
-				{
-					line_top = m_boxes.back()->bottom();
-				}
-			}
-			line_top		= get_cleared_top(el, line_top);
-			int line_left	= 0;
-			int line_right	= max_width;
-			get_line_left_right(line_top, max_width, line_left, line_right);
-
-			el->render(0, line_top, line_right);
-
-			if(line_left + el->width() > line_right)
-			{
-				int new_top = find_next_line_top(el->top(), el->width(), max_width);
-				el->m_pos.x = get_line_right(new_top, max_width) - el->width() + el->content_margins_left();
-				el->m_pos.y = new_top + el->content_margins_top();
-			} else
-			{
-				el->m_pos.x = line_right - el->width() + el->content_margins_left();
-			}
-			add_float(el, 0, 0);
-			ret_width = fix_line_width(max_width, float_right);
-
-			if(!ret_width)
-			{
-				line_left	= 0;
-				line_right	= max_width;
-				get_line_left_right(line_top, max_width, line_left, line_right);
-
-				ret_width = ret_width + (max_width - line_right);
-			}
-		}
-		break;
-	default:
-		{
-			line_context line_ctx;
-			line_ctx.top = 0;
-			if (!m_boxes.empty())
-			{
-				line_ctx.top = m_boxes.back()->top();
-			}
-			line_ctx.left = 0;
-			line_ctx.right = max_width;
-			line_ctx.fix_top();
-			get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
-
-			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:		
-				if(el->is_replaced() || el->is_floats_holder())
-				{
-					element::ptr el_parent = el->parent();
-					el->m_pos.width = el->get_css_width().calc_percent(line_ctx.right - line_ctx.left);
-					el->m_pos.height = el->get_css_height().calc_percent(el_parent ? el_parent->m_pos.height : 0);
-				}
-				el->calc_outlines(line_ctx.right - line_ctx.left);
-				break;
-			case display_inline_text:
-				{
-					litehtml::size sz;
-					el->get_content_size(sz, line_ctx.right);
-					el->m_pos = sz;
-				}
-				break;
-			default:
-				ret_width = 0;
-				break;
-			}
-
-			bool add_box = true;
-			if(!m_boxes.empty())
-			{
-				if(m_boxes.back()->can_hold(el, m_white_space))
-				{
-					add_box = false;
-				}
-			}
-			if(add_box)
-			{
-				new_box(el, max_width, line_ctx);
-			} else if(!m_boxes.empty())
-			{
-				line_ctx.top = m_boxes.back()->top();
-			}
-
-			if (line_ctx.top != line_ctx.calculatedTop)
-			{
-				line_ctx.left = 0;
-				line_ctx.right = max_width;
-				line_ctx.fix_top();
-				get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
-			}
-
-			if(!el->is_inline_box())
-			{
-				if(m_boxes.size() == 1)
-				{
-					if(collapse_top_margin())
-					{
-						int shift = el->margin_top();
-						if(shift >= 0)
-						{
-							line_ctx.top -= shift;
-							m_boxes.back()->y_shift(-shift);
-						}
-					}
-				} else
-				{
-					int shift = 0;
-					int prev_margin = m_boxes[m_boxes.size() - 2]->bottom_margin();
-
-					if(prev_margin > el->margin_top())
-					{
-						shift = el->margin_top();
-					} else
-					{
-						shift = prev_margin;
-					}
-					if(shift >= 0)
-					{
-						line_ctx.top -= shift;
-						m_boxes.back()->y_shift(-shift);
-					}
-				}
-			}
-
-			switch(el->get_display())
-			{
-			case display_table:
-			case display_list_item:
-				ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.width());
-				break;
-			case display_block:
-			case display_table_cell:
-			case display_table_caption:
-			case display_table_row:
-				if(el->is_replaced() || el->is_floats_holder())
-				{
-					ret_width = el->render(line_ctx.left, line_ctx.top, line_ctx.width()) + line_ctx.left + (max_width - line_ctx.right);
-				} else
-				{
-					ret_width = el->render(0, line_ctx.top, max_width);
-				}
-				break;
-			default:
-				ret_width = 0;
-				break;
-			}
-
-			m_boxes.back()->add_element(el);
-
-			if(el->is_inline_box() && !el->skip())
-			{
-				ret_width = el->right() + (max_width - line_ctx.right);
-			}
-		}
-		break;
-	}
-
-	return ret_width;
-}
-
-bool litehtml::html_tag::set_pseudo_class( const tchar_t* pclass, bool add )
-{
-	bool ret = false;
-	if(add)
-	{
-		if(std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), pclass) == m_pseudo_classes.end())
-		{
-			m_pseudo_classes.push_back(pclass);
-			ret = true;
-		}
-	} else
-	{
-		string_vector::iterator pi = std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), pclass);
-		if(pi != m_pseudo_classes.end())
-		{
-			m_pseudo_classes.erase(pi);
-			ret = true;
-		}
-	}
-	return ret;
-}
-
-bool litehtml::html_tag::set_class( const tchar_t* pclass, bool add )
-{
-	string_vector classes;
-	bool changed = false;
-
-	split_string( pclass, classes, _t(" ") );
-
-	if(add)
-	{
-		for( auto & _class : classes  )
-		{
-			if(std::find(m_class_values.begin(), m_class_values.end(), _class) == m_class_values.end())
-			{
-				m_class_values.push_back( std::move( _class ) );
-				changed = true;
-			}
-		}
-	} else
-	{
-		for( const auto & _class : classes )
-		{
-			auto end = std::remove(m_class_values.begin(), m_class_values.end(), _class);
-
-			if(end != m_class_values.end())
-			{
-				m_class_values.erase(end, m_class_values.end());
-				changed = true;
-			}
-		}
-	}
-
-	if( changed )
-	{
-		tstring class_string;
-		join_string(class_string, m_class_values, _t(" "));
-		set_attr(_t("class"), class_string.c_str());
-
-		return true;
-	}
-	else
-	{
-		return false;
-	}
-
-}
-
-int litehtml::html_tag::line_height() const
-{
-	return m_line_height;
-}
-
-bool litehtml::html_tag::is_replaced() const
-{
-	return false;
-}
-
-int litehtml::html_tag::finish_last_box(bool end_of_render)
-{
-	int line_top = 0;
-
-	if(!m_boxes.empty())
-	{
-		m_boxes.back()->finish(end_of_render);
-
-		if(m_boxes.back()->is_empty())
-		{
-			line_top = m_boxes.back()->top();
-			m_boxes.pop_back();
-		}
-
-		if(!m_boxes.empty())
-		{
-			line_top = m_boxes.back()->bottom();
-		}
-	}
-	return line_top;
-}
-
-int litehtml::html_tag::new_box(const element::ptr &el, int max_width, line_context& line_ctx)
-{
-	line_ctx.top = get_cleared_top(el, finish_last_box());
-
-	line_ctx.left = 0;
-	line_ctx.right = max_width;
-	line_ctx.fix_top();
-	get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
-
-	if(el->is_inline_box() || el->is_floats_holder())
-	{
-		if (el->width() > line_ctx.right - line_ctx.left)
-		{
-			line_ctx.top = find_next_line_top(line_ctx.top, el->width(), max_width);
-			line_ctx.left = 0;
-			line_ctx.right = max_width;
-			line_ctx.fix_top();
-			get_line_left_right(line_ctx.top, max_width, line_ctx.left, line_ctx.right);
-		}
-	}
-
-	int first_line_margin = 0;
-	if(m_boxes.empty() && m_list_style_type != list_style_type_none && m_list_style_position == list_style_position_inside)
-	{
-		int sz_font = get_font_size();
-		first_line_margin = sz_font;
-	}
-
-	if(el->is_inline_box())
-	{
-		int text_indent = 0;
-		if(m_css_text_indent.val() != 0)
-		{
-			bool line_box_found = false;
-			for(box::vector::iterator iter = m_boxes.begin(); iter != m_boxes.end(); iter++)
-			{
-				if((*iter)->get_type() == box_line)
-				{
-					line_box_found = true;
-					break;
-				}
-			}
-			if(!line_box_found)
-			{
-				text_indent = m_css_text_indent.calc_percent(max_width);
-			}
-		}
-
-		font_metrics fm;
-		get_font(&fm);
-		m_boxes.emplace_back(std::unique_ptr<line_box>(new line_box(line_ctx.top, line_ctx.left + first_line_margin + text_indent, line_ctx.right, line_height(), fm, m_text_align)));
-	} else
-	{
-		m_boxes.emplace_back(std::unique_ptr<block_box>(new block_box(line_ctx.top, line_ctx.left, line_ctx.right)));
-	}
-
-	return line_ctx.top;
-}
-
-int litehtml::html_tag::get_cleared_top(const element::ptr &el, int line_top) const
-{
-	switch(el->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();
-			if(fh && fh > line_top)
-			{
-				line_top = fh;
-			}
-		}
-		break;
-	default:
-		if(el->get_float() != float_none)
-		{
-			int fh = get_floats_height(el->get_float());
-			if(fh && fh > line_top)
-			{
-				line_top = fh;
-			}
-		}
-		break;
-	}
-	return line_top;
-}
-
-litehtml::style_display litehtml::html_tag::get_display() const
-{
-	return m_display;
-}
-
-litehtml::element_float litehtml::html_tag::get_float() const
-{
-	return m_float;
-}
-
-bool litehtml::html_tag::is_floats_holder() const
-{
-	if(	m_display == display_inline_block || 
-		m_display == display_table_cell || 
-		!have_parent() ||
-		is_body() || 
-		m_float != float_none ||
-		m_el_position == element_position_absolute ||
-		m_el_position == element_position_fixed ||
-		m_overflow > overflow_visible)
-	{
-		return true;
-	}
-	return false;
-}
-
-bool litehtml::html_tag::is_first_child_inline(const element::ptr& el) const
-{
-	if(!m_children.empty())
-	{
-		for (const auto& this_el : m_children)
-		{
-			if (!this_el->is_white_space())
-			{
-				if (el == this_el)
-				{
-					return true;
-				}
-				if (this_el->get_display() == display_inline)
-				{
-					if (this_el->have_inline_child())
-					{
-						return false;
-					}
-				} else
-				{
-					return false;
-				}
-			}
-		}
-	}
-	return false;
-}
-
-bool litehtml::html_tag::is_last_child_inline(const element::ptr& el)
-{
-	if(!m_children.empty())
-	{
-		for (auto this_el = m_children.rbegin(); this_el < m_children.rend(); ++this_el)
-		{
-			if (!(*this_el)->is_white_space())
-			{
-				if (el == (*this_el))
-				{
-					return true;
-				}
-				if ((*this_el)->get_display() == display_inline)
-				{
-					if ((*this_el)->have_inline_child())
-					{
-						return false;
-					}
-				} else
-				{
-					return false;
-				}
-			}
-		}
-	}
-	return false;
-}
-
-litehtml::white_space litehtml::html_tag::get_white_space() const
-{
-	return m_white_space;
-}
-
-litehtml::vertical_align litehtml::html_tag::get_vertical_align() const
-{
-	return m_vertical_align;
-}
-
-litehtml::css_length litehtml::html_tag::get_css_left() const
-{
-	return m_css_offsets.left;
-}
-
-litehtml::css_length litehtml::html_tag::get_css_right() const
-{
-	return m_css_offsets.right;
-}
-
-litehtml::css_length litehtml::html_tag::get_css_top() const
-{
-	return m_css_offsets.top;
-}
-
-litehtml::css_length litehtml::html_tag::get_css_bottom() const
-{
-	return m_css_offsets.bottom;
-}
-
-
-litehtml::css_offsets litehtml::html_tag::get_css_offsets() const
-{
-	return m_css_offsets;
-}
-
-litehtml::element_clear litehtml::html_tag::get_clear() const
-{
-	return m_clear;
-}
-
-litehtml::css_length litehtml::html_tag::get_css_width() const
-{
-	return m_css_width;
-}
-
-litehtml::css_length litehtml::html_tag::get_css_height() const
-{
-	return m_css_height;
-}
-
-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::set_css_width( css_length& w )
-{
-	m_css_width = w;
-}
-
-void litehtml::html_tag::apply_vertical_align()
-{
-	if(!m_boxes.empty())
-	{
-		int add = 0;
-		int content_height	= m_boxes.back()->bottom();
-
-		if(m_pos.height > content_height)
-		{
-			switch(m_vertical_align)
-			{
-			case va_middle:
-				add = (m_pos.height - content_height) / 2;
-				break;
-			case va_bottom:
-				add = m_pos.height - content_height;
-				break;
-			default:
-				add = 0;
-				break;
-			}
-		}
-
-		if(add)
-		{
-			for(size_t i = 0; i < m_boxes.size(); i++)
-			{
-				m_boxes[i]->y_shift(add);
-			}
-		}
-	}
-}
-
-litehtml::element_position litehtml::html_tag::get_element_position(css_offsets* offsets) const
-{
-	if(offsets && m_el_position != element_position_static)
-	{
-		*offsets = m_css_offsets;
-	}
-	return m_el_position;
-}
-
-void litehtml::html_tag::init_background_paint(position pos, background_paint &bg_paint, const background* bg)
-{
-	if(!bg) return;
-
-	bg_paint = *bg;
-	position content_box	= pos;
-	position padding_box	= pos;
-	padding_box += m_padding;
-	position border_box		= padding_box;
-	border_box += m_borders;
-
-	switch(bg->m_clip)
-	{
-	case litehtml::background_box_padding:
-		bg_paint.clip_box = padding_box;
-		break;
-	case litehtml::background_box_content:
-		bg_paint.clip_box = content_box;
-		break;
-	default:
-		bg_paint.clip_box = border_box;
-		break;
-	}
-
-	switch(bg->m_origin)
-	{
-	case litehtml::background_box_border:
-		bg_paint.origin_box = border_box;
-		break;
-	case litehtml::background_box_content:
-		bg_paint.origin_box = content_box;
-		break;
-	default:
-		bg_paint.origin_box = padding_box;
-		break;
-	}
-
-	if(!bg_paint.image.empty())
-	{
-		get_document()->container()->get_image_size(bg_paint.image.c_str(), bg_paint.baseurl.c_str(), bg_paint.image_size);
-		if(bg_paint.image_size.width && bg_paint.image_size.height)
-		{
-			litehtml::size img_new_sz = bg_paint.image_size;
-			double img_ar_width		= (double) bg_paint.image_size.width / (double) bg_paint.image_size.height;
-			double img_ar_height	= (double) bg_paint.image_size.height / (double) bg_paint.image_size.width;
-
-
-			if(bg->m_position.width.is_predefined())
-			{
-				switch(bg->m_position.width.predef())
-				{
-				case litehtml::background_size_contain:
-					if( (int) ((double) bg_paint.origin_box.width * img_ar_height) <= bg_paint.origin_box.height )
-					{
-						img_new_sz.width = bg_paint.origin_box.width;
-						img_new_sz.height	= (int) ((double) bg_paint.origin_box.width * img_ar_height);
-					} else
-					{
-						img_new_sz.height = bg_paint.origin_box.height;
-						img_new_sz.width	= (int) ((double) bg_paint.origin_box.height * img_ar_width);
-					}
-					break;
-				case litehtml::background_size_cover:
-					if( (int) ((double) bg_paint.origin_box.width * img_ar_height) >= bg_paint.origin_box.height )
-					{
-						img_new_sz.width = bg_paint.origin_box.width;
-						img_new_sz.height	= (int) ((double) bg_paint.origin_box.width * img_ar_height);
-					} else
-					{
-						img_new_sz.height = bg_paint.origin_box.height;
-						img_new_sz.width	= (int) ((double) bg_paint.origin_box.height * img_ar_width);
-					}
-					break;
-					break;
-				case litehtml::background_size_auto:
-					if(!bg->m_position.height.is_predefined())
-					{
-						img_new_sz.height	= bg->m_position.height.calc_percent(bg_paint.origin_box.height);
-						img_new_sz.width	= (int) ((double) img_new_sz.height * img_ar_width);
-					}
-					break;
-				}
-			} else
-			{
-				img_new_sz.width = bg->m_position.width.calc_percent(bg_paint.origin_box.width);
-				if(bg->m_position.height.is_predefined())
-				{
-					img_new_sz.height = (int) ((double) img_new_sz.width * img_ar_height);
-				} else
-				{
-					img_new_sz.height = bg->m_position.height.calc_percent(bg_paint.origin_box.height);
-				}
-			}
-
-			bg_paint.image_size = img_new_sz;
-			bg_paint.position_x = bg_paint.origin_box.x + (int) bg->m_position.x.calc_percent(bg_paint.origin_box.width - bg_paint.image_size.width);
-			bg_paint.position_y = bg_paint.origin_box.y + (int) bg->m_position.y.calc_percent(bg_paint.origin_box.height - bg_paint.image_size.height);
-		}
-
-	}
-	bg_paint.border_radius	= m_css_borders.radius.calc_percents(border_box.width, border_box.height);
-	bg_paint.border_box		= border_box;
-	bg_paint.is_root		= have_parent() ? false : true;
-}
-
-litehtml::visibility litehtml::html_tag::get_visibility() const
-{
-	return m_visibility;
-}
-
-void litehtml::html_tag::draw_list_marker( uint_ptr hdc, const position &pos )
-{
-	list_marker lm;
-
-	const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);
-	size img_size;
-	if(list_image)
-	{
-		css::parse_css_url(list_image, lm.image);
-		lm.baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);
-		get_document()->container()->get_image_size(lm.image.c_str(), lm.baseurl, img_size);
-	} else
-	{
-		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.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)
-	{
-		if(lm.pos.y + img_size.height > pos.y + pos.height)
-		{
-			lm.pos.y = pos.y + pos.height - img_size.height;
-		}
-		if(img_size.width > lm.pos.width)
-		{
-			lm.pos.x -= img_size.width - lm.pos.width;
-		}
-
-		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_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;
-		}
-	}
-
-	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;
-	default:
-		break;
-	}
-	return _t("");
-}
-
-void litehtml::html_tag::draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex )
-{
-	if (m_display == display_table || m_display == display_inline_table)
-	{
-		draw_children_table(hdc, x, y, clip, flag, zindex);
-	}
-	else
-	{
-		draw_children_box(hdc, x, y, clip, flag, zindex);
-	}
-}
-
-bool litehtml::html_tag::fetch_positioned()
-{
-	bool ret = false;
-
-	m_positioned.clear();
-
-	litehtml::element_position el_pos;
-
-	for(auto& el : m_children)
-	{
-		el_pos = el->get_element_position();
-		if (el_pos != element_position_static)
-		{
-			add_positioned(el);
-		}
-		if (!ret && (el_pos == element_position_absolute || el_pos == element_position_fixed))
-		{
-			ret = true;
-		}
-		if(el->fetch_positioned())
-		{
-			ret = true;
-		}
-	}
-	return ret;
-}
-
-int litehtml::html_tag::get_zindex() const
-{
-	return m_z_index;
-}
-
-void litehtml::html_tag::render_positioned(render_type rt)
-{
-	position wnd_position;
-	get_document()->container()->get_client_rect(wnd_position);
-
-	element_position el_position;
-	bool process;
-	for (auto& el : m_positioned)
-	{
-		el_position = el->get_element_position();
-
-		process = false;
-		if(el->get_display() != display_none)
-		{
-			if(el_position == element_position_absolute)
-			{
-				if(rt != render_fixed_only)
-				{
-					process = true;
-				}
-			} else if(el_position == element_position_fixed)
-			{
-				if(rt != render_no_fixed)
-				{
-					process = true;
-				}
-			}
-		}
-
-		if(process)
-		{
-			int parent_height	= 0;
-			int parent_width	= 0;
-			if(el_position == element_position_fixed)
-			{
-				parent_height	= wnd_position.height;
-				parent_width	= wnd_position.width;
-			} else
-			{
-				element::ptr el_parent = el->parent();
-				if(el_parent)
-				{
-					parent_height	= el_parent->height();
-					parent_width	= el_parent->width();
-				}
-			}
-
-			css_length	css_left	= el->get_css_left();
-			css_length	css_right	= el->get_css_right();
-			css_length	css_top		= el->get_css_top();
-			css_length	css_bottom	= el->get_css_bottom();
-
-			bool need_render = false;
-
-			css_length el_w = el->get_css_width();
-			css_length el_h = el->get_css_height();
-
-            int new_width = -1;
-            int new_height = -1;
-			if(el_w.units() == css_units_percentage && parent_width)
-			{
-                new_width = el_w.calc_percent(parent_width);
-                if(el->m_pos.width != new_width)
-				{
-					need_render = true;
-                    el->m_pos.width = new_width;
-				}
-			}
-
-			if(el_h.units() == css_units_percentage && parent_height)
-			{
-                new_height = el_h.calc_percent(parent_height);
-                if(el->m_pos.height != new_height)
-				{
-					need_render = true;
-                    el->m_pos.height = new_height;
-				}
-			}
-
-			bool cvt_x = false;
-			bool cvt_y = false;
-
-			if(el_position == element_position_fixed)
-			{
-				if(!css_left.is_predefined() || !css_right.is_predefined())
-				{
-					if(!css_left.is_predefined() && css_right.is_predefined())
-					{
-						el->m_pos.x = css_left.calc_percent(parent_width) + el->content_margins_left();
-					} else if(css_left.is_predefined() && !css_right.is_predefined())
-					{
-						el->m_pos.x = parent_width - css_right.calc_percent(parent_width) - el->m_pos.width - el->content_margins_right();
-					} else
-					{
-						el->m_pos.x		= css_left.calc_percent(parent_width) + el->content_margins_left();
-						el->m_pos.width	= parent_width - css_left.calc_percent(parent_width) - css_right.calc_percent(parent_width) - (el->content_margins_left() + el->content_margins_right());
-						need_render = true;
-					}
-				}
-
-				if(!css_top.is_predefined() || !css_bottom.is_predefined())
-				{
-					if(!css_top.is_predefined() && css_bottom.is_predefined())
-					{
-						el->m_pos.y = css_top.calc_percent(parent_height) + el->content_margins_top();
-					} else if(css_top.is_predefined() && !css_bottom.is_predefined())
-					{
-						el->m_pos.y = parent_height - css_bottom.calc_percent(parent_height) - el->m_pos.height - el->content_margins_bottom();
-					} else
-					{
-						el->m_pos.y			= css_top.calc_percent(parent_height) + el->content_margins_top();
-						el->m_pos.height	= parent_height - css_top.calc_percent(parent_height) - css_bottom.calc_percent(parent_height) - (el->content_margins_top() + el->content_margins_bottom());
-						need_render = true;
-					}
-				}
-			} else 
-			{
-				if(!css_left.is_predefined() || !css_right.is_predefined())
-				{
-					if(!css_left.is_predefined() && css_right.is_predefined())
-					{
-						el->m_pos.x = css_left.calc_percent(parent_width) + el->content_margins_left() - m_padding.left;
-					} else if(css_left.is_predefined() && !css_right.is_predefined())
-					{
-						el->m_pos.x = m_pos.width + m_padding.right - css_right.calc_percent(parent_width) - el->m_pos.width - el->content_margins_right();
-					} else
-					{
-						el->m_pos.x		= css_left.calc_percent(parent_width) + el->content_margins_left() - m_padding.left;
-						el->m_pos.width	= m_pos.width + m_padding.left + m_padding.right - css_left.calc_percent(parent_width) - css_right.calc_percent(parent_width) - (el->content_margins_left() + el->content_margins_right());
-                        if (new_width != -1)
-                        {
-                            el->m_pos.x += (el->m_pos.width - new_width) / 2;
-                            el->m_pos.width = new_width;
-                        }
-                        need_render = true;
-					}
-					cvt_x = true;
-				}
-
-				if(!css_top.is_predefined() || !css_bottom.is_predefined())
-				{
-					if(!css_top.is_predefined() && css_bottom.is_predefined())
-					{
-						el->m_pos.y = css_top.calc_percent(parent_height) + el->content_margins_top() - m_padding.top;
-					} else if(css_top.is_predefined() && !css_bottom.is_predefined())
-					{
-						el->m_pos.y = m_pos.height + m_padding.bottom - css_bottom.calc_percent(parent_height) - el->m_pos.height - el->content_margins_bottom();
-					} else
-					{
-						el->m_pos.y			= css_top.calc_percent(parent_height) + el->content_margins_top() - m_padding.top;
-						el->m_pos.height	= m_pos.height + m_padding.top + m_padding.bottom - css_top.calc_percent(parent_height) - css_bottom.calc_percent(parent_height) - (el->content_margins_top() + el->content_margins_bottom());
-                        if (new_height != -1)
-                        {
-                            el->m_pos.y += (el->m_pos.height - new_height) / 2;
-                            el->m_pos.height = new_height;
-                        }
-                        need_render = true;
-					}
-					cvt_y = true;
-				}
-			}
-
-			if(cvt_x || cvt_y)
-			{
-				int offset_x = 0;
-				int offset_y = 0;
-				element::ptr cur_el = el->parent();
-				element::ptr this_el = shared_from_this();
-				while(cur_el && cur_el != this_el)
-				{
-					offset_x += cur_el->m_pos.x;
-					offset_y += cur_el->m_pos.y;
-					cur_el = cur_el->parent();
-				}
-				if(cvt_x)	el->m_pos.x -= offset_x;
-				if(cvt_y)	el->m_pos.y -= offset_y;
-			}
-
-			if(need_render)
-			{
-				position pos = el->m_pos;
-				el->render(el->left(), el->top(), el->width(), true);
-				el->m_pos = pos;
-			}
-
-			if(el_position == element_position_fixed)
-			{
-				position fixed_pos;
-				el->get_redraw_box(fixed_pos);
-				get_document()->add_fixed_box(fixed_pos);
-			}
-		}
-
-		el->render_positioned();
-	}
-
-	if(!m_positioned.empty())
-	{
-		std::stable_sort(m_positioned.begin(), m_positioned.end(), [](const litehtml::element::ptr& _Left, const litehtml::element::ptr& _Right)
-		{
-			return (_Left->get_zindex() < _Right->get_zindex());
-		});
-	}
-}
-
-void litehtml::html_tag::draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned )
-{
-	if(!is_visible()) return;
-
-	std::map<int, bool> zindexes;
-	if(with_positioned)
-	{
-		for(elements_vector::iterator i = m_positioned.begin(); i != m_positioned.end(); i++)
-		{
-			zindexes[(*i)->get_zindex()];
-		}
-
-		for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)
-		{
-			if(idx->first < 0)
-			{
-				draw_children(hdc, x, y, clip, draw_positioned, idx->first);
-			}
-		}
-	}
-	draw_children(hdc, x, y, clip, draw_block, 0);
-	draw_children(hdc, x, y, clip, draw_floats, 0);
-	draw_children(hdc, x, y, clip, draw_inlines, 0);
-	if(with_positioned)
-	{
-		for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)
-		{
-			if(idx->first == 0)
-			{
-				draw_children(hdc, x, y, clip, draw_positioned, idx->first);
-			}
-		}
-
-		for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end(); idx++)
-		{
-			if(idx->first > 0)
-			{
-				draw_children(hdc, x, y, clip, draw_positioned, idx->first);
-			}
-		}
-	}
-}
-
-litehtml::overflow litehtml::html_tag::get_overflow() const
-{
-	return m_overflow;
-}
-
-bool litehtml::html_tag::is_nth_child(const element::ptr& el, int num, int off, bool of_type) const
-{
-	int idx = 1;
-	for(const auto& child : m_children)
-	{
-		if(child->get_display() != display_inline_text)
-		{
-			if( (!of_type) || (of_type && !t_strcmp(el->get_tagName(), child->get_tagName())) )
-			{
-				if(el == child)
-				{
-					if(num != 0)
-					{
-						if((idx - off) >= 0 && (idx - off) % num == 0)
-						{
-							return true;
-						}
-
-					} else if(idx == off)
-					{
-						return true;
-					}
-					return false;
-				}
-				idx++;
-			}
-			if(el == child) break;
-		}
-	}
-	return false;
-}
-
-bool litehtml::html_tag::is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const
-{
-	int idx = 1;
-	for(elements_vector::const_reverse_iterator child = m_children.rbegin(); child != m_children.rend(); child++)
-	{
-		if((*child)->get_display() != display_inline_text)
-		{
-			if( !of_type || (of_type && !t_strcmp(el->get_tagName(), (*child)->get_tagName())) )
-			{
-				if(el == (*child))
-				{
-					if(num != 0)
-					{
-						if((idx - off) >= 0 && (idx - off) % num == 0)
-						{
-							return true;
-						}
-
-					} else if(idx == off)
-					{
-						return true;
-					}
-					return false;
-				}
-				idx++;
-			}
-			if(el == (*child)) break;
-		}
-	}
-	return false;
-}
-
-void litehtml::html_tag::parse_nth_child_params( tstring param, int &num, int &off )
-{
-	if(param == _t("odd"))
-	{
-		num = 2;
-		off = 1;
-	} else if(param == _t("even"))
-	{
-		num = 2;
-		off = 0;
-	} else
-	{
-		string_vector tokens;
-		split_string(param, tokens, _t(" n"), _t("n"));
-
-		tstring s_num;
-		tstring s_off;
-
-		tstring s_int;
-		for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
-		{
-			if((*tok) == _t("n"))
-			{
-				s_num = s_int;
-				s_int.clear();
-			} else
-			{
-				s_int += (*tok);
-			}
-		}
-		s_off = s_int;
-
-		num = t_atoi(s_num.c_str());
-		off = t_atoi(s_off.c_str());
-	}
-}
-
-void litehtml::html_tag::calc_document_size( litehtml::size& sz, int x /*= 0*/, int y /*= 0*/ )
-{
-	if(is_visible() && m_el_position != element_position_fixed)
-	{
-		element::calc_document_size(sz, x, y);
-
-		if(m_overflow == overflow_visible)
-		{
-			for(auto& el : m_children)
-			{
-				el->calc_document_size(sz, x + m_pos.x, y + m_pos.y);
-			}
-		}
-
-		// root element (<html>) must to cover entire window
-		if(!have_parent())
-		{
-			position client_pos;
-			get_document()->container()->get_client_rect(client_pos);
-			m_pos.height = std::max(sz.height, client_pos.height) - content_margins_top() - content_margins_bottom();
-			m_pos.width	 = std::max(sz.width, client_pos.width) - content_margins_left() - content_margins_right();
-		}
-	}
-}
-
-
-void litehtml::html_tag::get_redraw_box(litehtml::position& pos, int x /*= 0*/, int y /*= 0*/)
-{
-	if(is_visible())
-	{
-		element::get_redraw_box(pos, x, y);
-
-		if(m_overflow == overflow_visible)
-		{
-			for(auto& el : m_children)
-			{
-				if(el->get_element_position() != element_position_fixed)
-				{
-					el->get_redraw_box(pos, x + m_pos.x, y + m_pos.y);
-				}
-			}
-		}
-	}
-}
-
-litehtml::element::ptr litehtml::html_tag::find_adjacent_sibling( const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/ )
-{
-	element::ptr ret;
-	for(auto& e : m_children)
-	{
-		if(e->get_display() != display_inline_text)
-		{
-			if(e == el)
-			{
-				if(ret)
-				{
-					int res = ret->select(selector, apply_pseudo);
-					if(res != select_no_match)
-					{
-						if(is_pseudo)
-						{
-							if(res & select_match_pseudo_class)
-							{
-								*is_pseudo = true;
-							} else
-							{
-								*is_pseudo = false;
-							}
-						}
-						return ret;
-					}
-				}
-				return 0;
-			} else
-			{
-				ret = e;
-			}
-		}
-	}
-	return 0;
-}
-
-litehtml::element::ptr litehtml::html_tag::find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/)
-{
-	element::ptr ret = 0;
-	for(auto& e : m_children)
-	{
-		if(e->get_display() != display_inline_text)
-		{
-			if(e == el)
-			{
-				return ret;
-			} else if(!ret)
-			{
-				int res = e->select(selector, apply_pseudo);
-				if(res != select_no_match)
-				{
-					if(is_pseudo)
-					{
-						if(res & select_match_pseudo_class)
-						{
-							*is_pseudo = true;
-						} else
-						{
-							*is_pseudo = false;
-						}
-					}
-					ret = e;
-				}
-			}
-		}
-	}
-	return 0;
-}
-
-bool litehtml::html_tag::is_only_child(const element::ptr& el, bool of_type) const
-{
-	int child_count = 0;
-	for(const auto& child : m_children)
-	{
-		if(child->get_display() != display_inline_text)
-		{
-			if( !of_type || (of_type && !t_strcmp(el->get_tagName(), child->get_tagName())) )
-			{
-				child_count++;
-			}
-			if(child_count > 1) break;
-		}
-	}
-	if(child_count > 1)
-	{
-		return false;
-	}
-	return true;
+	return false;
 }
 
-void litehtml::html_tag::update_floats(int dy, const element::ptr &parent)
+void litehtml::html_tag::set_data( const char* /*data*/ )
 {
-	if(is_floats_holder())
-	{
-		bool reset_cache = false;
-		for(floated_box::vector::reverse_iterator fb = m_floats_left.rbegin(); fb != m_floats_left.rend(); fb++)
-		{
-			if(fb->el->is_ancestor(parent))
-			{
-				reset_cache	= true;
-				fb->pos.y	+= dy;
-			}
-		}
-		if(reset_cache)
-		{
-			m_cahe_line_left.invalidate();
-		}
-		reset_cache = false;
-		for(floated_box::vector::reverse_iterator fb = m_floats_right.rbegin(); fb != m_floats_right.rend(); fb++)
-		{
-			if(fb->el->is_ancestor(parent))
-			{
-				reset_cache	= true;
-				fb->pos.y	+= dy;
-			}
-		}
-		if(reset_cache)
-		{
-			m_cahe_line_right.invalidate();
-		}
-	} else
+
+}
+
+bool litehtml::html_tag::on_mouse_over()
+{
+	bool ret = false;
+
+	element::ptr el = shared_from_this();
+	while(el)
 	{
-		element::ptr el_parent = this->parent();
-		if (el_parent)
+		if(el->set_pseudo_class(_hover_, true))
 		{
-			el_parent->update_floats(dy, parent);
+			ret = true;
 		}
+		el = el->parent();
 	}
+
+	return ret;
 }
 
-void litehtml::html_tag::remove_before_after()
+bool litehtml::html_tag::on_mouse_leave()
 {
-	if(!m_children.empty())
+	bool ret = false;
+
+	element::ptr el = shared_from_this();
+	while(el)
 	{
-		if( !t_strcmp(m_children.front()->get_tagName(), _t("::before")) )
+		if(el->set_pseudo_class(_hover_, false))
 		{
-			m_children.erase(m_children.begin());
+			ret = true;
 		}
-	}
-	if(!m_children.empty())
-	{
-		if( !t_strcmp(m_children.back()->get_tagName(), _t("::after")) )
+		if(el->set_pseudo_class(_active_, false))
 		{
-			m_children.erase(m_children.end() - 1);
+			ret = true;
 		}
+		el = el->parent();
 	}
+
+	return ret;
 }
 
-litehtml::element::ptr litehtml::html_tag::get_element_before()
+bool litehtml::html_tag::on_lbutton_down()
 {
-	if(!m_children.empty())
+	bool ret = false;
+
+	element::ptr el = shared_from_this();
+	while (el)
 	{
-		if( !t_strcmp(m_children.front()->get_tagName(), _t("::before")) )
+		if (el->set_pseudo_class(_active_, true))
 		{
-			return m_children.front();
+			ret = true;
 		}
+		el = el->parent();
 	}
-	element::ptr el = std::make_shared<el_before>(get_document());
-	el->parent(shared_from_this());
-	m_children.insert(m_children.begin(), el);
-	return el;
+
+	return ret;
 }
 
-litehtml::element::ptr litehtml::html_tag::get_element_after()
+bool litehtml::html_tag::on_lbutton_up()
 {
-	if(!m_children.empty())
+	bool ret = false;
+
+	element::ptr el = shared_from_this();
+	while (el)
 	{
-		if( !t_strcmp(m_children.back()->get_tagName(), _t("::after")) )
+		if (el->set_pseudo_class(_active_, false))
 		{
-			return m_children.back();
+			ret = true;
 		}
+		el = el->parent();
 	}
-	element::ptr el = std::make_shared<el_after>(get_document());
-	appendChild(el);
-	return el;
-}
 
-void litehtml::html_tag::add_style( const litehtml::style& st )
-{
-	m_style.combine(st);
+	on_click();
+
+	return ret;
 }
 
-bool litehtml::html_tag::have_inline_child() const
+void litehtml::html_tag::on_click()
 {
-	if(!m_children.empty())
+	if (!is_root())
 	{
-		for(const auto& el : m_children)
+		element::ptr el_parent = parent();
+		if (el_parent)
 		{
-			if(!el->is_white_space())
-			{
-				return true;
-			}
+			el_parent->on_click();
 		}
 	}
-	return false;
 }
 
-void litehtml::html_tag::refresh_styles()
+bool litehtml::html_tag::is_break() const
 {
-	remove_before_after();
+	return false;
+}
 
-	for (auto& el : m_children)
-	{
-		if(el->get_display() != display_inline_text)
-		{
-			el->refresh_styles();
-		}
-	}
+void litehtml::html_tag::draw_background(uint_ptr hdc, int x, int y, const position *clip,
+										 const std::shared_ptr<render_item> &ri)
+{
+	position pos = ri->pos();
+	pos.x	+= x;
+	pos.y	+= y;
 
-	m_style.clear();
+	position el_pos = pos;
+	el_pos += ri->get_paddings();
+	el_pos += ri->get_margins();
 
-	for (auto& usel : m_used_styles)
+	if(m_css.get_display() != display_inline && m_css.get_display() != display_table_row)
 	{
-		usel->m_used = false;
-
-		if(usel->m_selector->is_media_valid())
+		if(el_pos.does_intersect(clip) || is_root())
 		{
-			int apply = select(*usel->m_selector, false);
+			auto v_offset = ri->get_draw_vertical_offset();
+			pos.y += v_offset;
+			pos.height -= v_offset;
 
-			if(apply != select_no_match)
+			const background* bg = get_background();
+			if(bg)
 			{
-				if(apply & select_match_pseudo_class)
-				{
-					if(select(*usel->m_selector, true))
-					{
-						if(apply & select_match_with_after)
-						{
-							element::ptr el = get_element_after();
-							if(el)
-							{
-								el->add_style(*usel->m_selector->m_style);
-							}
-						} else if(apply & select_match_with_before)
-						{
-							element::ptr el = get_element_before();
-							if(el)
-							{
-								el->add_style(*usel->m_selector->m_style);
-							}
-						}
-						else
-						{
-							add_style(*usel->m_selector->m_style);
-							usel->m_used = true;
-						}
-					}
-				} else if(apply & select_match_with_after)
+				std::vector<background_paint> bg_paint;
+				init_background_paint(pos, bg_paint, bg, ri);
+				if(is_root())
 				{
-					element::ptr el = get_element_after();
-					if(el)
-					{
-						el->add_style(*usel->m_selector->m_style);
-					}
-				} else if(apply & select_match_with_before)
-				{
-					element::ptr el = get_element_before();
-					if(el)
+					for(auto& b : bg_paint)
 					{
-						el->add_style(*usel->m_selector->m_style);
+						b.clip_box = *clip;
+						b.border_box = *clip;
 					}
-				} else
-				{
-					add_style(*usel->m_selector->m_style);
-					usel->m_used = true;
 				}
-			}
-		}
-	}
-}
 
-litehtml::element::ptr litehtml::html_tag::get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex)
-{
-	element::ptr ret = 0;
+				get_document()->container()->draw_background(hdc, bg_paint);
+			}
+			position border_box = pos;
+			border_box += ri->get_paddings();
+			border_box += ri->get_borders();
 
-	if(m_overflow > overflow_visible)
-	{
-		if(!m_pos.is_point_inside(x, y))
-		{
-			return ret;
+			borders bdr = m_css.get_borders();
+			if(bdr.is_visible())
+			{
+				bdr.radius = m_css.get_borders().radius.calc_percents(border_box.width, border_box.height);
+				get_document()->container()->draw_borders(hdc, bdr, border_box, is_root());
+			}
 		}
-	}
+	} else
+	{
+		const background* bg = get_background();
 
-	position pos = m_pos;
-	pos.x	= x - pos.x;
-	pos.y	= y - pos.y;
+		position::vector boxes;
+		ri->get_inline_boxes(boxes);
 
-	for(elements_vector::reverse_iterator i = m_children.rbegin(); i != m_children.rend() && !ret; i++)
-	{
-		element::ptr el = (*i);
+		std::vector<background_paint> bg_paint;
+		position content_box;
 
-		if(el->is_visible() && el->get_display() != display_inline_text)
+		for(auto box = boxes.begin(); box != boxes.end(); box++)
 		{
-			switch(flag)
+			box->x	+= x;
+			box->y	+= y;
+
+			if(box->does_intersect(clip))
 			{
-			case draw_positioned:
-				if(el->is_positioned() && el->get_zindex() == zindex)
+				content_box = *box;
+				content_box -= ri->get_borders();
+				content_box -= ri->get_paddings();
+
+				if(bg)
 				{
-					if(el->get_element_position() == element_position_fixed)
-					{
-						ret = el->get_element_by_point(client_x, client_y, client_x, client_y);
-						if(!ret && (*i)->is_point_inside(client_x, client_y))
-						{
-							ret = (*i);
-						}
-					} else
-					{
-						ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);
-						if(!ret && (*i)->is_point_inside(pos.x, pos.y))
-						{
-							ret = (*i);
-						}
-					}
-					el = 0;
+					init_background_paint(content_box, bg_paint, bg, ri);
 				}
-				break;
-			case draw_block:
-				if(!el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
+
+				css_borders bdr;
+
+				// set left borders radius for the first box
+				if(box == boxes.begin())
 				{
-					if(el->is_point_inside(pos.x, pos.y))
-					{
-						ret = el;
-					}
+					bdr.radius.bottom_left_x	= m_css.get_borders().radius.bottom_left_x;
+					bdr.radius.bottom_left_y	= m_css.get_borders().radius.bottom_left_y;
+					bdr.radius.top_left_x		= m_css.get_borders().radius.top_left_x;
+					bdr.radius.top_left_y		= m_css.get_borders().radius.top_left_y;
 				}
-				break;
-			case draw_floats:
-				if(el->get_float() != float_none && !el->is_positioned())
+
+				// set right borders radius for the last box
+				if(box == boxes.end() - 1)
 				{
-					ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);
+					bdr.radius.bottom_right_x	= m_css.get_borders().radius.bottom_right_x;
+					bdr.radius.bottom_right_y	= m_css.get_borders().radius.bottom_right_y;
+					bdr.radius.top_right_x		= m_css.get_borders().radius.top_right_x;
+					bdr.radius.top_right_y		= m_css.get_borders().radius.top_right_y;
+				}
 
-					if(!ret && (*i)->is_point_inside(pos.x, pos.y))
-					{
-						ret = (*i);
-					}
-					el = 0;
+				
+				bdr.top		= m_css.get_borders().top;
+				bdr.bottom	= m_css.get_borders().bottom;
+				if(box == boxes.begin())
+				{
+					bdr.left	= m_css.get_borders().left;
 				}
-				break;
-			case draw_inlines:
-				if(el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
+				if(box == boxes.end() - 1)
 				{
-					if(el->get_display() == display_inline_block)
-					{
-						ret = el->get_element_by_point(pos.x, pos.y, client_x, client_y);
-						el = 0;
-					}
-					if(!ret && (*i)->is_point_inside(pos.x, pos.y))
-					{
-						ret = (*i);
-					}
+					bdr.right	= m_css.get_borders().right;
 				}
-				break;
-			default:
-				break;
-			}
 
-			if(el && !el->is_positioned())
-			{
-				if(flag == draw_positioned)
+				if(bg)
 				{
-					element::ptr child = el->get_child_by_point(pos.x, pos.y, client_x, client_y, flag, zindex);
-					if(child)
+					for (auto& bgp : bg_paint)
 					{
-						ret = child;
+						bgp.border_radius = bdr.radius.calc_percents(bgp.border_box.width, bgp.border_box.width);
 					}
-				} else
+					get_document()->container()->draw_background(hdc, bg_paint);
+				}
+				if(bdr.is_visible())
 				{
-					if(	el->get_float() == float_none &&
-						el->get_display() != display_inline_block)
-					{
-						element::ptr child = el->get_child_by_point(pos.x, pos.y, client_x, client_y, flag, zindex);
-						if(child)
-						{
-							ret = child;
-						}
-					}
+					borders b = bdr;
+					b.radius = bdr.radius.calc_percents(box->width, box->height);
+					get_document()->container()->draw_borders(hdc, b, *box, false);
 				}
 			}
 		}
 	}
-
-	return ret;
 }
 
-litehtml::element::ptr litehtml::html_tag::get_element_by_point(int x, int y, int client_x, int client_y)
+bool litehtml::html_tag::set_pseudo_class( string_id cls, bool add )
 {
-	if(!is_visible()) return 0;
-
-	element::ptr ret;
-
-	std::map<int, bool> zindexes;
-
-	for(elements_vector::iterator i = m_positioned.begin(); i != m_positioned.end(); i++)
-	{
-		zindexes[(*i)->get_zindex()];
-	}
-
-	for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)
-	{
-		if(idx->first > 0)
-		{
-			ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);
-		}
-	}
-	if(ret) return ret;
-
-	for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)
-	{
-		if(idx->first == 0)
-		{
-			ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);
-		}
-	}
-	if(ret) return ret;
-
-	ret = get_child_by_point(x, y, client_x, client_y, draw_inlines, 0);
-	if(ret) return ret;
-
-	ret = get_child_by_point(x, y, client_x, client_y, draw_floats, 0);
-	if(ret) return ret;
-
-	ret = get_child_by_point(x, y, client_x, client_y, draw_block, 0);
-	if(ret) return ret;
-
-
-	for(std::map<int, bool>::iterator idx = zindexes.begin(); idx != zindexes.end() && !ret; idx++)
-	{
-		if(idx->first < 0)
-		{
-			ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, idx->first);
-		}
-	}
-	if(ret) return ret;
-
-	if(m_el_position == element_position_fixed)
+	bool ret = false;
+	if(add)
 	{
-		if(is_point_inside(client_x, client_y))
+		if(std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), cls) == m_pseudo_classes.end())
 		{
-			ret = shared_from_this();
+			m_pseudo_classes.push_back(cls);
+			ret = true;
 		}
 	} else
 	{
-		if(is_point_inside(x, y))
+		auto pi = std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), cls);
+		if(pi != m_pseudo_classes.end())
 		{
-			ret = shared_from_this();
+			m_pseudo_classes.erase(pi);
+			ret = true;
 		}
 	}
-
 	return ret;
 }
 
-const litehtml::background* litehtml::html_tag::get_background(bool own_only)
+bool litehtml::html_tag::set_class( const char* pclass, bool add )
 {
-	if(own_only)
-	{
-		// return own background with check for empty one
-		if(m_bg.m_image.empty() && !m_bg.m_color.alpha)
-		{
-			return 0;
-		}
-		return &m_bg;
-	}
+	string_vector classes;
+	bool changed = false;
+
+	split_string( pclass, classes, " " );
 
-	if(m_bg.m_image.empty() && !m_bg.m_color.alpha)
+	if(add)
 	{
-		// if this is root element (<html>) try to get background from body
-		if (!have_parent())
+		for( auto & _class : classes )
 		{
-			for (const auto& el : m_children)
+			if(std::find(m_str_classes.begin(), m_str_classes.end(), _class) == m_str_classes.end())
 			{
-				if( el->is_body() )
-				{
-					// return own body background
-					return el->get_background(true);
-				}
-			}
-		}
-		return 0;
-	}
-	
-	if(is_body())
+				m_str_classes.push_back( std::move( _class ) );
+				changed = true;
+			}
+		}
+	} else
 	{
-		element::ptr el_parent = parent();
-		if (el_parent)
+		for( const auto & _class : classes )
 		{
-			if (!el_parent->get_background(true))
+			auto end = std::remove(m_str_classes.begin(), m_str_classes.end(), _class);
+
+			if(end != m_str_classes.end())
 			{
-				// parent of body will draw background for body
-				return 0;
+				m_str_classes.erase(end, m_str_classes.end());
+				changed = true;
 			}
 		}
 	}
 
-	return &m_bg;
+	if( changed )
+	{
+		string class_string;
+		join_string(class_string, m_str_classes, " ");
+		set_attr("class", class_string.c_str());
+
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+
 }
 
-int litehtml::html_tag::render_box(int x, int y, int max_width, bool second_pass /*= false*/)
+bool litehtml::html_tag::is_replaced() const
 {
-	int parent_width = max_width;
-
-	if (max_width <= 0)
-		return 0;
+	return false;
+}
 
-	calc_outlines(parent_width);
+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;
+}
 
-	m_pos.clear();
-	m_pos.move_to(x, y);
+size_t litehtml::html_tag::get_children_count() const
+{
+	return m_children.size();
+}
 
-	m_pos.x += content_margins_left();
-	m_pos.y += content_margins_top();
+litehtml::element::ptr litehtml::html_tag::get_child( int idx ) const
+{
+	return m_children[idx];
+}
 
-	int ret_width = 0;
 
-	def_value<int>	block_width(0);
+void litehtml::html_tag::init_background_paint(position pos, std::vector<background_paint>& bg_paint, const background* bg, const std::shared_ptr<render_item>& ri)
+{
+	bg_paint = { background_paint() };
+	if (!bg) return;
 
-	if (m_display != display_table_cell && !m_css_width.is_predefined())
-	{
-		int w = calc_width(parent_width);
-		
-		if (m_box_sizing == box_sizing_border_box)
-		{
-			w -= m_padding.width() + m_borders.width();
-		}
-		ret_width = max_width = block_width = w;
-	}
-	else
-	{
-		if (max_width)
-		{
-			max_width -= content_margins_left() + content_margins_right();
-		}
-	}
+	int bg_count = std::max((int)bg->m_image.size(), 1);
+	bg_paint.resize(bg_count);
 
-	// check for max-width (on the first pass only)
-	if (!m_css_max_width.is_predefined() && !second_pass)
+	for (int i = 0; i < bg_count; i++)
 	{
-		int mw = get_document()->cvt_units(m_css_max_width, m_font_size, parent_width);
-		if (m_box_sizing == box_sizing_border_box)
-		{
-			mw -= m_padding.left + m_borders.left + m_padding.right + m_borders.right;
-		}
-		if (max_width > mw)
-		{
-			max_width = mw;
-		}
+		init_one_background_paint(i, pos, bg_paint[i], bg, ri);
 	}
 
-	m_floats_left.clear();
-	m_floats_right.clear();
-	m_boxes.clear();
-	m_cahe_line_left.invalidate();
-	m_cahe_line_right.invalidate();
-
-	element_position el_position;
+	bg_paint.back().color = bg->m_color;
+}
 
-	int block_height = 0;
+void litehtml::html_tag::init_one_background_paint(int i, position pos, background_paint& bg_paint, const background* bg, const std::shared_ptr<render_item>& ri)
+{
+	bg_paint.image		= i < bg->m_image.size() ? bg->m_image[i] : "";
+	bg_paint.baseurl	= bg->m_baseurl;
+	bg_paint.attachment = i < bg->m_attachment.size() ? (background_attachment)bg->m_attachment[i] : background_attachment_scroll;
+	bg_paint.repeat		= i < bg->m_repeat.size() ? (background_repeat)bg->m_repeat[i] : background_repeat_repeat;
+	int clip			= i < bg->m_clip.size() ? bg->m_clip[i] : background_box_border;
+	int origin			= i < bg->m_origin.size() ? bg->m_origin[i] : background_box_padding;
+	const css_size auto_auto(css_length::predef_value(background_size_auto), css_length::predef_value(background_size_auto));
+	css_size size		= i < bg->m_size.size() ? bg->m_size[i] : auto_auto;
+	css_length position_x = i < bg->m_position_x.size() ? bg->m_position_x[i] : css_length(0, css_units_percentage);
+	css_length position_y = i < bg->m_position_y.size() ? bg->m_position_y[i] : css_length(0, css_units_percentage);
 
-	m_pos.height = 0;
+	position content_box	= pos;
+	position padding_box	= pos;
+	padding_box += ri->get_paddings();
+	position border_box		= padding_box;
+	border_box += ri->get_borders();
 
-	if (get_predefined_height(block_height))
+	switch(clip)
 	{
-		m_pos.height = block_height;
+	case background_box_padding:
+		bg_paint.clip_box = padding_box;
+		break;
+	case background_box_content:
+		bg_paint.clip_box = content_box;
+		break;
+	default:
+		bg_paint.clip_box = border_box;
+		break;
 	}
 
-	white_space ws = get_white_space();
-	bool skip_spaces = false;
-	if (ws == white_space_normal ||
-		ws == white_space_nowrap ||
-		ws == white_space_pre_line)
+	switch(origin)
 	{
-		skip_spaces = true;
+	case background_box_border:
+		bg_paint.origin_box = border_box;
+		break;
+	case background_box_content:
+		bg_paint.origin_box = content_box;
+		break;
+	default:
+		bg_paint.origin_box = padding_box;
+		break;
 	}
 
-	bool was_space = false;
-
-	for (auto el : m_children)
+	if(!bg_paint.image.empty())
 	{
-		// we don't need process absolute and fixed positioned element on the second pass
-		if (second_pass)
+		get_document()->container()->get_image_size(bg_paint.image.c_str(), bg_paint.baseurl.c_str(), bg_paint.image_size);
+		if(bg_paint.image_size.width && bg_paint.image_size.height)
 		{
-			el_position = el->get_element_position();
-			if ((el_position == element_position_absolute || el_position == element_position_fixed)) continue;
-		}
+			litehtml::size img_new_sz = bg_paint.image_size;
+			double img_ar_width		= (double) bg_paint.image_size.width / (double) bg_paint.image_size.height;
+			double img_ar_height	= (double) bg_paint.image_size.height / (double) bg_paint.image_size.width;
 
-		// skip spaces to make rendering a bit faster
-		if (skip_spaces)
-		{
-			if (el->is_white_space())
+
+			if(size.width.is_predefined())
 			{
-				if (was_space)
+				switch(size.width.predef())
 				{
-					el->skip(true);
-					continue;
+				case background_size_contain:
+					if( (int) ((double) bg_paint.origin_box.width * img_ar_height) <= bg_paint.origin_box.height )
+					{
+						img_new_sz.width = bg_paint.origin_box.width;
+						img_new_sz.height	= (int) ((double) bg_paint.origin_box.width * img_ar_height);
+					} else
+					{
+						img_new_sz.height = bg_paint.origin_box.height;
+						img_new_sz.width	= (int) ((double) bg_paint.origin_box.height * img_ar_width);
+					}
+					break;
+				case background_size_cover:
+					if( (int) ((double) bg_paint.origin_box.width * img_ar_height) >= bg_paint.origin_box.height )
+					{
+						img_new_sz.width = bg_paint.origin_box.width;
+						img_new_sz.height	= (int) ((double) bg_paint.origin_box.width * img_ar_height);
+					} else
+					{
+						img_new_sz.height = bg_paint.origin_box.height;
+						img_new_sz.width	= (int) ((double) bg_paint.origin_box.height * img_ar_width);
+					}
+					break;
+					break;
+				case background_size_auto:
+					if(!size.height.is_predefined())
+					{
+						img_new_sz.height	= size.height.calc_percent(bg_paint.origin_box.height);
+						img_new_sz.width	= (int) ((double) img_new_sz.height * img_ar_width);
+					}
+					break;
 				}
-				else
+			} else
+			{
+				img_new_sz.width = size.width.calc_percent(bg_paint.origin_box.width);
+				if(size.height.is_predefined())
+				{
+					img_new_sz.height = (int) ((double) img_new_sz.width * img_ar_height);
+				} else
 				{
-					was_space = true;
+					img_new_sz.height = size.height.calc_percent(bg_paint.origin_box.height);
 				}
 			}
-			else
-			{
-				was_space = false;
-			}
-		}
 
-		// place element into rendering flow
-		int rw = place_element(el, max_width);
-		if (rw > ret_width)
-		{
-			ret_width = rw;
+			bg_paint.image_size = img_new_sz;
+			bg_paint.position_x = bg_paint.origin_box.x + (int) position_x.calc_percent(bg_paint.origin_box.width - bg_paint.image_size.width);
+			bg_paint.position_y = bg_paint.origin_box.y + (int) position_y.calc_percent(bg_paint.origin_box.height - bg_paint.image_size.height);
 		}
 	}
+	bg_paint.border_radius	= m_css.get_borders().radius.calc_percents(border_box.width, border_box.height);
+	bg_paint.border_box		= border_box;
+	bg_paint.is_root		= is_root();
+}
 
-	finish_last_box(true);
+void litehtml::html_tag::draw_list_marker( uint_ptr hdc, const position& pos )
+{
+	list_marker lm;
 
-	if (block_width.is_default() && is_inline_box())
+	size img_size;
+	if (css().get_list_style_image() != "")
 	{
-		m_pos.width = ret_width;
-	}
-	else
+		lm.image   = css().get_list_style_image();
+		lm.baseurl = css().get_list_style_image_baseurl().c_str();
+		get_document()->container()->get_image_size(lm.image.c_str(), lm.baseurl, img_size);
+	} else
 	{
-		m_pos.width = max_width;
+		lm.baseurl = nullptr;
 	}
-	calc_auto_margins(parent_width);
 
-	if (!m_boxes.empty())
-	{
-		if (collapse_top_margin())
-		{
-			int old_top = m_margins.top;
-			m_margins.top = std::max(m_boxes.front()->top_margin(), m_margins.top);
-			if (m_margins.top != old_top)
-			{
-				update_floats(m_margins.top - old_top, shared_from_this());
-			}
-		}
-		if (collapse_bottom_margin())
-		{
-			m_margins.bottom = std::max(m_boxes.back()->bottom_margin(), m_margins.bottom);
-			m_pos.height = m_boxes.back()->bottom() - m_boxes.back()->bottom_margin();
-		}
-		else
-		{
-			m_pos.height = m_boxes.back()->bottom();
-		}
-	}
+	int ln_height	= css().get_line_height();
+	int sz_font		= css().get_font_size();
+	lm.pos.x		= pos.x;
+	lm.pos.width    = sz_font - sz_font * 2 / 3;
+	lm.color        = css().get_color();
+	lm.marker_type  = css().get_list_style_type();
+	lm.font         = css().get_font();
 
-	// add the floats height to the block height
-	if (is_floats_holder())
+	if (css().get_list_style_type() >= list_style_type_armenian)
 	{
-		int floats_height = get_floats_height();
-		if (floats_height > m_pos.height)
-		{
-			m_pos.height = floats_height;
-		}
+		lm.pos.y = pos.y;
+		lm.pos.height = pos.height;
+		lm.index = atoi(get_attr("list_index", "0"));
 	}
-
-	// calculate the final position
-
-	m_pos.move_to(x, y);
-	m_pos.x += content_margins_left();
-	m_pos.y += content_margins_top();
-
-	if (get_predefined_height(block_height))
+	else
 	{
-		m_pos.height = block_height;
+		lm.pos.height = sz_font - sz_font * 2 / 3;
+		lm.pos.y = pos.y + ln_height / 2 - lm.pos.height / 2;
+		lm.index = -1;
 	}
 
-	int min_height = 0;
-	if (!m_css_min_height.is_predefined() && m_css_min_height.units() == css_units_percentage)
+	if(img_size.width && img_size.height)
 	{
-		element::ptr el_parent = parent();
-		if (el_parent)
+		if(lm.pos.y + img_size.height > pos.y + pos.height)
 		{
-			if (el_parent->get_predefined_height(block_height))
-			{
-				min_height = m_css_min_height.calc_percent(block_height);
-			}
+			lm.pos.y = pos.y + pos.height - img_size.height;
 		}
-	}
-	else
-	{
-		min_height = (int)m_css_min_height.val();
-	}
-	if (min_height != 0 && m_box_sizing == box_sizing_border_box)
-	{
-		min_height -= m_padding.top + m_borders.top + m_padding.bottom + m_borders.bottom;
-		if (min_height < 0) min_height = 0;
-	}
-
-	if (m_display == display_list_item)
-	{
-		const tchar_t* list_image = get_style_property(_t("list-style-image"), true, 0);
-		if (list_image)
+		if(img_size.width > lm.pos.width)
 		{
-			tstring url;
-			css::parse_css_url(list_image, url);
-
-			size sz;
-			const tchar_t* list_image_baseurl = get_style_property(_t("list-style-image-baseurl"), true, 0);
-			get_document()->container()->get_image_size(url.c_str(), list_image_baseurl, sz);
-			if (min_height < sz.height)
-			{
-				min_height = sz.height;
-			}
+			lm.pos.x -= img_size.width - lm.pos.width;
 		}
 
+		lm.pos.width	= img_size.width;
+		lm.pos.height	= img_size.height;
 	}
 
-	if (min_height > m_pos.height)
-	{
-		m_pos.height = min_height;
-	}
-
-	int min_width = m_css_min_width.calc_percent(parent_width);
-
-	if (min_width != 0 && m_box_sizing == box_sizing_border_box)
-	{
-		min_width -= m_padding.left + m_borders.left + m_padding.right + m_borders.right;
-		if (min_width < 0) min_width = 0;
-	}
-
-	if (min_width != 0)
+	if (m_css.get_list_style_position() == list_style_position_outside)
 	{
-		if (min_width > m_pos.width)
+		if (m_css.get_list_style_type() >= list_style_type_armenian)
 		{
-			m_pos.width = min_width;
+			if(lm.font)
+			{
+				auto tw_space = get_document()->container()->text_width(" ", lm.font);
+				lm.pos.x = pos.x - tw_space * 2;
+				lm.pos.width = tw_space;
+			} else
+			{
+				lm.pos.width = 0;
+			}
 		}
-		if (min_width > ret_width)
+		else
 		{
-			ret_width = min_width;
+			lm.pos.x -= sz_font;
 		}
 	}
 
-	ret_width += content_margins_left() + content_margins_right();
-
-	// re-render with new width
-	if (ret_width < max_width && !second_pass && have_parent())
+	if (m_css.get_list_style_type() >= list_style_type_armenian)
 	{
-		if (m_display == display_inline_block ||
-			(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
-			))
-			)
+		auto marker_text = get_list_marker_text(lm.index);
+		lm.pos.height = ln_height;
+		if (marker_text.empty())
 		{
-			render(x, y, ret_width, true);
-			m_pos.width = ret_width - (content_margins_left() + content_margins_right());
+			get_document()->container()->draw_list_marker(hdc, lm);
 		}
-	}
-
-	if (is_floats_holder() && !second_pass)
-	{
-		for (const auto& fb : m_floats_left)
+		else
 		{
-			if (fb.el)
+			if(lm.font)
 			{
-				fb.el->apply_relative_shift(fb.el->parent()->calc_width(m_pos.width));
+				marker_text += ".";
+				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);
 			}
 		}
 	}
-
-
-	return ret_width;
-}
-
-int litehtml::html_tag::render_table(int x, int y, int max_width, bool second_pass /*= false*/)
-{
-	if (!m_grid) return 0;
-
-	int parent_width = max_width;
-
-	calc_outlines(parent_width);
-
-	m_pos.clear();
-	m_pos.move_to(x, y);
-
-	m_pos.x += content_margins_left();
-	m_pos.y += content_margins_top();
-
-	def_value<int>	block_width(0);
-
-	if (!m_css_width.is_predefined())
-	{
-		max_width = block_width = calc_width(parent_width) - m_padding.width() - m_borders.width();
-	}
-	else
-	{
-		if (max_width)
-		{
-			max_width -= content_margins_left() + content_margins_right();
-		}
-	}
-
-	// Calculate table spacing
-	int table_width_spacing = 0;
-	if (m_border_collapse == border_collapse_separate)
-	{
-		table_width_spacing = m_border_spacing_x * (m_grid->cols_count() + 1);
-	}
 	else
 	{
-		table_width_spacing = 0;
-
-		if (m_grid->cols_count())
-		{
-			table_width_spacing -= std::min(border_left(), m_grid->column(0).border_left);
-			table_width_spacing -= std::min(border_right(), m_grid->column(m_grid->cols_count() - 1).border_right);
-		}
-
-		for (int col = 1; col < m_grid->cols_count(); col++)
-		{
-			table_width_spacing -= std::min(m_grid->column(col).border_left, m_grid->column(col - 1).border_right);
-		}
+		get_document()->container()->draw_list_marker(hdc, lm);
 	}
+}
 
-
-	// Calculate the minimum content width (MCW) of each cell: the formatted content may span any number of lines but may not overflow the cell box. 
-	// If the specified 'width' (W) of the cell is greater than MCW, W is the minimum cell width. A value of 'auto' means that MCW is the minimum 
-	// cell width.
-	// 
-	// Also, calculate the "maximum" cell width of each cell: formatting the content without breaking lines other than where explicit line breaks occur.
-
-	if (m_grid->cols_count() == 1 && !block_width.is_default())
+litehtml::string litehtml::html_tag::get_list_marker_text(int index)
+{
+	switch (m_css.get_list_style_type())
 	{
-		for (int row = 0; row < m_grid->rows_count(); row++)
+	case litehtml::list_style_type_decimal:
+		return std::to_string(index);
+	case litehtml::list_style_type_decimal_leading_zero:
 		{
-			table_cell* cell = m_grid->cell(0, row);
-			if (cell && cell->el)
+			auto txt = std::to_string(index);
+			if (txt.length() == 1)
 			{
-				cell->min_width = cell->max_width = cell->el->render(0, 0, max_width - table_width_spacing);
-				cell->el->m_pos.width = cell->min_width - cell->el->content_margins_left() - cell->el->content_margins_right();
+				txt = "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);
+	default:
+		return "";
+//	case litehtml::list_style_type_armenian:
+//	case litehtml::list_style_type_georgian:
+//	case litehtml::list_style_type_hebrew:
+//	case litehtml::list_style_type_hiragana:
+//	case litehtml::list_style_type_hiragana_iroha:
+//	case litehtml::list_style_type_katakana:
+//	case litehtml::list_style_type_katakana_iroha:
+//  case litehtml::list_style_type_none:
+//  case litehtml::list_style_type_circle:
+//  case litehtml::list_style_type_disc:
+//  case litehtml::list_style_type_square:
+//  case litehtml::list_style_type_cjk_ideographic:
+//      break;
 	}
-	else
+}
+
+bool litehtml::html_tag::is_nth_child(const element::ptr& el, int num, int off, bool of_type) const
+{
+	int idx = 1;
+	for(const auto& child : m_children)
 	{
-		for (int row = 0; row < m_grid->rows_count(); row++)
+		if(child->css().get_display() != display_inline_text)
 		{
-			for (int col = 0; col < m_grid->cols_count(); col++)
+			if( (!of_type) || (of_type && el->tag() == child->tag()) )
 			{
-				table_cell* cell = m_grid->cell(col, row);
-				if (cell && cell->el)
+				if(el == child)
 				{
-					if (!m_grid->column(col).css_width.is_predefined() && m_grid->column(col).css_width.units() != css_units_percentage)
+					if(num != 0)
 					{
-						int css_w = m_grid->column(col).css_width.calc_percent(block_width);
-						int el_w = cell->el->render(0, 0, css_w);
-						cell->min_width = cell->max_width = std::max(css_w, el_w);
-						cell->el->m_pos.width = cell->min_width - cell->el->content_margins_left() - cell->el->content_margins_right();
-					}
-					else
+						if((idx - off) >= 0 && (idx - off) % num == 0)
+						{
+							return true;
+						}
+
+					} else if(idx == off)
 					{
-						// calculate minimum content width
-						cell->min_width = cell->el->render(0, 0, 1);
-						// calculate maximum content width
-						cell->max_width = cell->el->render(0, 0, max_width - table_width_spacing);
+						return true;
 					}
+					return false;
 				}
+				idx++;
 			}
+			if(el == child) break;
 		}
 	}
+	return false;
+}
 
-	// For each column, determine a maximum and minimum column width from the cells that span only that column. 
-	// The minimum is that required by the cell with the largest minimum cell width (or the column 'width', whichever is larger). 
-	// The maximum is that required by the cell with the largest maximum cell width (or the column 'width', whichever is larger).
-
-	for (int col = 0; col < m_grid->cols_count(); col++)
-	{
-		m_grid->column(col).max_width = 0;
-		m_grid->column(col).min_width = 0;
-		for (int row = 0; row < m_grid->rows_count(); row++)
-		{
-			if (m_grid->cell(col, row)->colspan <= 1)
-			{
-				m_grid->column(col).max_width = std::max(m_grid->column(col).max_width, m_grid->cell(col, row)->max_width);
-				m_grid->column(col).min_width = std::max(m_grid->column(col).min_width, m_grid->cell(col, row)->min_width);
-			}
-		}
-	}
-
-	// For each cell that spans more than one column, increase the minimum widths of the columns it spans so that together, 
-	// they are at least as wide as the cell. Do the same for the maximum widths. 
-	// If possible, widen all spanned columns by approximately the same amount.
-
-	for (int col = 0; col < m_grid->cols_count(); col++)
+bool litehtml::html_tag::is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const
+{
+	int idx = 1;
+	for(auto child = m_children.rbegin(); child != m_children.rend(); child++)
 	{
-		for (int row = 0; row < m_grid->rows_count(); row++)
+		if((*child)->css().get_display() != display_inline_text)
 		{
-			if (m_grid->cell(col, row)->colspan > 1)
+			if( !of_type || (of_type && el->tag() == (*child)->tag()) )
 			{
-				int max_total_width = m_grid->column(col).max_width;
-				int min_total_width = m_grid->column(col).min_width;
-				for (int col2 = col + 1; col2 < col + m_grid->cell(col, row)->colspan; col2++)
-				{
-					max_total_width += m_grid->column(col2).max_width;
-					min_total_width += m_grid->column(col2).min_width;
-				}
-				if (min_total_width < m_grid->cell(col, row)->min_width)
-				{
-					m_grid->distribute_min_width(m_grid->cell(col, row)->min_width - min_total_width, col, col + m_grid->cell(col, row)->colspan - 1);
-				}
-				if (max_total_width < m_grid->cell(col, row)->max_width)
+				if(el == (*child))
 				{
-					m_grid->distribute_max_width(m_grid->cell(col, row)->max_width - max_total_width, col, col + m_grid->cell(col, row)->colspan - 1);
+					if(num != 0)
+					{
+						if((idx - off) >= 0 && (idx - off) % num == 0)
+						{
+							return true;
+						}
+
+					} else if(idx == off)
+					{
+						return true;
+					}
+					return false;
 				}
+				idx++;
 			}
+			if(el == (*child)) break;
 		}
 	}
+	return false;
+}
 
-	// If the 'table' or 'inline-table' element's 'width' property has a computed value (W) other than 'auto', the used width is the 
-	// greater of W, CAPMIN, and the minimum width required by all the columns plus cell spacing or borders (MIN). 
-	// If the used width is greater than MIN, the extra width should be distributed over the columns.
-	//
-	// If the 'table' or 'inline-table' element has 'width: auto', the used width is the greater of the table's containing block width, 
-	// CAPMIN, and MIN. However, if either CAPMIN or the maximum width required by the columns plus cell spacing or borders (MAX) is 
-	// less than that of the containing block, use max(MAX, CAPMIN).
-
-
-	int table_width = 0;
-	int min_table_width = 0;
-	int max_table_width = 0;
-
-	if (!block_width.is_default())
-	{
-		table_width = m_grid->calc_table_width(block_width - table_width_spacing, false, min_table_width, max_table_width);
-	}
-	else
-	{
-		table_width = m_grid->calc_table_width(max_width - table_width_spacing, true, min_table_width, max_table_width);
-	}
-
-	min_table_width += table_width_spacing;
-	max_table_width += table_width_spacing;
-	table_width += table_width_spacing;
-	m_grid->calc_horizontal_positions(m_borders, m_border_collapse, m_border_spacing_x);
-
-	bool row_span_found = false;
-
-	// render cells with computed width
-	for (int row = 0; row < m_grid->rows_count(); row++)
+litehtml::element::ptr litehtml::html_tag::find_adjacent_sibling( const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/ )
+{
+	element::ptr ret;
+	for(auto& e : m_children)
 	{
-		m_grid->row(row).height = 0;
-		for (int col = 0; col < m_grid->cols_count(); col++)
+		if(e->css().get_display() != display_inline_text)
 		{
-			table_cell* cell = m_grid->cell(col, row);
-			if (cell->el)
+			if(e == el)
 			{
-				int span_col = col + cell->colspan - 1;
-				if (span_col >= m_grid->cols_count())
-				{
-					span_col = m_grid->cols_count() - 1;
-				}
-				int cell_width = m_grid->column(span_col).right - m_grid->column(col).left;
-
-				if (cell->el->m_pos.width != cell_width - cell->el->content_margins_left() - cell->el->content_margins_right())
-				{
-					cell->el->render(m_grid->column(col).left, 0, cell_width);
-					cell->el->m_pos.width = cell_width - cell->el->content_margins_left() - cell->el->content_margins_right();
-				}
-				else
-				{
-					cell->el->m_pos.x = m_grid->column(col).left + cell->el->content_margins_left();
-				}
-
-				if (cell->rowspan <= 1)
-				{
-					m_grid->row(row).height = std::max(m_grid->row(row).height, cell->el->height());
-				}
-				else
+				if(ret)
 				{
-					row_span_found = true;
+					int res = ret->select(selector, apply_pseudo);
+					if(res != select_no_match)
+					{
+						if(is_pseudo)
+						{
+							if(res & select_match_pseudo_class)
+							{
+								*is_pseudo = true;
+							} else
+							{
+								*is_pseudo = false;
+							}
+						}
+						return ret;
+					}
 				}
-
+				return nullptr;
+			} else
+			{
+				ret = e;
 			}
 		}
 	}
+	return nullptr;
+}
 
-	if (row_span_found)
+litehtml::element::ptr litehtml::html_tag::find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/)
+{
+	element::ptr ret = nullptr;
+	for(auto& e : m_children)
 	{
-		for (int col = 0; col < m_grid->cols_count(); col++)
+		if(e->css().get_display() != display_inline_text)
 		{
-			for (int row = 0; row < m_grid->rows_count(); row++)
+			if(e == el)
+			{
+				return ret;
+			} else if(!ret)
 			{
-				table_cell* cell = m_grid->cell(col, row);
-				if (cell->el)
+				int res = e->select(selector, apply_pseudo);
+				if(res != select_no_match)
 				{
-					int span_row = row + cell->rowspan - 1;
-					if (span_row >= m_grid->rows_count())
-					{
-						span_row = m_grid->rows_count() - 1;
-					}
-					if (span_row != row)
+					if(is_pseudo)
 					{
-						int h = 0;
-						for (int i = row; i <= span_row; i++)
+						if(res & select_match_pseudo_class)
 						{
-							h += m_grid->row(i).height;
-						}
-						if (h < cell->el->height())
+							*is_pseudo = true;
+						} else
 						{
-							m_grid->row(span_row).height += cell->el->height() - h;
+							*is_pseudo = false;
 						}
 					}
+					ret = e;
 				}
 			}
 		}
 	}
+	return nullptr;
+}
 
-	// Calculate vertical table spacing
-	int table_height_spacing = 0;
-	if (m_border_collapse == border_collapse_separate)
-	{
-		table_height_spacing = m_border_spacing_y * (m_grid->rows_count() + 1);
-	}
-	else
-	{
-		table_height_spacing = 0;
-
-		if (m_grid->rows_count())
-		{
-			table_height_spacing -= std::min(border_top(), m_grid->row(0).border_top);
-			table_height_spacing -= std::min(border_bottom(), m_grid->row(m_grid->rows_count() - 1).border_bottom);
-		}
-
-		for (int row = 1; row < m_grid->rows_count(); row++)
-		{
-			table_height_spacing -= std::min(m_grid->row(row).border_top, m_grid->row(row - 1).border_bottom);
-		}
-	}
-
-
-	// calculate block height
-	int block_height = 0;
-	if (get_predefined_height(block_height))
-	{
-		block_height -= m_padding.height() + m_borders.height();
-	}
-
-	// calculate minimum height from m_css_min_height
-	int min_height = 0;
-	if (!m_css_min_height.is_predefined() && m_css_min_height.units() == css_units_percentage)
+bool litehtml::html_tag::is_only_child(const element::ptr& el, bool of_type) const
+{
+	int child_count = 0;
+	for(const auto& child : m_children)
 	{
-		element::ptr el_parent = parent();
-		if (el_parent)
+		if(child->css().get_display() != display_inline_text)
 		{
-			int parent_height = 0;
-			if (el_parent->get_predefined_height(parent_height))
+			if( !of_type || (of_type && el->tag() == child->tag()) )
 			{
-				min_height = m_css_min_height.calc_percent(parent_height);
+				child_count++;
 			}
+			if(child_count > 1) break;
 		}
 	}
-	else
+	if(child_count > 1)
 	{
-		min_height = (int)m_css_min_height.val();
+		return false;
 	}
+	return true;
+}
 
-	int minimum_table_height = std::max(block_height, min_height);
-
-	m_grid->calc_rows_height(minimum_table_height - table_height_spacing, m_border_spacing_y);
-	m_grid->calc_vertical_positions(m_borders, m_border_collapse, m_border_spacing_y);
-
-	int table_height = 0;
-
-	// place cells vertically
-	for (int col = 0; col < m_grid->cols_count(); col++)
+litehtml::element::ptr litehtml::html_tag::get_element_before(const style& style, bool create)
+{
+	if(!m_children.empty())
 	{
-		for (int row = 0; row < m_grid->rows_count(); row++)
+		if( m_children.front()->tag() == __tag_before_ )
 		{
-			table_cell* cell = m_grid->cell(col, row);
-			if (cell->el)
-			{
-				int span_row = row + cell->rowspan - 1;
-				if (span_row >= m_grid->rows_count())
-				{
-					span_row = m_grid->rows_count() - 1;
-				}
-				cell->el->m_pos.y = m_grid->row(row).top + cell->el->content_margins_top();
-				cell->el->m_pos.height = m_grid->row(span_row).bottom - m_grid->row(row).top - cell->el->content_margins_top() - cell->el->content_margins_bottom();
-				table_height = std::max(table_height, m_grid->row(span_row).bottom);
-				cell->el->apply_vertical_align();
-			}
+			return m_children.front();
 		}
 	}
+	if(create)
+	{
+		return add_pseudo_before(style);
+	}
+	return nullptr;
+}
 
-	if (m_border_collapse == border_collapse_collapse)
+litehtml::element::ptr litehtml::html_tag::get_element_after(const style& style, bool create)
+{
+	if(!m_children.empty())
 	{
-		if (m_grid->rows_count())
+		if( m_children.back()->tag() == __tag_after_ )
 		{
-			table_height -= std::min(border_bottom(), m_grid->row(m_grid->rows_count() - 1).border_bottom);
+			return m_children.back();
 		}
 	}
-	else
+	if(create)
 	{
-		table_height += m_border_spacing_y;
+		return add_pseudo_after(style);
 	}
-
-	m_pos.width = table_width;
-
-	calc_auto_margins(parent_width);
-
-	m_pos.move_to(x, y);
-	m_pos.x += content_margins_left();
-	m_pos.y += content_margins_top();
-	m_pos.width = table_width;
-	m_pos.height = table_height;
-
-	return max_table_width;
+	return nullptr;
 }
 
-void litehtml::html_tag::draw_children_box(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex)
+void litehtml::html_tag::add_style(const style& style)
 {
-	position pos = m_pos;
-	pos.x += x;
-	pos.y += y;
-
-	document::ptr doc = get_document();
+	m_style.combine(style);
+}
 
-	if (m_overflow > overflow_visible)
+void litehtml::html_tag::refresh_styles()
+{
+	for (auto& el : m_children)
 	{
-		position border_box = pos;
-		border_box += m_padding;
-		border_box += m_borders;
-
-		border_radiuses bdr_radius = m_css_borders.radius.calc_percents(border_box.width, border_box.height);
-
-		bdr_radius -= m_borders;
-		bdr_radius -= m_padding;
-
-		doc->container()->set_clip(pos, bdr_radius, true, true);
+		if(el->css().get_display() != display_inline_text)
+		{
+			el->refresh_styles();
+		}
 	}
 
-	position browser_wnd;
-	doc->container()->get_client_rect(browser_wnd);
+	m_style.clear();
 
-	element::ptr el;
-	for (auto& item : m_children)
+	for (auto& usel : m_used_styles)
 	{
-		el = item;
-		if (el->is_visible())
+		usel->m_used = false;
+
+		if(usel->m_selector->is_media_valid())
 		{
-			switch (flag)
+			int apply = select(*usel->m_selector, false);
+
+			if(apply != select_no_match)
 			{
-			case draw_positioned:
-				if (el->is_positioned() && el->get_zindex() == zindex)
+				if(apply & select_match_pseudo_class)
 				{
-					if (el->get_element_position() == element_position_fixed)
-					{
-						el->draw(hdc, browser_wnd.x, browser_wnd.y, clip);
-						el->draw_stacking_context(hdc, browser_wnd.x, browser_wnd.y, clip, true);
-					}
-					else
+					if(select(*usel->m_selector, true))
 					{
-						el->draw(hdc, pos.x, pos.y, clip);
-						el->draw_stacking_context(hdc, pos.x, pos.y, clip, true);
+						if(apply & select_match_with_after)
+						{
+							element::ptr el = get_element_after(*usel->m_selector->m_style, false);
+							if(el)
+							{
+								el->add_style(*usel->m_selector->m_style);
+							}
+						} else if(apply & select_match_with_before)
+						{
+							element::ptr el = get_element_before(*usel->m_selector->m_style, false);
+							if(el)
+							{
+								el->add_style(*usel->m_selector->m_style);
+							}
+						}
+						else
+						{
+							add_style(*usel->m_selector->m_style);
+							usel->m_used = true;
+						}
 					}
-					el = 0;
-				}
-				break;
-			case draw_block:
-				if (!el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
-				{
-					el->draw(hdc, pos.x, pos.y, clip);
-				}
-				break;
-			case draw_floats:
-				if (el->get_float() != float_none && !el->is_positioned())
-				{
-					el->draw(hdc, pos.x, pos.y, clip);
-					el->draw_stacking_context(hdc, pos.x, pos.y, clip, false);
-					el = 0;
-				}
-				break;
-			case draw_inlines:
-				if (el->is_inline_box() && el->get_float() == float_none && !el->is_positioned())
+				} else if(apply & select_match_with_after)
 				{
-					el->draw(hdc, pos.x, pos.y, clip);
-					if (el->get_display() == display_inline_block)
+					element::ptr el = get_element_after(*usel->m_selector->m_style, false);
+					if(el)
 					{
-						el->draw_stacking_context(hdc, pos.x, pos.y, clip, false);
-						el = 0;
+						el->add_style(*usel->m_selector->m_style);
 					}
-				}
-				break;
-			default:
-				break;
-			}
-
-			if (el)
-			{
-				if (flag == draw_positioned)
+				} else if(apply & select_match_with_before)
 				{
-					if (!el->is_positioned())
+					element::ptr el = get_element_before(*usel->m_selector->m_style, false);
+					if(el)
 					{
-						el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
+						el->add_style(*usel->m_selector->m_style);
 					}
-				}
-				else
+				} else
 				{
-					if (el->get_float() == float_none &&
-						el->get_display() != display_inline_block &&
-						!el->is_positioned())
-					{
-						el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
-					}
+					add_style(*usel->m_selector->m_style);
+					usel->m_used = true;
 				}
 			}
 		}
 	}
-
-	if (m_overflow > overflow_visible)
-	{
-		doc->container()->del_clip();
-	}
 }
 
-void litehtml::html_tag::draw_children_table(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex)
+const litehtml::background* litehtml::html_tag::get_background(bool own_only)
 {
-	if (!m_grid) return;
-
-	position pos = m_pos;
-	pos.x += x;
-	pos.y += y;
-	for (int row = 0; row < m_grid->rows_count(); row++)
+	if(own_only)
 	{
-		if (flag == draw_block)
+		// return own background with check for empty one
+		if(m_css.get_bg().is_empty())
 		{
-			m_grid->row(row).el_row->draw_background(hdc, pos.x, pos.y, clip);
+			return nullptr;
 		}
-		for (int col = 0; col < m_grid->cols_count(); col++)
+		return &m_css.get_bg();
+	}
+
+	if(m_css.get_bg().is_empty())
+	{
+		// if this is root element (<html>) try to get background from body
+		if (is_root())
 		{
-			table_cell* cell = m_grid->cell(col, row);
-			if (cell->el)
+			for (const auto& el : m_children)
 			{
-				if (flag == draw_block)
+				if( el->is_body() )
 				{
-					cell->el->draw(hdc, pos.x, pos.y, clip);
+					// return own body background
+					return el->get_background(true);
 				}
-				cell->el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
 			}
 		}
+		return nullptr;
+	}
+	
+	if(is_body())
+	{
+		element::ptr el_parent = parent();
+		if (el_parent)
+		{
+			if (!el_parent->get_background(true))
+			{
+				// parent of body will draw background for body
+				return nullptr;
+			}
+		}
+	}
+
+	return &m_css.get_bg();
+}
+
+litehtml::string litehtml::html_tag::dump_get_name()
+{
+	if(m_tag == empty_id)
+	{
+		return "anon [html_tag]";
 	}
+	return _s(m_tag) + " [html_tag]";
 }
diff --git a/src/plugins/litehtml_viewer/litehtml/html_tag.h b/src/plugins/litehtml_viewer/litehtml/html_tag.h
index 3379a719b..71b9cb345 100644
--- a/src/plugins/litehtml_viewer/litehtml/html_tag.h
+++ b/src/plugins/litehtml_viewer/litehtml/html_tag.h
@@ -8,232 +8,120 @@
 #include "borders.h"
 #include "css_selector.h"
 #include "stylesheet.h"
-#include "box.h"
+#include "line_box.h"
 #include "table.h"
 
 namespace litehtml
 {
-	struct line_context
-	{
-		int calculatedTop;
-		int top;
-		int left;
-		int right;
-
-		int width()
-		{
-			return right - left;
-		}
-		void fix_top()
-		{
-			calculatedTop = top;
-		}
-	};
 
 	class html_tag : public element
 	{
 		friend class elements_iterator;
 		friend class el_table;
 		friend class table_grid;
-		friend class block_box;
 		friend class line_box;
 	public:
-		typedef std::shared_ptr<litehtml::html_tag>	ptr;
+		typedef std::shared_ptr<html_tag>	ptr;
 	protected:
-		box::vector				m_boxes;
-		string_vector			m_class_values;
-		tstring					m_tag;
+		string_id				m_tag;
+		string_id				m_id;
+		string_vector			m_str_classes;
+		std::vector<string_id>	m_classes;
 		litehtml::style			m_style;
 		string_map				m_attrs;
-		vertical_align			m_vertical_align;
-		text_align				m_text_align;
-		style_display			m_display;
-		list_style_type			m_list_style_type;
-		list_style_position		m_list_style_position;
-		white_space				m_white_space;
-		element_float			m_float;
-		element_clear			m_clear;
-		floated_box::vector		m_floats_left;
-		floated_box::vector		m_floats_right;
-		elements_vector			m_positioned;
-		background				m_bg;
-		element_position		m_el_position;
-		int						m_line_height;
-		bool					m_lh_predefined;
-		string_vector			m_pseudo_classes;
-		used_selector::vector	m_used_styles;		
-		
-		uint_ptr				m_font;
-		int						m_font_size;
-		font_metrics			m_font_metrics;
-
-		css_margins				m_css_margins;
-		css_margins				m_css_padding;
-		css_borders				m_css_borders;
-		css_length				m_css_width;
-		css_length				m_css_height;
-		css_length				m_css_min_width;
-		css_length				m_css_min_height;
-		css_length				m_css_max_width;
-		css_length				m_css_max_height;
-		css_offsets				m_css_offsets;
-		css_length				m_css_text_indent;
-
-		overflow				m_overflow;
-		visibility				m_visibility;
-		int						m_z_index;
-		box_sizing				m_box_sizing;
-
-		int_int_cache			m_cahe_line_left;
-		int_int_cache			m_cahe_line_right;
-
-		// data for table rendering
-		std::unique_ptr<table_grid>	m_grid;
-		css_length				m_css_border_spacing_x;
-		css_length				m_css_border_spacing_y;
-		int						m_border_spacing_x;
-		int						m_border_spacing_y;
-		border_collapse			m_border_collapse;
-
-		virtual void			select_all(const css_selector& selector, elements_vector& res) override;
+		std::vector<string_id>	m_pseudo_classes;
+
+		void			select_all(const css_selector& selector, elements_vector& res) override;
 
 	public:
-		html_tag(const std::shared_ptr<litehtml::document>& doc);
-		virtual ~html_tag();
-
-		/* render functions */
-
-		virtual int					render(int x, int y, int max_width, bool second_pass = false) override;
-
-		virtual int					render_inline(const element::ptr &container, int max_width) override;
-		virtual int					place_element(const element::ptr &el, int max_width) override;
-		virtual bool				fetch_positioned() override;
-		virtual void				render_positioned(render_type rt = render_all) override;
-
-		int							new_box(const element::ptr &el, int max_width, line_context& line_ctx);
-
-		int							get_cleared_top(const element::ptr &el, int line_top) const;
-		int							finish_last_box(bool end_of_render = false);
-
-		virtual bool				appendChild(const element::ptr &el) override;
-		virtual bool				removeChild(const element::ptr &el) override;
-		virtual void				clearRecursive() override;
-		virtual const tchar_t*		get_tagName() const override;
-		virtual void				set_tagName(const tchar_t* tag) override;
-		virtual void				set_data(const tchar_t* data) override;
-		virtual element_float		get_float() const override;
-		virtual vertical_align		get_vertical_align() const override;
-		virtual css_length			get_css_left() const override;
-		virtual css_length			get_css_right() const override;
-		virtual css_length			get_css_top() const override;
-		virtual css_length			get_css_bottom() const override;
-		virtual css_length			get_css_width() const override;
-		virtual css_offsets			get_css_offsets() const override;
-		virtual void				set_css_width(css_length& w) override;
-		virtual css_length			get_css_height() const override;
-		virtual element_clear		get_clear() const override;
-		virtual size_t				get_children_count() const override;
-		virtual element::ptr		get_child(int idx) const override;
-		virtual element_position	get_element_position(css_offsets* offsets = 0) const override;
-		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) const override;
-		virtual void				apply_stylesheet(const litehtml::css& stylesheet) override;
-		virtual void				refresh_styles() override;
-
-		virtual bool				is_white_space() const override;
-		virtual bool				is_body() const override;
-		virtual bool				is_break() const override;
-		virtual int					get_base_line() override;
-		virtual bool				on_mouse_over() override;
-		virtual bool				on_mouse_leave() override;
-		virtual bool				on_lbutton_down() override;
-		virtual bool				on_lbutton_up() override;
-		virtual void				on_click() override;
-		virtual bool				find_styles_changes(position::vector& redraw_boxes, int x, int y) override;
-		virtual const tchar_t*		get_cursor() override;
-		virtual void				init_font() override;
-		virtual bool				set_pseudo_class(const tchar_t* pclass, bool add) override;
-		virtual bool				set_class(const tchar_t* pclass, bool add) override;
-		virtual bool				is_replaced() const override;
-		virtual int					line_height() const override;
-		virtual white_space			get_white_space() const override;
-		virtual style_display		get_display() const override;
-		virtual visibility			get_visibility() const override;
-		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				draw_background(uint_ptr hdc, int x, int y, const position* clip) override;
-
-		virtual const tchar_t*		get_style_property(const tchar_t* name, bool inherited, const tchar_t* def = 0) override;
-		virtual uint_ptr			get_font(font_metrics* fm = 0) override;
-		virtual int					get_font_size() const override;
-
-		elements_vector&			children();
-		virtual void				calc_outlines(int parent_width) override;
-		virtual void				calc_auto_margins(int parent_width) override;
-
-		virtual int					select(const css_selector& selector, bool apply_pseudo = true) override;
-		virtual int					select(const css_element_selector& selector, bool apply_pseudo = true) override;
-
-		virtual elements_vector		select_all(const tstring& selector) override;
-		virtual elements_vector		select_all(const css_selector& selector) override;
-
-		virtual element::ptr		select_one(const tstring& selector) override;
-		virtual element::ptr		select_one(const css_selector& selector) override;
-
-		virtual element::ptr		find_ancestor(const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;
-		virtual element::ptr		find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;
-		virtual element::ptr		find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = 0) override;
-		virtual void				get_text(tstring& text) override;
-		virtual void				parse_attributes() override;
-
-		virtual bool				is_first_child_inline(const element::ptr& el) const override;
-		virtual bool				is_last_child_inline(const element::ptr& el) override;
-		virtual bool				have_inline_child() const override;
-		virtual void				get_content_size(size& sz, int max_width) override;
-		virtual void				init() override;
-		virtual void				get_inline_boxes(position::vector& boxes) override;
-		virtual bool				is_floats_holder() const override;
-		virtual int					get_floats_height(element_float el_float = float_none) const override;
-		virtual int					get_left_floats_height() const override;
-		virtual int					get_right_floats_height() const override;
-		virtual int					get_line_left(int y) override;
-		virtual int					get_line_right(int y, int def_right) override;
-		virtual void				get_line_left_right(int y, int def_right, int& ln_left, int& ln_right) override;
-		virtual void				add_float(const element::ptr &el, int x, int y) override;
-		virtual void				update_floats(int dy, const element::ptr &parent) override;
-		virtual void				add_positioned(const element::ptr &el) override;
-		virtual int					find_next_line_top(int top, int width, int def_right) override;
-		virtual void				apply_vertical_align() override;
-		virtual void				draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override;
-		virtual int					get_zindex() const override;
-		virtual void				draw_stacking_context(uint_ptr hdc, int x, int y, const position* clip, bool with_positioned) override;
-		virtual void				calc_document_size(litehtml::size& sz, int x = 0, int y = 0) override;
-		virtual void				get_redraw_box(litehtml::position& pos, int x = 0, int y = 0) override;
-		virtual void				add_style(const litehtml::style& st) override;
-		virtual element::ptr		get_element_by_point(int x, int y, int client_x, int client_y) override;
-		virtual element::ptr		get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex) override;
-
-		virtual bool				is_nth_child(const element::ptr& el, int num, int off, bool of_type) const override;
-		virtual bool				is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const override;
-		virtual bool				is_only_child(const element::ptr& el, bool of_type) const override;
-		virtual const background*	get_background(bool own_only = false) override;
+		explicit html_tag(const std::shared_ptr<document>& doc);
+		// constructor for anonymous wrapper boxes
+		explicit html_tag(const element::ptr& parent, const string& style = "display: block");
+
+		bool				appendChild(const element::ptr &el) override;
+		bool				removeChild(const element::ptr &el) override;
+		void				clearRecursive() override;
+		string_id			tag() const override;
+		string_id			id() const override;
+		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;
+		void				apply_stylesheet(const litehtml::css& stylesheet) override;
+		void				refresh_styles() override;
+
+		bool				is_white_space() const override;
+		bool				is_body() const override;
+		bool				is_break() const override;
+
+		bool				on_mouse_over() override;
+		bool				on_mouse_leave() override;
+		bool				on_lbutton_down() override;
+		bool				on_lbutton_up() override;
+		void				on_click() override;
+		bool				set_pseudo_class(string_id cls, bool add) override;
+		bool				set_class(const char* pclass, bool add) override;
+		bool				is_replaced() const override;
+		void				compute_styles(bool recursive = true) override;
+		void				draw(uint_ptr hdc, int x, int y, const position *clip, const std::shared_ptr<render_item> &ri) override;
+		void				draw_background(uint_ptr hdc, int x, int y, const position *clip,
+									const std::shared_ptr<render_item> &ri) override;
+
+		template<class Type, property_type property_value_type, Type property_value::* property_value_member>
+		const Type&			get_property_impl  (string_id name, bool inherited, const Type&   default_value, uint_ptr css_properties_member_offset) const;
+		int					get_enum_property  (string_id name, bool inherited, int           default_value, uint_ptr css_properties_member_offset) const override;
+		css_length			get_length_property(string_id name, bool inherited, css_length    default_value, uint_ptr css_properties_member_offset) const override;
+		web_color			get_color_property (string_id name, bool inherited, web_color     default_value, uint_ptr css_properties_member_offset) const override;
+		string				get_string_property(string_id name, bool inherited, const string& default_value, uint_ptr css_properties_member_offset) const override;
+		float				get_number_property(string_id name, bool inherited, float         default_value, uint_ptr css_properties_member_offset) const override;
+		string_vector		get_string_vector_property(string_id name, bool inherited, const string_vector& default_value, uint_ptr css_properties_member_offset) const override;
+		int_vector			get_int_vector_property   (string_id name, bool inherited, const int_vector&    default_value, uint_ptr css_properties_member_offset) const override;
+		length_vector		get_length_vector_property(string_id name, bool inherited, const length_vector& default_value, uint_ptr css_properties_member_offset) const override;
+		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();
+
+		int					select(const string& selector) override;
+		int					select(const css_selector& selector, bool apply_pseudo = true) override;
+		int					select(const css_element_selector& selector, bool apply_pseudo = true) override;
+		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;
+
+		element::ptr		select_one(const string& selector) override;
+		element::ptr		select_one(const css_selector& selector) override;
+
+		element::ptr		find_ancestor(const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = nullptr) override;
+		element::ptr		find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = nullptr) override;
+		element::ptr		find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = nullptr) override;
+		void				get_text(string& text) override;
+		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;
+		bool				is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const override;
+		bool				is_only_child(const element::ptr& el, bool of_type) const override;
+		const background*	get_background(bool own_only = false) override;
+
+		string				dump_get_name() override;
 
 	protected:
-		void						draw_children_box(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex);
-		void						draw_children_table(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex);
-		int							render_box(int x, int y, int max_width, bool second_pass = false);
-		int							render_table(int x, int y, int max_width, bool second_pass = false);
-		int							fix_line_width(int max_width, element_float flt);
-		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();
-		litehtml::element::ptr		get_element_after();
+		void				init_background_paint(position pos, std::vector<background_paint>& bg_paint, const background* bg, const std::shared_ptr<render_item>& ri);
+		void				init_one_background_paint(int i, position pos, background_paint& bg_paint, const background* bg, const std::shared_ptr<render_item>& ri);
+		void				draw_list_marker( uint_ptr hdc, const position &pos );
+		string				get_list_marker_text(int index);
+		element::ptr		get_element_before(const style& style, bool create);
+		element::ptr		get_element_after(const style& style, bool create);
 	};
 
 	/************************************************************************/
diff --git a/src/plugins/litehtml_viewer/litehtml/iterators.cpp b/src/plugins/litehtml_viewer/litehtml/iterators.cpp
index 9d6a623d8..5b3238ad2 100644
--- a/src/plugins/litehtml_viewer/litehtml/iterators.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/iterators.cpp
@@ -1,92 +1,99 @@
 #include "html.h"
 #include "iterators.h"
 #include "html_tag.h"
+#include "render_item.h"
+#include <iterator>
 
-litehtml::element::ptr litehtml::elements_iterator::next(bool ret_parent)
+litehtml::elements_iterator::elements_iterator(bool return_parents, iterator_selector* go_inside, iterator_selector* select) :
+    m_return_parent(return_parents),
+    m_go_inside(go_inside),
+    m_select(select)
 {
-	next_idx();
-
-	while(m_idx < (int) m_el->get_children_count())
-	{
-		element::ptr el = m_el->get_child(m_idx);
-		if(	el->get_children_count() && m_go_inside && m_go_inside->select(el) )
-		{
-			stack_item si;
-			si.idx		= m_idx;
-			si.el		= m_el;
-			m_stack.push_back(si);
-			m_el		= el;
-			m_idx		= -1;
-			if(ret_parent)
-			{
-				return el;
-			}
-			next_idx();
-		} else
-		{
-			if( !m_select || (m_select && m_select->select(m_el->get_child(m_idx))) )
-			{
-				return m_el->get_child(m_idx);
-			} else
-			{
-				next_idx();
-			}
-		}
-	}
+}
 
-	return 0;
+bool litehtml::elements_iterator::go_inside(const std::shared_ptr<render_item>& el)
+{
+    return 	/*!el->children().empty() &&*/ m_go_inside && m_go_inside->select(el);
 }
 
-void litehtml::elements_iterator::next_idx()
+void litehtml::elements_iterator::process(const std::shared_ptr<render_item>& container, const std::function<void (std::shared_ptr<render_item>&, iterator_item_type)>& func)
 {
-	m_idx++;
-	while(m_idx >= (int) m_el->get_children_count() && m_stack.size())
-	{
-		stack_item si = m_stack.back();
-		m_stack.pop_back();
-		m_idx	= si.idx;
-		m_el	= si.el;
-		m_idx++;
-		continue;
-	}
+    for(auto& el : container->children())
+    {
+        if(go_inside(el))
+        {
+            if(m_return_parent)
+            {
+                // call function for parent
+                func(el, iterator_item_type_start_parent);
+            }
+            // go inside element and process its items
+            process(el, func);
+			if(m_return_parent)
+			{
+				// call function for parent
+				func(el, iterator_item_type_end_parent);
+			}
+        } else
+        {
+            // call function for element
+            if(!m_select || m_select->select(el))
+            {
+                func(el, iterator_item_type_child);
+            }
+        }
+    }
 }
 
 //////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////
 
 
-bool litehtml::go_inside_inline::select(const element::ptr& el)
+bool litehtml::go_inside_inline::select(const std::shared_ptr<render_item>& el)
 {
-	if(el->get_display() == display_inline || el->get_display() == display_inline_text)
+	if(el->src_el()->css().get_display() == display_inline && el->src_el()->css().get_float() == float_none)
 	{
 		return true;
 	}
 	return false;
 }
 
-bool litehtml::go_inside_table::select(const element::ptr& el)
+bool litehtml::inline_selector::select(const std::shared_ptr<render_item>& el)
+{
+    if(el->src_el()->css().get_display() == display_inline_text ||
+        el->src_el()->css().get_display() == display_inline_table ||
+        el->src_el()->css().get_display() == display_inline_block ||
+        el->src_el()->css().get_display() == display_inline_flex ||
+        el->src_el()->css().get_float() != float_none)
+    {
+        return true;
+    }
+    return false;
+}
+
+bool litehtml::go_inside_table::select(const std::shared_ptr<render_item>& el)
 {
-	if(	el->get_display() == display_table_row_group ||
-		el->get_display() == display_table_header_group ||
-		el->get_display() == display_table_footer_group)
+	if(	el->src_el()->css().get_display() == display_table_row_group ||
+		el->src_el()->css().get_display() == display_table_header_group ||
+		el->src_el()->css().get_display() == display_table_footer_group)
 	{
 		return true;
 	}
 	return false;
 }
 
-bool litehtml::table_rows_selector::select(const element::ptr& el)
+bool litehtml::table_rows_selector::select(const std::shared_ptr<render_item>& el)
 {
-	if(	el->get_display() == display_table_row)
+	if(	el->src_el()->css().get_display() == display_table_row)
 	{
 		return true;
 	}
 	return false;
 }
 
-bool litehtml::table_cells_selector::select(const element::ptr& el)
+bool litehtml::table_cells_selector::select(const std::shared_ptr<render_item>& el)
 {
-	if(	el->get_display() == display_table_cell)
+	if(	el->src_el()->css().get_display() == display_table_cell)
 	{
 		return true;
 	}
diff --git a/src/plugins/litehtml_viewer/litehtml/iterators.h b/src/plugins/litehtml_viewer/litehtml/iterators.h
index 53f23c337..b1a678d7b 100644
--- a/src/plugins/litehtml_viewer/litehtml/iterators.h
+++ b/src/plugins/litehtml_viewer/litehtml/iterators.h
@@ -2,88 +2,82 @@
 #define LH_ITERATORS_H
 
 #include "types.h"
+#include <list>
+#include <functional>
 
 namespace litehtml
 {
-	class element;
+	class render_item;
 
 	class iterator_selector
 	{
 	public:
-		virtual bool select(const element::ptr& el) = 0;
+		virtual bool select(const std::shared_ptr<render_item>& el) = 0;
+
+        protected:
+		~iterator_selector() = default;
+	};
+
+	enum iterator_item_type
+	{
+		iterator_item_type_child,
+		iterator_item_type_start_parent,
+		iterator_item_type_end_parent
 	};
 
 	class elements_iterator
 	{
 	private:
-		struct stack_item
-		{
-			int				idx;
-			element::ptr	el;
-			stack_item()
-			{
+		iterator_selector* m_go_inside;
+		iterator_selector* m_select;
+        bool m_return_parent;
 
-			}
-			stack_item(const stack_item& val)
-			{
-				idx = val.idx;
-				el = val.el;
-			}
-			stack_item(stack_item&& val)
-			{
-				idx = val.idx;
-				el = std::move(val.el);
-			}
-		};
+        /**
+         * Checks if iterator should go inside the element
+         *
+         * @param el element to check
+         * @return true to go inside
+         */
+        bool go_inside(const std::shared_ptr<render_item>& el);
 
-		std::vector<stack_item>		m_stack;
-		element::ptr				m_el;
-		int							m_idx;
-		iterator_selector*			m_go_inside;
-		iterator_selector*			m_select;
 	public:
+		elements_iterator(bool return_parents, iterator_selector* go_inside, iterator_selector* select);
+		~elements_iterator() = default;
 
-		elements_iterator(const element::ptr& el, iterator_selector* go_inside, iterator_selector* select)
-		{ 
-			m_el			= el;
-			m_idx			= -1; 
-			m_go_inside		= go_inside;
-			m_select		= select;
-		}
-
-		~elements_iterator()
-		{
-
-		}
-
-		element::ptr next(bool ret_parent = true);
+        void process(const std::shared_ptr<render_item>& container, const std::function<void (std::shared_ptr<render_item>&, iterator_item_type)>& func);
 	
 	private:
 		void next_idx();
 	};
 
-	class go_inside_inline : public iterator_selector
+	class go_inside_inline final : public iterator_selector
 	{
 	public:
-		virtual bool select(const element::ptr& el);
+		bool select(const std::shared_ptr<render_item>& el) override;
 	};
 
-	class go_inside_table : public iterator_selector
+    class inline_selector final : public iterator_selector
+    {
+    public:
+        bool select(const std::shared_ptr<render_item>& el) override;
+    };
+
+	class go_inside_table final : public iterator_selector
 	{
 	public:
-		virtual bool select(const element::ptr& el);
+		bool select(const std::shared_ptr<render_item>& el) override;
 	};
 
-	class table_rows_selector : public iterator_selector
+	class table_rows_selector final : public iterator_selector
 	{
 	public:
-		virtual bool select(const element::ptr& el);
+		bool select(const std::shared_ptr<render_item>& el) override;
 	};
 
-	class table_cells_selector : public iterator_selector
+	class table_cells_selector final : public iterator_selector
 	{
 	public:
-		virtual bool select(const element::ptr& el);
+		bool select(const std::shared_ptr<render_item>& el) override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/line_box.cpp b/src/plugins/litehtml_viewer/litehtml/line_box.cpp
new file mode 100644
index 000000000..269dd4672
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/line_box.cpp
@@ -0,0 +1,698 @@
+#include "html.h"
+#include "line_box.h"
+#include "element.h"
+#include "render_item.h"
+#include <algorithm>
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void litehtml::line_box_item::place_to(int x, int y)
+{
+	m_element->pos().x = x + m_element->content_offset_left();
+	m_element->pos().y = y + m_element->content_offset_top();
+}
+
+litehtml::position& litehtml::line_box_item::pos()
+{
+	return m_element->pos();
+}
+
+
+int litehtml::line_box_item::width() const
+{
+	return m_element->width();
+}
+
+int litehtml::line_box_item::top() const
+{
+	return m_element->top();
+}
+
+int litehtml::line_box_item::bottom() const
+{
+	return m_element->bottom();
+}
+
+int litehtml::line_box_item::right() const
+{
+	return m_element->right();
+}
+
+int litehtml::line_box_item::left() const
+{
+	return m_element->left();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+litehtml::lbi_start::lbi_start(const std::shared_ptr<render_item>& element) : line_box_item(element)
+{
+	m_pos.height = m_element->src_el()->css().get_font_metrics().height;
+	m_pos.width = m_element->content_offset_left();
+}
+
+void litehtml::lbi_start::place_to(int x, int y)
+{
+	m_pos.x = x + m_element->content_offset_left();
+	m_pos.y = y;
+}
+
+int litehtml::lbi_start::width() const
+{
+	return m_pos.width;
+}
+
+int litehtml::lbi_start::top() const
+{
+	return m_pos.y;
+}
+
+int litehtml::lbi_start::bottom() const
+{
+	return m_pos.y + m_pos.height;
+}
+
+int litehtml::lbi_start::right() const
+{
+	return m_pos.x;
+}
+
+int litehtml::lbi_start::left() const
+{
+	return m_pos.x - m_element->content_offset_left();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+litehtml::lbi_end::lbi_end(const std::shared_ptr<render_item>& element) : lbi_start(element)
+{
+	m_pos.height = m_element->src_el()->css().get_font_metrics().height;
+	m_pos.width = m_element->content_offset_right();
+}
+
+void litehtml::lbi_end::place_to(int x, int y)
+{
+	m_pos.x = x;
+	m_pos.y = y;
+}
+
+int litehtml::lbi_end::right() const
+{
+	return m_pos.x + m_pos.width;
+}
+
+int litehtml::lbi_end::left() const
+{
+	return m_pos.x;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+litehtml::lbi_continue::lbi_continue(const std::shared_ptr<render_item>& element) : lbi_start(element)
+{
+	m_pos.height = m_element->src_el()->css().get_font_metrics().height;
+	m_pos.width = 0;
+}
+
+void litehtml::lbi_continue::place_to(int x, int y)
+{
+	m_pos.x = x;
+	m_pos.y = y;
+}
+
+int litehtml::lbi_continue::right() const
+{
+	return m_pos.x;
+}
+
+int litehtml::lbi_continue::left() const
+{
+	return m_pos.x;
+}
+
+int litehtml::lbi_continue::width() const
+{
+	return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void litehtml::line_box::add_item(std::unique_ptr<line_box_item> item)
+{
+    item->get_el()->skip(false);
+    bool add	= true;
+	switch (item->get_type())
+	{
+		case line_box_item::type_text_part:
+			if(item->get_el()->src_el()->is_white_space())
+			{
+				add = !is_empty() && !have_last_space();
+			}
+			break;
+		case line_box_item::type_inline_start:
+		case line_box_item::type_inline_end:
+		case line_box_item::type_inline_continue:
+			add = true;
+			break;
+	}
+	if(add)
+	{
+		item->place_to(m_left + m_width, m_top);
+		m_width += item->width();
+		m_height = std::max(m_height, item->get_el()->height());
+		m_items.emplace_back(std::move(item));
+	} else
+	{
+		item->get_el()->skip(true);
+	}
+}
+
+int litehtml::line_box::calc_va_baseline(const va_context& current, vertical_align va, const font_metrics& new_font, int top, int bottom)
+{
+	switch(va)
+	{
+		case va_super:
+			return current.baseline - current.fm.height / 3;
+		case va_sub:
+			return current.baseline + current.fm.height / 3;
+		case va_middle:
+			return current.baseline - current.fm.x_height / 2;
+		case va_text_top:
+			return current.baseline - (current.fm.height - current.fm.base_line()) +
+										new_font.height - new_font.base_line();
+		case va_text_bottom:
+			return current.baseline + current.fm.base_line() - new_font.base_line();
+		case va_top:
+			return top + new_font.height - new_font.base_line();
+		case va_bottom:
+			return bottom - new_font.height + new_font.base_line();
+		default:
+			return current.baseline;
+	}
+}
+
+std::list< std::unique_ptr<litehtml::line_box_item> > litehtml::line_box::finish(bool last_box, const containing_block_context &containing_block_size)
+{
+	std::list< std::unique_ptr<line_box_item> > ret_items;
+
+	if(!last_box)
+	{
+		while(!m_items.empty())
+		{
+			if (m_items.back()->get_type() == line_box_item::type_text_part)
+			{
+				// remove trailing spaces
+				if (m_items.back()->get_el()->src_el()->is_break() ||
+					m_items.back()->get_el()->src_el()->is_white_space())
+				{
+					m_width -= m_items.back()->width();
+					m_items.back()->get_el()->skip(true);
+					m_items.pop_back();
+				} else
+				{
+					break;
+				}
+			} else if (m_items.back()->get_type() == line_box_item::type_inline_start)
+			{
+				// remove trailing empty inline_start markers
+				// these markers will be added at the beginning of the next line box
+				m_width -= m_items.back()->width();
+				ret_items.emplace_back(std::move(m_items.back()));
+				m_items.pop_back();
+			} else
+			{
+				break;
+			}
+		}
+	} else
+	{
+		// remove trailing spaces
+		auto iter = m_items.rbegin();
+		while(iter != m_items.rend())
+		{
+			if ((*iter)->get_type() == line_box_item::type_text_part)
+			{
+				if((*iter)->get_el()->src_el()->is_white_space())
+				{
+					(*iter)->get_el()->skip(true);
+					m_width -= (*iter)->width();
+					// Space can be between text and inline_end marker
+					// We have to shift all items on the right side
+					if(iter != m_items.rbegin())
+					{
+						auto r_iter = iter;
+						r_iter--;
+						while (true)
+						{
+							(*r_iter)->pos().x -= (*iter)->width();
+							if (r_iter == m_items.rbegin())
+							{
+								break;
+							}
+							r_iter--;
+						}
+					}
+					// erase white space element
+					iter = decltype(iter) (m_items.erase( std::next(iter).base() ));
+				} else
+				{
+					break;
+				}
+			} else
+			{
+				iter++;
+			}
+		}
+	}
+
+    if( is_empty() || (!is_empty() && last_box && is_break_only()) )
+    {
+        m_height = m_default_line_height;
+		m_baseline = m_font_metrics.base_line();
+        return ret_items;
+    }
+
+    int spc_x = 0;
+
+    int add_x = 0;
+    switch(m_text_align)
+    {
+        case text_align_right:
+            if(m_width < (m_right - m_left))
+            {
+                add_x = (m_right - m_left) - m_width;
+            }
+            break;
+        case text_align_center:
+            if(m_width < (m_right - m_left))
+            {
+                add_x = ((m_right - m_left) - m_width) / 2;
+            }
+            break;
+        case text_align_justify:
+            if (m_width < (m_right - m_left))
+            {
+                add_x = 0;
+                spc_x = (m_right - m_left) - m_width;
+                if (spc_x > m_width/4)
+                    spc_x = 0;
+            }
+            break;
+        default:
+            add_x = 0;
+    }
+
+    int counter = 0;
+    float offj  = float(spc_x) / std::max(1.f, float(m_items.size())-1.f);
+    float cixx  = 0.0f;
+
+    int line_top	= 0;
+    int line_bottom	= 0;
+
+	va_context current_context;
+	std::list<va_context> contexts;
+
+	current_context.baseline = 0;
+	current_context.fm = m_font_metrics;
+
+	m_min_width = 0;
+
+    for (const auto& lbi : m_items)
+    {
+		m_min_width += lbi->get_rendered_min_width();
+		{ // start text_align_justify
+			if (spc_x && counter)
+			{
+				cixx += offj;
+				if ((counter + 1) == int(m_items.size()))
+					cixx += 0.99f;
+				lbi->pos().x += int(cixx);
+			}
+			counter++;
+			if ((m_text_align == text_align_right || spc_x) && counter == int(m_items.size()))
+			{
+				// Forcible justify the last element to the right side for text align right and justify;
+				lbi->pos().x = m_right - lbi->pos().width;
+			} else if (add_x)
+			{
+				lbi->pos().x += add_x;
+			}
+		} // end text_align_justify
+
+		if (lbi->get_type() == line_box_item::type_inline_start || lbi->get_type() == line_box_item::type_inline_continue)
+		{
+			contexts.push_back(current_context);
+			current_context.baseline = calc_va_baseline(current_context,
+														lbi->get_el()->css().get_vertical_align(),
+														lbi->get_el()->css().get_font_metrics(),
+														line_top, line_bottom);
+			current_context.fm = lbi->get_el()->css().get_font_metrics();
+		}
+
+		// Align elements vertically by baseline.
+        if(lbi->get_el()->src_el()->css().get_display() == display_inline_text || lbi->get_el()->src_el()->css().get_display() == display_inline)
+        {
+			// inline elements and text are aligned by baseline only
+			// at this point the baseline for text is properly aligned already
+			lbi->pos().y = current_context.baseline - lbi->get_el()->css().get_font_metrics().height + lbi->get_el()->css().get_font_metrics().base_line();
+        } else
+        {
+            switch(lbi->get_el()->css().get_vertical_align())
+            {
+				case va_sub:
+                case va_super:
+					{
+						int bl = calc_va_baseline(current_context, lbi->get_el()->css().get_vertical_align(), current_context.fm, line_top, line_bottom);
+						lbi->pos().y = bl - lbi->get_el()->height() + lbi->get_el()->get_base_line() +
+								lbi->get_el()->content_offset_top();
+					}
+					break;
+				case va_bottom:
+					lbi->pos().y = line_bottom - lbi->get_el()->height() + lbi->get_el()->content_offset_top();
+					break;
+				case va_top:
+					lbi->pos().y = line_top + lbi->get_el()->content_offset_top();
+					break;
+                case va_baseline:
+					lbi->pos().y = current_context.baseline - lbi->get_el()->height() + lbi->get_el()->get_base_line() +
+							lbi->get_el()->content_offset_top();
+                    break;
+                case va_text_top:
+					lbi->pos().y = current_context.baseline - current_context.fm.height + current_context.fm.base_line() +
+							lbi->get_el()->content_offset_top();
+                    break;
+				case va_text_bottom:
+					lbi->pos().y = current_context.baseline + current_context.fm.base_line() - lbi->get_el()->height() +
+							lbi->get_el()->content_offset_top();
+					break;
+                case va_middle:
+					lbi->pos().y = current_context.baseline - current_context.fm.x_height / 2 - lbi->get_el()->height() / 2 +
+							lbi->get_el()->content_offset_top();
+                    break;
+            }
+        }
+
+		if (lbi->get_type() == line_box_item::type_inline_end)
+		{
+			if(!contexts.empty())
+			{
+				current_context = contexts.back();
+				contexts.pop_back();
+			}
+		}
+
+		// calculate line height
+		line_top = std::min(line_top, lbi->top());
+		line_bottom = std::max(line_bottom, lbi->bottom());
+
+		if(lbi->get_el()->src_el()->css().get_display() == display_inline_text)
+		{
+			m_line_height = std::max(m_line_height, lbi->get_el()->css().get_line_height());
+		}
+    }
+
+	m_height = line_bottom - line_top;
+	int top_shift = line_top;
+	if(m_height < m_line_height)
+	{
+		top_shift -= (m_line_height - m_height) / 2;
+		m_height = m_line_height;
+	}
+	m_baseline = line_bottom;
+
+	struct inline_item_box
+	{
+		std::shared_ptr<render_item> element;
+		position box;
+
+		inline_item_box() = default;
+		explicit inline_item_box(const std::shared_ptr<render_item>& el) : element(el) {}
+	};
+
+	std::list<inline_item_box> inlines;
+
+	contexts.clear();
+
+	current_context.baseline = 0;
+	current_context.fm = m_font_metrics;
+	bool va_top_bottom = false;
+
+    for (const auto& lbi : m_items)
+    {
+		// Calculate baseline. Now we calculate baseline for vertical alignment top and bottom
+		if (lbi->get_type() == line_box_item::type_inline_start || lbi->get_type() == line_box_item::type_inline_continue)
+		{
+			contexts.push_back(current_context);
+			va_top_bottom = lbi->get_el()->css().get_vertical_align() == va_bottom || lbi->get_el()->css().get_vertical_align() == va_top;
+			current_context.baseline = calc_va_baseline(current_context,
+														lbi->get_el()->css().get_vertical_align(),
+														lbi->get_el()->css().get_font_metrics(),
+														top_shift, top_shift + m_height);
+			current_context.fm = lbi->get_el()->css().get_font_metrics();
+		}
+
+		// Align inlines and text by baseline if current vertical alignment is top or bottom
+		if(va_top_bottom)
+		{
+			if (lbi->get_el()->src_el()->css().get_display() == display_inline_text ||
+				lbi->get_el()->src_el()->css().get_display() == display_inline)
+			{
+				// inline elements and text are aligned by baseline only
+				// at this point the baseline for text is properly aligned already
+				lbi->pos().y = current_context.baseline - lbi->get_el()->css().get_font_metrics().height +
+							   lbi->get_el()->css().get_font_metrics().base_line();
+			}
+		}
+
+		// Pop the prev context
+		if (lbi->get_type() == line_box_item::type_inline_end)
+		{
+			if(!contexts.empty())
+			{
+				current_context = contexts.back();
+				contexts.pop_back();
+			}
+		}
+
+		// move element to the correct position
+		lbi->pos().y += m_top - top_shift;
+
+		// Perform vertical align top and bottom for inline boxes
+        if(lbi->get_el()->css().get_display() != display_inline_text && lbi->get_el()->css().get_display() != display_inline)
+        {
+            if(lbi->get_el()->css().get_vertical_align() == va_top)
+			{
+				lbi->pos().y = m_top + lbi->get_el()->content_offset_top();
+			} else if(lbi->get_el()->css().get_vertical_align() == va_bottom)
+			{
+				lbi->pos().y = m_top + m_height - lbi->get_el()->height() + lbi->get_el()->content_offset_top();
+			}
+        }
+        lbi->get_el()->apply_relative_shift(containing_block_size);
+
+		// Calculate and push inline box into the render item element
+		if(lbi->get_type() == line_box_item::type_inline_start || lbi->get_type() == line_box_item::type_inline_continue)
+		{
+			if(lbi->get_type() == line_box_item::type_inline_start)
+			{
+				lbi->get_el()->clear_inline_boxes();
+			}
+			inlines.emplace_back(lbi->get_el());
+			inlines.back().box.x = lbi->left();
+			inlines.back().box.y = lbi->top() - lbi->get_el()->content_offset_top();
+			inlines.back().box.height = lbi->bottom() - lbi->top() + lbi->get_el()->content_offset_height();
+		} else if(lbi->get_type() == line_box_item::type_inline_end)
+		{
+			if(!inlines.empty())
+			{
+				inlines.back().box.width = lbi->right() - inlines.back().box.x;
+				inlines.back().element->add_inline_box(inlines.back().box);
+				inlines.pop_back();
+			}
+		}
+    }
+
+	for(auto iter = inlines.rbegin(); iter != inlines.rend(); ++iter)
+	{
+		iter->box.width =  m_items.back()->right() - iter->box.x;
+		iter->element->add_inline_box(iter->box);
+
+		ret_items.emplace_front(std::unique_ptr<line_box_item>(new lbi_continue(iter->element)));
+	}
+
+	return std::move(ret_items);
+}
+
+std::shared_ptr<litehtml::render_item> litehtml::line_box::get_first_text_part() const
+{
+	for(const auto & item : m_items)
+	{
+		if(item->get_type() == line_box_item::type_text_part)
+		{
+			return item->get_el();
+		}
+	}
+	return nullptr;
+}
+
+
+std::shared_ptr<litehtml::render_item> litehtml::line_box::get_last_text_part() const
+{
+	for(auto iter = m_items.rbegin(); iter != m_items.rend(); iter++)
+	{
+		if((*iter)->get_type() == line_box_item::type_text_part)
+		{
+			return (*iter)->get_el();
+		}
+	}
+	return nullptr;
+}
+
+
+bool litehtml::line_box::can_hold(const std::unique_ptr<line_box_item>& item, white_space ws) const
+{
+    if(!item->get_el()->src_el()->is_inline_box()) return false;
+
+	if(item->get_type() == line_box_item::type_text_part)
+	{
+		auto last_el = get_last_text_part();
+
+		// force new line if the last placed element was line break
+		if (last_el && last_el->src_el()->is_break())
+		{
+			return false;
+		}
+
+		// line break should stay in current line box
+		if (item->get_el()->src_el()->is_break())
+		{
+			return true;
+		}
+
+		if (ws == white_space_nowrap || ws == white_space_pre ||
+			(ws == white_space_pre_wrap && item->get_el()->src_el()->is_space()))
+		{
+			return true;
+		}
+
+		if (m_left + m_width + item->width() > m_right)
+		{
+			return false;
+		}
+	}
+
+    return true;
+}
+
+bool litehtml::line_box::have_last_space()  const
+{
+	auto last_el = get_last_text_part();
+	if(last_el)
+	{
+		return last_el->src_el()->is_white_space() || last_el->src_el()->is_break();
+	}
+	return false;
+}
+
+bool litehtml::line_box::is_empty() const
+{
+    if(m_items.empty()) return true;
+    for (const auto& el : m_items)
+    {
+		if(el->get_type() == line_box_item::type_text_part)
+		{
+			if (!el->get_el()->skip() || el->get_el()->src_el()->is_break())
+			{
+				return false;
+			}
+		}
+    }
+    return true;
+}
+
+int litehtml::line_box::baseline() const
+{
+    return m_baseline;
+}
+
+int litehtml::line_box::top_margin() const
+{
+    return 0;
+}
+
+int litehtml::line_box::bottom_margin() const
+{
+    return 0;
+}
+
+void litehtml::line_box::y_shift( int shift )
+{
+	m_top += shift;
+    for (auto& el : m_items)
+    {
+        el->pos().y += shift;
+    }
+}
+
+bool litehtml::line_box::is_break_only() const
+{
+    if(m_items.empty()) return false;
+
+	bool break_found = false;
+
+	for (auto iter = m_items.rbegin(); iter != m_items.rend(); iter++)
+	{
+		if((*iter)->get_type() == line_box_item::type_text_part)
+		{
+			if((*iter)->get_el()->src_el()->is_break())
+			{
+				break_found = true;
+			} else if(!(*iter)->get_el()->skip())
+			{
+				return false;
+			}
+		}
+	}
+	return break_found;
+}
+
+std::list< std::unique_ptr<litehtml::line_box_item> > litehtml::line_box::new_width( int left, int right)
+{
+	std::list< std::unique_ptr<line_box_item> > ret_items;
+    int add = left - m_left;
+    if(add)
+    {
+		m_left	= left;
+		m_right	= right;
+        m_width = 0;
+        auto remove_begin = m_items.end();
+		auto i = m_items.begin();
+		i++;
+		while (i != m_items.end())
+        {
+            if(!(*i)->get_el()->skip())
+            {
+                if(m_left + m_width + (*i)->width() > m_right)
+                {
+                    remove_begin = i;
+                    break;
+                } else
+                {
+					(*i)->pos().x += add;
+                    m_width += (*i)->get_el()->width();
+                }
+            }
+			i++;
+        }
+        if(remove_begin != m_items.end())
+        {
+			while(remove_begin != m_items.end())
+			{
+				ret_items.emplace_back(std::move(*remove_begin));
+			}
+            m_items.erase(remove_begin, m_items.end());
+        }
+    }
+	return ret_items;
+}
+
diff --git a/src/plugins/litehtml_viewer/litehtml/line_box.h b/src/plugins/litehtml_viewer/litehtml/line_box.h
new file mode 100644
index 000000000..43f5d439e
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/line_box.h
@@ -0,0 +1,170 @@
+#ifndef LH_LINE_BOX_H
+#define LH_LINE_BOX_H
+
+#include <vector>
+#include <memory>
+#include "os_types.h"
+#include "types.h"
+
+namespace litehtml
+{
+    class render_item;
+
+    struct line_context
+    {
+        int calculatedTop;
+        int top;
+        int left;
+        int right;
+
+        int width() const
+        {
+            return right - left;
+        }
+        void fix_top()
+        {
+            calculatedTop = top;
+        }
+    };
+
+	class line_box_item
+	{
+	public:
+		enum element_type
+		{
+			type_text_part,
+			type_inline_start,
+			type_inline_continue,
+			type_inline_end
+		};
+	protected:
+		std::shared_ptr<render_item> m_element;
+		int m_rendered_min_width;
+	public:
+		explicit line_box_item(const std::shared_ptr<render_item>& element) : m_element(element), m_rendered_min_width(0) {}
+		line_box_item() = default;
+		line_box_item(const line_box_item& el) = default;
+		line_box_item(line_box_item&&) = default;
+
+		int height() const { return right() - left(); }
+		const std::shared_ptr<render_item>& get_el() const { return m_element; }
+		virtual position& pos();
+		virtual void place_to(int x, int y);
+		virtual int width() const;
+		virtual int top() const;
+		virtual int bottom() const;
+		virtual int right() const;
+		virtual int left() const;
+		virtual element_type get_type() const	{ return type_text_part; }
+		virtual int get_rendered_min_width() const	{ return m_rendered_min_width; }
+		virtual void set_rendered_min_width(int min_width)	{ m_rendered_min_width = min_width; }
+	};
+
+	class lbi_start : public line_box_item
+	{
+	protected:
+		position m_pos;
+	public:
+		explicit lbi_start(const std::shared_ptr<render_item>& element);
+
+		void place_to(int x, int y) override;
+		int width() const override;
+		position& pos() override { return m_pos; }
+		int top() const override;
+		int bottom() const override;
+		int right() const override;
+		int left() const override;
+		element_type get_type() const override	{ return type_inline_start; }
+		int get_rendered_min_width() const override { return width(); }
+	};
+
+	class lbi_end : public lbi_start
+	{
+	public:
+		explicit lbi_end(const std::shared_ptr<render_item>& element);
+
+		void place_to(int x, int y) override;
+		int right() const override;
+		int left() const override;
+		element_type get_type() const override	{ return type_inline_end; }
+	};
+
+	class lbi_continue : public lbi_start
+	{
+	public:
+		explicit lbi_continue(const std::shared_ptr<render_item>& element);
+
+		void place_to(int x, int y) override;
+		int right() const override;
+		int left() const override;
+		int width() const override;
+		element_type get_type() const override	{ return type_inline_continue; }
+	};
+
+	class line_box
+    {
+		struct va_context
+		{
+			int 			baseline;
+			font_metrics 	fm;
+
+			va_context() : baseline(0) {}
+		};
+
+        int		                m_top;
+        int		                m_left;
+        int		                m_right;
+        int						m_height;
+        int						m_width;
+		int						m_line_height;
+		int						m_default_line_height;
+        font_metrics			m_font_metrics;
+        int						m_baseline;
+        text_align				m_text_align;
+		int 					m_min_width;
+		std::list< std::unique_ptr<line_box_item> > m_items;
+    public:
+        line_box(int top, int left, int right, int line_height, const font_metrics& fm, text_align align) :
+				m_top(top),
+				m_left(left),
+				m_right(right),
+				m_height(0),
+				m_width(0),
+				m_font_metrics(fm),
+				m_default_line_height(line_height),
+				m_baseline(0),
+				m_line_height(0),
+				m_text_align(align),
+				m_min_width(0)
+		{
+        }
+
+        int		bottom() const	{ return m_top + height();	}
+        int		top() const		{ return m_top;				}
+        int		right() const	{ return m_left + width();	}
+        int		left() const	{ return m_left;			}
+        int		height() const  { return m_height;				}
+        int	 	width() const	{ return m_width;				}
+		int	 	line_right() const	{ return m_right;			}
+		int	 	min_width() const	{ return m_min_width;		}
+
+        void				add_item(std::unique_ptr<line_box_item> item);
+        bool				can_hold(const std::unique_ptr<line_box_item>& item, white_space ws) const;
+        bool				is_empty() const;
+        int					baseline() const;
+        int					top_margin() const;
+        int					bottom_margin() const;
+        void				y_shift(int shift);
+		std::list< std::unique_ptr<line_box_item> >	finish(bool last_box, const containing_block_context &containing_block_size);
+		std::list< std::unique_ptr<line_box_item> > new_width(int left, int right);
+		std::shared_ptr<render_item> 		get_last_text_part() const;
+		std::shared_ptr<render_item> 		get_first_text_part() const;
+		std::list< std::unique_ptr<line_box_item> >& 	items() { return m_items; }
+	private:
+        bool				have_last_space() const;
+        bool				is_break_only() const;
+		static int			calc_va_baseline(const va_context& current, vertical_align va, const font_metrics& new_font, int top, int bottom);
+    };
+}
+
+#endif //LH_LINE_BOX_H
diff --git a/src/plugins/litehtml_viewer/litehtml/litehtml.h b/src/plugins/litehtml_viewer/litehtml/litehtml.h
index 98a24e0da..2537aee83 100644
--- a/src/plugins/litehtml_viewer/litehtml/litehtml.h
+++ b/src/plugins/litehtml_viewer/litehtml/litehtml.h
@@ -6,5 +6,6 @@
 #include <litehtml/html_tag.h>
 #include <litehtml/stylesheet.h>
 #include <litehtml/element.h>
+#include <litehtml/utf8_strings.h>
 
 #endif  // LITEHTML_H
diff --git a/src/plugins/litehtml_viewer/litehtml/master_css.h b/src/plugins/litehtml_viewer/litehtml/master_css.h
new file mode 100644
index 000000000..b5c7f3f03
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/master_css.h
@@ -0,0 +1,351 @@
+#ifndef LH_MASTER_CSS_H
+#define LH_MASTER_CSS_H
+namespace litehtml{ const char* const master_css = R"##(
+
+
+html {
+    display: block;
+	position: relative;
+}
+
+head {
+    display: none
+}
+
+meta {
+    display: none
+}
+
+title {
+    display: none
+}
+
+link {
+    display: none
+}
+
+style {
+    display: none
+}
+
+script {
+    display: none
+}
+
+body {
+	display:block; 
+	margin:8px; 
+}
+
+p {
+	display:block; 
+	margin-top:1em; 
+	margin-bottom:1em;
+}
+
+b, strong {
+	display:inline; 
+	font-weight:bold;
+}
+
+i, em, cite {
+	display:inline; 
+	font-style:italic;
+}
+
+ins, u {
+	text-decoration:underline
+}
+
+del, s, strike {
+	text-decoration:line-through
+}
+
+center 
+{
+	text-align:center;
+	display:block;
+}
+
+a:link
+{
+	text-decoration: underline;
+	color: #00f;
+	cursor: pointer;
+}
+
+h1, h2, h3, h4, h5, h6, div {
+	display:block;
+}
+
+h1 {
+	font-weight:bold; 
+	margin-top:0.67em; 
+	margin-bottom:0.67em; 
+	font-size: 2em;
+}
+
+h2 {
+	font-weight:bold; 
+	margin-top:0.83em; 
+	margin-bottom:0.83em; 
+	font-size: 1.5em;
+}
+
+h3 {
+	font-weight:bold; 
+	margin-top:1em; 
+	margin-bottom:1em; 
+	font-size:1.17em;
+}
+
+h4 {
+	font-weight:bold; 
+	margin-top:1.33em; 
+	margin-bottom:1.33em
+}
+
+h5 {
+	font-weight:bold; 
+	margin-top:1.67em; 
+	margin-bottom:1.67em;
+	font-size:.83em;
+}
+
+h6 {
+	font-weight:bold; 
+	margin-top:2.33em; 
+	margin-bottom:2.33em;
+	font-size:.67em;
+} 
+
+br {
+	display:inline-block;
+}
+
+br[clear="all"]
+{
+	clear:both;
+}
+
+br[clear="left"]
+{
+	clear:left;
+}
+
+br[clear="right"]
+{
+	clear:right;
+}
+
+span {
+	display:inline
+}
+
+img {
+	display: inline-block;
+}
+
+img[align="right"]
+{
+	float: right;
+}
+
+img[align="left"]
+{
+	float: left;
+}
+
+hr {
+    display: block;
+    margin-top: 0.5em;
+    margin-bottom: 0.5em;
+    margin-left: auto;
+    margin-right: auto;
+    border-style: inset;
+    border-width: 1px
+}
+
+
+/***************** TABLES ********************/
+
+table {
+    display: table;
+    border-collapse: separate;
+    border-spacing: 2px;
+    border-top-color:gray;
+    border-left-color:gray;
+    border-bottom-color:black;
+    border-right-color:black;
+    font-size: medium;
+    font-weight: normal;
+    font-style: normal;
+}
+
+tbody, tfoot, thead {
+	display:table-row-group;
+	vertical-align:middle;
+}
+
+tr {
+    display: table-row;
+    vertical-align: inherit;
+    border-color: inherit;
+}
+
+td, th {
+    display: table-cell;
+    vertical-align: inherit;
+    border-width:1px;
+    padding:1px;
+}
+
+th {
+	font-weight: bold;
+}
+
+table[border] {
+    border-style:solid;
+}
+
+table[border|=0] {
+    border-style:none;
+}
+
+table[border] td, table[border] th {
+    border-style:solid;
+    border-top-color:black;
+    border-left-color:black;
+    border-bottom-color:gray;
+    border-right-color:gray;
+}
+
+table[border|=0] td, table[border|=0] th {
+    border-style:none;
+}
+
+caption {
+	display: table-caption;
+}
+
+td[nowrap], th[nowrap] {
+	white-space:nowrap;
+}
+
+tt, code, kbd, samp {
+    font-family: monospace
+}
+
+pre, xmp, plaintext, listing {
+    display: block;
+    font-family: monospace;
+    white-space: pre;
+    margin: 1em 0
+}
+
+/***************** LISTS ********************/
+
+ul, menu, dir {
+    display: block;
+    list-style-type: disc;
+    margin-top: 1em;
+    margin-bottom: 1em;
+    margin-left: 0;
+    margin-right: 0;
+    padding-left: 40px
+}
+
+ol {
+    display: block;
+    list-style-type: decimal;
+    margin-top: 1em;
+    margin-bottom: 1em;
+    margin-left: 0;
+    margin-right: 0;
+    padding-left: 40px
+}
+
+li {
+    display: list-item;
+}
+
+ul ul, ol ul {
+    list-style-type: circle;
+}
+
+ol ol ul, ol ul ul, ul ol ul, ul ul ul {
+    list-style-type: square;
+}
+
+dd {
+    display: block;
+    margin-left: 40px;
+}
+
+dl {
+    display: block;
+    margin-top: 1em;
+    margin-bottom: 1em;
+    margin-left: 0;
+    margin-right: 0;
+}
+
+dt {
+    display: block;
+}
+
+ol ul, ul ol, ul ul, ol ol {
+    margin-top: 0;
+    margin-bottom: 0
+}
+
+blockquote {
+	display: block;
+	margin-top: 1em;
+	margin-bottom: 1em;
+	margin-left: 40px;
+	margin-right: 40px;
+}
+
+/*********** FORM ELEMENTS ************/
+
+form {
+	display: block;
+	margin-top: 0em;
+}
+
+option {
+	display: none;
+}
+
+input, textarea, keygen, select, button, isindex {
+	margin: 0em;
+	color: initial;
+	line-height: normal;
+	text-transform: none;
+	text-indent: 0;
+	text-shadow: none;
+	display: inline-block;
+}
+input[type="hidden"] {
+	display: none;
+}
+
+
+article, aside, footer, header, hgroup, nav, section 
+{
+	display: block;
+}
+
+sub {
+	vertical-align: sub;
+	font-size: smaller;
+}
+
+sup {
+	vertical-align: super;
+	font-size: smaller;
+}
+
+)##"; }
+#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 c2b4275ed..763620367 100644
--- a/src/plugins/litehtml_viewer/litehtml/media_query.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/media_query.cpp
@@ -16,28 +16,28 @@ litehtml::media_query::media_query( const media_query& val )
 	m_media_type	= val.m_media_type;
 }
 
-litehtml::media_query::ptr litehtml::media_query::create_from_string(const tstring& str, const std::shared_ptr<document>& doc)
+litehtml::media_query::ptr litehtml::media_query::create_from_string(const string& str, const std::shared_ptr<document>& doc)
 {
 	media_query::ptr query = std::make_shared<media_query>();
 
 	string_vector tokens;
-	split_string(str, tokens, _t(" \t\r\n"), _t(""), _t("("));
+	split_string(str, tokens, " \t\r\n", "", "(");
 
-	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+	for(auto & token : tokens)
 	{
-		if((*tok) == _t("not"))
+		if(token == "not")
 		{
 			query->m_not = true;
-		} else if(tok->at(0) == _t('('))
+		} else if(token.at(0) == '(')
 		{
-			tok->erase(0, 1);
-			if(tok->at(tok->length() - 1) == _t(')'))
+			token.erase(0, 1);
+			if(token.at(token.length() - 1) == ')')
 			{
-				tok->erase(tok->length() - 1, 1);
+				token.erase(token.length() - 1, 1);
 			}
 			media_query_expression expr;
 			string_vector expr_tokens;
-			split_string((*tok), expr_tokens, _t(":"));
+			split_string(token, expr_tokens, ":");
 			if(!expr_tokens.empty())
 			{
 				trim(expr_tokens[0]);
@@ -56,23 +56,20 @@ litehtml::media_query::ptr litehtml::media_query::create_from_string(const tstri
 							expr.val = value_index(expr_tokens[1], media_orientation_strings, media_orientation_landscape);
 						} else
 						{
-							tstring::size_type slash_pos = expr_tokens[1].find(_t('/'));
-							if( slash_pos != tstring::npos )
+							string::size_type slash_pos = expr_tokens[1].find('/');
+							if( slash_pos != string::npos )
 							{
-								tstring val1 = expr_tokens[1].substr(0, slash_pos);
-								tstring val2 = expr_tokens[1].substr(slash_pos + 1);
+								string val1 = expr_tokens[1].substr(0, slash_pos);
+								string val2 = expr_tokens[1].substr(slash_pos + 1);
 								trim(val1);
 								trim(val2);
-								expr.val = t_atoi(val1.c_str());
-								expr.val2 = t_atoi(val2.c_str());
+								expr.val = atoi(val1.c_str());
+								expr.val2 = atoi(val2.c_str());
 							} else
 							{
 								css_length length;
 								length.fromString(expr_tokens[1]);
-								if(length.units() == css_units_dpcm)
-								{
-									expr.val = (int) (length.val() * 2.54);
-								} else if(length.units() == css_units_dpi)
+								if(length.units() == css_units_dpcm || length.units() == css_units_dpi)
 								{
 									expr.val = (int) (length.val() * 2.54);
 								} else
@@ -91,7 +88,7 @@ litehtml::media_query::ptr litehtml::media_query::create_from_string(const tstri
 			}
 		} else
 		{
-			query->m_media_type = (media_type) value_index((*tok), media_type_strings, media_type_all);
+			query->m_media_type = (media_type) value_index(token, media_type_strings, media_type_all);
 
 		}
 	}
@@ -105,11 +102,12 @@ bool litehtml::media_query::check( const media_features& features ) const
 	if(m_media_type == media_type_all || m_media_type == features.type)
 	{
 		res = true;
-		for(media_query_expression::vector::const_iterator expr = m_expressions.begin(); expr != m_expressions.end() && res; expr++)
+		for(auto expression : m_expressions)
 		{
-			if(!expr->check(features))
+			if(!expression.check(features))
 			{
 				res = false;
+                break;
 			}
 		}
 	}
@@ -124,19 +122,19 @@ bool litehtml::media_query::check( const media_features& features ) const
 
 //////////////////////////////////////////////////////////////////////////
 
-litehtml::media_query_list::ptr litehtml::media_query_list::create_from_string(const tstring& str, const std::shared_ptr<document>& doc)
+litehtml::media_query_list::ptr litehtml::media_query_list::create_from_string(const string& str, const std::shared_ptr<document>& doc)
 {
 	media_query_list::ptr list = std::make_shared<media_query_list>();
 
 	string_vector tokens;
-	split_string(str, tokens, _t(","));
+	split_string(str, tokens, ",");
 
-	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+	for(auto & token : tokens)
 	{
-		trim(*tok);
-		lcase(*tok);
+		trim(token);
+		lcase(token);
 
-		litehtml::media_query::ptr query = media_query::create_from_string(*tok, doc);
+		litehtml::media_query::ptr query = media_query::create_from_string(token, doc);
 		if(query)
 		{
 			list->m_queries.push_back(query);
@@ -144,7 +142,7 @@ litehtml::media_query_list::ptr litehtml::media_query_list::create_from_string(c
 	}
 	if(list->m_queries.empty())
 	{
-		list = 0;
+		list = nullptr;
 	}
 
 	return list;
@@ -154,11 +152,12 @@ bool litehtml::media_query_list::apply_media_features( const media_features& fea
 {
 	bool apply = false;
 	
-	for(media_query::vector::iterator iter = m_queries.begin(); iter != m_queries.end() && !apply; iter++)
+	for(auto & query : m_queries)
 	{
-		if((*iter)->check(features))
+		if(query->check(features))
 		{
 			apply = true;
+            break;
 		}
 	}
 
diff --git a/src/plugins/litehtml_viewer/litehtml/media_query.h b/src/plugins/litehtml_viewer/litehtml/media_query.h
index 6a81bcb32..4cb21fc2f 100644
--- a/src/plugins/litehtml_viewer/litehtml/media_query.h
+++ b/src/plugins/litehtml_viewer/litehtml/media_query.h
@@ -35,7 +35,7 @@ namespace litehtml
 		media_query();
 		media_query(const media_query& val);
 
-		static media_query::ptr create_from_string(const tstring& str, const std::shared_ptr<document>& doc);
+		static media_query::ptr create_from_string(const string& str, const std::shared_ptr<document>& doc);
 		bool check(const media_features& features) const;
 	};
 
@@ -51,7 +51,7 @@ namespace litehtml
 		media_query_list();
 		media_query_list(const media_query_list& val);
 
-		static media_query_list::ptr create_from_string(const tstring& str, const std::shared_ptr<document>& doc);
+		static media_query_list::ptr create_from_string(const string& str, const std::shared_ptr<document>& doc);
 		bool is_used() const;
 		bool apply_media_features(const media_features& features);	// returns true if the m_is_used changed
 	};
diff --git a/src/plugins/litehtml_viewer/litehtml/num_cvt.cpp b/src/plugins/litehtml_viewer/litehtml/num_cvt.cpp
index 16e7af442..23d594b5c 100644
--- a/src/plugins/litehtml_viewer/litehtml/num_cvt.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/num_cvt.cpp
@@ -1,16 +1,15 @@
 #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<char> latin_lower = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
+static std::vector<char> latin_upper = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', '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)
+static litehtml::string to_mapped_alpha(int num, const std::vector<char>& map)
 {
 	int dividend = num;
-	litehtml::tstring out;
+	litehtml::string out;
 	int modulo;
 
 	while (dividend > 0)
@@ -23,10 +22,10 @@ static litehtml::tstring to_mapped_alpha(int num, const std::vector<litehtml::tc
 	return out;
 }
 
-static litehtml::tstring to_mapped_alpha(int num, const std::vector<std::wstring>& map)
+static litehtml::string to_mapped_alpha(int num, const std::vector<std::wstring>& map)
 {
 	int dividend = num;
-	litehtml::tstring out;
+	litehtml::string out;
 	int modulo;
 
 	while (dividend > 0)
@@ -39,37 +38,37 @@ static litehtml::tstring to_mapped_alpha(int num, const std::vector<std::wstring
 	return out;
 }
 
-litehtml::tstring litehtml::num_cvt::to_latin_lower(int val)
+litehtml::string 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)
+litehtml::string 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)
+litehtml::string 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)
+litehtml::string litehtml::num_cvt::to_roman_lower(int value)
 {
-	struct romandata_t { int value; const litehtml::tchar_t* numeral; };
+	struct romandata_t { int value; const char* 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
+		{ 1000, "m" }, { 900, "cm" },
+		{ 500, "d" }, { 400, "cd" },
+		{ 100, "c" }, { 90, "xc" },
+		{ 50, "l" }, { 40, "xl" },
+		{ 10, "x" }, { 9, "ix" },
+		{ 5, "v" }, { 4, "iv" },
+		{ 1, "i" },
+		{ 0, nullptr } // end marker
 	};
 
-	litehtml::tstring result;
+	litehtml::string result;
 	for (const romandata_t* current = romandata; current->value > 0; ++current)
 	{
 		while (value >= current->value)
@@ -81,22 +80,22 @@ litehtml::tstring litehtml::num_cvt::to_roman_lower(int value)
 	return result;
 }
 
-litehtml::tstring litehtml::num_cvt::to_roman_upper(int value)
+litehtml::string litehtml::num_cvt::to_roman_upper(int value)
 {
-	struct romandata_t { int value; const litehtml::tchar_t* numeral; };
+	struct romandata_t { int value; const char* 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
+		{ 1000, "M" }, { 900, "CM" },
+		{ 500, "D" }, { 400, "CD" },
+		{ 100, "C" }, { 90, "XC" },
+		{ 50, "L" }, { 40, "XL" },
+		{ 10, "X" }, { 9, "IX" },
+		{ 5, "V" }, { 4, "IV" },
+		{ 1, "I" },
+		{ 0, nullptr } // end marker
 	};
 
-	litehtml::tstring result;
+	litehtml::string result;
 	for (const romandata_t* current = romandata; current->value > 0; ++current)
 	{
 		while (value >= current->value)
diff --git a/src/plugins/litehtml_viewer/litehtml/num_cvt.h b/src/plugins/litehtml_viewer/litehtml/num_cvt.h
index 367dcc36a..0eaaa6886 100644
--- a/src/plugins/litehtml_viewer/litehtml/num_cvt.h
+++ b/src/plugins/litehtml_viewer/litehtml/num_cvt.h
@@ -2,18 +2,17 @@
 #define NUM_CVT_H
 
 #include <string>
-#include <cstdint>
 #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);
+		string to_latin_lower(int val);
+		string to_latin_upper(int val);
+		string to_greek_lower(int val);
+		string to_roman_lower(int value);
+		string to_roman_upper(int value);
 	}
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/os_types.h b/src/plugins/litehtml_viewer/litehtml/os_types.h
index 53fd76643..bbc2c3cf6 100644
--- a/src/plugins/litehtml_viewer/litehtml/os_types.h
+++ b/src/plugins/litehtml_viewer/litehtml/os_types.h
@@ -1,90 +1,28 @@
 #ifndef LH_OS_TYPES_H
 #define LH_OS_TYPES_H
 
+#include <string>
+#include <cstdint>
+
 namespace litehtml
 {
-#if defined( WIN32 ) || defined( _WIN32 ) || defined( WINCE )
-
-#ifndef LITEHTML_UTF8
-
-	typedef std::wstring		tstring;
-	typedef wchar_t				tchar_t;
-	typedef std::wstringstream	tstringstream;
-
-	#define _t(quote)			L##quote
-
-	#define t_strlen			wcslen
-	#define t_strcmp			wcscmp
-	#define t_strncmp			wcsncmp
-	#define t_strcasecmp		_wcsicmp
-	#define t_strncasecmp		_wcsnicmp
-	#define t_strtol			wcstol
-	#define t_atoi				_wtoi
-	#define t_strtod			wcstod
-	#define t_itoa(value, buffer, size, radix)	_itow_s(value, buffer, size, radix)
-	#define t_strstr			wcsstr
-	#define t_tolower			towlower
-	#define t_isdigit			iswdigit
-	#define t_to_string(val)	std::to_wstring(val)
-
-#else
-
-	typedef std::string			tstring;
-	typedef char				tchar_t;
-	typedef std::stringstream	tstringstream;
+	using std::string;
+	typedef std::uintptr_t	uint_ptr;
 
-	#define _t(quote)			quote
-
-	#define t_strlen			strlen
-	#define t_strcmp			strcmp
-	#define t_strncmp			strncmp
-	#define t_strcasecmp		_stricmp
-	#define t_strncasecmp		_strnicmp
-	#define t_strtol			strtol
-	#define t_atoi				atoi
-	#define t_strtod			strtod
-	#define t_itoa(value, buffer, size, radix)	_itoa_s(value, buffer, size, radix)
-	#define t_strstr			strstr
-	#define t_tolower			tolower
-	#define t_isdigit			isdigit
-	#define t_to_string(val)	std::to_string(val)
+#if defined( WIN32 ) || defined( _WIN32 ) || defined( WINCE )
 
+// noexcept appeared since Visual Studio 2015
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#define noexcept
 #endif
 
-/*
-	#ifdef _WIN64
-		typedef unsigned __int64 uint_ptr;
-	#else
-		typedef unsigned int	uint_ptr;
-	#endif
-*/
-	typedef std::uintptr_t			uint_ptr;
+	#define t_itoa(value, buffer, size, radix)	_itoa_s(value, buffer, size, radix)
+	#define t_snprintf(s, n, format, ...) _snprintf_s(s, _TRUNCATE, n, format, __VA_ARGS__)
 
 #else
-	#define LITEHTML_UTF8
 
-	typedef std::string			tstring;
-	typedef char				tchar_t;
-	typedef std::uintptr_t			uint_ptr;
-	typedef std::stringstream	tstringstream;
-
-	#define _t(quote)			quote
-
-	#define t_strlen			strlen
-	#define t_strcmp			strcmp
-	#define t_strncmp			strncmp
-
-	#define t_strcasecmp		strcasecmp
-	#define t_strncasecmp		strncasecmp
 	#define t_itoa(value, buffer, size, radix)	snprintf(buffer, size, "%d", value)
-
-	#define t_strtol			strtol
-	#define t_atoi				atoi
-	#define t_strtod			strtod
-	#define t_strstr			strstr
-	#define t_tolower			tolower
-	#define t_isdigit			isdigit
-	#define t_to_string(val)	std::to_string(val)
+	#define t_snprintf(s, n, format, ...) snprintf(s, n, format, __VA_ARGS__)
 
 #endif
 }
diff --git a/src/plugins/litehtml_viewer/litehtml/render_block.cpp b/src/plugins/litehtml_viewer/litehtml/render_block.cpp
new file mode 100644
index 000000000..8e1d107b4
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/render_block.cpp
@@ -0,0 +1,856 @@
+#include "html.h"
+#include "render_item.h"
+#include "document.h"
+
+int litehtml::render_item_block::place_float(const std::shared_ptr<render_item> &el, int top, const containing_block_context &self_size)
+{
+    int 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<render_item> &el, int x, int y, int context)
+{
+    if(src_el()->is_floats_holder())
+    {
+        floated_box fb;
+        fb.pos.x		= el->left() + x;
+        fb.pos.y		= el->top() + y;
+        fb.pos.width	= el->width();
+        fb.pos.height	= el->height();
+        fb.float_side	= el->src_el()->css().get_float();
+        fb.clear_floats	= el->src_el()->css().get_clear();
+        fb.el			= el;
+		fb.context		= context;
+
+        if(fb.float_side == float_left)
+        {
+            if(m_floats_left.empty())
+            {
+                m_floats_left.push_back(fb);
+            } else
+            {
+                bool inserted = false;
+                for(auto i = m_floats_left.begin(); i != m_floats_left.end(); i++)
+                {
+                    if(fb.pos.right() > i->pos.right())
+                    {
+                        m_floats_left.insert(i, std::move(fb));
+                        inserted = true;
+                        break;
+                    }
+                }
+                if(!inserted)
+                {
+                    m_floats_left.push_back(std::move(fb));
+                }
+            }
+            m_cache_line_left.invalidate();
+        } else if(fb.float_side == float_right)
+        {
+            if(m_floats_right.empty())
+            {
+                m_floats_right.push_back(std::move(fb));
+            } else
+            {
+                bool inserted = false;
+                for(auto i = m_floats_right.begin(); i != m_floats_right.end(); i++)
+                {
+                    if(fb.pos.left() < i->pos.left())
+                    {
+                        m_floats_right.insert(i, std::move(fb));
+                        inserted = true;
+                        break;
+                    }
+                }
+                if(!inserted)
+                {
+                    m_floats_right.push_back(fb);
+                }
+            }
+            m_cache_line_right.invalidate();
+        }
+    } else
+    {
+        auto el_parent = parent();
+        if (el_parent)
+        {
+            el_parent->add_float(el, x + m_pos.x, y + m_pos.y, context);
+        }
+    }
+}
+
+int litehtml::render_item_block::get_cleared_top(const std::shared_ptr<render_item> &el, int line_top) const
+{
+    switch(el->src_el()->css().get_clear())
+    {
+        case clear_left:
+        {
+            int fh = get_left_floats_height();
+            if(fh && fh > line_top)
+            {
+                line_top = fh;
+            }
+        }
+            break;
+        case clear_right:
+        {
+            int fh = get_right_floats_height();
+            if(fh && fh > line_top)
+            {
+                line_top = fh;
+            }
+        }
+            break;
+        case clear_both:
+        {
+            int fh = get_floats_height(float_none);
+            if(fh && fh > line_top)
+            {
+                line_top = fh;
+            }
+        }
+            break;
+        default:
+            if(el->src_el()->css().get_float() != float_none)
+            {
+                int fh = get_floats_height(el->src_el()->css().get_float());
+                if(fh && fh > line_top)
+                {
+                    line_top = fh;
+                }
+            }
+            break;
+    }
+    return line_top;
+}
+
+int litehtml::render_item_block::find_next_line_top( int top, int width, int def_right )
+{
+    if(src_el()->is_floats_holder())
+    {
+        int new_top = top;
+        int_vector points;
+
+        for(const auto& fb : m_floats_left)
+        {
+            if(fb.pos.top() >= top)
+            {
+                if(find(points.begin(), points.end(), fb.pos.top()) == points.end())
+                {
+                    points.push_back(fb.pos.top());
+                }
+            }
+            if (fb.pos.bottom() >= top)
+            {
+                if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end())
+                {
+                    points.push_back(fb.pos.bottom());
+                }
+            }
+        }
+
+        for (const auto& fb : m_floats_right)
+        {
+            if (fb.pos.top() >= top)
+            {
+                if (find(points.begin(), points.end(), fb.pos.top()) == points.end())
+                {
+                    points.push_back(fb.pos.top());
+                }
+            }
+            if (fb.pos.bottom() >= top)
+            {
+                if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end())
+                {
+                    points.push_back(fb.pos.bottom());
+                }
+            }
+        }
+
+        if(!points.empty())
+        {
+            sort(points.begin(), points.end(), std::less<int>( ));
+            new_top = points.back();
+
+            for(auto pt : points)
+            {
+                int pos_left	= 0;
+                int pos_right	= def_right;
+                get_line_left_right(pt, def_right, pos_left, pos_right);
+
+                if(pos_right - pos_left >= width)
+                {
+                    new_top = pt;
+                    break;
+                }
+            }
+        }
+        return new_top;
+    }
+    auto el_parent = parent();
+    if (el_parent)
+    {
+        int new_top = el_parent->find_next_line_top(top + m_pos.y, width, def_right + m_pos.x);
+        return new_top - m_pos.y;
+    }
+    return 0;
+}
+
+void litehtml::render_item_block::update_floats(int dy, const std::shared_ptr<render_item> &_parent)
+{
+    if(src_el()->is_floats_holder())
+    {
+        bool reset_cache = false;
+        for(auto fb = m_floats_left.rbegin(); fb != m_floats_left.rend(); fb++)
+        {
+            if(fb->el->src_el()->is_ancestor(_parent->src_el()))
+            {
+                reset_cache	= true;
+                fb->pos.y	+= dy;
+            }
+        }
+        if(reset_cache)
+        {
+            m_cache_line_left.invalidate();
+        }
+        reset_cache = false;
+        for(auto fb = m_floats_right.rbegin(); fb != m_floats_right.rend(); fb++)
+        {
+            if(fb->el->src_el()->is_ancestor(_parent->src_el()))
+            {
+                reset_cache	= true;
+                fb->pos.y	+= dy;
+            }
+        }
+        if(reset_cache)
+        {
+            m_cache_line_right.invalidate();
+        }
+    } else
+    {
+        auto el_parent = parent();
+        if (el_parent)
+        {
+            el_parent->update_floats(dy, _parent);
+        }
+    }
+}
+
+std::shared_ptr<litehtml::render_item> litehtml::render_item_block::init()
+{
+    {
+        css_selector sel;
+        sel.parse(".inline_rating");
+        if(src_el()->select(sel))
+        {
+            int i = 0;
+            i++;
+        }
+    }
+    std::shared_ptr<render_item> 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<render_item_block_context>(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<html_tag>(src_el());
+                    auto anon_ri = std::make_shared<render_item_block>(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<html_tag>(src_el());
+            auto anon_ri = std::make_shared<render_item_block>(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<render_item_inline_context>(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();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/render_block_context.cpp b/src/plugins/litehtml_viewer/litehtml/render_block_context.cpp
new file mode 100644
index 000000000..b0aa444d7
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/render_block_context.cpp
@@ -0,0 +1,125 @@
+#include "html.h"
+#include "render_item.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)
+{
+    element_position el_position;
+
+    int child_top = 0;
+    int last_margin = 0;
+	std::shared_ptr<render_item> last_margin_el;
+    bool is_first = true;
+    for (const auto& el : m_children)
+    {
+        // we don't need to process absolute and fixed positioned element on the second pass
+        if (second_pass)
+        {
+            el_position = el->src_el()->css().get_position();
+            if ((el_position == element_position_absolute || el_position == element_position_fixed)) continue;
+        }
+
+        if(el->src_el()->css().get_float() != float_none)
+        {
+            int rw = place_float(el, child_top, self_size);
+            if (rw > ret_width)
+            {
+                ret_width = rw;
+            }
+        } else if(el->src_el()->css().get_display() != display_none)
+        {
+            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);
+            } else
+            {
+                child_top = get_cleared_top(el, child_top);
+                int child_x  = 0;
+                int child_width = self_size.render_width;
+
+                el->calc_outlines(self_size.width);
+
+                // Collapse top margin
+                if(is_first && collapse_top_margin())
+                {
+                    child_top -= el->get_margins().top;
+                    if(el->get_margins().top > get_margins().top)
+                    {
+                        m_margins.top = el->get_margins().top;
+                    }
+                } else
+                {
+                    if(last_margin > el->get_margins().top)
+                    {
+                        child_top -= el->get_margins().top;
+                    } else
+                    {
+                        child_top -= last_margin;
+                    }
+                }
+
+                if(el->src_el()->is_replaced() || el->src_el()->is_floats_holder() || 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);
+                    child_x = ln_left;
+                    child_width = ln_right - ln_left;
+
+                    auto el_parent = el->parent();
+                    el->pos().width = el->src_el()->css().get_width().calc_percent(child_width);
+                    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));
+				// 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));
+				}
+				int auto_margin = el->calc_auto_margins(child_width);
+				if(auto_margin)
+				{
+					el->pos().x += auto_margin;
+				}
+                if (rw > ret_width)
+                {
+                    ret_width = rw;
+                }
+                child_top += el->height();
+                last_margin = el->get_margins().bottom;
+				last_margin_el = el;
+                is_first = false;
+
+                if (el->src_el()->css().get_position() == element_position_relative)
+                {
+                    el->apply_relative_shift(self_size);
+                }
+            }
+        }
+    }
+
+    int block_height = 0;
+    if (get_predefined_height(block_height, self_size.height))
+    {
+        m_pos.height = block_height;
+    } else
+    {
+        m_pos.height = child_top;
+        if(collapse_bottom_margin())
+        {
+            m_pos.height -= last_margin;
+            if(m_margins.bottom < last_margin)
+            {
+                m_margins.bottom = last_margin;
+            }
+			if(last_margin_el)
+			{
+				last_margin_el->get_margins().bottom = 0;
+			}
+        }
+    }
+
+    return ret_width;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/render_flex.cpp b/src/plugins/litehtml_viewer/litehtml/render_flex.cpp
new file mode 100644
index 000000000..c9cf8e538
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/render_flex.cpp
@@ -0,0 +1,91 @@
+#include "html.h"
+#include "render_item.h"
+#include "types.h"
+
+int litehtml::render_item_flex::_render_content(int x, int y, bool second_pass, int ret_width,
+												const containing_block_context &self_size)
+{
+    return 0;
+}
+
+void litehtml::render_item_flex::draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex)
+{
+
+}
+
+std::shared_ptr<litehtml::render_item> litehtml::render_item_flex::init()
+{
+    auto doc = src_el()->get_document();
+    decltype(m_children) new_children;
+    decltype(m_children) inlines;
+
+    auto convert_inlines = [&]()
+        {
+        if(!inlines.empty())
+        {
+            // Find last not space
+            auto not_space = std::find_if(inlines.rbegin(), inlines.rend(), [&](const std::shared_ptr<render_item>& el)
+                {
+                return !el->src_el()->is_space();
+                });
+            if(not_space != inlines.rend())
+            {
+                // Erase all spaces at the end
+                inlines.erase((not_space.base()), inlines.end());
+            }
+
+            auto anon_el = std::make_shared<html_tag>(src_el());
+            auto anon_ri = std::make_shared<render_item_block>(anon_el);
+            for(const auto& inl : inlines)
+            {
+                anon_ri->add_child(inl);
+            }
+            anon_ri->parent(shared_from_this());
+
+            new_children.push_back(anon_ri->init());
+            inlines.clear();
+        }
+        };
+
+    for (const auto& el : m_children)
+    {
+        if(el->src_el()->css().get_display() == display_inline_text)
+        {
+            if(!inlines.empty())
+            {
+                inlines.push_back(el);
+            } else
+            {
+                if (!el->src_el()->is_white_space())
+                {
+                    inlines.push_back(el);
+                }
+            }
+        } else
+        {
+            convert_inlines();
+            if(el->src_el()->is_block_box())
+            {
+                // Add block boxes as is
+                el->parent(shared_from_this());
+                new_children.push_back(el->init());
+            } else
+            {
+                // Wrap inlines with anonymous block box
+                auto anon_el = std::make_shared<html_tag>(el->src_el());
+                auto anon_ri = std::make_shared<render_item_block>(anon_el);
+                anon_ri->add_child(el->init());
+                anon_ri->parent(shared_from_this());
+                new_children.push_back(anon_ri->init());
+            }
+        }
+    }
+    convert_inlines();
+    children() = new_children;
+    for(const auto& el : children())
+    {
+        m_flex_items.emplace_back(new flex_item(el));
+    }
+
+    return shared_from_this();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/render_image.cpp b/src/plugins/litehtml_viewer/litehtml/render_image.cpp
new file mode 100644
index 000000000..38f576bc1
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/render_image.cpp
@@ -0,0 +1,148 @@
+#include "html.h"
+#include "render_item.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 parent_width = containing_block_size.width;
+
+    calc_outlines(parent_width);
+
+    m_pos.move_to(x, y);
+
+    document::ptr doc = src_el()->get_document();
+
+    litehtml::size sz;
+    src_el()->get_content_size(sz, containing_block_size.width);
+
+    m_pos.width		= sz.width;
+    m_pos.height	= sz.height;
+
+    src_el()->css_w().set_line_height(height());
+
+    if(src_el()->css().get_height().is_predefined() && src_el()->css().get_width().is_predefined())
+    {
+        m_pos.height	= sz.height;
+        m_pos.width		= sz.width;
+
+        // check for max-width
+        if(!src_el()->css().get_max_width().is_predefined())
+        {
+            int max_width = doc->to_pixels(src_el()->css().get_max_width(), src_el()->css().get_font_size(), parent_width);
+            if(m_pos.width > max_width)
+            {
+                m_pos.width = max_width;
+            }
+            if(sz.width)
+            {
+                m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);
+            } else
+            {
+                m_pos.height = sz.height;
+            }
+        }
+
+        // check for max-height
+        if(!src_el()->css().get_max_height().is_predefined())
+        {
+            int max_height = calc_max_height(sz.height, containing_block_size.height);
+            if(m_pos.height > max_height)
+            {
+                m_pos.height = max_height;
+            }
+            if(sz.height)
+            {
+                m_pos.width = (int) ((float )m_pos.height * (float)sz.width / (float)sz.height);
+            } else
+            {
+                m_pos.width = sz.width;
+            }
+        }
+    } else if(!src_el()->css().get_height().is_predefined() && src_el()->css().get_width().is_predefined())
+    {
+        if (!get_predefined_height(m_pos.height, containing_block_size.height))
+        {
+            m_pos.height = (int)src_el()->css().get_height().val();
+        }
+
+        // check for max-height
+        if(!src_el()->css().get_max_height().is_predefined())
+        {
+            int max_height = calc_max_height(sz.height, containing_block_size.height);
+            if(m_pos.height > max_height)
+            {
+                m_pos.height = max_height;
+            }
+        }
+
+        if(sz.height)
+        {
+            m_pos.width = (int) ((float )m_pos.height * (float)sz.width / (float)sz.height);
+        } else
+        {
+            m_pos.width = sz.width;
+        }
+    } else if(src_el()->css().get_height().is_predefined() && !src_el()->css().get_width().is_predefined())
+    {
+        m_pos.width = (int) src_el()->css().get_width().calc_percent(parent_width);
+
+        // check for max-width
+        if(!src_el()->css().get_max_width().is_predefined())
+        {
+            int max_width = doc->to_pixels(src_el()->css().get_max_width(), src_el()->css().get_font_size(), parent_width);
+            if(m_pos.width > max_width)
+            {
+                m_pos.width = max_width;
+            }
+        }
+
+        if(sz.width)
+        {
+            m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);
+        } else
+        {
+            m_pos.height = sz.height;
+        }
+    } else
+    {
+        m_pos.width		= (int) src_el()->css().get_width().calc_percent(parent_width);
+        m_pos.height	= 0;
+        if (!get_predefined_height(m_pos.height, containing_block_size.height))
+        {
+            m_pos.height = (int)src_el()->css().get_height().val();
+        }
+
+        // check for max-height
+        if(!src_el()->css().get_max_height().is_predefined())
+        {
+            int max_height = calc_max_height(sz.height, containing_block_size.height);
+            if(m_pos.height > max_height)
+            {
+                m_pos.height = max_height;
+            }
+        }
+
+        // check for max-height
+        if(!src_el()->css().get_max_width().is_predefined())
+        {
+            int max_width = doc->to_pixels(src_el()->css().get_max_width(), src_el()->css().get_font_size(), parent_width);
+            if(m_pos.width > max_width)
+            {
+                m_pos.width = max_width;
+            }
+        }
+    }
+
+    m_pos.x	+= content_offset_left();
+    m_pos.y += content_offset_top();
+
+    return m_pos.width + content_offset_left() + content_offset_right();
+}
+
+int litehtml::render_item_image::calc_max_height(int image_height, int containing_block_height)
+{
+    document::ptr doc = src_el()->get_document();
+    return doc->to_pixels(src_el()->css().get_max_height(), src_el()->css().get_font_size(),
+						  containing_block_height == 0 ? image_height : containing_block_height);
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/render_inline.cpp b/src/plugins/litehtml_viewer/litehtml/render_inline.cpp
new file mode 100644
index 000000000..0ea24b17d
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/render_inline.cpp
@@ -0,0 +1,3 @@
+#include "html.h"
+#include "render_item.h"
+
diff --git a/src/plugins/litehtml_viewer/litehtml/render_inline_context.cpp b/src/plugins/litehtml_viewer/litehtml/render_inline_context.cpp
new file mode 100644
index 000000000..b348a8cf7
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/render_inline_context.cpp
@@ -0,0 +1,403 @@
+#include "html.h"
+#include "render_item.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)
+{
+    m_line_boxes.clear();
+	m_max_line_width = 0;
+
+    white_space ws = src_el()->css().get_white_space();
+    bool skip_spaces = false;
+    if (ws == white_space_normal ||
+        ws == white_space_nowrap ||
+        ws == white_space_pre_line)
+    {
+        skip_spaces = true;
+    }
+
+    bool was_space = false;
+
+    go_inside_inline go_inside_inlines_selector;
+    inline_selector select_inlines;
+    elements_iterator inlines_iter(true, &go_inside_inlines_selector, &select_inlines);
+
+    inlines_iter.process(shared_from_this(), [&](const std::shared_ptr<render_item>& el, iterator_item_type item_type)
+        {
+			switch (item_type)
+			{
+				case iterator_item_type_child:
+					{
+						// skip spaces to make rendering a bit faster
+						if (skip_spaces)
+						{
+							if (el->src_el()->is_white_space())
+							{
+								if (was_space)
+								{
+									el->skip(true);
+									return;
+								} else
+								{
+									was_space = true;
+								}
+							} else
+							{
+								// skip all spaces after line break
+								was_space = el->src_el()->is_break();
+							}
+						}
+						// place element into rendering flow
+						place_inline(std::unique_ptr<line_box_item>(new line_box_item(el)), self_size);
+					}
+					break;
+
+				case iterator_item_type_start_parent:
+					{
+						el->clear_inline_boxes();
+						place_inline(std::unique_ptr<lbi_start>(new lbi_start(el)), self_size);
+					}
+					break;
+
+				case iterator_item_type_end_parent:
+				{
+					place_inline(std::unique_ptr<lbi_end>(new lbi_end(el)), self_size);
+				}
+					break;
+			}
+        });
+
+    finish_last_box(true, self_size);
+
+    if (!m_line_boxes.empty())
+    {
+        if (collapse_top_margin())
+        {
+            int old_top = m_margins.top;
+            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());
+            }
+        }
+        if (collapse_bottom_margin())
+        {
+            m_margins.bottom = std::max(m_line_boxes.back()->bottom_margin(), m_margins.bottom);
+            m_pos.height = m_line_boxes.back()->bottom() - m_line_boxes.back()->bottom_margin();
+        }
+        else
+        {
+            m_pos.height = m_line_boxes.back()->bottom();
+        }
+    }
+
+    return std::max(ret_width, m_max_line_width);
+}
+
+void litehtml::render_item_inline_context::fix_line_width(element_float flt,
+														  const containing_block_context &self_size)
+{
+    int ret_width = 0;
+    if(!m_line_boxes.empty())
+    {
+		auto el_front = m_line_boxes.back()->get_first_text_part();
+
+        std::vector<std::shared_ptr<render_item>> els;
+        bool was_cleared = false;
+        if(el_front && el_front->src_el()->css().get_clear() != clear_none)
+        {
+            if(el_front->src_el()->css().get_clear() == clear_both)
+            {
+                was_cleared = true;
+            } else
+            {
+                if(	(flt == float_left	&& el_front->src_el()->css().get_clear() == clear_left) ||
+                       (flt == float_right	&& el_front->src_el()->css().get_clear() == clear_right) )
+                {
+                    was_cleared = true;
+                }
+            }
+        }
+
+        if(!was_cleared)
+        {
+			std::list<std::unique_ptr<line_box_item> > items = std::move(m_line_boxes.back()->items());
+            m_line_boxes.pop_back();
+
+            for(auto& item : items)
+            {
+                place_inline(std::move(item), self_size);
+            }
+        } else
+        {
+            int line_top = 0;
+            line_top = m_line_boxes.back()->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);
+
+            if(m_line_boxes.size() == 1)
+            {
+                if (src_el()->css().get_list_style_type() != list_style_type_none && src_el()->css().get_list_style_position() == list_style_position_inside)
+                {
+                    int sz_font = src_el()->css().get_font_size();
+                    line_left += sz_font;
+                }
+
+                if (src_el()->css().get_text_indent().val() != 0)
+                {
+                    line_left += src_el()->css().get_text_indent().calc_percent(self_size.width);
+                }
+            
+            }
+
+            auto items = m_line_boxes.back()->new_width(line_left, line_right);
+            for(auto& item : items)
+            {
+                place_inline(std::move(item), self_size);
+            }
+        }
+    }
+}
+
+std::list<std::unique_ptr<litehtml::line_box_item> > litehtml::render_item_inline_context::finish_last_box(bool end_of_render, const containing_block_context &self_size)
+{
+	std::list<std::unique_ptr<line_box_item> > ret;
+
+    if(!m_line_boxes.empty())
+    {
+		ret = m_line_boxes.back()->finish(end_of_render, self_size);
+
+        if(m_line_boxes.back()->is_empty() && end_of_render)
+        {
+			// remove the last empty line
+            m_line_boxes.pop_back();
+        } else
+		{
+			m_max_line_width = std::max(m_max_line_width, m_line_boxes.back()->min_width());
+		}
+    }
+    return ret;
+}
+
+int litehtml::render_item_inline_context::new_box(const std::unique_ptr<line_box_item>& el, line_context& line_ctx, const containing_block_context &self_size)
+{
+	auto items = finish_last_box(false, self_size);
+	int line_top = 0;
+	if(!m_line_boxes.empty())
+	{
+		line_top = m_line_boxes.back()->bottom();
+	}
+    line_ctx.top = 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);
+
+    if(el->get_el()->src_el()->is_inline_box() || el->get_el()->src_el()->is_floats_holder())
+    {
+        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.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);
+        }
+    }
+
+    int first_line_margin = 0;
+    int text_indent = 0;
+    if(m_line_boxes.empty())
+    {
+        if(src_el()->css().get_list_style_type() != list_style_type_none && src_el()->css().get_list_style_position() == list_style_position_inside)
+        {
+            int sz_font = src_el()->css().get_font_size();
+            first_line_margin = sz_font;
+        }
+        if(src_el()->css().get_text_indent().val() != 0)
+        {
+            text_indent = src_el()->css().get_text_indent().calc_percent(self_size.width);
+        }
+    }
+
+    m_line_boxes.emplace_back(std::unique_ptr<line_box>(new line_box(
+			line_ctx.top,
+			line_ctx.left + first_line_margin + text_indent, line_ctx.right,
+			css().get_line_height(),
+			css().get_font_metrics(),
+			css().get_text_align())));
+
+	// Add items returned by finish_last_box function into the new line
+	for(auto& it : items)
+	{
+		m_line_boxes.back()->add_item(std::move(it));
+	}
+
+    return line_ctx.top;
+}
+
+void litehtml::render_item_inline_context::place_inline(std::unique_ptr<line_box_item> item, const containing_block_context &self_size)
+{
+    if(item->get_el()->src_el()->css().get_display() == display_none) return;
+
+    if(item->get_el()->src_el()->is_float())
+    {
+        int line_top = 0;
+        if(!m_line_boxes.empty())
+        {
+            line_top = m_line_boxes.back()->top();
+        }
+        int ret = place_float(item->get_el(), line_top, self_size);
+		if(ret > m_max_line_width)
+		{
+			m_max_line_width = ret;
+		}
+		return;
+    }
+
+    line_context line_ctx = {0};
+    line_ctx.top = 0;
+    if (!m_line_boxes.empty())
+    {
+        line_ctx.top = m_line_boxes.back().get()->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);
+
+	if(item->get_type() == line_box_item::type_text_part)
+	{
+		switch (item->get_el()->src_el()->css().get_display())
+		{
+			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:
+			{
+				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);
+			}
+				break;
+		}
+	}
+
+    bool add_box = true;
+    if(!m_line_boxes.empty())
+    {
+        if(m_line_boxes.back()->can_hold(item, src_el()->css().get_white_space()))
+        {
+            add_box = false;
+        }
+    }
+    if(add_box)
+    {
+        new_box(item, line_ctx, self_size);
+    } else if(!m_line_boxes.empty())
+    {
+        line_ctx.top = m_line_boxes.back()->top();
+    }
+
+    if (line_ctx.top != line_ctx.calculatedTop)
+    {
+        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);
+    }
+
+    if(!item->get_el()->src_el()->is_inline_box())
+    {
+        if(m_line_boxes.size() == 1)
+        {
+            if(collapse_top_margin())
+            {
+                int shift = item->get_el()->margin_top();
+                if(shift >= 0)
+                {
+                    line_ctx.top -= shift;
+                    m_line_boxes.back()->y_shift(-shift);
+                }
+            }
+        } else
+        {
+            int shift = 0;
+            int prev_margin = m_line_boxes[m_line_boxes.size() - 2]->bottom_margin();
+
+            if(prev_margin > item->get_el()->margin_top())
+            {
+                shift = item->get_el()->margin_top();
+            } else
+            {
+                shift = prev_margin;
+            }
+            if(shift >= 0)
+            {
+                line_ctx.top -= shift;
+                m_line_boxes.back()->y_shift(-shift);
+            }
+        }
+    }
+
+	m_line_boxes.back()->add_item(std::move(item));
+}
+
+void litehtml::render_item_inline_context::apply_vertical_align()
+{
+    if(!m_line_boxes.empty())
+    {
+        int add = 0;
+        int content_height	= m_line_boxes.back()->bottom();
+
+        if(m_pos.height > content_height)
+        {
+            switch(src_el()->css().get_vertical_align())
+            {
+                case va_middle:
+                    add = (m_pos.height - content_height) / 2;
+                    break;
+                case va_bottom:
+                    add = m_pos.height - content_height;
+                    break;
+                default:
+                    add = 0;
+                    break;
+            }
+        }
+
+        if(add)
+        {
+            for(auto & box : m_line_boxes)
+            {
+                box->y_shift(add);
+            }
+        }
+    }
+}
+
+int litehtml::render_item_inline_context::get_base_line()
+{
+    auto el_parent = parent();
+    if(el_parent && src_el()->css().get_display() == display_inline_flex)
+    {
+        return el_parent->get_base_line();
+    }
+    if(src_el()->is_replaced())
+    {
+        return 0;
+    }
+    int bl = 0;
+    if(!m_line_boxes.empty())
+    {
+        bl = m_line_boxes.back()->baseline() + content_offset_bottom();
+    }
+    return bl;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/render_item.cpp b/src/plugins/litehtml_viewer/litehtml/render_item.cpp
new file mode 100644
index 000000000..2fc8e99c7
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/render_item.cpp
@@ -0,0 +1,1076 @@
+#include "html.h"
+#include "render_item.h"
+#include "document.h"
+#include <typeinfo>
+#include <utf8_strings.h>
+
+litehtml::render_item::render_item(std::shared_ptr<element>  _src_el) :
+        m_element(std::move(_src_el)),
+        m_skip(false)
+{
+    document::ptr doc = src_el()->get_document();
+    auto fnt_size = src_el()->css().get_font_size();
+
+    m_margins.left		= doc->to_pixels(src_el()->css().get_margins().left,         fnt_size);
+    m_margins.right		= doc->to_pixels(src_el()->css().get_margins().right,        fnt_size);
+    m_margins.top		= doc->to_pixels(src_el()->css().get_margins().top,          fnt_size);
+    m_margins.bottom	= doc->to_pixels(src_el()->css().get_margins().bottom,       fnt_size);
+
+    m_padding.left		= doc->to_pixels(src_el()->css().get_padding().left,         fnt_size);
+    m_padding.right		= doc->to_pixels(src_el()->css().get_padding().right,        fnt_size);
+    m_padding.top		= doc->to_pixels(src_el()->css().get_padding().top,          fnt_size);
+    m_padding.bottom	= doc->to_pixels(src_el()->css().get_padding().bottom,       fnt_size);
+
+    m_borders.left		= doc->to_pixels(src_el()->css().get_borders().left.width,   fnt_size);
+    m_borders.right		= doc->to_pixels(src_el()->css().get_borders().right.width,  fnt_size);
+    m_borders.top		= doc->to_pixels(src_el()->css().get_borders().top.width,    fnt_size);
+    m_borders.bottom	= doc->to_pixels(src_el()->css().get_borders().bottom.width, fnt_size);
+}
+
+
+void litehtml::render_item::calc_outlines( int parent_width )
+{
+    m_padding.left	= m_element->css().get_padding().left.calc_percent(parent_width);
+    m_padding.right	= m_element->css().get_padding().right.calc_percent(parent_width);
+
+    m_borders.left	= m_element->css().get_borders().left.width.calc_percent(parent_width);
+    m_borders.right	= m_element->css().get_borders().right.width.calc_percent(parent_width);
+
+    m_margins.left	= m_element->css().get_margins().left.calc_percent(parent_width);
+    m_margins.right	= m_element->css().get_margins().right.calc_percent(parent_width);
+
+    m_margins.top		= m_element->css().get_margins().top.calc_percent(parent_width);
+    m_margins.bottom	= m_element->css().get_margins().bottom.calc_percent(parent_width);
+
+    m_padding.top		= m_element->css().get_padding().top.calc_percent(parent_width);
+    m_padding.bottom	= m_element->css().get_padding().bottom.calc_percent(parent_width);
+}
+
+int litehtml::render_item::calc_auto_margins(int parent_width)
+{
+    if ((src_el()->css().get_display() == display_block || src_el()->css().get_display() == display_table) &&
+            src_el()->css().get_position() != element_position_absolute &&
+            src_el()->css().get_float() == float_none)
+    {
+        if (src_el()->css().get_margins().left.is_predefined() && src_el()->css().get_margins().right.is_predefined())
+        {
+            int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right;
+            if (el_width <= parent_width)
+            {
+                m_margins.left = (parent_width - el_width) / 2;
+                m_margins.right = (parent_width - el_width) - m_margins.left;
+            }
+            else
+            {
+                m_margins.left = 0;
+                m_margins.right = 0;
+            }
+			return m_margins.left;
+        }
+        else if (src_el()->css().get_margins().left.is_predefined() && !src_el()->css().get_margins().right.is_predefined())
+        {
+            int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.right;
+            m_margins.left = parent_width - el_width;
+            if (m_margins.left < 0) m_margins.left = 0;
+			return m_margins.left;
+        }
+        else if (!src_el()->css().get_margins().left.is_predefined() && src_el()->css().get_margins().right.is_predefined())
+        {
+            int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.left;
+            m_margins.right = parent_width - el_width;
+            if (m_margins.right < 0) m_margins.right = 0;
+        }
+    }
+	return 0;
+}
+
+void litehtml::render_item::apply_relative_shift(const containing_block_context &containing_block_size)
+{
+    if (src_el()->css().get_position() == element_position_relative)
+    {
+        css_offsets offsets = src_el()->css().get_offsets();
+        if (!offsets.left.is_predefined())
+        {
+            m_pos.x += offsets.left.calc_percent(containing_block_size.width);
+        }
+        else if (!offsets.right.is_predefined())
+        {
+            m_pos.x -= offsets.right.calc_percent(containing_block_size.width);
+        }
+        if (!offsets.top.is_predefined())
+        {
+            m_pos.y += offsets.top.calc_percent(containing_block_size.height);
+        }
+        else if (!offsets.bottom.is_predefined())
+        {
+            m_pos.y -= offsets.bottom.calc_percent(containing_block_size.height);
+        }
+    }
+}
+
+bool litehtml::render_item::get_predefined_height(int& p_height, int containing_block_height) const
+{
+    css_length h = src_el()->css().get_height();
+    if(h.is_predefined())
+    {
+        p_height = m_pos.height;
+        return false;
+    }
+    if(h.units() == css_units_percentage)
+    {
+		p_height = h.calc_percent(containing_block_height);
+		return containing_block_height != 0;
+    }
+    p_height = src_el()->get_document()->to_pixels(h, src_el()->css().get_font_size());
+    return true;
+}
+
+int litehtml::render_item::calc_width(int defVal, int containing_block_width) const
+{
+    css_length w = src_el()->css().get_width();
+    if(w.is_predefined() || src_el()->css().get_display() == display_table_cell)
+    {
+        return defVal;
+    }
+    if(w.units() == css_units_percentage)
+    {
+		return w.calc_percent(containing_block_width);
+    }
+    return 	src_el()->get_document()->to_pixels(w, src_el()->css().get_font_size());
+}
+
+std::tuple<
+        std::shared_ptr<litehtml::render_item>,
+        std::shared_ptr<litehtml::render_item>,
+        std::shared_ptr<litehtml::render_item>
+        > litehtml::render_item::split_inlines()
+{
+    std::tuple<
+            std::shared_ptr<litehtml::render_item>,
+            std::shared_ptr<litehtml::render_item>,
+            std::shared_ptr<litehtml::render_item>
+    > ret;
+    for(const auto& child: m_children)
+    {
+        if(child->src_el()->is_block_box() && child->src_el()->css().get_float() == float_none)
+        {
+            std::get<0>(ret) = clone();
+            std::get<1>(ret) = child;
+            std::get<2>(ret) = clone();
+
+            std::get<1>(ret)->parent(std::get<0>(ret));
+            std::get<2>(ret)->parent(std::get<0>(ret));
+
+            bool found = false;
+            for(const auto& ch: m_children)
+            {
+                if(ch == child)
+                {
+                    found = true;
+                    continue;
+                }
+                if(!found)
+                {
+                    std::get<0>(ret)->add_child(ch);
+                } else
+                {
+                    std::get<2>(ret)->add_child(ch);
+                }
+            }
+            break;
+        }
+        if(!child->children().empty())
+        {
+            auto child_split = child->split_inlines();
+            if(std::get<0>(child_split))
+            {
+                std::get<0>(ret) = clone();
+                std::get<1>(ret) = std::get<1>(child_split);
+                std::get<2>(ret) = clone();
+
+                std::get<2>(ret)->parent(std::get<0>(ret));
+
+                bool found = false;
+                for(const auto& ch: m_children)
+                {
+                    if(ch == child)
+                    {
+                        found = true;
+                        continue;
+                    }
+                    if(!found)
+                    {
+                        std::get<0>(ret)->add_child(ch);
+                    } else
+                    {
+                        std::get<2>(ret)->add_child(ch);
+                    }
+                }
+                std::get<0>(ret)->add_child(std::get<0>(child_split));
+                std::get<2>(ret)->add_child(std::get<2>(child_split));
+                break;
+            }
+        }
+    }
+    return ret;
+}
+
+bool litehtml::render_item::fetch_positioned()
+{
+    bool ret = false;
+
+    m_positioned.clear();
+
+    litehtml::element_position el_pos;
+
+    for(auto& el : m_children)
+    {
+        el_pos = el->src_el()->css().get_position();
+        if (el_pos != element_position_static)
+        {
+            add_positioned(el);
+        }
+        if (!ret && (el_pos == element_position_absolute || el_pos == element_position_fixed))
+        {
+            ret = true;
+        }
+        if(el->fetch_positioned())
+        {
+            ret = true;
+        }
+    }
+    return ret;
+}
+
+void litehtml::render_item::render_positioned(render_type rt)
+{
+    position wnd_position;
+    src_el()->get_document()->container()->get_client_rect(wnd_position);
+
+    element_position el_position;
+    bool process;
+    for (auto& el : m_positioned)
+    {
+        el_position = el->src_el()->css().get_position();
+
+        process = false;
+        if(el->src_el()->css().get_display() != display_none)
+        {
+            if(el_position == element_position_absolute)
+            {
+                if(rt != render_fixed_only)
+                {
+                    process = true;
+                }
+            } else if(el_position == element_position_fixed)
+            {
+                if(rt != render_no_fixed)
+                {
+                    process = true;
+                }
+            }
+        }
+
+        if(process)
+        {
+			containing_block_context containing_block_size;
+            int client_x		= 0;
+            int client_y		= 0;
+            if(el_position == element_position_fixed)
+            {
+				containing_block_size.height	= wnd_position.height;
+				containing_block_size.width		= wnd_position.width;
+                client_x		= wnd_position.left();
+                client_y		= wnd_position.top();
+            } else
+            {
+				containing_block_size.height	= m_pos.height;
+				containing_block_size.width		= m_pos.width;
+            }
+
+            css_length	css_left	= el->src_el()->css().get_offsets().left;
+            css_length	css_right	= el->src_el()->css().get_offsets().right;
+            css_length	css_top		= el->src_el()->css().get_offsets().top;
+            css_length	css_bottom	= el->src_el()->css().get_offsets().bottom;
+
+            bool need_render = false;
+
+            css_length el_w = el->src_el()->css().get_width();
+            css_length el_h = el->src_el()->css().get_height();
+
+            int new_width = -1;
+            int new_height = -1;
+            if(el_w.units() == css_units_percentage && containing_block_size.width)
+            {
+                new_width = el_w.calc_percent(containing_block_size.width);
+                if(el->m_pos.width != new_width)
+                {
+                    need_render = true;
+                    el->m_pos.width = new_width;
+                }
+            }
+
+            if(el_h.units() == css_units_percentage && containing_block_size.height)
+            {
+                new_height = el_h.calc_percent(containing_block_size.height);
+                if(el->m_pos.height != new_height)
+                {
+                    need_render = true;
+                    el->m_pos.height = new_height;
+                }
+            }
+
+            bool cvt_x = false;
+            bool cvt_y = false;
+
+            if(el_position == element_position_fixed)
+            {
+                if(!css_left.is_predefined() || !css_right.is_predefined())
+                {
+                    if(!css_left.is_predefined() && css_right.is_predefined())
+                    {
+                        el->m_pos.x = css_left.calc_percent(containing_block_size.width) + el->content_offset_left();
+                    } else if(css_left.is_predefined() && !css_right.is_predefined())
+                    {
+                        el->m_pos.x = containing_block_size.width - css_right.calc_percent(containing_block_size.width) - el->m_pos.width -
+								el->content_offset_right();
+                    } else
+                    {
+                        el->m_pos.x		= css_left.calc_percent(containing_block_size.width) + el->content_offset_left();
+                        el->m_pos.width	= containing_block_size.width -
+								css_left.calc_percent(containing_block_size.width) -
+								css_right.calc_percent(containing_block_size.width) -
+								(el->content_offset_left() + el->content_offset_right());
+                        need_render = true;
+                    }
+                }
+
+                if(!css_top.is_predefined() || !css_bottom.is_predefined())
+                {
+                    if(!css_top.is_predefined() && css_bottom.is_predefined())
+                    {
+                        el->m_pos.y = css_top.calc_percent(containing_block_size.height) + el->content_offset_top();
+                    } else if(css_top.is_predefined() && !css_bottom.is_predefined())
+                    {
+                        el->m_pos.y = containing_block_size.height - css_bottom.calc_percent(containing_block_size.height) - el->m_pos.height -
+								el->content_offset_bottom();
+                    } else
+                    {
+                        el->m_pos.y			= css_top.calc_percent(containing_block_size.height) + el->content_offset_top();
+                        el->m_pos.height	= containing_block_size.height -
+								css_top.calc_percent(containing_block_size.height) -
+								css_bottom.calc_percent(containing_block_size.height) -
+								(el->content_offset_top() + el->content_offset_bottom());
+                        need_render = true;
+                    }
+                }
+            } else
+            {
+                if(!css_left.is_predefined() || !css_right.is_predefined())
+                {
+                    if(!css_left.is_predefined() && css_right.is_predefined())
+                    {
+                        el->m_pos.x = css_left.calc_percent(containing_block_size.height) + el->content_offset_left() - m_padding.left;
+                    } else if(css_left.is_predefined() && !css_right.is_predefined())
+                    {
+                        el->m_pos.x = m_pos.width + m_padding.right - css_right.calc_percent(containing_block_size.height) - el->m_pos.width -
+								el->content_offset_right();
+                    } else
+                    {
+                        el->m_pos.x		= css_left.calc_percent(containing_block_size.height) + el->content_offset_left() - m_padding.left;
+                        el->m_pos.width	= m_pos.width + m_padding.left + m_padding.right -
+								css_left.calc_percent(containing_block_size.height) -
+								css_right.calc_percent(containing_block_size.height) -
+								(el->content_offset_left() + el->content_offset_right());
+                        if (new_width != -1)
+                        {
+                            el->m_pos.x += (el->m_pos.width - new_width) / 2;
+                            el->m_pos.width = new_width;
+                        }
+                        need_render = true;
+                    }
+                    cvt_x = true;
+                }
+
+                if(!css_top.is_predefined() || !css_bottom.is_predefined())
+                {
+                    if(!css_top.is_predefined() && css_bottom.is_predefined())
+                    {
+                        el->m_pos.y = css_top.calc_percent(containing_block_size.height) + el->content_offset_top() - m_padding.top;
+                    } else if(css_top.is_predefined() && !css_bottom.is_predefined())
+                    {
+                        el->m_pos.y = m_pos.height + m_padding.bottom - css_bottom.calc_percent(containing_block_size.height) - el->m_pos.height -
+								el->content_offset_bottom();
+                    } else
+                    {
+                        el->m_pos.y			= css_top.calc_percent(containing_block_size.height) + el->content_offset_top() - m_padding.top;
+                        el->m_pos.height	= m_pos.height + m_padding.top + m_padding.bottom -
+								css_top.calc_percent(containing_block_size.height) -
+								css_bottom.calc_percent(containing_block_size.height) -
+								(el->content_offset_top() + el->content_offset_bottom());
+                        if (new_height != -1)
+                        {
+                            el->m_pos.y += (el->m_pos.height - new_height) / 2;
+                            el->m_pos.height = new_height;
+                        }
+                        need_render = true;
+                    }
+                    cvt_y = true;
+                }
+            }
+
+            if(cvt_x || cvt_y)
+            {
+                int offset_x = 0;
+                int offset_y = 0;
+                auto cur_el = el->parent();
+                auto this_el = shared_from_this();
+                while(cur_el && cur_el != this_el)
+                {
+                    offset_x += cur_el->m_pos.x;
+                    offset_y += cur_el->m_pos.y;
+                    cur_el = cur_el->parent();
+                }
+                if(cvt_x)	el->m_pos.x -= offset_x;
+                if(cvt_y)	el->m_pos.y -= offset_y;
+            }
+
+            if(need_render)
+            {
+                position pos = el->m_pos;
+				el->render(el->left(), el->top(), containing_block_size.new_width(el->width()), true);
+                el->m_pos = pos;
+            }
+
+            if(el_position == element_position_fixed)
+            {
+                position fixed_pos;
+                el->get_redraw_box(fixed_pos);
+                src_el()->get_document()->add_fixed_box(fixed_pos);
+            }
+        }
+
+		el->render_positioned();
+    }
+
+    if(!m_positioned.empty())
+    {
+        std::stable_sort(m_positioned.begin(), m_positioned.end(), [](const std::shared_ptr<render_item>& Left, const std::shared_ptr<render_item>& Right)
+            {
+                return (Left->src_el()->css().get_z_index() < Right->src_el()->css().get_z_index());
+            });
+    }
+}
+
+void litehtml::render_item::add_positioned(const std::shared_ptr<litehtml::render_item> &el)
+{
+    if (src_el()->css().get_position() != element_position_static || is_root())
+    {
+        m_positioned.push_back(el);
+    } else
+    {
+        auto el_parent = parent();
+        if (el_parent)
+        {
+            el_parent->add_positioned(el);
+        }
+    }
+}
+
+void litehtml::render_item::get_redraw_box(litehtml::position& pos, int x /*= 0*/, int y /*= 0*/)
+{
+    if(is_visible())
+    {
+        int p_left		= std::min(pos.left(),	x + m_pos.left() - m_padding.left - m_borders.left);
+        int p_right		= std::max(pos.right(), x + m_pos.right() + m_padding.left + m_borders.left);
+        int p_top		= std::min(pos.top(), y + m_pos.top() - m_padding.top - m_borders.top);
+        int p_bottom	= std::max(pos.bottom(), y + m_pos.bottom() + m_padding.bottom + m_borders.bottom);
+
+        pos.x = p_left;
+        pos.y = p_top;
+        pos.width	= p_right - p_left;
+        pos.height	= p_bottom - p_top;
+
+        if(src_el()->css().get_overflow() == overflow_visible)
+        {
+            for(auto& el : m_children)
+            {
+                if(el->src_el()->css().get_position() != element_position_fixed)
+                {
+                    el->get_redraw_box(pos, x + m_pos.x, y + m_pos.y);
+                }
+            }
+        }
+    }
+}
+
+void litehtml::render_item::calc_document_size( litehtml::size& sz, litehtml::size& content_size, int x /*= 0*/, int y /*= 0*/ )
+{
+    if(is_visible() && src_el()->css().get_position() != element_position_fixed)
+    {
+		sz.width = std::max(sz.width, x + right());
+		sz.height = std::max(sz.height, y + bottom());
+
+		if(!src_el()->is_root() && !src_el()->is_body())
+		{
+			content_size.width = std::max(content_size.width, x + right());
+			content_size.height = std::max(content_size.height, y + bottom());
+		}
+
+		// All children of tables and blocks with style other than "overflow: visible" are inside element.
+		// We can skip calculating size of children
+        if(src_el()->css().get_overflow() == overflow_visible && src_el()->css().get_display() != display_table)
+        {
+            for(auto& el : m_children)
+            {
+                el->calc_document_size(sz, content_size, x + m_pos.x, y + m_pos.y);
+            }
+        }
+
+		if(src_el()->is_root() || src_el()->is_body())
+		{
+			content_size.width += content_offset_right();
+			content_size.height += content_offset_bottom();
+		}
+    }
+}
+
+void litehtml::render_item::draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned )
+{
+    if(!is_visible()) return;
+
+    std::map<int, bool> z_indexes;
+    if(with_positioned)
+    {
+        for(const auto& idx : m_positioned)
+        {
+            z_indexes[idx->src_el()->css().get_z_index()];
+        }
+
+        for(const auto& idx : z_indexes)
+        {
+            if(idx.first < 0)
+            {
+                draw_children(hdc, x, y, clip, draw_positioned, idx.first);
+            }
+        }
+    }
+    draw_children(hdc, x, y, clip, draw_block, 0);
+    draw_children(hdc, x, y, clip, draw_floats, 0);
+    draw_children(hdc, x, y, clip, draw_inlines, 0);
+    if(with_positioned)
+    {
+        for(auto& z_index : z_indexes)
+        {
+            if(z_index.first == 0)
+            {
+                draw_children(hdc, x, y, clip, draw_positioned, z_index.first);
+            }
+        }
+
+        for(auto& z_index : z_indexes)
+        {
+            if(z_index.first > 0)
+            {
+                draw_children(hdc, x, y, clip, draw_positioned, z_index.first);
+            }
+        }
+    }
+}
+
+void litehtml::render_item::draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex)
+{
+    position pos = m_pos;
+    pos.x += x;
+    pos.y += y;
+
+    document::ptr doc = src_el()->get_document();
+
+    if (src_el()->css().get_overflow() > overflow_visible)
+    {
+        // TODO: Process overflow for inline elements
+        if(src_el()->css().get_display() != display_inline)
+        {
+            position border_box = pos;
+            border_box += m_padding;
+            border_box += m_borders;
+
+            border_radiuses bdr_radius = src_el()->css().get_borders().radius.calc_percents(border_box.width,
+                                                                                            border_box.height);
+
+            bdr_radius -= m_borders;
+            bdr_radius -= m_padding;
+
+            doc->container()->set_clip(pos, bdr_radius);
+        }
+    }
+
+    for (const auto& el : m_children)
+    {
+        if (el->is_visible())
+        {
+            bool process = true;
+            switch (flag)
+            {
+                case draw_positioned:
+                    if (el->src_el()->is_positioned() && el->src_el()->css().get_z_index() == zindex)
+                    {
+                        if (el->src_el()->css().get_position() == element_position_fixed)
+                        {
+                            position browser_wnd;
+                            doc->container()->get_client_rect(browser_wnd);
+
+                            el->src_el()->draw(hdc, browser_wnd.x, browser_wnd.y, clip, el);
+                            el->draw_stacking_context(hdc, browser_wnd.x, browser_wnd.y, clip, true);
+                        }
+                        else
+                        {
+                            el->src_el()->draw(hdc, pos.x, pos.y, clip, el);
+                            el->draw_stacking_context(hdc, pos.x, pos.y, clip, true);
+                        }
+                        process = false;
+                    }
+                    break;
+                case draw_block:
+                    if (!el->src_el()->is_inline_box() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned())
+                    {
+                        el->src_el()->draw(hdc, pos.x, pos.y, clip, el);
+                    }
+                    break;
+                case draw_floats:
+                    if (el->src_el()->css().get_float() != float_none && !el->src_el()->is_positioned())
+                    {
+                        el->src_el()->draw(hdc, pos.x, pos.y, clip, el);
+                        el->draw_stacking_context(hdc, pos.x, pos.y, clip, false);
+                        process = false;
+                    }
+                    break;
+                case draw_inlines:
+                    if (el->src_el()->is_inline_box() && 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)
+                        {
+                            el->draw_stacking_context(hdc, pos.x, pos.y, clip, false);
+                            process = false;
+                        }
+                    }
+                    break;
+                default:
+                    break;
+            }
+
+            if (process)
+            {
+                if (flag == draw_positioned)
+                {
+                    if (!el->src_el()->is_positioned())
+                    {
+                        el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
+                    }
+                }
+                else
+                {
+                    if (el->src_el()->css().get_float() == float_none &&
+                        el->src_el()->css().get_display() != display_inline_block &&
+                        !el->src_el()->is_positioned())
+                    {
+                        el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
+                    }
+                }
+            }
+        }
+    }
+
+    if (src_el()->css().get_overflow() > overflow_visible)
+    {
+        doc->container()->del_clip();
+    }
+}
+
+std::shared_ptr<litehtml::element>  litehtml::render_item::get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex)
+{
+    element::ptr ret = nullptr;
+
+    if(src_el()->css().get_overflow() > overflow_visible)
+    {
+        if(!m_pos.is_point_inside(x, y))
+        {
+            return ret;
+        }
+    }
+
+    position el_pos = m_pos;
+    el_pos.x	= x - el_pos.x;
+    el_pos.y	= y - el_pos.y;
+
+    for(auto i = m_children.rbegin(); i != m_children.rend() && !ret; std::advance(i, 1))
+    {
+        auto el = (*i);
+
+        if(el->is_visible() && el->src_el()->css().get_display() != display_inline_text)
+        {
+            switch(flag)
+            {
+                case draw_positioned:
+                    if(el->src_el()->is_positioned() && el->src_el()->css().get_z_index() == zindex)
+                    {
+                        if(el->src_el()->css().get_position() == element_position_fixed)
+                        {
+                            ret = el->get_element_by_point(client_x, client_y, client_x, client_y);
+                            if(!ret && (*i)->is_point_inside(client_x, client_y))
+                            {
+                                ret = (*i)->src_el();
+                            }
+                        } else
+                        {
+                            ret = el->get_element_by_point(el_pos.x, el_pos.y, client_x, client_y);
+                            if(!ret && (*i)->is_point_inside(el_pos.x, el_pos.y))
+                            {
+                                ret = (*i)->src_el();
+                            }
+                        }
+                        el = nullptr;
+                    }
+                    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->is_point_inside(el_pos.x, el_pos.y))
+                        {
+                            ret = el->src_el();
+                        }
+                    }
+                    break;
+                case draw_floats:
+                    if(el->src_el()->css().get_float() != float_none && !el->src_el()->is_positioned())
+                    {
+                        ret = el->get_element_by_point(el_pos.x, el_pos.y, client_x, client_y);
+
+                        if(!ret && (*i)->is_point_inside(el_pos.x, el_pos.y))
+                        {
+                            ret = (*i)->src_el();
+                        }
+                        el = nullptr;
+                    }
+                    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()->css().get_display() == display_inline_block ||
+                                el->src_el()->css().get_display() == display_inline_table ||
+                                el->src_el()->css().get_display() == display_inline_flex)
+                        {
+                            ret = el->get_element_by_point(el_pos.x, el_pos.y, client_x, client_y);
+                            el = nullptr;
+                        }
+                        if(!ret && (*i)->is_point_inside(el_pos.x, el_pos.y))
+                        {
+                            ret = (*i)->src_el();
+                        }
+                    }
+                    break;
+                default:
+                    break;
+            }
+
+            if(el && !el->src_el()->is_positioned())
+            {
+                if(flag == draw_positioned)
+                {
+                    element::ptr child = el->get_child_by_point(el_pos.x, el_pos.y, client_x, client_y, flag, zindex);
+                    if(child)
+                    {
+                        ret = child;
+                    }
+                } else
+                {
+                    if(	el->src_el()->css().get_float() == float_none &&
+                           el->src_el()->css().get_display() != display_inline_block)
+                    {
+                        element::ptr child = el->get_child_by_point(el_pos.x, el_pos.y, client_x, client_y, flag, zindex);
+                        if(child)
+                        {
+                            ret = child;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return ret;
+}
+
+std::shared_ptr<litehtml::element> litehtml::render_item::get_element_by_point(int x, int y, int client_x, int client_y)
+{
+    if(!is_visible()) return nullptr;
+
+    element::ptr ret;
+
+    std::map<int, bool> z_indexes;
+
+    for(const auto& i : m_positioned)
+    {
+        z_indexes[i->src_el()->css().get_z_index()];
+    }
+
+    for(const auto& zindex : z_indexes)
+    {
+        if(zindex.first > 0)
+        {
+            ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, zindex.first);
+            break;
+        }
+    }
+    if(ret) return ret;
+
+    for(const auto& z_index : z_indexes)
+    {
+        if(z_index.first == 0)
+        {
+            ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, z_index.first);
+            break;
+        }
+    }
+    if(ret) return ret;
+
+    ret = get_child_by_point(x, y, client_x, client_y, draw_inlines, 0);
+    if(ret) return ret;
+
+    ret = get_child_by_point(x, y, client_x, client_y, draw_floats, 0);
+    if(ret) return ret;
+
+    ret = get_child_by_point(x, y, client_x, client_y, draw_block, 0);
+    if(ret) return ret;
+
+
+    for(const auto& z_index : z_indexes)
+    {
+        if(z_index.first < 0)
+        {
+            ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, z_index.first);
+            break;
+        }
+    }
+    if(ret) return ret;
+
+    if(src_el()->css().get_position() == element_position_fixed)
+    {
+        if(is_point_inside(client_x, client_y))
+        {
+            ret = src_el();
+        }
+    } else
+    {
+        if(is_point_inside(x, y))
+        {
+            ret = src_el();
+        }
+    }
+
+    return ret;
+}
+
+bool litehtml::render_item::is_point_inside( int x, int y )
+{
+	if(src_el()->css().get_display() != display_inline && src_el()->css().get_display() != display_table_row)
+	{
+		position pos = m_pos;
+		pos += m_padding;
+		pos += m_borders;
+		if(pos.is_point_inside(x, y))
+		{
+			return true;
+		} else
+		{
+			return false;
+		}
+	} else
+	{
+		position::vector boxes;
+		get_inline_boxes(boxes);
+		for(auto & box : boxes)
+		{
+			if(box.is_point_inside(x, y))
+			{
+				return true;
+			}
+		}
+	}
+    return false;
+}
+
+void litehtml::render_item::get_rendering_boxes( position::vector& redraw_boxes)
+{
+    if(src_el()->css().get_display() == display_inline || src_el()->css().get_display() == display_table_row)
+    {
+        get_inline_boxes(redraw_boxes);
+    } else
+    {
+        position pos = m_pos;
+        pos += m_padding;
+        pos += m_borders;
+        redraw_boxes.push_back(pos);
+    }
+
+    if(src_el()->css().get_position() != element_position_fixed)
+    {
+        auto cur_el = parent();
+        while(cur_el)
+        {
+            for(auto& box : redraw_boxes)
+            {
+                box.x += cur_el->m_pos.x;
+                box.y += cur_el->m_pos.y;
+            }
+            cur_el = cur_el->parent();
+        }
+    }
+}
+
+void litehtml::render_item::dump(litehtml::dumper& cout)
+{
+    cout.begin_node(src_el()->dump_get_name() + "{" + string(typeid(*this).name()) + "}");
+
+    auto attrs = src_el()->dump_get_attrs();
+    if(!attrs.empty())
+    {
+        cout.begin_attrs_group("attributes");
+        for (const auto &attr: attrs)
+        {
+            cout.add_attr(std::get<0>(attr), std::get<1>(attr));
+        }
+        cout.end_attrs_group();
+    }
+
+    if(!m_children.empty())
+    {
+        cout.begin_attrs_group("children");
+        for (const auto &el: m_children)
+        {
+            el->dump(cout);
+        }
+        cout.end_attrs_group();
+    }
+
+    cout.end_node();
+}
+
+litehtml::position litehtml::render_item::get_placement() const
+{
+	litehtml::position pos = m_pos;
+	auto cur_el = parent();
+	while(cur_el)
+	{
+		pos.x += cur_el->m_pos.x;
+		pos.y += cur_el->m_pos.y;
+		cur_el = cur_el->parent();
+	}
+	return pos;
+}
+
+std::shared_ptr<litehtml::render_item> litehtml::render_item::init()
+{
+    src_el()->add_render(shared_from_this());
+
+    for(auto& el : children())
+    {
+        el = el->init();
+    }
+
+    return shared_from_this();
+}
+
+void litehtml::render_item::calc_cb_length(const css_length& len, int percent_base, containing_block_context::typed_int& out_value) const
+{
+	if (!len.is_predefined())
+	{
+		if(len.units() == litehtml::css_units_percentage)
+		{
+			out_value.value = len.calc_percent(percent_base);
+			out_value.type = litehtml::containing_block_context::cbc_value_type_percentage;
+		} else
+		{
+			out_value.value = src_el()->get_document()->to_pixels(len, src_el()->css().get_font_size());
+			out_value.type = containing_block_context::cbc_value_type_absolute;
+		}
+	}
+}
+
+litehtml::containing_block_context litehtml::render_item::calculate_containing_block_context(const containing_block_context& cb_context)
+{
+	containing_block_context ret;
+	ret.context_idx = cb_context.context_idx + 1;
+	ret.width.value = ret.max_width.value = cb_context.width.value - content_offset_width();
+	if(src_el()->css().get_position() != element_position_absolute && src_el()->css().get_position() != element_position_fixed)
+	{
+		ret.height.value = cb_context.height.value - content_offset_height();
+	}
+
+	// Calculate width if css property is not auto
+	// We have to use aut value for display_table_cell also.
+	if (src_el()->css().get_display() != display_table_cell)
+	{
+		calc_cb_length(src_el()->css().get_width(), cb_context.width, ret.width);
+		calc_cb_length(src_el()->css().get_height(), cb_context.height, ret.height);
+		if (ret.width.type != containing_block_context::cbc_value_type_auto && (src_el()->css().get_display() == display_table || src_el()->is_root()))
+		{
+			ret.width.value -= content_offset_width();
+		}
+		if (ret.height.type != containing_block_context::cbc_value_type_auto && (src_el()->css().get_display() == display_table || src_el()->is_root()))
+		{
+			ret.height.value -= content_offset_height();
+		}
+	}
+	ret.render_width = ret.width;
+
+	calc_cb_length(src_el()->css().get_min_width(), cb_context.width, ret.min_width);
+	calc_cb_length(src_el()->css().get_max_width(), cb_context.width, ret.max_width);
+
+	calc_cb_length(src_el()->css().get_min_height(), cb_context.height, ret.min_height);
+	calc_cb_length(src_el()->css().get_max_height(), cb_context.height, ret.max_height);
+
+	if (src_el()->css().get_box_sizing() == box_sizing_border_box)
+	{
+		if(ret.width.type != containing_block_context::cbc_value_type_auto)
+		{
+			ret.render_width = ret.width - box_sizing_width();
+		}
+		if(ret.min_width.type != containing_block_context::cbc_value_type_none)
+		{
+			ret.min_width.value -= box_sizing_width();
+		}
+		if(ret.max_width.type != containing_block_context::cbc_value_type_none)
+		{
+			ret.max_width.value -= box_sizing_width();
+		}
+		if(ret.min_height.type != containing_block_context::cbc_value_type_none)
+		{
+			ret.min_height.value -= box_sizing_height();
+		}
+		if(ret.max_height.type != containing_block_context::cbc_value_type_none)
+		{
+			ret.max_height.value -= box_sizing_height();
+		}
+	}
+	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
new file mode 100644
index 000000000..f3575778f
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/render_item.h
@@ -0,0 +1,599 @@
+#ifndef LH_RENDER_ITEM_H
+#define LH_RENDER_ITEM_H
+
+#include <memory>
+#include <utility>
+#include <list>
+#include <tuple>
+#include "types.h"
+#include "line_box.h"
+#include "table.h"
+
+namespace litehtml
+{
+    class element;
+
+    class render_item : public std::enable_shared_from_this<render_item>
+    {
+    protected:
+        std::shared_ptr<element>                    m_element;
+        std::weak_ptr<render_item>                  m_parent;
+        std::list<std::shared_ptr<render_item>>     m_children;
+        margins						                m_margins;
+        margins						                m_padding;
+        margins						                m_borders;
+        position					                m_pos;
+        bool                                        m_skip;
+        std::vector<std::shared_ptr<render_item>>   m_positioned;
+
+		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;
+
+    public:
+        explicit render_item(std::shared_ptr<element>  src_el);
+
+        virtual ~render_item() = default;
+
+        std::list<std::shared_ptr<render_item>>& children()
+        {
+            return m_children;
+        }
+
+        position& pos()
+        {
+            return m_pos;
+        }
+
+        bool skip() const
+        {
+            return m_skip;
+        }
+
+        void skip(bool val)
+        {
+            m_skip = val;
+        }
+
+        int right() const
+        {
+            return left() + width();
+        }
+
+        int left() const
+        {
+            return m_pos.left() - m_margins.left - m_padding.left - m_borders.left;
+        }
+
+        int top() const
+        {
+            return m_pos.top() - m_margins.top - m_padding.top - m_borders.top;
+        }
+
+        int bottom() const
+        {
+            return top() + height();
+        }
+
+        int height() const
+        {
+            return m_pos.height + m_margins.height() + m_padding.height() + m_borders.height();
+        }
+
+        int width() const
+        {
+            return m_pos.width + m_margins.left + m_margins.right + m_padding.width() + m_borders.width();
+        }
+
+        int padding_top() const
+        {
+            return m_padding.top;
+        }
+
+        int padding_bottom() const
+        {
+            return m_padding.bottom;
+        }
+
+        int padding_left() const
+        {
+            return m_padding.left;
+        }
+
+        int padding_right() const
+        {
+            return m_padding.right;
+        }
+
+        int border_top() const
+        {
+            return m_borders.top;
+        }
+
+        int border_bottom() const
+        {
+            return m_borders.bottom;
+        }
+
+        int border_left() const
+        {
+            return m_borders.left;
+        }
+
+        int border_right() const
+        {
+            return m_borders.right;
+        }
+
+        int margin_top() const
+        {
+            return m_margins.top;
+        }
+
+        int margin_bottom() const
+        {
+            return m_margins.bottom;
+        }
+
+        int margin_left() const
+        {
+            return m_margins.left;
+        }
+
+        int margin_right() const
+        {
+            return m_margins.right;
+        }
+
+        std::shared_ptr<render_item> parent() const
+        {
+            return m_parent.lock();
+        }
+
+        margins& get_margins()
+        {
+            return m_margins;
+        }
+
+        margins& get_paddings()
+        {
+            return m_padding;
+        }
+
+		void set_paddings(const margins& val)
+		{
+			m_padding = val;
+		}
+
+        margins& get_borders()
+        {
+            return m_borders;
+        }
+
+		/**
+		 * Top offset to the element content. Includes paddings, margins and borders.
+		 */
+        int content_offset_top() const
+        {
+            return m_margins.top + m_padding.top + m_borders.top;
+        }
+
+		/**
+		 * Bottom offset to the element content. Includes paddings, margins and borders.
+		 */
+        inline int content_offset_bottom() const
+        {
+            return m_margins.bottom + m_padding.bottom + m_borders.bottom;
+        }
+
+		/**
+		 * Left offset to the element content. Includes paddings, margins and borders.
+		 */
+        int content_offset_left() const
+        {
+            return m_margins.left + m_padding.left + m_borders.left;
+        }
+
+		/**
+		 * Right offset to the element content. Includes paddings, margins and borders.
+		 */
+        int content_offset_right() const
+        {
+            return m_margins.right + m_padding.right + m_borders.right;
+        }
+
+		/**
+		 * Sum of left and right offsets to the element content. Includes paddings, margins and borders.
+		 */
+        int content_offset_width() const
+        {
+            return content_offset_left() + content_offset_right();
+        }
+
+		/**
+		 * Sum of top and bottom offsets to the element content. Includes paddings, margins and borders.
+		 */
+        int content_offset_height() const
+        {
+            return content_offset_top() + content_offset_bottom();
+        }
+
+		int box_sizing_left() const
+		{
+			return m_padding.left + m_borders.left;
+		}
+
+		int box_sizing_right() const
+		{
+			return m_padding.right + m_borders.right;
+		}
+
+		int box_sizing_width() const
+		{
+			return box_sizing_left() + box_sizing_left();
+		}
+
+		int box_sizing_top() const
+		{
+			return m_padding.top + m_borders.top;
+		}
+
+		int box_sizing_bottom() const
+		{
+			return m_padding.bottom + m_borders.bottom;
+		}
+
+		int box_sizing_height() const
+		{
+			return box_sizing_top() + box_sizing_bottom();
+		}
+
+        void parent(const std::shared_ptr<render_item>& par)
+        {
+            m_parent = par;
+        }
+
+        const std::shared_ptr<element>& src_el() const
+        {
+            return m_element;
+        }
+
+		const css_properties& css() const
+		{
+			return m_element->css();
+		}
+
+        void add_child(const std::shared_ptr<render_item>& ri)
+        {
+            m_children.push_back(ri);
+            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();
+		}
+
+        bool collapse_top_margin() const
+        {
+            return !m_borders.top &&
+                   !m_padding.top &&
+                   m_element->in_normal_flow() &&
+                   m_element->css().get_float() == float_none &&
+                   m_margins.top >= 0 &&
+                   !is_root();
+        }
+
+        bool collapse_bottom_margin() const
+        {
+            return !m_borders.bottom &&
+                   !m_padding.bottom &&
+                   m_element->in_normal_flow() &&
+                   m_element->css().get_float() == float_none &&
+                   m_margins.bottom >= 0 &&
+                   !is_root();
+        }
+
+        bool is_visible() const
+        {
+            return !(m_skip || src_el()->css().get_display() == display_none || src_el()->css().get_visibility() != visibility_visible);
+        }
+
+        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);
+        void calc_outlines( int parent_width );
+        int calc_auto_margins(int parent_width);	// returns left margin
+
+        virtual std::shared_ptr<render_item> init();
+        virtual void apply_vertical_align() {}
+        virtual int get_base_line() { return 0; }
+        virtual std::shared_ptr<render_item> clone()
+        {
+            return std::make_shared<render_item>(src_el());
+        }
+        std::tuple<
+                std::shared_ptr<litehtml::render_item>,
+                std::shared_ptr<litehtml::render_item>,
+                std::shared_ptr<litehtml::render_item>
+                > split_inlines();
+        bool fetch_positioned();
+        void render_positioned(render_type rt = render_all);
+        void add_positioned(const std::shared_ptr<litehtml::render_item> &el);
+        void get_redraw_box(litehtml::position& pos, int x = 0, int y = 0);
+        void calc_document_size( litehtml::size& sz, litehtml::size& content_size, int x = 0, int y = 0 );
+		virtual void get_inline_boxes( position::vector& boxes ) const {};
+		virtual void set_inline_boxes( position::vector& boxes ) {};
+		virtual void add_inline_box( const position& box ) {};
+		virtual void clear_inline_boxes() {};
+        void draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned );
+        virtual void draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex );
+        virtual int get_draw_vertical_offset() { return 0; }
+        virtual std::shared_ptr<element> get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex);
+        std::shared_ptr<element> get_element_by_point(int x, int y, int client_x, int client_y);
+        bool is_point_inside( int x, int y );
+        void dump(litehtml::dumper& cout);
+        position get_placement() const;
+        /**
+         * Returns the boxes of rendering element. All coordinates are absolute
+         *
+         * @param redraw_boxes [out] resulting rendering boxes
+         * @return
+         */
+        void get_rendering_boxes( position::vector& redraw_boxes);
+
+		virtual void get_line_left_right( int y, int def_right, int& ln_left, int& ln_right ) {}
+		virtual int get_line_left( int y )	{ return 0; }
+		virtual int get_line_right( int y, int def_right ) { return 0; }
+		virtual int get_left_floats_height() const	{ return 0; }
+		virtual int get_right_floats_height() const	{ return 0; }
+		virtual int get_floats_height(element_float el_float = float_none) const { return 0; }
+		virtual int find_next_line_top( int top, int width, int def_right ) { return 0; }
+		virtual void add_float(const std::shared_ptr<render_item> &el, int x, int y, int context) {}
+		virtual void clear_floats(int context) {}
+		virtual void update_floats(int dy, const std::shared_ptr<render_item> &_parent) {}
+	};
+
+    class render_item_block : public render_item
+    {
+    protected:
+		std::list<floated_box> m_floats_left;
+		std::list<floated_box> m_floats_right;
+        int_int_cache m_cache_line_left;
+        int_int_cache m_cache_line_right;
+
+		/**
+		 * Render block content.
+		 *
+		 * @param x - horizontal position of the content
+		 * @param y - vertical position of the content
+		 * @param second_pass - true is this is the second pass.
+		 * @param ret_width - input minimal width.
+		 * @param self_size - defines calculated size of block
+		 * @return return value is the minimal width of the content in block. Must be greater or equal to ret_width parameter
+		 */
+        virtual int _render_content(int x, int y, bool second_pass, int ret_width, const containing_block_context &self_size) {return ret_width;}
+		int render(int x, int y, const containing_block_context &containing_block_size, bool second_pass) override;
+
+        int place_float(const std::shared_ptr<render_item> &el, int top, const containing_block_context &self_size);
+        int get_floats_height(element_float el_float = float_none) const override;
+        int get_left_floats_height() const override;
+        int get_right_floats_height() const override;
+        int get_line_left( int y ) override;
+        int get_line_right( int y, int def_right ) override;
+        void get_line_left_right( int y, int def_right, int& ln_left, int& ln_right ) override;
+        void add_float(const std::shared_ptr<render_item> &el, int x, int y, int context) override;
+		void clear_floats(int context) override;
+		int get_cleared_top(const std::shared_ptr<render_item> &el, int line_top) const;
+        int find_next_line_top( int top, int width, int def_right ) override;
+        virtual void fix_line_width(element_float flt,
+									const containing_block_context &containing_block_size)
+		{}
+        void update_floats(int dy, const std::shared_ptr<render_item> &_parent) override;
+    public:
+        explicit render_item_block(std::shared_ptr<element>  src_el) : render_item(std::move(src_el))
+        {}
+
+        std::shared_ptr<render_item> clone() override
+        {
+            return std::make_shared<render_item_block>(src_el());
+        }
+        std::shared_ptr<render_item> init() override;
+    };
+
+    /**
+     * In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a
+     * containing block.
+     * https://www.w3.org/TR/CSS22/visuren.html#block-formatting
+     */
+    class render_item_block_context : public render_item_block
+    {
+    protected:
+        int _render_content(int x, int y, bool second_pass, int ret_width,
+							const containing_block_context &self_size) override;
+
+    public:
+        explicit render_item_block_context(std::shared_ptr<element>  src_el) : render_item_block(std::move(src_el))
+        {}
+
+        std::shared_ptr<render_item> clone() override
+        {
+            return std::make_shared<render_item_block_context>(src_el());
+        }
+    };
+
+    /**
+     * An inline formatting context is established by a block container box that contains no block-level boxes.
+     * https://www.w3.org/TR/CSS22/visuren.html#inline-formatting
+     */
+    class render_item_inline_context : public render_item_block
+    {
+		/**
+		 *	Structure contains elements with display: inline
+		 *	members:
+		 *	- element: 		render_item with display: inline
+		 *	- boxes: 		rectangles represented inline element content. There are can be many boxes if content
+		 *			 is split into some lines
+		 *	- start_box:	the start position of currently calculated box
+		 */
+		struct inlines_item
+		{
+			std::shared_ptr<render_item> element;
+			position::vector boxes;
+			position	start_box;
+
+			explicit inlines_item(const std::shared_ptr<render_item>& el) : element(el) {}
+		};
+    protected:
+        std::vector<std::unique_ptr<litehtml::line_box> > m_line_boxes;
+		int m_max_line_width;
+
+        int _render_content(int x, int y, bool second_pass, int ret_width,
+							const containing_block_context &self_size) override;
+        void fix_line_width(element_float flt,
+							const containing_block_context &self_size) override;
+
+        std::list<std::unique_ptr<line_box_item> > finish_last_box(bool end_of_render, const containing_block_context &self_size);
+        void place_inline(std::unique_ptr<line_box_item> item, const containing_block_context &self_size);
+        int new_box(const std::unique_ptr<line_box_item>& el, line_context& line_ctx, const containing_block_context &self_size);
+        void apply_vertical_align() override;
+    public:
+        explicit render_item_inline_context(std::shared_ptr<element>  src_el) : render_item_block(std::move(src_el)), m_max_line_width(0)
+        {}
+
+        std::shared_ptr<render_item> clone() override
+        {
+            return std::make_shared<render_item_inline_context>(src_el());
+        }
+
+        int get_base_line() override;
+    };
+
+    class render_item_table : public render_item
+    {
+    protected:
+        // data for table rendering
+        std::unique_ptr<table_grid>	m_grid;
+        int						    m_border_spacing_x;
+        int						    m_border_spacing_y;
+
+    public:
+        explicit render_item_table(std::shared_ptr<element>  src_el);
+
+        std::shared_ptr<render_item> clone() override
+        {
+            return std::make_shared<render_item_table>(src_el());
+        }
+		int render(int x, int y, const containing_block_context &containing_block_size, bool second_pass) override;
+        void draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override;
+        int get_draw_vertical_offset() override;
+        std::shared_ptr<render_item> init() override;
+    };
+
+	class render_item_table_part : public render_item
+	{
+	public:
+		explicit render_item_table_part(std::shared_ptr<element>  src_el) : render_item(std::move(src_el))
+		{}
+
+		std::shared_ptr<render_item> clone() override
+		{
+			return std::make_shared<render_item_table_part>(src_el());
+		}
+	};
+
+	class render_item_table_row : public render_item
+	{
+	public:
+		explicit render_item_table_row(std::shared_ptr<element>  src_el) : render_item(std::move(src_el))
+		{}
+
+		std::shared_ptr<render_item> clone() override
+		{
+			return std::make_shared<render_item_table_row>(src_el());
+		}
+		void get_inline_boxes( position::vector& boxes ) const override;
+	};
+
+	class render_item_inline : public render_item
+    {
+    protected:
+		position::vector m_boxes;
+
+    public:
+        explicit render_item_inline(std::shared_ptr<element>  src_el) : render_item(std::move(src_el))
+        {}
+
+		void get_inline_boxes( position::vector& boxes ) const override { boxes = m_boxes; }
+		void set_inline_boxes( position::vector& boxes ) override { m_boxes = boxes; }
+		void add_inline_box( const position& box ) override { m_boxes.emplace_back(box); };
+		void clear_inline_boxes() override { m_boxes.clear(); }
+		int get_base_line() override { return src_el()->css().get_font_metrics().base_line(); }
+
+		std::shared_ptr<render_item> clone() override
+        {
+            return std::make_shared<render_item_inline>(src_el());
+        }
+    };
+
+    class render_item_image : public render_item
+    {
+    protected:
+        int calc_max_height(int image_height, int containing_block_height);
+
+    public:
+        explicit render_item_image(std::shared_ptr<element>  src_el) : render_item(std::move(src_el))
+        {}
+
+		int render(int x, int y, const containing_block_context &containing_block_size, bool second_pass) override;
+        std::shared_ptr<render_item> clone() override
+        {
+            return std::make_shared<render_item_image>(src_el());
+        }
+    };
+
+    class render_item_flex : public render_item_block
+    {
+        struct flex_item
+        {
+            std::shared_ptr<render_item> el;
+            int base_size;
+            int main_size;
+            int min_width;
+            int max_width;
+            int line;
+
+            explicit flex_item(std::shared_ptr<render_item>  _el) :
+                el(std::move(_el)),
+                min_width(0),
+                max_width(0),
+                line(0),
+                base_size(0),
+                main_size(0)
+            {}
+        };
+    protected:
+        std::list<std::unique_ptr<flex_item>>   m_flex_items;
+
+        int _render_content(int x, int y, bool second_pass, int ret_width,
+							const containing_block_context &self_size) override;
+
+    public:
+        explicit render_item_flex(std::shared_ptr<element>  src_el) : render_item_block(std::move(src_el))
+        {}
+
+        std::shared_ptr<render_item> clone() override
+        {
+            return std::make_shared<render_item_flex>(src_el());
+        }
+        void draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override;
+        std::shared_ptr<render_item> init() override;
+    };
+
+}
+
+#endif //LH_RENDER_ITEM_H
diff --git a/src/plugins/litehtml_viewer/litehtml/render_table.cpp b/src/plugins/litehtml_viewer/litehtml/render_table.cpp
new file mode 100644
index 000000000..2ec048a98
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/render_table.cpp
@@ -0,0 +1,482 @@
+#include "html.h"
+#include "render_item.h"
+#include "document.h"
+#include "iterators.h"
+
+
+litehtml::render_item_table::render_item_table(std::shared_ptr<element> _src_el) :
+        render_item(std::move(_src_el)),
+        m_border_spacing_x(0),
+        m_border_spacing_y(0)
+{
+}
+
+int litehtml::render_item_table::render(int x, int y, const containing_block_context &containing_block_size, 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)
+    {
+        table_width_spacing = m_border_spacing_x * (m_grid->cols_count() + 1);
+    }
+    else
+    {
+        table_width_spacing = 0;
+
+        if (m_grid->cols_count())
+        {
+            table_width_spacing -= std::min(border_left(), m_grid->column(0).border_left);
+            table_width_spacing -= std::min(border_right(), m_grid->column(m_grid->cols_count() - 1).border_right);
+        }
+
+        for (int col = 1; col < m_grid->cols_count(); col++)
+        {
+            table_width_spacing -= std::min(m_grid->column(col).border_left, m_grid->column(col - 1).border_right);
+        }
+    }
+
+
+    // Calculate the minimum content width (MCW) of each cell: the formatted content may span any number of lines but may not overflow the cell box.
+    // If the specified 'width' (W) of the cell is greater than MCW, W is the minimum cell width. A value of 'auto' means that MCW is the minimum
+    // cell width.
+    //
+    // Also, calculate the "maximum" cell width of each cell: formatting the content without breaking lines other than where explicit line breaks occur.
+
+    if (m_grid->cols_count() == 1 && self_size.width.type != containing_block_context::cbc_value_type_auto)
+    {
+        for (int row = 0; row < m_grid->rows_count(); row++)
+        {
+            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->el->pos().width = cell->min_width - cell->el->content_offset_left() -
+						cell->el->content_offset_right();
+            }
+        }
+    }
+    else
+    {
+        for (int row = 0; row < m_grid->rows_count(); row++)
+        {
+            for (int col = 0; col < m_grid->cols_count(); col++)
+            {
+                table_cell* cell = m_grid->cell(col, row);
+                if (cell && cell->el)
+                {
+                    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));
+                        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();
+                    }
+                    else
+                    {
+                        // calculate minimum content width
+                        cell->min_width = cell->el->render(0, 0, self_size.new_width(cell->el->content_offset_width()));
+                        // calculate maximum content width
+                        cell->max_width = cell->el->render(0, 0, self_size.new_width(self_size.render_width - table_width_spacing));
+                    }
+                }
+            }
+        }
+    }
+
+    // For each column, determine a maximum and minimum column width from the cells that span only that column.
+    // The minimum is that required by the cell with the largest minimum cell width (or the column 'width', whichever is larger).
+    // The maximum is that required by the cell with the largest maximum cell width (or the column 'width', whichever is larger).
+
+    for (int col = 0; col < m_grid->cols_count(); col++)
+    {
+        m_grid->column(col).max_width = 0;
+        m_grid->column(col).min_width = 0;
+        for (int row = 0; row < m_grid->rows_count(); row++)
+        {
+            if (m_grid->cell(col, row)->colspan <= 1)
+            {
+                m_grid->column(col).max_width = std::max(m_grid->column(col).max_width, m_grid->cell(col, row)->max_width);
+                m_grid->column(col).min_width = std::max(m_grid->column(col).min_width, m_grid->cell(col, row)->min_width);
+            }
+        }
+    }
+
+    // For each cell that spans more than one column, increase the minimum widths of the columns it spans so that together,
+    // they are at least as wide as the cell. Do the same for the maximum widths.
+    // If possible, widen all spanned columns by approximately the same amount.
+
+    for (int col = 0; col < m_grid->cols_count(); col++)
+    {
+        for (int row = 0; row < m_grid->rows_count(); row++)
+        {
+            if (m_grid->cell(col, row)->colspan > 1)
+            {
+                int max_total_width = m_grid->column(col).max_width;
+                int min_total_width = m_grid->column(col).min_width;
+                for (int col2 = col + 1; col2 < col + m_grid->cell(col, row)->colspan; col2++)
+                {
+                    max_total_width += m_grid->column(col2).max_width;
+                    min_total_width += m_grid->column(col2).min_width;
+                }
+                if (min_total_width < m_grid->cell(col, row)->min_width)
+                {
+                    m_grid->distribute_min_width(m_grid->cell(col, row)->min_width - min_total_width, col, col + m_grid->cell(col, row)->colspan - 1);
+                }
+                if (max_total_width < m_grid->cell(col, row)->max_width)
+                {
+                    m_grid->distribute_max_width(m_grid->cell(col, row)->max_width - max_total_width, col, col + m_grid->cell(col, row)->colspan - 1);
+                }
+            }
+        }
+    }
+
+    // If the 'table' or 'inline-table' element's 'width' property has a computed value (W) other than 'auto', the used width is the
+    // greater of W, CAPMIN, and the minimum width required by all the columns plus cell spacing or borders (MIN).
+    // If the used width is greater than MIN, the extra width should be distributed over the columns.
+    //
+    // If the 'table' or 'inline-table' element has 'width: auto', the used width is the greater of the table's containing block width,
+    // CAPMIN, and MIN. However, if either CAPMIN or the maximum width required by the columns plus cell spacing or borders (MAX) is
+    // less than that of the containing block, use max(MAX, CAPMIN).
+
+
+    int table_width = 0;
+    int min_table_width = 0;
+    int max_table_width = 0;
+
+    if (self_size.width.type == containing_block_context::cbc_value_type_absolute)
+    {
+        table_width = m_grid->calc_table_width(self_size.render_width - table_width_spacing, false, min_table_width, max_table_width);
+    }
+    else
+    {
+        table_width = m_grid->calc_table_width(self_size.render_width - table_width_spacing, self_size.width.type == containing_block_context::cbc_value_type_auto, min_table_width, max_table_width);
+    }
+
+    min_table_width += table_width_spacing;
+    max_table_width += table_width_spacing;
+    table_width += table_width_spacing;
+    m_grid->calc_horizontal_positions(m_borders, src_el()->css().get_border_collapse(), m_border_spacing_x);
+
+    bool row_span_found = false;
+
+    // render cells with computed width
+    for (int row = 0; row < m_grid->rows_count(); row++)
+    {
+        m_grid->row(row).height = 0;
+        for (int col = 0; col < m_grid->cols_count(); col++)
+        {
+            table_cell* cell = m_grid->cell(col, row);
+            if (cell->el)
+            {
+                int span_col = col + cell->colspan - 1;
+                if (span_col >= m_grid->cols_count())
+                {
+                    span_col = m_grid->cols_count() - 1;
+                }
+                int cell_width = m_grid->column(span_col).right - m_grid->column(col).left;
+
+                //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->pos().width = cell_width - cell->el->content_offset_left() -
+							cell->el->content_offset_right();
+                }
+                /*else
+                {
+                    cell->el->pos().x = m_grid->column(col).left + cell->el->content_offset_left();
+                }*/
+
+                if (cell->rowspan <= 1)
+                {
+                    m_grid->row(row).height = std::max(m_grid->row(row).height, cell->el->height());
+                }
+                else
+                {
+                    row_span_found = true;
+                }
+
+            }
+        }
+    }
+
+    if (row_span_found)
+    {
+        for (int col = 0; col < m_grid->cols_count(); col++)
+        {
+            for (int row = 0; row < m_grid->rows_count(); row++)
+            {
+                table_cell* cell = m_grid->cell(col, row);
+                if (cell->el)
+                {
+                    int span_row = row + cell->rowspan - 1;
+                    if (span_row >= m_grid->rows_count())
+                    {
+                        span_row = m_grid->rows_count() - 1;
+                    }
+                    if (span_row != row)
+                    {
+                        int h = 0;
+                        for (int i = row; i <= span_row; i++)
+                        {
+                            h += m_grid->row(i).height;
+                        }
+                        if (h < cell->el->height())
+                        {
+                            m_grid->row(span_row).height += cell->el->height() - h;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // Calculate vertical table spacing
+    int table_height_spacing = 0;
+    if (src_el()->css().get_border_collapse() == border_collapse_separate)
+    {
+        table_height_spacing = m_border_spacing_y * (m_grid->rows_count() + 1);
+    }
+    else
+    {
+        table_height_spacing = 0;
+
+        if (m_grid->rows_count())
+        {
+            table_height_spacing -= std::min(border_top(), m_grid->row(0).border_top);
+            table_height_spacing -= std::min(border_bottom(), m_grid->row(m_grid->rows_count() - 1).border_bottom);
+        }
+
+        for (int row = 1; row < m_grid->rows_count(); row++)
+        {
+            table_height_spacing -= std::min(m_grid->row(row).border_top, m_grid->row(row - 1).border_bottom);
+        }
+    }
+
+
+    // calculate block height
+    int block_height = 0;
+    if (get_predefined_height(block_height, containing_block_size.height))
+    {
+        block_height -= m_padding.height() + m_borders.height();
+    }
+
+    // calculate minimum height from m_css.get_min_height()
+    int min_height = 0;
+    if (!src_el()->css().get_min_height().is_predefined() && src_el()->css().get_min_height().units() == css_units_percentage)
+    {
+		min_height = src_el()->css().get_min_height().calc_percent(containing_block_size.height);
+    }
+    else
+    {
+        min_height = (int)src_el()->css().get_min_height().val();
+    }
+
+    int minimum_table_height = std::max(block_height, min_height);
+
+    m_grid->calc_rows_height(minimum_table_height - table_height_spacing, m_border_spacing_y);
+    m_grid->calc_vertical_positions(m_borders, src_el()->css().get_border_collapse(), m_border_spacing_y);
+
+    int table_height = 0;
+
+    // place cells vertically
+    for (int col = 0; col < m_grid->cols_count(); col++)
+    {
+        for (int row = 0; row < m_grid->rows_count(); row++)
+        {
+            table_cell* cell = m_grid->cell(col, row);
+            if (cell->el)
+            {
+                int span_row = row + cell->rowspan - 1;
+                if (span_row >= m_grid->rows_count())
+                {
+                    span_row = m_grid->rows_count() - 1;
+                }
+                cell->el->pos().y = m_grid->row(row).top + cell->el->content_offset_top();
+                cell->el->pos().height = m_grid->row(span_row).bottom - m_grid->row(row).top -
+						cell->el->content_offset_top() -
+										 cell->el->content_offset_bottom();
+                table_height = std::max(table_height, m_grid->row(span_row).bottom);
+                cell->el->apply_vertical_align();
+            }
+        }
+    }
+
+    if (src_el()->css().get_border_collapse() == border_collapse_collapse)
+    {
+        if (m_grid->rows_count())
+        {
+            table_height -= std::min(border_bottom(), m_grid->row(m_grid->rows_count() - 1).border_bottom);
+        }
+    }
+    else
+    {
+        table_height += m_border_spacing_y;
+    }
+
+    // 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();
+
+    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 (captions_height)
+    {
+        // Add border height to get the top of cells
+        captions_height += border_top();
+
+        // Save caption height for draw_background
+        m_grid->captions_height(captions_height);
+
+        // 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;
+            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;
+                }
+            }
+        }
+    }
+
+	m_pos.move_to(x + content_offset_left(), y + content_offset_top());
+	m_pos.width = table_width;
+	m_pos.height = table_height + captions_height;
+
+	if(self_size.width.type != containing_block_context::cbc_value_type_absolute)
+	{
+		return std::min(table_width, max_table_width) + content_offset_width();
+	}
+	return table_width + content_offset_width();
+}
+
+std::shared_ptr<litehtml::render_item> litehtml::render_item_table::init()
+{
+    // Initialize Grid
+    m_grid = std::unique_ptr<table_grid>(new table_grid());
+
+    go_inside_table 		table_selector;
+    table_rows_selector		row_selector;
+    table_cells_selector	cell_selector;
+
+    elements_iterator row_iter(false, &table_selector, &row_selector);
+
+    row_iter.process(shared_from_this(), [&](std::shared_ptr<render_item>& el, iterator_item_type item_type)
+        {
+            m_grid->begin_row(el);
+
+
+            elements_iterator cell_iter(true, &table_selector, &cell_selector);
+            cell_iter.process(el, [&](std::shared_ptr<render_item>& el, iterator_item_type item_type)
+                {
+					if(item_type != iterator_item_type_end_parent)
+					{
+						el = el->init();
+						m_grid->add_cell(el);
+					}
+                });
+        });
+
+    for (auto& el : m_children)
+    {
+        if (el->src_el()->css().get_display() == display_table_caption)
+        {
+            el = el->init();
+            m_grid->captions().push_back(el);
+        }
+    }
+
+    m_grid->finish();
+
+	if(src_el()->css().get_border_collapse() == border_collapse_separate)
+	{
+		int font_size = src_el()->css().get_font_size();
+		document::ptr doc = src_el()->get_document();
+		m_border_spacing_x = doc->to_pixels(src_el()->css().get_border_spacing_x(), font_size);
+		m_border_spacing_y = doc->to_pixels(src_el()->css().get_border_spacing_y(), font_size);
+	} else
+	{
+		m_border_spacing_x	= 0;
+		m_border_spacing_y	= 0;
+	}
+
+    src_el()->add_render(shared_from_this());
+
+    return shared_from_this();
+}
+
+void litehtml::render_item_table::draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex)
+{
+    if (!m_grid) return;
+
+    position pos = m_pos;
+    pos.x += x;
+    pos.y += y;
+    for (auto& caption : m_grid->captions())
+    {
+        if (flag == draw_block)
+        {
+            caption->src_el()->draw(hdc, pos.x, pos.y, clip, caption);
+        }
+        caption->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
+    }
+    for (int row = 0; row < m_grid->rows_count(); row++)
+    {
+        if (flag == draw_block)
+        {
+            m_grid->row(row).el_row->src_el()->draw_background(hdc, pos.x, pos.y, clip, m_grid->row(row).el_row);
+        }
+        for (int col = 0; col < m_grid->cols_count(); col++)
+        {
+            table_cell* cell = m_grid->cell(col, row);
+            if (cell->el)
+            {
+                if (flag == draw_block)
+                {
+                    cell->el->src_el()->draw(hdc, pos.x, pos.y, clip, cell->el);
+                }
+                cell->el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
+            }
+        }
+    }
+}
+
+int litehtml::render_item_table::get_draw_vertical_offset()
+{
+    if(m_grid)
+    {
+        return m_grid->captions_height();
+    }
+    return 0;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/string_id.cpp b/src/plugins/litehtml_viewer/litehtml/string_id.cpp
new file mode 100644
index 000000000..9f8390303
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/string_id.cpp
@@ -0,0 +1,54 @@
+#include "html.h"
+#include "string_id.h"
+#include <assert.h>
+
+#ifndef LITEHTML_NO_THREADS
+	#include <mutex>
+	static std::mutex mutex;
+	#define lock_guard std::lock_guard<std::mutex> lock(mutex)
+#else
+	#define lock_guard
+#endif
+
+namespace litehtml
+{
+
+static std::map<string, string_id> map;
+static std::vector<string> array;
+
+static int init()
+{
+	string_vector names;
+	split_string(initial_string_ids, names, ",");
+	for (auto& name : names)
+	{
+		trim(name);
+		assert(name[0] == '_' && name.back() == '_');
+		name = name.substr(1, name.size() - 2);				// _border_color_ -> border_color
+		std::replace(name.begin(), name.end(), '_', '-');	// border_color   -> border-color
+		_id(name);  // this will create association _border_color_ <-> "border-color"
+	}
+	return 0;
+}
+static int dummy = init();
+
+const string_id empty_id = _id("");
+const string_id star_id = _id("*");
+
+string_id _id(const string& str)
+{
+	lock_guard;
+	auto it = map.find(str);
+	if (it != map.end()) return it->second;
+	// else: str not found, add it to the array and the map
+	array.push_back(str);
+	return map[str] = (string_id)(array.size() - 1);
+}
+
+const string& _s(string_id id)
+{
+	lock_guard;
+	return array[id];
+}
+
+} // namespace litehtml
\ No newline at end of file
diff --git a/src/plugins/litehtml_viewer/litehtml/string_id.h b/src/plugins/litehtml_viewer/litehtml/string_id.h
new file mode 100644
index 000000000..340ac7fbc
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/string_id.h
@@ -0,0 +1,300 @@
+#ifndef LH_STRING_ID_H
+#define LH_STRING_ID_H
+
+namespace litehtml
+{
+
+#define STRING_ID(...)\
+	enum string_id { __VA_ARGS__ };\
+	const auto initial_string_ids = #__VA_ARGS__;
+
+STRING_ID(
+
+	// HTML tags
+	_a_,
+	_abbr_,
+	_acronym_,
+	_address_,
+	_applet_,
+	_area_,
+	_article_,
+	_aside_,
+	_audio_,
+	_b_,
+	_base_,
+	_basefont_,
+	_bdi_,
+	_bdo_,
+	_big_,
+	_blockquote_,
+	_body_,
+	_br_,
+	_button_,
+	_canvas_,
+	_caption_,
+	_center_,
+	_cite_,
+	_code_,
+	_col_,
+	_colgroup_,
+	_data_,
+	_datalist_,
+	_dd_,
+	_del_,
+	_details_,
+	_dfn_,
+	_dialog_,
+	_dir_,
+	_div_,
+	_dl_,
+	_dt_,
+	_em_,
+	_embed_,
+	_fieldset_,
+	_figcaption_,
+	_figure_,
+	_footer_,
+	_form_,
+	_frame_,
+	_frameset_,
+	_h1_,
+	_h2_,
+	_h3_,
+	_h4_,
+	_h5_,
+	_h6_,
+	_head_,
+	_header_,
+	_hr_,
+	_html_,
+	_i_,
+	_iframe_,
+	_img_,
+	_input_,
+	_ins_,
+	_kbd_,
+	_label_,
+	_legend_,
+	_li_,
+	_link_,
+	_main_,
+	_map_,
+	_mark_,
+	_meta_,
+	_meter_,
+	_nav_,
+	_noframes_,
+	_noscript_,
+	_object_,
+	_ol_,
+	_optgroup_,
+	_option_,
+	_output_,
+	_p_,
+	_param_,
+	_picture_,
+	_pre_,
+	_progress_,
+	_q_,
+	_rp_,
+	_rt_,
+	_ruby_,
+	_s_,
+	_samp_,
+	_script_,
+	_section_,
+	_select_,
+	_small_,
+	_source_,
+	_span_,
+	_strike_,
+	_strong_,
+	_style_,
+	_sub_,
+	_summary_,
+	_sup_,
+	_svg_,
+	_table_,
+	_tbody_,
+	_td_,
+	_template_,
+	_textarea_,
+	_tfoot_,
+	_th_,
+	_thead_,
+	_time_,
+	_title_,
+	_tr_,
+	_track_,
+	_tt_,
+	_u_,
+	_ul_,
+	_var_,
+	_video_,
+	_wbr_,
+
+	// litehtml internal tags
+	__tag_before_, // note: real tag cannot start with '-'
+	__tag_after_,
+
+	// CSS pseudo-elements
+	_before_,
+	_after_,
+
+	// CSS pseudo-classes
+	_root_,
+	_only_child_,
+	_only_of_type_,
+	_first_child_,
+	_first_of_type_,
+	_last_child_,
+	_last_of_type_,
+	_nth_child_,
+	_nth_of_type_,
+	_nth_last_child_,
+	_nth_last_of_type_,
+	_not_,
+	_lang_,
+
+	_active_,
+	_hover_,
+
+	// CSS property names
+	_background_,
+	_background_color_,
+	_background_image_,
+	_background_image_baseurl_,
+	_background_repeat_,
+	_background_origin_,
+	_background_clip_,
+	_background_attachment_,
+	_background_size_,
+	_background_position_,
+	_background_position_x_,
+	_background_position_y_,
+
+	_border_,
+	_border_width_,
+	_border_style_,
+	_border_color_,
+
+	_border_spacing_,
+	__litehtml_border_spacing_x_,
+	__litehtml_border_spacing_y_,
+
+	_border_left_,
+	_border_right_,
+	_border_top_,
+	_border_bottom_,
+
+	_border_left_style_,
+	_border_right_style_,
+	_border_top_style_,
+	_border_bottom_style_,
+
+	_border_left_width_,
+	_border_right_width_,
+	_border_top_width_,
+	_border_bottom_width_,
+
+	_border_left_color_,
+	_border_right_color_,
+	_border_top_color_,
+	_border_bottom_color_,
+
+	_border_radius_,
+	_border_radius_x_,
+	_border_radius_y_,
+
+	_border_bottom_left_radius_,
+	_border_bottom_left_radius_x_,
+	_border_bottom_left_radius_y_,
+
+	_border_bottom_right_radius_,
+	_border_bottom_right_radius_x_,
+	_border_bottom_right_radius_y_,
+
+	_border_top_left_radius_,
+	_border_top_left_radius_x_,
+	_border_top_left_radius_y_,
+
+	_border_top_right_radius_,
+	_border_top_right_radius_x_,
+	_border_top_right_radius_y_,
+
+	_list_style_,
+	_list_style_type_,
+	_list_style_position_,
+	_list_style_image_,
+	_list_style_image_baseurl_,
+
+	_margin_,
+	_margin_left_,
+	_margin_right_,
+	_margin_top_,
+	_margin_bottom_,
+	_padding_,
+	_padding_left_,
+	_padding_right_,
+	_padding_top_,
+	_padding_bottom_,
+
+	_font_,
+	_font_family_,
+	_font_style_,
+	_font_variant_,
+	_font_weight_,
+	_font_size_,
+	_line_height_,
+	_text_decoration_,
+
+	_white_space_,
+	_text_align_,
+	_vertical_align_,
+	_color_,
+	_width_,
+	_height_,
+	_min_width_,
+	_min_height_,
+	_max_width_,
+	_max_height_,
+	_position_,
+	_overflow_,
+	_display_,
+	_visibility_,
+	_box_sizing_,
+	_z_index_,
+	_float_,
+	_clear_,
+	_text_indent_,
+	_left_,
+	_right_,
+	_top_,
+	_bottom_,
+	_cursor_,
+	_content_,
+	_border_collapse_,
+	_text_transform_,
+
+	_flex_,
+	_flex_flow_,
+	_flex_direction_,
+	_flex_wrap_,
+	_justify_content_,
+	_align_items_,
+	_align_content_,
+	_align_self_,
+	_flex_grow_,
+	_flex_shrink_,
+	_flex_basis_,
+);
+#undef STRING_ID
+extern const string_id empty_id; // _id("")
+extern const string_id star_id; // _id("*")
+
+string_id _id(const string& str);
+const string& _s(string_id id);
+
+} // namespace litehtml
+
+#endif  // LH_STRING_ID_H
diff --git a/src/plugins/litehtml_viewer/litehtml/strtod.cpp b/src/plugins/litehtml_viewer/litehtml/strtod.cpp
new file mode 100644
index 000000000..22392c494
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/strtod.cpp
@@ -0,0 +1,275 @@
+/* 
+ * strtod.c --
+ *
+ *	Source code for the "strtod" library procedure.
+ *
+ * Copyright (c) 1988-1993 The Regents of the University of California.
+ * Copyright (c) 1994 Sun Microsystems, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies.  The University of California
+ * makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ *
+ * RCS: @(#) $Id$
+ */
+
+#include "html.h"
+#include <cstdlib>
+#include <cctype>
+#include <cerrno>
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+#ifndef NULL
+#define NULL 0
+#endif
+
+static int maxExponent = 511;	/* Largest possible base 10 exponent.  Any
+				 * exponent larger than this will already
+				 * produce underflow or overflow, so there's
+				 * no need to worry about additional digits.
+				 */
+static double powersOf10[] = {	/* Table giving binary powers of 10.  Entry */
+    10.,			/* is 10^2^i.  Used to convert decimal */
+    100.,			/* exponents into floating-point numbers. */
+    1.0e4,
+    1.0e8,
+    1.0e16,
+    1.0e32,
+    1.0e64,
+    1.0e128,
+    1.0e256
+};
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * strtod --
+ *
+ *	This procedure converts a floating-point number from an ASCII
+ *	decimal representation to internal double-precision format.
+ *
+ * Results:
+ *	The return value is the double-precision floating-point
+ *	representation of the characters in string.  If endPtr isn't
+ *	NULL, then *endPtr is filled in with the address of the
+ *	next character after the last one that was part of the
+ *	floating-point number.
+ *
+ * Side effects:
+ *	None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+double litehtml::t_strtod(const char* string, char** endPtr)
+{
+    int sign, expSign = FALSE;
+    double fraction, dblExp, *d;
+    const char *p;
+    int c;
+    int exp = 0;		/* Exponent read from "EX" field. */
+    int fracExp = 0;		/* Exponent that derives from the fractional
+				 * part.  Under normal circumstatnces, it is
+				 * the negative of the number of digits in F.
+				 * However, if I is very long, the last digits
+				 * of I get dropped (otherwise a long I with a
+				 * large negative exponent could cause an
+				 * unnecessary overflow on I alone).  In this
+				 * case, fracExp is incremented one for each
+				 * dropped digit. */
+    int mantSize;		/* Number of digits in mantissa. */
+    int decPt;			/* Number of mantissa digits BEFORE decimal
+				 * point. */
+    const char *pExp;		/* Temporarily holds location of exponent
+				 * in string. */
+
+    /*
+     * Strip off leading blanks and check for a sign.
+     */
+
+    p = string;
+    while (isspace(*p))
+    {
+	    p += 1;
+    }
+    if (*p == '-')
+    {
+	    sign = TRUE;
+	    p += 1;
+    } else
+    {
+	    if (*p == '+')
+        {
+	        p += 1;
+	    }
+	    sign = FALSE;
+    }
+
+    /*
+     * Count the number of digits in the mantissa (including the decimal
+     * point), and also locate the decimal point.
+     */
+
+    decPt = -1;
+    for (mantSize = 0; ; mantSize += 1)
+    {
+        c = *p;
+        if (!t_isdigit(c))
+        {
+            if ((c != '.') || (decPt >= 0))
+            {
+                break;
+            }
+            decPt = mantSize;
+	    }
+	    p += 1;
+    }
+
+    /*
+     * Now suck up the digits in the mantissa.  Use two integers to
+     * collect 9 digits each (this is faster than using floating-point).
+     * If the mantissa has more than 18 digits, ignore the extras, since
+     * they can't affect the value anyway.
+     */
+    
+    pExp  = p;
+    p -= mantSize;
+    if (decPt < 0)
+    {
+	    decPt = mantSize;
+    } else
+    {
+	    mantSize -= 1;			/* One of the digits was the point. */
+    }
+    if (mantSize > 18)
+    {
+	    fracExp = decPt - 18;
+	    mantSize = 18;
+    } else
+    {
+	    fracExp = decPt - mantSize;
+    }
+    if (mantSize == 0)
+    {
+	    fraction = 0.0;
+	    p = string;
+	    goto done;
+    } else
+    {
+	    int frac1, frac2;
+	    frac1 = 0;
+	    for ( ; mantSize > 9; mantSize -= 1)
+	    {
+	        c = *p;
+	        p += 1;
+	        if (c == '.')
+            {
+		        c = *p;
+		        p += 1;
+	        }
+	        frac1 = 10*frac1 + (c - '0');
+	    }
+	    frac2 = 0;
+	    for (; mantSize > 0; mantSize -= 1)
+	    {
+	        c = *p;
+	        p += 1;
+	        if (c == '.')
+            {
+		        c = *p;
+		        p += 1;
+	        }
+	        frac2 = 10*frac2 + (c - '0');
+	    }
+	    fraction = (1.0e9 * frac1) + frac2;
+    }
+
+    /*
+     * Skim off the exponent.
+     */
+
+    p = pExp;
+    if ((*p == 'E') || (*p == 'e'))
+    {
+	    p += 1;
+	    if (*p == '-')
+        {
+	        expSign = TRUE;
+	        p += 1;
+	    } else
+        {
+	        if (*p == '+')
+            {
+		        p += 1;
+	        }
+	        expSign = FALSE;
+	    }
+	    while (isdigit(*p))
+        {
+	        exp = exp * 10 + (*p - '0');
+	        p += 1;
+	    }
+    }
+    if (expSign)
+    {
+	    exp = fracExp - exp;
+    } else
+    {
+	    exp = fracExp + exp;
+    }
+
+    /*
+     * Generate a floating-point number that represents the exponent.
+     * Do this by processing the exponent one bit at a time to combine
+     * many powers of 2 of 10. Then combine the exponent with the
+     * fraction.
+     */
+    
+    if (exp < 0)
+    {
+	    expSign = TRUE;
+	    exp = -exp;
+    } else
+    {
+	    expSign = FALSE;
+    }
+    if (exp > maxExponent)
+    {
+	    exp = maxExponent;
+	    errno = ERANGE;
+    }
+    dblExp = 1.0;
+    for (d = powersOf10; exp != 0; exp >>= 1, d += 1)
+    {
+	    if (exp & 01)
+        {
+	        dblExp *= *d;
+	    }
+    }
+    if (expSign)
+    {
+	    fraction /= dblExp;
+    } else
+    {
+	    fraction *= dblExp;
+    }
+
+done:
+    if (endPtr != nullptr)
+    {
+	    *endPtr = (char *) p;
+    }
+
+    if (sign)
+    {
+	    return -fraction;
+    }
+    return fraction;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/style.cpp b/src/plugins/litehtml_viewer/litehtml/style.cpp
index 2a7c8b9de..ca6b18f06 100644
--- a/src/plugins/litehtml_viewer/litehtml/style.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/style.cpp
@@ -1,48 +1,69 @@
 #include "html.h"
 #include "style.h"
-#include <functional>
-#include <algorithm>
-#ifndef WINCE
-#include <locale>
-#endif
 
-litehtml::string_map litehtml::style::m_valid_values =
+namespace litehtml
 {
-	{ _t("white-space"), white_space_strings }
-};
 
-litehtml::style::style()
+std::map<string_id, string> style::m_valid_values =
 {
-}
+	{ _display_, style_display_strings },
+	{ _visibility_, visibility_strings },
+	{ _position_, element_position_strings },
+	{ _float_, element_float_strings },
+	{ _clear_, element_clear_strings },
+	{ _overflow_, overflow_strings },
+	{ _box_sizing_, box_sizing_strings },
 
-litehtml::style::style( const style& val )
-{
-	m_properties = val.m_properties;
-}
+	{ _text_align_, text_align_strings },
+	{ _vertical_align_, vertical_align_strings },
+	{ _text_transform_, text_transform_strings },
+	{ _white_space_, white_space_strings },
 
-litehtml::style::~style()
-{
+	{ _font_style_, font_style_strings },
+	{ _font_variant_, font_variant_strings },
+	{ _font_weight_, font_weight_strings },
 
-}
+	{ _list_style_type_, list_style_type_strings },
+	{ _list_style_position_, list_style_position_strings },
 
-void litehtml::style::parse( const tchar_t* txt, const tchar_t* baseurl )
+	{ _border_left_style_, border_style_strings },
+	{ _border_right_style_, border_style_strings },
+	{ _border_top_style_, border_style_strings },
+	{ _border_bottom_style_, border_style_strings },
+	{ _border_collapse_, border_collapse_strings },
+
+	// these 4 properties are comma-separated lists of keywords, see parse_keyword_comma_list
+	{ _background_attachment_, background_attachment_strings },
+	{ _background_repeat_, background_repeat_strings },
+	{ _background_clip_, background_box_strings },
+	{ _background_origin_, background_box_strings },
+
+	{ _flex_direction_, flex_direction_strings },
+	{ _flex_wrap_, flex_wrap_strings },
+	{ _justify_content_, flex_justify_content_strings },
+	{ _align_items_, flex_align_items_strings },
+	{ _align_content_, flex_align_content_strings },
+	{ _align_self_, flex_align_self_strings },
+};
+
+void style::parse(const string& txt, const string& baseurl, document_container* container)
 {
-	std::vector<tstring> properties;
-	split_string(txt, properties, _t(";"), _t(""), _t("\"'"));
+	std::vector<string> properties;
+	split_string(txt, properties, ";", "", "\"'");
 
-	for(std::vector<tstring>::const_iterator i = properties.begin(); i != properties.end(); i++)
+	for(const auto & property : properties)
 	{
-		parse_property(*i, baseurl);
+		parse_property(property, baseurl, container);
 	}
 }
 
-void litehtml::style::parse_property( const tstring& txt, const tchar_t* baseurl )
+void style::parse_property(const string& txt, const string& baseurl, document_container* container)
 {
-	tstring::size_type pos = txt.find_first_of(_t(":"));
-	if(pos != tstring::npos)
+	string::size_type pos = txt.find_first_of(':');
+	if(pos != string::npos)
 	{
-		tstring name = txt.substr(0, pos);
-		tstring val	= txt.substr(pos + 1);
+		string name = txt.substr(0, pos);
+		string val	= txt.substr(pos + 1);
 
 		trim(name); lcase(name);
 		trim(val);
@@ -50,594 +71,1028 @@ void litehtml::style::parse_property( const tstring& txt, const tchar_t* baseurl
 		if(!name.empty() && !val.empty())
 		{
 			string_vector vals;
-			split_string(val, vals, _t("!"));
+			split_string(val, vals, "!");
 			if(vals.size() == 1)
 			{
-				add_property(name.c_str(), val.c_str(), baseurl, false);
+				add_property(_id(name), val, baseurl, false, container);
 			} else if(vals.size() > 1)
 			{
 				trim(vals[0]);
 				lcase(vals[1]);
-				add_property(name.c_str(), vals[0].c_str(), baseurl, vals[1] == _t("important"));
+				add_property(_id(name), vals[0], baseurl, vals[1] == "important", container);
 			}
 		}
 	}
 }
 
-void litehtml::style::combine( const litehtml::style& src )
+void style::add_property(string_id name, const string& val, const string& baseurl, bool important, document_container* container)
 {
-	for(props_map::const_iterator i = src.m_properties.begin(); i != src.m_properties.end(); i++)
-	{
-		add_parsed_property(i->first.c_str(), i->second.m_value.c_str(), i->second.m_important);
-	}
-}
+	if (val.find("var(") != -1) return add_parsed_property(name, property_value(val, important, prop_type_var));
+	if (val == "inherit" && name != _font_)       return add_parsed_property(name, property_value(important, prop_type_inherit));
 
-void litehtml::style::add_property( const tchar_t* name, const tchar_t* val, const tchar_t* baseurl, bool important )
-{
-	if(!name || !val)
-	{
-		return;
-	}
+	int idx;
+	string url;
+	css_length len[4], length;
 
-	// Add baseurl for background image 
-	if(	!t_strcmp(name, _t("background-image")))
+	switch (name)
 	{
-		add_parsed_property(name, val, important);
-		if(baseurl)
+	// keyword-only properties
+	case _display_:
+	case _visibility_:
+	case _position_:
+	case _float_:
+	case _clear_:
+	case _box_sizing_:
+	case _overflow_:
+
+	case _text_align_:
+	case _vertical_align_:
+	case _text_transform_:
+	case _white_space_:
+
+	case _font_style_:
+	case _font_variant_:
+	case _font_weight_:
+
+	case _list_style_type_:
+	case _list_style_position_:
+
+	case _border_top_style_:
+	case _border_bottom_style_:
+	case _border_left_style_:
+	case _border_right_style_:
+	case _border_collapse_:
+
+	case _flex_direction_:
+	case _flex_wrap_:
+	case _justify_content_:
+	case _align_items_:
+	case _align_content_:
+	case _align_self_:
+
+		idx = value_index(val, m_valid_values[name]);
+		if (idx >= 0)
 		{
-			add_parsed_property(_t("background-image-baseurl"), baseurl, important);
+			add_parsed_property(name, property_value(idx, important));
 		}
-	} else
+		break;
+
+	// <length>
+	case _text_indent_:
+	case _padding_left_:
+	case _padding_right_:
+	case _padding_top_:
+	case _padding_bottom_:
+		length.fromString(val);
+		add_parsed_property(name, property_value(length, important));
+		break;
+	
+	// <length> | auto
+	case _left_:
+	case _right_:
+	case _top_:
+	case _bottom_:
+	case _z_index_: // <integer> | auto
+	case _width_:
+	case _height_:
+	case _min_width_:
+	case _min_height_:
+	case _margin_left_:
+	case _margin_right_:
+	case _margin_top_:
+	case _margin_bottom_:
+		length.fromString(val, "auto", -1);
+		add_parsed_property(name, property_value(length, important));
+		break;
+
+	// <length> | none
+	case _max_width_:
+	case _max_height_:
+		length.fromString(val, "none", -1);
+		add_parsed_property(name, property_value(length, important));
+		break;
+	
+	case _line_height_:
+		length.fromString(val, "normal", -1);
+		add_parsed_property(name, property_value(length, important));
+		break;
+
+	case _font_size_:
+		length.fromString(val, font_size_strings, -1);
+		add_parsed_property(name, property_value(length, important));
+		break;
+
+	// Parse background shorthand properties 
+	case _background_:
+		parse_background(val, baseurl, important, container);
+		break;
+
+	case _background_image_:
+		parse_background_image(val, baseurl, important);
+		break;
+
+	case _background_attachment_:
+	case _background_repeat_:
+	case _background_clip_:
+	case _background_origin_:
+		parse_keyword_comma_list(name, val, important);
+		break;
+
+	case _background_position_:
+		parse_background_position(val, important);
+		break;
+
+	case _background_size_:
+		parse_background_size(val, important);
+		break;
 
 	// Parse border spacing properties 
-	if(	!t_strcmp(name, _t("border-spacing")))
-	{
-		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() == 1)
-		{
-			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_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
+	case _border_spacing_:
+		parse_two_lengths(val, len);
+		add_parsed_property(__litehtml_border_spacing_x_, property_value(len[0], important));
+		add_parsed_property(__litehtml_border_spacing_y_, property_value(len[1], important));
+		break;
 
 	// Parse borders shorthand properties 
-
-	if(	!t_strcmp(name, _t("border")))
+	case _border_:
 	{
 		string_vector tokens;
-		split_string(val, tokens, _t(" "), _t(""), _t("("));
-		int idx;
-		tstring str;
-		for(string_vector::const_iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+		split_string(val, tokens, " ", "", "(");
+		for (const auto& token : tokens)
 		{
-			idx = value_index(tok->c_str(), border_style_strings, -1);
-			if(idx >= 0)
+			int idx = value_index(token, border_style_strings);
+			if (idx >= 0)
 			{
-				add_property(_t("border-left-style"), tok->c_str(), baseurl, important);
-				add_property(_t("border-right-style"), tok->c_str(), baseurl, important);
-				add_property(_t("border-top-style"), tok->c_str(), baseurl, important);
-				add_property(_t("border-bottom-style"), tok->c_str(), baseurl, important);
-			} else
+				property_value style(idx, important);
+				add_parsed_property(_border_left_style_,	style);
+				add_parsed_property(_border_right_style_,	style);
+				add_parsed_property(_border_top_style_,		style);
+				add_parsed_property(_border_bottom_style_,	style);
+			}
+			else if (t_isdigit(token[0]) || token[0] == '.' ||
+				value_in_list(token, border_width_strings))
 			{
-				if (t_isdigit((*tok)[0]) || (*tok)[0] == _t('.') ||
-					value_in_list((*tok), _t("thin;medium;thick")))
-				{
-					add_property(_t("border-left-width"), tok->c_str(), baseurl, important);
-					add_property(_t("border-right-width"), tok->c_str(), baseurl, important);
-					add_property(_t("border-top-width"), tok->c_str(), baseurl, important);
-					add_property(_t("border-bottom-width"), tok->c_str(), baseurl, important);
-				} 
-				else
-				{
-					add_property(_t("border-left-color"), tok->c_str(), baseurl, important);
-					add_property(_t("border-right-color"), tok->c_str(), baseurl, important);
-					add_property(_t("border-top-color"), tok->c_str(), baseurl, important);
-					add_property(_t("border-bottom-color"), tok->c_str(), baseurl, important);
-				}
+				property_value width(parse_border_width(token), important);
+				add_parsed_property(_border_left_width_,	width);
+				add_parsed_property(_border_right_width_,	width);
+				add_parsed_property(_border_top_width_,		width);
+				add_parsed_property(_border_bottom_width_,	width);
+			}
+			else
+			{
+				web_color _color = web_color::from_string(token, container);
+				property_value color(_color, important);
+				add_parsed_property(_border_left_color_,	color);
+				add_parsed_property(_border_right_color_,	color);
+				add_parsed_property(_border_top_color_,		color);
+				add_parsed_property(_border_bottom_color_,	color);
 			}
 		}
-	} else if(	!t_strcmp(name, _t("border-left"))	||
-		!t_strcmp(name, _t("border-right"))	||
-		!t_strcmp(name, _t("border-top"))	||
-		!t_strcmp(name, _t("border-bottom")) )
+		break;
+	}
+
+	case _border_left_:
+	case _border_right_:
+	case _border_top_:
+	case _border_bottom_:
 	{
 		string_vector tokens;
-		split_string(val, tokens, _t(" "), _t(""), _t("("));
-		int idx;
-		tstring str;
-		for(string_vector::const_iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+		split_string(val, tokens, " ", "", "(");
+		for (const auto& token : tokens)
 		{
-			idx = value_index(tok->c_str(), border_style_strings, -1);
-			if(idx >= 0)
+			int idx = value_index(token, border_style_strings);
+			if (idx >= 0)
 			{
-				str = name;
-				str += _t("-style");
-				add_property(str.c_str(), tok->c_str(), baseurl, important);
-			} else
+				add_parsed_property(_id(_s(name) + "-style"), property_value(idx, important));
+			}
+			else if (t_isdigit(token[0]) || token[0] == '.' ||
+				value_in_list(token, border_width_strings))
 			{
-				if(web_color::is_color(tok->c_str()))
-				{
-					str = name;
-					str += _t("-color");
-					add_property(str.c_str(), tok->c_str(), baseurl, important);
-				} else
-				{
-					str = name;
-					str += _t("-width");
-					add_property(str.c_str(), tok->c_str(), baseurl, important);
-				}
+				property_value width(parse_border_width(token), important);
+				add_parsed_property(_id(_s(name) + "-width"), width);
+			}
+			else
+			{
+				web_color color = web_color::from_string(token, container);
+				add_parsed_property(_id(_s(name) + "-color"), property_value(color, important));
 			}
 		}
-	} else 
+		break;
+	}
 
-	// Parse border radius shorthand properties 
-	if(!t_strcmp(name, _t("border-bottom-left-radius")))
+	// Parse border-width/style/color shorthand properties 
+	case _border_width_:
+	case _border_style_:
+	case _border_color_:
 	{
-		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() >= 2)
-		{
-			add_property(_t("border-bottom-left-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-y"), tokens[1].c_str(), baseurl, important);
-		} else if(tokens.size() == 1)
-		{
-			add_property(_t("border-bottom-left-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-y"), tokens[0].c_str(), baseurl, important);
-		}
+		string prop = name == _border_width_ ? "-width" : name == _border_style_ ? "-style" : "-color";
 
-	} else if(!t_strcmp(name, _t("border-bottom-right-radius")))
-	{
 		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() >= 2)
+		split_string(val, tokens, " ");
+		if (tokens.size() == 4)
 		{
-			add_property(_t("border-bottom-right-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-y"), tokens[1].c_str(), baseurl, important);
-		} else if(tokens.size() == 1)
+			add_property(_id("border-top"    + prop), tokens[0], baseurl, important, container);
+			add_property(_id("border-right"  + prop), tokens[1], baseurl, important, container);
+			add_property(_id("border-bottom" + prop), tokens[2], baseurl, important, container);
+			add_property(_id("border-left"   + prop), tokens[3], baseurl, important, container);
+		}
+		else if (tokens.size() == 3)
 		{
-			add_property(_t("border-bottom-right-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-y"), tokens[0].c_str(), baseurl, important);
+			add_property(_id("border-top"    + prop), tokens[0], baseurl, important, container);
+			add_property(_id("border-right"  + prop), tokens[1], baseurl, important, container);
+			add_property(_id("border-left"   + prop), tokens[1], baseurl, important, container);
+			add_property(_id("border-bottom" + prop), tokens[2], baseurl, important, container);
 		}
-
-	} else if(!t_strcmp(name, _t("border-top-right-radius")))
-	{
-		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() >= 2)
+		else if (tokens.size() == 2)
 		{
-			add_property(_t("border-top-right-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-y"), tokens[1].c_str(), baseurl, important);
-		} else if(tokens.size() == 1)
+			add_property(_id("border-top"    + prop), tokens[0], baseurl, important, container);
+			add_property(_id("border-bottom" + prop), tokens[0], baseurl, important, container);
+			add_property(_id("border-right"  + prop), tokens[1], baseurl, important, container);
+			add_property(_id("border-left"   + prop), tokens[1], baseurl, important, container);
+		}
+		else if (tokens.size() == 1)
 		{
-			add_property(_t("border-top-right-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-y"), tokens[0].c_str(), baseurl, important);
+			add_property(_id("border-top"    + prop), tokens[0], baseurl, important, container);
+			add_property(_id("border-bottom" + prop), tokens[0], baseurl, important, container);
+			add_property(_id("border-right"  + prop), tokens[0], baseurl, important, container);
+			add_property(_id("border-left"   + prop), tokens[0], baseurl, important, container);
 		}
+		break;
+	}
+
+	case _border_top_width_:
+	case _border_bottom_width_:
+	case _border_left_width_:
+	case _border_right_width_:
+		length = parse_border_width(val);
+		add_parsed_property(name, property_value(length, important));
+		break;
 
-	} else if(!t_strcmp(name, _t("border-top-left-radius")))
+	case _color_:
+	case _background_color_:
+	case _border_top_color_:
+	case _border_bottom_color_:
+	case _border_left_color_:
+	case _border_right_color_:
 	{
-		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() >= 2)
-		{
-			add_property(_t("border-top-left-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-left-radius-y"), tokens[1].c_str(), baseurl, important);
-		} else if(tokens.size() == 1)
-		{
-			add_property(_t("border-top-left-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-left-radius-y"), tokens[0].c_str(), baseurl, important);
-		}
+		web_color color = web_color::from_string(val, container);
+		add_parsed_property(name, property_value(color, important));
+		break;
+	}
 
-	} else 
+	// Parse border radius shorthand properties 
+	case _border_bottom_left_radius_:
+	case _border_bottom_right_radius_:
+	case _border_top_right_radius_:
+	case _border_top_left_radius_:
+		parse_two_lengths(val, len);
+		add_parsed_property(_id(_s(name) + "-x"), property_value(len[0], important));
+		add_parsed_property(_id(_s(name) + "-y"), property_value(len[1], important));
+		break;
 
 	// Parse border-radius shorthand properties 
-	if(!t_strcmp(name, _t("border-radius")))
+	case _border_radius_:
 	{
 		string_vector tokens;
-		split_string(val, tokens, _t("/"));
-		if(tokens.size() == 1)
+		split_string(val, tokens, "/");
+		if (tokens.size() == 1)
 		{
-			add_property(_t("border-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-radius-y"), tokens[0].c_str(), baseurl, important);
-		} else if(tokens.size() >= 2)
+			add_property(_border_radius_x_, tokens[0], baseurl, important, container);
+			add_property(_border_radius_y_, tokens[0], baseurl, important, container);
+		}
+		else if (tokens.size() >= 2)
 		{
-			add_property(_t("border-radius-x"), tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-radius-y"), tokens[1].c_str(), baseurl, important);
+			add_property(_border_radius_x_, tokens[0], baseurl, important, container);
+			add_property(_border_radius_y_, tokens[1], baseurl, important, container);
 		}
-	} else if(!t_strcmp(name, _t("border-radius-x")))
-	{
-		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() == 1)
-		{
-			add_property(_t("border-top-left-radius-x"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-x"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-x"),	tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-x"),	tokens[0].c_str(), baseurl, important);
-		} else if(tokens.size() == 2)
-		{
-			add_property(_t("border-top-left-radius-x"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-x"),		tokens[1].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-x"),	tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-x"),	tokens[1].c_str(), baseurl, important);
-		} else if(tokens.size() == 3)
-		{
-			add_property(_t("border-top-left-radius-x"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-x"),		tokens[1].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-x"),	tokens[2].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-x"),	tokens[1].c_str(), baseurl, important);
-		} else if(tokens.size() == 4)
-		{
-			add_property(_t("border-top-left-radius-x"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-x"),		tokens[1].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-x"),	tokens[2].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-x"),	tokens[3].c_str(), baseurl, important);
-		}
-	} else if(!t_strcmp(name, _t("border-radius-y")))
+		break;
+	}
+	case _border_radius_x_:
+	case _border_radius_y_:
 	{
-		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() == 1)
-		{
-			add_property(_t("border-top-left-radius-y"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-y"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-y"),	tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-y"),	tokens[0].c_str(), baseurl, important);
-		} else if(tokens.size() == 2)
+		string_id top_left, top_right, bottom_right, bottom_left;
+		if (name == _border_radius_x_)
 		{
-			add_property(_t("border-top-left-radius-y"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-y"),		tokens[1].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-y"),	tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-y"),	tokens[1].c_str(), baseurl, important);
-		} else if(tokens.size() == 3)
+			top_left		= _border_top_left_radius_x_;
+			top_right		= _border_top_right_radius_x_;
+			bottom_right	= _border_bottom_right_radius_x_;
+			bottom_left		= _border_bottom_left_radius_x_;
+		}
+		else
 		{
-			add_property(_t("border-top-left-radius-y"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-y"),		tokens[1].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-y"),	tokens[2].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-y"),	tokens[1].c_str(), baseurl, important);
-		} else if(tokens.size() == 4)
+			top_left		= _border_top_left_radius_y_;
+			top_right		= _border_top_right_radius_y_;
+			bottom_right	= _border_bottom_right_radius_y_;
+			bottom_left		= _border_bottom_left_radius_y_;
+		}
+
+		switch (parse_four_lengths(val, len))
 		{
-			add_property(_t("border-top-left-radius-y"),		tokens[0].c_str(), baseurl, important);
-			add_property(_t("border-top-right-radius-y"),		tokens[1].c_str(), baseurl, important);
-			add_property(_t("border-bottom-right-radius-y"),	tokens[2].c_str(), baseurl, important);
-			add_property(_t("border-bottom-left-radius-y"),	tokens[3].c_str(), baseurl, important);
+		case 1:
+			add_parsed_property(top_left,		property_value(len[0], important));
+			add_parsed_property(top_right,		property_value(len[0], important));
+			add_parsed_property(bottom_right,	property_value(len[0], important));
+			add_parsed_property(bottom_left,	property_value(len[0], important));
+			break;
+		case 2:
+			add_parsed_property(top_left,		property_value(len[0], important));
+			add_parsed_property(top_right,		property_value(len[1], important));
+			add_parsed_property(bottom_right,	property_value(len[0], important));
+			add_parsed_property(bottom_left,	property_value(len[1], important));
+			break;
+		case 3:
+			add_parsed_property(top_left,		property_value(len[0], important));
+			add_parsed_property(top_right,		property_value(len[1], important));
+			add_parsed_property(bottom_right,	property_value(len[2], important));
+			add_parsed_property(bottom_left,	property_value(len[1], important));
+			break;
+		case 4:
+			add_parsed_property(top_left,		property_value(len[0], important));
+			add_parsed_property(top_right,		property_value(len[1], important));
+			add_parsed_property(bottom_right,	property_value(len[2], important));
+			add_parsed_property(bottom_left,	property_value(len[3], important));
+			break;
 		}
+		break;
 	}
-	else
 
 	// Parse list-style shorthand properties 
-	if(!t_strcmp(name, _t("list-style")))
+	case _list_style_:
 	{
-		add_parsed_property(_t("list-style-type"),			_t("disc"),		important);
-		add_parsed_property(_t("list-style-position"),		_t("outside"),	important);
-		add_parsed_property(_t("list-style-image"),			_t(""),			important);
-		add_parsed_property(_t("list-style-image-baseurl"),	_t(""),			important);
+		add_parsed_property(_list_style_type_,			property_value(list_style_type_disc,		important));
+		add_parsed_property(_list_style_position_,		property_value(list_style_position_outside,	important));
+		add_parsed_property(_list_style_image_,			property_value("",							important));
+		add_parsed_property(_list_style_image_baseurl_,	property_value("",							important));
 
 		string_vector tokens;
-		split_string(val, tokens, _t(" "), _t(""), _t("("));
-		for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+		split_string(val, tokens, " ", "", "(");
+		for (const auto& token : tokens)
 		{
-			int idx = value_index(tok->c_str(), list_style_type_strings, -1);
-			if(idx >= 0)
+			int idx = value_index(token, list_style_type_strings);
+			if (idx >= 0)
 			{
-				add_parsed_property(_t("list-style-type"), *tok, important);
-			} else
+				add_parsed_property(_list_style_type_, property_value(idx, important));
+			}
+			else
 			{
-				idx = value_index(tok->c_str(), list_style_position_strings, -1);
-				if(idx >= 0)
+				idx = value_index(token, list_style_position_strings);
+				if (idx >= 0)
 				{
-					add_parsed_property(_t("list-style-position"), *tok, important);
-				} else if(!t_strncmp(val, _t("url"), 3))
+					add_parsed_property(_list_style_position_, property_value(idx, important));
+				}
+				else if (!strncmp(token.c_str(), "url", 3))
 				{
-					add_parsed_property(_t("list-style-image"), *tok, important);
-					if(baseurl)
-					{
-						add_parsed_property(_t("list-style-image-baseurl"), baseurl, important);
-					}
+					css::parse_css_url(token, url);
+					add_parsed_property(_list_style_image_,			property_value(url,     important));
+					add_parsed_property(_list_style_image_baseurl_, property_value(baseurl, important));
 				}
 			}
 		}
-	} else 
+		break;
+	}
 
-	// Add baseurl for background image 
-	if(	!t_strcmp(name, _t("list-style-image")))
+	case _list_style_image_:
+		css::parse_css_url(val, url);
+		add_parsed_property(_list_style_image_,			property_value(url,     important));
+		add_parsed_property(_list_style_image_baseurl_, property_value(baseurl, important));
+		break;
+
+	// Parse margin and padding shorthand properties 
+	case _margin_:
+	case _padding_:
 	{
-		add_parsed_property(name, val, important);
-		if(baseurl)
+		switch (parse_four_lengths(val, len))
 		{
-			add_parsed_property(_t("list-style-image-baseurl"), baseurl, important);
+		case 4:
+			add_parsed_property(_id(_s(name) + "-top"),		property_value(len[0], important));
+			add_parsed_property(_id(_s(name) + "-right"),	property_value(len[1], important));
+			add_parsed_property(_id(_s(name) + "-bottom"),	property_value(len[2], important));
+			add_parsed_property(_id(_s(name) + "-left"),	property_value(len[3], important));
+			break;
+		case 3:
+			add_parsed_property(_id(_s(name) + "-top"),		property_value(len[0], important));
+			add_parsed_property(_id(_s(name) + "-right"),	property_value(len[1], important));
+			add_parsed_property(_id(_s(name) + "-left"),	property_value(len[1], important));
+			add_parsed_property(_id(_s(name) + "-bottom"),	property_value(len[2], important));
+			break;
+		case 2:
+			add_parsed_property(_id(_s(name) + "-top"),		property_value(len[0], important));
+			add_parsed_property(_id(_s(name) + "-bottom"),	property_value(len[0], important));
+			add_parsed_property(_id(_s(name) + "-right"),	property_value(len[1], important));
+			add_parsed_property(_id(_s(name) + "-left"),	property_value(len[1], important));
+			break;
+		case 1:
+			add_parsed_property(_id(_s(name) + "-top"),		property_value(len[0], important));
+			add_parsed_property(_id(_s(name) + "-bottom"),	property_value(len[0], important));
+			add_parsed_property(_id(_s(name) + "-right"),	property_value(len[0], important));
+			add_parsed_property(_id(_s(name) + "-left"),	property_value(len[0], important));
+			break;
 		}
-	} else
-		
-	// Parse background shorthand properties 
-	if(!t_strcmp(name, _t("background")))
-	{
-		parse_short_background(val, baseurl, important);
+		break;
+	}
 
-	} else 
-		
-	// Parse margin and padding shorthand properties 
-	if(!t_strcmp(name, _t("margin")) || !t_strcmp(name, _t("padding")))
+	// Parse font shorthand properties 
+	case _font_:
+		parse_font(val, important);
+		break;
+
+	// Parse flex-flow shorthand properties
+	case _flex_flow_:
 	{
 		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() >= 4)
-		{
-			add_parsed_property(tstring(name) + _t("-top"),		tokens[0], important);
-			add_parsed_property(tstring(name) + _t("-right"),		tokens[1], important);
-			add_parsed_property(tstring(name) + _t("-bottom"),	tokens[2], important);
-			add_parsed_property(tstring(name) + _t("-left"),		tokens[3], important);
-		} else if(tokens.size() == 3)
-		{
-			add_parsed_property(tstring(name) + _t("-top"),		tokens[0], important);
-			add_parsed_property(tstring(name) + _t("-right"),		tokens[1], important);
-			add_parsed_property(tstring(name) + _t("-left"),		tokens[1], important);
-			add_parsed_property(tstring(name) + _t("-bottom"),	tokens[2], important);
-		} else if(tokens.size() == 2)
-		{
-			add_parsed_property(tstring(name) + _t("-top"),		tokens[0], important);
-			add_parsed_property(tstring(name) + _t("-bottom"),	tokens[0], important);
-			add_parsed_property(tstring(name) + _t("-right"),		tokens[1], important);
-			add_parsed_property(tstring(name) + _t("-left"),		tokens[1], important);
-		} else if(tokens.size() == 1)
-		{
-			add_parsed_property(tstring(name) + _t("-top"),		tokens[0], important);
-			add_parsed_property(tstring(name) + _t("-bottom"),	tokens[0], important);
-			add_parsed_property(tstring(name) + _t("-right"),		tokens[0], important);
-			add_parsed_property(tstring(name) + _t("-left"),		tokens[0], important);
-		}
-	} else 
-		
-		
-	// Parse border-* shorthand properties 
-	if(	!t_strcmp(name, _t("border-left")) || 
-		!t_strcmp(name, _t("border-right")) ||
-		!t_strcmp(name, _t("border-top"))  || 
-		!t_strcmp(name, _t("border-bottom")))
-	{
-		parse_short_border(name, val, important);
-	} else 
-		
-	// Parse border-width/style/color shorthand properties 
-	if(	!t_strcmp(name, _t("border-width")) ||
-		!t_strcmp(name, _t("border-style"))  ||
-		!t_strcmp(name, _t("border-color")) )
+		split_string(val, tokens, " ");
+		for (const auto& tok : tokens)
+		{
+			int idx;
+			if ((idx = value_index(tok, flex_direction_strings)) >= 0)
+			{
+				add_parsed_property(_flex_direction_, property_value(idx, important));
+			}
+			else if ((idx = value_index(tok, flex_wrap_strings)) >= 0)
+			{
+				add_parsed_property(_flex_wrap_, property_value(idx, important));
+			}
+		}
+		break;
+	}
+
+	// Parse flex shorthand properties
+	case _flex_:
+		parse_flex(val, important);
+		break;
+
+	case _flex_grow_:
+	case _flex_shrink_:
+		add_parsed_property(name, property_value(t_strtof(val), important));
+		break;
+
+	case _flex_basis_:
+		length.fromString(val, flex_basis_strings, -1);
+		add_parsed_property(_flex_basis_, property_value(length, important));
+		break;
+
+	default:
+		add_parsed_property(name, property_value(val, important));
+	}
+}
+
+css_length style::parse_border_width(const string& str)
+{
+	css_length len;
+	if (t_isdigit(str[0]) || str[0] == '.')
 	{
-		string_vector nametokens;
-		split_string(name, nametokens, _t("-"));
+		len.fromString(str);
+	}
+	else
+	{
+		int idx = value_index(str, border_width_strings);
+		if (idx >= 0)
+		{
+			len.set_value(border_width_values[idx], css_units_px);
+		}
+	}
+	return len;
+}
 
-		string_vector tokens;
-		split_string(val, tokens, _t(" "));
-		if(tokens.size() >= 4)
-		{
-			add_parsed_property(nametokens[0] + _t("-top-")		+ nametokens[1],	tokens[0], important);
-			add_parsed_property(nametokens[0] + _t("-right-")	+ nametokens[1],	tokens[1], important);
-			add_parsed_property(nametokens[0] + _t("-bottom-")	+ nametokens[1],	tokens[2], important);
-			add_parsed_property(nametokens[0] + _t("-left-")	+ nametokens[1],	tokens[3], important);
-		} else if(tokens.size() == 3)
-		{
-			add_parsed_property(nametokens[0] + _t("-top-")		+ nametokens[1],	tokens[0], important);
-			add_parsed_property(nametokens[0] + _t("-right-")	+ nametokens[1],	tokens[1], important);
-			add_parsed_property(nametokens[0] + _t("-left-")	+ nametokens[1],	tokens[1], important);
-			add_parsed_property(nametokens[0] + _t("-bottom-")	+ nametokens[1],	tokens[2], important);
-		} else if(tokens.size() == 2)
-		{
-			add_parsed_property(nametokens[0] + _t("-top-")		+ nametokens[1],	tokens[0], important);
-			add_parsed_property(nametokens[0] + _t("-bottom-")	+ nametokens[1],	tokens[0], important);
-			add_parsed_property(nametokens[0] + _t("-right-")	+ nametokens[1],	tokens[1], important);
-			add_parsed_property(nametokens[0] + _t("-left-")	+ nametokens[1],	tokens[1], important);
-		} else if(tokens.size() == 1)
-		{
-			add_parsed_property(nametokens[0] + _t("-top-")		+ nametokens[1],	tokens[0], important);
-			add_parsed_property(nametokens[0] + _t("-bottom-")	+ nametokens[1],	tokens[0], important);
-			add_parsed_property(nametokens[0] + _t("-right-")	+ nametokens[1],	tokens[0], important);
-			add_parsed_property(nametokens[0] + _t("-left-")	+ nametokens[1],	tokens[0], important);
-		}
-	} else 
-		
-	// Parse font shorthand properties 
-	if(!t_strcmp(name, _t("font")))
+void style::parse_two_lengths(const string& str, css_length len[2])
+{
+	string_vector tokens;
+	split_string(str, tokens, " ");
+	if (tokens.size() == 1)
 	{
-		parse_short_font(val, important);
-	} else 
+		css_length length;
+		length.fromString(tokens[0]);
+		len[0] = len[1] = length;
+	}
+	else if (tokens.size() == 2)
 	{
-		add_parsed_property(name, val, important);
+		len[0].fromString(tokens[0]);
+		len[1].fromString(tokens[1]);
 	}
 }
 
-void litehtml::style::parse_short_border( const tstring& prefix, const tstring& val, bool important )
+int style::parse_four_lengths(const string& str, css_length len[4])
 {
 	string_vector tokens;
-	split_string(val, tokens, _t(" "), _t(""), _t("("));
-	if(tokens.size() >= 3)
+	split_string(str, tokens, " ");
+	if (tokens.size() == 0 || tokens.size() > 4)
 	{
-		add_parsed_property(prefix + _t("-width"),	tokens[0], important);
-		add_parsed_property(prefix + _t("-style"),	tokens[1], important);
-		add_parsed_property(prefix + _t("-color"),	tokens[2], important);
-	} else if(tokens.size() == 2)
+		return 0;
+	}
+	for (size_t i = 0; i < tokens.size(); i++)
 	{
-		if(iswdigit(tokens[0][0]) || value_index(val.c_str(), border_width_strings) >= 0)
-		{
-			add_parsed_property(prefix + _t("-width"),	tokens[0], important);
-			add_parsed_property(prefix + _t("-style"),	tokens[1], important);
-		} else
-		{
-			add_parsed_property(prefix + _t("-style"),	tokens[0], important);
-			add_parsed_property(prefix + _t("-color"),	tokens[1], important);
-		}
+		len[i].fromString(tokens[i]);
 	}
+	return (int)tokens.size();
 }
 
-void litehtml::style::parse_short_background( const tstring& val, const tchar_t* baseurl, bool important )
+void style::parse_background(const string& val, const string& baseurl, bool important, document_container* container)
 {
-	add_parsed_property(_t("background-color"),			_t("transparent"),	important);
-	add_parsed_property(_t("background-image"),			_t(""),				important);
-	add_parsed_property(_t("background-image-baseurl"), _t(""),				important);
-	add_parsed_property(_t("background-repeat"),		_t("repeat"),		important);
-	add_parsed_property(_t("background-origin"),		_t("padding-box"),	important);
-	add_parsed_property(_t("background-clip"),			_t("border-box"),	important);
-	add_parsed_property(_t("background-attachment"),	_t("scroll"),		important);
+	string_vector tokens;
+	split_string(val, tokens, ",", "", "(");
+	if (tokens.empty()) return;
+
+	web_color color;
+	string_vector images; 
+	int_vector repeats, origins, clips, attachments;
+	length_vector x_positions, y_positions;
+	size_vector sizes;
 
-	if(val == _t("none"))
+	for (const auto& token : tokens)
 	{
-		return;
+		background bg;
+		if (!parse_one_background(token, container, bg))
+			return;
+		
+		color = bg.m_color;
+		images.push_back(bg.m_image[0]);
+		repeats.push_back(bg.m_repeat[0]);
+		origins.push_back(bg.m_origin[0]);
+		clips.push_back(bg.m_clip[0]);
+		attachments.push_back(bg.m_attachment[0]);
+		x_positions.push_back(bg.m_position_x[0]);
+		y_positions.push_back(bg.m_position_y[0]);
+		sizes.push_back(bg.m_size[0]);
+	}
+
+	add_parsed_property(_background_color_,			property_value(color,		important));
+	add_parsed_property(_background_image_,			property_value(images,		important));
+	add_parsed_property(_background_image_baseurl_, property_value(baseurl,		important));
+	add_parsed_property(_background_repeat_,		property_value(repeats,		important));
+	add_parsed_property(_background_origin_,		property_value(origins,		important));
+	add_parsed_property(_background_clip_,			property_value(clips,		important));
+	add_parsed_property(_background_attachment_,	property_value(attachments, important));
+	add_parsed_property(_background_position_x_,	property_value(x_positions, important));
+	add_parsed_property(_background_position_y_,	property_value(y_positions, important));
+	add_parsed_property(_background_size_,			property_value(sizes,		important));
+}
+
+bool style::parse_one_background(const string& val, document_container* container, background& bg)
+{
+	bg.m_color = web_color::transparent;
+	bg.m_image = {""};
+	bg.m_repeat = { background_repeat_repeat };
+	bg.m_origin = { background_box_padding };
+	bg.m_clip = { background_box_border };
+	bg.m_attachment = { background_attachment_scroll };
+	bg.m_position_x = { css_length(0, css_units_percentage) };
+	bg.m_position_y = { css_length(0, css_units_percentage) };
+	bg.m_size = { css_size(css_length::predef_value(background_size_auto), css_length::predef_value(background_size_auto)) };
+
+	if(val == "none")
+	{
+		return true;
 	}
 
 	string_vector tokens;
-	split_string(val, tokens, _t(" "), _t(""), _t("("));
+	split_string(val, tokens, " \t\n\r", "", "(");
+
+	bool color_found = false;
+	bool image_found = false;
 	bool origin_found = false;
-	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+	bool clip_found = false;
+	bool repeat_found = false;
+	bool attachment_found = false;
+
+	string position;
+	for(const auto& token : tokens)
 	{
-		if(tok->substr(0, 3) == _t("url"))
+		int idx;
+		if(token.substr(0, 3) == "url")
 		{
-			add_parsed_property(_t("background-image"), *tok, important);
-			if(baseurl)
-			{
-				add_parsed_property(_t("background-image-baseurl"), baseurl, important);
-			}
-
-		} else if( value_in_list(tok->c_str(), background_repeat_strings) )
+			if (image_found) return false;
+			string url;
+			css::parse_css_url(token, url);
+			bg.m_image = { url };
+			image_found = true;
+		} else if( (idx = value_index(token, background_repeat_strings)) >= 0 )
 		{
-			add_parsed_property(_t("background-repeat"), *tok, important);
-		} else if( value_in_list(tok->c_str(), background_attachment_strings) )
+			if (repeat_found) return false;
+			bg.m_repeat = { idx };
+			repeat_found = true;
+		} else if( (idx = value_index(token, background_attachment_strings)) >= 0 )
 		{
-			add_parsed_property(_t("background-attachment"), *tok, important);
-		} else if( value_in_list(tok->c_str(), background_box_strings) )
+			if (attachment_found) return false;
+			bg.m_attachment = { idx };
+			attachment_found = true;
+		} else if( (idx = value_index(token, background_box_strings)) >= 0 )
 		{
 			if(!origin_found)
 			{
-				add_parsed_property(_t("background-origin"), *tok, important);
+				bg.m_origin = { idx };
 				origin_found = true;
 			} else
 			{
-				add_parsed_property(_t("background-clip"),*tok, important);
+				if (clip_found) return false;
+				bg.m_clip = { idx };
+				clip_found = true;
 			}
-		} else if(	value_in_list(tok->c_str(), _t("left;right;top;bottom;center")) ||
-					iswdigit((*tok)[0]) ||
-					(*tok)[0] == _t('-')	||
-					(*tok)[0] == _t('.')	||
-					(*tok)[0] == _t('+'))
+		} else if(	value_in_list(token, background_position_strings) ||
+					token.find('/') != -1 ||
+					t_isdigit(token[0]) ||
+					token[0] == '+'	||
+					token[0] == '-'	||
+					token[0] == '.' )
 		{
-			if(m_properties.find(_t("background-position")) != m_properties.end())
-			{
-				m_properties[_t("background-position")].m_value = m_properties[_t("background-position")].m_value + _t(" ") + *tok;
-			} else
-			{
-				add_parsed_property(_t("background-position"), *tok, important);
-			}
-		} else if (web_color::is_color(tok->c_str()))
+			position += " " + token;
+		} else if (web_color::is_color(token, container))
+		{
+			if (color_found) return false;
+			bg.m_color = web_color::from_string(token, container);
+			color_found = true;
+		}
+		else
 		{
-			add_parsed_property(_t("background-color"), *tok, important);
+			return false;
 		}
 	}
+	
+	if (position != "")
+	{
+		string_vector tokens;
+		split_string(position, tokens, "/");
+
+		if (tokens.size() > 2) return false;
+
+		if (tokens.size() == 2 && !parse_one_background_size(tokens[1], bg.m_size[0]))
+			return false;
+
+		if (tokens.size() > 0 && !parse_one_background_position(tokens[0], bg.m_position_x[0], bg.m_position_y[0]))
+			return false;
+	}
+	
+	return true;
+}
+
+void style::parse_background_image(const string& val, const string& baseurl, bool important)
+{
+	string_vector tokens;
+	split_string(val, tokens, ",", "", "(");
+	if (tokens.empty()) return;
+
+	string_vector images;
+
+	for (const auto& token : tokens)
+	{
+		string url;
+		css::parse_css_url(token, url);
+		images.push_back(url);
+	}
+
+	add_parsed_property(_background_image_,         property_value(images,  important));
+	add_parsed_property(_background_image_baseurl_, property_value(baseurl, important));
+}
+
+void style::parse_keyword_comma_list(string_id name, const string& val, bool important)
+{
+	string_vector tokens;
+	split_string(val, tokens, ",");
+	if (tokens.empty()) return;
+
+	int_vector vec;
+
+	for (auto& token : tokens)
+	{
+		trim(token);
+		int idx = value_index(token, m_valid_values[name]);
+		if (idx == -1) return;
+		vec.push_back(idx);
+	}
+
+	add_parsed_property(name, property_value(vec, important));
+}
+
+void style::parse_background_position(const string& val, bool important)
+{
+	string_vector tokens;
+	split_string(val, tokens, ",");
+	if (tokens.empty()) return;
+
+	length_vector x_positions, y_positions;
+
+	for (const auto& token : tokens)
+	{
+		css_length x, y;
+		if(!parse_one_background_position(token, x, y)) return;
+		x_positions.push_back(x);
+		y_positions.push_back(y);
+	}
+	
+	add_parsed_property(_background_position_x_, property_value(x_positions, important));
+	add_parsed_property(_background_position_y_, property_value(y_positions, important));
+}
+
+bool style::parse_one_background_position(const string& val, css_length& x, css_length& y)
+{
+	string_vector pos;
+	split_string(val, pos, " \t");
+	
+	if (pos.empty() || pos.size() > 2)
+	{
+		return false;
+	}
+	
+	if (pos.size() == 1)
+	{
+		if (value_in_list(pos[0], "left;right;center"))
+		{
+			x.fromString(pos[0], "left;right;center");
+			y.set_value(50, css_units_percentage);
+		}
+		else if (value_in_list(pos[0], "top;bottom;center"))
+		{
+			y.fromString(pos[0], "top;bottom;center");
+			x.set_value(50, css_units_percentage);
+		}
+		else
+		{
+			x.fromString(pos[0], "left;right;center");
+			y.set_value(50, css_units_percentage);
+		}
+	}
+	else if (pos.size() == 2)
+	{
+		if (value_in_list(pos[0], "left;right"))
+		{
+			x.fromString(pos[0], "left;right;center");
+			y.fromString(pos[1], "top;bottom;center");
+		}
+		else if (value_in_list(pos[0], "top;bottom"))
+		{
+			x.fromString(pos[1], "left;right;center");
+			y.fromString(pos[0], "top;bottom;center");
+		}
+		else if (value_in_list(pos[1], "left;right"))
+		{
+			x.fromString(pos[1], "left;right;center");
+			y.fromString(pos[0], "top;bottom;center");
+		}
+		else if (value_in_list(pos[1], "top;bottom"))
+		{
+			x.fromString(pos[0], "left;right;center");
+			y.fromString(pos[1], "top;bottom;center");
+		}
+		else
+		{
+			x.fromString(pos[0], "left;right;center");
+			y.fromString(pos[1], "top;bottom;center");
+		}
+	}
+
+	if (x.is_predefined())
+	{
+		switch (x.predef())
+		{
+		case 0:
+			x.set_value(0, css_units_percentage);
+			break;
+		case 1:
+			x.set_value(100, css_units_percentage);
+			break;
+		case 2:
+			x.set_value(50, css_units_percentage);
+			break;
+		}
+	}
+	if (y.is_predefined())
+	{
+		switch (y.predef())
+		{
+		case 0:
+			y.set_value(0, css_units_percentage);
+			break;
+		case 1:
+			y.set_value(100, css_units_percentage);
+			break;
+		case 2:
+			y.set_value(50, css_units_percentage);
+			break;
+		}
+	}
+	return true;
+}
+
+void style::parse_background_size(const string& val, bool important)
+{
+	string_vector tokens;
+	split_string(val, tokens, ",");
+	if (tokens.empty()) return;
+
+	size_vector sizes;
+
+	for (const auto& token : tokens)
+	{
+		css_size size;
+		if (!parse_one_background_size(token, size)) return;
+		sizes.push_back(size);
+	}
+
+	add_parsed_property(_background_size_, property_value(sizes, important));
+}
+
+bool style::parse_one_background_size(const string& val, css_size& size)
+{
+	string_vector res;
+	split_string(val, res, " \t");
+	if (res.empty())
+	{
+		return false;
+	}
+
+	size.width.fromString(res[0], background_size_strings);
+	if (res.size() > 1)
+	{
+		size.height.fromString(res[1], background_size_strings);
+	}
+	else
+	{
+		size.height.predef(background_size_auto);
+	}
+	return true;
 }
 
-void litehtml::style::parse_short_font( const tstring& val, bool important )
+void style::parse_font(const string& val, bool important)
 {
-	add_parsed_property(_t("font-style"),	_t("normal"),	important);
-	add_parsed_property(_t("font-variant"),	_t("normal"),	important);
-	add_parsed_property(_t("font-weight"),	_t("normal"),	important);
-	add_parsed_property(_t("font-size"),		_t("medium"),	important);
-	add_parsed_property(_t("line-height"),	_t("normal"),	important);
+	if (val == "inherit")
+	{
+		add_parsed_property(_font_style_, property_value(important, prop_type_inherit));
+		add_parsed_property(_font_variant_, property_value(important, prop_type_inherit));
+		add_parsed_property(_font_weight_, property_value(important, prop_type_inherit));
+		add_parsed_property(_font_size_, property_value(important, prop_type_inherit));
+		add_parsed_property(_line_height_, property_value(important, prop_type_inherit));
+		return;
+	} else
+	{
+		add_parsed_property(_font_style_, property_value(font_style_normal, important));
+		add_parsed_property(_font_variant_, property_value(font_variant_normal, important));
+		add_parsed_property(_font_weight_, property_value(font_weight_normal, important));
+		add_parsed_property(_font_size_, property_value(font_size_medium, important));
+		add_parsed_property(_line_height_, property_value(line_height_normal, important));
+	}
 
 	string_vector tokens;
-	split_string(val, tokens, _t(" "), _t(""), _t("\""));
+	split_string(val, tokens, " ", "", "\"");
 
-	int idx = 0;
-	bool was_normal = false;
+	int idx;
 	bool is_family = false;
-	tstring font_family;
-	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+	string font_family;
+	for(const auto& token : tokens)
 	{
-		idx = value_index(tok->c_str(), font_style_strings);
-		if(!is_family)
+		if(is_family)
 		{
-			if(idx >= 0)
+			font_family += token;
+			continue;
+		}
+
+		if((idx = value_index(token, font_style_strings)) >= 0)
+		{
+			if(idx == 0)
 			{
-				if(idx == 0 && !was_normal)
-				{
-					add_parsed_property(_t("font-weight"),		*tok, important);
-					add_parsed_property(_t("font-variant"),		*tok, important);
-					add_parsed_property(_t("font-style"),		*tok, important);
-				} else
-				{
-					add_parsed_property(_t("font-style"),		*tok, important);
-				}
+				add_parsed_property(_font_style_,	property_value(font_style_normal,	important));
+				add_parsed_property(_font_variant_, property_value(font_variant_normal,	important));
+				add_parsed_property(_font_weight_,	property_value(font_weight_normal,	important));
 			} else
 			{
-				if(value_in_list(tok->c_str(), font_weight_strings))
-				{
-					add_parsed_property(_t("font-weight"),		*tok, important);
-				} else
-				{
-					if(value_in_list(tok->c_str(), font_variant_strings))
-					{
-						add_parsed_property(_t("font-variant"),	*tok, important);
-					} else if( iswdigit((*tok)[0]) )
-					{
-						string_vector szlh;
-						split_string(*tok, szlh, _t("/"));
-
-						if(szlh.size() == 1)
-						{
-							add_parsed_property(_t("font-size"),	szlh[0], important);
-						} else	if(szlh.size() >= 2)
-						{
-							add_parsed_property(_t("font-size"),	szlh[0], important);
-							add_parsed_property(_t("line-height"),	szlh[1], important);
-						}
-					} else
-					{
-						is_family = true;
-						font_family += *tok;
-					}
-				}
+				add_parsed_property(_font_style_,	property_value(idx,		important));
+			}
+		} else if((idx = value_index(token, font_weight_strings)) >= 0)
+		{
+			add_parsed_property(_font_weight_, property_value(idx, important));
+		} else if((idx = value_index(token, font_variant_strings)) >= 0)
+		{
+			add_parsed_property(_font_variant_, property_value(idx, important));
+		}
+		else if(t_isdigit(token[0]) || token[0] == '.' || 
+			value_in_list(token, font_size_strings) || token.find('/') != -1)
+		{
+			string_vector szlh;
+			split_string(token, szlh, "/");
+
+			auto size = css_length::from_string(szlh[0], font_size_strings, -1);
+			add_parsed_property(_font_size_, property_value(size, important));
+
+			if(szlh.size() == 2)
+			{
+				auto height = css_length::from_string(szlh[1], "normal", -1);
+				add_parsed_property(_line_height_, property_value(height, important));
 			}
 		} else
 		{
-			font_family += *tok;
+			is_family = true;
+			font_family += token;
 		}
 	}
-	add_parsed_property(_t("font-family"), font_family, important);
+	add_parsed_property(_font_family_, property_value(font_family, important));
 }
 
-void litehtml::style::add_parsed_property( const tstring& name, const tstring& val, bool important )
+void style::parse_flex(const string& val, bool important)
 {
-	bool is_valid = true;
-	string_map::iterator vals = m_valid_values.find(name);
-	if (vals != m_valid_values.end())
+	auto is_number = [](const string& val)
 	{
-		if (!value_in_list(val, vals->second))
+		for (auto ch : val)
 		{
-			is_valid = false;
+			if ((ch < '0' || ch > '9') && ch != '.')
+			{
+				return false;
+			}
 		}
-	}
+		return true;
+	};
 
-	if (is_valid)
+	css_length _auto = css_length::predef_value(flex_basis_auto);
+
+	if (val == "initial")
 	{
-		props_map::iterator prop = m_properties.find(name);
-		if (prop != m_properties.end())
+		// 0 1 auto
+		add_parsed_property(_flex_grow_,	property_value(0.f, important));
+		add_parsed_property(_flex_shrink_,	property_value(1.f, important));
+		add_parsed_property(_flex_basis_,	property_value(_auto, important));
+	}
+	else if (val == "auto")
+	{
+		// 1 1 auto
+		add_parsed_property(_flex_grow_,	property_value(1.f, important));
+		add_parsed_property(_flex_shrink_,	property_value(1.f, important));
+		add_parsed_property(_flex_basis_,	property_value(_auto, important));
+	}
+	else if (val == "none")
+	{
+		// 0 0 auto
+		add_parsed_property(_flex_grow_,	property_value(0.f, important));
+		add_parsed_property(_flex_shrink_,	property_value(0.f, important));
+		add_parsed_property(_flex_basis_,	property_value(_auto, important));
+	}
+	else
+	{
+		string_vector tokens;
+		split_string(val, tokens, " ");
+		if (tokens.size() == 3)
 		{
-			if (!prop->second.m_important || (important && prop->second.m_important))
+			float grow = t_strtof(tokens[0]);
+			float shrink = t_strtof(tokens[1]);
+			auto basis = css_length::from_string(tokens[2], flex_basis_strings, -1);
+			
+			add_parsed_property(_flex_grow_,	property_value(grow, important));
+			add_parsed_property(_flex_shrink_,	property_value(shrink, important));
+			add_parsed_property(_flex_basis_,	property_value(basis, important));
+		}
+		else if (tokens.size() == 2)
+		{
+			float grow = t_strtof(tokens[0]);
+			add_parsed_property(_flex_grow_, property_value(grow, important));
+			
+			if (is_number(tokens[1]))
 			{
-				prop->second.m_value = val;
-				prop->second.m_important = important;
+				float shrink = t_strtof(tokens[1]);
+				add_parsed_property(_flex_shrink_, property_value(shrink, important));
+			}
+			else
+			{
+				auto basis = css_length::from_string(tokens[1], flex_basis_strings, -1);
+				add_parsed_property(_flex_basis_, property_value(basis, important));
 			}
 		}
-		else
+		else if (tokens.size() == 1)
 		{
-			m_properties[name] = property_value(val.c_str(), important);
+			if (is_number(tokens[0]))
+			{
+				float grow = t_strtof(tokens[0]);
+				add_parsed_property(_flex_grow_, property_value(grow, important));
+				
+				if (grow >= 1)
+				{
+					add_parsed_property(_flex_shrink_, property_value(1.f, important));
+					add_parsed_property(_flex_basis_,  property_value(css_length(0), important));
+				}
+			}
+			else
+			{
+				auto basis = css_length::from_string(tokens[0], flex_basis_strings, -1);
+				add_parsed_property(_flex_basis_, property_value(basis, important));
+			}
 		}
 	}
 }
 
-void litehtml::style::remove_property( const tstring& name, bool important )
+void style::add_parsed_property( string_id name, const property_value& propval )
 {
-	props_map::iterator prop = m_properties.find(name);
+	auto prop = m_properties.find(name);
+	if (prop != m_properties.end())
+	{
+		if (!prop->second.m_important || (propval.m_important && prop->second.m_important))
+		{
+			prop->second = propval;
+		}
+	}
+	else
+	{
+		m_properties[name] = propval;
+	}
+}
+
+void style::remove_property( string_id name, bool important )
+{
+	auto prop = m_properties.find(name);
 	if(prop != m_properties.end())
 	{
 		if( !prop->second.m_important || (important && prop->second.m_important) )
@@ -646,3 +1101,55 @@ void litehtml::style::remove_property( const tstring& name, bool important )
 		}
 	}
 }
+
+void style::combine(const style& src)
+{
+	for (const auto& property : src.m_properties)
+	{
+		add_parsed_property(property.first, property.second);
+	}
+}
+
+const property_value& style::get_property(string_id name) const
+{
+	auto it = m_properties.find(name);
+	if (it != m_properties.end())
+	{
+		return it->second;
+	}
+	static property_value dummy;
+	return dummy;
+}
+
+void style::subst_vars_(string& str, const element* el)
+{
+	while (1)
+	{
+		auto start = str.find("var(");
+		if (start == -1) break;
+		if (start > 0 && isalnum(str[start - 1])) break;
+		auto end = str.find(")", start + 4);
+		if (end == -1) break;
+		auto name = str.substr(start + 4, end - start - 4);
+		trim(name);
+		string val = el->get_custom_property(_id(name), "");
+		str.replace(start, end - start + 1, val);
+	}
+}
+
+void style::subst_vars(const element* el)
+{
+	for (auto& prop : m_properties)
+	{
+		if (prop.second.m_type == prop_type_var)
+		{
+			subst_vars_(prop.second.m_string, el);
+			// re-adding the same property
+			// if it is a custom property it will be readded as a string (currently it is prop_type_var)
+			// if it is a standard css property it will be parsed and properly added as typed property
+			add_property(prop.first, prop.second.m_string, "", prop.second.m_important, el->get_document()->container());
+		}
+	}
+}
+
+} // namespace litehtml
\ No newline at end of file
diff --git a/src/plugins/litehtml_viewer/litehtml/style.h b/src/plugins/litehtml_viewer/litehtml/style.h
index d84ee20e0..c83876ad6 100644
--- a/src/plugins/litehtml_viewer/litehtml/style.h
+++ b/src/plugins/litehtml_viewer/litehtml/style.h
@@ -1,41 +1,163 @@
 #ifndef LH_STYLE_H
 #define LH_STYLE_H
 
-#include "attributes.h"
-#include <string>
-
 namespace litehtml
 {
+	enum property_type
+	{
+		prop_type_invalid, // indicates "not found" condition in style::get_property
+		prop_type_inherit, // "inherit" was specified as the value of this property
+
+		prop_type_enum_item,
+		prop_type_enum_item_vector,
+		prop_type_length,
+		prop_type_length_vector,
+		prop_type_number,
+		prop_type_color,
+		prop_type_string,
+		prop_type_string_vector,
+		prop_type_size_vector,
+
+		prop_type_var, // also string, but needs further parsing because of var()
+	};
+
 	class property_value
 	{
 	public:
-		tstring	m_value;
+		property_type	m_type;
 		bool			m_important;
 
+		union {
+			int 			m_enum_item;
+			int_vector		m_enum_item_vector;
+			css_length		m_length;
+			length_vector	m_length_vector;
+			float			m_number;
+			web_color		m_color;
+			string			m_string;
+			string_vector	m_string_vector;
+			size_vector		m_size_vector;
+		};
+
 		property_value()
+			: m_type(prop_type_invalid)
 		{
-			m_important = false;
 		}
-		property_value(const tchar_t* val, bool imp)
+		property_value(bool important, property_type type)
+			: m_type(type), m_important(important)
 		{
-			m_important = imp;
-			m_value		= val;
 		}
-		property_value(const property_value& val)
+		property_value(const string& str, bool important, property_type type = prop_type_string)
+			: m_string(str), m_type(type), m_important(important)
 		{
-			m_value		= val.m_value;
-			m_important	= val.m_important;
 		}
-
+		property_value(const string_vector& vec, bool important)
+			: m_string_vector(vec), m_type(prop_type_string_vector), m_important(important)
+		{
+		}
+		property_value(const css_length& length, bool important)
+			: m_length(length), m_type(prop_type_length), m_important(important)
+		{
+		}
+		property_value(const length_vector& vec, bool important)
+			: m_length_vector(vec), m_type(prop_type_length_vector), m_important(important)
+		{
+		}
+		property_value(float number, bool important)
+			: m_number(number), m_type(prop_type_number), m_important(important)
+		{
+		}
+		property_value(int enum_item, bool important)
+			: m_enum_item(enum_item), m_type(prop_type_enum_item), m_important(important)
+		{
+		}
+		property_value(const int_vector& vec, bool important)
+			: m_enum_item_vector(vec), m_type(prop_type_enum_item_vector), m_important(important)
+		{
+		}
+		property_value(web_color color, bool important)
+			: m_color(color), m_type(prop_type_color), m_important(important)
+		{
+		}
+		property_value(const size_vector& vec, bool important)
+			: m_size_vector(vec), m_type(prop_type_size_vector), m_important(important)
+		{
+		}
+		~property_value()
+		{
+			switch (m_type)
+			{
+			case prop_type_string:
+			case prop_type_var:
+				m_string.~string();
+				break;
+			case prop_type_string_vector:
+				m_string_vector.~string_vector();
+				break;
+			case prop_type_length:
+				m_length.~css_length();
+				break;
+			case prop_type_length_vector:
+				m_length_vector.~length_vector();
+				break;
+			case prop_type_enum_item_vector:
+				m_enum_item_vector.~int_vector();
+				break;
+			case prop_type_color:
+				m_color.~web_color();
+				break;
+			case prop_type_size_vector:
+				m_size_vector.~size_vector();
+				break;
+			}
+		}
 		property_value& operator=(const property_value& val)
 		{
-			m_value		= val.m_value;
-			m_important	= val.m_important;
+			this->~property_value();
+
+			switch (val.m_type)
+			{
+			case prop_type_invalid:
+				new(this) property_value();
+				break;
+			case prop_type_inherit:
+				new(this) property_value(val.m_important, val.m_type);
+				break;
+			case prop_type_string:
+			case prop_type_var:
+				new(this) property_value(val.m_string, val.m_important, val.m_type);
+				break;
+			case prop_type_string_vector:
+				new(this) property_value(val.m_string_vector, val.m_important);
+				break;
+			case prop_type_enum_item:
+				new(this) property_value(val.m_enum_item, val.m_important);
+				break;
+			case prop_type_enum_item_vector:
+				new(this) property_value(val.m_enum_item_vector, val.m_important);
+				break;
+			case prop_type_length:
+				new(this) property_value(val.m_length, val.m_important);
+				break;
+			case prop_type_length_vector:
+				new(this) property_value(val.m_length_vector, val.m_important);
+				break;
+			case prop_type_number:
+				new(this) property_value(val.m_number, val.m_important);
+				break;
+			case prop_type_color:
+				new(this) property_value(val.m_color, val.m_important);
+				break;
+			case prop_type_size_vector:
+				new(this) property_value(val.m_size_vector, val.m_important);
+				break;
+			}
+
 			return *this;
 		}
 	};
 
-	typedef std::map<tstring, property_value>	props_map;
+	typedef std::map<string_id, property_value>	props_map;
 
 	class style
 	{
@@ -43,52 +165,47 @@ namespace litehtml
 		typedef std::shared_ptr<style>		ptr;
 		typedef std::vector<style::ptr>		vector;
 	private:
-		props_map			m_properties;
-		static string_map	m_valid_values;
+		props_map							m_properties;
+		static std::map<string_id, string>	m_valid_values;
 	public:
-		style();
-		style(const style& val);
-		virtual ~style();
-
-		void operator=(const style& val)
+		void add(const string& txt, const string& baseurl = "", document_container* container = nullptr)
 		{
-			m_properties = val.m_properties;
+			parse(txt, baseurl, container);
 		}
 
-		void add(const tchar_t* txt, const tchar_t* baseurl)
-		{
-			parse(txt, baseurl);
-		}
+		void add_property(string_id name, const string& val, const string& baseurl = "", bool important = false, document_container* container = nullptr);
 
-		void add_property(const tchar_t* name, const tchar_t* val, const tchar_t* baseurl, bool important);
-
-		const tchar_t* get_property(const tchar_t* name) const
-		{
-			if(name)
-			{
-				props_map::const_iterator f = m_properties.find(name);
-				if(f != m_properties.end())
-				{
-					return f->second.m_value.c_str();
-				}
-			}
-			return 0;
-		}
+		const property_value& get_property(string_id name) const;
 
-		void combine(const litehtml::style& src);
+		void combine(const style& src);
 		void clear()
 		{
 			m_properties.clear();
 		}
 
+		void subst_vars(const element* el);
+
 	private:
-		void parse_property(const tstring& txt, const tchar_t* baseurl);
-		void parse(const tchar_t* txt, const tchar_t* baseurl);
-		void parse_short_border(const tstring& prefix, const tstring& val, bool important);
-		void parse_short_background(const tstring& val, const tchar_t* baseurl, bool important);
-		void parse_short_font(const tstring& val, bool important);
-		void add_parsed_property(const tstring& name, const tstring& val, bool important);
-		void remove_property(const tstring& name, bool important);
+		void parse_property(const string& txt, const string& baseurl, document_container* container);
+		void parse(const string& txt, const string& baseurl, document_container* container);
+		void parse_background(const string& val, const string& baseurl, bool important, document_container* container);
+		bool parse_one_background(const string& val, document_container* container, background& bg);
+		void parse_background_image(const string& val, const string& baseurl, bool important);
+		// parse comma-separated list of keywords
+		void parse_keyword_comma_list(string_id name, const string& val, bool important);
+		void parse_background_position(const string& val, bool important);
+		bool parse_one_background_position(const string& val, css_length& x, css_length& y);
+		void parse_background_size(const string& val, bool important);
+		bool parse_one_background_size(const string& val, css_size& size);
+		void parse_font(const string& val, bool important);
+		void parse_flex(const string& val, bool important);
+		static css_length parse_border_width(const string& str);
+		static void parse_two_lengths(const string& str, css_length len[2]);
+		static int parse_four_lengths(const string& str, css_length len[4]);
+		static void subst_vars_(string& str, const element* el);
+
+		void add_parsed_property(string_id name, const property_value& propval);
+		void remove_property(string_id name, bool important);
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/stylesheet.cpp b/src/plugins/litehtml_viewer/litehtml/stylesheet.cpp
index 08ace6205..12bfd721d 100644
--- a/src/plugins/litehtml_viewer/litehtml/stylesheet.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/stylesheet.cpp
@@ -4,31 +4,31 @@
 #include "document.h"
 
 
-void litehtml::css::parse_stylesheet(const tchar_t* str, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media)
+void litehtml::css::parse_stylesheet(const char* str, const char* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media)
 {
-	tstring text = str;
+	string text = str;
 
 	// remove comments
-	tstring::size_type c_start = text.find(_t("/*"));
-	while(c_start != tstring::npos)
+	string::size_type c_start = text.find("/*");
+	while(c_start != string::npos)
 	{
-		tstring::size_type c_end = text.find(_t("*/"), c_start + 2);
+		string::size_type c_end = text.find("*/", c_start + 2);
 		text.erase(c_start, c_end - c_start + 2);
-		c_start = text.find(_t("/*"));
+		c_start = text.find("/*");
 	}
 
-	tstring::size_type pos = text.find_first_not_of(_t(" \n\r\t"));
-	while(pos != tstring::npos)
+	string::size_type pos = text.find_first_not_of(" \n\r\t");
+	while(pos != string::npos)
 	{
-		while(pos != tstring::npos && text[pos] == _t('@'))
+		while(pos != string::npos && text[pos] == '@')
 		{
-			tstring::size_type sPos = pos;
-			pos = text.find_first_of(_t("{;"), pos);
-			if(pos != tstring::npos && text[pos] == _t('{'))
+			string::size_type sPos = pos;
+			pos = text.find_first_of("{;", pos);
+			if(pos != string::npos && text[pos] == '{')
 			{
-				pos = find_close_bracket(text, pos, _t('{'), _t('}'));
+				pos = find_close_bracket(text, pos, '{', '}');
 			}
-			if(pos != tstring::npos)
+			if(pos != string::npos)
 			{
 				parse_atrule(text.substr(sPos, pos - sPos + 1), baseurl, doc, media);
 			} else
@@ -36,25 +36,26 @@ void litehtml::css::parse_stylesheet(const tchar_t* str, const tchar_t* baseurl,
 				parse_atrule(text.substr(sPos), baseurl, doc, media);
 			}
 
-			if(pos != tstring::npos)
+			if(pos != string::npos)
 			{
-				pos = text.find_first_not_of(_t(" \n\r\t"), pos + 1);
+				pos = text.find_first_not_of(" \n\r\t", pos + 1);
 			}
 		}
 
-		if(pos == tstring::npos)
+		if(pos == string::npos)
 		{
 			break;
 		}
 
-		tstring::size_type style_start = text.find(_t("{"), pos);
-		tstring::size_type style_end	= text.find(_t("}"), pos);
-		if(style_start != tstring::npos && style_end != tstring::npos)
+		string::size_type style_start	= text.find('{', pos);
+		string::size_type style_end	= text.find('}', pos);
+		if(style_start != string::npos && style_end != string::npos)
 		{
-			style::ptr st = std::make_shared<style>();
-			st->add(text.substr(style_start + 1, style_end - style_start - 1).c_str(), baseurl);
+			auto str_style = text.substr(style_start + 1, style_end - style_start - 1);
+			style::ptr style = std::make_shared<litehtml::style>();
+			style->add(str_style, baseurl ? baseurl : "", doc->container());
 
-			parse_selectors(text.substr(pos, style_start - pos), st, media);
+			parse_selectors(text.substr(pos, style_start - pos), style, media);
 
 			if(media && doc)
 			{
@@ -64,34 +65,34 @@ void litehtml::css::parse_stylesheet(const tchar_t* str, const tchar_t* baseurl,
 			pos = style_end + 1;
 		} else
 		{
-			pos = tstring::npos;
+			pos = string::npos;
 		}
 
-		if(pos != tstring::npos)
+		if(pos != string::npos)
 		{
-			pos = text.find_first_not_of(_t(" \n\r\t"), pos);
+			pos = text.find_first_not_of(" \n\r\t", pos);
 		}
 	}
 }
 
-void litehtml::css::parse_css_url( const tstring& str, tstring& url )
+void litehtml::css::parse_css_url( const string& str, string& url )
 {
-	url = _t("");
-	size_t pos1 = str.find(_t('('));
-	size_t pos2 = str.find(_t(')'));
-	if(pos1 != tstring::npos && pos2 != tstring::npos)
+	url = "";
+	size_t pos1 = str.find('(');
+	size_t pos2 = str.find(')');
+	if(pos1 != string::npos && pos2 != string::npos)
 	{
 		url = str.substr(pos1 + 1, pos2 - pos1 - 1);
 		if(url.length())
 		{
-			if(url[0] == _t('\'') || url[0] == _t('"'))
+			if(url[0] == '\'' || url[0] == '"')
 			{
 				url.erase(0, 1);
 			}
 		}
 		if(url.length())
 		{
-			if(url[url.length() - 1] == _t('\'') || url[url.length() - 1] == _t('"'))
+			if(url[url.length() - 1] == '\'' || url[url.length() - 1] == '"')
 			{
 				url.erase(url.length() - 1, 1);
 			}
@@ -99,24 +100,24 @@ void litehtml::css::parse_css_url( const tstring& str, tstring& url )
 	}
 }
 
-bool litehtml::css::parse_selectors( const tstring& txt, const litehtml::style::ptr& styles, const media_query_list::ptr& media )
+bool litehtml::css::parse_selectors( const string& txt, const style::ptr& styles, const media_query_list::ptr& media )
 {
-	tstring selector = txt;
+	string selector = txt;
 	trim(selector);
 	string_vector tokens;
-	split_string(selector, tokens, _t(","));
+	split_string(selector, tokens, ",");
 
 	bool added_something = false;
 
-	for(string_vector::iterator tok = tokens.begin(); tok != tokens.end(); tok++)
+	for(auto & token : tokens)
 	{
-		css_selector::ptr selector = std::make_shared<css_selector>(media);
-		selector->m_style = styles;
-		trim(*tok);
-		if(selector->parse(*tok))
+		css_selector::ptr new_selector = std::make_shared<css_selector>(media);
+        new_selector->m_style = styles;
+		trim(token);
+		if(new_selector->parse(token))
 		{
-			selector->calc_specificity();
-			add_selector(selector);
+			new_selector->calc_specificity();
+			add_selector(new_selector);
 			added_something = true;
 		}
 	}
@@ -134,23 +135,23 @@ void litehtml::css::sort_selectors()
 	);
 }
 
-void litehtml::css::parse_atrule(const tstring& text, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media)
+void litehtml::css::parse_atrule(const string& text, const char* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media)
 {
-	if(text.substr(0, 7) == _t("@import"))
+	if(text.substr(0, 7) == "@import")
 	{
 		int sPos = 7;
-		tstring iStr;
+		string iStr;
 		iStr = text.substr(sPos);
-		if(iStr[iStr.length() - 1] == _t(';'))
+		if(iStr[iStr.length() - 1] == ';')
 		{
 			iStr.erase(iStr.length() - 1);
 		}
 		trim(iStr);
 		string_vector tokens;
-		split_string(iStr, tokens, _t(" "), _t(""), _t("(\""));
+		split_string(iStr, tokens, " ", "", "(\"");
 		if(!tokens.empty())
 		{
-			tstring url;
+			string url;
 			parse_css_url(tokens.front(), url);
 			if(url.empty())
 			{
@@ -162,8 +163,8 @@ void litehtml::css::parse_atrule(const tstring& text, const tchar_t* baseurl, co
 				document_container* doc_cont = doc->container();
 				if(doc_cont)
 				{
-					tstring css_text;
-					tstring css_baseurl;
+					string css_text;
+					string css_baseurl;
 					if(baseurl)
 					{
 						css_baseurl = baseurl;
@@ -174,12 +175,12 @@ void litehtml::css::parse_atrule(const tstring& text, const tchar_t* baseurl, co
 						media_query_list::ptr new_media = media;
 						if(!tokens.empty())
 						{
-							tstring media_str;
-							for(string_vector::iterator iter = tokens.begin(); iter != tokens.end(); iter++)
+							string media_str;
+							for(auto iter = tokens.begin(); iter != tokens.end(); iter++)
 							{
 								if(iter != tokens.begin())
 								{
-									media_str += _t(" ");
+									media_str += " ";
 								}
 								media_str += (*iter);
 							}
@@ -194,18 +195,18 @@ void litehtml::css::parse_atrule(const tstring& text, const tchar_t* baseurl, co
 				}
 			}
 		}
-	} else if(text.substr(0, 6) == _t("@media"))
+	} else if(text.substr(0, 6) == "@media")
 	{
-		tstring::size_type b1 = text.find_first_of(_t('{'));
-		tstring::size_type b2 = text.find_last_of(_t('}'));
-		if(b1 != tstring::npos)
+		string::size_type b1 = text.find_first_of('{');
+		string::size_type b2 = text.find_last_of('}');
+		if(b1 != string::npos)
 		{
-			tstring media_type = text.substr(6, b1 - 6);
+			string media_type = text.substr(6, b1 - 6);
 			trim(media_type);
 			media_query_list::ptr new_media = media_query_list::create_from_string(media_type, doc);
 
-			tstring media_style;
-			if(b2 != tstring::npos)
+			string media_style;
+			if(b2 != string::npos)
 			{
 				media_style = text.substr(b1 + 1, b2 - b1 - 1);
 			} else
diff --git a/src/plugins/litehtml_viewer/litehtml/stylesheet.h b/src/plugins/litehtml_viewer/litehtml/stylesheet.h
index 84c5f1fbf..923853d76 100644
--- a/src/plugins/litehtml_viewer/litehtml/stylesheet.h
+++ b/src/plugins/litehtml_viewer/litehtml/stylesheet.h
@@ -12,15 +12,8 @@ namespace litehtml
 	{
 		css_selector::vector	m_selectors;
 	public:
-		css()
-		{
-
-		}
-		
-		~css()
-		{
-
-		}
+		css() = default;
+		~css() = default;
 
 		const css_selector::vector& selectors() const
 		{
@@ -32,18 +25,18 @@ namespace litehtml
 			m_selectors.clear();
 		}
 
-		void	parse_stylesheet(const tchar_t* str, const tchar_t* baseurl, const std::shared_ptr <document>& doc, const media_query_list::ptr& media);
+		void	parse_stylesheet(const char* str, const char* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media);
 		void	sort_selectors();
-		static void	parse_css_url(const tstring& str, tstring& url);
+		static void	parse_css_url(const string& str, string& url);
 
 	private:
-		void	parse_atrule(const tstring& text, const tchar_t* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media);
-		void	add_selector(css_selector::ptr selector);
-		bool	parse_selectors(const tstring& txt, const litehtml::style::ptr& styles, const media_query_list::ptr& media);
+		void	parse_atrule(const string& text, const char* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media);
+		void	add_selector(const css_selector::ptr& selector);
+		bool	parse_selectors(const string& txt, const style::ptr& styles, const media_query_list::ptr& media);
 
 	};
 
-	inline void litehtml::css::add_selector( css_selector::ptr selector )
+	inline void litehtml::css::add_selector( const css_selector::ptr& selector )
 	{
 		selector->m_order = (int) m_selectors.size();
 		m_selectors.push_back(selector);
diff --git a/src/plugins/litehtml_viewer/litehtml/table.cpp b/src/plugins/litehtml_viewer/litehtml/table.cpp
index c53509c76..da272c070 100644
--- a/src/plugins/litehtml_viewer/litehtml/table.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/table.cpp
@@ -1,13 +1,14 @@
 #include "html.h"
 #include "table.h"
-#include "html_tag.h"
+#include "element.h"
+#include "render_item.h"
 
-void litehtml::table_grid::add_cell(element::ptr& el)
+void litehtml::table_grid::add_cell(const std::shared_ptr<render_item>& el)
 {
 	table_cell cell;
 	cell.el = el;
-	cell.colspan	= t_atoi(el->get_attr(_t("colspan"), _t("1")));
-	cell.rowspan	= t_atoi(el->get_attr(_t("rowspan"), _t("1")));
+	cell.colspan	= atoi(el->src_el()->get_attr("colspan", "1"));
+	cell.rowspan	= atoi(el->src_el()->get_attr("rowspan", "1"));
 	cell.borders	= el->get_borders();
 
 	while( is_rowspanned( (int) m_cells.size() - 1, (int) m_cells.back().size() ) )
@@ -24,13 +25,12 @@ void litehtml::table_grid::add_cell(element::ptr& el)
 }
 
 
-void litehtml::table_grid::begin_row(element::ptr& row)
+void litehtml::table_grid::begin_row(const std::shared_ptr<render_item>& row)
 {
 	std::vector<table_cell> r;
 	m_cells.push_back(r);
 	
 	m_rows.push_back(table_row(0, row));
-
 }
 
 
@@ -56,16 +56,16 @@ void litehtml::table_grid::finish()
 {
 	m_rows_count	= (int) m_cells.size();
 	m_cols_count	= 0;
-	for(int i = 0; i < (int) m_cells.size(); i++)
+	for(auto& cell : m_cells)
 	{
-		m_cols_count = std::max(m_cols_count, (int) m_cells[i].size());
+		m_cols_count = std::max(m_cols_count, (int) cell.size());
 	}
-	for(int i = 0; i < (int) m_cells.size(); i++)
+	for(auto& cell : m_cells)
 	{
-		for(int j = (int) m_cells[i].size(); j < m_cols_count; j++)
+		for(int j = (int) cell.size(); j < m_cols_count; j++)
 		{
 			table_cell empty_cell;
-			m_cells[i].push_back(empty_cell);
+			cell.push_back(empty_cell);
 		}
 	}
 
@@ -117,9 +117,9 @@ void litehtml::table_grid::finish()
 
 			if(cell(col, row)->el && cell(col, row)->colspan <= 1)
 			{
-				if (!cell(col, row)->el->get_css_width().is_predefined() && m_columns[col].css_width.is_predefined())
+				if (!cell(col, row)->el->src_el()->css().get_width().is_predefined() && m_columns[col].css_width.is_predefined())
 				{
-					m_columns[col].css_width = cell(col, row)->el->get_css_width();
+					m_columns[col].css_width = cell(col, row)->el->src_el()->css().get_width();
 				}
 			}
 		}
@@ -129,9 +129,9 @@ void litehtml::table_grid::finish()
 	{
 		for(int row = 0; row < m_rows_count; row++)
 		{
-			if(cell(col, row)->el)
+			if(cell(col, row)->el && cell(col, row)->colspan == 1)
 			{
-				cell(col, row)->el->set_css_width(m_columns[col].css_width);
+				cell(col, row)->el->src_el()->css_w().set_width(m_columns[col].css_width);
 			}
 		}
 	}
@@ -143,7 +143,7 @@ litehtml::table_cell* litehtml::table_grid::cell( int t_col, int t_row )
 	{
 		return &m_cells[t_row][t_col];
 	}
-	return 0;
+	return nullptr;
 }
 
 void litehtml::table_grid::distribute_max_width( int width, int start, int end )
@@ -243,25 +243,25 @@ void litehtml::table_grid::distribute_width( int width, int start, int end )
 		if(!distribute_columns.empty() || step == 2)
 		{
 			int cols_width = 0;
-			for(std::vector<table_column*>::iterator col = distribute_columns.begin(); col != distribute_columns.end(); col++)
+			for(const auto& column : distribute_columns)
 			{
-				cols_width += (*col)->max_width - (*col)->min_width;
+				cols_width += column->max_width - column->min_width;
 			}
 
 			if(cols_width)
 			{
 				int add = width / (int) distribute_columns.size();
-				for(std::vector<table_column*>::iterator col = distribute_columns.begin(); col != distribute_columns.end(); col++)
+				for(const auto& column : distribute_columns)
 				{
-					add = round_f( (float) width * ((float) ((*col)->max_width - (*col)->min_width) / (float) cols_width) );
-					if((*col)->width + add >= (*col)->min_width)
+					add = round_f( (float) width * ((float) (column->max_width - column->min_width) / (float) cols_width) );
+					if(column->width + add >= column->min_width)
 					{
-						(*col)->width	+= add;
+                        column->width	+= add;
 						added_width		+= add;
 					} else
 					{
-						added_width	+= ((*col)->width - (*col)->min_width) * (add / abs(add));
-						(*col)->width = (*col)->min_width;
+						added_width	+= (column->width - column->min_width) * (add / abs(add));
+                        column->width = column->min_width;
 					}
 				}
 				if(added_width < width && step)
@@ -359,7 +359,7 @@ int litehtml::table_grid::calc_table_width(int block_width, bool is_auto, int& m
 				fixed_width += m_columns[col].width;
 			}
 		}
-		float scale = (float) (100.0 / percent);
+		auto scale = (float) (100.0 / percent);
 		cur_width = 0;
 		for(int col = 0; col < m_cols_count; col++)
 		{
@@ -375,6 +375,34 @@ int litehtml::table_grid::calc_table_width(int block_width, bool is_auto, int& m
 			}
 			cur_width += m_columns[col].width;
 		}
+		// If the table is still too wide shrink columns with % widths
+		if(cur_width > block_width)
+		{
+			while(true)
+			{
+				bool shrunk = false;
+				for(int col = 0; col < m_cols_count; col++)
+				{
+					if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage)
+					{
+						if(m_columns[col].width > m_columns[col].min_width)
+						{
+							m_columns[col].width--;
+							cur_width--;
+							shrunk = true;
+							if(cur_width == block_width)
+							{
+								break;
+							}
+						}
+					}
+				}
+				if(cur_width == block_width || !shrunk)
+				{
+					break;
+				}
+			}
+		}
 	}
 	return cur_width;
 }
@@ -388,7 +416,7 @@ void litehtml::table_grid::clear()
 	m_rows.clear();
 }
 
-void litehtml::table_grid::calc_horizontal_positions( margins& table_borders, border_collapse bc, int bdr_space_x)
+void litehtml::table_grid::calc_horizontal_positions( const margins& table_borders, border_collapse bc, int bdr_space_x)
 {
 	if(bc == border_collapse_separate)
 	{
@@ -420,7 +448,7 @@ void litehtml::table_grid::calc_horizontal_positions( margins& table_borders, bo
 	}
 }
 
-void litehtml::table_grid::calc_vertical_positions( margins& table_borders, border_collapse bc, int bdr_space_y )
+void litehtml::table_grid::calc_vertical_positions( const margins& table_borders, border_collapse bc, int bdr_space_y )
 {
 	if(bc == border_collapse_separate)
 	{
@@ -564,3 +592,18 @@ int& litehtml::table_column_accessor_width::get( table_column& col )
 {
 	return col.width;
 }
+
+litehtml::table_row::table_row(int h, const std::shared_ptr<render_item>& row)
+{
+    min_height		= 0;
+    height			= h;
+    el_row			= row;
+    border_bottom	= 0;
+    border_top		= 0;
+    top				= 0;
+    bottom			= 0;
+    if (row)
+    {
+        css_height = row->src_el()->css().get_height();
+    }
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/table.h b/src/plugins/litehtml_viewer/litehtml/table.h
index ca95febf5..edd5f055e 100644
--- a/src/plugins/litehtml_viewer/litehtml/table.h
+++ b/src/plugins/litehtml_viewer/litehtml/table.h
@@ -1,8 +1,14 @@
 #ifndef LH_TABLE_H
 #define LH_TABLE_H
 
+#include <vector>
+#include <memory>
+#include "css_length.h"
+
 namespace litehtml
 {
+    class render_item;
+
 	struct table_row
 	{
 		typedef std::vector<table_row>	vector;
@@ -10,7 +16,7 @@ namespace litehtml
 		int				height;
 		int				border_top;
 		int				border_bottom;
-		element::ptr	el_row;
+        std::shared_ptr<render_item>	el_row;
 		int				top;
 		int				bottom;
 		css_length		css_height;
@@ -28,20 +34,7 @@ namespace litehtml
 			css_height.predef(0);
 		}
 
-		table_row(int h, element::ptr& row)
-		{
-			min_height		= 0;
-			height			= h;
-			el_row			= row;
-			border_bottom	= 0;
-			border_top		= 0;
-			top				= 0;
-			bottom			= 0;
-			if (row)
-			{
-				css_height = row->get_css_height();
-			}
-		}
+		table_row(int h, const std::shared_ptr<render_item>& row);
 
 		table_row(const table_row& val)
 		{
@@ -55,7 +48,7 @@ namespace litehtml
 			el_row = val.el_row;
 		}
 
-		table_row(table_row&& val)
+		table_row(table_row&& val) noexcept
 		{
 			min_height = val.min_height;
 			top = val.top;
@@ -122,29 +115,32 @@ namespace litehtml
 	{
 	public:
 		virtual int& get(table_column& col) = 0;
+
+	protected:
+		~table_column_accessor() = default;
 	};
 
-	class table_column_accessor_max_width : public table_column_accessor
+	class table_column_accessor_max_width final : public table_column_accessor
 	{
 	public:
-		virtual int& get(table_column& col);
+		int& get(table_column& col) override;
 	};
 
-	class table_column_accessor_min_width : public table_column_accessor
+	class table_column_accessor_min_width final : public table_column_accessor
 	{
 	public:
-		virtual int& get(table_column& col);
+		int& get(table_column& col) override;
 	};
 
-	class table_column_accessor_width : public table_column_accessor
+	class table_column_accessor_width final : public table_column_accessor
 	{
 	public:
-		virtual int& get(table_column& col);
+		int& get(table_column& col) override;
 	};
 
 	struct table_cell
 	{
-		element::ptr	el;
+        std::shared_ptr<render_item>	el;
 		int				colspan;
 		int				rowspan;
 		int				min_width;
@@ -182,8 +178,8 @@ namespace litehtml
 			borders			= val.borders;
 		}
 
-		table_cell(const table_cell&& val)
-		{
+		table_cell(table_cell&& val) noexcept
+        {
 			el = std::move(val.el);
 			colspan = val.colspan;
 			rowspan = val.rowspan;
@@ -207,33 +203,40 @@ namespace litehtml
 		rows					m_cells;
 		table_column::vector	m_columns;
 		table_row::vector		m_rows;
+		std::vector<std::shared_ptr<render_item>> m_captions;
+		int						m_captions_height;
 	public:
 
 		table_grid()
 		{
 			m_rows_count	= 0;
 			m_cols_count	= 0;
+			m_captions_height = 0;
 		}
 
 		void			clear();
-		void			begin_row(element::ptr& row);
-		void			add_cell(element::ptr& el);
+		void			begin_row(const std::shared_ptr<render_item>& row);
+		void			add_cell(const std::shared_ptr<render_item>& el);
 		bool			is_rowspanned(int r, int c);
 		void			finish();
 		table_cell*		cell(int t_col, int t_row);
 		table_column&	column(int c)	{ return m_columns[c];	}
 		table_row&		row(int r)		{ return m_rows[r];		}
+        std::vector<std::shared_ptr<render_item>>& captions()		{ return m_captions; }
+
+		int				rows_count() const	{ return m_rows_count;	}
+		int				cols_count() const	{ return m_cols_count; }
 
-		int				rows_count()	{ return m_rows_count;	}
-		int				cols_count()	{ return m_cols_count;	}
+		void			captions_height(int height) { m_captions_height = height; }
+		int				captions_height() const { return m_captions_height; }
 
 		void			distribute_max_width(int width, int start, int end);
 		void			distribute_min_width(int width, int start, int end);
 		void			distribute_width(int width, int start, int end);
 		void			distribute_width(int width, int start, int end, table_column_accessor* acc);
 		int				calc_table_width(int block_width, bool is_auto, int& min_table_width, int& max_table_width);
-		void			calc_horizontal_positions(margins& table_borders, border_collapse bc, int bdr_space_x);
-		void			calc_vertical_positions(margins& table_borders, border_collapse bc, int bdr_space_y);
+		void			calc_horizontal_positions(const margins& table_borders, border_collapse bc, int bdr_space_x);
+		void			calc_vertical_positions(const margins& table_borders, border_collapse bc, int bdr_space_y);
 		void			calc_rows_height(int blockHeight, int borderSpacingY);
 	};
 }
diff --git a/src/plugins/litehtml_viewer/litehtml/tstring_view.cpp b/src/plugins/litehtml_viewer/litehtml/tstring_view.cpp
new file mode 100644
index 000000000..f9afa4bbc
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/tstring_view.cpp
@@ -0,0 +1,46 @@
+// Copyright (C) 2020-2021 Primate Labs Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the names of the copyright holders nor the names of their
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "tstring_view.h"
+
+namespace litehtml {
+
+
+std::basic_ostream<tstring_view::value_type>& operator<<(
+    std::basic_ostream<tstring_view::value_type>& os,
+    tstring_view str)
+{
+    if (os.good()) {
+        os.write(str.data(), str.size());
+    }
+
+    return os;
+}
+
+} // namespace litehtml
\ No newline at end of file
diff --git a/src/plugins/litehtml_viewer/litehtml/tstring_view.h b/src/plugins/litehtml_viewer/litehtml/tstring_view.h
new file mode 100644
index 000000000..384c8d7df
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/tstring_view.h
@@ -0,0 +1,136 @@
+// Copyright (C) 2020-2021 Primate Labs Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the names of the copyright holders nor the names of their
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef LITEHTML_TSTRING_VIEW_H__
+#define LITEHTML_TSTRING_VIEW_H__
+
+#include <cstddef>
+#include <ostream>
+
+#include "os_types.h"
+
+namespace litehtml {
+
+// tstring_view is a string reference type that provides a view into a string
+// that is owned elsewhere (e.g., by a std::string object).
+
+// tstring_view implements the same interface as std::base_string_view in the
+// standard library.  When litehtml moves to C++17 consider replacing the
+// tstring_view implementation with the standard library implementations
+// (e.g., via a using statement).
+
+class tstring_view {
+public:
+    using value_type = char;
+
+    using pointer = char*;
+
+    using const_pointer = const char*;
+
+    using reference = char&;
+
+    using const_reference = const char&;
+
+    using iterator = const_pointer;
+
+    using const_iterator = const_pointer;
+
+    using size_type = size_t;
+
+    using difference_type = std::ptrdiff_t;
+
+public:
+    tstring_view() = default;
+
+    tstring_view(const tstring_view& other) = default;
+
+    tstring_view(const_pointer s, size_type size)
+    : data_(s)
+    , size_(size)
+    {
+    }
+
+    constexpr const_iterator begin() const
+    {
+        return data_;
+    }
+
+    constexpr const_iterator cbegin() const
+    {
+        return data_;
+    }
+
+    constexpr const_iterator end() const
+    {
+        return data_ + size_;
+    }
+
+    constexpr const_iterator cend() const
+    {
+        return data_ + size_;
+    }
+
+    constexpr const_reference operator[](size_type offset) const
+    {
+        return *(data_ + offset);
+    }
+
+    constexpr const_pointer data() const
+    {
+        return data_;
+    }
+
+    size_type size() const
+    {
+        return size_;
+    }
+
+    size_type length() const
+    {
+        return size_;
+    }
+
+    bool empty() const
+    {
+        return (size_ == 0);
+    }
+
+private:
+    const_pointer data_ = nullptr;
+
+    size_type size_ = 0;
+};
+
+std::basic_ostream<tstring_view::value_type>& operator<<(
+    std::basic_ostream<tstring_view::value_type>&,
+    tstring_view str);
+
+} // namespace litehtml
+
+#endif // LITEHTML_TSTRING_VIEW_H__
diff --git a/src/plugins/litehtml_viewer/litehtml/types.h b/src/plugins/litehtml_viewer/litehtml/types.h
index 682fd7354..7946a3f08 100644
--- a/src/plugins/litehtml_viewer/litehtml/types.h
+++ b/src/plugins/litehtml_viewer/litehtml/types.h
@@ -1,7 +1,7 @@
 #ifndef LH_TYPES_H
 #define LH_TYPES_H
 
-#include <stdlib.h>
+#include <cstdlib>
 #include <memory>
 #include <map>
 #include <vector>
@@ -11,10 +11,10 @@ namespace litehtml
 	class document;
 	class element;
 
-	typedef std::map<litehtml::tstring, litehtml::tstring>			string_map;
-	typedef std::vector< std::shared_ptr<litehtml::element> >		elements_vector;
-	typedef std::vector<int>										int_vector;
-	typedef std::vector<litehtml::tstring>							string_vector;
+	typedef std::map<string, string>					string_map;
+	typedef std::vector< std::shared_ptr<element> >		elements_vector;
+	typedef std::vector<int>							int_vector;
+	typedef std::vector<string>							string_vector;
 
 	const unsigned int font_decoration_none			= 0x00;
 	const unsigned int font_decoration_underline	= 0x01;
@@ -45,10 +45,12 @@ namespace litehtml
 		int		width;
 		int		height;
 
-		size()
+		size(int w, int h) : width(w), height(h)
+		{
+		}
+
+		size() : width(0), height(0)
 		{
-			width	= 0;
-			height	= 0;
 		}
 	};
 
@@ -162,7 +164,7 @@ namespace litehtml
 			x_height		= 0;
 			draw_spaces		= true;
 		}
-		int base_line()	{ return descent; }
+		int base_line() const	{ return descent; }
 	};
 
 	struct font_item
@@ -171,7 +173,7 @@ namespace litehtml
 		font_metrics	metrics;
 	};
 
-	typedef std::map<tstring, font_item>	fonts_map;
+	typedef std::map<string, font_item> fonts_map;
 
 	enum draw_flag
 	{
@@ -182,7 +184,81 @@ 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;inline-text")
+	struct containing_block_context
+	{
+		enum cbc_value_type
+		{
+			cbc_value_type_absolute,	// width/height of containing block is defined as absolute value
+			cbc_value_type_percentage,	// width/height of containing block is defined as percentage
+			cbc_value_type_auto,		// width/height of containing block is defined as auto
+			cbc_value_type_none,		// min/max width/height of containing block is defined as none
+		};
+
+		struct typed_int
+		{
+			int 			value;
+			cbc_value_type	type;
+
+			typed_int(int val, cbc_value_type tp)
+			{
+				value = val;
+				type = tp;
+			}
+
+			operator int() const
+			{
+				return value;
+			}
+
+			typed_int& operator=(int val)
+			{
+				value = val;
+				return *this;
+			}
+
+			typed_int& operator=(const typed_int& v)
+			{
+				value = v.value;
+				type = v.type;
+				return *this;
+			}
+		};
+
+		typed_int width;						// width of the containing block
+		typed_int render_width;
+		typed_int min_width;
+		typed_int max_width;
+
+		typed_int height;						// height of the containing block
+		typed_int min_height;
+		typed_int max_height;
+
+		int context_idx;
+
+		containing_block_context() :
+				width(0, cbc_value_type_auto),
+				render_width(0, cbc_value_type_auto),
+				min_width(0, cbc_value_type_none),
+				max_width(0, cbc_value_type_none),
+				height(0, cbc_value_type_auto),
+				min_height(0, cbc_value_type_none),
+				max_height(0, cbc_value_type_none),
+				context_idx(0)
+		{}
+
+		containing_block_context new_width(int w) const
+		{
+			containing_block_context ret = *this;
+			//if(ret.width.type != cbc_value_type_absolute)
+			{
+				ret.render_width = w - (ret.width - ret.render_width);
+				ret.width = w;
+			}
+			return ret;
+		}
+	};
+
+#define  style_display_strings		"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;flex;inline-flex"
 
 	enum style_display
 	{
@@ -202,68 +278,68 @@ namespace litehtml
 		display_table_row,
 		display_table_row_group,
 		display_inline_text,
+		display_flex,
+		display_inline_flex,
 	};
 
-	enum style_border
+#define  font_size_strings		"xx-small;x-small;small;medium;large;x-large;xx-large;smaller;larger"
+
+	enum font_size
 	{
-		borderNope,
-		borderNone,
-		borderHidden,
-		borderDotted,
-		borderDashed,
-		borderSolid,
-		borderDouble
+		font_size_xx_small,
+		font_size_x_small,
+		font_size_small,
+		font_size_medium,
+		font_size_large,
+		font_size_x_large,
+		font_size_xx_large,
+		font_size_smaller,
+		font_size_larger,
 	};
 
-#define  font_size_strings		_t("xx-small;x-small;small;medium;large;x-large;xx-large;smaller;larger")
+#define line_height_strings "normal"
 
-	enum font_size
+	enum line_height
 	{
-		fontSize_xx_small,
-		fontSize_x_small,
-		fontSize_small,
-		fontSize_medium,
-		fontSize_large,
-		fontSize_x_large,
-		fontSize_xx_large,
-		fontSize_smaller,
-		fontSize_larger,
+		line_height_normal
 	};
 
-#define  font_style_strings		_t("normal;italic")
+#define  font_style_strings		"normal;italic"
 
 	enum font_style
 	{
-		fontStyleNormal,
-		fontStyleItalic
+		font_style_normal,
+		font_style_italic
 	};
 
-#define  font_variant_strings		_t("normal;small-caps")
+#define  font_variant_strings		"normal;small-caps"
 
 	enum font_variant
 	{
 		font_variant_normal,
-		font_variant_italic
+		font_variant_small_caps
 	};
 
-#define  font_weight_strings	_t("normal;bold;bolder;lighter;100;200;300;400;500;600;700")
+#define  font_weight_strings	"normal;bold;bolder;lighter;100;200;300;400;500;600;700;800;900"
 
 	enum font_weight
 	{
-		fontWeightNormal,
-		fontWeightBold,
-		fontWeightBolder,
-		fontWeightLighter,
-		fontWeight100,
-		fontWeight200,
-		fontWeight300,
-		fontWeight400,
-		fontWeight500,
-		fontWeight600,
-		fontWeight700
+		font_weight_normal,
+		font_weight_bold,
+		font_weight_bolder,
+		font_weight_lighter,
+		font_weight_100,
+		font_weight_200,
+		font_weight_300,
+		font_weight_400,
+		font_weight_500,
+		font_weight_600,
+		font_weight_700,
+		font_weight_800,
+		font_weight_900
 	};
 
-#define  list_style_type_strings	_t("none;circle;disc;square;armenian;cjk-ideographic;decimal;decimal-leading-zero;georgian;hebrew;hiragana;hiragana-iroha;katakana;katakana-iroha;lower-alpha;lower-greek;lower-latin;lower-roman;upper-alpha;upper-latin;upper-roman")
+#define  list_style_type_strings	"none;circle;disc;square;armenian;cjk-ideographic;decimal;decimal-leading-zero;georgian;hebrew;hiragana;hiragana-iroha;katakana;katakana-iroha;lower-alpha;lower-greek;lower-latin;lower-roman;upper-alpha;upper-latin;upper-roman"
 
 	enum list_style_type
 	{
@@ -290,7 +366,7 @@ namespace litehtml
 		list_style_type_upper_roman,
 	};
 
-#define  list_style_position_strings	_t("inside;outside")
+#define  list_style_position_strings	"inside;outside"
 
 	enum list_style_position
 	{
@@ -298,7 +374,7 @@ namespace litehtml
 		list_style_position_outside
 	};
 
-#define  vertical_align_strings	_t("baseline;sub;super;top;text-top;middle;bottom;text-bottom")
+#define  vertical_align_strings	"baseline;sub;super;top;text-top;middle;bottom;text-bottom"
 
 	enum vertical_align
 	{
@@ -312,7 +388,7 @@ namespace litehtml
 		va_text_bottom
 	};
 
-#define  border_width_strings	_t("thin;medium;thick")
+#define  border_width_strings	"thin;medium;thick"
 
 	enum border_width
 	{
@@ -321,7 +397,12 @@ namespace litehtml
 		border_width_thick
 	};
 
-#define  border_style_strings	_t("none;hidden;dotted;dashed;solid;double;groove;ridge;inset;outset")
+	const float border_width_thin_value = 1;
+	const float border_width_medium_value = 3;
+	const float border_width_thick_value = 5;
+	const float border_width_values[] = { border_width_thin_value, border_width_medium_value, border_width_thick_value };
+
+#define  border_style_strings	"none;hidden;dotted;dashed;solid;double;groove;ridge;inset;outset"
 
 	enum border_style
 	{
@@ -337,7 +418,7 @@ namespace litehtml
 		border_style_outset
 	};
 
-#define  element_float_strings	_t("none;left;right")
+#define  element_float_strings	"none;left;right"
 
 	enum element_float
 	{
@@ -346,7 +427,7 @@ namespace litehtml
 		float_right
 	};
 
-#define  element_clear_strings	_t("none;left;right;both")
+#define  element_clear_strings	"none;left;right;both"
 
 	enum element_clear
 	{
@@ -356,9 +437,9 @@ namespace litehtml
 		clear_both
 	};
 
-#define  css_units_strings	_t("none;%;in;cm;mm;em;ex;pt;pc;px;dpi;dpcm;vw;vh;vmin;vmax;rem")
+#define  css_units_strings	"none;%;in;cm;mm;em;ex;pt;pc;px;dpi;dpcm;vw;vh;vmin;vmax;rem"
 
-	enum css_units
+	enum css_units : byte
 	{
 		css_units_none,
 		css_units_percentage,
@@ -379,7 +460,7 @@ namespace litehtml
 		css_units_rem,
 	};
 
-#define  background_attachment_strings	_t("scroll;fixed")
+#define  background_attachment_strings	"scroll;fixed"
 
 	enum background_attachment
 	{
@@ -387,7 +468,7 @@ namespace litehtml
 		background_attachment_fixed
 	};
 
-#define  background_repeat_strings	_t("repeat;repeat-x;repeat-y;no-repeat")
+#define  background_repeat_strings	"repeat;repeat-x;repeat-y;no-repeat"
 
 	enum background_repeat
 	{
@@ -397,7 +478,7 @@ namespace litehtml
 		background_repeat_no_repeat
 	};
 
-#define  background_box_strings	_t("border-box;padding-box;content-box")
+#define  background_box_strings	"border-box;padding-box;content-box"
 
 	enum background_box
 	{
@@ -406,7 +487,18 @@ namespace litehtml
 		background_box_content
 	};
 
-#define element_position_strings	_t("static;relative;absolute;fixed")
+#define  background_position_strings	"top;bottom;left;right;center"
+
+	enum background_position
+	{
+		background_position_top,
+		background_position_bottom,
+		background_position_left,
+		background_position_right,
+		background_position_center,
+	};
+
+#define element_position_strings	"static;relative;absolute;fixed"
 
 	enum element_position
 	{
@@ -416,7 +508,7 @@ namespace litehtml
 		element_position_fixed,
 	};
 
-#define text_align_strings		_t("left;right;center;justify")
+#define text_align_strings		"left;right;center;justify"
 
 	enum text_align
 	{
@@ -426,7 +518,7 @@ namespace litehtml
 		text_align_justify
 	};
 
-#define text_transform_strings		_t("none;capitalize;uppercase;lowercase")
+#define text_transform_strings		"none;capitalize;uppercase;lowercase"
 
 	enum text_transform
 	{
@@ -436,7 +528,7 @@ namespace litehtml
 		text_transform_lowercase
 	};
 
-#define white_space_strings		_t("normal;nowrap;pre;pre-line;pre-wrap")
+#define white_space_strings		"normal;nowrap;pre;pre-line;pre-wrap"
 
 	enum white_space
 	{
@@ -447,7 +539,7 @@ namespace litehtml
 		white_space_pre_wrap
 	};
 
-#define overflow_strings		_t("visible;hidden;scroll;auto;no-display;no-content")
+#define overflow_strings		"visible;hidden;scroll;auto;no-display;no-content"
 
 	enum overflow
 	{
@@ -459,7 +551,7 @@ namespace litehtml
 		overflow_no_content
 	};
 
-#define background_size_strings		_t("auto;cover;contain")
+#define background_size_strings		"auto;cover;contain"
 
 	enum background_size
 	{
@@ -468,7 +560,7 @@ namespace litehtml
 		background_size_contain,
 	};
 
-#define visibility_strings			_t("visible;hidden;collapse")
+#define visibility_strings			"visible;hidden;collapse"
 
 	enum visibility
 	{
@@ -477,7 +569,7 @@ namespace litehtml
 		visibility_collapse,
 	};
 
-#define border_collapse_strings		_t("collapse;separate")
+#define border_collapse_strings		"collapse;separate"
 
 	enum border_collapse
 	{
@@ -485,26 +577,7 @@ namespace litehtml
 		border_collapse_separate,
 	};
 
-
-#define pseudo_class_strings		_t("only-child;only-of-type;first-child;first-of-type;last-child;last-of-type;nth-child;nth-of-type;nth-last-child;nth-last-of-type;not;lang")
-
-	enum pseudo_class
-	{
-		pseudo_class_only_child,
-		pseudo_class_only_of_type,
-		pseudo_class_first_child,
-		pseudo_class_first_of_type,
-		pseudo_class_last_child,
-		pseudo_class_last_of_type,
-		pseudo_class_nth_child,
-		pseudo_class_nth_of_type,
-		pseudo_class_nth_last_child,
-		pseudo_class_nth_last_of_type,
-		pseudo_class_not,
-		pseudo_class_lang,
-	};
-
-#define content_property_string		_t("none;normal;open-quote;close-quote;no-open-quote;no-close-quote")
+#define content_property_string		"none;normal;open-quote;close-quote;no-open-quote;no-close-quote"
 
 	enum content_property
 	{
@@ -516,15 +589,15 @@ namespace litehtml
 		content_property_no_close_quote,
 	};
 
+	class render_item;
 
 	struct floated_box
 	{
-		typedef std::vector<floated_box>	vector;
-
-		position		pos;
-		element_float	float_side;
-		element_clear	clear_floats;
-		std::shared_ptr<element>	el;
+		position		                pos;
+		element_float	                float_side;
+		element_clear	                clear_floats;
+		std::shared_ptr<render_item>	el;
+		int								context;
 
 		floated_box() = default;
 		floated_box(const floated_box& val)
@@ -533,6 +606,7 @@ namespace litehtml
 			float_side = val.float_side;
 			clear_floats = val.clear_floats;
 			el = val.el;
+			context = val.context;
 		}
 		floated_box& operator=(const floated_box& val)
 		{
@@ -540,6 +614,7 @@ namespace litehtml
 			float_side = val.float_side;
 			clear_floats = val.clear_floats;
 			el = val.el;
+			context = val.context;
 			return *this;
 		}
 		floated_box(floated_box&& val)
@@ -548,6 +623,7 @@ namespace litehtml
 			float_side = val.float_side;
 			clear_floats = val.clear_floats;
 			el = std::move(val.el);
+			context = val.context;
 		}
 		void operator=(floated_box&& val)
 		{
@@ -555,6 +631,7 @@ namespace litehtml
 			float_side = val.float_side;
 			clear_floats = val.clear_floats;
 			el = std::move(val.el);
+			context = val.context;
 		}
 	};
 
@@ -627,7 +704,7 @@ namespace litehtml
 	};
 
 
-#define media_orientation_strings		_t("portrait;landscape")
+#define media_orientation_strings		"portrait;landscape"
 
 	enum media_orientation
 	{
@@ -635,7 +712,7 @@ namespace litehtml
 		media_orientation_landscape,
 	};
 
-#define media_feature_strings		_t("none;width;min-width;max-width;height;min-height;max-height;device-width;min-device-width;max-device-width;device-height;min-device-height;max-device-height;orientation;aspect-ratio;min-aspect-ratio;max-aspect-ratio;device-aspect-ratio;min-device-aspect-ratio;max-device-aspect-ratio;color;min-color;max-color;color-index;min-color-index;max-color-index;monochrome;min-monochrome;max-monochrome;resolution;min-resolution;max-resolution")
+#define media_feature_strings		"none;width;min-width;max-width;height;min-height;max-height;device-width;min-device-width;max-device-width;device-height;min-device-height;max-device-height;orientation;aspect-ratio;min-aspect-ratio;max-aspect-ratio;device-aspect-ratio;min-device-aspect-ratio;max-device-aspect-ratio;color;min-color;max-color;color-index;min-color-index;max-color-index;monochrome;min-monochrome;max-monochrome;resolution;min-resolution;max-resolution"
 
 	enum media_feature
 	{
@@ -684,7 +761,7 @@ namespace litehtml
 		media_feature_max_resolution,
 	};
 
-#define box_sizing_strings		_t("content-box;border-box")
+#define box_sizing_strings		"content-box;border-box"
 
 	enum box_sizing
 	{
@@ -693,7 +770,7 @@ namespace litehtml
 	};
 
 
-#define media_type_strings		_t("none;all;screen;print;braille;embossed;handheld;projection;speech;tty;tv")
+#define media_type_strings		"none;all;screen;print;braille;embossed;handheld;projection;speech;tty;tv"
 
 	enum media_type
 	{
@@ -721,6 +798,19 @@ namespace litehtml
 		int			color_index;	// The number of entries in the color lookup table of the output device. If the device does not use a color lookup table, the value is zero.
 		int			monochrome;		// The number of bits per pixel in a monochrome frame buffer. If the device is not a monochrome device, the output device value will be 0.
 		int			resolution;		// The resolution of the output device (in DPI)
+
+		media_features()
+		{
+			type = media_type::media_type_none,
+			width =0;
+			height = 0;
+			device_width = 0;
+			device_height = 0;
+			color = 0;
+			color_index = 0;
+			monochrome = 0;
+			resolution = 0;
+		}
 	};
 
 	enum render_type
@@ -731,7 +821,84 @@ namespace litehtml
 	};
 
 	// List of the Void Elements (can't have any contents)
-	const litehtml::tchar_t* const void_elements = _t("area;base;br;col;command;embed;hr;img;input;keygen;link;meta;param;source;track;wbr");
+	const char* const void_elements = "area;base;br;col;command;embed;hr;img;input;keygen;link;meta;param;source;track;wbr";
+
+#define flex_direction_strings		"row;row-reverse;column;column-reverse"
+
+	enum flex_direction
+	{
+		flex_direction_row,
+		flex_direction_row_reverse,
+		flex_direction_column,
+		flex_direction_column_reverse
+	};
+
+#define flex_wrap_strings		"nowrap;wrap;wrap-reverse"
+
+	enum flex_wrap
+	{
+		flex_wrap_nowrap,
+		flex_wrap_wrap,
+		flex_wrap_wrap_reverse
+	};
+
+#define flex_justify_content_strings		"flex-start;flex-end;center;space-between;space-around"
+
+	enum flex_justify_content
+	{
+		flex_justify_content_flex_start,
+		flex_justify_content_flex_end,
+		flex_justify_content_center,
+		flex_justify_content_space_between,
+		flex_justify_content_space_around
+	};
+
+#define flex_align_items_strings		"flex-start;flex-end;center;baseline;stretch"
+
+	enum flex_align_items
+	{
+		flex_align_items_flex_start,
+		flex_align_items_flex_end,
+		flex_align_items_center,
+		flex_align_items_baseline,
+		flex_align_items_stretch
+	};
+
+#define flex_align_self_strings		"auto;flex-start;flex-end;center;baseline;stretch"
+
+	enum flex_align_self
+	{
+		flex_align_self_auto,
+		flex_align_self_flex_start,
+		flex_align_self_flex_end,
+		flex_align_self_center,
+		flex_align_self_baseline,
+		flex_align_self_stretch
+	};
+
+#define flex_align_content_strings		"flex-start;flex-end;center;space-between;space-around;stretch"
+
+	enum flex_align_content
+	{
+		flex_align_content_flex_start,
+		flex_align_content_flex_end,
+		flex_align_content_center,
+		flex_align_content_space_between,
+		flex_align_content_space_around,
+		flex_align_content_stretch
+	};
+
+#define flex_basis_strings		"auto;content;fit-content;min-content;max-content"
+
+	enum flex_basis
+	{
+		flex_basis_auto,
+		flex_basis_content,
+		flex_basis_fit_content,
+		flex_basis_min_content,
+		flex_basis_max_content,
+	};
+
 }
 
 #endif  // LH_TYPES_H
diff --git a/src/plugins/litehtml_viewer/litehtml/url.cpp b/src/plugins/litehtml_viewer/litehtml/url.cpp
new file mode 100644
index 000000000..13076e338
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/url.cpp
@@ -0,0 +1,163 @@
+// Copyright (C) 2020-2021 Primate Labs Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the names of the copyright holders nor the names of their
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "url.h"
+
+#include <iostream>
+#include <sstream>
+#include <algorithm>
+
+#include "codepoint.h"
+#include "url_path.h"
+
+namespace litehtml {
+
+url::url(const string& str)
+: str_(str)
+{
+    // TODO: Rewrite using tstring_view to avoid unnecessary allocations.
+    string tmp = str_;
+
+    // Does the URL include a scheme?
+    size_t offset = tmp.find(':');
+    if (offset != string::npos) {
+        bool valid_scheme = true;
+        for (size_t i = 0; i < offset; i++) {
+            if (!is_url_scheme_codepoint(tmp[i])) {
+                valid_scheme = false;
+                break;
+            }
+        }
+        if (valid_scheme) {
+            scheme_ = tmp.substr(0, offset);
+            tmp = tmp.substr(offset + 1);
+        }
+    }
+
+    // Does the URL include an authority?  An authority component is preceded
+    // by a double slash ("//") and is terminated by the next slash ("/"),
+    // question mark ("?"), number sign ("#"), or the end of the URL.
+
+    if (tmp.size() >= 2 && tmp[0] == '/' && tmp[1] == '/') {
+        tmp = tmp.substr(2);
+        offset = tmp.size();
+        offset = std::min(offset, tmp.find('/'));
+        offset = std::min(offset, tmp.find('?'));
+        offset = std::min(offset, tmp.find('#'));
+        authority_ = tmp.substr(0, offset);
+        tmp = tmp.substr(offset);
+
+        // TODO: Parse the network location into host and port?
+    }
+
+    // Does the URL include a fragment?
+    offset = tmp.find('#');
+    if (offset != string::npos) {
+        fragment_ = tmp.substr(offset + 1);
+        tmp = tmp.substr(0, offset);
+    }
+
+    // Does the URL include a query?
+    offset = tmp.find('?');
+    if (offset != string::npos) {
+        query_ = tmp.substr(offset + 1);
+        tmp = tmp.substr(0, offset);
+    }
+
+    // Whatever remains of the URL after removing the scheme, the network
+    // location, the query, and the fragment is the path.
+    path_ = tmp;
+}
+
+url::url(const string& scheme,
+    const string& authority,
+    const string& path,
+    const string& query,
+    const string& fragment)
+: scheme_(scheme)
+, authority_(authority)
+, path_(path)
+, query_(query)
+, fragment_(fragment)
+{
+    std::stringstream tss;
+
+    if (!scheme_.empty()) {
+        tss << scheme_ << ":";
+    }
+    if (!authority_.empty()) {
+        tss << "//" << authority_;
+    }
+    if (!path_.empty()) {
+        tss << path_;
+    }
+    if (!query_.empty()) {
+        tss << "?" << query_;
+    }
+    if (!fragment_.empty()) {
+        tss << "#" << fragment_;
+    }
+    str_ = tss.str();
+}
+
+url resolve(const url& b, const url& r)
+{
+    // The resolution algorithm roughly follows the resolution algorithm
+    // outlined in Section 5.2 (in particular Section 5.2.2) of RFC 3986.  The
+    // major difference between the resolution algorithm and resolve() is that
+    // resolve() does not attempt to normalize the path components.
+
+    if (r.has_scheme()) {
+        return r;
+    } else if (r.has_authority()) {
+        return url(b.scheme(), r.authority(), r.path(), r.query(), r.fragment());
+    } else if (r.has_path()) {
+
+        // The relative URL path is either an absolute path or a relative
+        // path. If it is an absolute path, build the URL using only the
+        // relative path.  If it is a relative path, resolve the relative path
+        // against the base path and build the URL using the resolved path.
+
+        if (is_url_path_absolute(r.path())) {
+            return url(b.scheme(), b.authority(), r.path(), r.query(), r.fragment());
+        } else {
+            string path = url_path_resolve(b.path(), r.path());
+            return url(b.scheme(), b.authority(), path, r.query(), r.fragment());
+        }
+
+    } else if (r.has_query()) {
+        return url(b.scheme(), b.authority(), b.path(), r.query(), r.fragment());
+    } else {
+        // The resolved URL never includes the base URL fragment (i.e., it
+        // always includes the reference URL fragment).
+        return url(b.scheme(), b.authority(), b.path(), b.query(), r.fragment());
+    }
+}
+
+} // namespace litehtml
diff --git a/src/plugins/litehtml_viewer/litehtml/url.h b/src/plugins/litehtml_viewer/litehtml/url.h
new file mode 100644
index 000000000..bd0cdc63c
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/url.h
@@ -0,0 +1,139 @@
+// Copyright (C) 2020-2021 Primate Labs Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the names of the copyright holders nor the names of their
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef LITEHTML_URL_H__
+#define LITEHTML_URL_H__
+
+#include <ostream>
+
+#include "os_types.h"
+
+// https://datatracker.ietf.org/doc/html/rfc3986
+
+namespace litehtml {
+
+class url {
+public:
+    url() = default;
+
+    explicit url(const string& str);
+
+    url(const string& scheme,
+        const string& authority,
+        const string& path,
+        const string& query,
+        const string& fragment);
+
+    const string& str() const
+    {
+        return str_;
+    }
+
+    const string& scheme() const
+    {
+        return scheme_;
+    }
+
+    bool has_scheme() const
+    {
+        return !scheme_.empty();
+    }
+
+    const string& authority() const
+    {
+        return authority_;
+    }
+
+    bool has_authority() const
+    {
+        return !authority_.empty();
+    }
+
+    const string& path() const
+    {
+        return path_;
+    }
+
+    bool has_path() const
+    {
+        return !path_.empty();
+    }
+
+    const string& query() const
+    {
+        return query_;
+    }
+
+    bool has_query() const
+    {
+        return !query_.empty();
+    }
+
+    const string& fragment() const
+    {
+        return fragment_;
+    }
+
+    bool has_fragment() const
+    {
+        return !fragment_.empty();
+    }
+
+protected:
+    string str_;
+
+    // Assume URLs are relative by default.  See RFC 3986 Section 4.3 for
+    // information on which URLs are considered relative and which URLs are
+    // considered absolute:
+    //
+    //   https://datatracker.ietf.org/doc/html/rfc3986#section-4.3
+
+    bool absolute_ = false;
+
+    string scheme_;
+
+    string authority_;
+
+    string path_;
+
+    string query_;
+
+    string fragment_;
+};
+
+// Returns a URL that is resolved from the reference URL that might be
+// relative to the base URL.  For example, given <https://www.twitter.com/> as
+// the base URL and </foo> as the relative URL, resolve() will return the URL
+// <https://www.twitter.com/foo>.
+
+url resolve(const url& base, const url& reference);
+
+} // namespace litehtml
+
+#endif // LITEHTML_URL_H__
diff --git a/src/plugins/litehtml_viewer/litehtml/url_path.cpp b/src/plugins/litehtml_viewer/litehtml/url_path.cpp
new file mode 100644
index 000000000..da8620251
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/url_path.cpp
@@ -0,0 +1,86 @@
+// Copyright (C) 2020-2021 Primate Labs Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the names of the copyright holders nor the names of their
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "url_path.h"
+
+namespace litehtml {
+
+bool is_url_path_absolute(const string& path)
+{
+    return path.length() > 0 && path[0] == '/';
+}
+
+string url_path_directory_name(const string& path)
+{
+    size_t offset = path.find_last_of('/');
+    if (offset == string::npos) {
+        return ".";
+    } else {
+        return path.substr(0, offset + 1);
+    }
+}
+
+string url_path_base_name(const string& path)
+{
+    size_t offset = path.find_last_of('/');
+    if (offset == string::npos) {
+        return path;
+    } else {
+        return path.substr(offset + 1);
+    }
+}
+
+string url_path_append(const string& base, const string& path)
+{
+    string result(base);
+
+    // Only append a separator if both base and path are not empty and if the
+    // last character of base is not already a separator.
+    if (!result.empty() && !path.empty() && result.back() != '/') {
+        result.append(1, '/');
+    }
+
+    result.append(path);
+
+    return result;
+}
+
+string url_path_resolve(const string& base, const string& path)
+{
+
+    // If the possibly relative path is an absolute path then it is not
+    // relative and the base path is irrelevant.
+    if (is_url_path_absolute(path)) {
+        return path;
+    }
+
+    return url_path_append(url_path_directory_name(base), path);
+}
+
+} // namespace litehtml
diff --git a/src/plugins/litehtml_viewer/litehtml/url_path.h b/src/plugins/litehtml_viewer/litehtml/url_path.h
new file mode 100644
index 000000000..6b102139d
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/url_path.h
@@ -0,0 +1,51 @@
+// Copyright (C) 2020-2021 Primate Labs Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the names of the copyright holders nor the names of their
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef LITEHTML_URL_PATH_H__
+#define LITEHTML_URL_PATH_H__
+
+#include <ostream>
+
+#include "os_types.h"
+
+namespace litehtml {
+
+bool is_url_path_absolute(const string& path);
+
+string url_path_directory_name(const string& path);
+
+string url_path_base_name(const string& path);
+
+string url_path_append(const string& base, const string& path);
+
+string url_path_resolve(const string& base, const string& path);
+
+} // namespace litehtml
+
+#endif // LITEHTML_URL_PATH_H__
diff --git a/src/plugins/litehtml_viewer/litehtml/utf8_strings.cpp b/src/plugins/litehtml_viewer/litehtml/utf8_strings.cpp
index 3cebc73dc..787af86f4 100644
--- a/src/plugins/litehtml_viewer/litehtml/utf8_strings.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/utf8_strings.cpp
@@ -5,6 +5,8 @@
 litehtml::utf8_to_wchar::utf8_to_wchar(const char* val)
 {
 	m_utf8 = (const byte*) val;
+	if (!m_utf8) return;
+
 	while (true)
 	{
 		ucode_t wch = get_char();
diff --git a/src/plugins/litehtml_viewer/litehtml/utf8_strings.h b/src/plugins/litehtml_viewer/litehtml/utf8_strings.h
index c5b24217b..72969fd3d 100644
--- a/src/plugins/litehtml_viewer/litehtml/utf8_strings.h
+++ b/src/plugins/litehtml_viewer/litehtml/utf8_strings.h
@@ -1,6 +1,9 @@
 #ifndef LH_UTF8_STRINGS_H
 #define LH_UTF8_STRINGS_H
 
+#include "os_types.h"
+#include "types.h"
+
 namespace litehtml
 {
 	class utf8_to_wchar
@@ -42,15 +45,8 @@ namespace litehtml
 		}
 	};
 
-#ifdef LITEHTML_UTF8
-#define litehtml_from_utf8(str)		str
-#define litehtml_to_utf8(str)		str
 #define litehtml_from_wchar(str)	litehtml::wchar_to_utf8(str)
-#else
-#define litehtml_from_utf8(str)		litehtml::utf8_to_wchar(str)
-#define litehtml_from_wchar(str)	str
-#define litehtml_to_utf8(str)		litehtml::wchar_to_utf8(str)
-#endif
+#define litehtml_to_wchar(str)		litehtml::utf8_to_wchar(str)
 }
 
 #endif  // LH_UTF8_STRINGS_H
diff --git a/src/plugins/litehtml_viewer/litehtml/web_color.cpp b/src/plugins/litehtml_viewer/litehtml/web_color.cpp
index 39ce2d7f0..78b201fac 100644
--- a/src/plugins/litehtml_viewer/litehtml/web_color.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/web_color.cpp
@@ -1,171 +1,176 @@
 #include "html.h"
 #include "web_color.h"
-#include <string.h>
+#include <cstring>
+
+const litehtml::web_color litehtml::web_color::transparent = web_color(0, 0, 0, 0);
+const litehtml::web_color litehtml::web_color::black       = web_color(0, 0, 0, 255);
+const litehtml::web_color litehtml::web_color::white       = web_color(255, 255, 255, 255);
 
 litehtml::def_color litehtml::g_def_colors[] = 
 {
-	{_t("transparent"),_t("rgba(0, 0, 0, 0)")},
-	{_t("AliceBlue"),_t("#F0F8FF")},
-	{_t("AntiqueWhite"),_t("#FAEBD7")},
-	{_t("Aqua"),_t("#00FFFF")},
-	{_t("Aquamarine"),_t("#7FFFD4")},
-	{_t("Azure"),_t("#F0FFFF")},
-	{_t("Beige"),_t("#F5F5DC")},
-	{_t("Bisque"),_t("#FFE4C4")},
-	{_t("Black"),_t("#000000")},
-	{_t("BlanchedAlmond"),_t("#FFEBCD")},
-	{_t("Blue"),_t("#0000FF")},
-	{_t("BlueViolet"),_t("#8A2BE2")},
-	{_t("Brown"),_t("#A52A2A")},
-	{_t("BurlyWood"),_t("#DEB887")},
-	{_t("CadetBlue"),_t("#5F9EA0")},
-	{_t("Chartreuse"),_t("#7FFF00")},
-	{_t("Chocolate"),_t("#D2691E")},
-	{_t("Coral"),_t("#FF7F50")},
-	{_t("CornflowerBlue"),_t("#6495ED")},
-	{_t("Cornsilk"),_t("#FFF8DC")},
-	{_t("Crimson"),_t("#DC143C")},
-	{_t("Cyan"),_t("#00FFFF")},
-	{_t("DarkBlue"),_t("#00008B")},
-	{_t("DarkCyan"),_t("#008B8B")},
-	{_t("DarkGoldenRod"),_t("#B8860B")},
-	{_t("DarkGray"),_t("#A9A9A9")},
-	{_t("DarkGrey"),_t("#A9A9A9")},
-	{_t("DarkGreen"),_t("#006400")},
-	{_t("DarkKhaki"),_t("#BDB76B")},
-	{_t("DarkMagenta"),_t("#8B008B")},
-	{_t("DarkOliveGreen"),_t("#556B2F")},
-	{_t("Darkorange"),_t("#FF8C00")},
-	{_t("DarkOrchid"),_t("#9932CC")},
-	{_t("DarkRed"),_t("#8B0000")},
-	{_t("DarkSalmon"),_t("#E9967A")},
-	{_t("DarkSeaGreen"),_t("#8FBC8F")},
-	{_t("DarkSlateBlue"),_t("#483D8B")},
-	{_t("DarkSlateGray"),_t("#2F4F4F")},
-	{_t("DarkSlateGrey"),_t("#2F4F4F")},
-	{_t("DarkTurquoise"),_t("#00CED1")},
-	{_t("DarkViolet"),_t("#9400D3")},
-	{_t("DeepPink"),_t("#FF1493")},
-	{_t("DeepSkyBlue"),_t("#00BFFF")},
-	{_t("DimGray"),_t("#696969")},
-	{_t("DimGrey"),_t("#696969")},
-	{_t("DodgerBlue"),_t("#1E90FF")},
-	{_t("FireBrick"),_t("#B22222")},
-	{_t("FloralWhite"),_t("#FFFAF0")},
-	{_t("ForestGreen"),_t("#228B22")},
-	{_t("Fuchsia"),_t("#FF00FF")},
-	{_t("Gainsboro"),_t("#DCDCDC")},
-	{_t("GhostWhite"),_t("#F8F8FF")},
-	{_t("Gold"),_t("#FFD700")},
-	{_t("GoldenRod"),_t("#DAA520")},
-	{_t("Gray"),_t("#808080")},
-	{_t("Grey"),_t("#808080")},
-	{_t("Green"),_t("#008000")},
-	{_t("GreenYellow"),_t("#ADFF2F")},
-	{_t("HoneyDew"),_t("#F0FFF0")},
-	{_t("HotPink"),_t("#FF69B4")},
-	{_t("Ivory"),_t("#FFFFF0")},
-	{_t("Khaki"),_t("#F0E68C")},
-	{_t("Lavender"),_t("#E6E6FA")},
-	{_t("LavenderBlush"),_t("#FFF0F5")},
-	{_t("LawnGreen"),_t("#7CFC00")},
-	{_t("LemonChiffon"),_t("#FFFACD")},
-	{_t("LightBlue"),_t("#ADD8E6")},
-	{_t("LightCoral"),_t("#F08080")},
-	{_t("LightCyan"),_t("#E0FFFF")},
-	{_t("LightGoldenRodYellow"),_t("#FAFAD2")},
-	{_t("LightGray"),_t("#D3D3D3")},
-	{_t("LightGrey"),_t("#D3D3D3")},
-	{_t("LightGreen"),_t("#90EE90")},
-	{_t("LightPink"),_t("#FFB6C1")},
-	{_t("LightSalmon"),_t("#FFA07A")},
-	{_t("LightSeaGreen"),_t("#20B2AA")},
-	{_t("LightSkyBlue"),_t("#87CEFA")},
-	{_t("LightSlateGray"),_t("#778899")},
-	{_t("LightSlateGrey"),_t("#778899")},
-	{_t("LightSteelBlue"),_t("#B0C4DE")},
-	{_t("LightYellow"),_t("#FFFFE0")},
-	{_t("Lime"),_t("#00FF00")},
-	{_t("LimeGreen"),_t("#32CD32")},
-	{_t("Linen"),_t("#FAF0E6")},
-	{_t("Magenta"),_t("#FF00FF")},
-	{_t("Maroon"),_t("#800000")},
-	{_t("MediumAquaMarine"),_t("#66CDAA")},
-	{_t("MediumBlue"),_t("#0000CD")},
-	{_t("MediumOrchid"),_t("#BA55D3")},
-	{_t("MediumPurple"),_t("#9370D8")},
-	{_t("MediumSeaGreen"),_t("#3CB371")},
-	{_t("MediumSlateBlue"),_t("#7B68EE")},
-	{_t("MediumSpringGreen"),_t("#00FA9A")},
-	{_t("MediumTurquoise"),_t("#48D1CC")},
-	{_t("MediumVioletRed"),_t("#C71585")},
-	{_t("MidnightBlue"),_t("#191970")},
-	{_t("MintCream"),_t("#F5FFFA")},
-	{_t("MistyRose"),_t("#FFE4E1")},
-	{_t("Moccasin"),_t("#FFE4B5")},
-	{_t("NavajoWhite"),_t("#FFDEAD")},
-	{_t("Navy"),_t("#000080")},
-	{_t("OldLace"),_t("#FDF5E6")},
-	{_t("Olive"),_t("#808000")},
-	{_t("OliveDrab"),_t("#6B8E23")},
-	{_t("Orange"),_t("#FFA500")},
-	{_t("OrangeRed"),_t("#FF4500")},
-	{_t("Orchid"),_t("#DA70D6")},
-	{_t("PaleGoldenRod"),_t("#EEE8AA")},
-	{_t("PaleGreen"),_t("#98FB98")},
-	{_t("PaleTurquoise"),_t("#AFEEEE")},
-	{_t("PaleVioletRed"),_t("#D87093")},
-	{_t("PapayaWhip"),_t("#FFEFD5")},
-	{_t("PeachPuff"),_t("#FFDAB9")},
-	{_t("Peru"),_t("#CD853F")},
-	{_t("Pink"),_t("#FFC0CB")},
-	{_t("Plum"),_t("#DDA0DD")},
-	{_t("PowderBlue"),_t("#B0E0E6")},
-	{_t("Purple"),_t("#800080")},
-	{_t("Red"),_t("#FF0000")},
-	{_t("RosyBrown"),_t("#BC8F8F")},
-	{_t("RoyalBlue"),_t("#4169E1")},
-	{_t("SaddleBrown"),_t("#8B4513")},
-	{_t("Salmon"),_t("#FA8072")},
-	{_t("SandyBrown"),_t("#F4A460")},
-	{_t("SeaGreen"),_t("#2E8B57")},
-	{_t("SeaShell"),_t("#FFF5EE")},
-	{_t("Sienna"),_t("#A0522D")},
-	{_t("Silver"),_t("#C0C0C0")},
-	{_t("SkyBlue"),_t("#87CEEB")},
-	{_t("SlateBlue"),_t("#6A5ACD")},
-	{_t("SlateGray"),_t("#708090")},
-	{_t("SlateGrey"),_t("#708090")},
-	{_t("Snow"),_t("#FFFAFA")},
-	{_t("SpringGreen"),_t("#00FF7F")},
-	{_t("SteelBlue"),_t("#4682B4")},
-	{_t("Tan"),_t("#D2B48C")},
-	{_t("Teal"),_t("#008080")},
-	{_t("Thistle"),_t("#D8BFD8")},
-	{_t("Tomato"),_t("#FF6347")},
-	{_t("Turquoise"),_t("#40E0D0")},
-	{_t("Violet"),_t("#EE82EE")},
-	{_t("Wheat"),_t("#F5DEB3")},
-	{_t("White"),_t("#FFFFFF")},
-	{_t("WhiteSmoke"),_t("#F5F5F5")},
-	{_t("Yellow"),_t("#FFFF00")},
-	{_t("YellowGreen"),_t("#9ACD32")},
-	{0,0}
+	{"transparent","rgba(0, 0, 0, 0)"},
+	{"AliceBlue","#F0F8FF"},
+	{"AntiqueWhite","#FAEBD7"},
+	{"Aqua","#00FFFF"},
+	{"Aquamarine","#7FFFD4"},
+	{"Azure","#F0FFFF"},
+	{"Beige","#F5F5DC"},
+	{"Bisque","#FFE4C4"},
+	{"Black","#000000"},
+	{"BlanchedAlmond","#FFEBCD"},
+	{"Blue","#0000FF"},
+	{"BlueViolet","#8A2BE2"},
+	{"Brown","#A52A2A"},
+	{"BurlyWood","#DEB887"},
+	{"CadetBlue","#5F9EA0"},
+	{"Chartreuse","#7FFF00"},
+	{"Chocolate","#D2691E"},
+	{"Coral","#FF7F50"},
+	{"CornflowerBlue","#6495ED"},
+	{"Cornsilk","#FFF8DC"},
+	{"Crimson","#DC143C"},
+	{"Cyan","#00FFFF"},
+	{"DarkBlue","#00008B"},
+	{"DarkCyan","#008B8B"},
+	{"DarkGoldenRod","#B8860B"},
+	{"DarkGray","#A9A9A9"},
+	{"DarkGrey","#A9A9A9"},
+	{"DarkGreen","#006400"},
+	{"DarkKhaki","#BDB76B"},
+	{"DarkMagenta","#8B008B"},
+	{"DarkOliveGreen","#556B2F"},
+	{"Darkorange","#FF8C00"},
+	{"DarkOrchid","#9932CC"},
+	{"DarkRed","#8B0000"},
+	{"DarkSalmon","#E9967A"},
+	{"DarkSeaGreen","#8FBC8F"},
+	{"DarkSlateBlue","#483D8B"},
+	{"DarkSlateGray","#2F4F4F"},
+	{"DarkSlateGrey","#2F4F4F"},
+	{"DarkTurquoise","#00CED1"},
+	{"DarkViolet","#9400D3"},
+	{"DeepPink","#FF1493"},
+	{"DeepSkyBlue","#00BFFF"},
+	{"DimGray","#696969"},
+	{"DimGrey","#696969"},
+	{"DodgerBlue","#1E90FF"},
+	{"FireBrick","#B22222"},
+	{"FloralWhite","#FFFAF0"},
+	{"ForestGreen","#228B22"},
+	{"Fuchsia","#FF00FF"},
+	{"Gainsboro","#DCDCDC"},
+	{"GhostWhite","#F8F8FF"},
+	{"Gold","#FFD700"},
+	{"GoldenRod","#DAA520"},
+	{"Gray","#808080"},
+	{"Grey","#808080"},
+	{"Green","#008000"},
+	{"GreenYellow","#ADFF2F"},
+	{"HoneyDew","#F0FFF0"},
+	{"HotPink","#FF69B4"},
+	{"Ivory","#FFFFF0"},
+	{"Khaki","#F0E68C"},
+	{"Lavender","#E6E6FA"},
+	{"LavenderBlush","#FFF0F5"},
+	{"LawnGreen","#7CFC00"},
+	{"LemonChiffon","#FFFACD"},
+	{"LightBlue","#ADD8E6"},
+	{"LightCoral","#F08080"},
+	{"LightCyan","#E0FFFF"},
+	{"LightGoldenRodYellow","#FAFAD2"},
+	{"LightGray","#D3D3D3"},
+	{"LightGrey","#D3D3D3"},
+	{"LightGreen","#90EE90"},
+	{"LightPink","#FFB6C1"},
+	{"LightSalmon","#FFA07A"},
+	{"LightSeaGreen","#20B2AA"},
+	{"LightSkyBlue","#87CEFA"},
+	{"LightSlateGray","#778899"},
+	{"LightSlateGrey","#778899"},
+	{"LightSteelBlue","#B0C4DE"},
+	{"LightYellow","#FFFFE0"},
+	{"Lime","#00FF00"},
+	{"LimeGreen","#32CD32"},
+	{"Linen","#FAF0E6"},
+	{"Magenta","#FF00FF"},
+	{"Maroon","#800000"},
+	{"MediumAquaMarine","#66CDAA"},
+	{"MediumBlue","#0000CD"},
+	{"MediumOrchid","#BA55D3"},
+	{"MediumPurple","#9370D8"},
+	{"MediumSeaGreen","#3CB371"},
+	{"MediumSlateBlue","#7B68EE"},
+	{"MediumSpringGreen","#00FA9A"},
+	{"MediumTurquoise","#48D1CC"},
+	{"MediumVioletRed","#C71585"},
+	{"MidnightBlue","#191970"},
+	{"MintCream","#F5FFFA"},
+	{"MistyRose","#FFE4E1"},
+	{"Moccasin","#FFE4B5"},
+	{"NavajoWhite","#FFDEAD"},
+	{"Navy","#000080"},
+	{"OldLace","#FDF5E6"},
+	{"Olive","#808000"},
+	{"OliveDrab","#6B8E23"},
+	{"Orange","#FFA500"},
+	{"OrangeRed","#FF4500"},
+	{"Orchid","#DA70D6"},
+	{"PaleGoldenRod","#EEE8AA"},
+	{"PaleGreen","#98FB98"},
+	{"PaleTurquoise","#AFEEEE"},
+	{"PaleVioletRed","#D87093"},
+	{"PapayaWhip","#FFEFD5"},
+	{"PeachPuff","#FFDAB9"},
+	{"Peru","#CD853F"},
+	{"Pink","#FFC0CB"},
+	{"Plum","#DDA0DD"},
+	{"PowderBlue","#B0E0E6"},
+	{"Purple","#800080"},
+	{"Red","#FF0000"},
+	{"RosyBrown","#BC8F8F"},
+	{"RoyalBlue","#4169E1"},
+	{"SaddleBrown","#8B4513"},
+	{"Salmon","#FA8072"},
+	{"SandyBrown","#F4A460"},
+	{"SeaGreen","#2E8B57"},
+	{"SeaShell","#FFF5EE"},
+	{"Sienna","#A0522D"},
+	{"Silver","#C0C0C0"},
+	{"SkyBlue","#87CEEB"},
+	{"SlateBlue","#6A5ACD"},
+	{"SlateGray","#708090"},
+	{"SlateGrey","#708090"},
+	{"Snow","#FFFAFA"},
+	{"SpringGreen","#00FF7F"},
+	{"SteelBlue","#4682B4"},
+	{"Tan","#D2B48C"},
+	{"Teal","#008080"},
+	{"Thistle","#D8BFD8"},
+	{"Tomato","#FF6347"},
+	{"Turquoise","#40E0D0"},
+	{"Violet","#EE82EE"},
+	{"Wheat","#F5DEB3"},
+	{"White","#FFFFFF"},
+	{"WhiteSmoke","#F5F5F5"},
+	{"Yellow","#FFFF00"},
+	{"YellowGreen","#9ACD32"},
+	{nullptr,nullptr}
 };
 
 
-litehtml::web_color litehtml::web_color::from_string(const tchar_t* str, litehtml::document_container* callback)
+litehtml::web_color litehtml::web_color::from_string(const string& _str, document_container* callback)
 {
-	if(!str || !str[0])
+	auto str = _str.c_str();
+	if(!str[0])
 	{
 		return web_color(0, 0, 0);
 	}
-	if(str[0] == _t('#'))
+	if(str[0] == '#')
 	{
-		tstring red		= _t("");
-		tstring green		= _t("");
-		tstring blue		= _t("");
-		if(t_strlen(str + 1) == 3)
+		string red;
+		string green;
+		string blue;
+		if(strlen(str + 1) == 3)
 		{
 			red		+= str[1];
 			red		+= str[1];
@@ -173,7 +178,7 @@ litehtml::web_color litehtml::web_color::from_string(const tchar_t* str, litehtm
 			green	+= str[2];
 			blue	+= str[3];
 			blue	+= str[3];
-		} else if(t_strlen(str + 1) == 6)
+		} else if(strlen(str + 1) == 6)
 		{
 			red		+= str[1];
 			red		+= str[2];
@@ -182,41 +187,41 @@ litehtml::web_color litehtml::web_color::from_string(const tchar_t* str, litehtm
 			blue	+= str[5];
 			blue	+= str[6];
 		}
-		tchar_t* sss = 0;
+		char* sss = nullptr;
 		web_color clr;
-		clr.red		= (byte) t_strtol(red.c_str(),	&sss, 16);
-		clr.green	= (byte) t_strtol(green.c_str(),	&sss, 16);
-		clr.blue	= (byte) t_strtol(blue.c_str(),	&sss, 16);
+		clr.red		= (byte) strtol(red.c_str(),	&sss, 16);
+		clr.green	= (byte) strtol(green.c_str(),	&sss, 16);
+		clr.blue	= (byte) strtol(blue.c_str(),	&sss, 16);
 		return clr;
-	} else if(!t_strncmp(str, _t("rgb"), 3))
+	} else if(!strncmp(str, "rgb", 3))
 	{
-		tstring s = str;
+		string s = str;
 
-		tstring::size_type pos = s.find_first_of(_t("("));
-		if(pos != tstring::npos)
+		string::size_type pos = s.find_first_of('(');
+		if(pos != string::npos)
 		{
 			s.erase(s.begin(), s.begin() + pos + 1);
 		}
-		pos = s.find_last_of(_t(")"));
-		if(pos != tstring::npos)
+		pos = s.find_last_of(')');
+		if(pos != string::npos)
 		{
 			s.erase(s.begin() + pos, s.end());
 		}
 
-		std::vector<tstring> tokens;
-		split_string(s, tokens, _t(", \t"));
+		std::vector<string> tokens;
+		split_string(s, tokens, ", \t");
 
 		web_color clr;
 
-		if(tokens.size() >= 1)	clr.red		= (byte) t_atoi(tokens[0].c_str());
-		if(tokens.size() >= 2)	clr.green	= (byte) t_atoi(tokens[1].c_str());
-		if(tokens.size() >= 3)	clr.blue	= (byte) t_atoi(tokens[2].c_str());
-		if(tokens.size() >= 4)	clr.alpha	= (byte) (t_strtod(tokens[3].c_str(), 0) * 255.0);
+		if(tokens.size() >= 1)	clr.red		= (byte) atoi(tokens[0].c_str());
+		if(tokens.size() >= 2)	clr.green	= (byte) atoi(tokens[1].c_str());
+		if(tokens.size() >= 3)	clr.blue	= (byte) atoi(tokens[2].c_str());
+		if(tokens.size() >= 4)	clr.alpha	= (byte) (t_strtod(tokens[3].c_str(), nullptr) * 255.0);
 
 		return clr;
 	} else
 	{
-		tstring rgb = resolve_name(str, callback);
+		string rgb = resolve_name(str, callback);
 		if(!rgb.empty())
 		{
 			return from_string(rgb.c_str(), callback);
@@ -225,32 +230,45 @@ litehtml::web_color litehtml::web_color::from_string(const tchar_t* str, litehtm
 	return web_color(0, 0, 0);
 }
 
-litehtml::tstring litehtml::web_color::resolve_name(const tchar_t* name, litehtml::document_container* callback)
+litehtml::string litehtml::web_color::resolve_name(const string& name, document_container* callback)
 {
 	for(int i=0; g_def_colors[i].name; i++)
 	{
-		if(!t_strcasecmp(name, g_def_colors[i].name))
+		if(!t_strcasecmp(name.c_str(), g_def_colors[i].name))
 		{
-            return std::move(litehtml::tstring(g_def_colors[i].rgb));
+            return g_def_colors[i].rgb;
 		}
 	}
     if (callback)
     {
-        litehtml::tstring clr = callback->resolve_color(name);
-        return std::move(clr);
+        string clr = callback->resolve_color(name);
+        return clr;
     }
-    return std::move(litehtml::tstring());
+	return "";
 }
 
-bool litehtml::web_color::is_color(const tchar_t* str)
+bool litehtml::web_color::is_color(const string& str, document_container* callback)
 {
-	if(!t_strncasecmp(str, _t("rgb"), 3) || str[0] == _t('#'))
+	if (!t_strncasecmp(str.c_str(), "rgb", 3) || str[0] == '#')
 	{
 		return true;
 	}
-    if (!t_isdigit(str[0]) && str[0] != _t('.'))
+    if (t_isalpha(str[0]) && resolve_name(str, callback) != "")
 	{
 		return true;
 	}
 	return false;
 }
+
+litehtml::string litehtml::web_color::to_string() const
+{
+    char str[9];
+    if(alpha)
+    {
+		t_snprintf(str, 9, "%02X%02X%02X%02X", red, green, blue, alpha);
+    } else
+    {
+		t_snprintf(str, 9, "%02X%02X%02X", red, green, blue);
+    }
+    return str;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/web_color.h b/src/plugins/litehtml_viewer/litehtml/web_color.h
index fa3b370b8..a42b416ca 100644
--- a/src/plugins/litehtml_viewer/litehtml/web_color.h
+++ b/src/plugins/litehtml_viewer/litehtml/web_color.h
@@ -5,56 +5,48 @@ namespace litehtml
 {
 	struct def_color
 	{
-		const tchar_t*	name;
-		const tchar_t*	rgb;
+		const char*	name;
+		const char*	rgb;
 	};
 
 	extern def_color g_def_colors[];
 
-    class document_container;
+	class document_container;
 
 	struct web_color
 	{
-		byte    blue;
-		byte    green;
-		byte    red;
-		byte    alpha;
+		byte	red;
+		byte	green;
+		byte	blue;
+		byte	alpha;
+
+		static const web_color transparent;
+		static const web_color black;
+		static const web_color white;
 
 		web_color(byte r, byte g, byte b, byte a = 255)
 		{
-			blue	= b;
-			green	= g;
 			red		= r;
+			green	= g;
+			blue	= b;
 			alpha	= a;
 		}
 
 		web_color()
 		{
-			blue	= 0;
-			green	= 0;
 			red		= 0;
+			green	= 0;
+			blue	= 0;
 			alpha	= 0xFF;
 		}
 
-		web_color(const web_color& val)
-		{
-			blue	= val.blue;
-			green	= val.green;
-			red		= val.red;
-			alpha	= val.alpha;
-		}
+		bool operator==(web_color color) const { return red == color.red && green == color.green && blue == color.blue && alpha == color.alpha; }
+		bool operator!=(web_color color) const { return !(*this == color); }
 
-		web_color& operator=(const web_color& val)
-		{
-			blue	= val.blue;
-			green	= val.green;
-			red		= val.red;
-			alpha	= val.alpha;
-			return *this;
-		}
-        static web_color            from_string(const tchar_t* str, litehtml::document_container* callback);
-		static litehtml::tstring    resolve_name(const tchar_t* name, litehtml::document_container* callback);
-        static bool                 is_color(const tchar_t* str);
+		string to_string() const;
+		static web_color	from_string(const string& str, document_container* callback);
+		static string		resolve_name(const string& name, document_container* callback);
+		static bool			is_color(const string& str, document_container* callback);
 	};
 }
 

-----------------------------------------------------------------------


hooks/post-receive
-- 
Claws Mail


More information about the Commits mailing list