[Commits] [SCM] claws branch, master, updated. 4.2.0-71-g2ab815a91

jonathan at claws-mail.org jonathan at claws-mail.org
Mon Mar 25 03:07:31 UTC 2024


The branch, master has been updated
       via  2ab815a9115fbad6b25f07c7e3b67ba1f79c4257 (commit)
      from  357c5342dd3e36a8a629929918dda7196e3f906d (commit)

Summary of changes:
 src/plugins/litehtml_viewer/container_linux.cpp    | 270 ++++++------
 src/plugins/litehtml_viewer/litehtml/Makefile.am   |   5 +-
 src/plugins/litehtml_viewer/litehtml/borders.h     |  30 ++
 .../litehtml_viewer/litehtml/css_properties.cpp    |  17 +-
 .../litehtml_viewer/litehtml/css_properties.h      |  25 +-
 .../litehtml_viewer/litehtml/el_before_after.cpp   |  13 +-
 src/plugins/litehtml_viewer/litehtml/element.cpp   | 127 ++++++
 src/plugins/litehtml_viewer/litehtml/element.h     |  15 +
 src/plugins/litehtml_viewer/litehtml/flex_item.cpp | 488 +++++++++++++++++++++
 src/plugins/litehtml_viewer/litehtml/flex_item.h   | 137 ++++++
 src/plugins/litehtml_viewer/litehtml/flex_line.cpp | 454 +++++++++++++++++++
 src/plugins/litehtml_viewer/litehtml/flex_line.h   |  56 +++
 src/plugins/litehtml_viewer/litehtml/html.cpp      |  17 +-
 src/plugins/litehtml_viewer/litehtml/html.h        |   6 +-
 src/plugins/litehtml_viewer/litehtml/html_tag.cpp  |  29 ++
 src/plugins/litehtml_viewer/litehtml/html_tag.h    |   5 +
 src/plugins/litehtml_viewer/litehtml/line_box.cpp  |  25 +-
 .../litehtml_viewer/litehtml/media_query.cpp       |   3 +-
 .../litehtml_viewer/litehtml/render_block.cpp      |  80 +++-
 .../litehtml/render_block_context.cpp              |  55 ++-
 .../litehtml/render_block_context.h                |   2 +
 .../litehtml_viewer/litehtml/render_flex.cpp       | 377 +++++++++++++++-
 src/plugins/litehtml_viewer/litehtml/render_flex.h |  29 +-
 .../litehtml_viewer/litehtml/render_image.cpp      |  17 +-
 .../litehtml_viewer/litehtml/render_inline.cpp     |   3 -
 .../litehtml_viewer/litehtml/render_inline.h       |  10 +-
 .../litehtml/render_inline_context.cpp             |  41 +-
 .../litehtml/render_inline_context.h               |   3 +-
 .../litehtml_viewer/litehtml/render_item.cpp       | 150 ++++---
 src/plugins/litehtml_viewer/litehtml/render_item.h |  53 ++-
 .../litehtml_viewer/litehtml/render_table.cpp      |   8 +-
 src/plugins/litehtml_viewer/litehtml/string_id.h   |   4 +
 src/plugins/litehtml_viewer/litehtml/style.cpp     | 118 +++--
 src/plugins/litehtml_viewer/litehtml/style.h       |   1 +
 src/plugins/litehtml_viewer/litehtml/types.h       | 135 ++++--
 35 files changed, 2425 insertions(+), 383 deletions(-)
 create mode 100644 src/plugins/litehtml_viewer/litehtml/flex_item.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/flex_item.h
 create mode 100644 src/plugins/litehtml_viewer/litehtml/flex_line.cpp
 create mode 100644 src/plugins/litehtml_viewer/litehtml/flex_line.h
 delete mode 100644 src/plugins/litehtml_viewer/litehtml/render_inline.cpp


- Log -----------------------------------------------------------------
commit 2ab815a9115fbad6b25f07c7e3b67ba1f79c4257
Author: Jonathan Boeing <jonathan at claws-mail.org>
Date:   Sun Mar 24 16:48:14 2024 -0700

    Update to LiteHTML v0.9

diff --git a/src/plugins/litehtml_viewer/container_linux.cpp b/src/plugins/litehtml_viewer/container_linux.cpp
index 498f90152..19d226202 100644
--- a/src/plugins/litehtml_viewer/container_linux.cpp
+++ b/src/plugins/litehtml_viewer/container_linux.cpp
@@ -382,6 +382,8 @@ void container_linux::draw_background( litehtml::uint_ptr hdc, const std::vector
 	{
 		const auto& bg = bgvec[i];
 
+		if(bg.image_size.height == 0 || bg.image_size.width == 0) continue;
+
 		cairo_rectangle(cr, bg.clip_box.x, bg.clip_box.y, bg.clip_box.width, bg.clip_box.height);
 		cairo_clip(cr);
 
@@ -513,57 +515,54 @@ void container_linux::draw_borders(litehtml::uint_ptr hdc, const litehtml::borde
 	{
 		set_color(cr, borders.right.color);
 
-		double r_top	= borders.radius.top_right_x;
-		double r_bottom	= borders.radius.bottom_right_x;
-
-		if(r_top)
+		if(borders.radius.top_right_x && borders.radius.top_right_y)
 		{
 			double end_angle	= 2 * M_PI;
 			double start_angle	= end_angle - M_PI / 2.0  / ((double) bdr_top / (double) bdr_right + 1);
 
 			add_path_arc(cr,
-				draw_pos.right() - r_top,
-				draw_pos.top() + r_top,
-				r_top - bdr_right,
-				r_top - bdr_right + (bdr_right - bdr_top),
-				end_angle,
-				start_angle, true);
+				         draw_pos.right() - borders.radius.top_right_x,
+						 draw_pos.top() + borders.radius.top_right_y,
+						 borders.radius.top_right_x - bdr_right,
+						 borders.radius.top_right_y - bdr_right + (bdr_right - bdr_top),
+						 end_angle,
+						 start_angle, true);
 
 			add_path_arc(cr,
-				draw_pos.right() - r_top,
-				draw_pos.top() + r_top,
-				r_top,
-				r_top,
-				start_angle,
-				end_angle, false);
+						 draw_pos.right() - borders.radius.top_right_x,
+						 draw_pos.top() + borders.radius.top_right_y,
+						 borders.radius.top_right_x,
+						 borders.radius.top_right_y,
+						 start_angle,
+						 end_angle, false);
 		} else
 		{
 			cairo_move_to(cr, draw_pos.right() - bdr_right, draw_pos.top() + bdr_top);
 			cairo_line_to(cr, draw_pos.right(), draw_pos.top());
 		}
 
-		if(r_bottom)
+		if(borders.radius.bottom_right_x && borders.radius.bottom_right_y)
 		{
-			cairo_line_to(cr, draw_pos.right(),	draw_pos.bottom() - r_bottom);
+			cairo_line_to(cr, draw_pos.right(),	draw_pos.bottom() - borders.radius.bottom_right_y);
 
 			double start_angle	= 0;
 			double end_angle	= start_angle + M_PI / 2.0  / ((double) bdr_bottom / (double) bdr_right + 1);
 
 			add_path_arc(cr,
-				draw_pos.right() - r_bottom,
-				draw_pos.bottom() - r_bottom,
-				r_bottom,
-				r_bottom,
-				start_angle,
-				end_angle, false);
+						 draw_pos.right() - borders.radius.bottom_right_x,
+						 draw_pos.bottom() - borders.radius.bottom_right_y,
+						 borders.radius.bottom_right_x,
+						 borders.radius.bottom_right_y,
+						 start_angle,
+						 end_angle, false);
 
 			add_path_arc(cr,
-				draw_pos.right() - r_bottom,
-				draw_pos.bottom() - r_bottom,
-				r_bottom - bdr_right,
-				r_bottom - bdr_right + (bdr_right - bdr_bottom),
-				end_angle,
-				start_angle, true);
+						 draw_pos.right() - borders.radius.bottom_right_x,
+						 draw_pos.bottom() - borders.radius.bottom_right_y,
+						 borders.radius.bottom_right_x - bdr_right,
+						 borders.radius.bottom_right_y - bdr_right + (bdr_right - bdr_bottom),
+						 end_angle,
+						 start_angle, true);
 		} else
 		{
 			cairo_line_to(cr, draw_pos.right(),	draw_pos.bottom());
@@ -578,57 +577,54 @@ void container_linux::draw_borders(litehtml::uint_ptr hdc, const litehtml::borde
 	{
 		set_color(cr, borders.bottom.color);
 
-		double r_left	= borders.radius.bottom_left_x;
-		double r_right	= borders.radius.bottom_right_x;
-
-		if(r_left)
+		if(borders.radius.bottom_left_x && borders.radius.bottom_left_y)
 		{
 			double start_angle	= M_PI / 2.0;
 			double end_angle	= start_angle + M_PI / 2.0  / ((double) bdr_left / (double) bdr_bottom + 1);
 
 			add_path_arc(cr,
-				draw_pos.left() + r_left,
-				draw_pos.bottom() - r_left,
-				r_left - bdr_bottom + (bdr_bottom - bdr_left),
-				r_left - bdr_bottom,
-				start_angle,
-				end_angle, false);
+						 draw_pos.left() + borders.radius.bottom_left_x,
+						 draw_pos.bottom() - borders.radius.bottom_left_y,
+						 borders.radius.bottom_left_x - bdr_bottom + (bdr_bottom - bdr_left),
+						 borders.radius.bottom_left_y - bdr_bottom,
+						 start_angle,
+						 end_angle, false);
 
 			add_path_arc(cr,
-				draw_pos.left() + r_left,
-				draw_pos.bottom() - r_left,
-				r_left,
-				r_left,
-				end_angle,
-				start_angle, true);
+						 draw_pos.left() + borders.radius.bottom_left_x,
+						 draw_pos.bottom() - borders.radius.bottom_left_y,
+						 borders.radius.bottom_left_x,
+						 borders.radius.bottom_left_y,
+						 end_angle,
+						 start_angle, true);
 		} else
 		{
 			cairo_move_to(cr, draw_pos.left(), draw_pos.bottom());
 			cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.bottom() - bdr_bottom);
 		}
 
