Gitweb links:

...log 
http://git.netsurf-browser.org/netsurf.git/shortlog/c83e1e96691c4c4fc7b1324ad3c2813613000296
...commit 
http://git.netsurf-browser.org/netsurf.git/commit/c83e1e96691c4c4fc7b1324ad3c2813613000296
...tree 
http://git.netsurf-browser.org/netsurf.git/tree/c83e1e96691c4c4fc7b1324ad3c2813613000296

The branch, tlsa/flex has been updated
  discards  285b25d12e6ce3eaa7da99f3f959b0b3f4943b43 (commit)
       via  c83e1e96691c4c4fc7b1324ad3c2813613000296 (commit)

This update added new revisions after undoing existing revisions.  That is
to say, the old revision is not a strict subset of the new revision.  This
situation occurs when you --force push a change and generate a repository
containing something like this:

 * -- * -- B -- O -- O -- O (285b25d12e6ce3eaa7da99f3f959b0b3f4943b43)
            \
             N -- N -- N (c83e1e96691c4c4fc7b1324ad3c2813613000296)

When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=c83e1e96691c4c4fc7b1324ad3c2813613000296
commit c83e1e96691c4c4fc7b1324ad3c2813613000296
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    WIP: flex

diff --git a/content/handlers/html/Makefile b/content/handlers/html/Makefile
index 8bb329b..e41cc1d 100644
--- a/content/handlers/html/Makefile
+++ b/content/handlers/html/Makefile
@@ -16,6 +16,7 @@ S_HTML := box_construct.c     \
        imagemap.c              \
        interaction.c           \
        layout.c                \
+       layout_flex.c           \
        object.c                \
        redraw.c                \
        redraw_border.c         \
diff --git a/content/handlers/html/box.h b/content/handlers/html/box.h
index 1059556..df2b99d 100644
--- a/content/handlers/html/box.h
+++ b/content/handlers/html/box.h
@@ -66,7 +66,9 @@ typedef enum {
        BOX_BR,
        BOX_TEXT,
        BOX_INLINE_END,
-       BOX_NONE
+       BOX_NONE,
+       BOX_FLEX,
+       BOX_INLINE_FLEX,
 } box_type;
 
 
diff --git a/content/handlers/html/box_construct.c 
b/content/handlers/html/box_construct.c
index 52e888e..245aab4 100644
--- a/content/handlers/html/box_construct.c
+++ b/content/handlers/html/box_construct.c
@@ -106,8 +106,8 @@ static const box_type box_map[] = {
        BOX_TABLE_CELL,      /* CSS_DISPLAY_TABLE_CELL */
        BOX_INLINE,          /* CSS_DISPLAY_TABLE_CAPTION */
        BOX_NONE,            /* CSS_DISPLAY_NONE */
-       BOX_BLOCK,           /* CSS_DISPLAY_FLEX */
-       BOX_INLINE_BLOCK,    /* CSS_DISPLAY_INLINE_FLEX */
+       BOX_FLEX,            /* CSS_DISPLAY_FLEX */
+       BOX_INLINE_FLEX,     /* CSS_DISPLAY_INLINE_FLEX */
 };
 
 
@@ -623,6 +623,7 @@ box_construct_element(struct box_construct_ctx *ctx, bool 
*convert_children)
                        (box->type == BOX_INLINE ||
                         box->type == BOX_BR ||
                         box->type == BOX_INLINE_BLOCK ||
+                        box->type == BOX_INLINE_FLEX ||
                         css_computed_float(box->style) == CSS_FLOAT_LEFT ||
                         css_computed_float(box->style) == CSS_FLOAT_RIGHT) &&
                        props.node_is_root == false) {
@@ -672,6 +673,7 @@ box_construct_element(struct box_construct_ctx *ctx, bool 
*convert_children)
                box->flags |= CONVERT_CHILDREN;
 
        if (box->type == BOX_INLINE || box->type == BOX_BR ||
+                       box->type == BOX_INLINE_FLEX ||
                        box->type == BOX_INLINE_BLOCK) {
                /* Inline container must exist, as we'll have
                 * created it above if it didn't */
diff --git a/content/handlers/html/box_inspect.c 
b/content/handlers/html/box_inspect.c
index b4b1394..73b0981 100644
--- a/content/handlers/html/box_inspect.c
+++ b/content/handlers/html/box_inspect.c
@@ -724,6 +724,14 @@ void box_dump(FILE *stream, struct box *box, unsigned int 
depth, bool style)
                fprintf(stream, "TEXT ");
                break;
 
+       case BOX_FLEX:
+               fprintf(stream, "FLEX ");
+               break;
+
+       case BOX_INLINE_FLEX:
+               fprintf(stream, "INLINE_FLEX ");
+               break;
+
        default:
                fprintf(stream, "Unknown box type ");
        }
diff --git a/content/handlers/html/box_inspect.h 
b/content/handlers/html/box_inspect.h
index b9161f1..a218326 100644
--- a/content/handlers/html/box_inspect.h
+++ b/content/handlers/html/box_inspect.h
@@ -139,5 +139,17 @@ static inline bool box_is_first_child(struct box *b)
        return (b->parent == NULL || b == b->parent->children);
 }
 
+static inline unsigned box_count_children(const struct box *b)
+{
+       const struct box *c = b->children;
+       unsigned count = 0;
+
+       while (c != NULL) {
+               count++;
+               c = c->next;
+       }
+
+       return count;
+}
 
 #endif
