html: layout: flex: Implement align-items and align-self

This commit is contained in:
Michael Drake 2022-11-02 13:34:35 +00:00 committed by Michael Drake
parent 47482bd539
commit 45b68a3b50
2 changed files with 125 additions and 34 deletions

View File

@ -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);
layout_flex__place_line_items_cross(ctx, line,
extra + extra_remainder);
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;
}

View File

@ -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.
*