-		if(r_right)
+		if(borders.radius.bottom_right_x && borders.radius.bottom_right_y)
 		{
-			cairo_line_to(cr, draw_pos.right() - r_right,	draw_pos.bottom());
+			cairo_line_to(cr, draw_pos.right() - borders.radius.bottom_right_x,	draw_pos.bottom());
 
 			double end_angle	= M_PI / 2.0;
 			double start_angle	= end_angle - M_PI / 2.0  / ((double) bdr_right / (double) bdr_bottom + 1);
 
 			add_path_arc(cr,
-				draw_pos.right() - r_right,
-				draw_pos.bottom() - r_right,
-				r_right,
-				r_right,
-				end_angle,
-				start_angle, true);
+						 draw_pos.right() - borders.radius.bottom_right_x,
+						 draw_pos.bottom() - borders.radius.bottom_right_y,
+						 borders.radius.bottom_right_x,
+						 borders.radius.bottom_right_y,
+						 end_angle,
+						 start_angle, true);
 
 			add_path_arc(cr,
-				draw_pos.right() - r_right,
-				draw_pos.bottom() - r_right,
-				r_right - bdr_bottom + (bdr_bottom - bdr_right),
-				r_right - bdr_bottom,
-				start_angle,
-				end_angle, false);
+						 draw_pos.right() - borders.radius.bottom_right_x,
+						 draw_pos.bottom() - borders.radius.bottom_right_y,
+						 borders.radius.bottom_right_x - bdr_bottom + (bdr_bottom - bdr_right),
+						 borders.radius.bottom_right_y - bdr_bottom,
+						 start_angle,
+						 end_angle, false);
 		} else
 		{
 			cairo_line_to(cr, draw_pos.right() - bdr_right,	draw_pos.bottom() - bdr_bottom);
@@ -643,57 +639,54 @@ void container_linux::draw_borders(litehtml::uint_ptr hdc, const litehtml::borde
 	{
 		set_color(cr, borders.top.color);
 
-		double r_left	= borders.radius.top_left_x;
-		double r_right	= borders.radius.top_right_x;
-
-		if(r_left)
+		if(borders.radius.top_left_x && borders.radius.top_left_y)
 		{
 			double end_angle	= M_PI * 3.0 / 2.0;
 			double start_angle	= end_angle - M_PI / 2.0  / ((double) bdr_left / (double) bdr_top + 1);
 
 			add_path_arc(cr,
-				draw_pos.left() + r_left,
-				draw_pos.top() + r_left,
-				r_left,
-				r_left,
-				end_angle,
-				start_angle, true);
+						 draw_pos.left() + borders.radius.top_left_x,
+						 draw_pos.top() + borders.radius.top_left_y,
+						 borders.radius.top_left_x,
+						 borders.radius.top_left_y,
+						 end_angle,
+						 start_angle, true);
 
 			add_path_arc(cr,
-				draw_pos.left() + r_left,
-				draw_pos.top() + r_left,
-				r_left - bdr_top + (bdr_top - bdr_left),
-				r_left - bdr_top,
-				start_angle,
-				end_angle, false);
+						 draw_pos.left() + borders.radius.top_left_x,
+						 draw_pos.top() + borders.radius.top_left_y,
+						 borders.radius.top_left_x - bdr_top + (bdr_top - bdr_left),
+						 borders.radius.top_left_y - bdr_top,
+						 start_angle,
+						 end_angle, false);
 		} else
 		{
 			cairo_move_to(cr, draw_pos.left(), draw_pos.top());
 			cairo_line_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
 		}
 
-		if(r_right)
+		if(borders.radius.top_right_x && borders.radius.top_right_y)
 		{
-			cairo_line_to(cr, draw_pos.right() - r_right,	draw_pos.top() + bdr_top);
+			cairo_line_to(cr, draw_pos.right() - borders.radius.top_right_x,	draw_pos.top() + bdr_top);
 
 			double start_angle	= M_PI * 3.0 / 2.0;
 			double end_angle	= start_angle + M_PI / 2.0  / ((double) bdr_right / (double) bdr_top + 1);
 
 			add_path_arc(cr,
-				draw_pos.right() - r_right,
-				draw_pos.top() + r_right,
-				r_right - bdr_top + (bdr_top - bdr_right),
-				r_right - bdr_top,
-				start_angle,
-				end_angle, false);
+						 draw_pos.right() - borders.radius.top_right_x,
+						 draw_pos.top() + borders.radius.top_right_y,
+						 borders.radius.top_right_x - bdr_top + (bdr_top - bdr_right),
+						 borders.radius.top_right_y - bdr_top,
+						 start_angle,
+						 end_angle, false);
 
 			add_path_arc(cr,
-				draw_pos.right() - r_right,
-				draw_pos.top() + r_right,
-				r_right,
-				r_right,
-				end_angle,
-				start_angle, true);
+						 draw_pos.right() - borders.radius.top_right_x,
+						 draw_pos.top() + borders.radius.top_right_y,
+						 borders.radius.top_right_x,
+						 borders.radius.top_right_y,
+						 end_angle,
+						 start_angle, true);
 		} else
 		{
 			cairo_line_to(cr, draw_pos.right() - bdr_right,	draw_pos.top() + bdr_top);
@@ -708,57 +701,54 @@ void container_linux::draw_borders(litehtml::uint_ptr hdc, const litehtml::borde
 	{
 		set_color(cr, borders.left.color);
 
-		double r_top	= borders.radius.top_left_x;
-		double r_bottom	= borders.radius.bottom_left_x;
-
-		if(r_top)
+		if(borders.radius.top_left_x && borders.radius.top_left_y)
 		{
 			double start_angle	= M_PI;
 			double end_angle	= start_angle + M_PI / 2.0  / ((double) bdr_top / (double) bdr_left + 1);
 
 			add_path_arc(cr,
-				draw_pos.left() + r_top,
-				draw_pos.top() + r_top,
-				r_top - bdr_left,
-				r_top - bdr_left + (bdr_left - bdr_top),
-				start_angle,
-				end_angle, false);
+						 draw_pos.left() + borders.radius.top_left_x,
+						 draw_pos.top() + borders.radius.top_left_y,
+						 borders.radius.top_left_x - bdr_left,
+						 borders.radius.top_left_y - bdr_left + (bdr_left - bdr_top),
+						 start_angle,
+						 end_angle, false);
 
 			add_path_arc(cr,
-				draw_pos.left() + r_top,
-				draw_pos.top() + r_top,
-				r_top,
-				r_top,
-				end_angle,
-				start_angle, true);
+						 draw_pos.left() + borders.radius.top_left_x,
+						 draw_pos.top() + borders.radius.top_left_y,
+						 borders.radius.top_left_x,
+						 borders.radius.top_left_y,
+						 end_angle,
+						 start_angle, true);
 		} else
 		{
 			cairo_move_to(cr, draw_pos.left() + bdr_left, draw_pos.top() + bdr_top);
 			cairo_line_to(cr, draw_pos.left(), draw_pos.top());
 		}
 
-		if(r_bottom)
+		if(borders.radius.bottom_left_x && borders.radius.bottom_left_y)
 		{
-			cairo_line_to(cr, draw_pos.left(),	draw_pos.bottom() - r_bottom);
+			cairo_line_to(cr, draw_pos.left(),	draw_pos.bottom() - borders.radius.bottom_left_y);
 
 			double end_angle	= M_PI;
 			double start_angle	= end_angle - M_PI / 2.0  / ((double) bdr_bottom / (double) bdr_left + 1);
 
 			add_path_arc(cr,
-				draw_pos.left() + r_bottom,
-				draw_pos.bottom() - r_bottom,
-				r_bottom,
-				r_bottom,
-				end_angle,
-				start_angle, true);
+						 draw_pos.left() + borders.radius.bottom_left_x,
+						 draw_pos.bottom() - borders.radius.bottom_left_y,
+						 borders.radius.bottom_left_x,
+						 borders.radius.bottom_left_y,
+						 end_angle,
+						 start_angle, true);
 
 			add_path_arc(cr,
-				draw_pos.left() + r_bottom,
-				draw_pos.bottom() - r_bottom,
-				r_bottom - bdr_left,
-				r_bottom - bdr_left + (bdr_left - bdr_bottom),
-				start_angle,
-				end_angle, false);
+						 draw_pos.left() + borders.radius.bottom_left_x,
+						 draw_pos.bottom() - borders.radius.bottom_left_y,
+						 borders.radius.bottom_left_x - bdr_left,
+						 borders.radius.bottom_left_y - bdr_left + (bdr_left - bdr_bottom),
+						 start_angle,
+						 end_angle, false);
 		} else
 		{
 			cairo_line_to(cr, draw_pos.left(),	draw_pos.bottom());
@@ -940,9 +930,15 @@ std::shared_ptr<litehtml::element>	container_linux::create_element(const char *t
 void container_linux::rounded_rectangle( cairo_t* cr, const litehtml::position &pos, const litehtml::border_radiuses &radius )
 {
 	cairo_new_path(cr);
-	if(radius.top_left_x)
+	if(radius.top_left_x && radius.top_left_y)
 	{
-		cairo_arc(cr, pos.left() + radius.top_left_x, pos.top() + radius.top_left_x, radius.top_left_x, M_PI, M_PI * 3.0 / 2.0);
+		add_path_arc(cr,
+			 pos.left() + radius.top_left_x,
+			 pos.top() + radius.top_left_y,
+			 radius.top_left_x,
+			 radius.top_left_y,
+			 M_PI,
+			 M_PI * 3.0 / 2.0, false);
 	} else
 	{
 		cairo_move_to(cr, pos.left(), pos.top());
@@ -950,23 +946,41 @@ void container_linux::rounded_rectangle( cairo_t* cr, const litehtml::position &
 
 	cairo_line_to(cr, pos.right() - radius.top_right_x, pos.top());
 
-	if(radius.top_right_x)
+	if(radius.top_right_x && radius.top_right_y)
 	{
-		cairo_arc(cr, pos.right() - radius.top_right_x, pos.top() + radius.top_right_x, radius.top_right_x, M_PI * 3.0 / 2.0, 2.0 * M_PI);
+		add_path_arc(cr,
+			 pos.right() - radius.top_right_x,
+			 pos.top() + radius.top_right_y,
+			 radius.top_right_x,
+			 radius.top_right_y,
+			 M_PI * 3.0 / 2.0,
+			 2.0 * M_PI, false);
 	}
 
 	cairo_line_to(cr, pos.right(), pos.bottom() - radius.bottom_right_x);
 
-	if(radius.bottom_right_x)
+	if(radius.bottom_right_x && radius.bottom_right_y)
 	{
-		cairo_arc(cr, pos.right() - radius.bottom_right_x, pos.bottom() - radius.bottom_right_x, radius.bottom_right_x, 0, M_PI / 2.0);
+		add_path_arc(cr,
+			 pos.right() - radius.bottom_right_x,
+			 pos.bottom() - radius.bottom_right_y,
+			 radius.bottom_right_x,
+			 radius.bottom_right_y,
+			 0,
+			 M_PI / 2.0, false);
 	}
 
 	cairo_line_to(cr, pos.left() - radius.bottom_left_x, pos.bottom());
 
-	if(radius.bottom_left_x)
+	if(radius.bottom_left_x && radius.bottom_left_y)
 	{
-		cairo_arc(cr, pos.left() + radius.bottom_left_x, pos.bottom() - radius.bottom_left_x, radius.bottom_left_x, M_PI / 2.0, M_PI);
+		add_path_arc(cr,
+			 pos.left() + radius.bottom_left_x,
+			 pos.bottom() - radius.bottom_left_y,
+			 radius.bottom_left_x,
+			 radius.bottom_left_y,
+			 M_PI / 2.0,
+			 M_PI, false);
 	}
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/Makefile.am b/src/plugins/litehtml_viewer/litehtml/Makefile.am
index e4b5ac94a..0429ffe22 100644
--- a/src/plugins/litehtml_viewer/litehtml/Makefile.am
+++ b/src/plugins/litehtml_viewer/litehtml/Makefile.am
@@ -76,6 +76,10 @@ liblitehtml_la_SOURCES = \
 	el_title.h \
 	el_tr.cpp \
 	el_tr.h \
+	flex_item.cpp \
+	flex_item.h \
+	flex_line.cpp \
+	flex_line.h \
 	formatting_context.cpp \
 	formatting_context.h \
 	html.cpp \
@@ -104,7 +108,6 @@ liblitehtml_la_SOURCES = \
 	render_image.h \
 	render_inline_context.cpp \
 	render_inline_context.h \
-	render_inline.cpp \
 	render_inline.h \
 	render_item.cpp \
 	render_item.h \
diff --git a/src/plugins/litehtml_viewer/litehtml/borders.h b/src/plugins/litehtml_viewer/litehtml/borders.h
index e690db6d3..9c47abca0 100644
--- a/src/plugins/litehtml_viewer/litehtml/borders.h
+++ b/src/plugins/litehtml_viewer/litehtml/borders.h
@@ -157,6 +157,35 @@ namespace litehtml
 			if (bottom_left_x < 0) bottom_left_x = 0;
 			if (bottom_left_y < 0) bottom_left_y = 0;
 		}
+		void fix_values(int width, int height)
+		{
+			fix_values();
+			int half_width = width / 2;
+			int half_height = height / 2;
+			auto fix_one = [&](int& radii_x, int& radii_y)
+				{
+					double factor = std::min((double) half_width / (double) radii_x, (double) half_height / (double) radii_y);
+					radii_x = (int) ((double) radii_x * factor);
+					radii_y = (int) ((double) radii_y * factor);
+				};
+
+			if(top_left_x > half_width || top_left_y > half_height)
+			{
+				fix_one(top_left_x, top_left_y);
+			}
+			if(top_right_x > half_width || top_right_y > half_height)
+			{
+				fix_one(top_right_x, top_right_y);
+			}
+			if(bottom_right_x > half_width || bottom_right_y > half_height)
+			{
+				fix_one(bottom_right_x, bottom_right_y);
+			}
+			if(bottom_left_x > half_width || bottom_left_y > half_height)
+			{
+				fix_one(bottom_left_x, bottom_left_y);
+			}
+		}
 	};
 
 	struct css_border_radius
@@ -213,6 +242,7 @@ namespace litehtml
 			ret.top_right_y = top_right_y.calc_percent(height);
 			ret.bottom_right_x = bottom_right_x.calc_percent(width);
 			ret.bottom_right_y = bottom_right_y.calc_percent(height);
+			ret.fix_values(width, height);
 			return ret;
 		}
 	};
diff --git a/src/plugins/litehtml_viewer/litehtml/css_properties.cpp b/src/plugins/litehtml_viewer/litehtml/css_properties.cpp
index 2696ae28f..a3b458ebf 100644
--- a/src/plugins/litehtml_viewer/litehtml/css_properties.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/css_properties.cpp
@@ -240,6 +240,8 @@ void litehtml::css_properties::compute(const element* el, const document::ptr& d
 		doc->container()->load_image(m_list_style_image.c_str(), m_list_style_image_baseurl.c_str(), true);
 	}
 
+	m_order = el->get_int_property(_order_, false, 0, offset(m_order));
+
 	compute_background(el, doc);
 	compute_flex(el, doc);
 }
@@ -391,22 +393,27 @@ void litehtml::css_properties::compute_background(const element* el, const docum
 
 void litehtml::css_properties::compute_flex(const element* el, const document::ptr& doc)
 {
-	if (m_display == display_flex)
+	if (m_display == display_flex || m_display == display_inline_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_items = (flex_align_items) el->get_enum_property(_align_items_, false, flex_align_items_flex_normal, 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));
 	}
+	m_flex_align_self = (flex_align_items) el->get_enum_property(_align_self_, false, flex_align_items_auto, offset(m_flex_align_self));
 	auto parent = el->parent();
-	if (parent && parent->css().m_display == display_flex)
+	if (parent && (parent->css().m_display == display_flex || parent->css().m_display == display_inline_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));
+		m_flex_basis = el->get_length_property(_flex_basis_, false, css_length::predef_value(flex_basis_auto), offset(m_flex_basis));
+		if(!m_flex_basis.is_predefined() && m_flex_basis.units() == css_units_none && m_flex_basis.val() != 0)
+		{
+			// flex-basis property must contain units
+			m_flex_basis.predef(flex_basis_auto);
+		}
 		doc->cvt_units(m_flex_basis, get_font_size());
 		if(m_display == display_inline || m_display == display_inline_block)
 		{
diff --git a/src/plugins/litehtml_viewer/litehtml/css_properties.h b/src/plugins/litehtml_viewer/litehtml/css_properties.h
index 739e35fc2..a5609a9b1 100644
--- a/src/plugins/litehtml_viewer/litehtml/css_properties.h
+++ b/src/plugins/litehtml_viewer/litehtml/css_properties.h
@@ -67,11 +67,13 @@ namespace litehtml
 		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_items		m_flex_align_self;
 		flex_align_content		m_flex_align_content;
 
 		caption_side			m_caption_side;
 
+		int 					m_order;
+
 	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);
@@ -119,8 +121,9 @@ namespace litehtml
 				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)
+				m_flex_align_self(flex_align_items_auto),
+				m_flex_align_content(flex_align_content_stretch),
+				m_order(0)
 		{}
 
 		void compute(const element* el, const std::shared_ptr<document>& doc);
@@ -250,8 +253,11 @@ namespace litehtml
 		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_items get_flex_align_self() const;
 		flex_align_content get_flex_align_content() const;
+
+		int get_order() const;
+		void set_order(int order);
 	};
 
 	inline element_position css_properties::get_position() const
@@ -634,7 +640,7 @@ namespace litehtml
 		return m_flex_align_items;
 	}
 
-	inline flex_align_self css_properties::get_flex_align_self() const
+	inline flex_align_items css_properties::get_flex_align_self() const
 	{
 		return m_flex_align_self;
 	}
@@ -653,6 +659,15 @@ namespace litehtml
 		m_caption_side = side;
 	}
 
+	inline int css_properties::get_order() const
+	{
+		return m_order;
+	}
+
+	inline void css_properties::set_order(int order)
+	{
+		m_order = order;
+	}
 }
 
 #endif //LITEHTML_CSS_PROPERTIES_H
