Gitweb links:

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

The branch, tlsa/flex has been updated
  discards  3763ff16e046d60f7c2f1c4ec8e79f19a9ab495e (commit)
  discards  4bde73fce3b188b87384cba8beb108907fafacb2 (commit)
  discards  db083bdd61c9395b3a48ae67dd63b59f64092468 (commit)
  discards  4b18dd0bdc55dd73ed1a43e06a697266d0ed5590 (commit)
  discards  fac0e16a3431c9ae320fe798f82f0e504c915389 (commit)
  discards  d24835c56634bc687698ef48e650a4ceadbaf636 (commit)
  discards  a6b7b8e38833e7d8d5f4bffc454d7418e491481b (commit)
  discards  e455f157f3e4c8cd8c6e3ef4730d95dbf95b9528 (commit)
  discards  05d645dc45d4d803a61e6fe811e6312f563deabe (commit)
  discards  eb56aaaaf1c89eee0f4b8c7cb6dfbaf6c55cd889 (commit)
  discards  1d14229c3b2f7c071a260f3d2035193227b286cb (commit)
  discards  e174d0995ae8a07df43e23901410dcdd2f82221e (commit)
  discards  aa6273ea0ea099aa9a5e0b5b233a66abd4890794 (commit)
  discards  388952b222953cbed410c189c27c85c0f5e58d44 (commit)
       via  e529060fdc7b8a8f7a39e6e4e5639f931505d6f3 (commit)
       via  ff1d9fde950699afe9011b1dabe86d013d113c77 (commit)
       via  6d72aeccbc62cddc10ed6e50e62692298521f233 (commit)
       via  fc7cde7f40b30ff8764dfecc0ea2a779bd418175 (commit)
       via  fe6848502e64c2a246d73b9bdb93a011c61be4e6 (commit)
       via  9ee7d59c3e5e1bbc9c429cd5bce9e00f8b9f8566 (commit)
       via  4e69654e5d79ad7db9d76cc2a88a1430c8522487 (commit)
       via  201f2378696b63f41dd0b2ef2fda80806433b65a (commit)
       via  2cbee4b589e65b2d665d47ec38386f829ac1d20f (commit)
       via  dcb786405dc3b561d61f3ef892901e82b3620eb6 (commit)
       via  3e5c12844b07130a0c1d82d27ae8ba65f184e097 (commit)
       via  e8a6104b552ef687e699857c26fe7829799b5bf0 (commit)
       via  61c1e194ae0696606795d792cf90cebd7fce9449 (commit)
       via  0fbe132d6150302a0fdefdeba6b6cf9a6828c1b7 (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 (3763ff16e046d60f7c2f1c4ec8e79f19a9ab495e)
            \
             N -- N -- N (e529060fdc7b8a8f7a39e6e4e5639f931505d6f3)

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=e529060fdc7b8a8f7a39e6e4e5639f931505d6f3
commit e529060fdc7b8a8f7a39e6e4e5639f931505d6f3
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    html: layout: Initial implementation of display: flex

diff --git a/content/handlers/css/utils.h b/content/handlers/css/utils.h
index 0b05374..ee241e2 100644
--- a/content/handlers/css/utils.h
+++ b/content/handlers/css/utils.h
@@ -36,11 +36,9 @@ static inline uint8_t ns_computed_display(
        uint8_t value = css_computed_display(style, root);
 
        switch (value) {
-       case CSS_DISPLAY_FLEX:
        case CSS_DISPLAY_GRID:
                return CSS_DISPLAY_BLOCK;
 
-       case CSS_DISPLAY_INLINE_FLEX:
        case CSS_DISPLAY_INLINE_GRID:
                return CSS_DISPLAY_INLINE_BLOCK;
 
@@ -61,11 +59,9 @@ static inline uint8_t ns_computed_display_static(
        uint8_t value = css_computed_display_static(style);
 
        switch (value) {
-       case CSS_DISPLAY_FLEX:
        case CSS_DISPLAY_GRID:
                return CSS_DISPLAY_BLOCK;
 
-       case CSS_DISPLAY_INLINE_FLEX:
        case CSS_DISPLAY_INLINE_GRID:
                return CSS_DISPLAY_INLINE_BLOCK;
 
@@ -76,7 +72,6 @@ static inline uint8_t ns_computed_display_static(
        return value;
 }
 
-
 static inline uint8_t ns_computed_min_height(
                const css_computed_style *style,
                css_fixed *length, css_unit *unit)
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 12d9df8..eeadb84 100644
--- a/content/handlers/html/box_construct.c
+++ b/content/handlers/html/box_construct.c
@@ -86,28 +86,30 @@ struct box_construct_props {
 
 static const content_type image_types = CONTENT_IMAGE;
 
-/**
- * mapping from CSS display to box type this table must be in sync
- * with libcss' css_display enum
- */
+/* mapping from CSS display to box type
+ * this table must be in sync with libcss' css_display enum */
 static const box_type box_map[] = {
-       0, /* CSS_DISPLAY_INHERIT, */
-       BOX_INLINE, /* CSS_DISPLAY_INLINE, */
-       BOX_BLOCK, /* CSS_DISPLAY_BLOCK, */
-       BOX_BLOCK, /* CSS_DISPLAY_LIST_ITEM, */
-       BOX_INLINE, /* CSS_DISPLAY_RUN_IN, */
-       BOX_INLINE_BLOCK, /* CSS_DISPLAY_INLINE_BLOCK, */
-       BOX_TABLE, /* CSS_DISPLAY_TABLE, */
-       BOX_TABLE, /* CSS_DISPLAY_INLINE_TABLE, */
-       BOX_TABLE_ROW_GROUP, /* CSS_DISPLAY_TABLE_ROW_GROUP, */
-       BOX_TABLE_ROW_GROUP, /* CSS_DISPLAY_TABLE_HEADER_GROUP, */
-       BOX_TABLE_ROW_GROUP, /* CSS_DISPLAY_TABLE_FOOTER_GROUP, */
-       BOX_TABLE_ROW, /* CSS_DISPLAY_TABLE_ROW, */
-       BOX_NONE, /* CSS_DISPLAY_TABLE_COLUMN_GROUP, */
-       BOX_NONE, /* CSS_DISPLAY_TABLE_COLUMN, */
-       BOX_TABLE_CELL, /* CSS_DISPLAY_TABLE_CELL, */
-       BOX_INLINE, /* CSS_DISPLAY_TABLE_CAPTION, */
-       BOX_NONE /* CSS_DISPLAY_NONE */
+       BOX_BLOCK,           /* CSS_DISPLAY_INHERIT */
+       BOX_INLINE,          /* CSS_DISPLAY_INLINE */
+       BOX_BLOCK,           /* CSS_DISPLAY_BLOCK */
+       BOX_BLOCK,           /* CSS_DISPLAY_LIST_ITEM */
+       BOX_INLINE,          /* CSS_DISPLAY_RUN_IN */
+       BOX_INLINE_BLOCK,    /* CSS_DISPLAY_INLINE_BLOCK */
+       BOX_TABLE,           /* CSS_DISPLAY_TABLE */
+       BOX_TABLE,           /* CSS_DISPLAY_INLINE_TABLE */
+       BOX_TABLE_ROW_GROUP, /* CSS_DISPLAY_TABLE_ROW_GROUP */
+       BOX_TABLE_ROW_GROUP, /* CSS_DISPLAY_TABLE_HEADER_GROUP */
+       BOX_TABLE_ROW_GROUP, /* CSS_DISPLAY_TABLE_FOOTER_GROUP */
+       BOX_TABLE_ROW,       /* CSS_DISPLAY_TABLE_ROW */
+       BOX_NONE,            /* CSS_DISPLAY_TABLE_COLUMN_GROUP */
+       BOX_NONE,            /* CSS_DISPLAY_TABLE_COLUMN */
+       BOX_TABLE_CELL,      /* CSS_DISPLAY_TABLE_CELL */
+       BOX_INLINE,          /* CSS_DISPLAY_TABLE_CAPTION */
+       BOX_NONE,            /* CSS_DISPLAY_NONE */
+       BOX_FLEX,            /* CSS_DISPLAY_FLEX */
+       BOX_INLINE_FLEX,     /* CSS_DISPLAY_INLINE_FLEX */
+       BOX_BLOCK,           /* CSS_DISPLAY_GRID */
+       BOX_INLINE_BLOCK,    /* CSS_DISPLAY_INLINE_GRID */
 };
 
 
@@ -142,7 +144,6 @@ static inline bool box_is_root(dom_node *n)
        return true;
 }
 
-
 /**
  * Extract transient construction properties
  *
@@ -438,6 +439,23 @@ box_construct_marker(struct box *box,
        return true;
 }
 
+static inline bool box__style_is_float(const struct box *box)
+{
+       return css_computed_float(box->style) == CSS_FLOAT_LEFT ||
+              css_computed_float(box->style) == CSS_FLOAT_RIGHT;
+}
+
+static inline bool box__is_flex(const struct box *box)
+{
+       return box->type == BOX_FLEX || box->type == BOX_INLINE_FLEX;
+}
+
+static inline bool box__containing_block_is_flex(
+               const struct box_construct_props *props)
+{
+       return props->containing_block != NULL &&
+              box__is_flex(props->containing_block);
+}
 
 /**
  * Construct the box tree for an XML element.
@@ -451,6 +469,7 @@ box_construct_element(struct box_construct_ctx *ctx, bool 
*convert_children)
 {
        dom_string *title0, *s;
        lwc_string *id = NULL;
+       enum css_display_e css_display;
        struct box *box = NULL, *old_box;
        css_select_results *styles = NULL;
        lwc_string *bgimage_uri;
@@ -549,16 +568,15 @@ box_construct_element(struct box_construct_ctx *ctx, bool 
*convert_children)
                dom_string_unref(s);
        }
 
+       css_display = ns_computed_display_static(box->style);
+
        /* Set box type from computed display */
        if ((css_computed_position(box->style) == CSS_POSITION_ABSOLUTE ||
-                       css_computed_position(box->style) ==
-                                       CSS_POSITION_FIXED) &&
-                       (ns_computed_display_static(box->style) ==
-                                       CSS_DISPLAY_INLINE ||
-                        ns_computed_display_static(box->style) ==
-                                       CSS_DISPLAY_INLINE_BLOCK ||
-                        ns_computed_display_static(box->style) ==
-                                       CSS_DISPLAY_INLINE_TABLE)) {
+            css_computed_position(box->style) == CSS_POSITION_FIXED) &&
+                       (css_display == CSS_DISPLAY_INLINE ||
+                        css_display == CSS_DISPLAY_INLINE_BLOCK ||
+                        css_display == CSS_DISPLAY_INLINE_TABLE ||
+                        css_display == CSS_DISPLAY_INLINE_FLEX)) {
                /* Special case for absolute positioning: make absolute inlines
                 * into inline block so that the boxes are constructed in an
                 * inline container as if they were not absolutely positioned.
@@ -572,6 +590,21 @@ box_construct_element(struct box_construct_ctx *ctx, bool 
*convert_children)
                /* Normal mapping */
                box->type = box_map[ns_computed_display(box->style,
                                props.node_is_root)];
+
+               if (props.containing_block->type == BOX_FLEX ||
+                   props.containing_block->type == BOX_INLINE_FLEX) {
+                       /* Blockification */
+                       switch (box->type) {
+                       case BOX_INLINE_FLEX:
+                               box->type = BOX_FLEX;
+                               break;
+                       case BOX_INLINE_BLOCK:
+                               box->type = BOX_BLOCK;
+                               break;
+                       default:
+                               break;
+                       }
+               }
        }
 
        if (convert_special_elements(ctx->n,
@@ -587,10 +620,9 @@ box_construct_element(struct box_construct_ctx *ctx, bool 
*convert_children)
                                box->styles->styles[CSS_PSEUDO_ELEMENT_BEFORE]);
        }
 
-       if (box->type == BOX_NONE ||
-           (ns_computed_display(box->style,
-                                props.node_is_root) == CSS_DISPLAY_NONE &&
-            props.node_is_root == false)) {
+       if (box->type == BOX_NONE || (ns_computed_display(box->style,
+                       props.node_is_root) == CSS_DISPLAY_NONE &&
+                       props.node_is_root == false)) {
                css_select_results_destroy(styles);
                box->styles = NULL;
                box->style = NULL;
@@ -625,8 +657,9 @@ box_construct_element(struct box_construct_ctx *ctx, bool 
*convert_children)
                        (box->type == BOX_INLINE ||
                         box->type == BOX_BR ||
                         box->type == BOX_INLINE_BLOCK ||
-                        css_computed_float(box->style) == CSS_FLOAT_LEFT ||
-                        css_computed_float(box->style) == CSS_FLOAT_RIGHT) &&
+                        box->type == BOX_INLINE_FLEX ||
+                        (box__style_is_float(box) &&
+                         !box__containing_block_is_flex(&props))) &&
                        props.node_is_root == false) {
                /* Found an inline child of a block without a current container
                 * (i.e. this box is the first child of its parent, or was
@@ -674,6 +707,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 */
@@ -690,6 +724,7 @@ box_construct_element(struct box_construct_ctx *ctx, bool 
*convert_children)
                }
 
                if (props.node_is_root == false &&
+                               box__containing_block_is_flex(&props) == false 
&&
                                (css_computed_float(box->style) ==
                                CSS_FLOAT_LEFT ||
                                css_computed_float(box->style) ==
@@ -1342,7 +1377,6 @@ struct box *box_for_node(dom_node *n)
        return box;
 }
 
-
 /* exported function documented in html/box_construct.h */
 bool
 box_extract_link(const html_content *content,
diff --git a/content/handlers/html/box_inspect.c 
b/content/handlers/html/box_inspect.c
index b6b9f81..181f58c 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/box_special.c 
b/content/handlers/html/box_special.c
index f761557..db3c412 100644
--- a/content/handlers/html/box_special.c
+++ b/content/handlers/html/box_special.c
@@ -560,8 +560,18 @@ static bool
 box_input_text(html_content *html, struct box *box, struct dom_node *node)
 {
        struct box *inline_container, *inline_box;
+       uint8_t display = css_computed_display_static(box->style);
 
-       box->type = BOX_INLINE_BLOCK;
+       switch (display) {
+       case CSS_DISPLAY_GRID:
+       case CSS_DISPLAY_FLEX:
+       case CSS_DISPLAY_BLOCK:
+               box->type = BOX_BLOCK;
+               break;
+       default:
+               box->type = BOX_INLINE_BLOCK;
+               break;
+       }
 
        inline_container = box_create(NULL, 0, false, 0, 0, 0, 0, html->bctx);
        if (!inline_container)
@@ -825,8 +835,8 @@ box_canvas(dom_node *n,
        }
        *convert_children = false;
 
-       if (box->style &&
-           ns_computed_display(box->style, box_is_root(n)) == CSS_DISPLAY_NONE)
+       if (box->style && ns_computed_display(box->style,
+                       box_is_root(n)) == CSS_DISPLAY_NONE)
                return true;
 
        /* This is replaced content */
@@ -854,8 +864,8 @@ box_embed(dom_node *n,
        dom_string *src;
        dom_exception err;
 
-       if (box->style &&
-           ns_computed_display(box->style, box_is_root(n)) == CSS_DISPLAY_NONE)
+       if (box->style && ns_computed_display(box->style,
+                       box_is_root(n)) == CSS_DISPLAY_NONE)
                return true;
 
        params = talloc(content->bctx, struct object_params);
@@ -1025,8 +1035,8 @@ box_iframe(dom_node *n,
        struct content_html_iframe *iframe;
        int i;
 
-       if (box->style &&
-           ns_computed_display(box->style, box_is_root(n)) == CSS_DISPLAY_NONE)
+       if (box->style && ns_computed_display(box->style,
+                       box_is_root(n)) == CSS_DISPLAY_NONE)
                return true;
 
        if (box->style &&
@@ -1154,8 +1164,8 @@ box_image(dom_node *n,
        css_unit wunit = CSS_UNIT_PX;
        css_unit hunit = CSS_UNIT_PX;
 
-       if (box->style &&
-           ns_computed_display(box->style, box_is_root(n)) == CSS_DISPLAY_NONE)
+       if (box->style && ns_computed_display(box->style,
+                       box_is_root(n)) == CSS_DISPLAY_NONE)
                return true;
 
        /* handle alt text */
@@ -1322,10 +1332,9 @@ box_input(dom_node *n,
                                                   corestring_lwc_image)) {
                gadget->type = GADGET_IMAGE;
 
-               if (box->style &&
-                   ns_computed_display(box->style,
+               if (box->style && ns_computed_display(box->style,
                                box_is_root(n)) != CSS_DISPLAY_NONE &&
-                   nsoption_bool(foreground_images) == true) {
+                               nsoption_bool(foreground_images) == true) {
                        dom_string *s;
 
                        err = dom_element_get_attribute(n, corestring_dom_src, 
&s);
@@ -1405,8 +1414,8 @@ box_object(dom_node *n,
        dom_node *c;
        dom_exception err;
 
-       if (box->style &&
-           ns_computed_display(box->style, box_is_root(n)) == CSS_DISPLAY_NONE)
+       if (box->style && ns_computed_display(box->style,
+                       box_is_root(n)) == CSS_DISPLAY_NONE)
                return true;
 
        if (box_get_attribute(n, "usemap", content->bctx, &box->usemap) ==
diff --git a/content/handlers/html/layout.c b/content/handlers/html/layout.c
index 816775c..8ba45da 100644
--- a/content/handlers/html/layout.c
+++ b/content/handlers/html/layout.c
@@ -522,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;
@@ -536,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;
@@ -869,7 +869,6 @@ layout_minmax_inline_container(struct box *inline_container,
                        inline_container->max_width);
 }
 
-
 /**
  * Calculate minimum and maximum width of a block.
  *
@@ -900,6 +899,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);
 
@@ -915,7 +916,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;
@@ -926,6 +928,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 ||
@@ -975,6 +980,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);
@@ -1016,10 +1022,24 @@ 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) &&
+                           lh__flex_main_is_horizontal(block)) {
+                               if (block->style != NULL &&
+                                   css_computed_flex_wrap(block->style) ==
+                                               CSS_FLEX_WRAP_NOWRAP) {
+                                       min += child->min_width;
+                               } else {
+                                       if (min < child->min_width)
+                                               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;
@@ -1032,7 +1052,7 @@ static void layout_minmax_block(
        }
 
        /* fixed width takes priority */
-       if (block->type != BOX_TABLE_CELL) {
+       if (block->type != BOX_TABLE_CELL && !lh__box_is_flex_item(block)) {
                bool border_box = bs == CSS_BOX_SIZING_BORDER_BOX;
                enum css_max_width_e max_type;
                enum css_min_width_e min_type;
@@ -1121,7 +1141,8 @@ static void layout_minmax_block(
                block->max_width = (max + extra_fixed) / (1.0 - extra_frac);
        }
 
-       assert(0 <= block->min_width && block->min_width <= block->max_width);
+       assert(0 <= block->min_width);
+       assert(block->min_width <= block->max_width);
 }
 
 
@@ -2283,7 +2304,9 @@ static bool layout_block_object(struct box *block)
 {
        assert(block);
        assert(block->type == BOX_BLOCK ||
+                       block->type == BOX_FLEX ||
                        block->type == BOX_INLINE_BLOCK ||
+                       block->type == BOX_INLINE_FLEX ||
                        block->type == BOX_TABLE ||
                        block->type == BOX_TABLE_CELL);
        assert(block->object);
@@ -2577,12 +2600,20 @@ 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))
-                       return false;
+       if (b->type == BOX_TABLE || b->type == BOX_INLINE_FLEX) {
+               if (b->type == BOX_TABLE) {
+                       if (!layout_table(b, width, content))
+                               return false;
+               } else {
+                       if (!layout_flex(b, width, content))
+                               return false;
+               }
                if (b->margin[LEFT] == AUTO)
                        b->margin[LEFT] = 0;
                if (b->margin[RIGHT] == AUTO)
@@ -2591,8 +2622,9 @@ static bool layout_float(struct box *b, int width, 
html_content *content)
                        b->margin[TOP] = 0;
                if (b->margin[BOTTOM] == AUTO)
                        b->margin[BOTTOM] = 0;
-       } else
+       } else {
                return layout_block_context(b, -1, content);
+       }
        return true;
 }
 
@@ -2800,7 +2832,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;
@@ -3020,7 +3053,8 @@ layout_line(struct box *first,
                        b->x = x;
 
                        if ((b->type == BOX_INLINE && !b->inline_end) ||
-                                       b->type == BOX_INLINE_BLOCK) {
+                                       b->type == BOX_INLINE_BLOCK ||
+                                       b->type == BOX_INLINE_FLEX) {
                                b->x += b->margin[LEFT] + b->border[LEFT].width;
                                x = b->x + b->padding[LEFT] + b->width +
                                                b->padding[RIGHT] +
@@ -3521,7 +3555,9 @@ bool layout_block_context(
 
        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);
 
@@ -3590,7 +3626,9 @@ bool layout_block_context(
                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
@@ -3641,7 +3679,9 @@ bool layout_block_context(
                 * left and right margins to avoid any floats. */
                lm = rm = 0;
 
-               if (box->type == BOX_BLOCK || box->flags & IFRAME) {
+               if (box->type == BOX_FLEX ||
+                   box->type == BOX_BLOCK ||
+                   box->flags & IFRAME) {
                        if (lh__box_is_object(box) == false &&
                                        box->style &&
                                        (overflow_x != CSS_OVERFLOW_VISIBLE ||
@@ -3727,6 +3767,7 @@ bool layout_block_context(
 
                /* 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)) ||
@@ -3751,11 +3792,19 @@ bool layout_block_context(
 
                /* Unless the box has an overflow style of visible, the box
                 * establishes a new block context. */
-               if (box->type == BOX_BLOCK && box->style &&
-                               (overflow_x != CSS_OVERFLOW_VISIBLE ||
-                                overflow_y != CSS_OVERFLOW_VISIBLE)) {
+               if (box->type == BOX_FLEX ||
+                               (box->type == BOX_BLOCK && box->style &&
+                                (overflow_x != CSS_OVERFLOW_VISIBLE ||
+                                 overflow_y != CSS_OVERFLOW_VISIBLE))) {
 
-                       layout_block_context(box, viewport_height, content);
+                       if (box->type == BOX_FLEX) {
+                               if (!layout_flex(box, box->width, content)) {
+                                       return false;
+                               }
+                       } else {
+                               layout_block_context(box,
+                                               viewport_height, content);
+                       }
 
                        cy += box->padding[TOP];
 
@@ -3776,7 +3825,8 @@ bool layout_block_context(
                        goto advance_to_next_box;
                }
 
-               NSLOG(layout, DEBUG,  "box %p, cx %i, cy %i", box, cx, cy);
+               NSLOG(layout, DEBUG,  "box %p, cx %i, cy %i, width %i",
+                               box, cx, cy, box->width);
 
                /* Layout (except tables). */
                if (box->object) {
@@ -4552,7 +4602,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
@@ -4787,6 +4839,13 @@ 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) {
+               /* layout_table also expects the containing block to be
+                * stored in the float_container field */
+               box->float_container = containing_block;
+               if (!layout_flex(box, width, content))
+                       return false;
+               box->float_container = NULL;
        }
 
        /* 10.6.4 */
@@ -4923,7 +4982,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) ==
diff --git a/content/handlers/html/layout_flex.c 
b/content/handlers/html/layout_flex.c
new file mode 100644
index 0000000..54bab70
--- /dev/null
+++ b/content/handlers/html/layout_flex.c
@@ -0,0 +1,830 @@
+/*
+ * 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_main;
+       int max_main;
+       int min_cross;
+       int max_cross;
+
+       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 main_size;
+       int cross_size;
+
+       size_t first;
+       size_t count;
+       size_t frozen;
+};
+
+struct flex_ctx {
+       html_content *content;
+       const struct box *flex;
+       const css_unit_ctx *unit_len_ctx;
+
+       int main_size;
+       int cross_size;
+
+       bool horizontal;
+       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);
+       ctx->horizontal = lh__flex_main_is_horizontal(flex);
+
+       return ctx;
+}
+
+static bool layout_flex_item(
+               const struct flex_ctx *ctx,
+               const struct flex_item_data *item,
+               int available_width)
+{
+       bool success;
+       struct box *b = item->box;
+
+       switch (b->type) {
+       case BOX_BLOCK:
+               success = layout_block_context(b, -1,
+                               ctx->content);
+               break;
+       case BOX_TABLE:
+               b->float_container = b->parent;
+               success = layout_table(b, available_width,
+                               ctx->content);
+               b->float_container = NULL;
+               break;
+       case BOX_FLEX:
+               b->float_container = b->parent;
+               success = layout_flex(b, available_width,
+                               ctx->content);
+               b->float_container = NULL;
+               break;
+       default:
+               assert(0 && "Bad flex item back type");
+               success = false;
+               break;
+       }
+
+       return success;
+}
+
+static inline bool 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 content_min_width = b->min_width;
+       int content_max_width = b->max_width;
+       int delta_outer_main = lh__delta_outer_main(ctx->flex, b);
+
+       NSLOG(flex, WARNING, "box %p: delta_outer_main: %i",
+                       b, delta_outer_main);
+
+       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 = ctx->horizontal ? b->width : b->height;
+       } else {
+               item->base_size = AUTO;
+       }
+
+       if (ctx->horizontal == false) {
+               if (b->width == AUTO) {
+                       b->width = min(available_width, content_max_width);
+                       b->width -= lh__delta_outer_width(b);
+               }
+
+               if (!layout_flex_item(ctx, item, b->width)) {
+                       NSLOG(flex, WARNING, "box %p: layout failed", b);
+                       return false;
+               }
+       }
+
+       if (item->base_size == AUTO) {
+               if (ctx->horizontal == false) {
+                       item->base_size = b->height;
+               } else {
+                       item->base_size = content_max_width - delta_outer_main;
+               }
+       }
+
+       item->base_size += delta_outer_main;
+
+       if (ctx->horizontal) {
+               item->base_size = min(item->base_size, available_width);
+               item->base_size = max(item->base_size, content_min_width);
+       }
+
+       item->target_main_size = item->base_size;
+       item->main_size = item->base_size;
+
+       if (item->max_main > 0 &&
+           item->main_size > item->max_main + delta_outer_main) {
+               item->main_size = item->max_main + delta_outer_main;
+       }
+
+       if (item->main_size < item->min_main + delta_outer_main) {
+               item->main_size = item->min_main + delta_outer_main;
+       }
+
+       NSLOG(flex, WARNING, "flex-item box: %p: base_size: %i, main_size %i",
+                       b, item->base_size, item->main_size);
+
+       return true;
+}
+
+static void layout_flex_ctx__populate_item_data(
+               const struct flex_ctx *ctx,
+               const struct box *flex,
+               int available_width)
+{
+       size_t i = 0;
+       bool horizontal = ctx->horizontal;
+
+       for (struct box *b = flex->children; b != NULL; b = b->next) {
+               struct flex_item_data *item = &ctx->item.data[i++];
+
+               b->float_container = b->parent;
+               layout_find_dimensions(ctx->unit_len_ctx, available_width, -1,
+                               b, b->style, &b->width, &b->height,
+                               horizontal ? &item->max_main : &item->max_cross,
+                               horizontal ? &item->min_main : &item->min_cross,
+                               horizontal ? &item->max_cross : &item->max_main,
+                               horizontal ? &item->min_cross : &item->min_main,
+                               b->margin, b->padding, b->border);
+               b->float_container = NULL;
+
+               NSLOG(flex, WARNING, "flex-item box: %p: width: %i",
+                               b, b->width);
+
+               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;
+
+       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;
+
+       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 struct flex_line_data *layout_flex__build_line(struct flex_ctx *ctx,
+               size_t item_index, int available_width, html_content *content)
+{
+       struct flex_line_data *line;
+       int available_main;
+       int used_main = 0;
+
+       if (!layout_flex_ctx__ensure_line(ctx)) {
+               return 0;
+       }
+
+       line = &ctx->line.data[ctx->line.count];
+       line->first = item_index;
+
+       if (ctx->horizontal) {
+               available_main = available_width;
+       } else {
+               available_main = ctx->flex->height;
+       }
+
+       NSLOG(flex, WARNING, "flex container %p: available main: %i",
+                       ctx->flex, available_main);
+
+       while (item_index < ctx->item.count) {
+               struct flex_item_data *item = &ctx->item.data[item_index];
+               struct box *b = item->box;
+               int main;
+
+               main = ctx->horizontal ?
+                               item->main_size :
+                               b->height + lh__delta_outer_main(ctx->flex, b);
+
+               if (ctx->wrap == CSS_FLEX_WRAP_NOWRAP ||
+                   main + used_main <= available_main ||
+                   lh__box_is_absolute(item->box) ||
+                   available_main == AUTO ||
+                   line->count == 0 ||
+                   main == 0) {
+                       if (lh__box_is_absolute(item->box) == false) {
+                               line->main_size += item->main_size;
+                               used_main += main;
+                       }
+                       item->line = ctx->line.count;
+                       line->count++;
+                       item_index++;
+               } else {
+                       break;
+               }
+       }
+
+       if (line->count > 0) {
+               ctx->line.count++;
+       } else {
+               NSLOG(layout, ERROR, "Failed to fit any flex items");
+       }
+
+       return line;
+}
+
+static inline void layout_flex__item_freeze(
+               struct flex_line_data *line,
+               struct flex_item_data *item)
+{
+       item->freeze = true;
+       line->frozen++;
+
+       NSLOG(flex, WARNING, "flex-item box: %p: Frozen at target_main_size: 
%i",
+                       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_space,
+               bool grow)
+{
+       int remaining_free_space = available_space;
+       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;
+               }
+       }
+
+       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;
+               }
+       }
+
+       NSLOG(flex, WARNING, "Remaining free space: %i", 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;
+
+               NSLOG(flex, WARNING, "item %p: target_main_size: %i",
+                                       item->box, target_main_size);
+
+               if (item->freeze) {
+                       continue;
+               }
+
+               if (item->max_main > 0 &&
+                   target_main_size > item->max_main) {
+                       target_main_size = item->max_main;
+                       item->max_violation = true;
+                       NSLOG(flex, WARNING, "Violation: max_main: %i",
+                                       item->max_main);
+               }
+
+               if (target_main_size < item->min_main) {
+                       target_main_size = item->min_main;
+                       item->min_violation = true;
+                       NSLOG(flex, WARNING, "Violation: min_main: %i",
+                                       item->min_main);
+               }
+
+               if (target_main_size < item->box->min_width) {
+                       target_main_size = item->box->min_width;
+                       item->min_violation = true;
+                       NSLOG(flex, WARNING, "Violation: box min_width: %i",
+                                       item->box->min_width);
+               }
+
+               if (target_main_size < 0) {
+                       target_main_size = 0;
+                       item->min_violation = true;
+                       NSLOG(flex, WARNING, "Violation: less than 0");
+               }
+
+               total_violation += target_main_size - item->target_main_size;
+               item->target_main_size = target_main_size;
+       }
+
+       NSLOG(flex, WARNING, "Total violation: %i", total_violation);
+
+       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;
+                       } else if (scaled_shrink_factor_sum == 0) {
+                               item->target_main_size = item->main_size;
+                               layout_flex__item_freeze(line, item);
+                               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));
+               }
+       }
+}
+
+static bool layout_flex__resolve_line_horizontal(
+               struct flex_ctx *ctx,
+               struct flex_line_data *line,
+               int available_width)
+{
+       size_t item_count = line->first + line->count;
+       int x = ctx->flex->padding[LEFT];
+
+       for (size_t i = line->first; i < item_count; i++) {
+               struct flex_item_data *item = &ctx->item.data[i];
+               struct box *b = item->box;
+               bool success = false;
+
+               b->width = item->target_main_size - lh__delta_outer_width(b);
+
+               success = layout_flex_item(ctx, item, b->width);
+               if (!success) {
+                       NSLOG(flex, WARNING, "box %p: layout failed", b);
+                       return false;
+               }
+
+               b->y = ctx->flex->padding[TOP] + ctx->cross_size +
+                               lh__non_auto_margin(b, TOP) +
+                               b->border[TOP].width;
+
+               b->x = x + lh__non_auto_margin(b, LEFT) +
+                               b->border[LEFT].width;
+
+               if (lh__box_is_absolute(b) == false) {
+                       int height;
+
+                       height = b->height + lh__delta_outer_height(b);
+                       if (line->cross_size < height) {
+                               line->cross_size = height;
+                       }
+
+                       x += b->width + lh__delta_outer_width(b);
+               }
+       }
+
+       return true;
+}
+
+static bool layout_flex__resolve_line_vertical(
+               struct flex_ctx *ctx,
+               struct flex_line_data *line,
+               int available_width)
+{
+       size_t item_count = line->first + line->count;
+       int y = ctx->flex->padding[TOP];
+
+       for (size_t i = line->first; i < item_count; i++) {
+               struct flex_item_data *item = &ctx->item.data[i];
+               struct box *b = item->box;
+
+               b->x = ctx->flex->padding[LEFT] + ctx->cross_size +
+                               lh__non_auto_margin(b, LEFT) +
+                               b->border[LEFT].width;
+
+               b->y = y + lh__non_auto_margin(b, TOP) +
+                               b->border[TOP].width;
+
+               if (lh__box_is_absolute(b) == false) {
+                       int width;
+
+                       width = b->width + lh__delta_outer_width(b);
+                       if (line->cross_size < width) {
+                               line->cross_size = width;
+                       }
+
+                       y += b->height + lh__delta_outer_height(b);
+               }
+       }
+
+       return true;
+}
+
+/** 9.7. Resolving Flexible Lengths */
+static bool layout_flex__resolve_line(
+               struct flex_ctx *ctx,
+               struct flex_line_data *line,
+               int available_width)
+{
+       bool grow = (line->main_size < available_width);
+       size_t item_count = line->first + line->count;
+       int available_space = available_width;
+       int initial_free_space;
+
+       available_space = available_width;
+       if (ctx->horizontal == false) {
+               available_space = ctx->flex->height;
+               if (available_space == AUTO) {
+                       available_space = INT_MAX;
+               }
+       }
+
+       initial_free_space = available_space;
+
+       NSLOG(flex, WARNING, "box %p: line %zu: first: %zu, count: %zu",
+                       ctx->flex, line - ctx->line.data,
+                       line->first, line->count);
+       NSLOG(flex, WARNING, "Line main_size: %i, available_space: %i",
+                       line->main_size, available_space);
+
+       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) {
+                               item->target_main_size = item->main_size;
+                               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;
+
+               NSLOG(flex, WARNING, "flex-container: %p: Resolver pass",
+                               ctx->flex);
+
+               /* b */
+               remaining_free_space = layout_flex__remaining_free_space(ctx,
+                               line, &unfrozen_factor_sum, initial_free_space,
+                               available_space, 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);
+                       }
+               }
+       }
+
+       if (ctx->horizontal) {
+               if (!layout_flex__resolve_line_horizontal(ctx,
+                               line, available_width)) {
+                       return false;
+               }
+       } else {
+               if (!layout_flex__resolve_line_vertical(ctx,
+                               line, available_width)) {
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+static bool layout_flex__collect_items_into_lines(
+               struct flex_ctx *ctx,
+               int available_width,
+               html_content *content)
+{
+       size_t pos = 0;
+
+       while (pos < ctx->item.count) {
+               struct flex_line_data *line;
+
+               line = layout_flex__build_line(ctx, pos,
+                               available_width, content);
+               if (line == NULL) {
+                       return false;
+               }
+
+               pos += line->count;
+
+               NSLOG(flex, WARNING, "flex-container: %p: "
+                               "fitted: %zu (total: %zu/%zu)",
+                               ctx->flex, line->count,
+                               pos, ctx->item.count);
+
+               if (!layout_flex__resolve_line(ctx, line, available_width)) {
+                       return false;
+               }
+
+               ctx->cross_size += line->cross_size;
+               if (ctx->main_size < line->main_size) {
+                       ctx->main_size = line->main_size;
+               }
+       }
+
+       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_height, min_height;
+       struct flex_ctx *ctx;
+       bool success = false;
+
+       ctx = layout_flex_ctx__create(content, flex);
+       if (ctx == NULL) {
+               return false;
+       }
+
+       NSLOG(flex, WARNING, "box %p: %s, available_width %i, width: %i", flex,
+                       ctx->horizontal ? "horizontal" : "vertical",
+                       available_width, flex->width);
+
+       layout_find_dimensions(
+                       ctx->unit_len_ctx, available_width, -1,
+                       flex, flex->style, NULL, &flex->height,
+                       NULL, NULL, &max_height, &min_height,
+                       flex->margin, flex->padding, flex->border);
+
+       available_width = min(available_width, flex->width);
+
+       layout_flex_ctx__populate_item_data(ctx, flex, available_width);
+
+       /* Place items onto lines. */
+       success = layout_flex__collect_items_into_lines(ctx,
+                       available_width, content);
+       if (!success) {
+               goto cleanup;
+       }
+
+       if (flex->height == AUTO) {
+               flex->height = ctx->horizontal ?
+                               ctx->cross_size :
+                               ctx->main_size;
+       }
+
+       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);
+
+       NSLOG(flex, WARNING, "box %p: %s", flex,
+                       success ? "success" : "failure");
+       return success;
+}
diff --git a/content/handlers/html/layout_internal.h 
b/content/handlers/html/layout_internal.h
index 39b42b1..445b430 100644
--- a/content/handlers/html/layout_internal.h
+++ b/content/handlers/html/layout_internal.h
@@ -106,11 +106,25 @@ static inline bool lh__box_is_float_box(const struct box 
*b)
 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 takes part in inline flow. */
+static inline bool lh__box_is_flex_item(const struct box *b)
+{
+       return (b->parent != NULL) && lh__box_is_flex_container(b->parent);
+}
+
 /** Layout helper: Check whether box is inline level. (Includes BR.) */
 static inline bool lh__box_is_inline_level(const struct box *b)
 {
@@ -147,6 +161,76 @@ static inline bool lh__have_border(
        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 ||
+              css_computed_position(b->style) == CSS_POSITION_FIXED;
+}
+
+static inline bool lh__flex_main_is_horizontal(const 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__non_auto_margin(const struct box *b, enum box_side side)
+{
+       return (b->margin[side] == AUTO) ? 0 : b->margin[side];
+}
+
+static inline int lh__delta_outer_height(const struct box *b)
+{
+       return b->padding[TOP] +
+              b->padding[BOTTOM] +
+              b->border[TOP].width +
+              b->border[BOTTOM].width +
+              lh__non_auto_margin(b, TOP) +
+              lh__non_auto_margin(b, BOTTOM);
+}
+
+static inline int lh__delta_outer_width(const struct box *b)
+{
+       return b->padding[LEFT] +
+              b->padding[RIGHT] +
+              b->border[LEFT].width +
+              b->border[RIGHT].width +
+              lh__non_auto_margin(b, LEFT) +
+              lh__non_auto_margin(b, RIGHT);
+}
+
+static inline int lh__delta_outer_main(
+               const struct box *flex,
+               const struct box *b)
+{
+       if (lh__flex_main_is_horizontal(flex)) {
+               return lh__delta_outer_width(b);
+       } else {
+               return lh__delta_outer_height(b);
+       }
+}
+
+static inline int lh__delta_outer_cross(
+               const struct box *flex,
+               const struct box *b)
+{
+       if (lh__flex_main_is_horizontal(flex) == false) {
+               return lh__delta_outer_width(b);
+       } else {
+               return lh__delta_outer_height(b);
+       }
+}
+
 /**
  * Determine width of margin, borders, and padding on one side of a box.
  *


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

    html: box_dump: Indicate descendant bounding box values

diff --git a/content/handlers/html/box_inspect.c 
b/content/handlers/html/box_inspect.c
index b4b1394..b6b9f81 100644
--- a/content/handlers/html/box_inspect.c
+++ b/content/handlers/html/box_inspect.c
@@ -660,7 +660,7 @@ void box_dump(FILE *stream, struct box *box, unsigned int 
depth, bool style)
        if (box->max_width != UNKNOWN_MAX_WIDTH) {
                fprintf(stream, "min%i max%i ", box->min_width, box->max_width);
        }
-       fprintf(stream, "(%i %i %i %i) ",
+       fprintf(stream, "desc(%i %i %i %i) ",
                box->descendant_x0, box->descendant_y0,
                box->descendant_x1, box->descendant_y1);
 


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

    layout: minmax pass: Improve handling of {min|max}_width properties

diff --git a/content/handlers/html/layout.c b/content/handlers/html/layout.c
index f632bdc..816775c 100644
--- a/content/handlers/html/layout.c
+++ b/content/handlers/html/layout.c
@@ -895,6 +895,8 @@ static void layout_minmax_block(
        css_fixed height = 0;
        css_unit hunit = CSS_UNIT_PX;
        enum css_box_sizing_e bs = CSS_BOX_SIZING_CONTENT_BOX;
+       bool using_min_border_box = false;
+       bool using_max_border_box = false;
        bool child_has_height = false;
 
        assert(block->type == BOX_BLOCK ||
@@ -1030,23 +1032,40 @@ static void layout_minmax_block(
        }
 
        /* fixed width takes priority */
-       if (block->type != BOX_TABLE_CELL && wtype == CSS_WIDTH_SET &&
-                       wunit != CSS_UNIT_PCT) {
-               min = max = FIXTOINT(css_unit_len2device_px(block->style,
-                               &content->unit_len_ctx, width, wunit));
-               if (bs == CSS_BOX_SIZING_BORDER_BOX) {
-                       int border_box_fixed = 0;
-                       float border_box_frac = 0;
-                       calculate_mbp_width(&content->unit_len_ctx,
-                                       block->style, LEFT,
-                                       false, true, true,
-                                       &border_box_fixed, &border_box_frac);
-                       calculate_mbp_width(&content->unit_len_ctx,
-                                       block->style, RIGHT,
-                                       false, true, true,
-                                       &border_box_fixed, &border_box_frac);
-                       if (min < border_box_fixed) {
-                               min = max = border_box_fixed;
+       if (block->type != BOX_TABLE_CELL) {
+               bool border_box = bs == CSS_BOX_SIZING_BORDER_BOX;
+               enum css_max_width_e max_type;
+               enum css_min_width_e min_type;
+               css_unit unit = CSS_UNIT_PX;
+               css_fixed value = 0;
+
+               if (wtype == CSS_WIDTH_SET && wunit != CSS_UNIT_PCT) {
+                       min = max = FIXTOINT(
+                                       css_unit_len2device_px(block->style,
+                                       &content->unit_len_ctx, width, wunit));
+                       using_max_border_box = border_box;
+                       using_min_border_box = border_box;
+               }
+
+               min_type = css_computed_min_width(block->style, &value, &unit);
+               if (min_type == CSS_MIN_WIDTH_SET && unit != CSS_UNIT_PCT) {
+                       int val = FIXTOINT(css_unit_len2device_px(block->style,
+                                       &content->unit_len_ctx, value, unit));
+
+                       if (min < val) {
+                               min = val;
+                               using_min_border_box = border_box;
+                       }
+               }
+
+               max_type = css_computed_max_width(block->style, &value, &unit);
+               if (max_type == CSS_MAX_WIDTH_SET && unit != CSS_UNIT_PCT) {
+                       int val = FIXTOINT(css_unit_len2device_px(block->style,
+                                       &content->unit_len_ctx, value, unit));
+
+                       if (val >= 0 && max > val) {
+                               max = val;
+                               using_max_border_box = border_box;
                        }
                }
        }
@@ -1060,22 +1079,30 @@ static void layout_minmax_block(
        /* add margins, border, padding to min, max widths */
        /* Note: we don't know available width here so percentage margin
         * and paddings are wrong. */
-       if (bs == CSS_BOX_SIZING_BORDER_BOX && wtype == CSS_WIDTH_SET) {
-               /* Border and padding included in width, so just get margin */
-               calculate_mbp_width(&content->unit_len_ctx,
-                               block->style, LEFT, true, false, false,
-                               &extra_fixed, &extra_frac);
-               calculate_mbp_width(&content->unit_len_ctx,
-                               block->style, RIGHT, true, false, false,
-                               &extra_fixed, &extra_frac);
-       } else {
-               calculate_mbp_width(&content->unit_len_ctx,
-                               block->style, LEFT, true, true, true,
-                               &extra_fixed, &extra_frac);
-               calculate_mbp_width(&content->unit_len_ctx,
-                               block->style, RIGHT, true, true, true,
-                               &extra_fixed, &extra_frac);
+       calculate_mbp_width(&content->unit_len_ctx, block->style, LEFT,
+                       false, true, true, &extra_fixed, &extra_frac);
+       calculate_mbp_width(&content->unit_len_ctx, block->style, RIGHT,
+                       false, true, true, &extra_fixed, &extra_frac);
+
+       if (using_max_border_box) {
+               max -= extra_fixed;
+               max = max(max, 0);
+       }
+
+       if (using_min_border_box) {
+               min -= extra_fixed;
+               min = max(min, 0);
        }
+
+       if (max < min) {
+               min = max;
+       }
+
+       calculate_mbp_width(&content->unit_len_ctx, block->style, LEFT,
+                       true, false, false, &extra_fixed, &extra_frac);
+       calculate_mbp_width(&content->unit_len_ctx, block->style, RIGHT,
+                       true, false, false, &extra_fixed, &extra_frac);
+
        if (extra_fixed < 0)
                extra_fixed = 0;
        if (extra_frac < 0)


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

    layout: minmax table: Change logging level to error

diff --git a/content/handlers/html/layout.c b/content/handlers/html/layout.c
index 9fe93a7..f632bdc 100644
--- a/content/handlers/html/layout.c
+++ b/content/handlers/html/layout.c
@@ -283,7 +283,7 @@ static void layout_minmax_table(struct box *table,
                return;
 
        if (table_calculate_column_types(&content->unit_len_ctx, table) == 
false) {
-               NSLOG(netsurf, WARNING,
+               NSLOG(netsurf, ERROR,
                                "Could not establish table column types.");
                return;
        }


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

    layout: calculate_mbp_width: Preserve percentage values

diff --git a/content/handlers/html/layout_internal.h 
b/content/handlers/html/layout_internal.h
index 0c171ef..39b42b1 100644
--- a/content/handlers/html/layout_internal.h
+++ b/content/handlers/html/layout_internal.h
@@ -181,7 +181,7 @@ static inline void calculate_mbp_width(
                type = margin_funcs[side](style, &value, &unit);
                if (type == CSS_MARGIN_SET) {
                        if (unit == CSS_UNIT_PCT) {
-                               *frac += FIXTOINT(FDIV(value, F_100));
+                               *frac += FIXTOFLT(FDIV(value, F_100));
                        } else {
                                *fixed += FIXTOINT(css_unit_len2device_px(
                                                style, unit_len_ctx,
@@ -205,7 +205,7 @@ static inline void calculate_mbp_width(
        if (padding) {
                padding_funcs[side](style, &value, &unit);
                if (unit == CSS_UNIT_PCT) {
-                       *frac += FIXTOINT(FDIV(value, F_100));
+                       *frac += FIXTOFLT(FDIV(value, F_100));
                } else {
                        *fixed += FIXTOINT(css_unit_len2device_px(
                                        style, unit_len_ctx,


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

    log: Add flex logging catagory

diff --git a/utils/log.c b/utils/log.c
index 68b188e..8cc42a3 100644
--- a/utils/log.c
+++ b/utils/log.c
@@ -99,6 +99,7 @@ NSLOG_DEFINE_CATEGORY(plot, "Rendering system");
 NSLOG_DEFINE_CATEGORY(schedule, "Scheduler");
 NSLOG_DEFINE_CATEGORY(fbtk, "Framebuffer toolkit");
 NSLOG_DEFINE_CATEGORY(layout, "Layout");
+NSLOG_DEFINE_CATEGORY(flex, "Flex");
 NSLOG_DEFINE_CATEGORY(dukky, "Duktape JavaScript Binding");
 NSLOG_DEFINE_CATEGORY(jserrors, "JavaScript error messages");
 
diff --git a/utils/log.h b/utils/log.h
index 02a886c..b7aa833 100644
--- a/utils/log.h
+++ b/utils/log.h
@@ -84,6 +84,7 @@ NSLOG_DECLARE_CATEGORY(plot);
 NSLOG_DECLARE_CATEGORY(schedule);
 NSLOG_DECLARE_CATEGORY(fbtk);
 NSLOG_DECLARE_CATEGORY(layout);
+NSLOG_DECLARE_CATEGORY(flex);
 NSLOG_DECLARE_CATEGORY(dukky);
 NSLOG_DECLARE_CATEGORY(jserrors);
 


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

    html: layout: Improve block container assertions

diff --git a/content/handlers/html/layout.c b/content/handlers/html/layout.c
index 99e9bcf..9fe93a7 100644
--- a/content/handlers/html/layout.c
+++ b/content/handlers/html/layout.c
@@ -4433,9 +4433,9 @@ layout_compute_offsets(const css_unit_ctx *unit_len_ctx,
        css_fixed value = 0;
        css_unit unit = CSS_UNIT_PX;
 
-       assert(containing_block->width != UNKNOWN_WIDTH &&
-                       containing_block->width != AUTO &&
-                       containing_block->height != AUTO);
+       assert(containing_block->width != UNKNOWN_WIDTH);
+       assert(containing_block->width != AUTO);
+       assert(containing_block->height != AUTO);
 
        /* left */
        type = css_computed_left(box->style, &value, &unit);


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

    html: layout: Split out common helpers

diff --git a/content/handlers/html/layout.c b/content/handlers/html/layout.c
index cb5be5d..99e9bcf 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
@@ -1227,375 +1099,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 +1561,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 */
@@ -3977,21 +3475,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 */
diff --git a/content/handlers/html/layout_internal.h 
b/content/handlers/html/layout_internal.h
new file mode 100644
index 0000000..0c171ef
--- /dev/null
+++ b/content/handlers/html/layout_internal.h
@@ -0,0 +1,584 @@
+/*
+ * 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
+ * HTML layout private interface.
+ */
+
+#ifndef NETSURF_HTML_LAYOUT_INTERNAL_H
+#define NETSURF_HTML_LAYOUT_INTERNAL_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)))
+
+/**
+ * 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_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);
+}
+
+/** 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;
+}
+
+/**
+ * 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


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

    css: Fix dump of display: inline-flex

diff --git a/content/handlers/css/dump.c b/content/handlers/css/dump.c
index 1e448e0..4138f93 100644
--- a/content/handlers/css/dump.c
+++ b/content/handlers/css/dump.c
@@ -864,6 +864,12 @@ void nscss_dump_computed_style(FILE *stream, const 
css_computed_style *style)
        case CSS_DISPLAY_NONE:
                fprintf(stream, "display: none ");
                break;
+       case CSS_DISPLAY_FLEX:
+               fprintf(stream, "display: flex ");
+               break;
+       case CSS_DISPLAY_INLINE_FLEX:
+               fprintf(stream, "display: inline-flex ");
+               break;
        default:
                break;
        }


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

    layout: Constify box through layout_find_dimensions()

diff --git a/content/handlers/html/layout.c b/content/handlers/html/layout.c
index 442ced6..cb5be5d 100644
--- a/content/handlers/html/layout.c
+++ b/content/handlers/html/layout.c
@@ -1293,7 +1293,7 @@ static void
 layout_find_dimensions(const css_unit_ctx *unit_len_ctx,
                       int available_width,
                       int viewport_height,
-                      struct box *box,
+                      const struct box *box,
                       const css_computed_style *style,
                       int *width,
                       int *height,


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

    layout: Constify box through layout_handle_box_sizing()

diff --git a/content/handlers/html/layout.c b/content/handlers/html/layout.c
index fb4010d..442ced6 100644
--- a/content/handlers/html/layout.c
+++ b/content/handlers/html/layout.c
@@ -1242,7 +1242,7 @@ static void layout_minmax_block(
  */
 static void layout_handle_box_sizing(
                const css_unit_ctx *unit_len_ctx,
-               struct box *box,
+               const struct box *box,
                int available_width,
                bool setwidth,
                int *dimension)


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

    layout: Add helpers for various box type checks

diff --git a/content/handlers/html/layout.c b/content/handlers/html/layout.c
index 4d55bb5..fb4010d 100644
--- a/content/handlers/html/layout.c
+++ b/content/handlers/html/layout.c
@@ -123,6 +123,50 @@ static inline bool lh__have_border(
        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] = {
        [TOP]    = css_computed_border_top_color,
@@ -595,11 +639,7 @@ layout_minmax_line(struct box *first,
                css_fixed value = 0;
                css_unit unit = CSS_UNIT_PX;
 
-               assert(b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK ||
-                               b->type == BOX_FLOAT_LEFT ||
-                               b->type == BOX_FLOAT_RIGHT ||
-                               b->type == BOX_BR || b->type == BOX_TEXT ||
-                               b->type == BOX_INLINE_END);
+               assert(lh__box_is_inline_content(b));
 
                NSLOG(layout, DEBUG, "%p: min %i, max %i", b, min, max);
 
@@ -608,7 +648,7 @@ layout_minmax_line(struct box *first,
                        break;
                }
 
-               if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT) {
+               if (lh__box_is_float_box(b)) {
                        assert(b->children);
                        if (b->children->type == BOX_BLOCK)
                                layout_minmax_block(b->children, font_func,
@@ -675,8 +715,7 @@ layout_minmax_line(struct box *first,
                        continue;
                }
 
-               if (!b->object && !(b->flags & IFRAME) && !b->gadget &&
-                               !(b->flags & REPLACE_DIM)) {
+               if (lh__box_is_replace(b) == false) {
                        /* inline non-replaced, 10.3.1 and 10.6.1 */
                        bool no_wrap_box;
                        if (!b->text)
@@ -1001,8 +1040,7 @@ static void layout_minmax_block(
        }
 
        /* set whether the minimum width is of any interest for this box */
-       if (((block->parent && (block->parent->type == BOX_FLOAT_LEFT ||
-                       block->parent->type == BOX_FLOAT_RIGHT)) ||
+       if (((block->parent && lh__box_is_float_box(block->parent)) ||
                        block->type == BOX_INLINE_BLOCK) &&
                        wtype != CSS_WIDTH_SET) {
                /* box shrinks to fit; need minimum width */
@@ -3216,20 +3254,14 @@ layout_line(struct box *first,
        for (x = 0, b = first; x <= x1 - x0 && b != 0; b = b->next) {
                int min_width, max_width, min_height, max_height;
 
-               assert(b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK ||
-                               b->type == BOX_FLOAT_LEFT ||
-                               b->type == BOX_FLOAT_RIGHT ||
-                               b->type == BOX_BR || b->type == BOX_TEXT ||
-                               b->type == BOX_INLINE_END);
-
+               assert(lh__box_is_inline_content(b));
 
                NSLOG(layout, DEBUG,  "pass 1: b %p, x %i", b, x);
 
-
                if (b->type == BOX_BR)
                        break;
 
-               if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT)
+               if (lh__box_is_float_box(b))
                        continue;
                if (b->type == BOX_INLINE_BLOCK &&
                                (css_computed_position(b->style) ==
@@ -3295,8 +3327,7 @@ layout_line(struct box *first,
                        continue;
                }
 
-               if (!b->object && !(b->flags & IFRAME) && !b->gadget &&
-                               !(b->flags & REPLACE_DIM)) {
+               if (lh__box_is_replace(b) == false) {
                        /* inline non-replaced, 10.3.1 and 10.6.1 */
                        b->height = line_height(&content->unit_len_ctx,
                                        b->style ? b->style :
@@ -3456,10 +3487,7 @@ layout_line(struct box *first,
                                                CSS_POSITION_FIXED)) {
                        b->x = x + space_after;
 
-               } else if (b->type == BOX_INLINE ||
-                               b->type == BOX_INLINE_BLOCK ||
-                               b->type == BOX_TEXT ||
-                               b->type == BOX_INLINE_END) {
+               } else if (lh__box_is_inline_flow(b)) {
                        assert(b->width != UNKNOWN_WIDTH);
 
                        x_previous = x;
@@ -3798,9 +3826,7 @@ layout_line(struct box *first,
                        d->y = *y;
                        continue;
                } else if ((d->type == BOX_INLINE &&
-                               ((d->object || d->gadget) == false) &&
-                               !(d->flags & IFRAME) &&
-                               !(d->flags & REPLACE_DIM)) ||
+                               lh__box_is_replace(d) == false) ||
                                d->type == BOX_BR ||
                                d->type == BOX_TEXT ||
                                d->type == BOX_INLINE_END) {
@@ -3921,8 +3947,7 @@ static bool layout_inline_container(struct box 
*inline_container, int width,
                                whitespace == CSS_WHITE_SPACE_PRE_WRAP);
                }
 
-               if ((!c->object && !(c->flags & REPLACE_DIM) &&
-                               !(c->flags & IFRAME) &&
+               if ((lh__box_is_object(c) == false &&
                                c->text && (c->length || is_pre)) ||
                                c->type == BOX_BR)
                        has_text_children = true;
@@ -4102,8 +4127,7 @@ layout_block_context(struct box *block,
                lm = rm = 0;
 
                if (box->type == BOX_BLOCK || box->flags & IFRAME) {
-                       if (!box->object && !(box->flags & IFRAME) &&
-                                       !(box->flags & REPLACE_DIM) &&
+                       if (lh__box_is_object(box) == false &&
                                        box->style &&
                                        (overflow_x != CSS_OVERFLOW_VISIBLE ||
                                         overflow_y != CSS_OVERFLOW_VISIBLE)) {


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

    layout: Add helper for checking if a style has a border on a side

diff --git a/content/handlers/html/layout.c b/content/handlers/html/layout.c
index f50a711..4d55bb5 100644
--- a/content/handlers/html/layout.c
+++ b/content/handlers/html/layout.c
@@ -115,6 +115,14 @@ static const css_border_style_func border_style_funcs[4] = 
{
        [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;
+}
+
 /** Array of per-side access functions for computed style border colors. */
 static const css_border_color_func border_color_funcs[4] = {
        [TOP]    = css_computed_border_top_color,
@@ -307,8 +315,7 @@ calculate_mbp_width(const css_unit_ctx *unit_len_ctx,
 
        /* border */
        if (border) {
-               if (border_style_funcs[side](style) !=
-                               CSS_BORDER_STYLE_NONE) {
+               if (lh__have_border(side, style)) {
                        border_width_funcs[side](style, &value, &unit);
 
                        *fixed += FIXTOINT(css_unit_len2device_px(


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

    layout: Drop redundant else block

diff --git a/content/handlers/html/layout.c b/content/handlers/html/layout.c
index c06fdf6..f50a711 100644
--- a/content/handlers/html/layout.c
+++ b/content/handlers/html/layout.c
@@ -5024,8 +5024,6 @@ layout_absolute(struct box *box,
                                containing_block->padding[RIGHT];
                containing_block->height += containing_block->padding[TOP] +
                                containing_block->padding[BOTTOM];
-       } else {
-               /** \todo inline containers */
        }
 
        layout_compute_offsets(&content->unit_len_ctx, box, containing_block,


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

Summary of changes:
 content/handlers/html/layout.c          |   14 +++++++++-----
 content/handlers/html/layout_flex.c     |    2 +-
 content/handlers/html/layout_internal.h |    6 +++---
 3 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/content/handlers/html/layout.c b/content/handlers/html/layout.c
index 431075d..8ba45da 100644
--- a/content/handlers/html/layout.c
+++ b/content/handlers/html/layout.c
@@ -1023,11 +1023,15 @@ static void layout_minmax_block(
                        }
 
                        if (lh__box_is_flex_container(block) &&
-                                       layout_flex__main_is_horizontal(block) 
&&
-                                       block->style != NULL &&
-                                       css_computed_flex_wrap(block->style) ==
-                                       CSS_FLEX_WRAP_NOWRAP) {
-                               min += child->min_width;
+                           lh__flex_main_is_horizontal(block)) {
+                               if (block->style != NULL &&
+                                   css_computed_flex_wrap(block->style) ==
+                                               CSS_FLEX_WRAP_NOWRAP) {
+                                       min += child->min_width;
+                               } else {
+                                       if (min < child->min_width)
+                                               min = child->min_width;
+                               }
                                max += child->max_width;
 
                        } else {
diff --git a/content/handlers/html/layout_flex.c 
b/content/handlers/html/layout_flex.c
index 64797af..54bab70 100644
--- a/content/handlers/html/layout_flex.c
+++ b/content/handlers/html/layout_flex.c
@@ -138,7 +138,7 @@ static struct flex_ctx *layout_flex_ctx__create(
        ctx->unit_len_ctx = &content->unit_len_ctx;
 
        ctx->wrap = css_computed_flex_wrap(flex->style);
-       ctx->horizontal = layout_flex__main_is_horizontal(flex);
+       ctx->horizontal = lh__flex_main_is_horizontal(flex);
 
        return ctx;
 }
diff --git a/content/handlers/html/layout_internal.h 
b/content/handlers/html/layout_internal.h
index 75d6de7..445b430 100644
--- a/content/handlers/html/layout_internal.h
+++ b/content/handlers/html/layout_internal.h
@@ -167,7 +167,7 @@ static inline bool lh__box_is_absolute(const struct box *b)
               css_computed_position(b->style) == CSS_POSITION_FIXED;
 }
 
-static inline bool layout_flex__main_is_horizontal(const struct box *flex)
+static inline bool lh__flex_main_is_horizontal(const struct box *flex)
 {
        const css_computed_style *style = flex->style;
 
@@ -213,7 +213,7 @@ static inline int lh__delta_outer_main(
                const struct box *flex,
                const struct box *b)
 {
-       if (layout_flex__main_is_horizontal(flex)) {
+       if (lh__flex_main_is_horizontal(flex)) {
                return lh__delta_outer_width(b);
        } else {
                return lh__delta_outer_height(b);
@@ -224,7 +224,7 @@ static inline int lh__delta_outer_cross(
                const struct box *flex,
                const struct box *b)
 {
-       if (layout_flex__main_is_horizontal(flex) == false) {
+       if (lh__flex_main_is_horizontal(flex) == false) {
                return lh__delta_outer_width(b);
        } else {
                return lh__delta_outer_height(b);


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

Reply via email to