diff --git a/content/handlers/html/box_normalise.c 
b/content/handlers/html/box_normalise.c
index 1b6a345..8f25b03 100644
--- a/content/handlers/html/box_normalise.c
+++ b/content/handlers/html/box_normalise.c
@@ -177,6 +177,7 @@ box_normalise_table_row(struct box *row,
                                return false;
                        cell = child;
                        break;
+               case BOX_FLEX:
                case BOX_BLOCK:
                case BOX_INLINE_CONTAINER:
                case BOX_TABLE:
@@ -211,6 +212,7 @@ box_normalise_table_row(struct box *row,
                        cell->prev = child->prev;
 
                        while (child != NULL && (
+                                       child->type == BOX_FLEX ||
                                        child->type == BOX_BLOCK ||
                                        child->type == BOX_INLINE_CONTAINER ||
                                        child->type == BOX_TABLE ||
@@ -238,6 +240,7 @@ box_normalise_table_row(struct box *row,
                        break;
                case BOX_INLINE:
                case BOX_INLINE_END:
+               case BOX_INLINE_FLEX:
                case BOX_INLINE_BLOCK:
                case BOX_FLOAT_LEFT:
                case BOX_FLOAT_RIGHT:
@@ -314,6 +317,7 @@ box_normalise_table_row_group(struct box *row_group,
                                        c) == false)
                                return false;
                        break;
+               case BOX_FLEX:
                case BOX_BLOCK:
                case BOX_INLINE_CONTAINER:
                case BOX_TABLE:
@@ -348,6 +352,7 @@ box_normalise_table_row_group(struct box *row_group,
                        row->prev = child->prev;
 
                        while (child != NULL && (
+                                       child->type == BOX_FLEX ||
                                        child->type == BOX_BLOCK ||
                                        child->type == BOX_INLINE_CONTAINER ||
                                        child->type == BOX_TABLE ||
@@ -377,6 +382,7 @@ box_normalise_table_row_group(struct box *row_group,
                        break;
                case BOX_INLINE:
                case BOX_INLINE_END:
+               case BOX_INLINE_FLEX:
                case BOX_INLINE_BLOCK:
                case BOX_FLOAT_LEFT:
                case BOX_FLOAT_RIGHT:
@@ -648,6 +654,7 @@ box_normalise_table(struct box *table, const struct box 
*root, html_content * c)
                                return false;
                        }
                        break;
+               case BOX_FLEX:
                case BOX_BLOCK:
                case BOX_INLINE_CONTAINER:
                case BOX_TABLE:
@@ -686,6 +693,7 @@ box_normalise_table(struct box *table, const struct box 
*root, html_content * c)
                        row_group->prev = child->prev;
 
                        while (child != NULL && (
+                                       child->type == BOX_FLEX ||
                                        child->type == BOX_BLOCK ||
                                        child->type == BOX_INLINE_CONTAINER ||
                                        child->type == BOX_TABLE ||
@@ -716,6 +724,7 @@ box_normalise_table(struct box *table, const struct box 
*root, html_content * c)
                        break;
                case BOX_INLINE:
                case BOX_INLINE_END:
+               case BOX_INLINE_FLEX:
                case BOX_INLINE_BLOCK:
                case BOX_FLOAT_LEFT:
                case BOX_FLOAT_RIGHT:
@@ -806,6 +815,181 @@ box_normalise_table(struct box *table, const struct box 
*root, html_content * c)
        return true;
 }
 
+static bool box_normalise_flex(
+               struct box *flex_container,
+               const struct box *root,
+               html_content *c)
+{
+       struct box *child;
+       struct box *next_child;
+       struct box *implied_flex_item;
+       css_computed_style *style;
+       nscss_select_ctx ctx;
+
+       assert(flex_container != NULL);
+       assert(root != NULL);
+
+       ctx.root_style = root->style;
+
+#ifdef BOX_NORMALISE_DEBUG
+       NSLOG(netsurf, INFO, "flex_container %p, flex_container->type %u",
+                       flex_container, flex_container->type);
+#endif
+
+       assert(flex_container->type == BOX_FLEX ||
+              flex_container->type == BOX_INLINE_FLEX);
+
+       for (child = flex_container->children; child != NULL; child = 
next_child) {
+#ifdef BOX_NORMALISE_DEBUG
+               NSLOG(netsurf, INFO, "child %p, child->type = %d",
+                               child, child->type);
+#endif
+
+               next_child = child->next;       /* child may be destroyed */
+
+               switch (child->type) {
+               case BOX_FLEX:
+                       /* ok */
+                       if (box_normalise_flex(child, root, c) == false)
+                               return false;
+                       break;
+               case BOX_BLOCK:
+                       /* ok */
+                       if (box_normalise_block(child, root, c) == false)
+                               return false;
+                       break;
+               case BOX_INLINE_CONTAINER:
+                       /* insert implied flex item */
+                       assert(flex_container->style != NULL);
+
+                       ctx.ctx = c->select_ctx;
+                       ctx.quirks = (c->quirks == 
DOM_DOCUMENT_QUIRKS_MODE_FULL);
+                       ctx.base_url = c->base_url;
+                       ctx.universal = c->universal;
+
+                       style = nscss_get_blank_style(&ctx, &c->unit_len_ctx,
+                                       flex_container->style);
+                       if (style == NULL)
+                               return false;
+
+                       implied_flex_item = box_create(NULL, style, true,
+                                       flex_container->href,
+                                       flex_container->target,
+                                       NULL, NULL, c->bctx);
+                       if (implied_flex_item == NULL) {
+                               css_computed_style_destroy(style);
+                               return false;
+                       }
+                       implied_flex_item->type = BOX_BLOCK;
+
+                       if (child->prev == NULL)
+                               flex_container->children = implied_flex_item;
+                       else
+                               child->prev->next = implied_flex_item;
+
+                       implied_flex_item->prev = child->prev;
+
+                       while (child != NULL &&
+                                       child->type == BOX_INLINE_CONTAINER) {
+                               box_add_child(implied_flex_item, child);
+
+                               next_child = child->next;
+                               child->next = NULL;
+                               child = next_child;
+                       }
+
+                       implied_flex_item->last->next = NULL;
+                       implied_flex_item->next = next_child = child;
+                       if (implied_flex_item->next != NULL)
+                               implied_flex_item->next->prev = 
implied_flex_item;
+                       else
+                               flex_container->last = implied_flex_item;
+                       implied_flex_item->parent = flex_container;
+
+                       if (box_normalise_block(implied_flex_item,
+                                       root, c) == false)
+                               return false;
+                       break;
+
+               case BOX_TABLE:
+                       if (box_normalise_table(child, root, c) == false)
+                               return false;
+                       break;
+               case BOX_INLINE:
+               case BOX_INLINE_END:
+               case BOX_INLINE_FLEX:
+               case BOX_INLINE_BLOCK:
+               case BOX_FLOAT_LEFT:
+               case BOX_FLOAT_RIGHT:
+               case BOX_BR:
+               case BOX_TEXT:
+                       /* should have been wrapped in inline
+                          container by convert_xml_to_box() */
+                       assert(0);
+                       break;
+               case BOX_TABLE_ROW_GROUP:
+               case BOX_TABLE_ROW:
+               case BOX_TABLE_CELL:
+                       /* insert implied table */
+                       assert(flex_container->style != NULL);
+
+                       ctx.ctx = c->select_ctx;
+                       ctx.quirks = (c->quirks == 
DOM_DOCUMENT_QUIRKS_MODE_FULL);
+                       ctx.base_url = c->base_url;
+                       ctx.universal = c->universal;
+
+                       style = nscss_get_blank_style(&ctx, &c->unit_len_ctx,
+                                       flex_container->style);
+                       if (style == NULL)
+                               return false;
+
+                       implied_flex_item = box_create(NULL, style, true,
+                                       flex_container->href,
+                                       flex_container->target,
+                                       NULL, NULL, c->bctx);
+                       if (implied_flex_item == NULL) {
+                               css_computed_style_destroy(style);
+                               return false;
+                       }
+                       implied_flex_item->type = BOX_TABLE;
+
+                       if (child->prev == NULL)
+                               flex_container->children = implied_flex_item;
+                       else
+                               child->prev->next = implied_flex_item;
+
+                       implied_flex_item->prev = child->prev;
+
+                       while (child != NULL && (
+                                       child->type == BOX_TABLE_ROW_GROUP ||
+                                       child->type == BOX_TABLE_ROW ||
+                                       child->type == BOX_TABLE_CELL)) {
+                               box_add_child(implied_flex_item, child);
+
+                               next_child = child->next;
+                               child->next = NULL;
+                               child = next_child;
+                       }
+
+                       implied_flex_item->last->next = NULL;
+                       implied_flex_item->next = next_child = child;
+                       if (implied_flex_item->next != NULL)
+                               implied_flex_item->next->prev = 
implied_flex_item;
+                       else
+                               flex_container->last = implied_flex_item;
+                       implied_flex_item->parent = flex_container;
+
+                       if (box_normalise_table(implied_flex_item,
+                                       root, c) == false)
+                               return false;
+                       break;
+               default:
+                       assert(0);
+               }
+       }
+
+       return true;
+}
 
 static bool
 box_normalise_inline_container(struct box *cont,
@@ -836,6 +1020,11 @@ box_normalise_inline_container(struct box *cont,
                        if (box_normalise_block(child, root, c) == false)
                                return false;
                        break;
+               case BOX_INLINE_FLEX:
+                       /* ok */
+                       if (box_normalise_flex(child, root, c) == false)
+                               return false;
+                       break;
                case BOX_FLOAT_LEFT:
                case BOX_FLOAT_RIGHT:
                        /* ok */
@@ -852,6 +1041,11 @@ box_normalise_inline_container(struct box *cont,
                                                c) == false)
                                        return false;
                                break;
+                       case BOX_FLEX:
+                               if (box_normalise_flex(child->children, root,
+                                               c) == false)
+                                       return false;
+                               break;
                        default:
                                assert(0);
                        }
@@ -870,6 +1064,7 @@ box_normalise_inline_container(struct box *cont,
                                box_free(child);
                        }
                        break;
+               case BOX_FLEX:
                case BOX_BLOCK:
                case BOX_INLINE_CONTAINER:
                case BOX_TABLE:
@@ -888,7 +1083,6 @@ box_normalise_inline_container(struct box *cont,
        return true;
 }
 
-
 /* Exported function documented in html/box_normalise.h */
 bool
 box_normalise_block(struct box *block, const struct box *root, html_content *c)
@@ -920,6 +1114,11 @@ box_normalise_block(struct box *block, const struct box 
*root, html_content *c)
                next_child = child->next;       /* child may be destroyed */
 
                switch (child->type) {
+               case BOX_FLEX:
+                       /* ok */
+                       if (box_normalise_flex(child, root, c) == false)
+                               return false;
+                       break;
                case BOX_BLOCK:
                        /* ok */
                        if (box_normalise_block(child, root, c) == false)
@@ -935,6 +1134,7 @@ box_normalise_block(struct box *block, const struct box 
*root, html_content *c)
                        break;
                case BOX_INLINE:
                case BOX_INLINE_END:
+               case BOX_INLINE_FLEX:
                case BOX_INLINE_BLOCK:
                case BOX_FLOAT_LEFT:
                case BOX_FLOAT_RIGHT:
diff --git a/content/handlers/html/box_normalise.h 
b/content/handlers/html/box_normalise.h
index 591feab..377cd90 100644
--- a/content/handlers/html/box_normalise.h
+++ b/content/handlers/html/box_normalise.h
@@ -50,14 +50,15 @@
  * The tree is modified to satisfy the following:
  * \code
  * parent               permitted child nodes
- * BLOCK, INLINE_BLOCK  BLOCK, INLINE_CONTAINER, TABLE
- * INLINE_CONTAINER     INLINE, INLINE_BLOCK, FLOAT_LEFT, FLOAT_RIGHT, BR, TEXT
+ * BLOCK, INLINE_BLOCK  BLOCK, INLINE_CONTAINER, TABLE, FLEX
+ * FLEX, INLINE_FLEX    BLOCK, INLINE_CONTAINER, TABLE, FLEX
+ * INLINE_CONTAINER     INLINE, INLINE_BLOCK, FLOAT_LEFT, FLOAT_RIGHT, BR, 
TEXT, INLINE_FLEX
  * INLINE, TEXT         none
  * TABLE                at least 1 TABLE_ROW_GROUP
  * TABLE_ROW_GROUP      at least 1 TABLE_ROW
  * TABLE_ROW            at least 1 TABLE_CELL
- * TABLE_CELL           BLOCK, INLINE_CONTAINER, TABLE (same as BLOCK)
- * FLOAT_(LEFT|RIGHT)   exactly 1 BLOCK or TABLE
+ * TABLE_CELL           BLOCK, INLINE_CONTAINER, TABLE, FLEX (same as BLOCK)
+ * FLOAT_(LEFT|RIGHT)   exactly 1 BLOCK, TABLE or FLEX
  * \endcode
  */
 bool box_normalise_block(struct box *block, const struct box *root, struct 
html_content *c);
diff --git a/content/handlers/html/layout.c b/content/handlers/html/layout.c
index cb5be5d..bf8f68c 100644
--- a/content/handlers/html/layout.c
+++ b/content/handlers/html/layout.c
@@ -67,13 +67,9 @@
 #include "html/font.h"
 #include "html/form_internal.h"
 #include "html/layout.h"
+#include "html/layout_internal.h"
 #include "html/table.h"
 
-#define AUTO INT_MIN
-
-/* Fixed point percentage (a) of an integer (b), to an integer */
-#define FPCT_OF_INT_TOINT(a, b) (FIXTOINT(FDIV((a * b), F_100)))
-
 typedef uint8_t (*css_len_func)(
                const css_computed_style *style,
                css_fixed *length, css_unit *unit);
@@ -84,7 +80,7 @@ typedef uint8_t (*css_border_color_func)(
                css_color *color);
 
 /** Array of per-side access functions for computed style margins. */
-static const css_len_func margin_funcs[4] = {
+const css_len_func margin_funcs[4] = {
        [TOP]    = css_computed_margin_top,
        [RIGHT]  = css_computed_margin_right,
        [BOTTOM] = css_computed_margin_bottom,
@@ -92,7 +88,7 @@ static const css_len_func margin_funcs[4] = {
 };
 
 /** Array of per-side access functions for computed style paddings. */
-static const css_len_func padding_funcs[4] = {
+const css_len_func padding_funcs[4] = {
        [TOP]    = css_computed_padding_top,
        [RIGHT]  = css_computed_padding_right,
        [BOTTOM] = css_computed_padding_bottom,
@@ -100,7 +96,7 @@ static const css_len_func padding_funcs[4] = {
 };
 
 /** Array of per-side access functions for computed style border_widths. */
-static const css_len_func border_width_funcs[4] = {
+const css_len_func border_width_funcs[4] = {
        [TOP]    = css_computed_border_top_width,
        [RIGHT]  = css_computed_border_right_width,
        [BOTTOM] = css_computed_border_bottom_width,
@@ -108,67 +104,15 @@ static const css_len_func border_width_funcs[4] = {
 };
 
 /** Array of per-side access functions for computed style border styles. */
-static const css_border_style_func border_style_funcs[4] = {
+const css_border_style_func border_style_funcs[4] = {
        [TOP]    = css_computed_border_top_style,
        [RIGHT]  = css_computed_border_right_style,
        [BOTTOM] = css_computed_border_bottom_style,
        [LEFT]   = css_computed_border_left_style,
 };
 
-/** Layout helper: Check for CSS border on given side. */
-static inline bool lh__have_border(
-               enum box_side side,
-               const css_computed_style *style)
-{
-       return border_style_funcs[side](style) != CSS_BORDER_STYLE_NONE;
-}
-
-/** Layout helper: Check whether box is a float. */
-static inline bool lh__box_is_float_box(const struct box *b)
-{
-       return b->type == BOX_FLOAT_LEFT ||
-              b->type == BOX_FLOAT_RIGHT;
-}
-
-/** Layout helper: Check whether box takes part in inline flow. */
-static inline bool lh__box_is_inline_flow(const struct box *b)
-{
-       return b->type == BOX_INLINE ||
-              b->type == BOX_INLINE_BLOCK ||
-              b->type == BOX_TEXT ||
-              b->type == BOX_INLINE_END;
-}
-
-/** Layout helper: Check whether box is inline level. (Includes BR.) */
-static inline bool lh__box_is_inline_level(const struct box *b)
-{
-       return lh__box_is_inline_flow(b) ||
-              b->type == BOX_BR;
-}
-
-/** Layout helper: Check whether box is inline level. (Includes BR, floats.) */
-static inline bool lh__box_is_inline_content(const struct box *b)
-{
-       return lh__box_is_float_box(b) ||
-              lh__box_is_inline_level(b);
-}
-
-/** Layout helper: Check whether box is an object. */
-static inline bool lh__box_is_object(const struct box *b)
-{
-       return b->object ||
-              (b->flags & (IFRAME | REPLACE_DIM));
-}
-
-/** Layout helper: Check whether box is replaced. */
-static inline bool lh__box_is_replace(const struct box *b)
-{
-       return b->gadget ||
-              lh__box_is_object(b);
-}
-
 /** Array of per-side access functions for computed style border colors. */
-static const css_border_color_func border_color_funcs[4] = {
+const css_border_color_func border_color_funcs[4] = {
        [TOP]    = css_computed_border_top_color,
        [RIGHT]  = css_computed_border_right_color,
        [BOTTOM] = css_computed_border_bottom_color,
@@ -176,10 +120,6 @@ static const css_border_color_func border_color_funcs[4] = 
{
 };
 
 /* forward declaration to break cycles */
-static bool layout_block_context(
-               struct box *block,
-               int viewport_height,
-               html_content *content);
 static void layout_minmax_block(
                struct box *block,
                const struct gui_layout_table *font_func,
@@ -315,74 +255,6 @@ static int layout_text_indent(
 
 
 /**
- * Determine width of margin, borders, and padding on one side of a box.
- *
- * \param unit_len_ctx  CSS length conversion context for document
- * \param style    style to measure
- * \param side     side of box to measure
- * \param margin   whether margin width is required
- * \param border   whether border width is required
- * \param padding  whether padding width is required
- * \param fixed    increased by sum of fixed margin, border, and padding
- * \param frac     increased by sum of fractional margin and padding
- */
-static void
-calculate_mbp_width(const css_unit_ctx *unit_len_ctx,
-                   const css_computed_style *style,
-                   unsigned int side,
-                   bool margin,
-                   bool border,
-                   bool padding,
-                   int *fixed,
-                   float *frac)
-{
-       css_fixed value = 0;
-       css_unit unit = CSS_UNIT_PX;
-
-       assert(style);
-
-       /* margin */
-       if (margin) {
-               enum css_margin_e type;
-
-               type = margin_funcs[side](style, &value, &unit);
-               if (type == CSS_MARGIN_SET) {
-                       if (unit == CSS_UNIT_PCT) {
-                               *frac += FIXTOINT(FDIV(value, F_100));
-                       } else {
-                               *fixed += FIXTOINT(css_unit_len2device_px(
-                                               style, unit_len_ctx,
-                                               value, unit));
-                       }
-               }
-       }
-
-       /* border */
-       if (border) {
-               if (lh__have_border(side, style)) {
-                       border_width_funcs[side](style, &value, &unit);
-
-                       *fixed += FIXTOINT(css_unit_len2device_px(
-                                       style, unit_len_ctx,
-                                       value, unit));
-               }
-       }
-
-       /* padding */
-       if (padding) {
-               padding_funcs[side](style, &value, &unit);
-               if (unit == CSS_UNIT_PCT) {
-                       *frac += FIXTOINT(FDIV(value, F_100));
-               } else {
-                       *fixed += FIXTOINT(css_unit_len2device_px(
-                                       style, unit_len_ctx,
-                                       value, unit));
-               }
-       }
-}
-
-
-/**
  * Calculate minimum and maximum width of a table.
  *
  * \param table box of type TABLE
@@ -650,11 +522,11 @@ layout_minmax_line(struct box *first,
 
                if (lh__box_is_float_box(b)) {
                        assert(b->children);
-                       if (b->children->type == BOX_BLOCK)
-                               layout_minmax_block(b->children, font_func,
+                       if (b->children->type == BOX_TABLE)
+                               layout_minmax_table(b->children, font_func,
                                                content);
                        else
-                               layout_minmax_table(b->children, font_func,
+                               layout_minmax_block(b->children, font_func,
                                                content);
                        b->min_width = b->children->min_width;
                        b->max_width = b->children->max_width;
@@ -664,7 +536,7 @@ layout_minmax_line(struct box *first,
                        continue;
                }
 
-               if (b->type == BOX_INLINE_BLOCK) {
+               if (b->type == BOX_INLINE_BLOCK || b->type == BOX_INLINE_FLEX) {
                        layout_minmax_block(b, font_func, content);
                        if (min < b->min_width)
                                min = b->min_width;
@@ -997,7 +869,6 @@ layout_minmax_inline_container(struct box *inline_container,
                        inline_container->max_width);
 }
 
-
 /**
  * Calculate minimum and maximum width of a block.
  *
@@ -1026,6 +897,8 @@ static void layout_minmax_block(
        bool child_has_height = false;
 
        assert(block->type == BOX_BLOCK ||
+                       block->type == BOX_FLEX ||
+                       block->type == BOX_INLINE_FLEX ||
                        block->type == BOX_INLINE_BLOCK ||
                        block->type == BOX_TABLE_CELL);
 
@@ -1041,7 +914,8 @@ static void layout_minmax_block(
 
        /* set whether the minimum width is of any interest for this box */
        if (((block->parent && lh__box_is_float_box(block->parent)) ||
-                       block->type == BOX_INLINE_BLOCK) &&
+                       block->type == BOX_INLINE_BLOCK ||
+                       block->type == BOX_INLINE_FLEX) &&
                        wtype != CSS_WIDTH_SET) {
                /* box shrinks to fit; need minimum width */
                block->flags |= NEED_MIN;
@@ -1052,6 +926,9 @@ static void layout_minmax_block(
                        wtype != CSS_WIDTH_SET) {
                /* box inside shrink-to-fit context; need minimum width */
                block->flags |= NEED_MIN;
+       } else if (block->parent && (block->parent->type == BOX_FLEX)) {
+               /* box is flex item */
+               block->flags |= NEED_MIN;
        }
 
        if (block->gadget && (block->gadget->type == GADGET_TEXTBOX ||
@@ -1101,6 +978,7 @@ static void layout_minmax_block(
                /* recurse through children */
                for (child = block->children; child; child = child->next) {
                        switch (child->type) {
+                       case BOX_FLEX:
                        case BOX_BLOCK:
                                layout_minmax_block(child, font_func,
                                                content);
@@ -1142,10 +1020,19 @@ static void layout_minmax_block(
                                continue;
                        }
 
-                       if (min < child->min_width)
-                               min = child->min_width;
-                       if (max < child->max_width)
-                               max = child->max_width;
+                       if (lh__box_is_flex_container(block) &&
+                                       block->style != NULL &&
+                                       css_computed_flex_wrap(block->style) ==
+                                       CSS_FLEX_WRAP_NOWRAP) {
+                               min += child->min_width;
+                               max += child->max_width;
+
+                       } else {
+                               if (min < child->min_width)
+                                       min = child->min_width;
+                               if (max < child->max_width)
+                                       max = child->max_width;
+                       }
 
                        if (child_has_height)
                                block->flags |= HAS_HEIGHT;
@@ -1227,375 +1114,6 @@ static void layout_minmax_block(
 
 
 /**
- * Adjust a specified width or height for the box-sizing property.
- *
- * This turns the specified dimension into a content-box dimension.
- *
- * \param  unit_len_ctx          Length conversion context
- * \param  box             gadget to adjust dimensions of
- * \param  available_width  width of containing block
- * \param  setwidth        set true if the dimension to be tweaked is a width,
- *                             else set false for a height
- * \param  dimension       current value for given width/height dimension.
- *                             updated to new value after consideration of
- *                             gadget properties.
- */
-static void layout_handle_box_sizing(
-               const css_unit_ctx *unit_len_ctx,
-               const struct box *box,
-               int available_width,
-               bool setwidth,
-               int *dimension)
-{
-       enum css_box_sizing_e bs;
-
-       assert(box && box->style);
-
-       bs = css_computed_box_sizing(box->style);
-
-       if (bs == CSS_BOX_SIZING_BORDER_BOX) {
-               int orig = *dimension;
-               int fixed = 0;
-               float frac = 0;
-
-               calculate_mbp_width(unit_len_ctx, box->style,
-                               setwidth ? LEFT : TOP,
-                               false, true, true, &fixed, &frac);
-               calculate_mbp_width(unit_len_ctx, box->style,
-                               setwidth ? RIGHT : BOTTOM,
-                               false, true, true, &fixed, &frac);
-               orig -= frac * available_width + fixed;
-               *dimension = orig > 0 ? orig : 0;
-       }
-}
-
-
-/**
- * Calculate width, height, and thickness of margins, paddings, and borders.
- *
- * \param  unit_len_ctx          Length conversion context
- * \param  available_width  width of containing block
- * \param  viewport_height  height of viewport in pixels or -ve if unknown
- * \param  box             current box
- * \param  style           style giving width, height, margins, paddings,
- *                          and borders
- * \param  width            updated to width, may be NULL
- * \param  height           updated to height, may be NULL
- * \param  max_width        updated to max-width, may be NULL
- * \param  min_width        updated to min-width, may be NULL
- * \param  max_height       updated to max-height, may be NULL
- * \param  min_height       updated to min-height, may be NULL
- * \param  margin          filled with margins, may be NULL
- * \param  padding         filled with paddings, may be NULL
- * \param  border          filled with border widths, may be NULL
- */
-static void
-layout_find_dimensions(const css_unit_ctx *unit_len_ctx,
-                      int available_width,
-                      int viewport_height,
-                      const struct box *box,
-                      const css_computed_style *style,
-                      int *width,
-                      int *height,
-                      int *max_width,
-                      int *min_width,
-                      int *max_height,
-                      int *min_height,
-                      int margin[4],
-                      int padding[4],
-                      struct box_border border[4])
-{
-       struct box *containing_block = NULL;
-       unsigned int i;
-
-       if (width) {
-               enum css_width_e wtype;
-               css_fixed value = 0;
-               css_unit unit = CSS_UNIT_PX;
-
-               wtype = css_computed_width(style, &value, &unit);
-
-               if (wtype == CSS_WIDTH_SET) {
-                       if (unit == CSS_UNIT_PCT) {
-                               *width = FPCT_OF_INT_TOINT(
-                                               value, available_width);
-                       } else {
-                               *width = FIXTOINT(css_unit_len2device_px(
-                                               style, unit_len_ctx,
-                                               value, unit));
-                       }
-               } else {
-                       *width = AUTO;
-               }
-
-               if (*width != AUTO) {
-                       layout_handle_box_sizing(unit_len_ctx, box, 
available_width,
-                                       true, width);
-               }
-       }
-
-       if (height) {
-               enum css_height_e htype;
-               css_fixed value = 0;
-               css_unit unit = CSS_UNIT_PX;
-
-               htype = css_computed_height(style, &value, &unit);
-
-               if (htype == CSS_HEIGHT_SET) {
-                       if (unit == CSS_UNIT_PCT) {
-                               enum css_height_e cbhtype;
-
-                               if (css_computed_position(box->style) ==
-                                               CSS_POSITION_ABSOLUTE &&
-                                               box->parent) {
-                                       /* Box is absolutely positioned */
-                                       assert(box->float_container);
-                                       containing_block = box->float_container;
-                               } else if (box->float_container &&
-                                       css_computed_position(box->style) !=
-                                               CSS_POSITION_ABSOLUTE &&
-                                       (css_computed_float(box->style) ==
-                                               CSS_FLOAT_LEFT ||
-                                        css_computed_float(box->style) ==
-                                               CSS_FLOAT_RIGHT)) {
-                                       /* Box is a float */
-                                       assert(box->parent &&
-                                               box->parent->parent &&
-                                               box->parent->parent->parent);
-
-                                       containing_block =
-                                               box->parent->parent->parent;
-                               } else if (box->parent && box->parent->type !=
-                                               BOX_INLINE_CONTAINER) {
-                                       /* Box is a block level element */
-                                       containing_block = box->parent;
-                               } else if (box->parent && box->parent->type ==
-                                               BOX_INLINE_CONTAINER) {
-                                       /* Box is an inline block */
-                                       assert(box->parent->parent);
-                                       containing_block = box->parent->parent;
-                               }
-
-                               if (containing_block) {
-                                       css_fixed f = 0;
-                                       css_unit u = CSS_UNIT_PX;
-
-                                       cbhtype = css_computed_height(
-                                                       containing_block->style,
-                                                       &f, &u);
-                               }
-
-                               if (containing_block &&
-                                       containing_block->height != AUTO &&
-                                       (css_computed_position(box->style) ==
-                                                       CSS_POSITION_ABSOLUTE ||
-                                               cbhtype == CSS_HEIGHT_SET)) {
-                                       /* Box is absolutely positioned or its
-                                        * containing block has a valid
-                                        * specified height.
-                                        * (CSS 2.1 Section 10.5) */
-                                       *height = FPCT_OF_INT_TOINT(value,
-                                               containing_block->height);
-                               } else if ((!box->parent ||
-                                               !box->parent->parent) &&
-                                               viewport_height >= 0) {
-                                       /* If root element or it's child
-                                        * (HTML or BODY) */
-                                       *height = FPCT_OF_INT_TOINT(value,
-                                                       viewport_height);
-                               } else {
-                                       /* precentage height not permissible
-                                        * treat height as auto */
-                                       *height = AUTO;
-                               }
-                       } else {
-                               *height = FIXTOINT(css_unit_len2device_px(
-                                               style, unit_len_ctx,
-                                               value, unit));
-                       }
-               } else {
-                       *height = AUTO;
-               }
-
-               if (*height != AUTO) {
-                       layout_handle_box_sizing(unit_len_ctx, box, 
available_width,
-                                       false, height);
-               }
-       }
-
-       if (max_width) {
-               enum css_max_width_e type;
-               css_fixed value = 0;
-               css_unit unit = CSS_UNIT_PX;
-
-               type = css_computed_max_width(style, &value, &unit);
-
-               if (type == CSS_MAX_WIDTH_SET) {
-                       if (unit == CSS_UNIT_PCT) {
-                               *max_width = FPCT_OF_INT_TOINT(value,
-                                               available_width);
-                       } else {
-                               *max_width = FIXTOINT(css_unit_len2device_px(
-                                               style, unit_len_ctx,
-                                               value, unit));
-                       }
-               } else {
-                       /* Inadmissible */
-                       *max_width = -1;
-               }
-
-               if (*max_width != -1) {
-                       layout_handle_box_sizing(unit_len_ctx, box, 
available_width,
-                                       true, max_width);
-               }
-       }
-
-       if (min_width) {
-               enum css_min_width_e type;
-               css_fixed value = 0;
-               css_unit unit = CSS_UNIT_PX;
-
-               type = ns_computed_min_width(style, &value, &unit);
-
-               if (type == CSS_MIN_WIDTH_SET) {
-                       if (unit == CSS_UNIT_PCT) {
-                               *min_width = FPCT_OF_INT_TOINT(value,
-                                               available_width);
-                       } else {
-                               *min_width = FIXTOINT(css_unit_len2device_px(
-                                               style, unit_len_ctx,
-                                               value, unit));
-                       }
-               } else {
-                       /* Inadmissible */
-                       *min_width = 0;
-               }
-
-               if (*min_width != 0) {
-                       layout_handle_box_sizing(unit_len_ctx, box, 
available_width,
-                                       true, min_width);
-               }
-       }
-
-       if (max_height) {
-               enum css_max_height_e type;
-               css_fixed value = 0;
-               css_unit unit = CSS_UNIT_PX;
-
-               type = css_computed_max_height(style, &value, &unit);
-
-               if (type == CSS_MAX_HEIGHT_SET) {
-                       if (unit == CSS_UNIT_PCT) {
-                               /* TODO: handle percentage */
-                               *max_height = -1;
-                       } else {
-                               *max_height = FIXTOINT(css_unit_len2device_px(
-                                               style, unit_len_ctx,
-                                               value, unit));
-                       }
-               } else {
-                       /* Inadmissible */
-                       *max_height = -1;
-               }
-       }
-
-       if (min_height) {
-               enum css_min_height_e type;
-               css_fixed value = 0;
-               css_unit unit = CSS_UNIT_PX;
-
-               type = ns_computed_min_height(style, &value, &unit);
-
-               if (type == CSS_MIN_HEIGHT_SET) {
-                       if (unit == CSS_UNIT_PCT) {
-                               /* TODO: handle percentage */
-                               *min_height = 0;
-                       } else {
-                               *min_height = FIXTOINT(css_unit_len2device_px(
-                                               style, unit_len_ctx,
-                                               value, unit));
-                       }
-               } else {
-                       /* Inadmissible */
-                       *min_height = 0;
-               }
-       }
-
-       for (i = 0; i != 4; i++) {
-               if (margin) {
-                       enum css_margin_e type = CSS_MARGIN_AUTO;
-                       css_fixed value = 0;
-                       css_unit unit = CSS_UNIT_PX;
-
-                       type = margin_funcs[i](style, &value, &unit);
-
-                       if (type == CSS_MARGIN_SET) {
-                               if (unit == CSS_UNIT_PCT) {
-                                       margin[i] = FPCT_OF_INT_TOINT(value,
-                                                       available_width);
-                               } else {
-                                       margin[i] = 
FIXTOINT(css_unit_len2device_px(
-                                                       style, unit_len_ctx,
-                                                       value, unit));
-                               }
-                       } else {
-                               margin[i] = AUTO;
-                       }
-               }
-
-               if (padding) {
-                       css_fixed value = 0;
-                       css_unit unit = CSS_UNIT_PX;
-
-                       padding_funcs[i](style, &value, &unit);
-
-                       if (unit == CSS_UNIT_PCT) {
-                               padding[i] = FPCT_OF_INT_TOINT(value,
-                                               available_width);
-                       } else {
-                               padding[i] = FIXTOINT(css_unit_len2device_px(
-                                               style, unit_len_ctx,
-                                               value, unit));
-                       }
-               }
-
-               /* Table cell borders are populated in table.c */
-               if (border && box->type != BOX_TABLE_CELL) {
-                       enum css_border_style_e bstyle = CSS_BORDER_STYLE_NONE;
-                       css_color color = 0;
-                       css_fixed value = 0;
-                       css_unit unit = CSS_UNIT_PX;
-
-                       border_width_funcs[i](style, &value, &unit);
-                       bstyle = border_style_funcs[i](style);
-                       border_color_funcs[i](style, &color);
-
-                       border[i].style = bstyle;
-                       border[i].c = color;
-
-                       if (bstyle == CSS_BORDER_STYLE_HIDDEN ||
-                                       bstyle == CSS_BORDER_STYLE_NONE)
-                               /* spec unclear: following Mozilla */
-                               border[i].width = 0;
-                       else
-                               border[i].width = 
FIXTOINT(css_unit_len2device_px(
-                                               style, unit_len_ctx,
-                                               value, unit));
-
-                       /* Special case for border-collapse: make all borders
-                        * on table/table-row-group/table-row zero width. */
-                       if (css_computed_border_collapse(style) ==
-                                       CSS_BORDER_COLLAPSE_COLLAPSE &&
-                                       (box->type == BOX_TABLE ||
-                                        box->type == BOX_TABLE_ROW_GROUP ||
-                                        box->type == BOX_TABLE_ROW))
-                               border[i].width = 0;
-               }
-       }
-}
-
-
-/**
  * Find next block that current margin collapses to.
  *
  * \param  unit_len_ctx  Length conversion context
@@ -2058,15 +1576,10 @@ static void layout_move_children(struct box *box, int 
x, int y)
 }
 
 
-/**
- * Layout a table.
- *
- * \param  table           table to layout
- * \param  available_width  width of containing block
- * \param  content        memory pool for any new boxes
- * \return  true on success, false on memory exhaustion
- */
-static bool layout_table(struct box *table, int available_width,
+/* Documented in layout_internal.h */
+bool layout_table(
+               struct box *table,
+               int available_width,
                html_content *content)
 {
        unsigned int columns = table->columns;  /* total columns */
@@ -3052,8 +2565,11 @@ layout_float_find_dimensions(
  */
 static bool layout_float(struct box *b, int width, html_content *content)
 {
-       assert(b->type == BOX_TABLE || b->type == BOX_BLOCK ||
-                       b->type == BOX_INLINE_BLOCK);
+       assert(b->type == BOX_TABLE ||
+              b->type == BOX_BLOCK ||
+              b->type == BOX_INLINE_BLOCK ||
+              b->type == BOX_FLEX ||
+              b->type == BOX_INLINE_FLEX);
        layout_float_find_dimensions(&content->unit_len_ctx, width, b->style, 
b);
        if (b->type == BOX_TABLE) {
                if (!layout_table(b, width, content))
@@ -3275,7 +2791,8 @@ layout_line(struct box *first,
 
                x += space_after;
 
-               if (b->type == BOX_INLINE_BLOCK) {
+               if (b->type == BOX_INLINE_BLOCK ||
+                   b->type == BOX_INLINE_FLEX) {
                        if (b->max_width != UNKNOWN_WIDTH)
                                if (!layout_float(b, *width, content))
                                        return false;
@@ -3977,21 +3494,11 @@ static bool layout_inline_container(struct box 
*inline_container, int width,
 }
 
 
-/**
- * Layout a block formatting context.
- *
- * \param  block           BLOCK, INLINE_BLOCK, or TABLE_CELL to layout
- * \param  viewport_height  Height of viewport in pixels or -ve if unknown
- * \param  content         Memory pool for any new boxes
- * \return  true on success, false on memory exhaustion
- *
- * This function carries out layout of a block and its children, as described
- * in CSS 2.1 9.4.1.
- */
-static bool
-layout_block_context(struct box *block,
-                    int viewport_height,
-                    html_content *content)
+/* Documented in layout_intertnal.h */
+bool layout_block_context(
+               struct box *block,
+               int viewport_height,
+               html_content *content)
 {
        struct box *box;
        int cx, cy;  /**< current coordinates */
@@ -4006,7 +3513,9 @@ layout_block_context(struct box *block,
 
        assert(block->type == BOX_BLOCK ||
                        block->type == BOX_INLINE_BLOCK ||
-                       block->type == BOX_TABLE_CELL);
+                       block->type == BOX_TABLE_CELL ||
+                       block->type == BOX_FLEX ||
+                       block->type == BOX_INLINE_FLEX);
        assert(block->width != UNKNOWN_WIDTH);
        assert(block->width != AUTO);
 
@@ -4075,7 +3584,9 @@ layout_block_context(struct box *block,
                enum css_overflow_e overflow_x = CSS_OVERFLOW_VISIBLE;
                enum css_overflow_e overflow_y = CSS_OVERFLOW_VISIBLE;
 
-               assert(box->type == BOX_BLOCK || box->type == BOX_TABLE ||
+               assert(box->type == BOX_BLOCK ||
+                               box->type == BOX_FLEX ||
+                               box->type == BOX_TABLE ||
                                box->type == BOX_INLINE_CONTAINER);
 
                /* Tables are laid out before being positioned, because the
@@ -4159,7 +3670,7 @@ layout_block_context(struct box *block,
                                layout_block_add_scrollbar(box, RIGHT);
                                layout_block_add_scrollbar(box, BOTTOM);
                        }
-               } else if (box->type == BOX_TABLE) {
+               } else if (box->type == BOX_TABLE || box->type == BOX_FLEX) {
                        if (box->style != NULL) {
                                enum css_width_e wtype;
                                css_fixed width = 0;
@@ -4192,11 +3703,21 @@ layout_block_context(struct box *block,
                                                x1;
                                }
                        }
-                       if (!layout_table(box, box->parent->width - lm - rm,
-                                       content))
-                               return false;
-                       layout_solve_width(box, box->parent->width, box->width,
-                                       lm, rm, -1, -1);
+                       if (box->type == BOX_TABLE) {
+                               if (!layout_table(box,
+                                               box->parent->width - lm - rm,
+                                               content))
+                                       return false;
+                               layout_solve_width(box,
+                                               box->parent->width, box->width,
+                                               lm, rm, -1, -1);
+                       } else {
+                               if (!layout_flex(box,
+                                               box->parent->width - lm - rm,
+                                               content)) {
+                                       return false;
+                               }
+                       }
                }
 
                /* Position box: horizontal. */
@@ -4212,6 +3733,7 @@ layout_block_context(struct box *block,
 
                /* Vertical margin */
                if (((box->type == BOX_BLOCK && (box->flags & HAS_HEIGHT)) ||
+                    box->type == BOX_FLEX ||
                     box->type == BOX_TABLE ||
                     (box->type == BOX_INLINE_CONTAINER &&
                      !box_is_first_child(box)) ||
@@ -5037,7 +4559,9 @@ layout_absolute(struct box *box,
        int space;
 
        assert(box->type == BOX_BLOCK || box->type == BOX_TABLE ||
-                       box->type == BOX_INLINE_BLOCK);
+                       box->type == BOX_INLINE_BLOCK ||
+                       box->type == BOX_FLEX ||
+                       box->type == BOX_INLINE_FLEX);
 
        /* The static position is where the box would be if it was not
         * absolutely positioned. The x and y are filled in by
@@ -5272,6 +4796,9 @@ layout_absolute(struct box *box,
                box->float_container = NULL;
                layout_solve_width(box, box->parent->width, box->width, 0, 0,
                                -1, -1);
+       } else if (box->type == BOX_FLEX || box->type == BOX_INLINE_FLEX) {
+               if (!layout_flex(box, width, content))
+                       return false;
        }
 
        /* 10.6.4 */
@@ -5408,7 +4935,9 @@ layout_position_absolute(struct box *box,
 
        for (c = box->children; c; c = c->next) {
                if ((c->type == BOX_BLOCK || c->type == BOX_TABLE ||
-                               c->type == BOX_INLINE_BLOCK) &&
+                               c->type == BOX_INLINE_BLOCK ||
+                               c->type == BOX_FLEX ||
+                               c->type == BOX_INLINE_FLEX) &&
                                (css_computed_position(c->style) ==
                                                CSS_POSITION_ABSOLUTE ||
                                 css_computed_position(c->style) ==
@@ -5762,6 +5291,15 @@ static void layout_calculate_descendant_bboxes(
 {
        struct box *child;
 
+if (box->width == UNKNOWN_WIDTH) {
+       struct box *a = box;
+       while (a->parent) {
+               a = a->parent;
+       }
+       printf("box %p width: %i\n", box, box->width);
+       box_dump(stdout, a, 0, true);
+}
+
        assert(box->width != UNKNOWN_WIDTH);
        assert(box->height != AUTO);
        /* assert((box->width >= 0) && (box->height >= 0)); */
@@ -5897,6 +5435,7 @@ bool layout_document(html_content *content, int width, 
int height)
        layout_position_absolute(doc, doc, 0, 0, content);
        layout_position_relative(&content->unit_len_ctx, doc, doc, 0, 0);
 
+//     box_dump(stderr, doc, 0, false);
        layout_calculate_descendant_bboxes(&content->unit_len_ctx, doc);
 
        return ret;
diff --git a/content/handlers/html/layout_flex.c 
b/content/handlers/html/layout_flex.c
new file mode 100644
index 0000000..d2ea0b8
--- /dev/null
+++ b/content/handlers/html/layout_flex.c
@@ -0,0 +1,703 @@
+/*
+ * Copyright 2022 Michael Drake <[email protected]>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * HTML layout implementation: display: flex.
+ *
+ * Layout is carried out in two stages:
+ *
+ * 1. + calculation of minimum / maximum box widths, and
+ *    + determination of whether block level boxes will have >zero height
+ *
+ * 2. + layout (position and dimensions)
+ *
+ * In most cases the functions for the two stages are a corresponding pair
+ * layout_minmax_X() and layout_X().
+ */
+
+#include <string.h>
+
+#include "utils/log.h"
+#include "utils/utils.h"
+
+#include "html/box.h"
+#include "html/html.h"
+#include "html/private.h"
+#include "html/box_inspect.h"
+#include "html/layout_internal.h"
+
+struct flex_item_data {
+       enum css_flex_basis_e basis;
+       css_fixed basis_length;
+       css_unit basis_unit;
+       struct box *box;
+
+       css_fixed shrink;
+       css_fixed grow;
+
+       int min_width;
+       int max_width;
+       int min_height;
+       int max_height;
+
+       int target_main_size;
+       int base_size;
+       int main_size;
+       size_t line;
+
+       bool freeze;
+       bool min_violation;
+       bool max_violation;
+};
+
+struct flex_line_data {
+       int height;
+
+       int main_size;
+
+       size_t first;
+       size_t count;
+       size_t frozen;
+};
+
+struct flex_ctx {
+       int height;
+       html_content *content;
+       const struct box *flex;
+       const css_unit_ctx *unit_len_ctx;
+
+       enum css_flex_wrap_e wrap;
+
+       struct flex_items {
+               size_t count;
+               struct flex_item_data *data;
+       } item;
+
+       struct flex_lines {
+               size_t count;
+               size_t alloc;
+               struct flex_line_data *data;
+       } line;
+};
+
+static void layout_flex_ctx__destroy(struct flex_ctx *ctx)
+{
+       if (ctx != NULL) {
+               free(ctx->item.data);
+               free(ctx->line.data);
+               free(ctx);
+       }
+}
+
+static struct flex_ctx *layout_flex_ctx__create(
+               html_content *content,
+               const struct box *flex)
+{
+       struct flex_ctx *ctx;
+
+       ctx = calloc(1, sizeof(*ctx));
+       if (ctx == NULL) {
+               return NULL;
+       }
+       ctx->line.alloc = 1;
+
+       ctx->item.count = box_count_children(flex);
+       ctx->item.data = calloc(ctx->item.count, sizeof(*ctx->item.data));
+       if (ctx->item.data == NULL) {
+               layout_flex_ctx__destroy(ctx);
+               return NULL;
+       }
+
+       ctx->line.alloc = 1;
+       ctx->line.data = calloc(ctx->line.alloc, sizeof(*ctx->line.data));
+       if (ctx->line.data == NULL) {
+               layout_flex_ctx__destroy(ctx);
+               return NULL;
+       }
+
+       ctx->flex = flex;
+       ctx->content = content;
+       ctx->unit_len_ctx = &content->unit_len_ctx;
+       ctx->wrap = css_computed_flex_wrap(flex->style);
+
+       return ctx;
+}
+
+static inline void layout_flex__base_and_main_sizes(
+               const struct flex_ctx *ctx,
+               struct flex_item_data *item,
+               int available_width)
+{
+       struct box *b = item->box;
+       int delta_outer_width = lh__delta_outer_width(b);
+
+       if (item->basis == CSS_FLEX_BASIS_SET) {
+               if (item->basis_unit == CSS_UNIT_PCT) {
+                       item->base_size = FPCT_OF_INT_TOINT(
+                                       item->basis_length,
+                                       available_width);
+               } else {
+                       item->base_size = FIXTOINT(css_unit_len2device_px(
+                                       b->style, ctx->unit_len_ctx,
+                                       item->basis_length,
+                                       item->basis_unit));
+               }
+
+       } else if (item->basis == CSS_FLEX_BASIS_AUTO) {
+               item->base_size = b->width;
+       } else {
+               item->base_size = AUTO;
+       }
+
+       if (item->base_size != AUTO) {
+               layout_handle_box_sizing(ctx->unit_len_ctx, b,
+                               available_width, true,
+                               &item->base_size);
+       } else {
+               item->base_size = b->max_width;
+       }
+
+       item->base_size += delta_outer_width;
+
+       fprintf(stderr, "base_size: %i\n", item->base_size);
+       item->base_size = max(min(item->base_size, available_width),
+                       b->min_width + delta_outer_width);
+
+       item->target_main_size = item->base_size;
+       item->main_size = item->base_size;
+
+       fprintf(stderr, "main_size: %i\n", item->main_size);
+
+       if (item->max_width > 0 &&
+           item->main_size > item->max_width + delta_outer_width) {
+               item->main_size = item->max_width + delta_outer_width;
+       }
+
+       if (item->main_size < item->min_width + delta_outer_width) {
+               item->main_size = item->min_width + delta_outer_width;
+       }
+       fprintf(stderr, "main_size: %i\n", item->main_size);
+}
+
+static void layout_flex_ctx__populate_item_data(
+               const struct flex_ctx *ctx,
+               const struct box *flex,
+               int available_width)
+{
+       size_t i = 0;
+
+       for (struct box *b = flex->children; b != NULL; b = b->next) {
+               struct flex_item_data *item = &ctx->item.data[i++];
+
+               layout_find_dimensions(ctx->unit_len_ctx, available_width, -1,
+                               b, b->style, &b->width, &b->height,
+                               &item->max_width, &item->min_width,
+                               &item->max_height, &item->min_height,
+                               b->margin, b->padding, b->border);
+
+               item->box = b;
+               item->basis = css_computed_flex_basis(b->style,
+                               &item->basis_length, &item->basis_unit);
+
+               css_computed_flex_shrink(b->style, &item->shrink);
+               css_computed_flex_grow(b->style, &item->grow);
+
+               layout_flex__base_and_main_sizes(ctx, item, available_width);
+       }
+}
+
+static bool layout_flex_ctx__ensure_line(struct flex_ctx *ctx)
+{
+       struct flex_line_data *temp;
+       size_t line_alloc = ctx->line.alloc * 2;
+
+       fprintf(stderr, "Ensure line start: count: %zu, alloc: %zu\n",
+                       ctx->line.count, ctx->line.alloc);
+
+       if (ctx->line.alloc > ctx->line.count) {
+               return true;
+       }
+
+       temp = realloc(ctx->line.data, sizeof(*ctx->line.data) * line_alloc);
+       if (temp == NULL) {
+               return false;
+       }
+       ctx->line.data = temp;
+
+       fprintf(stderr, "Ensure line   end: count: %zu, alloc: %zu\n",
+                       ctx->line.count, line_alloc);
+
+       memset(ctx->line.data + ctx->line.alloc, 0,
+              sizeof(*ctx->line.data) * (line_alloc - ctx->line.alloc));
+       ctx->line.alloc = line_alloc;
+
+       return true;
+}
+
+static size_t layout_flex__build_line(struct flex_ctx *ctx,
+               size_t item_index, int available_width, html_content *content)
+{
+       struct flex_line_data *line;
+       int used_width = 0;
+
+       if (!layout_flex_ctx__ensure_line(ctx)) {
+               return 0;
+       }
+
+       line = &ctx->line.data[ctx->line.count];
+       line->first = item_index;
+
+       while (item_index < ctx->item.count) {
+               struct flex_item_data *item = &ctx->item.data[item_index];
+               struct box *b = item->box;
+               int width = b->max_width;
+
+               width += lh__delta_outer_width(b);
+
+               if (ctx->wrap == CSS_FLEX_WRAP_NOWRAP ||
+                   lh__box_is_absolute(item->box) ||
+                   width == 0 ||
+                   width + used_width <= available_width ||
+                   line->count == 0) {
+                       line->main_size += item->main_size;
+                       item->line = ctx->line.count;
+                       used_width += width;
+                       line->count++;
+                       item_index++;
+               } else {
+                       break;
+               }
+       }
+
+       if (line->count > 0) {
+               ctx->line.count++;
+       }
+
+       return line->count;
+}
+
+static bool layout_flex__collect_items_into_lines(
+               struct flex_ctx *ctx,
+               int available_width,
+               html_content *content)
+{
+       size_t fitted = 0;
+       size_t pos = 0;
+
+       do {
+               fitted = layout_flex__build_line(ctx, pos,
+                               available_width, content);
+               pos += fitted;
+               fprintf(stderr, "  pos: %zu, fitted: %zu\n",
+                               pos, fitted);
+       } while (fitted != 0 && pos != ctx->item.count);
+
+       if (fitted == 0) {
+               NSLOG(layout, ERROR, "Failed to fit any flex items");
+               return false;
+       }
+
+       return true;
+}
+
+static inline void layout_flex__item_freeze(
+               struct flex_line_data *line,
+               struct flex_item_data *item)
+{
+       item->freeze = true;
+       line->frozen++;
+       fprintf(stderr, "    frozen: block: %p: width: %i\n",
+                       item->box, item->target_main_size);
+}
+
+static inline int layout_flex__remaining_free_space(
+               struct flex_ctx *ctx,
+               struct flex_line_data *line,
+               css_fixed *unfrozen_factor_sum,
+               int initial_free_space,
+               int available_width,
+               bool grow)
+{
+       int remaining_free_space = available_width;
+       size_t item_count = line->first + line->count;
+
+       *unfrozen_factor_sum = 0;
+
+       for (size_t i = line->first; i < item_count; i++) {
+               struct flex_item_data *item = &ctx->item.data[i];
+
+               if (item->freeze) {
+                       remaining_free_space -= item->target_main_size;
+               } else {
+                       remaining_free_space -= item->base_size;
+
+                       *unfrozen_factor_sum += grow ?
+                                       item->grow : item->shrink;
+               }
+       }
+       fprintf(stderr, "    Remaining free space: %i\n", remaining_free_space);
+
+       if (*unfrozen_factor_sum < F_1) {
+               int free_space = FIXTOINT(FMUL(INTTOFIX(initial_free_space),
+                               *unfrozen_factor_sum));
+
+               if (free_space < remaining_free_space) {
+                       remaining_free_space = free_space;
+               }
+               fprintf(stderr, "    Remaining free space: %i\n", 
remaining_free_space);
+       }
+
+       return remaining_free_space;
+}
+
+static inline int layout_flex__get_min_max_violations(
+               struct flex_ctx *ctx,
+               struct flex_line_data *line)
+{
+
+       int total_violation = 0;
+       size_t item_count = line->first + line->count;
+
+       for (size_t i = line->first; i < item_count; i++) {
+               struct flex_item_data *item = &ctx->item.data[i];
+               int target_main_size = item->target_main_size;
+
+               if (item->freeze) {
+                       continue;
+               }
+
+               if (item->max_width > 0 &&
+                   target_main_size > item->max_width) {
+                       target_main_size = item->max_width;
+                       item->max_violation = true;
+               }
+
+               if (target_main_size < item->min_width) {
+                       target_main_size = item->min_width;
+                       item->min_violation = true;
+               }
+
+               if (target_main_size < item->box->min_width) {
+                       target_main_size = item->box->min_width;
+                       item->min_violation = true;
+               }
+
+               if (target_main_size < 0) {
+                       target_main_size = 0;
+                       item->min_violation = true;
+               }
+
+               total_violation += target_main_size - item->target_main_size;
+               item->target_main_size = target_main_size;
+       }
+
+       return total_violation;
+}
+
+static inline void layout_flex__distribute_free_space(
+               struct flex_ctx *ctx,
+               struct flex_line_data *line,
+               css_fixed unfrozen_factor_sum,
+               int remaining_free_space,
+               bool grow)
+{
+       size_t item_count = line->first + line->count;
+
+       if (grow) {
+               for (size_t i = line->first; i < item_count; i++) {
+                       struct flex_item_data *item = &ctx->item.data[i];
+                       css_fixed ratio;
+
+                       if (item->freeze) {
+                               continue;
+                       }
+
+                       ratio = FDIV(item->grow, unfrozen_factor_sum);
+
+                       item->target_main_size = item->base_size +
+                                       FIXTOINT(FMUL(
+                                       INTTOFIX(remaining_free_space),
+                                       ratio));
+               }
+       } else {
+               css_fixed scaled_shrink_factor_sum = 0;
+
+               for (size_t i = line->first; i < item_count; i++) {
+                       struct flex_item_data *item = &ctx->item.data[i];
+                       css_fixed scaled_shrink_factor;
+
+                       if (item->freeze) {
+                               continue;
+                       }
+
+                       scaled_shrink_factor = FMUL(
+                                       item->shrink,
+                                       INTTOFIX(item->base_size));
+                       scaled_shrink_factor_sum += scaled_shrink_factor;
+               }
+
+               for (size_t i = line->first; i < item_count; i++) {
+                       struct flex_item_data *item = &ctx->item.data[i];
+                       css_fixed scaled_shrink_factor;
+                       css_fixed ratio;
+
+                       if (item->freeze) {
+                               continue;
+                       }
+
+                       scaled_shrink_factor = FMUL(
+                                       item->shrink,
+                                       INTTOFIX(item->base_size));
+                       ratio = FDIV(scaled_shrink_factor,
+                                    scaled_shrink_factor_sum);
+
+                       item->target_main_size = item->base_size -
+                                       FIXTOINT(FMUL(
+                                       INTTOFIX(abs(remaining_free_space)),
+                                       ratio));
+               }
+       }
+}
+
+/** 9.7. Resolving Flexible Lengths */
+static bool layout_flex__resolve_line(
+               struct flex_ctx *ctx,
+               int available_width,
+               size_t line_index)
+{
+       struct flex_line_data *line = &ctx->line.data[line_index];
+       bool grow = (line->main_size < available_width);
+       int initial_free_space = available_width;
+       size_t item_count = line->first + line->count;
+       int x = 0;
+
+       fprintf(stderr, "  Line main_size: %i, available_width: %i\n",
+                       line->main_size, available_width);
+
+       for (size_t i = line->first; i < item_count; i++) {
+               struct flex_item_data *item = &ctx->item.data[i];
+
+               /* 3. Size inflexible items */
+               if (grow) {
+                       if (item->grow == 0 ||
+                           item->base_size > item->main_size) {
+                               fprintf(stderr, "    Grow: %f\n", 
FIXTOFLT(item->grow));
+                               fprintf(stderr, "    Base size: %i, Main size: 
%i\n",
+                                               item->base_size, 
item->main_size);
+                               item->target_main_size = item->main_size;
+                               fprintf(stderr, "    Grow freeze\n");
+                               layout_flex__item_freeze(line, item);
+                       }
+               } else {
+                       if (item->shrink == 0 ||
+                           item->base_size < item->main_size) {
+                               item->target_main_size = item->main_size;
+                               layout_flex__item_freeze(line, item);
+                       }
+               }
+
+               /* 4. Calculate initial free space */
+               if (item->freeze) {
+                       initial_free_space -= item->target_main_size;
+               } else {
+                       initial_free_space -= item->base_size;
+               }
+       }
+
+       /* 5. Loop */
+       while (line->frozen < line->count) {
+               css_fixed unfrozen_factor_sum;
+               int remaining_free_space;
+               int total_violation;
+
+               fprintf(stderr, "  Flex resolver pass\n");
+
+               /* b */
+               remaining_free_space = layout_flex__remaining_free_space(ctx,
+                               line, &unfrozen_factor_sum, initial_free_space,
+                               available_width, grow);
+
+               /* c */
+               if (remaining_free_space != 0) {
+                       layout_flex__distribute_free_space(ctx,
+                                       line, unfrozen_factor_sum,
+                                       remaining_free_space, grow);
+               }
+
+               /* d */
+               total_violation = layout_flex__get_min_max_violations(
+                               ctx, line);
+
+               /* e */
+               for (size_t i = line->first; i < item_count; i++) {
+                       struct flex_item_data *item = &ctx->item.data[i];
+
+                       if (total_violation == 0 ||
+                           (total_violation > 0 && item->min_violation) ||
+                           (total_violation < 0 && item->max_violation)) {
+                               layout_flex__item_freeze(line, item);
+                       }
+               }
+       }
+
+       for (size_t i = line->first; i < line->first + line->count; i++) {
+               fprintf(stderr, "    Item: %zu\n", i);
+               struct flex_item_data *item = &ctx->item.data[i];
+               struct box *b = item->box;
+               bool success = false;
+               int height;
+
+               b->width = item->target_main_size - lh__delta_outer_width(b);
+
+               switch (b->type) {
+               case BOX_BLOCK:
+                       fprintf(stderr, "      flex item: block: %p: width: 
%i\n", b, b->width);
+                       success = layout_block_context(b, -1,
+                                       ctx->content);
+                       break;
+               case BOX_TABLE:
+                       success = layout_table(b, available_width,
+                                       ctx->content);
+                       break;
+               case BOX_FLEX:
+                       success = layout_flex(b, available_width,
+                                       ctx->content);
+                       break;
+               default:
+                       assert(0 && "Bad flex item back type");
+                       success = false;
+                       break;
+               }
+               if (!success) {
+                       fprintf(stderr, "flex item: layout of %p failed\n", b);
+                       return false;
+               }
+
+               height = b->height + lh__delta_outer_height(b);
+
+               b->y = ctx->height + b->margin[TOP] + b->border[TOP].width + 
b->padding[TOP];
+               if (line->height < height) {
+                       line->height = height;
+               }
+
+               b->x = x + b->margin[LEFT] + b->border[LEFT].width + 
b->padding[LEFT];
+               x += b->width + lh__delta_outer_width(b);
+       }
+
+       return true;
+}
+
+/**
+ * Layout a flex container.
+ *
+ * \param[in] flex             table to layout
+ * \param[in] available_width  width of containing block
+ * \param[in] content          memory pool for any new boxes
+ * \return  true on success, false on memory exhaustion
+ */
+bool layout_flex(struct box *flex, int available_width,
+               html_content *content)
+{
+       int max_width, min_width, max_height, min_height;
+       struct flex_ctx *ctx;
+       bool success = false;
+
+       fprintf(stderr, "layout_flex: box: %p\n", flex);
+
+       ctx = layout_flex_ctx__create(content, flex);
+       if (ctx == NULL) {
+               return false;
+       }
+
+       layout_flex_ctx__populate_item_data(ctx, flex, available_width);
+
+       layout_find_dimensions(
+                       ctx->unit_len_ctx, available_width, -1,
+                       flex, flex->style, &flex->width, &flex->height,
+                       &max_width, &min_width, &max_height, &min_height,
+                       flex->margin, flex->padding, flex->border);
+
+       if (flex->width == AUTO) {
+               int w = available_width;
+               int fixed = 0;
+               float frac = 0;
+
+               calculate_mbp_width(ctx->unit_len_ctx, flex->style, LEFT,
+                               true, true, true, &fixed, &frac);
+               calculate_mbp_width(ctx->unit_len_ctx, flex->style, RIGHT,
+                               true, true, true, &fixed, &frac);
+
+               w -= frac * available_width + fixed;
+               flex->width = w > 0 ? w : 0;
+       }
+
+       if (flex->width == AUTO) {
+               flex->width = available_width;
+       }
+
+       available_width -= lh__delta_outer_width(flex);
+
+       /* Place items onto lines. */
+       success = layout_flex__collect_items_into_lines(ctx,
+                       available_width, content);
+       if (!success) {
+               goto cleanup;
+       }
+
+       /* Layout children */
+       for (size_t i = 0; i < ctx->line.count; i++) {
+               fprintf(stderr, "  Line %zu: First: %zu, Count: %zu\n", i,
+                               ctx->line.data[i].first,
+                               ctx->line.data[i].count);
+               success = layout_flex__resolve_line(ctx,
+                               available_width, i);
+               if (!success) {
+                       goto cleanup;
+               }
+
+               ctx->height += ctx->line.data[i].height;
+       }
+
+       if (flex->height == AUTO) {
+               flex->height = ctx->height;
+       }
+
+       if (max_width >= 0 && flex->width > max_width) {
+               flex->width = max_width;
+       }
+       if (min_width >  0 && flex->width < min_width) {
+               flex->width = min_width;
+       }
+
+       if (flex->height != AUTO) {
+               if (max_height >= 0 && flex->height > max_height) {
+                       flex->height = max_height;
+               }
+               if (min_height >  0 && flex->height < min_height) {
+                       flex->height = min_height;
+               }
+       }
+
+       success = true;
+
+cleanup:
+       layout_flex_ctx__destroy(ctx);
+       fprintf(stderr, "Flex layout: %s\n\n", success ? "success" : "failure");
+       return success;
+}
diff --git a/content/handlers/html/layout_internal.h 
b/content/handlers/html/layout_internal.h
new file mode 100644
index 0000000..86feda7
--- /dev/null
+++ b/content/handlers/html/layout_internal.h
@@ -0,0 +1,642 @@
+/*
+ * Copyright 2003 James Bursa <[email protected]>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * interface to HTML layout.
+ *
+ * The main interface to the layout code is layout_document(), which takes a
+ * normalized box tree and assigns coordinates and dimensions to the boxes, and
+ * also adds boxes to the tree (eg. when formatting lines of text).
+ */
+
+#ifndef NETSURF_HTML_LAYOUT_INTERNAL_H
+#define NETSURF_HTML_LAYOUT_INTERNAL_H
+
+struct box;
+struct html_content;
+struct gui_layout_table;
+
+#define AUTO INT_MIN
+
+/* Fixed point percentage (a) of an integer (b), to an integer */
+#define FPCT_OF_INT_TOINT(a, b) (FIXTOINT(FDIV((a * b), F_100)))
+
+/**
+ * Layout a block formatting context.
+ *
+ * \param  block            BLOCK, INLINE_BLOCK, or TABLE_CELL to layout
+ * \param  viewport_height  Height of viewport in pixels or -ve if unknown
+ * \param  content          Memory pool for any new boxes
+ * \return  true on success, false on memory exhaustion
+ *
+ * This function carries out layout of a block and its children, as described
+ * in CSS 2.1 9.4.1.
+ */
+bool layout_block_context(
+               struct box *block,
+               int viewport_height,
+               html_content *content);
+
+/**
+ * Layout a table.
+ *
+ * \param  table            table to layout
+ * \param  available_width  width of containing block
+ * \param  content          memory pool for any new boxes
+ * \return  true on success, false on memory exhaustion
+ */
+bool layout_table(
+               struct box *table,
+               int available_width,
+               html_content *content);
+
+/**
+ * Layout a flex container.
+ *
+ * \param[in] flex             table to layout
+ * \param[in] available_width  width of containing block
+ * \param[in] content          memory pool for any new boxes
+ * \return  true on success, false on memory exhaustion
+ */
+bool layout_flex(
+               struct box *flex,
+               int available_width,
+               html_content *content);
+
+typedef uint8_t (*css_len_func)(
+               const css_computed_style *style,
+               css_fixed *length, css_unit *unit);
+typedef uint8_t (*css_border_style_func)(
+               const css_computed_style *style);
+typedef uint8_t (*css_border_color_func)(
+               const css_computed_style *style,
+               css_color *color);
+
+/** Array of per-side access functions for computed style margins. */
+extern const css_len_func margin_funcs[4];
+
+/** Array of per-side access functions for computed style paddings. */
+extern const css_len_func padding_funcs[4];
+
+/** Array of per-side access functions for computed style border_widths. */
+extern const css_len_func border_width_funcs[4];
+
+/** Array of per-side access functions for computed style border styles. */
+extern const css_border_style_func border_style_funcs[4];
+
+/** Array of per-side access functions for computed style border colors. */
+extern const css_border_color_func border_color_funcs[4];
+
+/** Layout helper: Check whether box is a float. */
+static inline bool lh__box_is_float_box(const struct box *b)
+{
+       return b->type == BOX_FLOAT_LEFT ||
+              b->type == BOX_FLOAT_RIGHT;
+}
+
+/** Layout helper: Check whether box takes part in inline flow. */
+static inline bool lh__box_is_inline_flow(const struct box *b)
+{
+       return b->type == BOX_INLINE ||
+              b->type == BOX_INLINE_FLEX ||
+              b->type == BOX_INLINE_BLOCK ||
+              b->type == BOX_TEXT ||
+              b->type == BOX_INLINE_END;
+}
+
+/** Layout helper: Check whether box takes part in inline flow. */
+static inline bool lh__box_is_flex_container(const struct box *b)
+{
+       return b->type == BOX_FLEX ||
+              b->type == BOX_INLINE_FLEX;
+}
+
+/** Layout helper: Check whether box is inline level. (Includes BR.) */
+static inline bool lh__box_is_inline_level(const struct box *b)
+{
+       return lh__box_is_inline_flow(b) ||
+              b->type == BOX_BR;
+}
+
+/** Layout helper: Check whether box is inline level. (Includes BR, floats.) */
+static inline bool lh__box_is_inline_content(const struct box *b)
+{
+       return lh__box_is_float_box(b) ||
+              lh__box_is_inline_level(b);
+}
+
+/** Layout helper: Check whether box is an object. */
+static inline bool lh__box_is_object(const struct box *b)
+{
+       return b->object ||
+              (b->flags & (IFRAME | REPLACE_DIM));
+}
+
+/** Layout helper: Check whether box is replaced. */
+static inline bool lh__box_is_replace(const struct box *b)
+{
+       return b->gadget ||
+              lh__box_is_object(b);
+}
+
+/** Layout helper: Check for CSS border on given side. */
+static inline bool lh__have_border(
+               enum box_side side,
+               const css_computed_style *style)
+{
+       return border_style_funcs[side](style) != CSS_BORDER_STYLE_NONE;
+}
+
+static inline bool lh__box_is_absolute(const struct box *b)
+{
+       return css_computed_position(b->style) == CSS_POSITION_ABSOLUTE;
+}
+
+static inline bool layout_flex__main_is_horizontal(struct box *flex)
+{
+       const css_computed_style *style = flex->style;
+
+       assert(style != NULL);
+
+       switch (css_computed_flex_direction(style)) {
+       default:                        /* Fallthrough. */
+       case CSS_FLEX_DIRECTION_ROW:    /* Fallthrough. */
+       case CSS_FLEX_DIRECTION_ROW_REVERSE:
+               return true;
+       case CSS_FLEX_DIRECTION_COLUMN: /* Fallthrough. */
+       case CSS_FLEX_DIRECTION_COLUMN_REVERSE:
+               return false;
+       }
+}
+
+static inline int lh__delta_outer_height(const struct box *b)
+{
+       return b->margin[TOP] +
+              b->margin[BOTTOM] +
+              b->border[TOP].width +
+              b->border[BOTTOM].width +
+              b->padding[TOP] +
+              b->padding[BOTTOM];
+}
+
+static inline int lh__delta_outer_width(const struct box *b)
+{
+       return b->margin[LEFT] +
+              b->margin[RIGHT] +
+              b->border[LEFT].width +
+              b->border[RIGHT].width +
+              b->padding[LEFT] +
+              b->padding[RIGHT];
+}
+
+/**
+ * Determine width of margin, borders, and padding on one side of a box.
+ *
+ * \param unit_len_ctx  CSS length conversion context for document
+ * \param style    style to measure
+ * \param side     side of box to measure
+ * \param margin   whether margin width is required
+ * \param border   whether border width is required
+ * \param padding  whether padding width is required
+ * \param fixed    increased by sum of fixed margin, border, and padding
+ * \param frac     increased by sum of fractional margin and padding
+ */
+static inline void calculate_mbp_width(
+               const css_unit_ctx *unit_len_ctx,
+               const css_computed_style *style,
+               unsigned int side,
+               bool margin,
+               bool border,
+               bool padding,
+               int *fixed,
+               float *frac)
+{
+       css_fixed value = 0;
+       css_unit unit = CSS_UNIT_PX;
+
+       assert(style);
+
+       /* margin */
+       if (margin) {
+               enum css_margin_e type;
+
+               type = margin_funcs[side](style, &value, &unit);
+               if (type == CSS_MARGIN_SET) {
+                       if (unit == CSS_UNIT_PCT) {
+                               *frac += FIXTOINT(FDIV(value, F_100));
+                       } else {
+                               *fixed += FIXTOINT(css_unit_len2device_px(
+                                               style, unit_len_ctx,
+                                               value, unit));
+                       }
+               }
+       }
+
+       /* border */
+       if (border) {
+               if (lh__have_border(side, style)) {
+                       border_width_funcs[side](style, &value, &unit);
+
+                       *fixed += FIXTOINT(css_unit_len2device_px(
+                                       style, unit_len_ctx,
+                                       value, unit));
+               }
+       }
+
+       /* padding */
+       if (padding) {
+               padding_funcs[side](style, &value, &unit);
+               if (unit == CSS_UNIT_PCT) {
+                       *frac += FIXTOINT(FDIV(value, F_100));
+               } else {
+                       *fixed += FIXTOINT(css_unit_len2device_px(
+                                       style, unit_len_ctx,
+                                       value, unit));
+               }
+       }
+}
+
+/**
+ * Adjust a specified width or height for the box-sizing property.
+ *
+ * This turns the specified dimension into a content-box dimension.
+ *
+ * \param  unit_len_ctx          Length conversion context
+ * \param  box             gadget to adjust dimensions of
+ * \param  available_width  width of containing block
+ * \param  setwidth        set true if the dimension to be tweaked is a width,
+ *                             else set false for a height
+ * \param  dimension       current value for given width/height dimension.
+ *                             updated to new value after consideration of
+ *                             gadget properties.
+ */
+static inline void layout_handle_box_sizing(
+               const css_unit_ctx *unit_len_ctx,
+               const struct box *box,
+               int available_width,
+               bool setwidth,
+               int *dimension)
+{
+       enum css_box_sizing_e bs;
+
+       assert(box && box->style);
+
+       bs = css_computed_box_sizing(box->style);
+
+       if (bs == CSS_BOX_SIZING_BORDER_BOX) {
+               int orig = *dimension;
+               int fixed = 0;
+               float frac = 0;
+
+               calculate_mbp_width(unit_len_ctx, box->style,
+                               setwidth ? LEFT : TOP,
+                               false, true, true, &fixed, &frac);
+               calculate_mbp_width(unit_len_ctx, box->style,
+                               setwidth ? RIGHT : BOTTOM,
+                               false, true, true, &fixed, &frac);
+               orig -= frac * available_width + fixed;
+               *dimension = orig > 0 ? orig : 0;
+       }
+}
+
+/**
+ * Calculate width, height, and thickness of margins, paddings, and borders.
+ *
+ * \param  unit_len_ctx     Length conversion context
+ * \param  available_width  width of containing block
+ * \param  viewport_height  height of viewport in pixels or -ve if unknown
+ * \param  box              current box
+ * \param  style            style giving width, height, margins, paddings,
+ *                          and borders
+ * \param  width            updated to width, may be NULL
+ * \param  height           updated to height, may be NULL
+ * \param  max_width        updated to max-width, may be NULL
+ * \param  min_width        updated to min-width, may be NULL
+ * \param  max_height       updated to max-height, may be NULL
+ * \param  min_height       updated to min-height, may be NULL
+ * \param  margin           filled with margins, may be NULL
+ * \param  padding          filled with paddings, may be NULL
+ * \param  border           filled with border widths, may be NULL
+ */
+static inline void layout_find_dimensions(
+               const css_unit_ctx *unit_len_ctx,
+               int available_width,
+               int viewport_height,
+               const struct box *box,
+               const css_computed_style *style,
+               int *width,
+               int *height,
+               int *max_width,
+               int *min_width,
+               int *max_height,
+               int *min_height,
+               int margin[4],
+               int padding[4],
+               struct box_border border[4])
+{
+       struct box *containing_block = NULL;
+       unsigned int i;
+
+       if (width) {
+               enum css_width_e wtype;
+               css_fixed value = 0;
+               css_unit unit = CSS_UNIT_PX;
+
+               wtype = css_computed_width(style, &value, &unit);
+
+               if (wtype == CSS_WIDTH_SET) {
+                       if (unit == CSS_UNIT_PCT) {
+                               *width = FPCT_OF_INT_TOINT(
+                                               value, available_width);
+                       } else {
+                               *width = FIXTOINT(css_unit_len2device_px(
+                                               style, unit_len_ctx,
+                                               value, unit));
+                       }
+               } else {
+                       *width = AUTO;
+               }
+
+               if (*width != AUTO) {
+                       layout_handle_box_sizing(unit_len_ctx, box,
+                                       available_width, true, width);
+               }
+       }
+
+       if (height) {
+               enum css_height_e htype;
+               css_fixed value = 0;
+               css_unit unit = CSS_UNIT_PX;
+
+               htype = css_computed_height(style, &value, &unit);
+
+               if (htype == CSS_HEIGHT_SET) {
+                       if (unit == CSS_UNIT_PCT) {
+                               enum css_height_e cbhtype;
+
+                               if (css_computed_position(box->style) ==
+                                               CSS_POSITION_ABSOLUTE &&
+                                               box->parent) {
+                                       /* Box is absolutely positioned */
+                                       assert(box->float_container);
+                                       containing_block = box->float_container;
+                               } else if (box->float_container &&
+                                       css_computed_position(box->style) !=
+                                               CSS_POSITION_ABSOLUTE &&
+                                       (css_computed_float(box->style) ==
+                                               CSS_FLOAT_LEFT ||
+                                        css_computed_float(box->style) ==
+                                               CSS_FLOAT_RIGHT)) {
+                                       /* Box is a float */
+                                       assert(box->parent &&
+                                               box->parent->parent &&
+                                               box->parent->parent->parent);
+
+                                       containing_block =
+                                               box->parent->parent->parent;
+                               } else if (box->parent && box->parent->type !=
+                                               BOX_INLINE_CONTAINER) {
+                                       /* Box is a block level element */
+                                       containing_block = box->parent;
+                               } else if (box->parent && box->parent->type ==
+                                               BOX_INLINE_CONTAINER) {
+                                       /* Box is an inline block */
+                                       assert(box->parent->parent);
+                                       containing_block = box->parent->parent;
+                               }
+
+                               if (containing_block) {
+                                       css_fixed f = 0;
+                                       css_unit u = CSS_UNIT_PX;
+
+                                       cbhtype = css_computed_height(
+                                                       containing_block->style,
+                                                       &f, &u);
+                               }
+
+                               if (containing_block &&
+                                       containing_block->height != AUTO &&
+                                       (css_computed_position(box->style) ==
+                                                       CSS_POSITION_ABSOLUTE ||
+                                               cbhtype == CSS_HEIGHT_SET)) {
+                                       /* Box is absolutely positioned or its
+                                        * containing block has a valid
+                                        * specified height.
+                                        * (CSS 2.1 Section 10.5) */
+                                       *height = FPCT_OF_INT_TOINT(value,
+                                               containing_block->height);
+                               } else if ((!box->parent ||
+                                               !box->parent->parent) &&
+                                               viewport_height >= 0) {
+                                       /* If root element or it's child
+                                        * (HTML or BODY) */
+                                       *height = FPCT_OF_INT_TOINT(value,
+                                                       viewport_height);
+                               } else {
+                                       /* precentage height not permissible
+                                        * treat height as auto */
+                                       *height = AUTO;
+                               }
+                       } else {
+                               *height = FIXTOINT(css_unit_len2device_px(
+                                               style, unit_len_ctx,
+                                               value, unit));
+                       }
+               } else {
+                       *height = AUTO;
+               }
+
+               if (*height != AUTO) {
+                       layout_handle_box_sizing(unit_len_ctx, box,
+                                       available_width, false, height);
+               }
+       }
+
+       if (max_width) {
+               enum css_max_width_e type;
+               css_fixed value = 0;
+               css_unit unit = CSS_UNIT_PX;
+
+               type = css_computed_max_width(style, &value, &unit);
+
+               if (type == CSS_MAX_WIDTH_SET) {
+                       if (unit == CSS_UNIT_PCT) {
+                               *max_width = FPCT_OF_INT_TOINT(value,
+                                               available_width);
+                       } else {
+                               *max_width = FIXTOINT(css_unit_len2device_px(
+                                               style, unit_len_ctx,
+                                               value, unit));
+                       }
+               } else {
+                       /* Inadmissible */
+                       *max_width = -1;
+               }
+
+               if (*max_width != -1) {
+                       layout_handle_box_sizing(unit_len_ctx, box,
+                                       available_width, true, max_width);
+               }
+       }
+
+       if (min_width) {
+               enum css_min_width_e type;
+               css_fixed value = 0;
+               css_unit unit = CSS_UNIT_PX;
+
+               type = ns_computed_min_width(style, &value, &unit);
+
+               if (type == CSS_MIN_WIDTH_SET) {
+                       if (unit == CSS_UNIT_PCT) {
+                               *min_width = FPCT_OF_INT_TOINT(value,
+                                               available_width);
+                       } else {
+                               *min_width = FIXTOINT(css_unit_len2device_px(
+                                               style, unit_len_ctx,
+                                               value, unit));
+                       }
+               } else {
+                       /* Inadmissible */
+                       *min_width = 0;
+               }
+
+               if (*min_width != 0) {
+                       layout_handle_box_sizing(unit_len_ctx, box,
+                                       available_width, true, min_width);
+               }
+       }
+
+       if (max_height) {
+               enum css_max_height_e type;
+               css_fixed value = 0;
+               css_unit unit = CSS_UNIT_PX;
+
+               type = css_computed_max_height(style, &value, &unit);
+
+               if (type == CSS_MAX_HEIGHT_SET) {
+                       if (unit == CSS_UNIT_PCT) {
+                               /* TODO: handle percentage */
+                               *max_height = -1;
+                       } else {
+                               *max_height = FIXTOINT(css_unit_len2device_px(
+                                               style, unit_len_ctx,
+                                               value, unit));
+                       }
+               } else {
+                       /* Inadmissible */
+                       *max_height = -1;
+               }
+       }
+
+       if (min_height) {
+               enum css_min_height_e type;
+               css_fixed value = 0;
+               css_unit unit = CSS_UNIT_PX;
+
+               type = ns_computed_min_height(style, &value, &unit);
+
+               if (type == CSS_MIN_HEIGHT_SET) {
+                       if (unit == CSS_UNIT_PCT) {
+                               /* TODO: handle percentage */
+                               *min_height = 0;
+                       } else {
+                               *min_height = FIXTOINT(css_unit_len2device_px(
+                                               style, unit_len_ctx,
+                                               value, unit));
+                       }
+               } else {
+                       /* Inadmissible */
+                       *min_height = 0;
+               }
+       }
+
+       for (i = 0; i != 4; i++) {
+               if (margin) {
+                       enum css_margin_e type = CSS_MARGIN_AUTO;
+                       css_fixed value = 0;
+                       css_unit unit = CSS_UNIT_PX;
+
+                       type = margin_funcs[i](style, &value, &unit);
+
+                       if (type == CSS_MARGIN_SET) {
+                               if (unit == CSS_UNIT_PCT) {
+                                       margin[i] = FPCT_OF_INT_TOINT(value,
+                                                       available_width);
+                               } else {
+                                       margin[i] = 
FIXTOINT(css_unit_len2device_px(
+                                                       style, unit_len_ctx,
+                                                       value, unit));
+                               }
+                       } else {
+                               margin[i] = AUTO;
+                       }
+               }
+
+               if (padding) {
+                       css_fixed value = 0;
+                       css_unit unit = CSS_UNIT_PX;
+
+                       padding_funcs[i](style, &value, &unit);
+
+                       if (unit == CSS_UNIT_PCT) {
+                               padding[i] = FPCT_OF_INT_TOINT(value,
+                                               available_width);
+                       } else {
+                               padding[i] = FIXTOINT(css_unit_len2device_px(
+                                               style, unit_len_ctx,
+                                               value, unit));
+                       }
+               }
+
+               /* Table cell borders are populated in table.c */
+               if (border && box->type != BOX_TABLE_CELL) {
+                       enum css_border_style_e bstyle = CSS_BORDER_STYLE_NONE;
+                       css_color color = 0;
+                       css_fixed value = 0;
+                       css_unit unit = CSS_UNIT_PX;
+
+                       border_width_funcs[i](style, &value, &unit);
+                       bstyle = border_style_funcs[i](style);
+                       border_color_funcs[i](style, &color);
+
+                       border[i].style = bstyle;
+                       border[i].c = color;
+
+                       if (bstyle == CSS_BORDER_STYLE_HIDDEN ||
+                                       bstyle == CSS_BORDER_STYLE_NONE)
+                               /* spec unclear: following Mozilla */
+                               border[i].width = 0;
+                       else
+                               border[i].width = 
FIXTOINT(css_unit_len2device_px(
+                                               style, unit_len_ctx,
+                                               value, unit));
+
+                       /* Special case for border-collapse: make all borders
+                        * on table/table-row-group/table-row zero width. */
+                       if (css_computed_border_collapse(style) ==
+                                       CSS_BORDER_COLLAPSE_COLLAPSE &&
+                                       (box->type == BOX_TABLE ||
+                                        box->type == BOX_TABLE_ROW_GROUP ||
+                                        box->type == BOX_TABLE_ROW))
+                               border[i].width = 0;
+               }
+       }
+}
+
+#endif
diff --git a/content/handlers/html/table.c b/content/handlers/html/table.c
index 4ffccea..5e5d1cc 100644
--- a/content/handlers/html/table.c
+++ b/content/handlers/html/table.c
@@ -836,8 +836,12 @@ table_calculate_column_types(const css_unit_ctx 
*unit_len_ctx, struct box *table
                                enum css_width_e type;
                                css_fixed value = 0;
                                css_unit unit = CSS_UNIT_PX;
-
-                               assert(cell->type == BOX_TABLE_CELL);
+if (cell->type != BOX_TABLE_CELL && cell->type != BOX_FLEX) {
+       box_dump(stderr, table, 0, false);
+       printf("cell %p type: %u\n", cell, cell->type);
+}
+                               assert(cell->type == BOX_TABLE_CELL ||
+                                      cell->type == BOX_FLEX);
                                assert(cell->style);
 
                                if (cell->columns != 1)


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

Summary of changes:
 content/handlers/html/layout_flex.c |  347 +++++++++++++++++++----------------
 1 file changed, 193 insertions(+), 154 deletions(-)

diff --git a/content/handlers/html/layout_flex.c 
b/content/handlers/html/layout_flex.c
index 2cc232f..d2ea0b8 100644
--- a/content/handlers/html/layout_flex.c
+++ b/content/handlers/html/layout_flex.c
@@ -33,6 +33,7 @@
 
 #include <string.h>
 
+#include "utils/log.h"
 #include "utils/utils.h"
 
 #include "html/box.h"
@@ -249,7 +250,7 @@ static bool layout_flex_ctx__ensure_line(struct flex_ctx 
*ctx)
        return true;
 }
 
-static size_t layout_flex__fit_to_line(struct flex_ctx *ctx,
+static size_t layout_flex__build_line(struct flex_ctx *ctx,
                size_t item_index, int available_width, html_content *content)
 {
        struct flex_line_data *line;
@@ -269,7 +270,8 @@ static size_t layout_flex__fit_to_line(struct flex_ctx *ctx,
 
                width += lh__delta_outer_width(b);
 
-               if (lh__box_is_absolute(item->box) ||
+               if (ctx->wrap == CSS_FLEX_WRAP_NOWRAP ||
+                   lh__box_is_absolute(item->box) ||
                    width == 0 ||
                    width + used_width <= available_width ||
                    line->count == 0) {
@@ -290,6 +292,30 @@ static size_t layout_flex__fit_to_line(struct flex_ctx 
*ctx,
        return line->count;
 }
 
+static bool layout_flex__collect_items_into_lines(
+               struct flex_ctx *ctx,
+               int available_width,
+               html_content *content)
+{
+       size_t fitted = 0;
+       size_t pos = 0;
+
+       do {
+               fitted = layout_flex__build_line(ctx, pos,
+                               available_width, content);
+               pos += fitted;
+               fprintf(stderr, "  pos: %zu, fitted: %zu\n",
+                               pos, fitted);
+       } while (fitted != 0 && pos != ctx->item.count);
+
+       if (fitted == 0) {
+               NSLOG(layout, ERROR, "Failed to fit any flex items");
+               return false;
+       }
+
+       return true;
+}
+
 static inline void layout_flex__item_freeze(
                struct flex_line_data *line,
                struct flex_item_data *item)
@@ -300,6 +326,155 @@ static inline void layout_flex__item_freeze(
                        item->box, item->target_main_size);
 }
 
+static inline int layout_flex__remaining_free_space(
+               struct flex_ctx *ctx,
+               struct flex_line_data *line,
+               css_fixed *unfrozen_factor_sum,
+               int initial_free_space,
+               int available_width,
+               bool grow)
+{
+       int remaining_free_space = available_width;
+       size_t item_count = line->first + line->count;
+
+       *unfrozen_factor_sum = 0;
+
+       for (size_t i = line->first; i < item_count; i++) {
+               struct flex_item_data *item = &ctx->item.data[i];
+
+               if (item->freeze) {
+                       remaining_free_space -= item->target_main_size;
+               } else {
+                       remaining_free_space -= item->base_size;
+
+                       *unfrozen_factor_sum += grow ?
+                                       item->grow : item->shrink;
+               }
+       }
+       fprintf(stderr, "    Remaining free space: %i\n", remaining_free_space);
+
+       if (*unfrozen_factor_sum < F_1) {
+               int free_space = FIXTOINT(FMUL(INTTOFIX(initial_free_space),
+                               *unfrozen_factor_sum));
+
+               if (free_space < remaining_free_space) {
+                       remaining_free_space = free_space;
+               }
+               fprintf(stderr, "    Remaining free space: %i\n", 
remaining_free_space);
+       }
+
+       return remaining_free_space;
+}
+
+static inline int layout_flex__get_min_max_violations(
+               struct flex_ctx *ctx,
+               struct flex_line_data *line)
+{
+
+       int total_violation = 0;
+       size_t item_count = line->first + line->count;
+
+       for (size_t i = line->first; i < item_count; i++) {
+               struct flex_item_data *item = &ctx->item.data[i];
+               int target_main_size = item->target_main_size;
+
+               if (item->freeze) {
+                       continue;
+               }
+
+               if (item->max_width > 0 &&
+                   target_main_size > item->max_width) {
+                       target_main_size = item->max_width;
+                       item->max_violation = true;
+               }
+
+               if (target_main_size < item->min_width) {
+                       target_main_size = item->min_width;
+                       item->min_violation = true;
+               }
+
+               if (target_main_size < item->box->min_width) {
+                       target_main_size = item->box->min_width;
+                       item->min_violation = true;
+               }
+
+               if (target_main_size < 0) {
+                       target_main_size = 0;
+                       item->min_violation = true;
+               }
+
+               total_violation += target_main_size - item->target_main_size;
+               item->target_main_size = target_main_size;
+       }
+
+       return total_violation;
+}
+
+static inline void layout_flex__distribute_free_space(
+               struct flex_ctx *ctx,
+               struct flex_line_data *line,
+               css_fixed unfrozen_factor_sum,
+               int remaining_free_space,
+               bool grow)
+{
+       size_t item_count = line->first + line->count;
+
+       if (grow) {
+               for (size_t i = line->first; i < item_count; i++) {
+                       struct flex_item_data *item = &ctx->item.data[i];
+                       css_fixed ratio;
+
+                       if (item->freeze) {
+                               continue;
+                       }
+
+                       ratio = FDIV(item->grow, unfrozen_factor_sum);
+
+                       item->target_main_size = item->base_size +
+                                       FIXTOINT(FMUL(
+                                       INTTOFIX(remaining_free_space),
+                                       ratio));
+               }
+       } else {
+               css_fixed scaled_shrink_factor_sum = 0;
+
+               for (size_t i = line->first; i < item_count; i++) {
+                       struct flex_item_data *item = &ctx->item.data[i];
+                       css_fixed scaled_shrink_factor;
+
+                       if (item->freeze) {
+                               continue;
+                       }
+
+                       scaled_shrink_factor = FMUL(
+                                       item->shrink,
+                                       INTTOFIX(item->base_size));
+                       scaled_shrink_factor_sum += scaled_shrink_factor;
+               }
+
+               for (size_t i = line->first; i < item_count; i++) {
+                       struct flex_item_data *item = &ctx->item.data[i];
+                       css_fixed scaled_shrink_factor;
+                       css_fixed ratio;
+
+                       if (item->freeze) {
+                               continue;
+                       }
+
+                       scaled_shrink_factor = FMUL(
+                                       item->shrink,
+                                       INTTOFIX(item->base_size));
+                       ratio = FDIV(scaled_shrink_factor,
+                                    scaled_shrink_factor_sum);
+
+                       item->target_main_size = item->base_size -
+                                       FIXTOINT(FMUL(
+                                       INTTOFIX(abs(remaining_free_space)),
+                                       ratio));
+               }
+       }
+}
+
 /** 9.7. Resolving Flexible Lengths */
 static bool layout_flex__resolve_line(
                struct flex_ctx *ctx,
@@ -347,129 +522,27 @@ static bool layout_flex__resolve_line(
 
        /* 5. Loop */
        while (line->frozen < line->count) {
-               int remaining_free_space = available_width;
-               css_fixed unfrozen_factor_sum = 0;
+               css_fixed unfrozen_factor_sum;
+               int remaining_free_space;
+               int total_violation;
 
                fprintf(stderr, "  Flex resolver pass\n");
 
                /* b */
-               for (size_t i = line->first; i < item_count; i++) {
-                       struct flex_item_data *item = &ctx->item.data[i];
-
-                       if (item->freeze) {
-                               remaining_free_space -= item->target_main_size;
-                       } else {
-                               remaining_free_space -= item->base_size;
-
-                               unfrozen_factor_sum += grow ?
-                                               item->grow : item->shrink;
-                       }
-               }
-               fprintf(stderr, "    Remaining free space: %i\n", 
remaining_free_space);
-
-               if (unfrozen_factor_sum < F_1) {
-                       int free_space = FIXTOINT(FMUL(
-                                       INTTOFIX(initial_free_space),
-                                       unfrozen_factor_sum));
-
-                       if (free_space < remaining_free_space) {
-                               remaining_free_space = free_space;
-                       }
-                       fprintf(stderr, "    Remaining free space: %i\n", 
remaining_free_space);
-               }
+               remaining_free_space = layout_flex__remaining_free_space(ctx,
+                               line, &unfrozen_factor_sum, initial_free_space,
+                               available_width, grow);
 
                /* c */
                if (remaining_free_space != 0) {
-                       if (grow) {
-                               for (size_t i = line->first; i < item_count; 
i++) {
-                                       struct flex_item_data *item = 
&ctx->item.data[i];
-                                       css_fixed ratio;
-
-                                       if (item->freeze) {
-                                               continue;
-                                       }
-
-                                       ratio = FDIV(item->grow, 
unfrozen_factor_sum);
-
-                                       item->target_main_size = 
item->base_size +
-                                                       FIXTOINT(FMUL(
-                                                       
INTTOFIX(remaining_free_space),
-                                                       ratio));
-                               }
-                       } else {
-                               css_fixed scaled_shrink_factor_sum = 0;
-
-                               for (size_t i = line->first; i < item_count; 
i++) {
-                                       struct flex_item_data *item = 
&ctx->item.data[i];
-                                       css_fixed scaled_shrink_factor;
-
-                                       if (item->freeze) {
-                                               continue;
-                                       }
-
-                                       scaled_shrink_factor = FMUL(
-                                                       item->shrink,
-                                                       
INTTOFIX(item->base_size));
-                                       scaled_shrink_factor_sum += 
scaled_shrink_factor;
-                               }
-
-                               for (size_t i = line->first; i < item_count; 
i++) {
-                                       struct flex_item_data *item = 
&ctx->item.data[i];
-                                       css_fixed scaled_shrink_factor;
-                                       css_fixed ratio;
-
-                                       if (item->freeze) {
-                                               continue;
-                                       }
-
-                                       scaled_shrink_factor = FMUL(
-                                                       item->shrink,
-                                                       
INTTOFIX(item->base_size));
-                                       ratio = FDIV(scaled_shrink_factor,
-                                                    scaled_shrink_factor_sum);
-
-                                       item->target_main_size = 
item->base_size -
-                                                       FIXTOINT(FMUL(
-                                                       
INTTOFIX(abs(remaining_free_space)),
-                                                       ratio));
-                               }
-                       }
+                       layout_flex__distribute_free_space(ctx,
+                                       line, unfrozen_factor_sum,
+                                       remaining_free_space, grow);
                }
 
                /* d */
-               int total_violation = 0;
-               for (size_t i = line->first; i < item_count; i++) {
-                       struct flex_item_data *item = &ctx->item.data[i];
-                       int target_main_size = item->target_main_size;
-
-                       if (item->freeze) {
-                               continue;
-                       }
-
-                       if (item->max_width > 0 &&
-                           target_main_size > item->max_width) {
-                               target_main_size = item->max_width;
-                               item->max_violation = true;
-                       }
-
-                       if (target_main_size < item->min_width) {
-                               target_main_size = item->min_width;
-                               item->min_violation = true;
-                       }
-
-                       if (target_main_size < item->box->min_width) {
-                               target_main_size = item->box->min_width;
-                               item->min_violation = true;
-                       }
-
-                       if (target_main_size < 0) {
-                               target_main_size = 0;
-                               item->min_violation = true;
-                       }
-
-                       total_violation += target_main_size - 
item->target_main_size;
-                       item->target_main_size = target_main_size;
-               }
+               total_violation = layout_flex__get_min_max_violations(
+                               ctx, line);
 
                /* e */
                for (size_t i = line->first; i < item_count; i++) {
@@ -578,47 +651,13 @@ bool layout_flex(struct box *flex, int available_width,
                flex->width = available_width;
        }
 
-       available_width -= flex->margin[LEFT] +
-                          flex->margin[RIGHT] +
-                          flex->border[LEFT].width +
-                          flex->border[RIGHT].width +
-                          flex->padding[LEFT] +
-                          flex->padding[RIGHT];
+       available_width -= lh__delta_outer_width(flex);
 
        /* Place items onto lines. */
-       if (ctx->wrap == CSS_FLEX_WRAP_NOWRAP) {
-               fprintf(stderr, "Flex Wrap: nowrap\n");
-               struct flex_line_data *line = ctx->line.data;
-
-               for (size_t i = 0; i < ctx->item.count; i++) {
-                       struct flex_item_data *item = &ctx->item.data[i];
-                       struct box *b = item->box;
-
-                       if (!lh__box_is_absolute(b)) {
-                               line->main_size += item->main_size;
-                       }
-               }
-
-               line->first = 0;
-               line->count = ctx->item.count;
-               ctx->line.count = 1;
-       } else {
-               fprintf(stderr, "Flex Wrap: wrap\n");
-               size_t fitted = 0;
-               size_t pos = 0;
-
-               do {
-                       fitted = layout_flex__fit_to_line(ctx, pos,
-                                       available_width, content);
-                       pos += fitted;
-                       fprintf(stderr, "  pos: %zu, fitted: %zu\n",
-                                       pos, fitted);
-               } while (fitted != 0 && pos != ctx->item.count);
-
-               if (fitted == 0) {
-                       fprintf(stderr, "  Failed to fit any flex items\n");
-                       goto cleanup;
-               }
+       success = layout_flex__collect_items_into_lines(ctx,
+                       available_width, content);
+       if (!success) {
+               goto cleanup;
        }
 
        /* Layout children */


-- 
NetSurf Browser
_______________________________________________
netsurf-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to