diff --git a/src/plugins/litehtml_viewer/litehtml/el_before_after.cpp b/src/plugins/litehtml_viewer/litehtml/el_before_after.cpp
index 8c24eec98..c7c2d680b 100644
--- a/src/plugins/litehtml_viewer/litehtml/el_before_after.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/el_before_after.cpp
@@ -133,7 +133,7 @@ void litehtml::el_before_after_base::add_text( const string& txt )
 
 void litehtml::el_before_after_base::add_function( const string& fnc, const string& params )
 {
-	int idx = value_index(fnc, "attr;counter;url");
+	int idx = value_index(fnc, "attr;counter;counters;url");
 	switch(idx)
 	{
 	// attr
@@ -155,9 +155,18 @@ void litehtml::el_before_after_base::add_function( const string& fnc, const stri
 		break;
 	// counter
 	case 1:
+		add_text(get_counter_value(params));
 		break;
-	// url
+	// counters
 	case 2:
+		{
+			string_vector tokens;
+			split_string(params, tokens, ",");
+			add_text(get_counters_value(tokens));
+		}
+		break;
+	// url
+	case 3:
 		{
 			string p_url = params;
 			trim(p_url);
diff --git a/src/plugins/litehtml_viewer/litehtml/element.cpp b/src/plugins/litehtml_viewer/litehtml/element.cpp
index 1d0a509b1..16b4b5878 100644
--- a/src/plugins/litehtml_viewer/litehtml/element.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/element.cpp
@@ -274,8 +274,18 @@ element::ptr element::_add_before_after(int type, const style& style)
 
 bool element::is_block_formatting_context() const
 {
+	if(m_css.get_display() == display_block)
+	{
+		auto par = parent();
+		if(par && (par->css().get_display() == display_inline_flex || par->css().get_display() == display_flex))
+		{
+			return true;
+		}
+	}
 	if(	m_css.get_display() == display_inline_block ||
 		   m_css.get_display() == display_table_cell ||
+		   m_css.get_display() == display_inline_flex ||
+		   m_css.get_display() == display_flex ||
 		   m_css.get_display() == display_table_caption ||
 		   is_root() ||
 		   m_css.get_float() != float_none ||
@@ -288,6 +298,122 @@ bool element::is_block_formatting_context() const
 	return false;
 }
 
+litehtml::string litehtml::element::get_counter_value(const string& counter_name)
+{
+	std::map<string_id, int>::iterator i;
+	if (find_counter(_id(counter_name), i))
+	{
+		return std::to_string(i->second);
+	}
+	return "0";
+}
+
+string litehtml::element::get_counters_value(const string_vector& parameters)
+{
+	string result = "";
+	if (parameters.size() >= 2) {
+		const string_id counter_name_id = _id(parameters[0]);
+		string delims = parameters[1];
+		litehtml::trim(delims, "\"'");
+
+		string_vector values;
+		
+		element::ptr current = shared_from_this();
+		while (current != nullptr)
+		{
+			auto map_iterator = current->m_counter_values.find(counter_name_id);
+			if (map_iterator != current->m_counter_values.end()) {
+				values.push_back(std::to_string(map_iterator->second));
+			}
+			current = current->parent();
+		}
+		if (values.empty()) {
+			// if no counter is found, instanciate one with value '0'
+			shared_from_this()->m_counter_values[counter_name_id] = 0;
+			result = "0";
+		}
+		else {
+			std::reverse(values.begin(), values.end());
+			litehtml::join_string(result, values, delims);
+		}
+	}
+	return result;
+}
+
+
+bool litehtml::element::find_counter(const string_id& counter_name_id, std::map<string_id, int>::iterator& map_iterator) {
+	element::ptr current = shared_from_this();
+
+	while (current != nullptr)
+	{
+		map_iterator = current->m_counter_values.find(counter_name_id);
+		if (map_iterator != current->m_counter_values.end()) {
+			return true;
+		}
+
+		// on each level, search previous siblings too
+		std::vector<element::ptr> siblings = current->get_siblings_before();
+		std::reverse(siblings.begin(), siblings.end());
+		for (const element::ptr& sibling : siblings) {
+			map_iterator = sibling->m_counter_values.find(counter_name_id);
+			if (map_iterator != sibling->m_counter_values.end()) {
+				return true;
+			}
+		}
+		current = current->parent();
+	}
+	
+	return false;
+}
+
+std::vector<element::ptr> litehtml::element::get_siblings_before() const
+{
+	std::vector<element::ptr> siblings;
+	if (parent() != nullptr) {
+		for (const element::ptr& sybling : parent()->children()) {
+			if (sybling == shared_from_this()) {
+				break;
+			}
+			siblings.push_back(sybling);
+		}
+	}
+	return siblings;
+}
+
+
+void litehtml::element::parse_counter_tokens(const string_vector& tokens, const int default_value, std::function<void(const string_id&, const int)> handler) const {
+	int pos = 0;
+	while (pos < tokens.size()) {
+		string name = tokens[pos];
+		int value = default_value;
+		if (pos < tokens.size() - 1 && litehtml::is_number(tokens[pos + 1], 0)) {
+			value = atoi(tokens[pos + 1].c_str());
+			pos += 2;
+		}
+		else {
+			pos += 1;
+		}
+		handler(_id(name), value);
+	}
+}
+
+void litehtml::element::increment_counter(const string_id& counter_name_id, const int increment)
+{
+	std::map<string_id, int>::iterator i;
+	if (find_counter(counter_name_id, i)) {
+		i->second = i->second + increment;
+	}
+	else {
+		// if counter is not found, initialize one on this element
+		m_counter_values[counter_name_id] = increment;
+	}
+}
+
+void litehtml::element::reset_counter(const string_id& counter_name_id, const int value)
+{
+	m_counter_values[counter_name_id] = value;
+}
+
 const background* element::get_background(bool own_only)						LITEHTML_RETURN_FUNC(nullptr)
 void element::add_style( const style& style)	        						LITEHTML_EMPTY_FUNC
 void element::select_all(const css_selector& selector, elements_list& res)	LITEHTML_EMPTY_FUNC
@@ -332,6 +458,7 @@ 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)
+int				element::get_int_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("")
diff --git a/src/plugins/litehtml_viewer/litehtml/element.h b/src/plugins/litehtml_viewer/litehtml/element.h
index e330b5c01..4d244736b 100644
--- a/src/plugins/litehtml_viewer/litehtml/element.h
+++ b/src/plugins/litehtml_viewer/litehtml/element.h
@@ -35,6 +35,10 @@ namespace litehtml
 
 		virtual void select_all(const css_selector& selector, elements_list& res);
 		element::ptr _add_before_after(int type, const style& style);
+
+	private:
+		std::map<string_id, int>	m_counter_values;
+
 	public:
 		explicit element(const std::shared_ptr<document>& doc);
 		virtual ~element() = default;
@@ -99,6 +103,7 @@ namespace litehtml
 		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 int					get_int_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;
@@ -142,6 +147,16 @@ namespace litehtml
 		{
 			return _add_before_after(1, style);
 		}
+
+		string				get_counter_value(const string& counter_name);
+		string				get_counters_value(const string_vector& parameters);
+		void				increment_counter(const string_id& counter_name_id, const int increment = 1);
+		void				reset_counter(const string_id& counter_name_id, const int value = 0);
+
+	private:
+		std::vector<element::ptr> get_siblings_before() const;
+		bool				find_counter(const string_id& counter_name_id, std::map<string_id, int>::iterator& map_iterator);
+		void				parse_counter_tokens(const string_vector& tokens, const int default_value, std::function<void(const string_id&, const int)> handler) const;
 	};
 
 	//////////////////////////////////////////////////////////////////////////
diff --git a/src/plugins/litehtml_viewer/litehtml/flex_item.cpp b/src/plugins/litehtml_viewer/litehtml/flex_item.cpp
new file mode 100644
index 000000000..d0fbaecd7
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/flex_item.cpp
@@ -0,0 +1,488 @@
+#include "html.h"
+#include "flex_item.h"
+#include "render_item.h"
+#include "flex_line.h"
+#include <cmath>
+
+void litehtml::flex_item::init(const litehtml::containing_block_context &self_size,
+							   litehtml::formatting_context *fmt_ctx, flex_align_items align_items)
+{
+	grow = (int) std::nearbyint(el->css().get_flex_grow() * 1000.0);
+	// Negative numbers are invalid.
+	// https://www.w3.org/TR/css-flexbox-1/#valdef-flex-grow-number
+	if(grow < 0) grow = 0;
+
+	shrink = (int) std::nearbyint(el->css().get_flex_shrink() * 1000.0);
+	// Negative numbers are invalid.
+	// https://www.w3.org/TR/css-flexbox-1/#valdef-flex-shrink-number
+	if(shrink < 0) shrink = 1000;
+
+	el->calc_outlines(self_size.render_width);
+	order = el->css().get_order();
+
+	direction_specific_init(self_size, fmt_ctx);
+
+	if (el->css().get_flex_align_self() == flex_align_items_auto)
+	{
+		align = align_items;
+	} else
+	{
+		align = el->css().get_flex_align_self();
+	}
+	main_size = base_size;
+	scaled_flex_shrink_factor = base_size * shrink;
+	frozen = false;
+}
+
+void litehtml::flex_item::place(flex_line &ln, int main_pos,
+								const containing_block_context &self_size,
+								formatting_context *fmt_ctx)
+{
+	apply_main_auto_margins();
+	set_main_position(main_pos);
+	if(!apply_cross_auto_margins(ln.cross_size))
+	{
+		switch (align & 0xFF)
+		{
+			case flex_align_items_baseline:
+				align_baseline(ln, self_size, fmt_ctx);
+				break;
+			case flex_align_items_flex_end:
+				if(ln.reverse_cross)
+				{
+					set_cross_position(ln.cross_start);
+					break;	/// If cross axis is reversed position item from start
+				}
+			case flex_align_items_end:
+				set_cross_position(ln.cross_start + ln.cross_size - get_el_cross_size());
+				break;
+			case flex_align_items_center:
+				set_cross_position(ln.cross_start + ln.cross_size / 2 - get_el_cross_size() / 2);
+				break;
+			case flex_align_items_flex_start:
+				if(ln.reverse_cross)	/// If cross axis is reversed position item from end
+				{
+					set_cross_position(ln.cross_start + ln.cross_size - get_el_cross_size());
+					break;
+				}
+			case flex_align_items_start:
+				set_cross_position(ln.cross_start);
+				break;
+			default:
+				align_stretch(ln, self_size, fmt_ctx);
+				break;
+		}
+	}
+}
+
+int litehtml::flex_item::get_last_baseline(baseline::_baseline_type type) const
+{
+	if(type == baseline::baseline_type_top)
+	{
+		return el->get_last_baseline();
+	} else if(type == baseline::baseline_type_bottom)
+	{
+		return el->height() - el->get_last_baseline();
+	}
+	return 0;
+}
+
+int litehtml::flex_item::get_first_baseline(litehtml::baseline::_baseline_type type) const
+{
+	if(type == baseline::baseline_type_top)
+	{
+		return el->get_first_baseline();
+	} else if(type == baseline::baseline_type_bottom)
+	{
+		return el->height() - el->get_first_baseline();
+	}
+	return 0;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void litehtml::flex_item_row_direction::direction_specific_init(const litehtml::containing_block_context &self_size,
+																litehtml::formatting_context *fmt_ctx)
+{
+	if(el->css().get_margins().left.is_predefined())
+	{
+		auto_margin_main_start = 0;
+	}
+	if(el->css().get_margins().right.is_predefined())
+	{
+		auto_margin_main_end = 0;
+	}
+	if(el->css().get_margins().top.is_predefined())
+	{
+		auto_margin_cross_start = true;
+	}
+	if(el->css().get_margins().bottom.is_predefined())
+	{
+		auto_margin_cross_end = true;
+	}
+	def_value<int> content_size(0);
+	if (el->css().get_min_width().is_predefined())
+	{
+		min_size = el->render(0, 0,
+							  self_size.new_width(el->content_offset_width(),
+												  containing_block_context::size_mode_content), fmt_ctx);
+		content_size = min_size;
+	} else
+	{
+		min_size = el->css().get_min_width().calc_percent(self_size.render_width) +
+				   el->content_offset_width();
+	}
+	if (!el->css().get_max_width().is_predefined())
+	{
+		max_size = el->css().get_max_width().calc_percent(self_size.render_width) +
+				   el->content_offset_width();
+	}
+	bool flex_basis_predefined = el->css().get_flex_basis().is_predefined();
+	int predef = flex_basis_auto;
+	if(flex_basis_predefined)
+	{
+		predef = el->css().get_flex_basis().predef();
+	} else
+	{
+		if(el->css().get_flex_basis().val() < 0)
+		{
+			flex_basis_predefined = true;
+		}
+	}
+
+	if (flex_basis_predefined)
+	{
+		switch (predef)
+		{
+			case flex_basis_auto:
+				if (!el->css().get_width().is_predefined())
+				{
+					base_size = el->css().get_width().calc_percent(self_size.render_width) +
+								el->content_offset_width();
+					break;
+				}
+				// if width is not predefined, use content size as base size
+			case flex_basis_fit_content:
+			case flex_basis_content:
+				base_size = el->render(0, 0, self_size.new_width(self_size.render_width + el->content_offset_width(),
+																 containing_block_context::size_mode_content |
+																 containing_block_context::size_mode_exact_width),
+									   fmt_ctx);
+				break;
+			case flex_basis_min_content:
+				if(content_size.is_default())
+				{
+					content_size = el->render(0, 0,
+											  self_size.new_width(el->content_offset_width(),
+																  containing_block_context::size_mode_content),
+											  fmt_ctx);
+				}
+				base_size = content_size;
+				break;
+			case flex_basis_max_content:
+				el->render(0, 0, self_size, fmt_ctx);
+				base_size = el->width();
+				break;
+			default:
+				base_size = 0;
+				break;
+		}
+	} else
+	{
+		base_size = el->css().get_flex_basis().calc_percent(self_size.render_width) +
+					el->content_offset_width();
+		base_size = std::max(base_size, min_size);
+	}
+}
+
+void litehtml::flex_item_row_direction::apply_main_auto_margins()
+{
+	// apply auto margins to item
+	if(!auto_margin_main_start.is_default())
+	{
+		el->get_margins().left = auto_margin_main_start;
+		el->pos().x += auto_margin_main_start;
+	}
+	if(!auto_margin_main_end.is_default()) el->get_margins().right = auto_margin_main_end;
+}
+
+bool litehtml::flex_item_row_direction::apply_cross_auto_margins(int cross_size)
+{
+	if(auto_margin_cross_end || auto_margin_cross_start)
+	{
+		int margins_num = 0;
+		if(auto_margin_cross_end)
+		{
+			margins_num++;
+		}
+		if(auto_margin_cross_start)
+		{
+			margins_num++;
+		}
+		int margin = (cross_size - el->height()) / margins_num;
+		if(auto_margin_cross_start)
+		{
+			el->get_margins().top = margin;
+			el->pos().y = el->content_offset_top();
+		}
+		if(auto_margin_cross_end)
+		{
+			el->get_margins().bottom = margin;
+		}
+		return true;
+	}
+	return false;
+}
+
+void litehtml::flex_item_row_direction::set_main_position(int pos)
+{
+	el->pos().x = pos + el->content_offset_left();
+}
+
+void litehtml::flex_item_row_direction::set_cross_position(int pos)
+{
+	el->pos().y = pos + el->content_offset_top();
+}
+
+void litehtml::flex_item_row_direction::align_stretch(flex_line &ln, const containing_block_context &self_size,
+													  formatting_context *fmt_ctx)
+{
+	set_cross_position(ln.cross_start);
+	if (el->css().get_height().is_predefined())
+	{
+		el->render(el->left(), el->top(), self_size.new_width_height(
+				el->pos().width + el->box_sizing_width(),
+				ln.cross_size - el->content_offset_height() + el->box_sizing_height(),
+				containing_block_context::size_mode_exact_width |
+				containing_block_context::size_mode_exact_height
+				), fmt_ctx);
+		apply_main_auto_margins();
+	}
+}
+
+void litehtml::flex_item_row_direction::align_baseline(litehtml::flex_line &ln,
+													   const containing_block_context &self_size,
+													   formatting_context *fmt_ctx)
+{
+	if (align & flex_align_items_last)
+	{
+		set_cross_position(ln.cross_start + ln.last_baseline.get_offset_from_top(ln.cross_size) - el->get_last_baseline());
+	} else
+	{
+		set_cross_position(ln.cross_start + ln.first_baseline.get_offset_from_top(ln.cross_size) - el->get_first_baseline());
+	}
+}
+
+int litehtml::flex_item_row_direction::get_el_main_size()
+{
+	return el->width();
+}
+
+int litehtml::flex_item_row_direction::get_el_cross_size()
+{
+	return el->height();
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void litehtml::flex_item_column_direction::direction_specific_init(const litehtml::containing_block_context &self_size,
+																   litehtml::formatting_context *fmt_ctx)
+{
+	if(el->css().get_margins().top.is_predefined())
+	{
+		auto_margin_main_start = 0;
+	}
+	if(el->css().get_margins().bottom.is_predefined())
+	{
+		auto_margin_main_end = 0;
+	}
+	if(el->css().get_margins().left.is_predefined())
+	{
+		auto_margin_cross_start = true;
+	}
+	if(el->css().get_margins().right.is_predefined())
+	{
+		auto_margin_cross_end = true;
+	}
+	if (el->css().get_min_height().is_predefined())
+	{
+		el->render(0, 0, self_size.new_width(self_size.render_width, containing_block_context::size_mode_content), fmt_ctx);
+		min_size = el->height();
+	} else
+	{
+		min_size = el->css().get_min_height().calc_percent(self_size.height) +
+				   el->content_offset_height();
+	}
+	if (!el->css().get_max_height().is_predefined())
+	{
+		max_size = el->css().get_max_height().calc_percent(self_size.height) +
+				   el->content_offset_width();
+	}
+
+	bool flex_basis_predefined = el->css().get_flex_basis().is_predefined();
+	int predef = flex_basis_auto;
+	if(flex_basis_predefined)
+	{
+		predef = el->css().get_flex_basis().predef();
+	} else
+	{
+		if(el->css().get_flex_basis().val() < 0)
+		{
+			flex_basis_predefined = true;
+		}
+	}
+
+	if (flex_basis_predefined)
+	{
+		switch (predef)
+		{
+			case flex_basis_auto:
+				if (!el->css().get_height().is_predefined())
+				{
+					base_size = el->css().get_height().calc_percent(self_size.height) +
+								el->content_offset_height();
+					break;
+				}
+			case flex_basis_max_content:
+			case flex_basis_fit_content:
+				el->render(0, 0, self_size, fmt_ctx);
+				base_size = el->height();
+				break;
+			case flex_basis_min_content:
+				base_size = min_size;
+				break;
+			default:
+				base_size = 0;
+		}
+	} else
+	{
+		if(el->css().get_flex_basis().units() == css_units_percentage)
+		{
+			if(self_size.height.type == containing_block_context::cbc_value_type_absolute)
+			{
+				base_size = el->css().get_flex_basis().calc_percent(self_size.height) +
+							el->content_offset_height();
+			} else
+			{
+				base_size = 0;
+			}
+		} else
+		{
+			base_size = (int) el->css().get_flex_basis().val() + el->content_offset_height();
+		}
+		base_size = std::max(base_size, min_size);
+	}
+}
+
+void litehtml::flex_item_column_direction::apply_main_auto_margins()
+{
+	// apply auto margins to item
+	if(!auto_margin_main_start.is_default())
+	{
+		el->get_margins().top = auto_margin_main_start;
+		el->pos().y += auto_margin_main_start;
+	}
+	if(!auto_margin_main_end.is_default()) el->get_margins().bottom = auto_margin_main_end;
+}
+
+bool litehtml::flex_item_column_direction::apply_cross_auto_margins(int cross_size)
+{
+	if(auto_margin_cross_end || auto_margin_cross_start)
+	{
+		int margins_num = 0;
+		if(auto_margin_cross_end)
+		{
+			margins_num++;
+		}
+		if(auto_margin_cross_start)
+		{
+			margins_num++;
+		}
+		int margin = (cross_size - el->width()) / margins_num;
+		if(auto_margin_cross_start)
+		{
+			el->get_margins().left = margin;
+			el->pos().x += el->content_offset_left();
+		}
+		if(auto_margin_cross_end)
+		{
+			el->get_margins().right = margin;
+		}
+	}
+	return false;
+}
+
+void litehtml::flex_item_column_direction::set_main_position(int pos)
+{
+	el->pos().y = pos + el->content_offset_top();
+}
+
+void litehtml::flex_item_column_direction::set_cross_position(int pos)
+{
+	el->pos().x = pos + el->content_offset_left();
+}
+
+void litehtml::flex_item_column_direction::align_stretch(flex_line &ln, const containing_block_context &self_size,
+														 formatting_context *fmt_ctx)
+{
+	/// MAIN:  Y
+	/// CROSS: X
+	if (!el->css().get_width().is_predefined())
+	{
+		el->render(ln.cross_start,
+				   el->pos().y - el->content_offset_top(),
+				   self_size.new_width_height(ln.cross_size - el->content_offset_width() + el->box_sizing_width(),
+											  main_size - el->content_offset_height() + el->box_sizing_height(),
+											  containing_block_context::size_mode_exact_height),
+				   fmt_ctx, false);
+	} else
+	{
+		el->render(ln.cross_start,
+				   el->pos().y - el->content_offset_top(),
+				   self_size.new_width_height(
+						   ln.cross_size - el->content_offset_width() + el->box_sizing_width(),
+						   main_size - el->content_offset_height() + el->box_sizing_height(),
+						   containing_block_context::size_mode_exact_width |
+						   containing_block_context::size_mode_exact_height),
+				   fmt_ctx, false);
+	}
+	/// Apply auto margins after rendering
+	apply_main_auto_margins();
+}
+
+void litehtml::flex_item_column_direction::align_baseline(litehtml::flex_line &ln,
+														  const containing_block_context &self_size,
+														  formatting_context *fmt_ctx)
+{
+	// The fallback alignment for first baseline is start, the one for last baseline is end.
+	if(align & flex_align_items_last)
+	{
+		if(ln.reverse_cross)
+		{
+			set_cross_position(ln.cross_start);
+		} else
+		{
+			set_cross_position(ln.cross_start + ln.cross_size - get_el_cross_size());
+		}
+	} else
+	{
+		if(!ln.reverse_cross)
+		{
+			set_cross_position(ln.cross_start);
+		} else
+		{
+			set_cross_position(ln.cross_start + ln.cross_size - get_el_cross_size());
+		}
+	}
+}
+
+int litehtml::flex_item_column_direction::get_el_main_size()
+{
+	return el->height();
+}
+
+int litehtml::flex_item_column_direction::get_el_cross_size()
+{
+	return el->width();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/flex_item.h b/src/plugins/litehtml_viewer/litehtml/flex_item.h
new file mode 100644
index 000000000..a2b3426f1
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/flex_item.h
@@ -0,0 +1,137 @@
+#ifndef LITEHTML_FLEX_ITEM_H
+#define LITEHTML_FLEX_ITEM_H
+
+#include <functional>
+#include "formatting_context.h"
+
+namespace litehtml
+{
+	class flex_line;
+
+	/**
+	 * Base class for flex item
+	 */
+	class flex_item
+	{
+	public:
+		std::shared_ptr<render_item> el;
+		int base_size;
+		int min_size;
+		def_value<int> max_size;
+		int main_size;
+		int grow;
+		int shrink;
+		int scaled_flex_shrink_factor;
+		bool frozen;
+		int order;
+		int src_order;
+		def_value<int> auto_margin_main_start;
+		def_value<int> auto_margin_main_end;
+		bool auto_margin_cross_start;
+		bool auto_margin_cross_end;
+		flex_align_items align;
+
+		explicit flex_item(std::shared_ptr<render_item> &_el) :
+				el(_el),
+				align(flex_align_items_auto),
+				grow(0),
+				base_size(0),
+				shrink(0),
+				min_size(0),
+				frozen(false),
+				main_size(0),
+				max_size(0),
+				order(0),
+				src_order(0),
+				scaled_flex_shrink_factor(0),
+				auto_margin_main_start(0),
+				auto_margin_main_end(0),
+				auto_margin_cross_start(false),
+				auto_margin_cross_end(false)
+		{}
+
+		virtual ~flex_item() = default;
+
+		bool operator<(const flex_item& b) const
+		{
+			if(order < b.order) return true;
+			if(order == b.order) return src_order < b.src_order;
+			return false;
+		}
+		void init(const litehtml::containing_block_context &self_size,
+				  litehtml::formatting_context *fmt_ctx, flex_align_items align_items);
+		virtual void apply_main_auto_margins() = 0;
+		virtual bool apply_cross_auto_margins(int cross_size) = 0;
+		virtual void set_main_position(int pos) = 0;
+		virtual void set_cross_position(int pos) = 0;
+		virtual int get_el_main_size() = 0;
+		virtual int get_el_cross_size() = 0;
+
+		void place(flex_line &ln, int main_pos,
+				   const containing_block_context &self_size,
+				   formatting_context *fmt_ctx);
+		int get_last_baseline(baseline::_baseline_type type) const;
+		int get_first_baseline(baseline::_baseline_type type) const;
+
+	protected:
+		virtual void direction_specific_init(const litehtml::containing_block_context &self_size,
+											 litehtml::formatting_context *fmt_ctx) = 0;
+		virtual void align_stretch(flex_line &ln, const containing_block_context &self_size,
+								   formatting_context *fmt_ctx) = 0;
+		virtual void align_baseline(flex_line &ln,
+									const containing_block_context &self_size,
+									formatting_context *fmt_ctx) = 0;
+	};
+
+	/**
+	 * Flex item with "flex-direction: row" or " flex-direction: row-reverse"
+	 */
+	class flex_item_row_direction : public flex_item
+	{
+	public:
+		explicit flex_item_row_direction(std::shared_ptr<render_item> &_el) : flex_item(_el) {}
+
+		void apply_main_auto_margins() override;
+		bool apply_cross_auto_margins(int cross_size) override;
+		void set_main_position(int pos) override;
+		void set_cross_position(int pos) override;
+		int get_el_main_size() override;
+		int get_el_cross_size() override;
+
+	protected:
+		void direction_specific_init(const litehtml::containing_block_context &self_size,
+									 litehtml::formatting_context *fmt_ctx) override;
+		void align_stretch(flex_line &ln, const containing_block_context &self_size,
+						   formatting_context *fmt_ctx) override;
+		void align_baseline(flex_line &ln,
+							const containing_block_context &self_size,
+							formatting_context *fmt_ctx) override;
+	};
+
+	/**
+	 * Flex item with "flex-direction: column" or " flex-direction: column-reverse"
+	 */
+	class flex_item_column_direction : public flex_item
+	{
+	public:
+		explicit flex_item_column_direction(std::shared_ptr<render_item> &_el) : flex_item(_el) {}
+
+		void apply_main_auto_margins() override;
+		bool apply_cross_auto_margins(int cross_size) override;
+		void set_main_position(int pos) override;
+		void set_cross_position(int pos) override;
+		int get_el_main_size() override;
+		int get_el_cross_size() override;
+
+	protected:
+		void direction_specific_init(const litehtml::containing_block_context &self_size,
+									 litehtml::formatting_context *fmt_ctx) override;
+		void align_stretch(flex_line &ln, const containing_block_context &self_size,
+						   formatting_context *fmt_ctx) override;
+		void align_baseline(flex_line &ln,
+							const containing_block_context &self_size,
+							formatting_context *fmt_ctx) override;
+	};
+}
+
+#endif //LITEHTML_FLEX_ITEM_H
diff --git a/src/plugins/litehtml_viewer/litehtml/flex_line.cpp b/src/plugins/litehtml_viewer/litehtml/flex_line.cpp
new file mode 100644
index 000000000..5f966b3b1
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/flex_line.cpp
@@ -0,0 +1,454 @@
+#include "html.h"
+#include "flex_line.h"
+#include "flex_item.h"
+#include "render_item.h"
+
+void litehtml::flex_line::distribute_free_space(int container_main_size)
+{
+	// Determine the used flex factor. Sum the outer hypothetical main sizes of all items on the line.
+	// If the sum is less than the flex container’s inner main size, use the flex grow factor for the
+	// rest of this algorithm; otherwise, use the flex shrink factor.
+	int initial_free_space = container_main_size - base_size;
+	bool grow;
+	int total_flex_factor;
+	if(initial_free_space < 0)
+	{
+		grow = false;
+		total_flex_factor = total_shrink;
+		// Flex values between 0 and 1 have a somewhat special behavior: when the sum of the flex values on the line
+		// is less than 1, they will take up less than 100% of the free space.
+		// https://www.w3.org/TR/css-flexbox-1/#valdef-flex-flex-grow
+		if(total_flex_factor < 1000)
+		{
+			for(auto &item : items)
+			{
+				item->main_size += initial_free_space * item->shrink / 1000;
+			}
+			return;
+		}
+	} else
+	{
+		grow = true;
+		total_flex_factor = total_grow;
+		// Flex values between 0 and 1 have a somewhat special behavior: when the sum of the flex values on the line
+		// is less than 1, they will take up less than 100% of the free space.
+		// https://www.w3.org/TR/css-flexbox-1/#valdef-flex-flex-grow
+		if(total_flex_factor < 1000)
+		{
+			for(auto &item : items)
+			{
+				item->main_size += initial_free_space * item->grow / 1000;
+			}
+			return;
+		}
+	}
+
+	if(total_flex_factor > 0)
+	{
+		bool processed = true;
+		while (processed)
+		{
+			int sum_scaled_flex_shrink_factor = 0;
+			int sum_flex_factors = 0;
+			int remaining_free_space = container_main_size;
+			int total_not_frozen = 0;
+			for (auto &item: items)
+			{
+				if (!item->frozen)
+				{
+					sum_scaled_flex_shrink_factor += item->scaled_flex_shrink_factor;
+					if(grow)
+					{
+						sum_flex_factors += item->grow;
+					} else
+					{
+						sum_flex_factors += item->shrink;
+					}
+					remaining_free_space -= item->base_size;
+					total_not_frozen++;
+				} else
+				{
+					remaining_free_space -= item->main_size;
+				}
+			}
+			// Check for flexible items. If all the flex items on the line are frozen, free space has
+			// been distributed; exit this loop.
+			if (!total_not_frozen) break;
+
+			remaining_free_space = abs(remaining_free_space);
+			// c. Distribute free space proportional to the flex factors.
+			// If the remaining free space is zero
+			//    Do nothing.
+			if (!remaining_free_space)
+			{
+				processed = false;
+			} else
+			{
+				int total_clamped = 0;
+				for (auto &item: items)
+				{
+					if (!item->frozen)
+					{
+						if(!grow)
+						{
+							// If using the flex shrink factor
+							//    For every unfrozen item on the line, multiply its flex shrink factor by its
+							//    inner flex base size, and note this as its scaled flex shrink factor. Find
+							//    the ratio of the item’s scaled flex shrink factor to the sum of the scaled
+							//    flex shrink factors of all unfrozen items on the line. Set the item’s target
+							//    main size to its flex base size minus a fraction of the absolute value of the
+							//    remaining free space proportional to the ratio.
+							int scaled_flex_shrink_factor = item->base_size * item->shrink;
+							item->main_size = (int) ((float) item->base_size - (float) remaining_free_space *
+																			 (float) scaled_flex_shrink_factor /
+																			 (float) sum_scaled_flex_shrink_factor);
+
+							// d. Fix min/max violations. Clamp each non-frozen item’s target main size by its used
+							// min and max main sizes and floor its content-box size at zero. If the item’s target
+							// main size was made smaller by this, it’s a max violation. If the item’s target main
+							// size was made larger by this, it’s a min violation.
+							if (item->main_size <= item->min_size)
+							{
+								total_clamped++;
+								item->main_size = item->min_size;
+								item->frozen = true;
+							}
+							if(!item->max_size.is_default() && item->main_size >= item->max_size)
+							{
+								total_clamped++;
+								item->main_size = item->max_size;
+								item->frozen = true;
+							}
+						} else
+						{
+							// If using the flex grow factor
+							//    Find the ratio of the item’s flex grow factor to the sum of the flex grow
+							//    factors of all unfrozen items on the line. Set the item’s target main size to
+							//    its flex base size plus a fraction of the remaining free space proportional
+							//    to the ratio.
+							item->main_size = (int) ((float) item->base_size +
+													(float) remaining_free_space * (float) item->grow /
+													(float) total_flex_factor);
+							// d. Fix min/max violations. Clamp each non-frozen item’s target main size by its used
+							// min and max main sizes and floor its content-box size at zero. If the item’s target
+							// main size was made smaller by this, it’s a max violation. If the item’s target main
+							// size was made larger by this, it’s a min violation.
+							if (item->main_size >= container_main_size)
+							{
+								total_clamped++;
+								item->main_size = container_main_size;
+								item->frozen = true;
+							}
+							if(!item->max_size.is_default() && item->main_size >= item->max_size)
+							{
+								total_clamped++;
+								item->main_size = item->max_size;
+								item->frozen = true;
+							}
+						}
+					}
+				}
+				if (total_clamped == 0) processed = false;
+			}
+		}
+		// Distribute remaining after algorithm space
+		int sum_main_size = 0;
+		for(auto &item : items)
+		{
+			sum_main_size += item->main_size;
+		}
+		int free_space = container_main_size - sum_main_size;
+		if(free_space > 0)
+		{
+			for(auto &item : items)
+			{
+				if(free_space == 0) break;
+				item->main_size++;
+				free_space--;
+			}
+		}
+	}
+}
+
+bool litehtml::flex_line::distribute_main_auto_margins(int free_main_size)
+{
+	if(free_main_size > 0 && (num_auto_margin_main_start || num_auto_margin_main_end))
+	{
+		int add = (int) (free_main_size / (items.size() * 2));
+		for (auto &item: items)
+		{
+			if(!item->auto_margin_main_start.is_default())
+			{
+				item->auto_margin_main_start = add;
+				item->main_size += add;
+				main_size += add;
+				free_main_size -= add;
+			}
+			if(!item->auto_margin_main_end.is_default())
+			{
+				item->auto_margin_main_end = add;
+				item->main_size += add;
+				main_size += add;
+				free_main_size -= add;
+			}
+		}
+		while (free_main_size > 0)
+		{
+			for (auto &item: items)
+			{
+				if(!item->auto_margin_main_start.is_default())
+				{
+					item->auto_margin_main_start = item->auto_margin_main_start + 1;
+					free_main_size--;
+					if(!free_main_size) break;
+				}
+				if(!item->auto_margin_main_end.is_default())
+				{
+					item->auto_margin_main_end = item->auto_margin_main_end + 1;
+					free_main_size--;
+					if(!free_main_size) break;
+				}
+			}
+		}
+		return true;
+	}
+	return false;
+}
+
+void litehtml::flex_line::init(int container_main_size, bool fit_container, bool is_row_direction,
+							   const litehtml::containing_block_context &self_size,
+							   litehtml::formatting_context *fmt_ctx)
+{
+	cross_size = 0;
+	main_size = 0;
+	first_baseline.set(0, baseline::baseline_type_none);
+	last_baseline.set(0, baseline::baseline_type_none);
+
+	if(!fit_container)
+	{
+		distribute_free_space(container_main_size);
+	}
+
+	if(is_row_direction)
+	{
+		def_value<int> first_baseline_top = 0;
+		def_value<int> first_baseline_bottom = 0;
+		def_value<int> last_baseline_top = 0;
+		def_value<int> last_baseline_bottom = 0;
+		int non_baseline_height = 0;
+
+		// Calculate maximum cross size
+		def_value<int> max_cross_size(0);
+		if(self_size.height.type != containing_block_context::cbc_value_type_auto)
+		{
+			max_cross_size = self_size.height;
+		}
+		if(self_size.max_height.type != containing_block_context::cbc_value_type_none)
+		{
+			if(max_cross_size.is_default())
+			{
+				max_cross_size = self_size.max_height;
+			} else
+			{
+				max_cross_size = std::max((int) max_cross_size, (int) self_size.max_height);
+			}
+		}
+
+		/// Render items into new size
+		/// Find line cross_size
+		/// Find line first/last baseline
+		for (auto &item: items)
+		{
+			item->el->render(0,
+							 0,
+							 self_size.new_width(item->main_size - item->el->content_offset_width(), containing_block_context::size_mode_exact_width), fmt_ctx, false);
+
+			if((item->align & 0xFF) == flex_align_items_baseline)
+			{
+				if(item->align & flex_align_items_last)
+				{
+					last_baseline.type(reverse_cross ? baseline::baseline_type_top : baseline::baseline_type_bottom);
+
+					int top = -item->el->get_last_baseline();
+					int bottom = top + item->el->height();
+
+					if(last_baseline_top.is_default()) last_baseline_top = top;
+					else last_baseline_top = std::min((int) last_baseline_top, top);
+
+					if(last_baseline_bottom.is_default()) last_baseline_bottom = bottom;
+					else last_baseline_bottom = std::max((int)last_baseline_bottom, bottom);
+				} else
+				{
+					first_baseline.type(reverse_cross ? baseline::baseline_type_bottom : baseline::baseline_type_top);
+					int top = -item->el->get_first_baseline();
+					int bottom = top + item->el->height();
+
+					if(first_baseline_top.is_default()) first_baseline_top = top;
+					else first_baseline_top = std::min((int) first_baseline_top, top);
+
+					if(first_baseline_bottom.is_default()) first_baseline_bottom = bottom;
+					else first_baseline_bottom = std::max((int) first_baseline_bottom, bottom);
+				}
+			} else
+			{
+				non_baseline_height = std::max(non_baseline_height, item->el->height());
+			}
+			main_size += item->el->width();
+		}
+
+		cross_size = std::max(first_baseline_bottom - first_baseline_top,last_baseline_bottom - last_baseline_top);
+		cross_size = std::max(cross_size, non_baseline_height);
+		if(!max_cross_size.is_default() && cross_size > max_cross_size)
+		{
+			cross_size = max_cross_size;
+		}
+
+		first_baseline.calc(first_baseline_top, first_baseline_bottom);
+		last_baseline.calc(last_baseline_top, last_baseline_bottom);
+	} else
+	{
+		// Calculate maximum cross size
+		def_value<int> max_cross_size(0);
+		if(self_size.width.type != containing_block_context::cbc_value_type_auto)
+		{
+			max_cross_size = self_size.width;
+		}
+		if(self_size.max_width.type != containing_block_context::cbc_value_type_none)
+		{
+			if(max_cross_size.is_default())
+			{
+				max_cross_size = self_size.max_width;
+			} else
+			{
+				max_cross_size = std::max((int) max_cross_size, (int) self_size.max_width);
+			}
+		}
+
+		for (auto &item: items)
+		{
+			int el_ret_width = item->el->render(0,
+												0,
+												self_size, fmt_ctx, false);
+			item->el->render(0,
+							 0,
+							 self_size.new_width_height(el_ret_width - item->el->content_offset_width(),
+														item->main_size - item->el->content_offset_height(),
+														containing_block_context::size_mode_exact_width |
+														containing_block_context::size_mode_exact_height),
+							 fmt_ctx, false);
+			main_size += item->el->height();
+			cross_size = std::max(cross_size, item->el->width());
+		}
+		if(!max_cross_size.is_default() && cross_size > max_cross_size)
+		{
+			cross_size = max_cross_size;
+		}
+	}
+}
+
+int litehtml::flex_line::calculate_items_position(int container_main_size,
+												  flex_justify_content justify_content,
+												  bool is_row_direction,
+												  const containing_block_context &self_size,
+												  formatting_context *fmt_ctx)
+{
+	/// Distribute main axis free space for auto-margins
+	int free_main_size = container_main_size - main_size;
+	distribute_main_auto_margins(free_main_size);
+	free_main_size = container_main_size - main_size;
+
+	/// Fix justify-content property
+	switch (justify_content)
+	{
+		case flex_justify_content_left:
+		case flex_justify_content_right:
+			if(!is_row_direction)
+			{
+				justify_content = flex_justify_content_start;
+			}
+			break;
+		case flex_justify_content_space_between:
+			// If the leftover free-space is negative or there is only a single flex item on the line, this
+			// value is identical to flex-start.
+			if(items.size() == 1 || free_main_size < 0)  justify_content = flex_justify_content_flex_start;
+			break;
+		case flex_justify_content_space_around:
+		case flex_justify_content_space_evenly:
+			// If the leftover free-space is negative or there is only a single flex item on the line, this
+			// value is identical to center
+			if(items.size() == 1 || free_main_size < 0)  justify_content = flex_justify_content_center;
+			break;
+		default:
+			break;
+	}
+
+	/// Distribute free main size using justify-content property
+	int main_pos = 0;
+	int add_before_item = 0;
+	int add_after_item = 0;
+	int item_remainder = 0;
+
+	/// find initial main position and spaces between items
+	switch (justify_content)
+	{
+
+		case flex_justify_content_right:
+			main_pos = free_main_size;
+			break;
+		case flex_justify_content_left:
+		case flex_justify_content_start:
+			main_pos = 0;
+			break;
+		case flex_justify_content_end:
+			main_pos = free_main_size;
+			break;
+		case flex_justify_content_flex_end:
+			if(!reverse_main)
+			{
+				main_pos = free_main_size;
+			}
+			break;
+		case flex_justify_content_center:
+			main_pos = free_main_size / 2;
+			break;
+		case flex_justify_content_space_between:
+			add_after_item = free_main_size / ((int) items.size() - 1);
+			item_remainder = free_main_size - (add_after_item * ((int) items.size() - 1));
+			break;
+		case flex_justify_content_space_around:
+			add_after_item = add_before_item = free_main_size / ((int) items.size() * 2);
+			item_remainder = free_main_size - (add_after_item * (int) items.size() * 2);
+			break;
+		case flex_justify_content_space_evenly:
+			add_before_item = free_main_size / ((int) items.size() + 1);
+			item_remainder = free_main_size - add_before_item * ((int) items.size() + 1);
+			break;
+		default:
+			if(reverse_main)
+			{
+				main_pos = free_main_size;
+			}
+			break;
+	}
+
+	/// Place all items in main and cross positions
+	int height =  0;
+	for(auto &item : items)
+	{
+		main_pos += add_before_item;
+		if(add_before_item > 0 && item_remainder > 0)
+		{
+			main_pos++;
+			item_remainder--;
+		}
+		item->place(*this, main_pos, self_size, fmt_ctx);
+		main_pos += item->get_el_main_size() + add_after_item;
+		if(add_after_item > 0 && item_remainder > 0)
+		{
+			main_pos++;
+			item_remainder--;
+		}
+		height = std::max(height, item->el->bottom());
+	}
+	return height;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/flex_line.h b/src/plugins/litehtml_viewer/litehtml/flex_line.h
new file mode 100644
index 000000000..4803d2386
--- /dev/null
+++ b/src/plugins/litehtml_viewer/litehtml/flex_line.h
@@ -0,0 +1,56 @@
+#ifndef LITEHTML_FLEX_LINE_H
+#define LITEHTML_FLEX_LINE_H
+
+#include "formatting_context.h"
+
+namespace litehtml
+{
+	class flex_item;
+
+	class flex_line
+	{
+		public:
+		std::list<std::shared_ptr<flex_item>> items;
+		int cross_start;	// for row direction: top. for column direction: left
+		int main_size;		// sum of all items main size
+		int cross_size;		// sum of all items cross size
+		int base_size;
+		int total_grow;
+		int total_shrink;
+		int num_auto_margin_main_start;		// number of items with auto margin left/top
+		int num_auto_margin_main_end;		// number of items with auto margin right/bottom
+		baseline first_baseline;
+		baseline last_baseline;
+		bool reverse_main;
+		bool reverse_cross;
+
+		flex_line(bool _reverse_main, bool _reverse_cross) :
+				cross_size(0),
+				cross_start(0),
+				total_grow(0),
+				base_size(0),
+				total_shrink(0),
+				main_size(0),
+				num_auto_margin_main_start(0),
+				num_auto_margin_main_end(0),
+				first_baseline(),
+				last_baseline(),
+				reverse_main(_reverse_main),
+				reverse_cross(_reverse_cross)
+		{}
+
+		void init(int container_main_size, bool fit_container, bool is_row_direction,
+				  const litehtml::containing_block_context &self_size,
+				  litehtml::formatting_context *fmt_ctx);
+		bool distribute_main_auto_margins(int free_main_size);
+		int  calculate_items_position(int container_main_size,
+									  flex_justify_content justify_content,
+									  bool is_row_direction,
+									  const containing_block_context &self_size,
+									  formatting_context *fmt_ctx);
+	protected:
+		void distribute_free_space(int container_main_size);
+	};
+}
+
+#endif //LITEHTML_FLEX_LINE_H
diff --git a/src/plugins/litehtml_viewer/litehtml/html.cpp b/src/plugins/litehtml_viewer/litehtml/html.cpp
index 9695180a7..ee8ddad8d 100644
--- a/src/plugins/litehtml_viewer/litehtml/html.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/html.cpp
@@ -2,9 +2,9 @@
 #include "types.h"
 #include "utf8_strings.h"
 
-void litehtml::trim(string &s) 
+void litehtml::trim(string &s, const string& chars_to_trim)
 {
-	string::size_type pos = s.find_first_not_of(" \n\r\t");
+	string::size_type pos = s.find_first_not_of(chars_to_trim);
 	if(pos != string::npos)
 	{
 		s.erase(s.begin(), s.begin() + pos);
@@ -14,7 +14,7 @@ void litehtml::trim(string &s)
 		s = "";
 		return;
 	}
-	pos = s.find_last_not_of(" \n\r\t");
+	pos = s.find_last_not_of(chars_to_trim);
 	if(pos != string::npos)
 	{
 		s.erase(s.begin() + pos + 1, s.end());
@@ -277,3 +277,14 @@ litehtml::string litehtml::get_escaped_string(const string& in_str)
 	}
 	return ret;
 }
+
+bool litehtml::is_number(const string& string, const bool allow_dot) {
+	for (auto ch : string)
+	{
+		if (!(t_isdigit(ch) || (allow_dot && ch == '.')))
+		{
+			return false;
+		}
+	}
+	return true;
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/html.h b/src/plugins/litehtml_viewer/litehtml/html.h
index b184ac30a..818d5ce56 100644
--- a/src/plugins/litehtml_viewer/litehtml/html.h
+++ b/src/plugins/litehtml_viewer/litehtml/html.h
@@ -23,7 +23,7 @@
 
 namespace litehtml
 {
-	void trim(string &s);
+	void trim(string &s, const string& chars_to_trim = " \n\r\t");
 	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 = ';');
@@ -36,7 +36,9 @@ namespace litehtml
 
 	int t_strcasecmp(const char *s1, const char *s2);
 	int t_strncasecmp(const char *s1, const char *s2, size_t n);
-	
+
+	bool is_number(const string& string, const bool allow_dot = 1);
+
 	inline int t_isdigit(int c)
 	{
 		return (c >= '0' && c <= '9');
diff --git a/src/plugins/litehtml_viewer/litehtml/html_tag.cpp b/src/plugins/litehtml_viewer/litehtml/html_tag.cpp
index 0b978f56a..1814e9c3a 100644
--- a/src/plugins/litehtml_viewer/litehtml/html_tag.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/html_tag.cpp
@@ -367,6 +367,11 @@ int litehtml::html_tag::get_enum_property(string_id name, bool inherited, int de
 	return get_property_impl<int, prop_type_enum_item, &property_value::m_enum_item>(name, inherited, default_value, css_properties_member_offset);
 }
 
+int litehtml::html_tag::get_int_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);
@@ -1548,9 +1553,33 @@ litehtml::element::ptr litehtml::html_tag::get_element_after(const style& style,
 	return nullptr;
 }
 
+
+void litehtml::html_tag::handle_counter_properties()
+{
+	const auto& reset_property = m_style.get_property(string_id::_counter_reset_);
+	if (reset_property.m_type == prop_type_string_vector) {
+		auto reset_function = [&](const string_id&name_id, const int value) {
+			reset_counter(name_id, value);
+		};
+		parse_counter_tokens(reset_property.m_string_vector, 0, reset_function);
+		return;
+	}
+
+	const auto& inc_property = m_style.get_property(string_id::_counter_increment_);
+	if (inc_property.m_type == prop_type_string_vector) {
+		auto inc_function = [&](const string_id&name_id, const int value) {
+			increment_counter(name_id, value);
+		};
+		parse_counter_tokens(inc_property.m_string_vector, 1, inc_function);
+		return;
+	}
+}
+
+
 void litehtml::html_tag::add_style(const style& style)
 {
 	m_style.combine(style);
+	handle_counter_properties();
 }
 
 void litehtml::html_tag::refresh_styles()
diff --git a/src/plugins/litehtml_viewer/litehtml/html_tag.h b/src/plugins/litehtml_viewer/litehtml/html_tag.h
index 9148031b2..b085d7dfb 100644
--- a/src/plugins/litehtml_viewer/litehtml/html_tag.h
+++ b/src/plugins/litehtml_viewer/litehtml/html_tag.h
@@ -72,6 +72,7 @@ namespace litehtml
 		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;
+		int					get_int_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;
@@ -119,6 +120,10 @@ namespace litehtml
 		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);
+
+	private:
+		void				handle_counter_properties();
+
 	};
 
 	/************************************************************************/
diff --git a/src/plugins/litehtml_viewer/litehtml/line_box.cpp b/src/plugins/litehtml_viewer/litehtml/line_box.cpp
index 1ca9c85d7..e739e63c8 100644
--- a/src/plugins/litehtml_viewer/litehtml/line_box.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/line_box.cpp
@@ -363,7 +363,7 @@ std::list< std::unique_ptr<litehtml::line_box_item> > litehtml::line_box::finish
                 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->pos().y = bl - lbi->get_el()->get_last_baseline() +
 								lbi->get_el()->content_offset_top();
 					}
 					break;
@@ -374,7 +374,7 @@ std::list< std::unique_ptr<litehtml::line_box_item> > litehtml::line_box::finish
 					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->pos().y = current_context.baseline - lbi->get_el()->get_last_baseline() +
 							lbi->get_el()->content_offset_top();
                     break;
                 case va_text_top:
@@ -555,10 +555,23 @@ bool litehtml::line_box::can_hold(const std::unique_ptr<line_box_item>& item, wh
 
 	if(item->get_type() == line_box_item::type_text_part)
 	{
+		// force new line on floats clearing
+		if (item->get_el()->src_el()->is_break() && item->get_el()->src_el()->css().get_clear() != clear_none)
+		{
+			return false;
+		}
+
 		auto last_el = get_last_text_part();
 
+		// the first word is always can be hold
+		if(!last_el)
+		{
+			return true;
+		}
+
 		// force new line if the last placed element was line break
-		if (last_el && last_el->src_el()->is_break())
+		// Skip If there are the only break item - this is float clearing
+		if (last_el && last_el->src_el()->is_break() && m_items.size() > 1)
 		{
 			return false;
 		}
@@ -597,6 +610,12 @@ bool litehtml::line_box::have_last_space()  const
 bool litehtml::line_box::is_empty() const
 {
     if(m_items.empty()) return true;
+	if(m_items.size() == 1 &&
+		m_items.front()->get_el()->src_el()->is_break() &&
+		m_items.front()->get_el()->src_el()->css().get_clear() != clear_none)
+	{
+		return true;
+	}
     for (const auto& el : m_items)
     {
 		if(el->get_type() == line_box_item::type_text_part)
diff --git a/src/plugins/litehtml_viewer/litehtml/media_query.cpp b/src/plugins/litehtml_viewer/litehtml/media_query.cpp
index 7cddb15a2..8c2afff27 100644
--- a/src/plugins/litehtml_viewer/litehtml/media_query.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/media_query.cpp
@@ -88,8 +88,7 @@ litehtml::media_query::ptr litehtml::media_query::create_from_string(const strin
 			}
 		} else
 		{
-			query->m_media_type = (media_type) value_index(token, media_type_strings, media_type_all);
-
+			query->m_media_type = (media_type) value_index(token, media_type_strings, media_type_none);
 		}
 	}
 
diff --git a/src/plugins/litehtml_viewer/litehtml/render_block.cpp b/src/plugins/litehtml_viewer/litehtml/render_block.cpp
index d653f3114..c170c341f 100644
--- a/src/plugins/litehtml_viewer/litehtml/render_block.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/render_block.cpp
@@ -208,24 +208,21 @@ int litehtml::render_item_block::_render(int x, int y, const containing_block_co
 	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)
+	if(!(containing_block_size.size_mode & containing_block_context::size_mode_content))
 	{
-		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;
+		if(self_size.width.type == containing_block_context::cbc_value_type_absolute)
+		{
+			ret_width = m_pos.width = self_size.render_width;
+		} else
+		{
+			m_pos.width = self_size.render_width;
+		}
 	} else
 	{
-		m_pos.width = self_size.render_width;
-	}
-
-	// Fix width with min-width attribute
-	if(self_size.min_width.type != containing_block_context::cbc_value_type_none)
-	{
-		if(m_pos.width < self_size.min_width)
+		m_pos.width = ret_width;
+		if(self_size.width.type == containing_block_context::cbc_value_type_absolute && ret_width > self_size.width)
 		{
-			m_pos.width = self_size.min_width;
-			requires_rerender = true;
+			ret_width = self_size.width;
 		}
 	}
 
@@ -239,6 +236,19 @@ int litehtml::render_item_block::_render(int x, int y, const containing_block_co
 		}
 	}
 
+	// 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;
+		}
+	} else if(m_pos.width < 0)
+	{
+		m_pos.width = 0;
+	}
+
 	// re-render content with new width if required
 	if (requires_rerender && !second_pass && !is_root())
 	{
@@ -254,25 +264,44 @@ int litehtml::render_item_block::_render(int x, int y, const containing_block_co
 	}
 
 	// Set block height
-	if (self_size.height.type != containing_block_context::cbc_value_type_auto)
+	if (self_size.height.type != containing_block_context::cbc_value_type_auto &&
+	    !(containing_block_size.size_mode & containing_block_context::size_mode_content))
 	{
-		if(self_size.height > 0)
+		// TODO: Something wrong here
+		// Percentage height from undefined containing block height is usually <= 0
+		if(self_size.height.type == containing_block_context::cbc_value_type_percentage)
+		{
+			if (self_size.height > 0)
+			{
+				m_pos.height = self_size.height;
+			}
+		} else
 		{
 			m_pos.height = self_size.height;
 		}
-		if(src_el()->css().get_box_sizing() == box_sizing_border_box)
+		if (src_el()->css().get_box_sizing() == box_sizing_border_box)
 		{
 			m_pos.height -= box_sizing_height();
 		}
 	} else if (src_el()->is_block_formatting_context())
-    {
+	{
 		// add the floats' height to the block height
-        int floats_height = fmt_ctx->get_floats_height();
-        if (floats_height > m_pos.height)
-        {
-            m_pos.height = floats_height;
-        }
-    }
+		int floats_height = fmt_ctx->get_floats_height();
+		if (floats_height > m_pos.height)
+		{
+			m_pos.height = floats_height;
+		}
+	}
+	if(containing_block_size.size_mode & containing_block_context::size_mode_content)
+	{
+		if(self_size.height.type == containing_block_context::cbc_value_type_absolute)
+		{
+			if(m_pos.height > self_size.height)
+			{
+				m_pos.height = self_size.height;
+			}
+		}
+	}
 
 	// Fix height with min-height attribute
 	if(self_size.min_height.type != containing_block_context::cbc_value_type_none)
@@ -281,6 +310,9 @@ int litehtml::render_item_block::_render(int x, int y, const containing_block_co
 		{
 			m_pos.height = self_size.min_height;
 		}
+	} else if(m_pos.height < 0)
+	{
+		m_pos.height = 0;
 	}
 
 	// Fix width with max-width attribute
diff --git a/src/plugins/litehtml_viewer/litehtml/render_block_context.cpp b/src/plugins/litehtml_viewer/litehtml/render_block_context.cpp
index 7591378c2..bf6b09277 100644
--- a/src/plugins/litehtml_viewer/litehtml/render_block_context.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/render_block_context.cpp
@@ -47,20 +47,26 @@ int litehtml::render_item_block_context::_render_content(int x, int y, bool seco
                 // 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;
-                    }
+					if(el->get_margins().top > 0)
+					{
+						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->get_margins().top > 0)
+					{
+						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_block_formatting_context() || el->src_el()->css().get_display() == display_table)
@@ -104,10 +110,9 @@ int litehtml::render_item_block_context::_render_content(int x, int y, bool seco
         }
     }
 
-    int block_height = 0;
-    if (get_predefined_height(block_height, self_size.height))
+    if (self_size.height.type != containing_block_context::cbc_value_type_auto  && self_size.height > 0)
     {
-        m_pos.height = block_height;
+        m_pos.height = self_size.height;
     } else
     {
         m_pos.height = child_top;
@@ -127,3 +132,23 @@ int litehtml::render_item_block_context::_render_content(int x, int y, bool seco
 
     return ret_width;
 }
+
+int litehtml::render_item_block_context::get_first_baseline()
+{
+	if(m_children.empty())
+	{
+		return height() - margin_bottom();
+	}
+	const auto &item = m_children.front();
+	return content_offset_top() + item->top() + item->get_first_baseline();
+}
+
+int litehtml::render_item_block_context::get_last_baseline()
+{
+	if(m_children.empty())
+	{
+		return height() - margin_bottom();
+	}
+	const auto &item = m_children.back();
+	return content_offset_top() + item->top() + item->get_last_baseline();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/render_block_context.h b/src/plugins/litehtml_viewer/litehtml/render_block_context.h
index 3b5192261..c69389832 100644
--- a/src/plugins/litehtml_viewer/litehtml/render_block_context.h
+++ b/src/plugins/litehtml_viewer/litehtml/render_block_context.h
@@ -23,6 +23,8 @@ namespace litehtml
 		{
 			return std::make_shared<render_item_block_context>(src_el());
 		}
+		int get_first_baseline() override;
+		int get_last_baseline() override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/render_flex.cpp b/src/plugins/litehtml_viewer/litehtml/render_flex.cpp
index 2cab59e04..d0170e650 100644
--- a/src/plugins/litehtml_viewer/litehtml/render_flex.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/render_flex.cpp
@@ -4,12 +4,327 @@
 
 int litehtml::render_item_flex::_render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx)
 {
-    return 0;
+	bool is_row_direction = true;
+	bool reverse = false;
+	int container_main_size = self_size.render_width;
+
+	switch (css().get_flex_direction())
+	{
+		case flex_direction_column:
+			is_row_direction = false;
+			reverse = false;
+			break;
+		case flex_direction_column_reverse:
+			is_row_direction = false;
+			reverse = true;
+			break;
+		case flex_direction_row:
+			is_row_direction = true;
+			reverse = false;
+			break;
+		case flex_direction_row_reverse:
+			is_row_direction = true;
+			reverse = true;
+			break;
+	}
+
+	bool single_line = css().get_flex_wrap() == flex_wrap_nowrap;
+	bool fit_container = false;
+
+	if(!is_row_direction)
+	{
+		if(self_size.height.type != containing_block_context::cbc_value_type_auto)
+		{
+			container_main_size = self_size.height;
+			if (css().get_box_sizing() == box_sizing_border_box)
+			{
+				container_main_size -= box_sizing_height();
+			}
+		} else
+		{
+			// Direction columns, height is auto - always in single line
+			container_main_size = 0;
+			single_line = true;
+			fit_container = true;
+		}
+		if(self_size.min_height.type != containing_block_context::cbc_value_type_auto && self_size.min_height > container_main_size)
+		{
+			container_main_size = self_size.min_height;
+		}
+		if(self_size.max_height.type != containing_block_context::cbc_value_type_auto && self_size.max_height > container_main_size)
+		{
+			container_main_size = self_size.max_height;
+			single_line = false;
+		}
+	}
+
+	/////////////////////////////////////////////////////////////////
+	/// Split flex items to lines
+	/////////////////////////////////////////////////////////////////
+	m_lines = get_lines(self_size, fmt_ctx, is_row_direction, container_main_size, single_line);
+
+	int el_y = 0;
+	int el_x = 0;
+	int sum_cross_size = 0;
+	int sum_main_size = 0;
+	int ret_width = 0;
+
+	/////////////////////////////////////////////////////////////////
+	/// Resolving Flexible Lengths
+	/// REF: https://www.w3.org/TR/css-flexbox-1/#resolve-flexible-lengths
+	/////////////////////////////////////////////////////////////////
+	for(auto& ln : m_lines)
+	{
+		if(is_row_direction)
+		{
+			ret_width += ln.base_size;
+		}
+		ln.init(container_main_size, fit_container, is_row_direction, self_size, fmt_ctx);
+		sum_cross_size += ln.cross_size;
+		sum_main_size = std::max(sum_main_size, ln.main_size);
+		if(reverse)
+		{
+			ln.items.reverse();
+		}
+	}
+
+	int free_cross_size = 0;
+	int cross_start = 0;
+	bool is_wrap_reverse = css().get_flex_wrap() == flex_wrap_wrap_reverse;
+	if(container_main_size == 0)
+	{
+		container_main_size = sum_main_size;
+	}
+
+	/////////////////////////////////////////////////////////////////
+	/// Calculate free cross size
+	/////////////////////////////////////////////////////////////////
+	if (is_row_direction)
+	{
+		cross_start = content_offset_top();
+		if (self_size.height.type != containing_block_context::cbc_value_type_auto)
+		{
+			int height = self_size.height;
+			if (src_el()->css().get_box_sizing() == box_sizing_border_box)
+			{
+				height -= box_sizing_height();
+			}
+			free_cross_size = height - sum_cross_size;
+		}
+	} else
+	{
+		cross_start = content_offset_left();
+		free_cross_size = self_size.render_width - sum_cross_size;
+		ret_width = sum_cross_size;
+	}
+
+	/////////////////////////////////////////////////////////////////
+	/// Fix align-content property
+	/////////////////////////////////////////////////////////////////
+	flex_align_content align_content = css().get_flex_align_content();
+	if(align_content == flex_align_content_space_between)
+	{
+		// If the leftover free-space is negative or there is only a single flex line in the flex
+		// container, this value is identical to flex-start.
+		if (m_lines.size() == 1 || free_cross_size < 0) align_content = flex_align_content_flex_start;
+	}
+	if(align_content == flex_align_content_space_around)
+	{
+		// If the leftover free-space is negative or there is only a single flex line in the flex
+		// container, this value is identical to flex-start.
+		if (m_lines.size() == 1 || free_cross_size < 0) align_content = flex_align_content_center;
+	}
+
+	/////////////////////////////////////////////////////////////////
+	/// Distribute free cross size for align-content: stretch
+	/////////////////////////////////////////////////////////////////
+	if(css().get_flex_align_content() == flex_align_content_stretch && free_cross_size > 0)
+	{
+		int add = (int)((double) free_cross_size / (double) m_lines.size());
+		if(add > 0)
+		{
+			for (auto &ln: m_lines)
+			{
+				ln.cross_size += add;
+				free_cross_size -= add;
+			}
+		}
+		if(!m_lines.empty())
+		{
+			while (free_cross_size > 0)
+			{
+				for (auto &ln: m_lines)
+				{
+					ln.cross_size++;
+					free_cross_size--;
+				}
+			}
+		}
+	}
+
+	/// Reverse lines for flex-wrap: wrap-reverse
+	if(css().get_flex_wrap() == flex_wrap_wrap_reverse)
+	{
+		m_lines.reverse();
+	}
+
+	/////////////////////////////////////////////////////////////////
+	/// Align flex lines
+	/////////////////////////////////////////////////////////////////
+	int line_pos = 0;
+	int add_before_line = 0;
+	int add_after_line = 0;
+	switch (align_content)
+	{
+		case flex_align_content_flex_start:
+			if(is_wrap_reverse)
+			{
+				line_pos = free_cross_size;
+			}
+			break;
+		case flex_align_content_flex_end:
+			if(!is_wrap_reverse)
+			{
+				line_pos = free_cross_size;
+			}
+			break;
+		case flex_align_content_end:
+			line_pos = free_cross_size;
+			break;
+		case flex_align_content_center:
+			line_pos = free_cross_size / 2;
+			break;
+		case flex_align_content_space_between:
+			add_after_line = free_cross_size / ((int) m_lines.size() - 1);
+			break;
+		case flex_align_content_space_around:
+			add_before_line = add_after_line = free_cross_size / ((int) m_lines.size() * 2);
+			break;
+		default:
+			if(is_wrap_reverse)
+			{
+				line_pos = free_cross_size;
+			}
+			break;
+	}
+	for(auto &ln : m_lines)
+	{
+		line_pos += add_before_line;
+		ln.cross_start = line_pos;
+		line_pos += ln.cross_size + add_after_line;
+	}
+
+	/// Fix justify-content property
+	flex_justify_content justify_content = css().get_flex_justify_content();
+	if((justify_content == flex_justify_content_right || justify_content == flex_justify_content_left) && !is_row_direction)
+	{
+		justify_content = flex_justify_content_start;
+	}
+
+	/////////////////////////////////////////////////////////////////
+	/// Align flex items in flex lines
+	/////////////////////////////////////////////////////////////////
+	int line_num = 0;
+	for(auto &ln : m_lines)
+	{
+		int height = ln.calculate_items_position(container_main_size,
+									justify_content,
+									is_row_direction,
+									self_size,
+									fmt_ctx);
+		line_num++;
+		m_pos.height = std::max(m_pos.height, height);
+	}
+
+	// calculate the final position
+	m_pos.move_to(x, y);
+	m_pos.x += content_offset_left();
+	m_pos.y += content_offset_top();
+
+	return ret_width;
 }
 
-void litehtml::render_item_flex::draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex)
+std::list<litehtml::flex_line> litehtml::render_item_flex::get_lines(const litehtml::containing_block_context &self_size,
+																	 litehtml::formatting_context *fmt_ctx,
+																	 bool is_row_direction, int container_main_size,
+																	 bool single_line)
 {
+	bool reverse_main;
+	bool reverse_cross = css().get_flex_wrap() == flex_wrap_wrap_reverse;
+
+	if(is_row_direction)
+	{
+		reverse_main = css().get_flex_direction() == flex_direction_row_reverse;
+	} else
+	{
+		reverse_main = css().get_flex_direction() == flex_direction_column_reverse;
+	}
+
+	std::list<flex_line> lines;
+	flex_line line(reverse_main, reverse_cross);
+	std::list<std::shared_ptr<flex_item>> items;
+	int src_order = 0;
+	bool sort_required = false;
+	def_value<int> prev_order(0);
+
+	for( auto& el : m_children)
+	{
+		std::shared_ptr<flex_item> item = nullptr;
+		if(is_row_direction)
+		{
+			item = std::make_shared<flex_item_row_direction>(el);
+		} else
+		{
+			item = std::make_shared<flex_item_column_direction>(el);
+		}
+		item->init(self_size, fmt_ctx, css().get_flex_align_items());
+		item->src_order = src_order++;
 
+		if(prev_order.is_default())
+		{
+			prev_order = item->order;
+		} else if(!sort_required && item->order != prev_order)
+		{
+			sort_required = true;
+		}
+
+		items.emplace_back(item);
+	}
+
+	if(sort_required)
+	{
+		items.sort([](const std::shared_ptr<flex_item>& item1, const std::shared_ptr<flex_item>& item2)
+					   {
+					   		if(item1->order < item2->order) return true;
+					   		if(item1->order == item2->order)
+							{
+								return item1->src_order < item2->src_order;
+							}
+							return false;
+					   });
+	}
+
+	// Add flex items to lines
+	for(auto& item : items)
+	{
+		if(!line.items.empty() && !single_line && line.base_size + item->base_size > container_main_size)
+		{
+			lines.emplace_back(line);
+			line = flex_line(reverse_main, reverse_cross);
+		}
+		line.base_size += item->base_size;
+		line.total_grow += item->grow;
+		line.total_shrink += item->shrink;
+		if(!item->auto_margin_main_start.is_default()) line.num_auto_margin_main_start++;
+		if(!item->auto_margin_main_end.is_default()) line.num_auto_margin_main_end++;
+		line.items.push_back(item);
+	}
+	// Add the last line to the lines list
+	if(!line.items.empty())
+	{
+		lines.emplace_back(line);
+	}
+	return lines;
 }
 
 std::shared_ptr<litehtml::render_item> litehtml::render_item_flex::init()
@@ -81,10 +396,60 @@ std::shared_ptr<litehtml::render_item> litehtml::render_item_flex::init()
     }
     convert_inlines();
     children() = new_children;
-    for(const auto& el : children())
-    {
-        m_flex_items.emplace_back(new flex_item(el));
-    }
 
     return shared_from_this();
 }
+
+int litehtml::render_item_flex::get_first_baseline()
+{
+	if(css().get_flex_direction() == flex_direction_row || css().get_flex_direction() == flex_direction_row_reverse)
+	{
+		if(!m_lines.empty())
+		{
+			const auto &first_line = m_lines.front();
+			if(first_line.first_baseline.type() != baseline::baseline_type_none)
+			{
+				return first_line.cross_start + first_line.first_baseline.get_offset_from_top(first_line.cross_size) + content_offset_top();
+			}
+			if(first_line.last_baseline.type() != baseline::baseline_type_none)
+			{
+				return first_line.cross_start + first_line.last_baseline.get_offset_from_top(first_line.cross_size) + content_offset_top();
+			}
+		}
+	}
+	if(!m_lines.empty())
+	{
+		if(!m_lines.front().items.empty())
+		{
+			return m_lines.front().items.front()->el->get_first_baseline() + content_offset_top();
+		}
+	}
+	return height();
+}
+
+int litehtml::render_item_flex::get_last_baseline()
+{
+	if(css().get_flex_direction() == flex_direction_row || css().get_flex_direction() == flex_direction_row_reverse)
+	{
+		if(!m_lines.empty())
+		{
+			const auto &first_line = m_lines.front();
+			if(first_line.last_baseline.type() != baseline::baseline_type_none)
+			{
+				return first_line.cross_start + first_line.last_baseline.get_offset_from_top(first_line.cross_size) + content_offset_top();
+			}
+			if(first_line.first_baseline.type() != baseline::baseline_type_none)
+			{
+				return first_line.cross_start + first_line.first_baseline.get_offset_from_top(first_line.cross_size) + content_offset_top();
+			}
+		}
+	}
+	if(!m_lines.empty())
+	{
+		if(!m_lines.front().items.empty())
+		{
+			return m_lines.front().items.front()->el->get_last_baseline() + content_offset_top();
+		}
+	}
+	return height();
+}
diff --git a/src/plugins/litehtml_viewer/litehtml/render_flex.h b/src/plugins/litehtml_viewer/litehtml/render_flex.h
index 5d31bc9bf..6a03b98ec 100644
--- a/src/plugins/litehtml_viewer/litehtml/render_flex.h
+++ b/src/plugins/litehtml_viewer/litehtml/render_flex.h
@@ -2,32 +2,17 @@
 #define LITEHTML_RENDER_FLEX_H
 
 #include "render_block.h"
+#include "flex_item.h"
+#include "flex_line.h"
 
 namespace litehtml
 {
 	class render_item_flex : public render_item_block
 	{
-		struct flex_item
-		{
-			std::shared_ptr<render_item> el;
-			int base_size;
-			int main_size;
-			int min_width;
-			int max_width;
-			int line;
-
-			explicit flex_item(std::shared_ptr<render_item>  _el) :
-					el(std::move(_el)),
-					min_width(0),
-					max_width(0),
-					line(0),
-					base_size(0),
-					main_size(0)
-			{}
-		};
-	protected:
-		std::list<std::unique_ptr<flex_item>>   m_flex_items;
+		std::list<flex_line> m_lines;
 
+		std::list<flex_line> get_lines(const containing_block_context &self_size, formatting_context *fmt_ctx, bool is_row_direction,
+									   int container_main_size, bool single_line);
 		int _render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) override;
 
 	public:
@@ -38,8 +23,10 @@ namespace litehtml
 		{
 			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;
+
+		int get_first_baseline() override;
+		int get_last_baseline() override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/render_image.cpp b/src/plugins/litehtml_viewer/litehtml/render_image.cpp
index 63e622d7b..1ff4574bb 100644
--- a/src/plugins/litehtml_viewer/litehtml/render_image.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/render_image.cpp
@@ -5,6 +5,7 @@
 int litehtml::render_item_image::_render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass)
 {
     int parent_width = containing_block_size.width;
+	containing_block_context self_size = calculate_containing_block_context(containing_block_size);
 
     calc_outlines(parent_width);
 
@@ -60,10 +61,10 @@ int litehtml::render_item_image::_render(int x, int y, const containing_block_co
         }
     } 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();
-        }
+		if(self_size.height.type != containing_block_context::cbc_value_type_auto && self_size.height > 0)
+		{
+			m_pos.height = self_size.height;
+		}
 
         // check for max-height
         if(!src_el()->css().get_max_height().is_predefined())
@@ -107,10 +108,10 @@ int litehtml::render_item_image::_render(int x, int y, const containing_block_co
     {
         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();
-        }
+		if(self_size.height.type != containing_block_context::cbc_value_type_auto && self_size.height > 0)
+		{
+			m_pos.height = self_size.height;
+		}
 
         // check for max-height
         if(!src_el()->css().get_max_height().is_predefined())
diff --git a/src/plugins/litehtml_viewer/litehtml/render_inline.cpp b/src/plugins/litehtml_viewer/litehtml/render_inline.cpp
deleted file mode 100644
index 0ea24b17d..000000000
--- a/src/plugins/litehtml_viewer/litehtml/render_inline.cpp
+++ /dev/null
@@ -1,3 +0,0 @@
-#include "html.h"
-#include "render_item.h"
-
diff --git a/src/plugins/litehtml_viewer/litehtml/render_inline.h b/src/plugins/litehtml_viewer/litehtml/render_inline.h
index 476011563..666074b90 100644
--- a/src/plugins/litehtml_viewer/litehtml/render_inline.h
+++ b/src/plugins/litehtml_viewer/litehtml/render_inline.h
@@ -18,7 +18,14 @@ namespace litehtml
 		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(); }
+		int get_first_baseline() override
+		{
+			return src_el()->css().get_font_metrics().height - src_el()->css().get_font_metrics().base_line();
+		}
+		int get_last_baseline() override
+		{
+			return src_el()->css().get_font_metrics().height - src_el()->css().get_font_metrics().base_line();
+		}
 
 		std::shared_ptr<render_item> clone() override
 		{
@@ -28,3 +35,4 @@ namespace litehtml
 }
 
 #endif //LITEHTML_RENDER_INLINE_H
+
diff --git a/src/plugins/litehtml_viewer/litehtml/render_inline_context.cpp b/src/plugins/litehtml_viewer/litehtml/render_inline_context.cpp
index 2d8f2e173..4f5d77015 100644
--- a/src/plugins/litehtml_viewer/litehtml/render_inline_context.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/render_inline_context.cpp
@@ -382,21 +382,30 @@ void litehtml::render_item_inline_context::apply_vertical_align()
     }
 }
 
