diff options
Diffstat (limited to 'content/handlers/html/layout.c')
-rw-r--r-- | content/handlers/html/layout.c | 135 |
1 files changed, 126 insertions, 9 deletions
diff --git a/content/handlers/html/layout.c b/content/handlers/html/layout.c index ab8c83afe..0beee0361 100644 --- a/content/handlers/html/layout.c +++ b/content/handlers/html/layout.c @@ -653,7 +653,8 @@ 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; @@ -1011,7 +1012,9 @@ static void layout_minmax_block( bool child_has_height = false; assert(block->type == BOX_BLOCK || + block->type == BOX_FLEX || block->type == BOX_INLINE_BLOCK || + block->type == BOX_INLINE_FLEX || block->type == BOX_TABLE_CELL); /* check if the widths have already been calculated */ @@ -1026,7 +1029,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; @@ -1112,6 +1116,11 @@ static void layout_minmax_block( child_has_height = true; child->flags |= MAKE_HEIGHT; break; + case BOX_FLEX: + layout_minmax_block(child, font_func, content); + child_has_height = true; + child->flags |= MAKE_HEIGHT; + break; default: assert(0); } @@ -2034,6 +2043,101 @@ static void layout_move_children(struct box *box, int x, int y) } } +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; + } +} + +/** + * 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 + */ +static bool layout_flex(struct box *flex, int available_width, + html_content *content) +{ + bool main_is_horizontal = layout_flex__main_is_horizontal(flex); + int max_width, min_width, max_height, min_height; + const nscss_len_ctx *len_ctx = &content->len_ctx; + struct box_border *border = flex->border; + int *padding = flex->padding; + int *margin = flex->margin; + int *len_main, *len_cross; + unsigned n_children; + struct flex_item_data { + int main_size; + } *flex_item; + + assert(flex->width != UNKNOWN_WIDTH); + assert(flex->width != AUTO); + + layout_find_dimensions(len_ctx, available_width, -1, flex, flex->style, + &flex->width, &flex->height, &max_width, &min_width, + &max_height, &min_height, margin, padding, border); + + if (flex->width == AUTO) { + int w = available_width; + int fixed = 0; + float frac = 0; + + calculate_mbp_width(len_ctx, flex->style, LEFT, + false, true, true, &fixed, &frac); + calculate_mbp_width(len_ctx, flex->style, RIGHT, + false, true, true, &fixed, &frac); + + w -= frac * available_width + fixed; + flex->width = w > 0 ? w : 0; + } + + 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; + } + } + + if (main_is_horizontal) { + len_main = &flex->width; + len_cross = &flex->height; + } else { + len_main = &flex->height; + len_cross = &flex->width; + } + + flex_item = calloc(box_count_children(flex), sizeof(*flex_item)); + if (flex_item == false) { + return false; + } + + + free(flex_item); + return true; +} + /** * Layout a table. @@ -4039,7 +4143,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 @@ -4123,7 +4229,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; @@ -4156,11 +4262,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. */ @@ -4176,6 +4292,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)) || |