File: | content/handlers/html/layout_internal.h |
Warning: | line 163, column 31 Access to field 'style' results in a dereference of a null pointer (loaded from variable 'b') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | ||||
2 | * Copyright 2022 Michael Drake <tlsa@netsurf-browser.org> | ||||
3 | * | ||||
4 | * This file is part of NetSurf, http://www.netsurf-browser.org/ | ||||
5 | * | ||||
6 | * NetSurf is free software; you can redistribute it and/or modify | ||||
7 | * it under the terms of the GNU General Public License as published by | ||||
8 | * the Free Software Foundation; version 2 of the License. | ||||
9 | * | ||||
10 | * NetSurf is distributed in the hope that it will be useful, | ||||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
13 | * GNU General Public License for more details. | ||||
14 | * | ||||
15 | * You should have received a copy of the GNU General Public License | ||||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
17 | */ | ||||
18 | |||||
19 | /** | ||||
20 | * \file | ||||
21 | * HTML layout implementation: display: flex. | ||||
22 | * | ||||
23 | * Layout is carried out in two stages: | ||||
24 | * | ||||
25 | * 1. + calculation of minimum / maximum box widths, and | ||||
26 | * + determination of whether block level boxes will have >zero height | ||||
27 | * | ||||
28 | * 2. + layout (position and dimensions) | ||||
29 | * | ||||
30 | * In most cases the functions for the two stages are a corresponding pair | ||||
31 | * layout_minmax_X() and layout_X(). | ||||
32 | */ | ||||
33 | |||||
34 | #include <string.h> | ||||
35 | |||||
36 | #include "utils/log.h" | ||||
37 | #include "utils/utils.h" | ||||
38 | |||||
39 | #include "html/box.h" | ||||
40 | #include "html/html.h" | ||||
41 | #include "html/private.h" | ||||
42 | #include "html/box_inspect.h" | ||||
43 | #include "html/layout_internal.h" | ||||
44 | |||||
45 | /** | ||||
46 | * Flex item data | ||||
47 | */ | ||||
48 | struct flex_item_data { | ||||
49 | enum css_flex_basis_e basis; | ||||
50 | css_fixed basis_length; | ||||
51 | css_unit basis_unit; | ||||
52 | struct box *box; | ||||
53 | |||||
54 | css_fixed shrink; | ||||
55 | css_fixed grow; | ||||
56 | |||||
57 | int min_main; | ||||
58 | int max_main; | ||||
59 | int min_cross; | ||||
60 | int max_cross; | ||||
61 | |||||
62 | int target_main_size; | ||||
63 | int base_size; | ||||
64 | int main_size; | ||||
65 | size_t line; | ||||
66 | |||||
67 | bool_Bool freeze; | ||||
68 | bool_Bool min_violation; | ||||
69 | bool_Bool max_violation; | ||||
70 | }; | ||||
71 | |||||
72 | /** | ||||
73 | * Flex line data | ||||
74 | */ | ||||
75 | struct flex_line_data { | ||||
76 | int main_size; | ||||
77 | int cross_size; | ||||
78 | |||||
79 | int used_main_size; | ||||
80 | int main_auto_margin_count; | ||||
81 | |||||
82 | int pos; | ||||
83 | |||||
84 | size_t first; | ||||
85 | size_t count; | ||||
86 | size_t frozen; | ||||
87 | }; | ||||
88 | |||||
89 | /** | ||||
90 | * Flex layout context | ||||
91 | */ | ||||
92 | struct flex_ctx { | ||||
93 | html_content *content; | ||||
94 | const struct box *flex; | ||||
95 | const css_unit_ctx *unit_len_ctx; | ||||
96 | |||||
97 | int main_size; | ||||
98 | int cross_size; | ||||
99 | |||||
100 | int available_main; | ||||
101 | int available_cross; | ||||
102 | |||||
103 | bool_Bool horizontal; | ||||
104 | bool_Bool main_reversed; | ||||
105 | enum css_flex_wrap_e wrap; | ||||
106 | |||||
107 | struct flex_items { | ||||
108 | size_t count; | ||||
109 | struct flex_item_data *data; | ||||
110 | } item; | ||||
111 | |||||
112 | struct flex_lines { | ||||
113 | size_t count; | ||||
114 | size_t alloc; | ||||
115 | struct flex_line_data *data; | ||||
116 | } line; | ||||
117 | }; | ||||
118 | |||||
119 | /** | ||||
120 | * Destroy a flex layout context | ||||
121 | * | ||||
122 | * \param[in] ctx Flex layout context | ||||
123 | */ | ||||
124 | static void layout_flex_ctx__destroy(struct flex_ctx *ctx) | ||||
125 | { | ||||
126 | if (ctx != NULL((void*)0)) { | ||||
127 | free(ctx->item.data); | ||||
128 | free(ctx->line.data); | ||||
129 | free(ctx); | ||||
130 | } | ||||
131 | } | ||||
132 | |||||
133 | /** | ||||
134 | * Create a flex layout context | ||||
135 | * | ||||
136 | * \param[in] content HTML content containing flex box | ||||
137 | * \param[in] flex Box to create layout context for | ||||
138 | * \return flex layout context or NULL on error | ||||
139 | */ | ||||
140 | static struct flex_ctx *layout_flex_ctx__create( | ||||
141 | html_content *content, | ||||
142 | const struct box *flex) | ||||
143 | { | ||||
144 | struct flex_ctx *ctx; | ||||
145 | |||||
146 | ctx = calloc(1, sizeof(*ctx)); | ||||
147 | if (ctx == NULL((void*)0)) { | ||||
148 | return NULL((void*)0); | ||||
149 | } | ||||
150 | ctx->line.alloc = 1; | ||||
151 | |||||
152 | ctx->item.count = box_count_children(flex); | ||||
153 | ctx->item.data = calloc(ctx->item.count, sizeof(*ctx->item.data)); | ||||
154 | if (ctx->item.data == NULL((void*)0)) { | ||||
155 | layout_flex_ctx__destroy(ctx); | ||||
156 | return NULL((void*)0); | ||||
157 | } | ||||
158 | |||||
159 | ctx->line.alloc = 1; | ||||
160 | ctx->line.data = calloc(ctx->line.alloc, sizeof(*ctx->line.data)); | ||||
161 | if (ctx->line.data == NULL((void*)0)) { | ||||
162 | layout_flex_ctx__destroy(ctx); | ||||
163 | return NULL((void*)0); | ||||
164 | } | ||||
165 | |||||
166 | ctx->flex = flex; | ||||
167 | ctx->content = content; | ||||
168 | ctx->unit_len_ctx = &content->unit_len_ctx; | ||||
169 | |||||
170 | ctx->wrap = css_computed_flex_wrap(flex->style); | ||||
171 | ctx->horizontal = lh__flex_main_is_horizontal(flex); | ||||
172 | ctx->main_reversed = lh__flex_direction_reversed(flex); | ||||
173 | |||||
174 | return ctx; | ||||
175 | } | ||||
176 | |||||
177 | /** | ||||
178 | * Find box side representing the start of flex container in main direction. | ||||
179 | * | ||||
180 | * \param[in] ctx Flex layout context. | ||||
181 | * \return the start side. | ||||
182 | */ | ||||
183 | static enum box_side layout_flex__main_start_side( | ||||
184 | const struct flex_ctx *ctx) | ||||
185 | { | ||||
186 | if (ctx->horizontal) { | ||||
187 | return (ctx->main_reversed) ? RIGHT : LEFT; | ||||
188 | } else { | ||||
189 | return (ctx->main_reversed) ? BOTTOM : TOP; | ||||
190 | } | ||||
191 | } | ||||
192 | |||||
193 | /** | ||||
194 | * Find box side representing the end of flex container in main direction. | ||||
195 | * | ||||
196 | * \param[in] ctx Flex layout context. | ||||
197 | * \return the end side. | ||||
198 | */ | ||||
199 | static enum box_side layout_flex__main_end_side( | ||||
200 | const struct flex_ctx *ctx) | ||||
201 | { | ||||
202 | if (ctx->horizontal) { | ||||
203 | return (ctx->main_reversed) ? LEFT : RIGHT; | ||||
204 | } else { | ||||
205 | return (ctx->main_reversed) ? TOP : BOTTOM; | ||||
206 | } | ||||
207 | } | ||||
208 | |||||
209 | /** | ||||
210 | * Perform layout on a flex item | ||||
211 | * | ||||
212 | * \param[in] ctx Flex layout context | ||||
213 | * \param[in] item Item to lay out | ||||
214 | * \param[in] available_width Available width for item in pixels | ||||
215 | * \return true on success false on failure | ||||
216 | */ | ||||
217 | static bool_Bool layout_flex_item( | ||||
218 | const struct flex_ctx *ctx, | ||||
219 | const struct flex_item_data *item, | ||||
220 | int available_width) | ||||
221 | { | ||||
222 | bool_Bool success; | ||||
223 | struct box *b = item->box; | ||||
224 | |||||
225 | switch (b->type) { | ||||
| |||||
226 | case BOX_BLOCK: | ||||
227 | success = layout_block_context(b, -1, ctx->content); | ||||
228 | break; | ||||
229 | case BOX_TABLE: | ||||
230 | b->float_container = b->parent; | ||||
231 | success = layout_table(b, available_width, ctx->content); | ||||
232 | b->float_container = NULL((void*)0); | ||||
233 | break; | ||||
234 | case BOX_FLEX: | ||||
235 | b->float_container = b->parent; | ||||
236 | success = layout_flex(b, available_width, ctx->content); | ||||
237 | b->float_container = NULL((void*)0); | ||||
238 | break; | ||||
239 | default: | ||||
240 | assert(0 && "Bad flex item back type")((0 && "Bad flex item back type") ? (void) (0) : __assert_fail ("0 && \"Bad flex item back type\"", "content/handlers/html/layout_flex.c" , 240, __extension__ __PRETTY_FUNCTION__)); | ||||
241 | success = false0; | ||||
242 | break; | ||||
243 | } | ||||
244 | |||||
245 | if (!success) { | ||||
246 | NSLOG(flex, ERROR, "box %p: layout failed", b)do { if (NSLOG_LEVEL_ERROR >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_ERROR, "content/handlers/html/layout_flex.c", sizeof ("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 246, }; nslog__log(&_nslog_ctx , "box %p: layout failed", b); } } while(0); | ||||
247 | } | ||||
248 | |||||
249 | return success; | ||||
250 | } | ||||
251 | |||||
252 | /** | ||||
253 | * Calculate an item's base and target main sizes. | ||||
254 | * | ||||
255 | * \param[in] ctx Flex layout context | ||||
256 | * \param[in] item Item to get sizes of | ||||
257 | * \param[in] available_width Available width in pixels | ||||
258 | * \return true on success false on failure | ||||
259 | */ | ||||
260 | static inline bool_Bool layout_flex__base_and_main_sizes( | ||||
261 | const struct flex_ctx *ctx, | ||||
262 | struct flex_item_data *item, | ||||
263 | int available_width) | ||||
264 | { | ||||
265 | struct box *b = item->box; | ||||
266 | int content_min_width = b->min_width; | ||||
267 | int content_max_width = b->max_width; | ||||
268 | int delta_outer_main = lh__delta_outer_main(ctx->flex, b); | ||||
269 | |||||
270 | NSLOG(flex, DEEPDEBUG, "box %p: delta_outer_main: %i",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 271, }; nslog__log(&_nslog_ctx , "box %p: delta_outer_main: %i", b, delta_outer_main); } } while (0) | ||||
271 | b, delta_outer_main)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 271, }; nslog__log(&_nslog_ctx , "box %p: delta_outer_main: %i", b, delta_outer_main); } } while (0); | ||||
272 | |||||
273 | if (item->basis == CSS_FLEX_BASIS_SET) { | ||||
274 | if (item->basis_unit == CSS_UNIT_PCT) { | ||||
275 | item->base_size = FPCT_OF_INT_TOINT(((((css_divide_fixed(((item->basis_length * available_width )), (0x00019000)))) >> 10)) | ||||
276 | item->basis_length,((((css_divide_fixed(((item->basis_length * available_width )), (0x00019000)))) >> 10)) | ||||
277 | available_width)((((css_divide_fixed(((item->basis_length * available_width )), (0x00019000)))) >> 10)); | ||||
278 | } else { | ||||
279 | item->base_size = FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( b->style, ctx->unit_len_ctx, item ->basis_length, item->basis_unit)) >> 10) | ||||
280 | b->style, ctx->unit_len_ctx,((css_unit_len2device_px( b->style, ctx->unit_len_ctx, item ->basis_length, item->basis_unit)) >> 10) | ||||
281 | item->basis_length,((css_unit_len2device_px( b->style, ctx->unit_len_ctx, item ->basis_length, item->basis_unit)) >> 10) | ||||
282 | item->basis_unit))((css_unit_len2device_px( b->style, ctx->unit_len_ctx, item ->basis_length, item->basis_unit)) >> 10); | ||||
283 | } | ||||
284 | |||||
285 | } else if (item->basis == CSS_FLEX_BASIS_AUTO) { | ||||
286 | item->base_size = ctx->horizontal ? b->width : b->height; | ||||
287 | } else { | ||||
288 | item->base_size = AUTO(-2147483647 -1); | ||||
289 | } | ||||
290 | |||||
291 | if (ctx->horizontal == false0) { | ||||
292 | if (b->width == AUTO(-2147483647 -1)) { | ||||
293 | b->width = min(max(content_min_width, available_width),((((((content_min_width)>(available_width))?(content_min_width ):(available_width)))<(content_max_width))?((((content_min_width )>(available_width))?(content_min_width):(available_width) )):(content_max_width)) | ||||
294 | content_max_width)((((((content_min_width)>(available_width))?(content_min_width ):(available_width)))<(content_max_width))?((((content_min_width )>(available_width))?(content_min_width):(available_width) )):(content_max_width)); | ||||
295 | b->width -= lh__delta_outer_width(b); | ||||
296 | } | ||||
297 | |||||
298 | if (!layout_flex_item(ctx, item, b->width)) { | ||||
299 | return false0; | ||||
300 | } | ||||
301 | } | ||||
302 | |||||
303 | if (item->base_size == AUTO(-2147483647 -1)) { | ||||
304 | if (ctx->horizontal == false0) { | ||||
305 | item->base_size = b->height; | ||||
306 | } else { | ||||
307 | item->base_size = content_max_width - delta_outer_main; | ||||
308 | } | ||||
309 | } | ||||
310 | |||||
311 | item->base_size += delta_outer_main; | ||||
312 | |||||
313 | if (ctx->horizontal) { | ||||
314 | item->base_size = min(item->base_size, available_width)(((item->base_size)<(available_width))?(item->base_size ):(available_width)); | ||||
315 | item->base_size = max(item->base_size, content_min_width)(((item->base_size)>(content_min_width))?(item->base_size ):(content_min_width)); | ||||
316 | } | ||||
317 | |||||
318 | item->target_main_size = item->base_size; | ||||
319 | item->main_size = item->base_size; | ||||
320 | |||||
321 | if (item->max_main > 0 && | ||||
322 | item->main_size > item->max_main + delta_outer_main) { | ||||
323 | item->main_size = item->max_main + delta_outer_main; | ||||
324 | } | ||||
325 | |||||
326 | if (item->main_size < item->min_main + delta_outer_main) { | ||||
327 | item->main_size = item->min_main + delta_outer_main; | ||||
328 | } | ||||
329 | |||||
330 | NSLOG(flex, DEEPDEBUG, "flex-item box: %p: base_size: %i, main_size %i",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 331, }; nslog__log(&_nslog_ctx , "flex-item box: %p: base_size: %i, main_size %i", b, item-> base_size, item->main_size); } } while(0) | ||||
331 | b, item->base_size, item->main_size)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 331, }; nslog__log(&_nslog_ctx , "flex-item box: %p: base_size: %i, main_size %i", b, item-> base_size, item->main_size); } } while(0); | ||||
332 | |||||
333 | return true1; | ||||
334 | } | ||||
335 | |||||
336 | /** | ||||
337 | * Fill out all item's data in a flex container. | ||||
338 | * | ||||
339 | * \param[in] ctx Flex layout context | ||||
340 | * \param[in] flex Flex box | ||||
341 | * \param[in] available_width Available width in pixels | ||||
342 | */ | ||||
343 | static void layout_flex_ctx__populate_item_data( | ||||
344 | const struct flex_ctx *ctx, | ||||
345 | const struct box *flex, | ||||
346 | int available_width) | ||||
347 | { | ||||
348 | size_t i = 0; | ||||
349 | bool_Bool horizontal = ctx->horizontal; | ||||
350 | |||||
351 | for (struct box *b = flex->children; b != NULL((void*)0); b = b->next) { | ||||
352 | struct flex_item_data *item = &ctx->item.data[i++]; | ||||
353 | |||||
354 | b->float_container = b->parent; | ||||
355 | layout_find_dimensions(ctx->unit_len_ctx, available_width, -1, | ||||
356 | b, b->style, &b->width, &b->height, | ||||
357 | horizontal ? &item->max_main : &item->max_cross, | ||||
358 | horizontal ? &item->min_main : &item->min_cross, | ||||
359 | horizontal ? &item->max_cross : &item->max_main, | ||||
360 | horizontal ? &item->min_cross : &item->min_main, | ||||
361 | b->margin, b->padding, b->border); | ||||
362 | b->float_container = NULL((void*)0); | ||||
363 | |||||
364 | NSLOG(flex, DEEPDEBUG, "flex-item box: %p: width: %i",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 365, }; nslog__log(&_nslog_ctx , "flex-item box: %p: width: %i", b, b->width); } } while( 0) | ||||
365 | b, b->width)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 365, }; nslog__log(&_nslog_ctx , "flex-item box: %p: width: %i", b, b->width); } } while( 0); | ||||
366 | |||||
367 | item->box = b; | ||||
368 | item->basis = css_computed_flex_basis(b->style, | ||||
369 | &item->basis_length, &item->basis_unit); | ||||
370 | |||||
371 | css_computed_flex_shrink(b->style, &item->shrink); | ||||
372 | css_computed_flex_grow(b->style, &item->grow); | ||||
373 | |||||
374 | layout_flex__base_and_main_sizes(ctx, item, available_width); | ||||
375 | } | ||||
376 | } | ||||
377 | |||||
378 | /** | ||||
379 | * Ensure context's lines array has a free space | ||||
380 | * | ||||
381 | * \param[in] ctx Flex layout context | ||||
382 | * \return true on success false on out of memory | ||||
383 | */ | ||||
384 | static bool_Bool layout_flex_ctx__ensure_line(struct flex_ctx *ctx) | ||||
385 | { | ||||
386 | struct flex_line_data *temp; | ||||
387 | size_t line_alloc = ctx->line.alloc * 2; | ||||
388 | |||||
389 | if (ctx->line.alloc
| ||||
390 | return true1; | ||||
391 | } | ||||
392 | |||||
393 | temp = realloc(ctx->line.data, sizeof(*ctx->line.data) * line_alloc); | ||||
394 | if (temp == NULL((void*)0)) { | ||||
395 | return false0; | ||||
396 | } | ||||
397 | ctx->line.data = temp; | ||||
398 | |||||
399 | memset(ctx->line.data + ctx->line.alloc, 0, | ||||
400 | sizeof(*ctx->line.data) * (line_alloc - ctx->line.alloc)); | ||||
401 | ctx->line.alloc = line_alloc; | ||||
402 | |||||
403 | return true1; | ||||
404 | } | ||||
405 | |||||
406 | /** | ||||
407 | * Assigns flex items to the line and returns the line | ||||
408 | * | ||||
409 | * \param[in] ctx Flex layout context | ||||
410 | * \param[in] item_index Index to first item to assign to this line | ||||
411 | * \return Pointer to the new line, or NULL on error. | ||||
412 | */ | ||||
413 | static struct flex_line_data *layout_flex__build_line(struct flex_ctx *ctx, | ||||
414 | size_t item_index) | ||||
415 | { | ||||
416 | enum box_side start_side = layout_flex__main_start_side(ctx); | ||||
417 | enum box_side end_side = layout_flex__main_end_side(ctx); | ||||
418 | struct flex_line_data *line; | ||||
419 | int used_main = 0; | ||||
420 | |||||
421 | if (!layout_flex_ctx__ensure_line(ctx)) { | ||||
422 | return NULL((void*)0); | ||||
423 | } | ||||
424 | |||||
425 | line = &ctx->line.data[ctx->line.count]; | ||||
426 | line->first = item_index; | ||||
427 | |||||
428 | NSLOG(flex, DEEPDEBUG, "flex container %p: available main: %i",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 429, }; nslog__log(&_nslog_ctx , "flex container %p: available main: %i", ctx->flex, ctx-> available_main); } } while(0) | ||||
429 | ctx->flex, ctx->available_main)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 429, }; nslog__log(&_nslog_ctx , "flex container %p: available main: %i", ctx->flex, ctx-> available_main); } } while(0); | ||||
430 | |||||
431 | while (item_index < ctx->item.count) { | ||||
432 | struct flex_item_data *item = &ctx->item.data[item_index]; | ||||
433 | struct box *b = item->box; | ||||
434 | int pos_main; | ||||
435 | |||||
436 | pos_main = ctx->horizontal
| ||||
437 | item->main_size : | ||||
438 | b->height + lh__delta_outer_main(ctx->flex, b); | ||||
439 | |||||
440 | if (ctx->wrap == CSS_FLEX_WRAP_NOWRAP || | ||||
441 | pos_main + used_main <= ctx->available_main || | ||||
442 | lh__box_is_absolute(item->box) || | ||||
443 | ctx->available_main == AUTO(-2147483647 -1) || | ||||
444 | line->count == 0 || | ||||
445 | pos_main == 0) { | ||||
446 | if (lh__box_is_absolute(item->box) == false0) { | ||||
447 | line->main_size += item->main_size; | ||||
448 | used_main += pos_main; | ||||
449 | |||||
450 | if (b->margin[start_side] == AUTO(-2147483647 -1)) { | ||||
451 | line->main_auto_margin_count++; | ||||
452 | } | ||||
453 | if (b->margin[end_side] == AUTO(-2147483647 -1)) { | ||||
454 | line->main_auto_margin_count++; | ||||
455 | } | ||||
456 | } | ||||
457 | item->line = ctx->line.count; | ||||
458 | line->count++; | ||||
459 | item_index++; | ||||
460 | } else { | ||||
461 | break; | ||||
462 | } | ||||
463 | } | ||||
464 | |||||
465 | if (line->count > 0) { | ||||
466 | ctx->line.count++; | ||||
467 | } else { | ||||
468 | NSLOG(layout, ERROR, "Failed to fit any flex items")do { if (NSLOG_LEVEL_ERROR >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_layout , NSLOG_LEVEL_ERROR, "content/handlers/html/layout_flex.c", sizeof ("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 468, }; nslog__log(&_nslog_ctx , "Failed to fit any flex items"); } } while(0); | ||||
469 | } | ||||
470 | |||||
471 | return line; | ||||
472 | } | ||||
473 | |||||
474 | /** | ||||
475 | * Freeze an item on a line | ||||
476 | * | ||||
477 | * \param[in] line Line to containing item | ||||
478 | * \param[in] item Item to freeze | ||||
479 | */ | ||||
480 | static inline void layout_flex__item_freeze( | ||||
481 | struct flex_line_data *line, | ||||
482 | struct flex_item_data *item) | ||||
483 | { | ||||
484 | item->freeze = true1; | ||||
485 | line->frozen++; | ||||
486 | |||||
487 | if (!lh__box_is_absolute(item->box)){ | ||||
488 | line->used_main_size += item->target_main_size; | ||||
489 | } | ||||
490 | |||||
491 | NSLOG(flex, DEEPDEBUG, "flex-item box: %p: "do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 493, }; nslog__log(&_nslog_ctx , "flex-item box: %p: " "Frozen at target_main_size: %i", item ->box, item->target_main_size); } } while(0) | ||||
492 | "Frozen at target_main_size: %i",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 493, }; nslog__log(&_nslog_ctx , "flex-item box: %p: " "Frozen at target_main_size: %i", item ->box, item->target_main_size); } } while(0) | ||||
493 | item->box, item->target_main_size)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 493, }; nslog__log(&_nslog_ctx , "flex-item box: %p: " "Frozen at target_main_size: %i", item ->box, item->target_main_size); } } while(0); | ||||
494 | } | ||||
495 | |||||
496 | /** | ||||
497 | * Calculate remaining free space and unfrozen item factor sum | ||||
498 | * | ||||
499 | * \param[in] ctx Flex layout context | ||||
500 | * \param[in] line Line to calculate free space on | ||||
501 | * \param[out] unfrozen_factor_sum Returns sum of unfrozen item's flex factors | ||||
502 | * \param[in] initial_free_main Initial free space in main direction | ||||
503 | * \param[in] available_main Available space in main direction | ||||
504 | * \param[in] grow Whether to grow or shrink | ||||
505 | * return remaining free space on line | ||||
506 | */ | ||||
507 | static inline int layout_flex__remaining_free_main( | ||||
508 | struct flex_ctx *ctx, | ||||
509 | struct flex_line_data *line, | ||||
510 | css_fixed *unfrozen_factor_sum, | ||||
511 | int initial_free_main, | ||||
512 | int available_main, | ||||
513 | bool_Bool grow) | ||||
514 | { | ||||
515 | int remaining_free_main = available_main; | ||||
516 | size_t item_count = line->first + line->count; | ||||
517 | |||||
518 | *unfrozen_factor_sum = 0; | ||||
519 | |||||
520 | for (size_t i = line->first; i < item_count; i++) { | ||||
521 | struct flex_item_data *item = &ctx->item.data[i]; | ||||
522 | |||||
523 | if (item->freeze) { | ||||
524 | remaining_free_main -= item->target_main_size; | ||||
525 | } else { | ||||
526 | remaining_free_main -= item->base_size; | ||||
527 | |||||
528 | *unfrozen_factor_sum += grow ? | ||||
529 | item->grow : item->shrink; | ||||
530 | } | ||||
531 | } | ||||
532 | |||||
533 | if (*unfrozen_factor_sum < F_10x00000400) { | ||||
534 | int free_space = FIXTOINT(FMUL(INTTOFIX(initial_free_main),(((css_multiply_fixed(((css_int_to_fixed(initial_free_main))) , (*unfrozen_factor_sum)))) >> 10) | ||||
535 | *unfrozen_factor_sum))(((css_multiply_fixed(((css_int_to_fixed(initial_free_main))) , (*unfrozen_factor_sum)))) >> 10); | ||||
536 | |||||
537 | if (free_space < remaining_free_main) { | ||||
538 | remaining_free_main = free_space; | ||||
539 | } | ||||
540 | } | ||||
541 | |||||
542 | NSLOG(flex, DEEPDEBUG, "Remaining free space: %i",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 543, }; nslog__log(&_nslog_ctx , "Remaining free space: %i", remaining_free_main); } } while (0) | ||||
543 | remaining_free_main)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 543, }; nslog__log(&_nslog_ctx , "Remaining free space: %i", remaining_free_main); } } while (0); | ||||
544 | |||||
545 | return remaining_free_main; | ||||
546 | } | ||||
547 | |||||
548 | /** | ||||
549 | * Clamp flex item target main size and get min/max violations | ||||
550 | * | ||||
551 | * \param[in] ctx Flex layout context | ||||
552 | * \param[in] line Line to align items on | ||||
553 | * return total violation in pixels | ||||
554 | */ | ||||
555 | static inline int layout_flex__get_min_max_violations( | ||||
556 | struct flex_ctx *ctx, | ||||
557 | struct flex_line_data *line) | ||||
558 | { | ||||
559 | |||||
560 | int total_violation = 0; | ||||
561 | size_t item_count = line->first + line->count; | ||||
562 | |||||
563 | for (size_t i = line->first; i < item_count; i++) { | ||||
564 | struct flex_item_data *item = &ctx->item.data[i]; | ||||
565 | int target_main_size = item->target_main_size; | ||||
566 | |||||
567 | NSLOG(flex, DEEPDEBUG, "item %p: target_main_size: %i",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 568, }; nslog__log(&_nslog_ctx , "item %p: target_main_size: %i", item->box, target_main_size ); } } while(0) | ||||
568 | item->box, target_main_size)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 568, }; nslog__log(&_nslog_ctx , "item %p: target_main_size: %i", item->box, target_main_size ); } } while(0); | ||||
569 | |||||
570 | if (item->freeze) { | ||||
571 | continue; | ||||
572 | } | ||||
573 | |||||
574 | if (item->max_main > 0 && | ||||
575 | target_main_size > item->max_main) { | ||||
576 | target_main_size = item->max_main; | ||||
577 | item->max_violation = true1; | ||||
578 | NSLOG(flex, DEEPDEBUG, "Violation: max_main: %i",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 579, }; nslog__log(&_nslog_ctx , "Violation: max_main: %i", item->max_main); } } while(0) | ||||
579 | item->max_main)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 579, }; nslog__log(&_nslog_ctx , "Violation: max_main: %i", item->max_main); } } while(0); | ||||
580 | } | ||||
581 | |||||
582 | if (target_main_size < item->min_main) { | ||||
583 | target_main_size = item->min_main; | ||||
584 | item->min_violation = true1; | ||||
585 | NSLOG(flex, DEEPDEBUG, "Violation: min_main: %i",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 586, }; nslog__log(&_nslog_ctx , "Violation: min_main: %i", item->min_main); } } while(0) | ||||
586 | item->min_main)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 586, }; nslog__log(&_nslog_ctx , "Violation: min_main: %i", item->min_main); } } while(0); | ||||
587 | } | ||||
588 | |||||
589 | if (target_main_size < item->box->min_width) { | ||||
590 | target_main_size = item->box->min_width; | ||||
591 | item->min_violation = true1; | ||||
592 | NSLOG(flex, DEEPDEBUG, "Violation: box min_width: %i",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 593, }; nslog__log(&_nslog_ctx , "Violation: box min_width: %i", item->box->min_width) ; } } while(0) | ||||
593 | item->box->min_width)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 593, }; nslog__log(&_nslog_ctx , "Violation: box min_width: %i", item->box->min_width) ; } } while(0); | ||||
594 | } | ||||
595 | |||||
596 | if (target_main_size < 0) { | ||||
597 | target_main_size = 0; | ||||
598 | item->min_violation = true1; | ||||
599 | NSLOG(flex, DEEPDEBUG, "Violation: less than 0")do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 599, }; nslog__log(&_nslog_ctx , "Violation: less than 0"); } } while(0); | ||||
600 | } | ||||
601 | |||||
602 | total_violation += target_main_size - item->target_main_size; | ||||
603 | item->target_main_size = target_main_size; | ||||
604 | } | ||||
605 | |||||
606 | NSLOG(flex, DEEPDEBUG, "Total violation: %i", total_violation)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 606, }; nslog__log(&_nslog_ctx , "Total violation: %i", total_violation); } } while(0); | ||||
607 | |||||
608 | return total_violation; | ||||
609 | } | ||||
610 | |||||
611 | /** | ||||
612 | * Distribute remaining free space proportional to the flex factors. | ||||
613 | * | ||||
614 | * Remaining free space may be negative. | ||||
615 | * | ||||
616 | * \param[in] ctx Flex layout context | ||||
617 | * \param[in] line Line to distribute free space on | ||||
618 | * \param[in] unfrozen_factor_sum Sum of unfrozen item's flex factors | ||||
619 | * \param[in] remaining_free_main Remaining free space in main direction | ||||
620 | * \param[in] grow Whether to grow or shrink | ||||
621 | */ | ||||
622 | static inline void layout_flex__distribute_free_main( | ||||
623 | struct flex_ctx *ctx, | ||||
624 | struct flex_line_data *line, | ||||
625 | css_fixed unfrozen_factor_sum, | ||||
626 | int remaining_free_main, | ||||
627 | bool_Bool grow) | ||||
628 | { | ||||
629 | size_t item_count = line->first + line->count; | ||||
630 | |||||
631 | if (grow) { | ||||
632 | css_fixed remainder = 0; | ||||
633 | for (size_t i = line->first; i < item_count; i++) { | ||||
634 | struct flex_item_data *item = &ctx->item.data[i]; | ||||
635 | css_fixed result; | ||||
636 | css_fixed ratio; | ||||
637 | |||||
638 | if (item->freeze) { | ||||
639 | continue; | ||||
640 | } | ||||
641 | |||||
642 | ratio = FDIV(item->grow, unfrozen_factor_sum)(css_divide_fixed((item->grow), (unfrozen_factor_sum))); | ||||
643 | result = FMUL(INTTOFIX(remaining_free_main), ratio)(css_multiply_fixed(((css_int_to_fixed(remaining_free_main))) , (ratio))) + | ||||
644 | remainder; | ||||
645 | |||||
646 | item->target_main_size = item->base_size + | ||||
647 | FIXTOINT(result)((result) >> 10); | ||||
648 | remainder = FIXFRAC(result)(result & ((1 << 10)- 1 )); | ||||
649 | } | ||||
650 | } else { | ||||
651 | css_fixed scaled_shrink_factor_sum = 0; | ||||
652 | css_fixed remainder = 0; | ||||
653 | |||||
654 | for (size_t i = line->first; i < item_count; i++) { | ||||
655 | struct flex_item_data *item = &ctx->item.data[i]; | ||||
656 | css_fixed scaled_shrink_factor; | ||||
657 | |||||
658 | if (item->freeze) { | ||||
659 | continue; | ||||
660 | } | ||||
661 | |||||
662 | scaled_shrink_factor = FMUL((css_multiply_fixed((item->shrink), ((css_int_to_fixed(item ->base_size))))) | ||||
663 | item->shrink,(css_multiply_fixed((item->shrink), ((css_int_to_fixed(item ->base_size))))) | ||||
664 | INTTOFIX(item->base_size))(css_multiply_fixed((item->shrink), ((css_int_to_fixed(item ->base_size))))); | ||||
665 | scaled_shrink_factor_sum += scaled_shrink_factor; | ||||
666 | } | ||||
667 | |||||
668 | for (size_t i = line->first; i < item_count; i++) { | ||||
669 | struct flex_item_data *item = &ctx->item.data[i]; | ||||
670 | css_fixed scaled_shrink_factor; | ||||
671 | css_fixed result; | ||||
672 | css_fixed ratio; | ||||
673 | |||||
674 | if (item->freeze) { | ||||
675 | continue; | ||||
676 | } else if (scaled_shrink_factor_sum == 0) { | ||||
677 | item->target_main_size = item->main_size; | ||||
678 | layout_flex__item_freeze(line, item); | ||||
679 | continue; | ||||
680 | } | ||||
681 | |||||
682 | scaled_shrink_factor = FMUL((css_multiply_fixed((item->shrink), ((css_int_to_fixed(item ->base_size))))) | ||||
683 | item->shrink,(css_multiply_fixed((item->shrink), ((css_int_to_fixed(item ->base_size))))) | ||||
684 | INTTOFIX(item->base_size))(css_multiply_fixed((item->shrink), ((css_int_to_fixed(item ->base_size))))); | ||||
685 | ratio = FDIV(scaled_shrink_factor,(css_divide_fixed((scaled_shrink_factor), (scaled_shrink_factor_sum ))) | ||||
686 | scaled_shrink_factor_sum)(css_divide_fixed((scaled_shrink_factor), (scaled_shrink_factor_sum ))); | ||||
687 | result = FMUL(INTTOFIX(abs(remaining_free_main)),(css_multiply_fixed(((css_int_to_fixed(abs(remaining_free_main )))), (ratio))) | ||||
688 | ratio)(css_multiply_fixed(((css_int_to_fixed(abs(remaining_free_main )))), (ratio))) + remainder; | ||||
689 | |||||
690 | item->target_main_size = item->base_size - | ||||
691 | FIXTOINT(result)((result) >> 10); | ||||
692 | remainder = FIXFRAC(result)(result & ((1 << 10)- 1 )); | ||||
693 | } | ||||
694 | } | ||||
695 | } | ||||
696 | |||||
697 | /** | ||||
698 | * Resolve flexible item lengths along a line. | ||||
699 | * | ||||
700 | * See 9.7 of Tests CSS Flexible Box Layout Module Level 1. | ||||
701 | * | ||||
702 | * \param[in] ctx Flex layout context | ||||
703 | * \param[in] line Line to resolve | ||||
704 | * \return true on success, false on failure. | ||||
705 | */ | ||||
706 | static bool_Bool layout_flex__resolve_line( | ||||
707 | struct flex_ctx *ctx, | ||||
708 | struct flex_line_data *line) | ||||
709 | { | ||||
710 | size_t item_count = line->first + line->count; | ||||
711 | int available_main = ctx->available_main; | ||||
712 | int initial_free_main; | ||||
713 | bool_Bool grow; | ||||
714 | |||||
715 | if (available_main == AUTO(-2147483647 -1)) { | ||||
716 | available_main = INT_MAX2147483647; | ||||
717 | } | ||||
718 | |||||
719 | grow = (line->main_size < available_main); | ||||
720 | initial_free_main = available_main; | ||||
721 | |||||
722 | NSLOG(flex, DEEPDEBUG, "box %p: line %zu: first: %zu, count: %zu",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 724, }; nslog__log(&_nslog_ctx , "box %p: line %zu: first: %zu, count: %zu", ctx->flex, line - ctx->line.data, line->first, line->count); } } while (0) | ||||
723 | ctx->flex, line - ctx->line.data,do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 724, }; nslog__log(&_nslog_ctx , "box %p: line %zu: first: %zu, count: %zu", ctx->flex, line - ctx->line.data, line->first, line->count); } } while (0) | ||||
724 | line->first, line->count)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 724, }; nslog__log(&_nslog_ctx , "box %p: line %zu: first: %zu, count: %zu", ctx->flex, line - ctx->line.data, line->first, line->count); } } while (0); | ||||
725 | NSLOG(flex, DEEPDEBUG, "Line main_size: %i, available_main: %i",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 726, }; nslog__log(&_nslog_ctx , "Line main_size: %i, available_main: %i", line->main_size , available_main); } } while(0) | ||||
726 | line->main_size, available_main)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 726, }; nslog__log(&_nslog_ctx , "Line main_size: %i, available_main: %i", line->main_size , available_main); } } while(0); | ||||
727 | |||||
728 | for (size_t i = line->first; i < item_count; i++) { | ||||
729 | struct flex_item_data *item = &ctx->item.data[i]; | ||||
730 | |||||
731 | /* 3. Size inflexible items */ | ||||
732 | if (grow) { | ||||
733 | if (item->grow == 0 || | ||||
734 | item->base_size > item->main_size) { | ||||
735 | item->target_main_size = item->main_size; | ||||
736 | layout_flex__item_freeze(line, item); | ||||
737 | } | ||||
738 | } else { | ||||
739 | if (item->shrink == 0 || | ||||
740 | item->base_size < item->main_size) { | ||||
741 | item->target_main_size = item->main_size; | ||||
742 | layout_flex__item_freeze(line, item); | ||||
743 | } | ||||
744 | } | ||||
745 | |||||
746 | /* 4. Calculate initial free space */ | ||||
747 | if (item->freeze) { | ||||
748 | initial_free_main -= item->target_main_size; | ||||
749 | } else { | ||||
750 | initial_free_main -= item->base_size; | ||||
751 | } | ||||
752 | } | ||||
753 | |||||
754 | /* 5. Loop */ | ||||
755 | while (line->frozen < line->count) { | ||||
756 | css_fixed unfrozen_factor_sum; | ||||
757 | int remaining_free_main; | ||||
758 | int total_violation; | ||||
759 | |||||
760 | NSLOG(flex, DEEPDEBUG, "flex-container: %p: Resolver pass",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 761, }; nslog__log(&_nslog_ctx , "flex-container: %p: Resolver pass", ctx->flex); } } while (0) | ||||
761 | ctx->flex)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 761, }; nslog__log(&_nslog_ctx , "flex-container: %p: Resolver pass", ctx->flex); } } while (0); | ||||
762 | |||||
763 | /* b */ | ||||
764 | remaining_free_main = layout_flex__remaining_free_main(ctx, | ||||
765 | line, &unfrozen_factor_sum, initial_free_main, | ||||
766 | available_main, grow); | ||||
767 | |||||
768 | /* c */ | ||||
769 | if (remaining_free_main != 0) { | ||||
770 | layout_flex__distribute_free_main(ctx, | ||||
771 | line, unfrozen_factor_sum, | ||||
772 | remaining_free_main, grow); | ||||
773 | } | ||||
774 | |||||
775 | /* d */ | ||||
776 | total_violation = layout_flex__get_min_max_violations( | ||||
777 | ctx, line); | ||||
778 | |||||
779 | /* e */ | ||||
780 | for (size_t i = line->first; i < item_count; i++) { | ||||
781 | struct flex_item_data *item = &ctx->item.data[i]; | ||||
782 | |||||
783 | if (item->freeze) { | ||||
784 | continue; | ||||
785 | } | ||||
786 | |||||
787 | if (total_violation == 0 || | ||||
788 | (total_violation > 0 && item->min_violation) || | ||||
789 | (total_violation < 0 && item->max_violation)) { | ||||
790 | layout_flex__item_freeze(line, item); | ||||
791 | } | ||||
792 | } | ||||
793 | } | ||||
794 | |||||
795 | return true1; | ||||
796 | } | ||||
797 | |||||
798 | /** | ||||
799 | * Position items along a line | ||||
800 | * | ||||
801 | * \param[in] ctx Flex layout context | ||||
802 | * \param[in] line Line to resolve | ||||
803 | * \return true on success, false on failure. | ||||
804 | */ | ||||
805 | static bool_Bool layout_flex__place_line_items_main( | ||||
806 | struct flex_ctx *ctx, | ||||
807 | struct flex_line_data *line) | ||||
808 | { | ||||
809 | int main_pos = ctx->flex->padding[layout_flex__main_start_side(ctx)]; | ||||
810 | int post_multiplier = ctx->main_reversed ? 0 : 1; | ||||
811 | int pre_multiplier = ctx->main_reversed ? -1 : 0; | ||||
812 | size_t item_count = line->first + line->count; | ||||
813 | int extra_remainder = 0; | ||||
814 | int extra = 0; | ||||
815 | |||||
816 | if (ctx->main_reversed) { | ||||
817 | main_pos = lh__box_size_main(ctx->horizontal, ctx->flex) - | ||||
818 | main_pos; | ||||
819 | } | ||||
820 | |||||
821 | if (ctx->available_main != AUTO(-2147483647 -1) && | ||||
822 | ctx->available_main != UNKNOWN_WIDTH2147483647 && | ||||
823 | ctx->available_main > line->used_main_size) { | ||||
824 | if (line->main_auto_margin_count > 0) { | ||||
825 | extra = ctx->available_main - line->used_main_size; | ||||
826 | |||||
827 | extra_remainder = extra % line->main_auto_margin_count; | ||||
828 | extra /= line->main_auto_margin_count; | ||||
829 | } | ||||
830 | } | ||||
831 | |||||
832 | for (size_t i = line->first; i < item_count; i++) { | ||||
833 | enum box_side main_end = ctx->horizontal ? RIGHT : BOTTOM; | ||||
834 | enum box_side main_start = ctx->horizontal ? LEFT : TOP; | ||||
835 | struct flex_item_data *item = &ctx->item.data[i]; | ||||
836 | struct box *b = item->box; | ||||
837 | int extra_total = 0; | ||||
838 | int extra_post = 0; | ||||
839 | int extra_pre = 0; | ||||
840 | int box_size_main; | ||||
841 | int *box_pos_main; | ||||
842 | |||||
843 | if (ctx->horizontal) { | ||||
844 | b->width = item->target_main_size - | ||||
845 | lh__delta_outer_width(b); | ||||
846 | |||||
847 | if (!layout_flex_item(ctx, item, b->width)) { | ||||
848 | return false0; | ||||
849 | } | ||||
850 | } | ||||
851 | |||||
852 | box_size_main = lh__box_size_main(ctx->horizontal, b); | ||||
853 | box_pos_main = ctx->horizontal ? &b->x : &b->y; | ||||
854 | |||||
855 | if (!lh__box_is_absolute(b)) { | ||||
856 | if (b->margin[main_start] == AUTO(-2147483647 -1)) { | ||||
857 | extra_pre = extra + extra_remainder; | ||||
858 | } | ||||
859 | if (b->margin[main_end] == AUTO(-2147483647 -1)) { | ||||
860 | extra_post = extra + extra_remainder; | ||||
861 | } | ||||
862 | extra_total = extra_pre + extra_post; | ||||
863 | |||||
864 | main_pos += pre_multiplier * | ||||
865 | (extra_total + box_size_main + | ||||
866 | lh__delta_outer_main(ctx->flex, b)); | ||||
867 | } | ||||
868 | |||||
869 | *box_pos_main = main_pos + lh__non_auto_margin(b, main_start) + | ||||
870 | extra_pre + b->border[main_start].width; | ||||
871 | |||||
872 | if (!lh__box_is_absolute(b)) { | ||||
873 | int cross_size; | ||||
874 | int box_size_cross = lh__box_size_cross( | ||||
875 | ctx->horizontal, b); | ||||
876 | |||||
877 | main_pos += post_multiplier * | ||||
878 | (extra_total + box_size_main + | ||||
879 | lh__delta_outer_main(ctx->flex, b)); | ||||
880 | |||||
881 | cross_size = box_size_cross + lh__delta_outer_cross( | ||||
882 | ctx->flex, b); | ||||
883 | if (line->cross_size < cross_size) { | ||||
884 | line->cross_size = cross_size; | ||||
885 | } | ||||
886 | } | ||||
887 | } | ||||
888 | |||||
889 | return true1; | ||||
890 | } | ||||
891 | |||||
892 | /** | ||||
893 | * Collect items onto lines and place items along the lines | ||||
894 | * | ||||
895 | * \param[in] ctx Flex layout context | ||||
896 | * \return true on success, false on failure. | ||||
897 | */ | ||||
898 | static bool_Bool layout_flex__collect_items_into_lines( | ||||
899 | struct flex_ctx *ctx) | ||||
900 | { | ||||
901 | size_t pos = 0; | ||||
902 | |||||
903 | while (pos < ctx->item.count) { | ||||
904 | struct flex_line_data *line; | ||||
905 | |||||
906 | line = layout_flex__build_line(ctx, pos); | ||||
907 | if (line == NULL((void*)0)) { | ||||
908 | return false0; | ||||
909 | } | ||||
910 | |||||
911 | pos += line->count; | ||||
912 | |||||
913 | NSLOG(flex, DEEPDEBUG, "flex-container: %p: "do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 916, }; nslog__log(&_nslog_ctx , "flex-container: %p: " "fitted: %zu (total: %zu/%zu)", ctx-> flex, line->count, pos, ctx->item.count); } } while(0) | ||||
914 | "fitted: %zu (total: %zu/%zu)",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 916, }; nslog__log(&_nslog_ctx , "flex-container: %p: " "fitted: %zu (total: %zu/%zu)", ctx-> flex, line->count, pos, ctx->item.count); } } while(0) | ||||
915 | ctx->flex, line->count,do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 916, }; nslog__log(&_nslog_ctx , "flex-container: %p: " "fitted: %zu (total: %zu/%zu)", ctx-> flex, line->count, pos, ctx->item.count); } } while(0) | ||||
916 | pos, ctx->item.count)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 916, }; nslog__log(&_nslog_ctx , "flex-container: %p: " "fitted: %zu (total: %zu/%zu)", ctx-> flex, line->count, pos, ctx->item.count); } } while(0); | ||||
917 | |||||
918 | if (!layout_flex__resolve_line(ctx, line)) { | ||||
919 | return false0; | ||||
920 | } | ||||
921 | |||||
922 | if (!layout_flex__place_line_items_main(ctx, line)) { | ||||
923 | return false0; | ||||
924 | } | ||||
925 | |||||
926 | ctx->cross_size += line->cross_size; | ||||
927 | if (ctx->main_size < line->main_size) { | ||||
928 | ctx->main_size = line->main_size; | ||||
929 | } | ||||
930 | } | ||||
931 | |||||
932 | return true1; | ||||
933 | } | ||||
934 | |||||
935 | /** | ||||
936 | * Align items on a line. | ||||
937 | * | ||||
938 | * \param[in] ctx Flex layout context | ||||
939 | * \param[in] line Line to align items on | ||||
940 | * \param[in] extra Extra line width in pixels | ||||
941 | */ | ||||
942 | static void layout_flex__place_line_items_cross(struct flex_ctx *ctx, | ||||
943 | struct flex_line_data *line, int extra) | ||||
944 | { | ||||
945 | enum box_side cross_start = ctx->horizontal ? TOP : LEFT; | ||||
946 | size_t item_count = line->first + line->count; | ||||
947 | |||||
948 | for (size_t i = line->first; i < item_count; i++) { | ||||
949 | struct flex_item_data *item = &ctx->item.data[i]; | ||||
950 | struct box *b = item->box; | ||||
951 | int cross_free_space; | ||||
952 | int *box_size_cross; | ||||
953 | int *box_pos_cross; | ||||
954 | |||||
955 | box_pos_cross = ctx->horizontal ? &b->y : &b->x; | ||||
956 | box_size_cross = lh__box_size_cross_ptr(ctx->horizontal, b); | ||||
957 | |||||
958 | cross_free_space = line->cross_size + extra - *box_size_cross - | ||||
959 | lh__delta_outer_cross(ctx->flex, b); | ||||
960 | |||||
961 | switch (lh__box_align_self(ctx->flex, b)) { | ||||
962 | default: | ||||
963 | case CSS_ALIGN_SELF_STRETCH: | ||||
964 | if (lh__box_size_cross_is_auto(ctx->horizontal, b)) { | ||||
965 | *box_size_cross += cross_free_space; | ||||
966 | |||||
967 | /* Relayout children for stretch. */ | ||||
968 | if (!layout_flex_item(ctx, item, b->width)) { | ||||
969 | return; | ||||
970 | } | ||||
971 | } | ||||
972 | fallthrough__attribute__((__fallthrough__)); | ||||
973 | case CSS_ALIGN_SELF_FLEX_START: | ||||
974 | *box_pos_cross = ctx->flex->padding[cross_start] + | ||||
975 | line->pos + | ||||
976 | lh__non_auto_margin(b, cross_start) + | ||||
977 | b->border[cross_start].width; | ||||
978 | break; | ||||
979 | |||||
980 | case CSS_ALIGN_SELF_FLEX_END: | ||||
981 | *box_pos_cross = ctx->flex->padding[cross_start] + | ||||
982 | line->pos + cross_free_space + | ||||
983 | lh__non_auto_margin(b, cross_start) + | ||||
984 | b->border[cross_start].width; | ||||
985 | break; | ||||
986 | |||||
987 | case CSS_ALIGN_SELF_BASELINE: | ||||
988 | case CSS_ALIGN_SELF_CENTER: | ||||
989 | *box_pos_cross = ctx->flex->padding[cross_start] + | ||||
990 | line->pos + cross_free_space / 2 + | ||||
991 | lh__non_auto_margin(b, cross_start) + | ||||
992 | b->border[cross_start].width; | ||||
993 | break; | ||||
994 | } | ||||
995 | } | ||||
996 | } | ||||
997 | |||||
998 | /** | ||||
999 | * Place the lines and align the items on the line. | ||||
1000 | * | ||||
1001 | * \param[in] ctx Flex layout context | ||||
1002 | */ | ||||
1003 | static void layout_flex__place_lines(struct flex_ctx *ctx) | ||||
1004 | { | ||||
1005 | bool_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; | ||||
1010 | int extra = 0; | ||||
1011 | |||||
1012 | if (ctx->available_cross != AUTO(-2147483647 -1) && | ||||
1013 | ctx->available_cross > ctx->cross_size && | ||||
1014 | ctx->line.count > 0) { | ||||
1015 | extra = ctx->available_cross - ctx->cross_size; | ||||
1016 | |||||
1017 | extra_remainder = extra % ctx->line.count; | ||||
1018 | extra /= ctx->line.count; | ||||
1019 | } | ||||
1020 | |||||
1021 | for (size_t i = 0; i < ctx->line.count; i++) { | ||||
1022 | struct flex_line_data *line = &ctx->line.data[i]; | ||||
1023 | |||||
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; | ||||
1028 | |||||
1029 | layout_flex__place_line_items_cross(ctx, line, | ||||
1030 | extra + extra_remainder); | ||||
1031 | |||||
1032 | if (extra_remainder > 0) { | ||||
1033 | extra_remainder--; | ||||
1034 | } | ||||
1035 | } | ||||
1036 | } | ||||
1037 | |||||
1038 | /** | ||||
1039 | * Layout a flex container. | ||||
1040 | * | ||||
1041 | * \param[in] flex table to layout | ||||
1042 | * \param[in] available_width width of containing block | ||||
1043 | * \param[in] content memory pool for any new boxes | ||||
1044 | * \return true on success, false on memory exhaustion | ||||
1045 | */ | ||||
1046 | bool_Bool layout_flex(struct box *flex, int available_width, | ||||
1047 | html_content *content) | ||||
1048 | { | ||||
1049 | int max_height, min_height; | ||||
1050 | struct flex_ctx *ctx; | ||||
1051 | bool_Bool success = false0; | ||||
1052 | |||||
1053 | ctx = layout_flex_ctx__create(content, flex); | ||||
1054 | if (ctx
| ||||
1055 | return false0; | ||||
1056 | } | ||||
1057 | |||||
1058 | NSLOG(flex, DEEPDEBUG, "box %p: %s, available_width %i, width: %i",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 1060, }; nslog__log(&_nslog_ctx , "box %p: %s, available_width %i, width: %i", flex, ctx-> horizontal ? "horizontal" : "vertical", available_width, flex ->width); } } while(0) | ||||
1059 | flex, ctx->horizontal ? "horizontal" : "vertical",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 1060, }; nslog__log(&_nslog_ctx , "box %p: %s, available_width %i, width: %i", flex, ctx-> horizontal ? "horizontal" : "vertical", available_width, flex ->width); } } while(0) | ||||
1060 | available_width, flex->width)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 1060, }; nslog__log(&_nslog_ctx , "box %p: %s, available_width %i, width: %i", flex, ctx-> horizontal ? "horizontal" : "vertical", available_width, flex ->width); } } while(0); | ||||
1061 | |||||
1062 | layout_find_dimensions( | ||||
1063 | ctx->unit_len_ctx, available_width, -1, | ||||
1064 | flex, flex->style, NULL((void*)0), &flex->height, | ||||
1065 | NULL((void*)0), NULL((void*)0), &max_height, &min_height, | ||||
1066 | flex->margin, flex->padding, flex->border); | ||||
1067 | |||||
1068 | available_width = min(available_width, flex->width)(((available_width)<(flex->width))?(available_width):(flex ->width)); | ||||
1069 | |||||
1070 | if (ctx->horizontal
| ||||
1071 | ctx->available_main = available_width; | ||||
1072 | ctx->available_cross = ctx->flex->height; | ||||
1073 | } else { | ||||
1074 | ctx->available_main = ctx->flex->height; | ||||
1075 | ctx->available_cross = available_width; | ||||
1076 | } | ||||
1077 | |||||
1078 | NSLOG(flex, DEEPDEBUG, "box %p: available_main: %i",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 1079, }; nslog__log(&_nslog_ctx , "box %p: available_main: %i", flex, ctx->available_main) ; } } while(0) | ||||
1079 | flex, ctx->available_main)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 1079, }; nslog__log(&_nslog_ctx , "box %p: available_main: %i", flex, ctx->available_main) ; } } while(0); | ||||
1080 | NSLOG(flex, DEEPDEBUG, "box %p: available_cross: %i",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 1081, }; nslog__log(&_nslog_ctx , "box %p: available_cross: %i", flex, ctx->available_cross ); } } while(0) | ||||
1081 | flex, ctx->available_cross)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 1081, }; nslog__log(&_nslog_ctx , "box %p: available_cross: %i", flex, ctx->available_cross ); } } while(0); | ||||
1082 | |||||
1083 | layout_flex_ctx__populate_item_data(ctx, flex, available_width); | ||||
1084 | |||||
1085 | /* Place items onto lines. */ | ||||
1086 | success = layout_flex__collect_items_into_lines(ctx); | ||||
1087 | if (!success) { | ||||
1088 | goto cleanup; | ||||
1089 | } | ||||
1090 | |||||
1091 | layout_flex__place_lines(ctx); | ||||
1092 | |||||
1093 | if (flex->height == AUTO(-2147483647 -1)) { | ||||
1094 | flex->height = ctx->horizontal ? | ||||
1095 | ctx->cross_size : | ||||
1096 | ctx->main_size; | ||||
1097 | } | ||||
1098 | |||||
1099 | if (flex->height != AUTO(-2147483647 -1)) { | ||||
1100 | if (max_height >= 0 && flex->height > max_height) { | ||||
1101 | flex->height = max_height; | ||||
1102 | } | ||||
1103 | if (min_height > 0 && flex->height < min_height) { | ||||
1104 | flex->height = min_height; | ||||
1105 | } | ||||
1106 | } | ||||
1107 | |||||
1108 | success = true1; | ||||
1109 | |||||
1110 | cleanup: | ||||
1111 | layout_flex_ctx__destroy(ctx); | ||||
1112 | |||||
1113 | NSLOG(flex, DEEPDEBUG, "box %p: %s: w: %i, h: %i", flex,do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 1115, }; nslog__log(&_nslog_ctx , "box %p: %s: w: %i, h: %i", flex, success ? "success" : "failure" , flex->width, flex->height); } } while(0) | ||||
1114 | success ? "success" : "failure",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 1115, }; nslog__log(&_nslog_ctx , "box %p: %s: w: %i, h: %i", flex, success ? "success" : "failure" , flex->width, flex->height); } } while(0) | ||||
1115 | flex->width, flex->height)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_flex , NSLOG_LEVEL_DEEPDEBUG, "content/handlers/html/layout_flex.c" , sizeof("content/handlers/html/layout_flex.c") - 1, __PRETTY_FUNCTION__ , sizeof(__PRETTY_FUNCTION__) - 1, 1115, }; nslog__log(&_nslog_ctx , "box %p: %s: w: %i, h: %i", flex, success ? "success" : "failure" , flex->width, flex->height); } } while(0); | ||||
1116 | return success; | ||||
1117 | } |
1 | /* | |||
2 | * Copyright 2003 James Bursa <bursa@users.sourceforge.net> | |||
3 | * | |||
4 | * This file is part of NetSurf, http://www.netsurf-browser.org/ | |||
5 | * | |||
6 | * NetSurf is free software; you can redistribute it and/or modify | |||
7 | * it under the terms of the GNU General Public License as published by | |||
8 | * the Free Software Foundation; version 2 of the License. | |||
9 | * | |||
10 | * NetSurf is distributed in the hope that it will be useful, | |||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
13 | * GNU General Public License for more details. | |||
14 | * | |||
15 | * You should have received a copy of the GNU General Public License | |||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
17 | */ | |||
18 | ||||
19 | /** | |||
20 | * \file | |||
21 | * HTML layout private interface. | |||
22 | */ | |||
23 | ||||
24 | #ifndef NETSURF_HTML_LAYOUT_INTERNAL_H | |||
25 | #define NETSURF_HTML_LAYOUT_INTERNAL_H | |||
26 | ||||
27 | #define AUTO(-2147483647 -1) INT_MIN(-2147483647 -1) | |||
28 | ||||
29 | /** | |||
30 | * Layout a block formatting context. | |||
31 | * | |||
32 | * \param block BLOCK, INLINE_BLOCK, or TABLE_CELL to layout | |||
33 | * \param viewport_height Height of viewport in pixels or -ve if unknown | |||
34 | * \param content Memory pool for any new boxes | |||
35 | * \return true on success, false on memory exhaustion | |||
36 | * | |||
37 | * This function carries out layout of a block and its children, as described | |||
38 | * in CSS 2.1 9.4.1. | |||
39 | */ | |||
40 | bool_Bool layout_block_context( | |||
41 | struct box *block, | |||
42 | int viewport_height, | |||
43 | html_content *content); | |||
44 | ||||
45 | /** | |||
46 | * Layout a table. | |||
47 | * | |||
48 | * \param table table to layout | |||
49 | * \param available_width width of containing block | |||
50 | * \param content memory pool for any new boxes | |||
51 | * \return true on success, false on memory exhaustion | |||
52 | */ | |||
53 | bool_Bool layout_table( | |||
54 | struct box *table, | |||
55 | int available_width, | |||
56 | html_content *content); | |||
57 | ||||
58 | /** | |||
59 | * Layout a flex container. | |||
60 | * | |||
61 | * \param[in] flex table to layout | |||
62 | * \param[in] available_width width of containing block | |||
63 | * \param[in] content memory pool for any new boxes | |||
64 | * \return true on success, false on memory exhaustion | |||
65 | */ | |||
66 | bool_Bool layout_flex( | |||
67 | struct box *flex, | |||
68 | int available_width, | |||
69 | html_content *content); | |||
70 | ||||
71 | typedef uint8_t (*css_len_func)( | |||
72 | const css_computed_style *style, | |||
73 | css_fixed *length, css_unit *unit); | |||
74 | typedef uint8_t (*css_border_style_func)( | |||
75 | const css_computed_style *style); | |||
76 | typedef uint8_t (*css_border_color_func)( | |||
77 | const css_computed_style *style, | |||
78 | css_color *color); | |||
79 | ||||
80 | /** Array of per-side access functions for computed style margins. */ | |||
81 | extern const css_len_func margin_funcs[4]; | |||
82 | ||||
83 | /** Array of per-side access functions for computed style paddings. */ | |||
84 | extern const css_len_func padding_funcs[4]; | |||
85 | ||||
86 | /** Array of per-side access functions for computed style border_widths. */ | |||
87 | extern const css_len_func border_width_funcs[4]; | |||
88 | ||||
89 | /** Array of per-side access functions for computed style border styles. */ | |||
90 | extern const css_border_style_func border_style_funcs[4]; | |||
91 | ||||
92 | /** Array of per-side access functions for computed style border colors. */ | |||
93 | extern const css_border_color_func border_color_funcs[4]; | |||
94 | ||||
95 | /** Layout helper: Check whether box is a float. */ | |||
96 | static inline bool_Bool lh__box_is_float_box(const struct box *b) | |||
97 | { | |||
98 | return b->type == BOX_FLOAT_LEFT || | |||
99 | b->type == BOX_FLOAT_RIGHT; | |||
100 | } | |||
101 | ||||
102 | /** Layout helper: Check whether box takes part in inline flow. */ | |||
103 | static inline bool_Bool lh__box_is_inline_flow(const struct box *b) | |||
104 | { | |||
105 | return b->type == BOX_INLINE || | |||
106 | b->type == BOX_INLINE_FLEX || | |||
107 | b->type == BOX_INLINE_BLOCK || | |||
108 | b->type == BOX_TEXT || | |||
109 | b->type == BOX_INLINE_END; | |||
110 | } | |||
111 | ||||
112 | /** Layout helper: Check whether box takes part in inline flow. */ | |||
113 | static inline bool_Bool lh__box_is_flex_container(const struct box *b) | |||
114 | { | |||
115 | return b->type == BOX_FLEX || | |||
116 | b->type == BOX_INLINE_FLEX; | |||
117 | } | |||
118 | ||||
119 | /** Layout helper: Check whether box takes part in inline flow. */ | |||
120 | static inline bool_Bool lh__box_is_flex_item(const struct box *b) | |||
121 | { | |||
122 | return (b->parent != NULL((void*)0)) && lh__box_is_flex_container(b->parent); | |||
123 | } | |||
124 | ||||
125 | /** Layout helper: Check whether box is inline level. (Includes BR.) */ | |||
126 | static inline bool_Bool lh__box_is_inline_level(const struct box *b) | |||
127 | { | |||
128 | return lh__box_is_inline_flow(b) || | |||
129 | b->type == BOX_BR; | |||
130 | } | |||
131 | ||||
132 | /** Layout helper: Check whether box is inline level. (Includes BR, floats.) */ | |||
133 | static inline bool_Bool lh__box_is_inline_content(const struct box *b) | |||
134 | { | |||
135 | return lh__box_is_float_box(b) || | |||
136 | lh__box_is_inline_level(b); | |||
137 | } | |||
138 | ||||
139 | /** Layout helper: Check whether box is an object. */ | |||
140 | static inline bool_Bool lh__box_is_object(const struct box *b) | |||
141 | { | |||
142 | return b->object || | |||
143 | (b->flags & (IFRAME | REPLACE_DIM)); | |||
144 | } | |||
145 | ||||
146 | /** Layout helper: Check whether box is replaced. */ | |||
147 | static inline bool_Bool lh__box_is_replace(const struct box *b) | |||
148 | { | |||
149 | return b->gadget || | |||
150 | lh__box_is_object(b); | |||
151 | } | |||
152 | ||||
153 | /** Layout helper: Check for CSS border on given side. */ | |||
154 | static inline bool_Bool lh__have_border( | |||
155 | enum box_side side, | |||
156 | const css_computed_style *style) | |||
157 | { | |||
158 | return border_style_funcs[side](style) != CSS_BORDER_STYLE_NONE; | |||
159 | } | |||
160 | ||||
161 | static inline bool_Bool lh__box_is_absolute(const struct box *b) | |||
162 | { | |||
163 | return css_computed_position(b->style) == CSS_POSITION_ABSOLUTE || | |||
| ||||
164 | css_computed_position(b->style) == CSS_POSITION_FIXED; | |||
165 | } | |||
166 | ||||
167 | static inline bool_Bool lh__flex_main_is_horizontal(const struct box *flex) | |||
168 | { | |||
169 | const css_computed_style *style = flex->style; | |||
170 | ||||
171 | assert(style != NULL)((style != ((void*)0)) ? (void) (0) : __assert_fail ("style != NULL" , "content/handlers/html/layout_internal.h", 171, __extension__ __PRETTY_FUNCTION__)); | |||
172 | ||||
173 | switch (css_computed_flex_direction(style)) { | |||
174 | default: /* Fallthrough. */ | |||
175 | case CSS_FLEX_DIRECTION_ROW: /* Fallthrough. */ | |||
176 | case CSS_FLEX_DIRECTION_ROW_REVERSE: | |||
177 | return true1; | |||
178 | case CSS_FLEX_DIRECTION_COLUMN: /* Fallthrough. */ | |||
179 | case CSS_FLEX_DIRECTION_COLUMN_REVERSE: | |||
180 | return false0; | |||
181 | } | |||
182 | } | |||
183 | ||||
184 | static inline bool_Bool lh__flex_direction_reversed(const struct box *flex) | |||
185 | { | |||
186 | switch (css_computed_flex_direction(flex->style)) { | |||
187 | default: /* Fallthrough. */ | |||
188 | case CSS_FLEX_DIRECTION_ROW_REVERSE: /* Fallthrough. */ | |||
189 | case CSS_FLEX_DIRECTION_COLUMN_REVERSE: | |||
190 | return true1; | |||
191 | case CSS_FLEX_DIRECTION_ROW: /* Fallthrough. */ | |||
192 | case CSS_FLEX_DIRECTION_COLUMN: | |||
193 | return false0; | |||
194 | } | |||
195 | } | |||
196 | ||||
197 | static inline int lh__non_auto_margin(const struct box *b, enum box_side side) | |||
198 | { | |||
199 | return (b->margin[side] == AUTO(-2147483647 -1)) ? 0 : b->margin[side]; | |||
200 | } | |||
201 | ||||
202 | static inline int lh__delta_outer_height(const struct box *b) | |||
203 | { | |||
204 | return b->padding[TOP] + | |||
205 | b->padding[BOTTOM] + | |||
206 | b->border[TOP].width + | |||
207 | b->border[BOTTOM].width + | |||
208 | lh__non_auto_margin(b, TOP) + | |||
209 | lh__non_auto_margin(b, BOTTOM); | |||
210 | } | |||
211 | ||||
212 | static inline int lh__delta_outer_width(const struct box *b) | |||
213 | { | |||
214 | return b->padding[LEFT] + | |||
215 | b->padding[RIGHT] + | |||
216 | b->border[LEFT].width + | |||
217 | b->border[RIGHT].width + | |||
218 | lh__non_auto_margin(b, LEFT) + | |||
219 | lh__non_auto_margin(b, RIGHT); | |||
220 | } | |||
221 | ||||
222 | static inline int lh__delta_outer_main( | |||
223 | const struct box *flex, | |||
224 | const struct box *b) | |||
225 | { | |||
226 | if (lh__flex_main_is_horizontal(flex)) { | |||
227 | return lh__delta_outer_width(b); | |||
228 | } else { | |||
229 | return lh__delta_outer_height(b); | |||
230 | } | |||
231 | } | |||
232 | ||||
233 | static inline int lh__delta_outer_cross( | |||
234 | const struct box *flex, | |||
235 | const struct box *b) | |||
236 | { | |||
237 | if (lh__flex_main_is_horizontal(flex) == false0) { | |||
238 | return lh__delta_outer_width(b); | |||
239 | } else { | |||
240 | return lh__delta_outer_height(b); | |||
241 | } | |||
242 | } | |||
243 | ||||
244 | static inline int *lh__box_size_main_ptr( | |||
245 | bool_Bool horizontal, | |||
246 | struct box *b) | |||
247 | { | |||
248 | return horizontal ? &b->width : &b->height; | |||
249 | } | |||
250 | ||||
251 | static inline int *lh__box_size_cross_ptr( | |||
252 | bool_Bool horizontal, | |||
253 | struct box *b) | |||
254 | { | |||
255 | return horizontal ? &b->height : &b->width; | |||
256 | } | |||
257 | ||||
258 | static inline int lh__box_size_main( | |||
259 | bool_Bool horizontal, | |||
260 | const struct box *b) | |||
261 | { | |||
262 | return horizontal ? b->width : b->height; | |||
263 | } | |||
264 | ||||
265 | static inline int lh__box_size_cross( | |||
266 | bool_Bool horizontal, | |||
267 | const struct box *b) | |||
268 | { | |||
269 | return horizontal ? b->height : b->width; | |||
270 | } | |||
271 | ||||
272 | static inline bool_Bool lh__box_size_cross_is_auto( | |||
273 | bool_Bool horizontal, | |||
274 | struct box *b) | |||
275 | { | |||
276 | css_fixed length; | |||
277 | css_unit unit; | |||
278 | ||||
279 | if (horizontal) { | |||
280 | return css_computed_height(b->style, | |||
281 | &length, &unit) == CSS_HEIGHT_AUTO; | |||
282 | } else { | |||
283 | return css_computed_width(b->style, | |||
284 | &length, &unit) == CSS_WIDTH_AUTO; | |||
285 | } | |||
286 | } | |||
287 | ||||
288 | static inline enum css_align_self_e lh__box_align_self( | |||
289 | const struct box *flex, | |||
290 | const struct box *item) | |||
291 | { | |||
292 | enum css_align_self_e align_self = css_computed_align_self(item->style); | |||
293 | ||||
294 | if (align_self == CSS_ALIGN_SELF_AUTO) { | |||
295 | align_self = css_computed_align_items(flex->style); | |||
296 | } | |||
297 | ||||
298 | return align_self; | |||
299 | } | |||
300 | ||||
301 | /** | |||
302 | * Determine width of margin, borders, and padding on one side of a box. | |||
303 | * | |||
304 | * \param unit_len_ctx CSS length conversion context for document | |||
305 | * \param style style to measure | |||
306 | * \param side side of box to measure | |||
307 | * \param margin whether margin width is required | |||
308 | * \param border whether border width is required | |||
309 | * \param padding whether padding width is required | |||
310 | * \param fixed increased by sum of fixed margin, border, and padding | |||
311 | * \param frac increased by sum of fractional margin and padding | |||
312 | */ | |||
313 | static inline void calculate_mbp_width( | |||
314 | const css_unit_ctx *unit_len_ctx, | |||
315 | const css_computed_style *style, | |||
316 | unsigned int side, | |||
317 | bool_Bool margin, | |||
318 | bool_Bool border, | |||
319 | bool_Bool padding, | |||
320 | int *fixed, | |||
321 | float *frac) | |||
322 | { | |||
323 | css_fixed value = 0; | |||
324 | css_unit unit = CSS_UNIT_PX; | |||
325 | ||||
326 | assert(style)((style) ? (void) (0) : __assert_fail ("style", "content/handlers/html/layout_internal.h" , 326, __extension__ __PRETTY_FUNCTION__)); | |||
327 | ||||
328 | /* margin */ | |||
329 | if (margin) { | |||
330 | enum css_margin_e type; | |||
331 | ||||
332 | type = margin_funcs[side](style, &value, &unit); | |||
333 | if (type == CSS_MARGIN_SET) { | |||
334 | if (unit == CSS_UNIT_PCT) { | |||
335 | *frac += FIXTOFLT(FDIV(value, F_100))((float) ((css_divide_fixed((value), (0x00019000)))) / (float ) (1 << 10)); | |||
336 | } else { | |||
337 | *fixed += FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
338 | style, unit_len_ctx,((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
339 | value, unit))((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10); | |||
340 | } | |||
341 | } | |||
342 | } | |||
343 | ||||
344 | /* border */ | |||
345 | if (border) { | |||
346 | if (lh__have_border(side, style)) { | |||
347 | border_width_funcs[side](style, &value, &unit); | |||
348 | ||||
349 | *fixed += FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
350 | style, unit_len_ctx,((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
351 | value, unit))((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10); | |||
352 | } | |||
353 | } | |||
354 | ||||
355 | /* padding */ | |||
356 | if (padding) { | |||
357 | padding_funcs[side](style, &value, &unit); | |||
358 | if (unit == CSS_UNIT_PCT) { | |||
359 | *frac += FIXTOFLT(FDIV(value, F_100))((float) ((css_divide_fixed((value), (0x00019000)))) / (float ) (1 << 10)); | |||
360 | } else { | |||
361 | *fixed += FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
362 | style, unit_len_ctx,((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
363 | value, unit))((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10); | |||
364 | } | |||
365 | } | |||
366 | } | |||
367 | ||||
368 | /** | |||
369 | * Adjust a specified width or height for the box-sizing property. | |||
370 | * | |||
371 | * This turns the specified dimension into a content-box dimension. | |||
372 | * | |||
373 | * \param unit_len_ctx Length conversion context | |||
374 | * \param box gadget to adjust dimensions of | |||
375 | * \param available_width width of containing block | |||
376 | * \param setwidth set true if the dimension to be tweaked is a width, | |||
377 | * else set false for a height | |||
378 | * \param dimension current value for given width/height dimension. | |||
379 | * updated to new value after consideration of | |||
380 | * gadget properties. | |||
381 | */ | |||
382 | static inline void layout_handle_box_sizing( | |||
383 | const css_unit_ctx *unit_len_ctx, | |||
384 | const struct box *box, | |||
385 | int available_width, | |||
386 | bool_Bool setwidth, | |||
387 | int *dimension) | |||
388 | { | |||
389 | enum css_box_sizing_e bs; | |||
390 | ||||
391 | assert(box && box->style)((box && box->style) ? (void) (0) : __assert_fail ( "box && box->style", "content/handlers/html/layout_internal.h" , 391, __extension__ __PRETTY_FUNCTION__)); | |||
392 | ||||
393 | bs = css_computed_box_sizing(box->style); | |||
394 | ||||
395 | if (bs == CSS_BOX_SIZING_BORDER_BOX) { | |||
396 | int orig = *dimension; | |||
397 | int fixed = 0; | |||
398 | float frac = 0; | |||
399 | ||||
400 | calculate_mbp_width(unit_len_ctx, box->style, | |||
401 | setwidth ? LEFT : TOP, | |||
402 | false0, true1, true1, &fixed, &frac); | |||
403 | calculate_mbp_width(unit_len_ctx, box->style, | |||
404 | setwidth ? RIGHT : BOTTOM, | |||
405 | false0, true1, true1, &fixed, &frac); | |||
406 | orig -= frac * available_width + fixed; | |||
407 | *dimension = orig > 0 ? orig : 0; | |||
408 | } | |||
409 | } | |||
410 | ||||
411 | /** | |||
412 | * Calculate width, height, and thickness of margins, paddings, and borders. | |||
413 | * | |||
414 | * \param unit_len_ctx Length conversion context | |||
415 | * \param available_width width of containing block | |||
416 | * \param viewport_height height of viewport in pixels or -ve if unknown | |||
417 | * \param box current box | |||
418 | * \param style style giving width, height, margins, paddings, | |||
419 | * and borders | |||
420 | * \param width updated to width, may be NULL | |||
421 | * \param height updated to height, may be NULL | |||
422 | * \param max_width updated to max-width, may be NULL | |||
423 | * \param min_width updated to min-width, may be NULL | |||
424 | * \param max_height updated to max-height, may be NULL | |||
425 | * \param min_height updated to min-height, may be NULL | |||
426 | * \param margin filled with margins, may be NULL | |||
427 | * \param padding filled with paddings, may be NULL | |||
428 | * \param border filled with border widths, may be NULL | |||
429 | */ | |||
430 | static inline void layout_find_dimensions( | |||
431 | const css_unit_ctx *unit_len_ctx, | |||
432 | int available_width, | |||
433 | int viewport_height, | |||
434 | const struct box *box, | |||
435 | const css_computed_style *style, | |||
436 | int *width, | |||
437 | int *height, | |||
438 | int *max_width, | |||
439 | int *min_width, | |||
440 | int *max_height, | |||
441 | int *min_height, | |||
442 | int margin[4], | |||
443 | int padding[4], | |||
444 | struct box_border border[4]) | |||
445 | { | |||
446 | struct box *containing_block = NULL((void*)0); | |||
447 | unsigned int i; | |||
448 | ||||
449 | if (width) { | |||
450 | if (css_computed_width_px(style, unit_len_ctx, | |||
451 | available_width, width) == CSS_WIDTH_SET) { | |||
452 | layout_handle_box_sizing(unit_len_ctx, box, | |||
453 | available_width, true1, width); | |||
454 | } else { | |||
455 | *width = AUTO(-2147483647 -1); | |||
456 | } | |||
457 | } | |||
458 | ||||
459 | if (height) { | |||
460 | enum css_height_e htype; | |||
461 | css_fixed value = 0; | |||
462 | css_unit unit = CSS_UNIT_PX; | |||
463 | ||||
464 | htype = css_computed_height(style, &value, &unit); | |||
465 | ||||
466 | if (htype == CSS_HEIGHT_SET) { | |||
467 | if (unit == CSS_UNIT_PCT) { | |||
468 | enum css_height_e cbhtype; | |||
469 | ||||
470 | if (css_computed_position(box->style) == | |||
471 | CSS_POSITION_ABSOLUTE && | |||
472 | box->parent) { | |||
473 | /* Box is absolutely positioned */ | |||
474 | assert(box->float_container)((box->float_container) ? (void) (0) : __assert_fail ("box->float_container" , "content/handlers/html/layout_internal.h", 474, __extension__ __PRETTY_FUNCTION__)); | |||
475 | containing_block = box->float_container; | |||
476 | } else if (box->float_container && | |||
477 | css_computed_position(box->style) != | |||
478 | CSS_POSITION_ABSOLUTE && | |||
479 | (css_computed_float(box->style) == | |||
480 | CSS_FLOAT_LEFT || | |||
481 | css_computed_float(box->style) == | |||
482 | CSS_FLOAT_RIGHT)) { | |||
483 | /* Box is a float */ | |||
484 | assert(box->parent &&((box->parent && box->parent->parent && box->parent->parent->parent) ? (void) (0) : __assert_fail ("box->parent && box->parent->parent && box->parent->parent->parent" , "content/handlers/html/layout_internal.h", 486, __extension__ __PRETTY_FUNCTION__)) | |||
485 | box->parent->parent &&((box->parent && box->parent->parent && box->parent->parent->parent) ? (void) (0) : __assert_fail ("box->parent && box->parent->parent && box->parent->parent->parent" , "content/handlers/html/layout_internal.h", 486, __extension__ __PRETTY_FUNCTION__)) | |||
486 | box->parent->parent->parent)((box->parent && box->parent->parent && box->parent->parent->parent) ? (void) (0) : __assert_fail ("box->parent && box->parent->parent && box->parent->parent->parent" , "content/handlers/html/layout_internal.h", 486, __extension__ __PRETTY_FUNCTION__)); | |||
487 | ||||
488 | containing_block = | |||
489 | box->parent->parent->parent; | |||
490 | } else if (box->parent && box->parent->type != | |||
491 | BOX_INLINE_CONTAINER) { | |||
492 | /* Box is a block level element */ | |||
493 | containing_block = box->parent; | |||
494 | } else if (box->parent && box->parent->type == | |||
495 | BOX_INLINE_CONTAINER) { | |||
496 | /* Box is an inline block */ | |||
497 | assert(box->parent->parent)((box->parent->parent) ? (void) (0) : __assert_fail ("box->parent->parent" , "content/handlers/html/layout_internal.h", 497, __extension__ __PRETTY_FUNCTION__)); | |||
498 | containing_block = box->parent->parent; | |||
499 | } | |||
500 | ||||
501 | if (containing_block) { | |||
502 | css_fixed f = 0; | |||
503 | css_unit u = CSS_UNIT_PX; | |||
504 | ||||
505 | cbhtype = css_computed_height( | |||
506 | containing_block->style, | |||
507 | &f, &u); | |||
508 | } | |||
509 | ||||
510 | if (containing_block && | |||
511 | containing_block->height != AUTO(-2147483647 -1) && | |||
512 | (css_computed_position(box->style) == | |||
513 | CSS_POSITION_ABSOLUTE || | |||
514 | cbhtype == CSS_HEIGHT_SET)) { | |||
515 | /* Box is absolutely positioned or its | |||
516 | * containing block has a valid | |||
517 | * specified height. | |||
518 | * (CSS 2.1 Section 10.5) */ | |||
519 | *height = FPCT_OF_INT_TOINT(value,((((css_divide_fixed(((value * containing_block->height)), (0x00019000)))) >> 10)) | |||
520 | containing_block->height)((((css_divide_fixed(((value * containing_block->height)), (0x00019000)))) >> 10)); | |||
521 | } else if ((!box->parent || | |||
522 | !box->parent->parent) && | |||
523 | viewport_height >= 0) { | |||
524 | /* If root element or it's child | |||
525 | * (HTML or BODY) */ | |||
526 | *height = FPCT_OF_INT_TOINT(value,((((css_divide_fixed(((value * viewport_height)), (0x00019000 )))) >> 10)) | |||
527 | viewport_height)((((css_divide_fixed(((value * viewport_height)), (0x00019000 )))) >> 10)); | |||
528 | } else { | |||
529 | /* precentage height not permissible | |||
530 | * treat height as auto */ | |||
531 | *height = AUTO(-2147483647 -1); | |||
532 | } | |||
533 | } else { | |||
534 | *height = FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
535 | style, unit_len_ctx,((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
536 | value, unit))((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10); | |||
537 | } | |||
538 | } else { | |||
539 | *height = AUTO(-2147483647 -1); | |||
540 | } | |||
541 | ||||
542 | if (*height != AUTO(-2147483647 -1)) { | |||
543 | layout_handle_box_sizing(unit_len_ctx, box, | |||
544 | available_width, false0, height); | |||
545 | } | |||
546 | } | |||
547 | ||||
548 | if (max_width) { | |||
549 | enum css_max_width_e type; | |||
550 | css_fixed value = 0; | |||
551 | css_unit unit = CSS_UNIT_PX; | |||
552 | ||||
553 | type = css_computed_max_width(style, &value, &unit); | |||
554 | ||||
555 | if (type == CSS_MAX_WIDTH_SET) { | |||
556 | if (unit == CSS_UNIT_PCT) { | |||
557 | *max_width = FPCT_OF_INT_TOINT(value,((((css_divide_fixed(((value * available_width)), (0x00019000 )))) >> 10)) | |||
558 | available_width)((((css_divide_fixed(((value * available_width)), (0x00019000 )))) >> 10)); | |||
559 | } else { | |||
560 | *max_width = FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
561 | style, unit_len_ctx,((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
562 | value, unit))((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10); | |||
563 | } | |||
564 | } else { | |||
565 | /* Inadmissible */ | |||
566 | *max_width = -1; | |||
567 | } | |||
568 | ||||
569 | if (*max_width != -1) { | |||
570 | layout_handle_box_sizing(unit_len_ctx, box, | |||
571 | available_width, true1, max_width); | |||
572 | } | |||
573 | } | |||
574 | ||||
575 | if (min_width) { | |||
576 | enum css_min_width_e type; | |||
577 | css_fixed value = 0; | |||
578 | css_unit unit = CSS_UNIT_PX; | |||
579 | ||||
580 | type = ns_computed_min_width(style, &value, &unit); | |||
581 | ||||
582 | if (type == CSS_MIN_WIDTH_SET) { | |||
583 | if (unit == CSS_UNIT_PCT) { | |||
584 | *min_width = FPCT_OF_INT_TOINT(value,((((css_divide_fixed(((value * available_width)), (0x00019000 )))) >> 10)) | |||
585 | available_width)((((css_divide_fixed(((value * available_width)), (0x00019000 )))) >> 10)); | |||
586 | } else { | |||
587 | *min_width = FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
588 | style, unit_len_ctx,((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
589 | value, unit))((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10); | |||
590 | } | |||
591 | } else { | |||
592 | /* Inadmissible */ | |||
593 | *min_width = 0; | |||
594 | } | |||
595 | ||||
596 | if (*min_width != 0) { | |||
597 | layout_handle_box_sizing(unit_len_ctx, box, | |||
598 | available_width, true1, min_width); | |||
599 | } | |||
600 | } | |||
601 | ||||
602 | if (max_height) { | |||
603 | enum css_max_height_e type; | |||
604 | css_fixed value = 0; | |||
605 | css_unit unit = CSS_UNIT_PX; | |||
606 | ||||
607 | type = css_computed_max_height(style, &value, &unit); | |||
608 | ||||
609 | if (type == CSS_MAX_HEIGHT_SET) { | |||
610 | if (unit == CSS_UNIT_PCT) { | |||
611 | /* TODO: handle percentage */ | |||
612 | *max_height = -1; | |||
613 | } else { | |||
614 | *max_height = FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
615 | style, unit_len_ctx,((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
616 | value, unit))((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10); | |||
617 | } | |||
618 | } else { | |||
619 | /* Inadmissible */ | |||
620 | *max_height = -1; | |||
621 | } | |||
622 | } | |||
623 | ||||
624 | if (min_height) { | |||
625 | enum css_min_height_e type; | |||
626 | css_fixed value = 0; | |||
627 | css_unit unit = CSS_UNIT_PX; | |||
628 | ||||
629 | type = ns_computed_min_height(style, &value, &unit); | |||
630 | ||||
631 | if (type == CSS_MIN_HEIGHT_SET) { | |||
632 | if (unit == CSS_UNIT_PCT) { | |||
633 | /* TODO: handle percentage */ | |||
634 | *min_height = 0; | |||
635 | } else { | |||
636 | *min_height = FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
637 | style, unit_len_ctx,((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
638 | value, unit))((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10); | |||
639 | } | |||
640 | } else { | |||
641 | /* Inadmissible */ | |||
642 | *min_height = 0; | |||
643 | } | |||
644 | } | |||
645 | ||||
646 | for (i = 0; i != 4; i++) { | |||
647 | if (margin) { | |||
648 | enum css_margin_e type = CSS_MARGIN_AUTO; | |||
649 | css_fixed value = 0; | |||
650 | css_unit unit = CSS_UNIT_PX; | |||
651 | ||||
652 | type = margin_funcs[i](style, &value, &unit); | |||
653 | ||||
654 | if (type == CSS_MARGIN_SET) { | |||
655 | if (unit == CSS_UNIT_PCT) { | |||
656 | margin[i] = FPCT_OF_INT_TOINT(value,((((css_divide_fixed(((value * available_width)), (0x00019000 )))) >> 10)) | |||
657 | available_width)((((css_divide_fixed(((value * available_width)), (0x00019000 )))) >> 10)); | |||
658 | } else { | |||
659 | margin[i] = FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
660 | style, unit_len_ctx,((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
661 | value, unit))((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10); | |||
662 | } | |||
663 | } else { | |||
664 | margin[i] = AUTO(-2147483647 -1); | |||
665 | } | |||
666 | } | |||
667 | ||||
668 | if (padding) { | |||
669 | css_fixed value = 0; | |||
670 | css_unit unit = CSS_UNIT_PX; | |||
671 | ||||
672 | padding_funcs[i](style, &value, &unit); | |||
673 | ||||
674 | if (unit == CSS_UNIT_PCT) { | |||
675 | padding[i] = FPCT_OF_INT_TOINT(value,((((css_divide_fixed(((value * available_width)), (0x00019000 )))) >> 10)) | |||
676 | available_width)((((css_divide_fixed(((value * available_width)), (0x00019000 )))) >> 10)); | |||
677 | } else { | |||
678 | padding[i] = FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
679 | style, unit_len_ctx,((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
680 | value, unit))((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10); | |||
681 | } | |||
682 | } | |||
683 | ||||
684 | /* Table cell borders are populated in table.c */ | |||
685 | if (border && box->type != BOX_TABLE_CELL) { | |||
686 | enum css_border_style_e bstyle = CSS_BORDER_STYLE_NONE; | |||
687 | css_color color = 0; | |||
688 | css_fixed value = 0; | |||
689 | css_unit unit = CSS_UNIT_PX; | |||
690 | ||||
691 | border_width_funcs[i](style, &value, &unit); | |||
692 | bstyle = border_style_funcs[i](style); | |||
693 | border_color_funcs[i](style, &color); | |||
694 | ||||
695 | border[i].style = bstyle; | |||
696 | border[i].c = color; | |||
697 | ||||
698 | if (bstyle == CSS_BORDER_STYLE_HIDDEN || | |||
699 | bstyle == CSS_BORDER_STYLE_NONE) | |||
700 | /* spec unclear: following Mozilla */ | |||
701 | border[i].width = 0; | |||
702 | else | |||
703 | border[i].width = FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
704 | style, unit_len_ctx,((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10) | |||
705 | value, unit))((css_unit_len2device_px( style, unit_len_ctx, value, unit)) >> 10); | |||
706 | ||||
707 | /* Special case for border-collapse: make all borders | |||
708 | * on table/table-row-group/table-row zero width. */ | |||
709 | if (css_computed_border_collapse(style) == | |||
710 | CSS_BORDER_COLLAPSE_COLLAPSE && | |||
711 | (box->type == BOX_TABLE || | |||
712 | box->type == BOX_TABLE_ROW_GROUP || | |||
713 | box->type == BOX_TABLE_ROW)) | |||
714 | border[i].width = 0; | |||
715 | } | |||
716 | } | |||
717 | } | |||
718 | ||||
719 | #endif |