-int litehtml::render_item_inline_context::get_base_line()
+int litehtml::render_item_inline_context::get_first_baseline()
 {
-    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;
+	int bl;
+	if(!m_line_boxes.empty())
+	{
+		const auto &line = m_line_boxes.front();
+		bl = line->bottom() - line->baseline() + content_offset_top();
+	} else
+	{
+		bl = height() - margin_bottom();
+	}
+	return bl;
+}
+
+int litehtml::render_item_inline_context::get_last_baseline()
+{
+	int bl;
+	if(!m_line_boxes.empty())
+	{
+		const auto &line = m_line_boxes.back();
+		bl = line->bottom() - line->baseline() + content_offset_top();
+	} else
+	{
+		bl = height() - margin_bottom();
+	}
+	return bl;
 }
diff --git a/src/plugins/litehtml_viewer/litehtml/render_inline_context.h b/src/plugins/litehtml_viewer/litehtml/render_inline_context.h
index 894cfe989..7d629bc7f 100644
--- a/src/plugins/litehtml_viewer/litehtml/render_inline_context.h
+++ b/src/plugins/litehtml_viewer/litehtml/render_inline_context.h
@@ -48,7 +48,8 @@ namespace litehtml
 			return std::make_shared<render_item_inline_context>(src_el());
 		}
 
