summaryrefslogtreecommitdiff
path: root/content
diff options
context:
space:
mode:
authorMichael Drake <tlsa@netsurf-browser.org>2022-11-02 13:34:35 +0000
committerMichael Drake <mdrake.unique@gmail.com>2022-11-02 20:16:41 +0000
commit45b68a3b509cb8a579c2dfff05c714f91b339cb4 (patch)
treecf9971118e277126f86657a5ac8509a8356af7d4 /content
parent47482bd5391e15ab12293133feea9616b235b8b9 (diff)
downloadnetsurf-45b68a3b509cb8a579c2dfff05c714f91b339cb4.tar.gz
netsurf-45b68a3b509cb8a579c2dfff05c714f91b339cb4.tar.bz2
html: layout: flex: Implement align-items and align-self
Diffstat (limited to 'content')
-rw-r--r--content/handlers/html/layout_flex.c130
-rw-r--r--content/handlers/html/layout_internal.h29
2 files changed, 125 insertions, 34 deletions
diff --git a/content/handlers/html/layout_flex.c b/content/handlers/html/layout_flex.c
index f0dfca833..d64004a6a 100644
--- a/content/handlers/html/layout_flex.c
+++ b/content/handlers/html/layout_flex.c
@@ -85,6 +85,9 @@ struct flex_ctx {
int main_size;
int cross_size;
+ int available_main;
+ int available_cross;
+
bool horizontal;
enum css_flex_wrap_e wrap;
@@ -216,7 +219,8 @@ static inline bool layout_flex__base_and_main_sizes(
if (ctx->horizontal == false) {
if (b->width == AUTO) {
- b->width = min(available_width, content_max_width);
+ b->width = min(max(content_min_width, available_width),
+ content_max_width);
b->width -= lh__delta_outer_width(b);
}
@@ -316,10 +320,9 @@ static bool layout_flex_ctx__ensure_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)
+ size_t item_index)
{
struct flex_line_data *line;
- int available_main;
int used_main = 0;
if (!layout_flex_ctx__ensure_line(ctx)) {
@@ -329,14 +332,8 @@ static struct flex_line_data *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);
+ ctx->flex, ctx->available_main);
while (item_index < ctx->item.count) {
struct flex_item_data *item = &ctx->item.data[item_index];
@@ -348,9 +345,9 @@ static struct flex_line_data *layout_flex__build_line(struct flex_ctx *ctx,
b->height + lh__delta_outer_main(ctx->flex, b);
if (ctx->wrap == CSS_FLEX_WRAP_NOWRAP ||
- pos_main + used_main <= available_main ||
+ pos_main + used_main <= ctx->available_main ||
lh__box_is_absolute(item->box) ||
- available_main == AUTO ||
+ ctx->available_main == AUTO ||
line->count == 0 ||
pos_main == 0) {
if (lh__box_is_absolute(item->box) == false) {
@@ -601,20 +598,15 @@ static bool layout_flex__place_line_items_main(
/** 9.7. Resolving Flexible Lengths */
static bool layout_flex__resolve_line(
struct flex_ctx *ctx,
- struct flex_line_data *line,
- int available_width)
+ struct flex_line_data *line)
{
size_t item_count = line->first + line->count;
- int available_main = available_width;
+ int available_main = ctx->available_main;
int initial_free_main;
bool grow;
- available_main = available_width;
- if (ctx->horizontal == false) {
- available_main = ctx->flex->height;
- if (available_main == AUTO) {
- available_main = INT_MAX;
- }
+ if (available_main == AUTO) {
+ available_main = INT_MAX;
}
grow = (line->main_size < available_main);
@@ -697,15 +689,14 @@ static bool layout_flex__resolve_line(
}
static bool layout_flex__collect_items_into_lines(
- struct flex_ctx *ctx,
- int available_width)
+ struct flex_ctx *ctx)
{
size_t pos = 0;
while (pos < ctx->item.count) {
struct flex_line_data *line;
- line = layout_flex__build_line(ctx, pos, available_width);
+ line = layout_flex__build_line(ctx, pos);
if (line == NULL) {
return false;
}
@@ -717,7 +708,7 @@ static bool layout_flex__collect_items_into_lines(
ctx->flex, line->count,
pos, ctx->item.count);
- if (!layout_flex__resolve_line(ctx, line, available_width)) {
+ if (!layout_flex__resolve_line(ctx, line)) {
return false;
}
@@ -731,7 +722,7 @@ static bool layout_flex__collect_items_into_lines(
}
static void layout_flex__place_line_items_cross(struct flex_ctx *ctx,
- struct flex_line_data *line)
+ struct flex_line_data *line, int extra)
{
enum box_side cross_start = ctx->horizontal ? TOP : LEFT;
size_t item_count = line->first + line->count;
@@ -739,12 +730,52 @@ static void layout_flex__place_line_items_cross(struct flex_ctx *ctx,
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 cross_free_space;
+ int *box_size_cross;
int *box_pos_cross;
box_pos_cross = ctx->horizontal ? &b->y : &b->x;
- *box_pos_cross = ctx->flex->padding[cross_start] + line->pos +
- lh__non_auto_margin(b, cross_start) +
- b->border[cross_start].width;
+ box_size_cross = lh__box_size_cross(ctx->horizontal, b);
+
+ cross_free_space = line->cross_size + extra - *box_size_cross -
+ lh__delta_outer_cross(ctx->flex, b);
+
+ switch (lh__box_align_self(ctx->flex, b)) {
+ default:
+ /* Fall through. */
+ case CSS_ALIGN_SELF_STRETCH:
+ if (lh__box_size_cross_is_auto(ctx->horizontal, b)) {
+ *box_size_cross += cross_free_space;
+
+ /* Relayout children for stretch. */
+ if (!layout_flex_item(ctx, item, b->width)) {
+ return;
+ }
+ }
+ /* Fall through. */
+ case CSS_ALIGN_SELF_FLEX_START:
+ *box_pos_cross = ctx->flex->padding[cross_start] +
+ line->pos +
+ lh__non_auto_margin(b, cross_start) +
+ b->border[cross_start].width;
+ break;
+
+ case CSS_ALIGN_SELF_FLEX_END:
+ *box_pos_cross = ctx->flex->padding[cross_start] +
+ line->pos + cross_free_space +
+ lh__non_auto_margin(b, cross_start) +
+ b->border[cross_start].width;
+ break;
+
+ case CSS_ALIGN_SELF_BASELINE:
+ /* Fall through. */
+ case CSS_ALIGN_SELF_CENTER:
+ *box_pos_cross = ctx->flex->padding[cross_start] +
+ line->pos + cross_free_space / 2 +
+ lh__non_auto_margin(b, cross_start) +
+ b->border[cross_start].width;
+ break;
+ }
}
}
@@ -754,15 +785,32 @@ static void layout_flex__place_lines(struct flex_ctx *ctx)
int line_pos = reversed ? ctx->cross_size : 0;
int post_multiplier = reversed ? 0 : 1;
int pre_multiplier = reversed ? -1 : 0;
+ int extra_remainder = 0;
+ int extra = 0;
+
+ if (ctx->available_cross != AUTO &&
+ ctx->available_cross != ctx->cross_size &&
+ ctx->line.count > 0) {
+ extra = ctx->available_cross - ctx->cross_size;
+
+ extra_remainder = extra % ctx->line.count;
+ extra /= ctx->line.count;
+ }
for (size_t i = 0; i < ctx->line.count; i++) {
struct flex_line_data *line = &ctx->line.data[i];
line_pos += pre_multiplier * line->cross_size;
line->pos = line_pos;
- line_pos += post_multiplier * line->cross_size;
+ line_pos += post_multiplier * line->cross_size +
+ extra + extra_remainder;
+
+ layout_flex__place_line_items_cross(ctx, line,
+ extra + extra_remainder);
- layout_flex__place_line_items_cross(ctx, line);
+ if (extra_remainder > 0) {
+ extra_remainder--;
+ }
}
}
@@ -798,10 +846,23 @@ bool layout_flex(struct box *flex, int available_width,
available_width = min(available_width, flex->width);
+ if (ctx->horizontal) {
+ ctx->available_main = available_width;
+ ctx->available_cross = ctx->flex->height;
+ } else {
+ ctx->available_main = ctx->flex->height;
+ ctx->available_cross = available_width;
+ }
+
+ NSLOG(flex, WARNING, "box %p: available_main: %i",
+ flex, ctx->available_main);
+ NSLOG(flex, WARNING, "box %p: available_cross: %i",
+ flex, ctx->available_cross);
+
layout_flex_ctx__populate_item_data(ctx, flex, available_width);
/* Place items onto lines. */
- success = layout_flex__collect_items_into_lines(ctx, available_width);
+ success = layout_flex__collect_items_into_lines(ctx);
if (!success) {
goto cleanup;
}
@@ -828,7 +889,8 @@ bool layout_flex(struct box *flex, int available_width,
cleanup:
layout_flex_ctx__destroy(ctx);
- NSLOG(flex, WARNING, "box %p: %s", flex,
- success ? "success" : "failure");
+ NSLOG(flex, WARNING, "box %p: %s: w: %i, h: %i", flex,
+ success ? "success" : "failure",
+ flex->width, flex->height);
return success;
}
diff --git a/content/handlers/html/layout_internal.h b/content/handlers/html/layout_internal.h
index 8751700b5..974f49348 100644
--- a/content/handlers/html/layout_internal.h
+++ b/content/handlers/html/layout_internal.h
@@ -245,6 +245,35 @@ static inline int *lh__box_size_cross(
return horizontal ? &b->height : &b->width;
}
+static inline bool lh__box_size_cross_is_auto(
+ bool horizontal,
+ struct box *b)
+{
+ css_fixed length;
+ css_unit unit;
+
+ if (horizontal) {
+ return css_computed_height(b->style,
+ &length, &unit) == CSS_HEIGHT_AUTO;
+ } else {
+ return css_computed_width(b->style,
+ &length, &unit) == CSS_WIDTH_AUTO;
+ }
+}
+
+static inline enum css_align_self_e lh__box_align_self(
+ const struct box *flex,
+ const struct box *item)
+{
+ enum css_align_self_e align_self = css_computed_align_self(item->style);
+
+ if (align_self == CSS_ALIGN_SELF_AUTO) {
+ align_self = css_computed_align_items(flex->style);
+ }
+
+ return align_self;
+}
+
/**
* Determine width of margin, borders, and padding on one side of a box.
*