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