-		int get_base_line() override;
+		int get_first_baseline() override;
+		int get_last_baseline() override;
 	};
 }
 
diff --git a/src/plugins/litehtml_viewer/litehtml/render_item.cpp b/src/plugins/litehtml_viewer/litehtml/render_item.cpp
index 4eb25757d..0af172807 100644
--- a/src/plugins/litehtml_viewer/litehtml/render_item.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/render_item.cpp
@@ -138,37 +138,6 @@ void litehtml::render_item::apply_relative_shift(const containing_block_context
     }
 }
 
-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 p_height > 0;
-}
-
-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>,
@@ -679,7 +648,7 @@ void litehtml::render_item::draw_children(uint_ptr hdc, int x, int y, const posi
                     if (el->src_el()->is_inline() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned())
                     {
                         el->src_el()->draw(hdc, pos.x, pos.y, clip, el);
-                        if (el->src_el()->css().get_display() == display_inline_block)
+                        if (el->src_el()->css().get_display() == display_inline_block || el->src_el()->css().get_display() == display_inline_flex)
                         {
                             el->draw_stacking_context(hdc, pos.x, pos.y, clip, false);
                             process = false;
@@ -816,7 +785,7 @@ std::shared_ptr<litehtml::element>  litehtml::render_item::get_child_by_point(in
                 } else
                 {
                     if(	el->src_el()->css().get_float() == float_none &&
-                           el->src_el()->css().get_display() != display_inline_block)
+                           el->src_el()->css().get_display() != display_inline_block && el->src_el()->css().get_display() != display_inline_flex)
                     {
                         element::ptr child = el->get_child_by_point(el_pos.x, el_pos.y, client_x, client_y, flag, zindex);
                         if(child)
@@ -845,25 +814,23 @@ std::shared_ptr<litehtml::element> litehtml::render_item::get_element_by_point(i
         z_indexes[i->src_el()->css().get_z_index()];
     }
 
-    for(const auto& zindex : z_indexes)
+    for(auto iter = z_indexes.rbegin(); iter != z_indexes.rend(); iter++)
     {
-        if(zindex.first > 0)
+        if(iter->first > 0)
         {
-            ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, zindex.first);
-            break;
+            ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, iter->first);
+			if(ret) return ret;
         }
     }
-    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(ret) return ret;
 
     ret = get_child_by_point(x, y, client_x, client_y, draw_inlines, 0);
     if(ret) return ret;
@@ -875,15 +842,14 @@ std::shared_ptr<litehtml::element> litehtml::render_item::get_element_by_point(i
     if(ret) return ret;
 
 
-    for(const auto& z_index : z_indexes)
-    {
-        if(z_index.first < 0)
+	for(auto iter = z_indexes.rbegin(); iter != z_indexes.rend(); iter++)
+	{
+        if(iter->first < 0)
         {
-            ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, z_index.first);
-            break;
+            ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, iter->first);
+			if(ret) return ret;
         }
     }
-    if(ret) return ret;
 
     if(src_el()->css().get_position() == element_position_fixed)
     {
@@ -1042,8 +1008,55 @@ litehtml::containing_block_context litehtml::render_item::calculate_containing_b
 	// 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);
+		auto par = parent();
+		if(cb_context.size_mode & containing_block_context::size_mode_exact_width)
+		{
+			ret.width.value = cb_context.width;
+			ret.width.type = containing_block_context::cbc_value_type_absolute;
+		} else
+		{
+			auto *width = &css().get_width();
+			if(par && (par->css().get_display() == display_flex || par->css().get_display() == display_inline_flex))
+			{
+				if(!css().get_flex_basis().is_predefined() && css().get_flex_basis().val() >= 0)
+				{
+					if(par->css().get_flex_direction() == flex_direction_row || par->css().get_flex_direction() == flex_direction_row_reverse)
+					{
+						ret.width.type = containing_block_context::cbc_value_type_auto;
+						ret.width.value = 0;
+						width = nullptr;
+					}
+				}
+			}
+			if(width)
+			{
+				calc_cb_length(*width, cb_context.width, ret.width);
+			}
+		}
+		if(cb_context.size_mode & containing_block_context::size_mode_exact_height)
+		{
+			ret.height.value = cb_context.height;
+			ret.height.type = containing_block_context::cbc_value_type_absolute;
+		} else
+		{
+			auto *height = &css().get_height();
+			if(par && (par->css().get_display() == display_flex || par->css().get_display() == display_inline_flex))
+			{
+				if(!css().get_flex_basis().is_predefined() && css().get_flex_basis().val() >= 0)
+				{
+					if(par->css().get_flex_direction() == flex_direction_column || par->css().get_flex_direction() == flex_direction_column_reverse)
+					{
+						ret.height.type = containing_block_context::cbc_value_type_auto;
+						ret.height.value = 0;
+						height = nullptr;
+					}
+				}
+			}
+			if(height)
+			{
+				calc_cb_length(*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();
@@ -1061,28 +1074,27 @@ litehtml::containing_block_context litehtml::render_item::calculate_containing_b
 	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)
+	// Fix box sizing
+	if(ret.width.type != containing_block_context::cbc_value_type_auto)
 	{
-		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();
-		}
+		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;
 }
diff --git a/src/plugins/litehtml_viewer/litehtml/render_item.h b/src/plugins/litehtml_viewer/litehtml/render_item.h
index 9d4561e5a..ac8a9f4c6 100644
--- a/src/plugins/litehtml_viewer/litehtml/render_item.h
+++ b/src/plugins/litehtml_viewer/litehtml/render_item.h
@@ -86,7 +86,7 @@ namespace litehtml
 
         int width() const
         {
-            return m_pos.width + m_margins.left + m_margins.right + m_padding.width() + m_borders.width();
+            return m_pos.width + m_margins.width() + m_padding.width() + m_borders.width();
         }
 
         int padding_top() const
@@ -224,27 +224,43 @@ namespace litehtml
 
 		int box_sizing_left() const
 		{
-			return m_padding.left + m_borders.left;
+			if(css().get_box_sizing() == box_sizing_border_box)
+			{
+				return m_padding.left + m_borders.left;
+			}
+			return 0;
 		}
 
 		int box_sizing_right() const
 		{
-			return m_padding.right + m_borders.right;
+			if(css().get_box_sizing() == box_sizing_border_box)
+			{
+				return m_padding.right + m_borders.right;
+			}
+			return 0;
 		}
 
 		int box_sizing_width() const
 		{
-			return box_sizing_left() + box_sizing_left();
+			return box_sizing_left() + box_sizing_right();
 		}
 
 		int box_sizing_top() const
 		{
-			return m_padding.top + m_borders.top;
+			if(css().get_box_sizing() == box_sizing_border_box)
+			{
+				return m_padding.top + m_borders.top;
+			}
+			return 0;
 		}
 
 		int box_sizing_bottom() const
 		{
-			return m_padding.bottom + m_borders.bottom;
+			if(css().get_box_sizing() == box_sizing_border_box)
+			{
+				return m_padding.bottom + m_borders.bottom;
+			}
+			return 0;
 		}
 
 		int box_sizing_height() const
@@ -285,6 +301,7 @@ namespace litehtml
                    m_element->in_normal_flow() &&
                    m_element->css().get_float() == float_none &&
                    m_margins.top >= 0 &&
+				   !is_flex_item() &&
                    !is_root();
         }
 
@@ -303,16 +320,34 @@ namespace litehtml
             return !(m_skip || src_el()->css().get_display() == display_none || src_el()->css().get_visibility() != visibility_visible);
         }
 
+		bool is_flex_item() const
+		{
+			auto par = parent();
+			if(par && (par->css().get_display() == display_inline_flex || par->css().get_display() == display_flex))
+			{
+				return true;
+			}
+			return false;
+		}
+
 		int render(int x, int y, const containing_block_context& containing_block_size, formatting_context* fmt_ctx, bool second_pass = false);
-        int calc_width(int defVal, int containing_block_width) const;
-        bool get_predefined_height(int& p_height, int containing_block_height) const;
         void apply_relative_shift(const containing_block_context &containing_block_size);
         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; }
+		/**
+		 * Get first baseline position. Default position is element bottom without bottom margin.
+		 * @returns offset of the first baseline from element top
+		 */
+		virtual int get_first_baseline() { return height() - margin_bottom(); }
+		/**
+		 * Get last baseline position.  Default position is element bottom without bottom margin.
+		 * @returns offset of the last baseline from element top
+		 */
+		virtual int get_last_baseline() { return height() - margin_bottom(); }
+
         virtual std::shared_ptr<render_item> clone()
         {
             return std::make_shared<render_item>(src_el());
diff --git a/src/plugins/litehtml_viewer/litehtml/render_table.cpp b/src/plugins/litehtml_viewer/litehtml/render_table.cpp
index 1a3859641..fdff1f826 100644
--- a/src/plugins/litehtml_viewer/litehtml/render_table.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/render_table.cpp
@@ -261,10 +261,10 @@ int litehtml::render_item_table::_render(int x, int y, const containing_block_co
 
     // 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();
-    }
+	if(self_size.height.type != containing_block_context::cbc_value_type_auto && self_size.height > 0)
+	{
+		block_height = self_size.height - (m_padding.height() + m_borders.height());
+	}
 
     // calculate minimum height from m_css.get_min_height()
     int min_height = 0;
diff --git a/src/plugins/litehtml_viewer/litehtml/string_id.h b/src/plugins/litehtml_viewer/litehtml/string_id.h
index 60d30f5e4..2c90fc659 100644
--- a/src/plugins/litehtml_viewer/litehtml/string_id.h
+++ b/src/plugins/litehtml_viewer/litehtml/string_id.h
@@ -289,6 +289,10 @@ STRING_ID(
 	_flex_basis_,
 
 	_caption_side_,
+	_order_,
+
+  _counter_reset_,
+	_counter_increment_,
 );
 #undef STRING_ID
 extern const string_id empty_id; // _id("")
diff --git a/src/plugins/litehtml_viewer/litehtml/style.cpp b/src/plugins/litehtml_viewer/litehtml/style.cpp
index 5642d36c4..356f49afc 100644
--- a/src/plugins/litehtml_viewer/litehtml/style.cpp
+++ b/src/plugins/litehtml_viewer/litehtml/style.cpp
@@ -43,7 +43,7 @@ std::map<string_id, string> style::m_valid_values =
 	{ _justify_content_, flex_justify_content_strings },
 	{ _align_items_, flex_align_items_strings },
 	{ _align_content_, flex_align_content_strings },
-	{ _align_self_, flex_align_self_strings },
+	{ _align_self_, flex_align_items_strings },
 
 	{ _caption_side_, caption_side_strings },
 };
@@ -128,9 +128,7 @@ void style::add_property(string_id name, const string& val, const string& baseur
 	case _flex_direction_:
 	case _flex_wrap_:
 	case _justify_content_:
-	case _align_items_:
 	case _align_content_:
-	case _align_self_:
 
 	case _caption_side_:
 
@@ -141,6 +139,11 @@ void style::add_property(string_id name, const string& val, const string& baseur
 		}
 		break;
 
+	case _align_items_:
+	case _align_self_:
+		parse_align_self(name, val, important);
+		break;
+
 	// <length>
 	case _text_indent_:
 	case _padding_left_:
@@ -536,6 +539,25 @@ void style::add_property(string_id name, const string& val, const string& baseur
 		add_parsed_property(_flex_basis_, property_value(length, important));
 		break;
 
+	case _order_: // <integer>
+		{
+			char* end;
+			int int_val = (int) strtol(val.c_str(), &end, 10);
+			if(end[0] == '\0')
+			{
+				add_parsed_property(name, property_value(int_val, important));
+			}
+		}
+		break;
+	case _counter_increment_:
+	case _counter_reset_:
+	{	
+		string_vector tokens;
+		split_string(val, tokens, " ");
+		add_parsed_property(name, property_value(tokens, important));
+		break;
+	}
+
 	default:
 		add_parsed_property(name, property_value(val, important));
 	}
@@ -972,14 +994,16 @@ void style::parse_font(const string& val, bool important)
 		{
 			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)
+			if(!szlh.empty())
 			{
-				auto height = css_length::from_string(szlh[1], "normal", -1);
-				add_parsed_property(_line_height_, property_value(height, important));
+				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
 		{
@@ -992,18 +1016,6 @@ void style::parse_font(const string& val, bool important)
 
 void style::parse_flex(const string& val, bool important)
 {
-	auto is_number = [](const string& val)
-	{
-		for (auto ch : val)
-		{
-			if ((ch < '0' || ch > '9') && ch != '.')
-			{
-				return false;
-			}
-		}
-		return true;
-	};
-
 	css_length _auto = css_length::predef_value(flex_basis_auto);
 
 	if (val == "initial")
@@ -1036,6 +1048,10 @@ void style::parse_flex(const string& val, bool 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);
+			if(!basis.is_predefined() && basis.units() == css_units_none && basis.val() == 0)
+			{
+				basis.set_value(basis.val(), css_units_px);
+			}
 			
 			add_parsed_property(_flex_grow_,	property_value(grow, important));
 			add_parsed_property(_flex_shrink_,	property_value(shrink, important));
@@ -1046,10 +1062,11 @@ void style::parse_flex(const string& val, bool important)
 			float grow = t_strtof(tokens[0]);
 			add_parsed_property(_flex_grow_, property_value(grow, important));
 			
-			if (is_number(tokens[1]))
+			if (litehtml::is_number(tokens[1]))
 			{
 				float shrink = t_strtof(tokens[1]);
 				add_parsed_property(_flex_shrink_, property_value(shrink, important));
+				add_parsed_property(_flex_basis_, property_value(css_length(0), important));
 			}
 			else
 			{
@@ -1063,22 +1080,65 @@ void style::parse_flex(const string& val, bool important)
 			{
 				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));
-				}
+				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_grow_, property_value(1.f, important));
+				add_parsed_property(_flex_shrink_, property_value(1.f, important));
 				add_parsed_property(_flex_basis_, property_value(basis, important));
 			}
 		}
 	}
 }
 
