146 ctx = calloc(1,
sizeof(*ctx));
223 struct box *b = item->
box;
240 assert(0 &&
"Bad flex item back type");
246 NSLOG(flex, ERROR,
"box %p: layout failed", b);
265 struct box *b = item->
box;
270 NSLOG(flex, DEEPDEBUG,
"box %p: delta_outer_main: %i",
271 b, delta_outer_main);
273 if (item->
basis == CSS_FLEX_BASIS_SET) {
279 item->
base_size = FIXTOINT(css_unit_len2device_px(
285 }
else if (item->
basis == CSS_FLEX_BASIS_AUTO) {
293 b->
width =
min(
max(content_min_width, available_width),
307 item->
base_size = content_max_width - delta_outer_main;
330 NSLOG(flex, DEEPDEBUG,
"flex-item box: %p: base_size: %i, main_size %i",
345 const struct box *flex,
354 b->float_container = b->parent;
356 b, b->style, &b->width, &b->height,
361 b->margin, b->padding, b->border);
362 b->float_container = NULL;
364 NSLOG(flex, DEEPDEBUG,
"flex-item box: %p: width: %i",
368 item->
basis = css_computed_flex_basis(b->style,
371 css_computed_flex_shrink(b->style, &item->
shrink);
372 css_computed_flex_grow(b->style, &item->
grow);
426 line->first = item_index;
428 NSLOG(flex, DEEPDEBUG,
"flex container %p: available main: %i",
431 while (item_index < ctx->item.count) {
433 struct box *b = item->
box;
440 if (ctx->
wrap == CSS_FLEX_WRAP_NOWRAP ||
441 pos_main + used_main <= ctx->available_main ||
448 used_main += pos_main;
451 line->main_auto_margin_count++;
454 line->main_auto_margin_count++;
465 if (
line->count > 0) {
468 NSLOG(layout, ERROR,
"Failed to fit any flex items");
491 NSLOG(flex, DEEPDEBUG,
"flex-item box: %p: "
492 "Frozen at target_main_size: %i",
510 css_fixed *unfrozen_factor_sum,
511 int initial_free_main,
515 int remaining_free_main = available_main;
516 size_t item_count =
line->first +
line->count;
518 *unfrozen_factor_sum = 0;
520 for (
size_t i =
line->first; i < item_count; i++) {
528 *unfrozen_factor_sum +=
grow ?
533 if (*unfrozen_factor_sum < F_1) {
534 int free_space = FIXTOINT(FMUL(INTTOFIX(initial_free_main),
535 *unfrozen_factor_sum));
537 if (free_space < remaining_free_main) {
538 remaining_free_main = free_space;
542 NSLOG(flex, DEEPDEBUG,
"Remaining free space: %i",
543 remaining_free_main);
545 return remaining_free_main;
560 int total_violation = 0;
561 size_t item_count =
line->first +
line->count;
563 for (
size_t i =
line->first; i < item_count; i++) {
567 NSLOG(flex, DEEPDEBUG,
"item %p: target_main_size: %i",
578 NSLOG(flex, DEEPDEBUG,
"Violation: max_main: %i",
582 if (target_main_size < item->
min_main) {
585 NSLOG(flex, DEEPDEBUG,
"Violation: min_main: %i",
592 NSLOG(flex, DEEPDEBUG,
"Violation: box min_width: %i",
599 NSLOG(flex, DEEPDEBUG,
"Violation: less than 0");
606 NSLOG(flex, DEEPDEBUG,
"Total violation: %i", total_violation);
608 return total_violation;
625 css_fixed unfrozen_factor_sum,
626 int remaining_free_main,
629 size_t item_count =
line->first +
line->count;
632 css_fixed remainder = 0;
633 for (
size_t i =
line->first; i < item_count; i++) {
642 ratio = FDIV(item->
grow, unfrozen_factor_sum);
643 result = FMUL(INTTOFIX(remaining_free_main), ratio) +
648 remainder = FIXFRAC(
result);
651 css_fixed scaled_shrink_factor_sum = 0;
652 css_fixed remainder = 0;
654 for (
size_t i =
line->first; i < item_count; i++) {
656 css_fixed scaled_shrink_factor;
662 scaled_shrink_factor = FMUL(
665 scaled_shrink_factor_sum += scaled_shrink_factor;
668 for (
size_t i =
line->first; i < item_count; i++) {
670 css_fixed scaled_shrink_factor;
676 }
else if (scaled_shrink_factor_sum == 0) {
682 scaled_shrink_factor = FMUL(
685 ratio = FDIV(scaled_shrink_factor,
686 scaled_shrink_factor_sum);
687 result = FMUL(INTTOFIX(abs(remaining_free_main)),
692 remainder = FIXFRAC(
result);
710 size_t item_count =
line->first +
line->count;
712 int initial_free_main;
715 if (available_main ==
AUTO) {
716 available_main = INT_MAX;
719 grow = (
line->main_size < available_main);
720 initial_free_main = available_main;
722 NSLOG(flex, DEEPDEBUG,
"box %p: line %zu: first: %zu, count: %zu",
725 NSLOG(flex, DEEPDEBUG,
"Line main_size: %i, available_main: %i",
726 line->main_size, available_main);
728 for (
size_t i =
line->first; i < item_count; i++) {
733 if (item->
grow == 0 ||
755 while (
line->frozen <
line->count) {
756 css_fixed unfrozen_factor_sum;
757 int remaining_free_main;
760 NSLOG(flex, DEEPDEBUG,
"flex-container: %p: Resolver pass",
765 line, &unfrozen_factor_sum, initial_free_main,
766 available_main,
grow);
769 if (remaining_free_main != 0) {
771 line, unfrozen_factor_sum,
772 remaining_free_main,
grow);
780 for (
size_t i =
line->first; i < item_count; i++) {
787 if (total_violation == 0 ||
812 size_t item_count =
line->first +
line->count;
813 int extra_remainder = 0;
824 if (
line->main_auto_margin_count > 0) {
827 extra_remainder = extra %
line->main_auto_margin_count;
828 extra /=
line->main_auto_margin_count;
832 for (
size_t i =
line->first; i < item_count; i++) {
836 struct box *b = item->
box;
857 extra_pre = extra + extra_remainder;
860 extra_post = extra + extra_remainder;
862 extra_total = extra_pre + extra_post;
864 main_pos += pre_multiplier *
865 (extra_total + box_size_main +
877 main_pos += post_multiplier *
878 (extra_total + box_size_main +
883 if (
line->cross_size < cross_size) {
884 line->cross_size = cross_size;
903 while (pos < ctx->item.count) {
913 NSLOG(flex, DEEPDEBUG,
"flex-container: %p: "
914 "fitted: %zu (total: %zu/%zu)",
946 size_t item_count =
line->first +
line->count;
948 for (
size_t i =
line->first; i < item_count; i++) {
950 struct box *b = item->
box;
951 int cross_free_space;
958 cross_free_space =
line->cross_size + extra - *box_size_cross -
963 case CSS_ALIGN_SELF_STRETCH:
965 *box_size_cross += cross_free_space;
973 case CSS_ALIGN_SELF_FLEX_START:
980 case CSS_ALIGN_SELF_FLEX_END:
982 line->pos + cross_free_space +
987 case CSS_ALIGN_SELF_BASELINE:
988 case CSS_ALIGN_SELF_CENTER:
990 line->pos + cross_free_space / 2 +
1005 bool reversed = ctx->
wrap == CSS_FLEX_WRAP_WRAP_REVERSE;
1006 int line_pos = reversed ? ctx->
cross_size : 0;
1007 int post_multiplier = reversed ? 0 : 1;
1008 int pre_multiplier = reversed ? -1 : 0;
1009 int extra_remainder = 0;
1017 extra_remainder = extra % ctx->
line.
count;
1021 for (
size_t i = 0; i < ctx->
line.
count; i++) {
1024 line_pos += pre_multiplier *
line->cross_size;
1025 line->pos = line_pos;
1026 line_pos += post_multiplier *
line->cross_size +
1027 extra + extra_remainder;
1030 extra + extra_remainder);
1032 if (extra_remainder > 0) {
1049 int max_height, min_height;
1051 bool success =
false;
1058 NSLOG(
flex, DEEPDEBUG,
"box %p: %s, available_width %i, width: %i",
1065 NULL, NULL, &max_height, &min_height,
1078 NSLOG(
flex, DEEPDEBUG,
"box %p: available_main: %i",
1080 NSLOG(
flex, DEEPDEBUG,
"box %p: available_cross: %i",
1100 if (max_height >= 0 &&
flex->
height > max_height) {
1103 if (min_height > 0 &&
flex->
height < min_height) {
1114 success ?
"success" :
"failure",
HTML Box tree inspection interface.
static unsigned box_count_children(const struct box *b)
bool layout_block_context(struct box *block, int viewport_height, html_content *content)
Layout a block formatting context.
static struct gui_layout_table layout_table
Interface to text/html content handler.
static int layout_flex__get_min_max_violations(struct flex_ctx *ctx, struct flex_line_data *line)
Clamp flex item target main size and get min/max violations.
static void layout_flex__distribute_free_main(struct flex_ctx *ctx, struct flex_line_data *line, css_fixed unfrozen_factor_sum, int remaining_free_main, bool grow)
Distribute remaining free space proportional to the flex factors.
static bool layout_flex_item(const struct flex_ctx *ctx, const struct flex_item_data *item, int available_width)
Perform layout on a flex item.
static enum box_side layout_flex__main_start_side(const struct flex_ctx *ctx)
Find box side representing the start of flex container in main direction.
static bool layout_flex__place_line_items_main(struct flex_ctx *ctx, struct flex_line_data *line)
Position items along a line.
static void layout_flex_ctx__populate_item_data(const struct flex_ctx *ctx, const struct box *flex, int available_width)
Fill out all item's data in a flex container.
bool layout_flex(struct box *flex, int available_width, html_content *content)
Layout a flex container.
static enum box_side layout_flex__main_end_side(const struct flex_ctx *ctx)
Find box side representing the end of flex container in main direction.
static bool layout_flex__resolve_line(struct flex_ctx *ctx, struct flex_line_data *line)
Resolve flexible item lengths along a line.
static void layout_flex__place_lines(struct flex_ctx *ctx)
Place the lines and align the items on the line.
static bool layout_flex__collect_items_into_lines(struct flex_ctx *ctx)
Collect items onto lines and place items along the lines.
static struct flex_ctx * layout_flex_ctx__create(html_content *content, const struct box *flex)
Create a flex layout context.
static void layout_flex_ctx__destroy(struct flex_ctx *ctx)
Destroy a flex layout context.
static bool layout_flex__base_and_main_sizes(const struct flex_ctx *ctx, struct flex_item_data *item, int available_width)
Calculate an item's base and target main sizes.
static void layout_flex__item_freeze(struct flex_line_data *line, struct flex_item_data *item)
Freeze an item on a line.
static struct flex_line_data * layout_flex__build_line(struct flex_ctx *ctx, size_t item_index)
Assigns flex items to the line and returns the line.
static bool layout_flex_ctx__ensure_line(struct flex_ctx *ctx)
Ensure context's lines array has a free space.
static void layout_flex__place_line_items_cross(struct flex_ctx *ctx, struct flex_line_data *line, int extra)
Align items on a line.
static int layout_flex__remaining_free_main(struct flex_ctx *ctx, struct flex_line_data *line, css_fixed *unfrozen_factor_sum, int initial_free_main, int available_main, bool grow)
Calculate remaining free space and unfrozen item factor sum.
HTML layout private interface.
static bool lh__flex_direction_reversed(const struct box *flex)
static bool lh__flex_main_is_horizontal(const struct box *flex)
static int lh__delta_outer_main(const struct box *flex, const struct box *b)
static int * lh__box_size_cross_ptr(bool horizontal, struct box *b)
static bool lh__box_is_absolute(const struct box *b)
static int lh__box_size_main(bool horizontal, const struct box *b)
static int lh__box_size_cross(bool horizontal, const struct box *b)
static void layout_find_dimensions(const css_unit_ctx *unit_len_ctx, int available_width, int viewport_height, const struct box *box, const css_computed_style *style, int *width, int *height, int *max_width, int *min_width, int *max_height, int *min_height, int margin[4], int padding[4], struct box_border border[4])
Calculate width, height, and thickness of margins, paddings, and borders.
static enum css_align_self_e lh__box_align_self(const struct box *flex, const struct box *item)
static int lh__delta_outer_width(const struct box *b)
static int lh__delta_outer_cross(const struct box *flex, const struct box *b)
static int lh__non_auto_margin(const struct box *b, enum box_side side)
static bool lh__box_size_cross_is_auto(bool horizontal, struct box *b)
#define NSLOG(catname, level, logmsg, args...)
Private data for text/html content.
Interface to utility string handling.
int width
border-width (pixels)
struct box_border border[4]
Border: TOP, RIGHT, BOTTOM, LEFT.
int min_width
Width of box taking all line breaks (including margins etc).
int width
Width of content box (excluding padding etc.).
struct box * parent
Parent box, or NULL.
struct box * children
First child box, or NULL.
int height
Height of content box (excluding padding etc.).
struct box * float_container
If box is a float, points to box's containing block.
int margin[4]
Margin: TOP, RIGHT, BOTTOM, LEFT.
int max_width
Width that would be taken with no line breaks.
struct box * next
Next sibling box, or NULL.
box_type type
Type of box.
css_computed_style * style
Style for this box.
int padding[4]
Padding: TOP, RIGHT, BOTTOM, LEFT.
int x
Coordinate of left padding edge relative to parent box, or relative to ancestor that contains this bo...
int y
Coordinate of top padding edge, relative as for x.
Content which corresponds to a single URL.
struct flex_item_data * data
struct flex_line_data * data
struct flex_ctx::flex_lines line
struct flex_ctx::flex_items item
const css_unit_ctx * unit_len_ctx
enum css_flex_wrap_e wrap
enum css_flex_basis_e basis
int main_auto_margin_count
Data specific to CONTENT_HTML.
Interface to a number of general purpose functionality.
#define fallthrough
switch fall through
static nserror line(const struct redraw_context *ctx, const plot_style_t *style, const struct rect *line)
Plots a line.