summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Drake <tlsa@netsurf-browser.org>2022-10-18 17:23:15 +0100
committerMichael Drake <tlsa@netsurf-browser.org>2022-10-23 17:25:52 +0100
commit28f872e858cf42e66cd198636ec7761e91800033 (patch)
treeb438e38a03a20ba6239285a02d096eba9fc8b6d4
parente106e50917244fb29777607f49379ea6e46b69d0 (diff)
downloadnetsurf-28f872e858cf42e66cd198636ec7761e91800033.tar.gz
netsurf-28f872e858cf42e66cd198636ec7761e91800033.tar.bz2
WIP: Flex columns
-rw-r--r--content/handlers/html/layout_flex.c368
1 files changed, 238 insertions, 130 deletions
diff --git a/content/handlers/html/layout_flex.c b/content/handlers/html/layout_flex.c
index 2c2c7adba..949953626 100644
--- a/content/handlers/html/layout_flex.c
+++ b/content/handlers/html/layout_flex.c
@@ -51,10 +51,10 @@ struct flex_item_data {
css_fixed shrink;
css_fixed grow;
- int min_width;
- int max_width;
- int min_height;
- int max_height;
+ int min_main;
+ int max_main;
+ int min_cross;
+ int max_cross;
int target_main_size;
int base_size;
@@ -80,8 +80,10 @@ struct flex_ctx {
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 {
@@ -134,18 +136,54 @@ static struct flex_ctx *layout_flex_ctx__create(
ctx->flex = flex;
ctx->content = content;
ctx->unit_len_ctx = &content->unit_len_ctx;
+
ctx->wrap = css_computed_flex_wrap(flex->style);
+ ctx->horizontal = layout_flex__main_is_horizontal(flex);
return ctx;
}
-static inline void layout_flex__base_and_main_sizes(
+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 delta_outer_width = lh__delta_outer_width(b);
+ int delta_outer_main = lh__delta_outer_main(b);
if (item->basis == CSS_FLEX_BASIS_SET) {
if (item->basis_unit == CSS_UNIT_PCT) {
@@ -160,37 +198,59 @@ static inline void layout_flex__base_and_main_sizes(
}
} else if (item->basis == CSS_FLEX_BASIS_AUTO) {
- item->base_size = b->width;
+ 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, b->max_width);
+ b->width -= lh__delta_outer_cross(b);
+ }
+
+ if (!layout_flex_item(ctx, item, available_width)) {
+ NSLOG(flex, WARNING, "box %p: layout failed", b);
+ return false;
+ }
+ }
+
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;
+ if (ctx->horizontal == false) {
+ item->base_size = b->height;
+ } else {
+ item->base_size = b->max_width;
+ }
}
- item->base_size += delta_outer_width;
+ item->base_size = min(item->base_size + delta_outer_main,
+ available_width);
- item->base_size = max(min(item->base_size, available_width),
- b->min_width + delta_outer_width);
+ if (ctx->horizontal) {
+ item->base_size = max(item->base_size,
+ b->min_width + delta_outer_main);
+ }
item->target_main_size = item->base_size;
item->main_size = item->base_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->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_width + delta_outer_width) {
- item->main_size = item->min_width + delta_outer_width;
+ 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(
@@ -199,6 +259,7 @@ static void layout_flex_ctx__populate_item_data(
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++];
@@ -206,8 +267,10 @@ static void layout_flex_ctx__populate_item_data(
b->float_container = b->parent;
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,
+ 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;
@@ -244,11 +307,12 @@ static bool layout_flex_ctx__ensure_line(struct flex_ctx *ctx)
return true;
}
-static size_t layout_flex__build_line(struct flex_ctx *ctx,
+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 used_width = 0;
+ int available_main;
+ int used_main = 0;
if (!layout_flex_ctx__ensure_line(ctx)) {
return 0;
@@ -257,21 +321,32 @@ static size_t layout_flex__build_line(struct flex_ctx *ctx,
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 width = b->max_width;
+ int main;
- width += lh__delta_outer_width(b);
+ main = ctx->horizontal ? b->max_width : b->height;
+ main += lh__delta_outer_main(b);
if (ctx->wrap == CSS_FLEX_WRAP_NOWRAP ||
lh__box_is_absolute(item->box) ||
- width == 0 ||
- width + used_width <= available_width ||
+ main == 0 ||
+ main + used_main <= available_main ||
+ available_main == AUTO ||
line->count == 0) {
line->main_size += item->main_size;
item->line = ctx->line.count;
- used_width += width;
+ used_main += main;
line->count++;
item_index++;
} else {
@@ -281,37 +356,11 @@ static size_t layout_flex__build_line(struct flex_ctx *ctx,
if (line->count > 0) {
ctx->line.count++;
+ } else {
+ NSLOG(layout, ERROR, "Failed to fit any flex items");
}
- 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;
- NSLOG(flex, WARNING, "flex-container: %p: "
- "fitted: %zu (total: %zu/%zu)",
- ctx->flex, fitted,
- pos, ctx->item.count);
- } while (fitted != 0 && pos != ctx->item.count);
-
- if (fitted == 0) {
- NSLOG(layout, ERROR, "Failed to fit any flex items");
- return false;
- }
- }
-
- return true;
+ return line;
}
static inline void layout_flex__item_freeze(
@@ -320,7 +369,8 @@ static inline void layout_flex__item_freeze(
{
item->freeze = true;
line->frozen++;
- NSLOG(flex, WARNING, "flex-item box: %p: Frozen at width: %i",
+
+ NSLOG(flex, WARNING, "flex-item box: %p: Frozen at target_main_size: %i",
item->box, item->target_main_size);
}
@@ -383,19 +433,19 @@ static inline int layout_flex__get_min_max_violations(
continue;
}
- if (item->max_width > 0 &&
- target_main_size > item->max_width) {
- target_main_size = item->max_width;
+ 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_width: %i",
- item->max_width);
+ NSLOG(flex, WARNING, "Violation: max_main: %i",
+ item->max_main);
}
- if (target_main_size < item->min_width) {
- target_main_size = item->min_width;
+ if (target_main_size < item->min_main) {
+ target_main_size = item->min_main;
item->min_violation = true;
- NSLOG(flex, WARNING, "Violation: min_width: %i",
- item->min_width);
+ NSLOG(flex, WARNING, "Violation: min_main: %i",
+ item->min_main);
}
if (target_main_size < item->box->min_width) {
@@ -489,18 +539,92 @@ static inline void layout_flex__distribute_free_space(
}
}
+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 = 0;
+
+ 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;
+ int height;
+
+ b->width = item->target_main_size - lh__delta_outer_width(b);
+
+ success = layout_flex_item(ctx, item, available_width);
+ if (!success) {
+ NSLOG(flex, WARNING, "box %p: layout failed", b);
+ return false;
+ }
+
+ height = b->height + lh__delta_outer_height(b);
+
+ b->y = ctx->cross_size +
+ b->margin[TOP] +
+ b->border[TOP].width +
+ b->padding[TOP];
+ if (line->cross_size < height) {
+ line->cross_size = height;
+ }
+
+ b->x = x + b->margin[LEFT] +
+ b->border[LEFT].width +
+ b->padding[LEFT];
+ 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 = 0;
+
+ for (size_t i = line->first; i < item_count; i++) {
+ struct flex_item_data *item = &ctx->item.data[i];
+ struct box *b = item->box;
+ int width;
+
+ width = b->width + lh__delta_outer_width(b);
+
+ b->x = ctx->cross_size +
+ b->margin[LEFT] +
+ b->border[LEFT].width +
+ b->padding[LEFT];
+ if (line->cross_size < width) {
+ line->cross_size = width;
+ }
+
+ b->y = y + b->margin[TOP] +
+ b->border[TOP].width +
+ b->padding[TOP];
+ 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,
- int available_width,
- size_t line_index)
+ struct flex_line_data *line,
+ int available_width)
{
- 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;
+ int initial_free_space = available_width;
+ 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_width: %i",
line->main_size, available_width);
@@ -567,55 +691,52 @@ static bool layout_flex__resolve_line(
}
}
- for (size_t i = line->first; i < line->first + line->count; i++) {
- struct flex_item_data *item = &ctx->item.data[i];
- struct box *b = item->box;
- bool success = false;
- int height;
+ 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;
+ }
+ }
- b->width = item->target_main_size - lh__delta_outer_width(b);
+ return true;
+}
- 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;
- }
- if (!success) {
- NSLOG(flex, WARNING, "box %p: layout failed", b);
+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;
}
- height = b->height + lh__delta_outer_height(b);
+ pos += line->count;
- b->y = ctx->cross_size +
- b->margin[TOP] +
- b->border[TOP].width +
- b->padding[TOP];
- if (line->cross_size < height) {
- line->cross_size = height;
+ 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;
}
- b->x = x + b->margin[LEFT] +
- b->border[LEFT].width +
- b->padding[LEFT];
- x += b->width + lh__delta_outer_width(b);
+ ctx->cross_size += line->cross_size;
+ if (ctx->main_size < line->main_size) {
+ ctx->main_size = line->main_size;
+ }
}
return true;
@@ -636,14 +757,13 @@ bool layout_flex(struct box *flex, int available_width,
struct flex_ctx *ctx;
bool success = false;
- NSLOG(flex, WARNING, "box %p", flex);
-
ctx = layout_flex_ctx__create(content, flex);
if (ctx == NULL) {
return false;
}
- layout_flex_ctx__populate_item_data(ctx, flex, available_width);
+ NSLOG(flex, WARNING, "box %p (%s)", flex,
+ ctx->horizontal ? "horizontal" : "vertical");
layout_find_dimensions(
ctx->unit_len_ctx, available_width, -1,
@@ -671,6 +791,8 @@ bool layout_flex(struct box *flex, int available_width,
available_width -= lh__delta_outer_width(flex);
+ 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);
@@ -678,24 +800,10 @@ bool layout_flex(struct box *flex, int available_width,
goto cleanup;
}
- /* Layout children */
- for (size_t i = 0; i < ctx->line.count; i++) {
- NSLOG(flex, WARNING, "box %p: "
- "line %zu: first: %zu, count: %zu",
- flex, 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->cross_size += ctx->line.data[i].cross_size;
- }
-
if (flex->height == AUTO) {
- flex->height = ctx->cross_size;
+ flex->height = ctx->horizontal ?
+ ctx->cross_size :
+ ctx->main_size;
}
if (max_width >= 0 && flex->width > max_width) {