+void style::parse_align_self(string_id name, const string& val, bool important)
+{
+	string_vector tokens;
+	split_string(val, tokens, " ");
+	if(tokens.size() == 1)
+	{
+		int idx = value_index(val, m_valid_values[name]);
+		if (idx >= 0)
+		{
+			add_parsed_property(name, property_value(idx, important));
+		}
+	} else
+	{
+		int val1 = 0;
+		int val2 = -1;
+		for(auto &token : tokens)
+		{
+			if(token == "first")
+			{
+				val1 |= flex_align_items_first;
+			} else if(token == "last")
+			{
+				val1 |= flex_align_items_last;
+			} else if(token == "safe")
+			{
+				val1 |= flex_align_items_safe;
+			} else if(token == "unsafe")
+			{
+				val1 |= flex_align_items_unsafe;
+			} else
+			{
+				int idx = value_index(token, m_valid_values[name]);
+				if(idx >= 0)
+				{
+					val2 = idx;
+				}
+			}
+		}
+		if(val2 >= 0)
+		{
+			add_parsed_property(name, property_value(val1 | val2, important));
+		}
+	}
+}
+
 void style::add_parsed_property( string_id name, const property_value& propval )
 {
 	auto prop = m_properties.find(name);
diff --git a/src/plugins/litehtml_viewer/litehtml/style.h b/src/plugins/litehtml_viewer/litehtml/style.h
index c83876ad6..2e04059f2 100644
--- a/src/plugins/litehtml_viewer/litehtml/style.h
+++ b/src/plugins/litehtml_viewer/litehtml/style.h
@@ -199,6 +199,7 @@ namespace litehtml
 		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);
