diff options
author | Michael Drake <tlsa@netsurf-browser.org> | 2022-10-18 17:23:15 +0100 |
---|---|---|
committer | Michael Drake <tlsa@netsurf-browser.org> | 2022-10-23 17:25:52 +0100 |
commit | 28f872e858cf42e66cd198636ec7761e91800033 (patch) | |
tree | b438e38a03a20ba6239285a02d096eba9fc8b6d4 /content | |
parent | e106e50917244fb29777607f49379ea6e46b69d0 (diff) | |
download | netsurf-28f872e858cf42e66cd198636ec7761e91800033.tar.gz netsurf-28f872e858cf42e66cd198636ec7761e91800033.tar.bz2 |
WIP: Flex columns
Diffstat (limited to 'content')
-rw-r--r-- | content/handlers/html/layout_flex.c | 368 |
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) { |