File: | content/handlers/html/layout_flex.c |
Warning: | line 438, column 5 Access to field 'height' 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 |