+		void parse_align_self(string_id name, 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]);
diff --git a/src/plugins/litehtml_viewer/litehtml/types.h b/src/plugins/litehtml_viewer/litehtml/types.h
index b1feeeea6..bfcaa6c3a 100644
--- a/src/plugins/litehtml_viewer/litehtml/types.h
+++ b/src/plugins/litehtml_viewer/litehtml/types.h
@@ -195,6 +195,14 @@ namespace litehtml
 			cbc_value_type_none,		// min/max width/height of containing block is defined as none
 		};
 
+		enum cbc_size_mode
+		{
+			size_mode_normal = 0x00,
+			size_mode_exact_width = 0x01,
+			size_mode_exact_height = 0x02,
+			size_mode_content = 0x04,
+		};
+
 		struct typed_int
 		{
 			int 			value;
@@ -235,6 +243,7 @@ namespace litehtml
 		typed_int max_height;
 
 		int context_idx;
+		uint32_t size_mode;
 
 		containing_block_context() :
 				width(0, cbc_value_type_auto),
@@ -244,17 +253,26 @@ namespace litehtml
 				height(0, cbc_value_type_auto),
 				min_height(0, cbc_value_type_none),
 				max_height(0, cbc_value_type_none),
-				context_idx(0)
+				context_idx(0),
+				size_mode(size_mode_normal)
 		{}
 
-		containing_block_context new_width(int w) const
+		containing_block_context new_width(int w, uint32_t _size_mode = size_mode_normal) 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;
-			}
+			ret.render_width = w - (ret.width - ret.render_width);
+			ret.width = w;
+			ret.size_mode = _size_mode;
+			return ret;
+		}
+
+		containing_block_context new_width_height(int w, int h, uint32_t _size_mode = size_mode_normal) const
+		{
+			containing_block_context ret = *this;
+			ret.render_width = w - (ret.width - ret.render_width);
+			ret.width = w;
+			ret.height = h;
+			ret.size_mode = _size_mode;
 			return ret;
 		}
 	};
