Bug Summary

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')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name layout_flex.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/var/lib/jenkins/workspace/scan-build-netsurf -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -I . -I include -I build/Linux-gtk2 -I frontends -I content/handlers -D WITH_JPEG -U WITH_PDF_EXPORT -D LIBICONV_PLUG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /usr/include/x86_64-linux-gnu -D WITH_CURL -D WITH_OPENSSL -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D UTF8PROC_EXPORTS -D WITH_UTF8PROC -D WITH_WEBP -I /usr/include/libpng16 -D WITH_PNG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include/ -D WITH_BMP -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_GIF -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NS_SVG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSSPRITE -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSPSL -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSLOG -D NETSURF_UA_FORMAT_STRING="Mozilla/5.0 (%s) NetSurf/%d.%d" -D NETSURF_HOMEPAGE="about:welcome" -D NETSURF_LOG_LEVEL=VERBOSE -D NETSURF_BUILTIN_LOG_FILTER="(level:WARNING || cat:jserrors)" -D NETSURF_BUILTIN_VERBOSE_FILTER="(level:VERBOSE || cat:jserrors)" -D STMTEXPR=1 -I /usr/include/librsvg-2.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/libpng16 -I /usr/include/x86_64-linux-gnu -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/freetype2 -D WITH_RSVG -I /usr/include/gtk-2.0 -I /usr/lib/x86_64-linux-gnu/gtk-2.0/include -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/atk-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -D gtk -D nsgtk -D G_DISABLE_SINGLE_INCLUDES -D G_DISABLE_DEPRECATED -D GTK_DISABLE_SINGLE_INCLUDES -D GTK_MULTIHEAD_SAFE -D PANGO_DISABLE_DEPRECATED -D GTK_DISABLE_DEPRECATED -D _XOPEN_SOURCE=700 -D _POSIX_C_SOURCE=200809L -D _BSD_SOURCE -D _DEFAULT_SOURCE -D _NETBSD_SOURCE -D GTK_RESPATH="/var/lib/jenkins/artifacts-x86_64-linux-gnu/share/netsurf/:./frontends/gtk/res/" -D WITH_GRESOURCE -D DUK_OPT_HAVE_CUSTOM_H -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wwrite-strings -Wno-unused-parameter -Wno-unused-but-set-variable -std=c99 -fconst-strings -fdebug-compilation-dir=/var/lib/jenkins/workspace/scan-build-netsurf -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-display-progress -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/lib/jenkins/workspace/scan-build-netsurf/clangScanBuildReports/2024-09-22-162811-2804354-1 -x c content/handlers/html/layout_flex.c

content/handlers/html/layout_flex.c

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 */
48struct 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 */
75struct 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 */
92struct 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 */
124static 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 */
140static 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)) {
4
Assuming 'ctx' is not equal to NULL
5
Taking false branch
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));
6
Null pointer value stored to field 'box'
154 if (ctx->item.data == NULL((void*)0)) {
7
Assuming field 'data' is not equal to NULL
8
Taking false branch
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)) {
9
Assuming field 'data' is not equal to NULL
10
Taking false branch
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);
11
Calling 'lh__flex_main_is_horizontal'
16
Returning from 'lh__flex_main_is_horizontal'
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 */
183static 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 */
199static 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 */
217static 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) {
1
Control jumps to 'case BOX_FLEX:' at line 234
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);
2
Calling 'layout_flex'
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 */
260static 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 */
343static 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 */
384static 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
31.1
Field 'alloc' is > field 'count'
31.1
Field 'alloc' is > field 'count'
> ctx->line.count) {
32
Taking true branch
390 return true1;
33
Returning without writing to 'ctx->horizontal', which participates in a condition later
34
Returning the value 1, which participates in a condition later
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 */
413static 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)) {
31
Calling 'layout_flex_ctx__ensure_line'
35
Returning from 'layout_flex_ctx__ensure_line'
36
Taking false branch
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)
37
Taking false branch
38
Loop condition is false. Exiting loop
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) {
39
Loop condition is true. Entering loop body
432 struct flex_item_data *item = &ctx->item.data[item_index];
433 struct box *b = item->box;
40
'b' initialized to a null pointer value
434 int pos_main;
435
436 pos_main = ctx->horizontal
40.1
Field 'horizontal' is false
40.1
Field 'horizontal' is false
?
41
'?' condition is false
437 item->main_size :
438 b->height + lh__delta_outer_main(ctx->flex, b);
42
Access to field 'height' results in a dereference of a null pointer (loaded from variable '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 */
480static 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 */
507static 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 */
555static 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 */
622static 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 */
706static 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 */
805static 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 */
898static 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) {
29
Loop condition is true. Entering loop body
904 struct flex_line_data *line;
905
906 line = layout_flex__build_line(ctx, pos);
30
Calling 'layout_flex__build_line'
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 */
942static 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 */
1003static 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 */
1046bool_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);
3
Calling 'layout_flex_ctx__create'
17
Returning from 'layout_flex_ctx__create'
1054 if (ctx
17.1
'ctx' is not equal to NULL
17.1
'ctx' is not equal to NULL
== NULL((void*)0)) {
18
Taking false branch
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)
19
Taking false branch
20
Loop condition is false. Exiting loop
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))
;
21
Assuming 'available_width' is < field 'width'
22
'?' condition is true
1069
1070 if (ctx->horizontal
22.1
Field 'horizontal' is false
22.1
Field 'horizontal' is false
) {
23
Taking false branch
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)
24
Taking false branch
25
Loop condition is false. Exiting loop
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)
26
Taking false branch
27
Loop condition is false. Exiting loop
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);
28
Calling 'layout_flex__collect_items_into_lines'
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
1110cleanup:
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}

content/handlers/html/layout_internal.h

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 */
40bool_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 */
53bool_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 */
66bool_Bool layout_flex(
67 struct box *flex,
68 int available_width,
69 html_content *content);
70
71typedef uint8_t (*css_len_func)(
72 const css_computed_style *style,
73 css_fixed *length, css_unit *unit);
74typedef uint8_t (*css_border_style_func)(
75 const css_computed_style *style);
76typedef 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. */
81extern const css_len_func margin_funcs[4];
82
83/** Array of per-side access functions for computed style paddings. */
84extern const css_len_func padding_funcs[4];
85
86/** Array of per-side access functions for computed style border_widths. */
87extern const css_len_func border_width_funcs[4];
88
89/** Array of per-side access functions for computed style border styles. */
90extern const css_border_style_func border_style_funcs[4];
91
92/** Array of per-side access functions for computed style border colors. */
93extern const css_border_color_func border_color_funcs[4];
94
95/** Layout helper: Check whether box is a float. */
96static 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. */
103static 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. */
113static 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. */
120static 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.) */
126static 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.) */
133static 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. */
140static 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. */
147static 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. */
154static 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
161static 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
167static 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__))
;
12
Assuming 'style' is not equal to null
13
'?' condition is true
172
173 switch (css_computed_flex_direction(style)) {
14
Control jumps to 'case CSS_FLEX_DIRECTION_COLUMN_REVERSE:' at line 179
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;
15
Returning zero, which participates in a condition later
181 }
182}
183
184static 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
197static 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
202static 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
212static 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
222static 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
233static 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
244static 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
251static 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
258static 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
265static 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
272static 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
288static 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 */
313static 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 */
382static 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 */
430static 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