summaryrefslogtreecommitdiff
path: root/content/handlers/html/layout.c
diff options
context:
space:
mode:
Diffstat (limited to 'content/handlers/html/layout.c')
-rw-r--r--content/handlers/html/layout.c135
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)) ||