@@ -693,7 +711,7 @@ namespace litehtml
 			m_is_default	= true;
 			m_val			= def_val;
 		}
-		bool is_default()
+		bool is_default() const
 		{
 			return m_is_default;
 		}
@@ -703,12 +721,72 @@ namespace litehtml
 			m_is_default	= false;
 			return m_val;
 		}
-		operator T()
+		operator T() const
 		{
 			return m_val;
 		}
 	};
 
+	class baseline
+	{
+	public:
+		enum _baseline_type
+		{
+			baseline_type_none,
+			baseline_type_top,
+			baseline_type_bottom,
+		};
+
+	public:
+		baseline() : m_value(0), m_type(baseline_type_none) {}
+		baseline(int _value, _baseline_type _type) : m_value(_value), m_type(_type) {}
+
+		int value() const				{ return m_value; 	}
+		void value(int _value) 			{ m_value = _value; }
+		_baseline_type type() const		{ return m_type; 	}
+		void type(_baseline_type _type)	{ m_type = _type; 	}
+
+		operator int() const	{ return m_value; 	}
+		baseline& operator=(int _value) { m_value = _value; return *this; }
+
+		void set(int _value, _baseline_type _type)	{ m_value = _value; m_type =_type; }
+		/**
+		 * Get baseline offset from top of element with specified height
+		 * @param height - element height
+		 * @return baseline offset
+		 */
+		int get_offset_from_top(int height) const
+		{
+			if(m_type == baseline_type_top) return m_value;
+			return height - m_value;
+		}
+		/**
+		 * Get baseline offset from bottom of element with specified height
+		 * @param height - element height
+		 * @return baseline offset
+		 */
+		int get_offset_from_bottom(int height) const
+		{
+			if(m_type == baseline_type_bottom) return m_value;
+			return height - m_value;
+		}
+		/**
+		 * Calculate baseline by top and bottom positions of element aligned by baseline == 0
+		 * @param top - top of the aligned element
+		 * @param bottom - bottom of the aligned element
+		 */
+		void calc(int top, int bottom)
+		{
+			if(m_type == baseline_type_top)
+				m_value = -top;
+			else if(m_type == baseline_type_bottom)
+				m_value = bottom;
+		}
+	private:
+		int m_value;
+		_baseline_type m_type;
+	};
+
 
 #define media_orientation_strings		"portrait;landscape"
 
@@ -848,46 +926,51 @@ namespace litehtml
 		flex_wrap_wrap_reverse
 	};
 
-#define flex_justify_content_strings		"flex-start;flex-end;center;space-between;space-around"
+#define flex_justify_content_strings		"normal;flex-start;flex-end;center;space-between;space-around;start;end;left;right;space-evenly;stretch"
 
 	enum flex_justify_content
 	{
+		flex_justify_content_normal,
 		flex_justify_content_flex_start,
 		flex_justify_content_flex_end,
 		flex_justify_content_center,
 		flex_justify_content_space_between,
-		flex_justify_content_space_around
+		flex_justify_content_space_around,
+		flex_justify_content_start,
+		flex_justify_content_end,
+		flex_justify_content_left,
+		flex_justify_content_right,
+		flex_justify_content_space_evenly,
+		flex_justify_content_stretch,
 	};
 
-#define flex_align_items_strings		"flex-start;flex-end;center;baseline;stretch"
+#define flex_align_items_strings		"normal;flex-start;flex-end;center;start;end;baseline;stretch;auto"
 
 	enum flex_align_items
 	{
+		flex_align_items_flex_normal,
 		flex_align_items_flex_start,
 		flex_align_items_flex_end,
 		flex_align_items_center,
+		flex_align_items_start,
+		flex_align_items_end,
 		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
+		flex_align_items_stretch,
+		flex_align_items_auto, // used for align-self property only
+		flex_align_items_first = 0x100,
+		flex_align_items_last = 0x200,
+		flex_align_items_unsafe = 0x400,
+		flex_align_items_safe  = 0x800,
 	};
 
-#define flex_align_content_strings		"flex-start;flex-end;center;space-between;space-around;stretch"
+#define flex_align_content_strings		"flex-start;start;flex-end;end;center;space-between;space-around;stretch"
 
 	enum flex_align_content
 	{
 		flex_align_content_flex_start,
+		flex_align_content_start,
 		flex_align_content_flex_end,
+		flex_align_content_end,
 		flex_align_content_center,
 		flex_align_content_space_between,
 		flex_align_content_space_around,

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


hooks/post-receive
-- 
Claws Mail


More information about the Commits mailing list