2 * Copyright (c) 2014, Facebook, Inc.
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
15 // in concatenated header, don't include Layout.h it's already at the top
16 #ifndef CSS_LAYOUT_IMPLEMENTATION
24 /* define fmaxf if < VC12 */
26 __forceinline const float fmaxf(const float a, const float b) {
27 return (a > b) ? a : b;
32 bool isUndefined(float value) {
36 static bool eq(float a, float b) {
38 return isUndefined(b);
40 return fabs(a - b) < 0.0001;
43 void init_css_node(css_node_t *node) {
44 node->style.align_items = CSS_ALIGN_STRETCH;
45 node->style.align_content = CSS_ALIGN_FLEX_START;
47 node->style.direction = CSS_DIRECTION_INHERIT;
48 node->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN;
50 // Some of the fields default to undefined and not 0
51 node->style.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
52 node->style.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
54 node->style.minDimensions[CSS_WIDTH] = CSS_UNDEFINED;
55 node->style.minDimensions[CSS_HEIGHT] = CSS_UNDEFINED;
57 node->style.maxDimensions[CSS_WIDTH] = CSS_UNDEFINED;
58 node->style.maxDimensions[CSS_HEIGHT] = CSS_UNDEFINED;
60 node->style.position[CSS_LEFT] = CSS_UNDEFINED;
61 node->style.position[CSS_TOP] = CSS_UNDEFINED;
62 node->style.position[CSS_RIGHT] = CSS_UNDEFINED;
63 node->style.position[CSS_BOTTOM] = CSS_UNDEFINED;
65 node->style.margin[CSS_START] = CSS_UNDEFINED;
66 node->style.margin[CSS_END] = CSS_UNDEFINED;
67 node->style.padding[CSS_START] = CSS_UNDEFINED;
68 node->style.padding[CSS_END] = CSS_UNDEFINED;
69 node->style.border[CSS_START] = CSS_UNDEFINED;
70 node->style.border[CSS_END] = CSS_UNDEFINED;
72 node->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
73 node->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
75 // Such that the comparison is always going to be false
76 node->layout.last_requested_dimensions[CSS_WIDTH] = -1;
77 node->layout.last_requested_dimensions[CSS_HEIGHT] = -1;
78 node->layout.last_parent_max_width = -1;
79 node->layout.last_parent_max_height = -1;
80 node->layout.last_direction = (css_direction_t)-1;
81 node->layout.should_update = true;
84 css_node_t *new_css_node() {
85 css_node_t *node = (css_node_t *)calloc(1, sizeof(*node));
90 void free_css_node(css_node_t *node) {
94 static void indent(int n) {
96 for (i = 0; i < n; ++i) {
101 static void print_number_0(const char *str, float number) {
102 if (!eq(number, 0)) {
103 printf("%s: %g, ", str, number);
107 static void print_number_nan(const char *str, float number) {
108 if (!isnan(number)) {
109 printf("%s: %g, ", str, number);
113 static bool four_equal(float four[4]) {
115 eq(four[0], four[1]) &&
116 eq(four[0], four[2]) &&
117 eq(four[0], four[3]);
121 static void print_css_node_rec(
123 css_print_options_t options,
130 node->print(node->context);
133 if (options & CSS_PRINT_LAYOUT) {
135 printf("width: %g, ", node->layout.dimensions[CSS_WIDTH]);
136 printf("height: %g, ", node->layout.dimensions[CSS_HEIGHT]);
137 printf("top: %g, ", node->layout.position[CSS_TOP]);
138 printf("left: %g", node->layout.position[CSS_LEFT]);
142 if (options & CSS_PRINT_STYLE) {
143 if (node->style.direction == CSS_DIRECTION_INHERIT) {
144 printf("direction: 'inherit', ");
145 } else if (node->style.direction == CSS_DIRECTION_LTR) {
146 printf("direction: 'LTR', ");
147 } else if (node->style.direction == CSS_DIRECTION_RTL) {
148 printf("direction: 'RTL', ");
151 if (node->style.flex_direction == CSS_FLEX_DIRECTION_COLUMN) {
152 printf("flexDirection: 'column', ");
153 } else if (node->style.flex_direction == CSS_FLEX_DIRECTION_COLUMN_REVERSE) {
154 printf("flexDirection: 'columnReverse', ");
155 } else if (node->style.flex_direction == CSS_FLEX_DIRECTION_ROW) {
156 printf("flexDirection: 'row', ");
157 } else if (node->style.flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE) {
158 printf("flexDirection: 'rowReverse', ");
161 if (node->style.justify_content == CSS_JUSTIFY_FLEX_START) {
162 printf("justifyContent: 'flex-start', ");
163 } else if (node->style.justify_content == CSS_JUSTIFY_CENTER) {
164 printf("justifyContent: 'center', ");
165 } else if (node->style.justify_content == CSS_JUSTIFY_FLEX_END) {
166 printf("justifyContent: 'flex-end', ");
167 } else if (node->style.justify_content == CSS_JUSTIFY_SPACE_AROUND) {
168 printf("justifyContent: 'space-around', ");
169 } else if (node->style.justify_content == CSS_JUSTIFY_SPACE_BETWEEN) {
170 printf("justifyContent: 'space-between', ");
173 if (node->style.align_items == CSS_ALIGN_FLEX_START) {
174 printf("alignItems: 'flex-start', ");
175 } else if (node->style.align_items == CSS_ALIGN_CENTER) {
176 printf("alignItems: 'center', ");
177 } else if (node->style.align_items == CSS_ALIGN_FLEX_END) {
178 printf("alignItems: 'flex-end', ");
179 } else if (node->style.align_items == CSS_ALIGN_STRETCH) {
180 printf("alignItems: 'stretch', ");
183 if (node->style.align_content == CSS_ALIGN_FLEX_START) {
184 printf("alignContent: 'flex-start', ");
185 } else if (node->style.align_content == CSS_ALIGN_CENTER) {
186 printf("alignContent: 'center', ");
187 } else if (node->style.align_content == CSS_ALIGN_FLEX_END) {
188 printf("alignContent: 'flex-end', ");
189 } else if (node->style.align_content == CSS_ALIGN_STRETCH) {
190 printf("alignContent: 'stretch', ");
193 if (node->style.align_self == CSS_ALIGN_FLEX_START) {
194 printf("alignSelf: 'flex-start', ");
195 } else if (node->style.align_self == CSS_ALIGN_CENTER) {
196 printf("alignSelf: 'center', ");
197 } else if (node->style.align_self == CSS_ALIGN_FLEX_END) {
198 printf("alignSelf: 'flex-end', ");
199 } else if (node->style.align_self == CSS_ALIGN_STRETCH) {
200 printf("alignSelf: 'stretch', ");
201 } else if (node->style.align_self == CSS_ALIGN_AUTO) {
202 printf("alignSelf: 'auto', ");
205 if (node->style.flex_wrap == CSS_NOWRAP) {
206 printf("flexWrap: 'no-wrap', ");
207 } else if (node->style.flex_wrap == CSS_WRAP) {
208 printf("flexWrap: 'wrap', ");
211 print_number_nan("flex", node->style.flex);
213 if (four_equal(node->style.margin)) {
214 print_number_0("margin", node->style.margin[CSS_LEFT]);
216 print_number_0("marginLeft", node->style.margin[CSS_LEFT]);
217 print_number_0("marginRight", node->style.margin[CSS_RIGHT]);
218 print_number_0("marginTop", node->style.margin[CSS_TOP]);
219 print_number_0("marginBottom", node->style.margin[CSS_BOTTOM]);
220 print_number_0("marginStart", node->style.margin[CSS_START]);
221 print_number_0("marginEnd", node->style.margin[CSS_END]);
224 if (four_equal(node->style.padding)) {
225 print_number_0("padding", node->style.margin[CSS_LEFT]);
227 print_number_0("paddingLeft", node->style.padding[CSS_LEFT]);
228 print_number_0("paddingRight", node->style.padding[CSS_RIGHT]);
229 print_number_0("paddingTop", node->style.padding[CSS_TOP]);
230 print_number_0("paddingBottom", node->style.padding[CSS_BOTTOM]);
231 print_number_0("paddingStart", node->style.padding[CSS_START]);
232 print_number_0("paddingEnd", node->style.padding[CSS_END]);
235 if (four_equal(node->style.border)) {
236 print_number_0("borderWidth", node->style.border[CSS_LEFT]);
238 print_number_0("borderLeftWidth", node->style.border[CSS_LEFT]);
239 print_number_0("borderRightWidth", node->style.border[CSS_RIGHT]);
240 print_number_0("borderTopWidth", node->style.border[CSS_TOP]);
241 print_number_0("borderBottomWidth", node->style.border[CSS_BOTTOM]);
242 print_number_0("borderStartWidth", node->style.border[CSS_START]);
243 print_number_0("borderEndWidth", node->style.border[CSS_END]);
246 print_number_nan("width", node->style.dimensions[CSS_WIDTH]);
247 print_number_nan("height", node->style.dimensions[CSS_HEIGHT]);
249 if(node->style.minDimensions[CSS_WIDTH] != CSS_UNDEFINED) {
250 print_number_nan("minWidth", node->style.minDimensions[CSS_WIDTH]);
252 if(node->style.minDimensions[CSS_HEIGHT] != CSS_UNDEFINED) {
253 print_number_nan("minHeight", node->style.minDimensions[CSS_HEIGHT]);
255 if(node->style.maxDimensions[CSS_WIDTH] != CSS_UNDEFINED) {
256 print_number_nan("maxWidth", node->style.maxDimensions[CSS_WIDTH]);
258 if(node->style.maxDimensions[CSS_HEIGHT] != CSS_UNDEFINED) {
259 print_number_nan("maxHeight", node->style.maxDimensions[CSS_HEIGHT]);
262 if (node->style.position_type == CSS_POSITION_ABSOLUTE) {
263 printf("position: 'absolute', ");
265 else if (node->style.position_type == CSS_POSITION_RELATIVE) {
266 printf("position: 'relative', ");
269 print_number_nan("position-left", node->style.position[CSS_LEFT]);
270 print_number_nan("position-right", node->style.position[CSS_RIGHT]);
271 print_number_nan("position-top", node->style.position[CSS_TOP]);
272 print_number_nan("position-bottom", node->style.position[CSS_BOTTOM]);
275 if (options & CSS_PRINT_CHILDREN && node->children_count > 0) {
276 printf("children: [\n");
278 for (i = 0; i < node->children_count; ++i) {
279 print_css_node_rec(node->get_child(node->context, i), options, level + 1);
288 void print_css_node(css_node_t *node, css_print_options_t options) {
289 print_css_node_rec(node, options, 0);
293 static css_position_t leading[4] = {
294 /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_TOP,
295 /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_BOTTOM,
296 /* CSS_FLEX_DIRECTION_ROW = */ CSS_LEFT,
297 /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_RIGHT
299 static css_position_t trailing[4] = {
300 /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_BOTTOM,
301 /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_TOP,
302 /* CSS_FLEX_DIRECTION_ROW = */ CSS_RIGHT,
303 /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_LEFT
305 static css_position_t pos[4] = {
306 /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_TOP,
307 /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_BOTTOM,
308 /* CSS_FLEX_DIRECTION_ROW = */ CSS_LEFT,
309 /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_RIGHT
311 static css_dimension_t dim[4] = {
312 /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_HEIGHT,
313 /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_HEIGHT,
314 /* CSS_FLEX_DIRECTION_ROW = */ CSS_WIDTH,
315 /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_WIDTH
318 static bool isRowDirection(css_flex_direction_t flex_direction) {
319 return flex_direction == CSS_FLEX_DIRECTION_ROW ||
320 flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE;
323 static bool isColumnDirection(css_flex_direction_t flex_direction) {
324 return flex_direction == CSS_FLEX_DIRECTION_COLUMN ||
325 flex_direction == CSS_FLEX_DIRECTION_COLUMN_REVERSE;
328 static float getLeadingMargin(css_node_t *node, css_flex_direction_t axis) {
329 if (isRowDirection(axis) && !isUndefined(node->style.margin[CSS_START])) {
330 return node->style.margin[CSS_START];
333 return node->style.margin[leading[axis]];
336 static float getTrailingMargin(css_node_t *node, css_flex_direction_t axis) {
337 if (isRowDirection(axis) && !isUndefined(node->style.margin[CSS_END])) {
338 return node->style.margin[CSS_END];
341 return node->style.margin[trailing[axis]];
344 static float getLeadingPadding(css_node_t *node, css_flex_direction_t axis) {
345 if (isRowDirection(axis) &&
346 !isUndefined(node->style.padding[CSS_START]) &&
347 node->style.padding[CSS_START] >= 0) {
348 return node->style.padding[CSS_START];
351 if (node->style.padding[leading[axis]] >= 0) {
352 return node->style.padding[leading[axis]];
358 static float getTrailingPadding(css_node_t *node, css_flex_direction_t axis) {
359 if (isRowDirection(axis) &&
360 !isUndefined(node->style.padding[CSS_END]) &&
361 node->style.padding[CSS_END] >= 0) {
362 return node->style.padding[CSS_END];
365 if (node->style.padding[trailing[axis]] >= 0) {
366 return node->style.padding[trailing[axis]];
372 static float getLeadingBorder(css_node_t *node, css_flex_direction_t axis) {
373 if (isRowDirection(axis) &&
374 !isUndefined(node->style.border[CSS_START]) &&
375 node->style.border[CSS_START] >= 0) {
376 return node->style.border[CSS_START];
379 if (node->style.border[leading[axis]] >= 0) {
380 return node->style.border[leading[axis]];
386 static float getTrailingBorder(css_node_t *node, css_flex_direction_t axis) {
387 if (isRowDirection(axis) &&
388 !isUndefined(node->style.border[CSS_END]) &&
389 node->style.border[CSS_END] >= 0) {
390 return node->style.border[CSS_END];
393 if (node->style.border[trailing[axis]] >= 0) {
394 return node->style.border[trailing[axis]];
400 static float getLeadingPaddingAndBorder(css_node_t *node, css_flex_direction_t axis) {
401 return getLeadingPadding(node, axis) + getLeadingBorder(node, axis);
404 static float getTrailingPaddingAndBorder(css_node_t *node, css_flex_direction_t axis) {
405 return getTrailingPadding(node, axis) + getTrailingBorder(node, axis);
408 static float getBorderAxis(css_node_t *node, css_flex_direction_t axis) {
409 return getLeadingBorder(node, axis) + getTrailingBorder(node, axis);
412 static float getMarginAxis(css_node_t *node, css_flex_direction_t axis) {
413 return getLeadingMargin(node, axis) + getTrailingMargin(node, axis);
416 static float getPaddingAndBorderAxis(css_node_t *node, css_flex_direction_t axis) {
417 return getLeadingPaddingAndBorder(node, axis) + getTrailingPaddingAndBorder(node, axis);
420 static css_align_t getAlignItem(css_node_t *node, css_node_t *child) {
421 if (child->style.align_self != CSS_ALIGN_AUTO) {
422 return child->style.align_self;
424 return node->style.align_items;
427 static css_direction_t resolveDirection(css_node_t *node, css_direction_t parentDirection) {
428 css_direction_t direction = node->style.direction;
430 if (direction == CSS_DIRECTION_INHERIT) {
431 direction = parentDirection > CSS_DIRECTION_INHERIT ? parentDirection : CSS_DIRECTION_LTR;
437 static css_flex_direction_t getFlexDirection(css_node_t *node) {
438 return node->style.flex_direction;
441 static css_flex_direction_t resolveAxis(css_flex_direction_t flex_direction, css_direction_t direction) {
442 if (direction == CSS_DIRECTION_RTL) {
443 if (flex_direction == CSS_FLEX_DIRECTION_ROW) {
444 return CSS_FLEX_DIRECTION_ROW_REVERSE;
445 } else if (flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE) {
446 return CSS_FLEX_DIRECTION_ROW;
450 return flex_direction;
453 static css_flex_direction_t getCrossFlexDirection(css_flex_direction_t flex_direction, css_direction_t direction) {
454 if (isColumnDirection(flex_direction)) {
455 return resolveAxis(CSS_FLEX_DIRECTION_ROW, direction);
457 return CSS_FLEX_DIRECTION_COLUMN;
461 static float getFlex(css_node_t *node) {
462 return node->style.flex;
465 static bool isFlex(css_node_t *node) {
467 node->style.position_type == CSS_POSITION_RELATIVE &&
472 static bool isFlexWrap(css_node_t *node) {
473 return node->style.flex_wrap == CSS_WRAP;
476 static float getDimWithMargin(css_node_t *node, css_flex_direction_t axis) {
477 return node->layout.dimensions[dim[axis]] +
478 getLeadingMargin(node, axis) +
479 getTrailingMargin(node, axis);
482 static bool isStyleDimDefined(css_node_t *node, css_flex_direction_t axis) {
483 float value = node->style.dimensions[dim[axis]];
484 return !isUndefined(value) && value >= 0.0;
487 static bool isLayoutDimDefined(css_node_t *node, css_flex_direction_t axis) {
488 float value = node->layout.dimensions[dim[axis]];
489 return !isUndefined(value) && value >= 0.0;
492 static bool isPosDefined(css_node_t *node, css_position_t position) {
493 return !isUndefined(node->style.position[position]);
496 static bool isMeasureDefined(css_node_t *node) {
497 return node->measure;
500 static float getPosition(css_node_t *node, css_position_t position) {
501 float result = node->style.position[position];
502 if (!isUndefined(result)) {
508 static float boundAxis(css_node_t *node, css_flex_direction_t axis, float value) {
509 float min = CSS_UNDEFINED;
510 float max = CSS_UNDEFINED;
512 if (isColumnDirection(axis)) {
513 min = node->style.minDimensions[CSS_HEIGHT];
514 max = node->style.maxDimensions[CSS_HEIGHT];
515 } else if (isRowDirection(axis)) {
516 min = node->style.minDimensions[CSS_WIDTH];
517 max = node->style.maxDimensions[CSS_WIDTH];
520 float boundValue = value;
522 if (!isUndefined(max) && max >= 0.0 && boundValue > max) {
525 if (!isUndefined(min) && min >= 0.0 && boundValue < min) {
532 // When the user specifically sets a value for width or height
533 static void setDimensionFromStyle(css_node_t *node, css_flex_direction_t axis) {
534 // The parent already computed us a width or height. We just skip it
535 if (isLayoutDimDefined(node, axis)) {
538 // We only run if there's a width or height defined
539 if (!isStyleDimDefined(node, axis)) {
543 // The dimensions can never be smaller than the padding and border
544 node->layout.dimensions[dim[axis]] = fmaxf(
545 boundAxis(node, axis, node->style.dimensions[dim[axis]]),
546 getPaddingAndBorderAxis(node, axis)
550 static void setTrailingPosition(css_node_t *node, css_node_t *child, css_flex_direction_t axis) {
551 child->layout.position[trailing[axis]] = node->layout.dimensions[dim[axis]] -
552 child->layout.dimensions[dim[axis]] - child->layout.position[pos[axis]];
555 // If both left and right are defined, then use left. Otherwise return
556 // +left or -right depending on which is defined.
557 static float getRelativePosition(css_node_t *node, css_flex_direction_t axis) {
558 float lead = node->style.position[leading[axis]];
559 if (!isUndefined(lead)) {
562 return -getPosition(node, trailing[axis]);
565 static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentMaxHeight, css_direction_t parentDirection) {
566 /** START_GENERATED **/
567 css_direction_t direction = resolveDirection(node, parentDirection);
568 css_flex_direction_t mainAxis = resolveAxis(getFlexDirection(node), direction);
569 css_flex_direction_t crossAxis = getCrossFlexDirection(mainAxis, direction);
570 css_flex_direction_t resolvedRowAxis = resolveAxis(CSS_FLEX_DIRECTION_ROW, direction);
572 // Handle width and height style attributes
573 setDimensionFromStyle(node, mainAxis);
574 setDimensionFromStyle(node, crossAxis);
576 // Set the resolved resolution in the node's layout
577 node->layout.direction = direction;
579 // The position is set by the parent, but we need to complete it with a
580 // delta composed of the margin and left/top/right/bottom
581 node->layout.position[leading[mainAxis]] += getLeadingMargin(node, mainAxis) +
582 getRelativePosition(node, mainAxis);
583 node->layout.position[trailing[mainAxis]] += getTrailingMargin(node, mainAxis) +
584 getRelativePosition(node, mainAxis);
585 node->layout.position[leading[crossAxis]] += getLeadingMargin(node, crossAxis) +
586 getRelativePosition(node, crossAxis);
587 node->layout.position[trailing[crossAxis]] += getTrailingMargin(node, crossAxis) +
588 getRelativePosition(node, crossAxis);
590 // Inline immutable values from the target node to avoid excessive method
591 // invocations during the layout calculation.
592 int childCount = node->children_count;
593 float paddingAndBorderAxisResolvedRow = getPaddingAndBorderAxis(node, resolvedRowAxis);
594 float paddingAndBorderAxisColumn = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
596 if (isMeasureDefined(node)) {
597 bool isResolvedRowDimDefined = isLayoutDimDefined(node, resolvedRowAxis);
599 float width = CSS_UNDEFINED;
600 css_measure_mode_t widthMode = CSS_MEASURE_MODE_UNDEFINED;
601 if (isStyleDimDefined(node, resolvedRowAxis)) {
602 width = node->style.dimensions[CSS_WIDTH];
603 widthMode = CSS_MEASURE_MODE_EXACTLY;
604 } else if (isResolvedRowDimDefined) {
605 width = node->layout.dimensions[dim[resolvedRowAxis]];
606 widthMode = CSS_MEASURE_MODE_EXACTLY;
608 width = parentMaxWidth -
609 getMarginAxis(node, resolvedRowAxis);
610 widthMode = CSS_MEASURE_MODE_AT_MOST;
612 width -= paddingAndBorderAxisResolvedRow;
613 if (isUndefined(width)) {
614 widthMode = CSS_MEASURE_MODE_UNDEFINED;
617 float height = CSS_UNDEFINED;
618 css_measure_mode_t heightMode = CSS_MEASURE_MODE_UNDEFINED;
619 if (isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
620 height = node->style.dimensions[CSS_HEIGHT];
621 heightMode = CSS_MEASURE_MODE_EXACTLY;
622 } else if (isLayoutDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
623 height = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]];
624 heightMode = CSS_MEASURE_MODE_EXACTLY;
626 height = parentMaxHeight -
627 getMarginAxis(node, resolvedRowAxis);
628 heightMode = CSS_MEASURE_MODE_AT_MOST;
630 height -= getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
631 if (isUndefined(height)) {
632 heightMode = CSS_MEASURE_MODE_UNDEFINED;
635 // We only need to give a dimension for the text if we haven't got any
636 // for it computed yet. It can either be from the style attribute or because
637 // the element is flexible.
638 bool isRowUndefined = !isStyleDimDefined(node, resolvedRowAxis) && !isResolvedRowDimDefined;
639 bool isColumnUndefined = !isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN) &&
640 isUndefined(node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]);
642 // Let's not measure the text if we already know both dimensions
643 if (isRowUndefined || isColumnUndefined) {
644 css_dim_t measureDim = node->measure(
651 if (isRowUndefined) {
652 node->layout.dimensions[CSS_WIDTH] = measureDim.dimensions[CSS_WIDTH] +
653 paddingAndBorderAxisResolvedRow;
655 if (isColumnUndefined) {
656 node->layout.dimensions[CSS_HEIGHT] = measureDim.dimensions[CSS_HEIGHT] +
657 paddingAndBorderAxisColumn;
660 if (childCount == 0) {
665 bool isNodeFlexWrap = isFlexWrap(node);
667 css_justify_t justifyContent = node->style.justify_content;
669 float leadingPaddingAndBorderMain = getLeadingPaddingAndBorder(node, mainAxis);
670 float leadingPaddingAndBorderCross = getLeadingPaddingAndBorder(node, crossAxis);
671 float paddingAndBorderAxisMain = getPaddingAndBorderAxis(node, mainAxis);
672 float paddingAndBorderAxisCross = getPaddingAndBorderAxis(node, crossAxis);
674 bool isMainDimDefined = isLayoutDimDefined(node, mainAxis);
675 bool isCrossDimDefined = isLayoutDimDefined(node, crossAxis);
676 bool isMainRowDirection = isRowDirection(mainAxis);
681 css_flex_direction_t axis;
683 css_node_t* firstAbsoluteChild = NULL;
684 css_node_t* currentAbsoluteChild = NULL;
686 float definedMainDim = CSS_UNDEFINED;
687 if (isMainDimDefined) {
688 definedMainDim = node->layout.dimensions[dim[mainAxis]] - paddingAndBorderAxisMain;
691 // We want to execute the next two loops one per line with flex-wrap
694 // int nextOffset = 0;
695 int alreadyComputedNextLayout = 0;
696 // We aggregate the total dimensions of the container in those two variables
697 float linesCrossDim = 0;
698 float linesMainDim = 0;
700 while (endLine < childCount) {
701 // <Loop A> Layout non flexible children and count children by type
703 // mainContentDim is accumulation of the dimensions and margin of all the
704 // non flexible children. This will be used in order to either set the
705 // dimensions of the node if none already exist, or to compute the
706 // remaining space left for the flexible children.
707 float mainContentDim = 0;
709 // There are three kind of children, non flexible, flexible and absolute.
710 // We need to know how many there are in order to distribute the space.
711 int flexibleChildrenCount = 0;
712 float totalFlexible = 0;
713 int nonFlexibleChildrenCount = 0;
715 // Use the line loop to position children in the main axis for as long
716 // as they are using a simple stacking behaviour. Children that are
717 // immediately stacked in the initial loop will not be touched again
719 bool isSimpleStackMain =
720 (isMainDimDefined && justifyContent == CSS_JUSTIFY_FLEX_START) ||
721 (!isMainDimDefined && justifyContent != CSS_JUSTIFY_CENTER);
722 int firstComplexMain = (isSimpleStackMain ? childCount : startLine);
724 // Use the initial line loop to position children in the cross axis for
725 // as long as they are relatively positioned with alignment STRETCH or
726 // FLEX_START. Children that are immediately stacked in the initial loop
727 // will not be touched again in <Loop D>.
728 bool isSimpleStackCross = true;
729 int firstComplexCross = childCount;
731 css_node_t* firstFlexChild = NULL;
732 css_node_t* currentFlexChild = NULL;
734 float mainDim = leadingPaddingAndBorderMain;
737 float maxWidth = CSS_UNDEFINED;
738 float maxHeight = CSS_UNDEFINED;
739 for (i = startLine; i < childCount; ++i) {
740 child = node->get_child(node->context, i);
741 child->line_index = linesCount;
743 child->next_absolute_child = NULL;
744 child->next_flex_child = NULL;
746 css_align_t alignItem = getAlignItem(node, child);
748 // Pre-fill cross axis dimensions when the child is using stretch before
749 // we call the recursive layout pass
750 if (alignItem == CSS_ALIGN_STRETCH &&
751 child->style.position_type == CSS_POSITION_RELATIVE &&
753 !isStyleDimDefined(child, crossAxis)) {
754 child->layout.dimensions[dim[crossAxis]] = fmaxf(
755 boundAxis(child, crossAxis, node->layout.dimensions[dim[crossAxis]] -
756 paddingAndBorderAxisCross - getMarginAxis(child, crossAxis)),
757 // You never want to go smaller than padding
758 getPaddingAndBorderAxis(child, crossAxis)
760 } else if (child->style.position_type == CSS_POSITION_ABSOLUTE) {
761 // Store a private linked list of absolutely positioned children
762 // so that we can efficiently traverse them later.
763 if (firstAbsoluteChild == NULL) {
764 firstAbsoluteChild = child;
766 if (currentAbsoluteChild != NULL) {
767 currentAbsoluteChild->next_absolute_child = child;
769 currentAbsoluteChild = child;
771 // Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both
772 // left and right or top and bottom).
773 for (ii = 0; ii < 2; ii++) {
774 axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN;
775 if (isLayoutDimDefined(node, axis) &&
776 !isStyleDimDefined(child, axis) &&
777 isPosDefined(child, leading[axis]) &&
778 isPosDefined(child, trailing[axis])) {
779 child->layout.dimensions[dim[axis]] = fmaxf(
780 boundAxis(child, axis, node->layout.dimensions[dim[axis]] -
781 getPaddingAndBorderAxis(node, axis) -
782 getMarginAxis(child, axis) -
783 getPosition(child, leading[axis]) -
784 getPosition(child, trailing[axis])),
785 // You never want to go smaller than padding
786 getPaddingAndBorderAxis(child, axis)
792 float nextContentDim = 0;
794 // It only makes sense to consider a child flexible if we have a computed
795 // dimension for the node->
796 if (isMainDimDefined && isFlex(child)) {
797 flexibleChildrenCount++;
798 totalFlexible += child->style.flex;
800 // Store a private linked list of flexible children so that we can
801 // efficiently traverse them later.
802 if (firstFlexChild == NULL) {
803 firstFlexChild = child;
805 if (currentFlexChild != NULL) {
806 currentFlexChild->next_flex_child = child;
808 currentFlexChild = child;
810 // Even if we don't know its exact size yet, we already know the padding,
811 // border and margin. We'll use this partial information, which represents
812 // the smallest possible size for the child, to compute the remaining
814 nextContentDim = getPaddingAndBorderAxis(child, mainAxis) +
815 getMarginAxis(child, mainAxis);
818 maxWidth = CSS_UNDEFINED;
819 maxHeight = CSS_UNDEFINED;
821 if (!isMainRowDirection) {
822 if (isLayoutDimDefined(node, resolvedRowAxis)) {
823 maxWidth = node->layout.dimensions[dim[resolvedRowAxis]] -
824 paddingAndBorderAxisResolvedRow;
826 maxWidth = parentMaxWidth -
827 getMarginAxis(node, resolvedRowAxis) -
828 paddingAndBorderAxisResolvedRow;
831 if (isLayoutDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
832 maxHeight = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] -
833 paddingAndBorderAxisColumn;
835 maxHeight = parentMaxHeight -
836 getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN) -
837 paddingAndBorderAxisColumn;
841 // This is the main recursive call. We layout non flexible children.
842 if (alreadyComputedNextLayout == 0) {
843 layoutNode(child, maxWidth, maxHeight, direction);
846 // Absolute positioned elements do not take part of the layout, so we
847 // don't use them to compute mainContentDim
848 if (child->style.position_type == CSS_POSITION_RELATIVE) {
849 nonFlexibleChildrenCount++;
850 // At this point we know the final size and margin of the element.
851 nextContentDim = getDimWithMargin(child, mainAxis);
855 // The element we are about to add would make us go to the next line
856 if (isNodeFlexWrap &&
858 mainContentDim + nextContentDim > definedMainDim &&
859 // If there's only one element, then it's bigger than the content
860 // and needs its own line
862 nonFlexibleChildrenCount--;
863 alreadyComputedNextLayout = 1;
867 // Disable simple stacking in the main axis for the current line as
868 // we found a non-trivial child-> The remaining children will be laid out
870 if (isSimpleStackMain &&
871 (child->style.position_type != CSS_POSITION_RELATIVE || isFlex(child))) {
872 isSimpleStackMain = false;
873 firstComplexMain = i;
876 // Disable simple stacking in the cross axis for the current line as
877 // we found a non-trivial child-> The remaining children will be laid out
879 if (isSimpleStackCross &&
880 (child->style.position_type != CSS_POSITION_RELATIVE ||
881 (alignItem != CSS_ALIGN_STRETCH && alignItem != CSS_ALIGN_FLEX_START) ||
882 (alignItem == CSS_ALIGN_STRETCH && !isCrossDimDefined))) {
883 isSimpleStackCross = false;
884 firstComplexCross = i;
887 if (isSimpleStackMain) {
888 child->layout.position[pos[mainAxis]] += mainDim;
889 if (isMainDimDefined) {
890 setTrailingPosition(node, child, mainAxis);
893 mainDim += getDimWithMargin(child, mainAxis);
894 crossDim = fmaxf(crossDim, boundAxis(child, crossAxis, getDimWithMargin(child, crossAxis)));
897 if (isSimpleStackCross) {
898 child->layout.position[pos[crossAxis]] += linesCrossDim + leadingPaddingAndBorderCross;
899 if (isCrossDimDefined) {
900 setTrailingPosition(node, child, crossAxis);
904 alreadyComputedNextLayout = 0;
905 mainContentDim += nextContentDim;
909 // <Loop B> Layout flexible children and allocate empty space
911 // In order to position the elements in the main axis, we have two
912 // controls. The space between the beginning and the first element
913 // and the space between each two elements.
914 float leadingMainDim = 0;
915 float betweenMainDim = 0;
917 // The remaining available space that needs to be allocated
918 float remainingMainDim = 0;
919 if (isMainDimDefined) {
920 remainingMainDim = definedMainDim - mainContentDim;
922 remainingMainDim = fmaxf(mainContentDim, 0) - mainContentDim;
925 // If there are flexible children in the mix, they are going to fill the
927 if (flexibleChildrenCount != 0) {
928 float flexibleMainDim = remainingMainDim / totalFlexible;
932 // If the flex share of remaining space doesn't meet min/max bounds,
933 // remove this child from flex calculations.
934 currentFlexChild = firstFlexChild;
935 while (currentFlexChild != NULL) {
936 baseMainDim = flexibleMainDim * currentFlexChild->style.flex +
937 getPaddingAndBorderAxis(currentFlexChild, mainAxis);
938 boundMainDim = boundAxis(currentFlexChild, mainAxis, baseMainDim);
940 if (baseMainDim != boundMainDim) {
941 remainingMainDim -= boundMainDim;
942 totalFlexible -= currentFlexChild->style.flex;
945 currentFlexChild = currentFlexChild->next_flex_child;
947 flexibleMainDim = remainingMainDim / totalFlexible;
949 // The non flexible children can overflow the container, in this case
950 // we should just assume that there is no space available.
951 if (flexibleMainDim < 0) {
955 currentFlexChild = firstFlexChild;
956 while (currentFlexChild != NULL) {
957 // At this point we know the final size of the element in the main
959 currentFlexChild->layout.dimensions[dim[mainAxis]] = boundAxis(currentFlexChild, mainAxis,
960 flexibleMainDim * currentFlexChild->style.flex +
961 getPaddingAndBorderAxis(currentFlexChild, mainAxis)
964 maxWidth = CSS_UNDEFINED;
965 if (isLayoutDimDefined(node, resolvedRowAxis)) {
966 maxWidth = node->layout.dimensions[dim[resolvedRowAxis]] -
967 paddingAndBorderAxisResolvedRow;
968 } else if (!isMainRowDirection) {
969 maxWidth = parentMaxWidth -
970 getMarginAxis(node, resolvedRowAxis) -
971 paddingAndBorderAxisResolvedRow;
973 maxHeight = CSS_UNDEFINED;
974 if (isLayoutDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
975 maxHeight = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] -
976 paddingAndBorderAxisColumn;
977 } else if (isMainRowDirection) {
978 maxHeight = parentMaxHeight -
979 getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN) -
980 paddingAndBorderAxisColumn;
983 // And we recursively call the layout algorithm for this child
984 layoutNode(currentFlexChild, maxWidth, maxHeight, direction);
986 child = currentFlexChild;
987 currentFlexChild = currentFlexChild->next_flex_child;
988 child->next_flex_child = NULL;
991 // We use justifyContent to figure out how to allocate the remaining
993 } else if (justifyContent != CSS_JUSTIFY_FLEX_START) {
994 if (justifyContent == CSS_JUSTIFY_CENTER) {
995 leadingMainDim = remainingMainDim / 2;
996 } else if (justifyContent == CSS_JUSTIFY_FLEX_END) {
997 leadingMainDim = remainingMainDim;
998 } else if (justifyContent == CSS_JUSTIFY_SPACE_BETWEEN) {
999 remainingMainDim = fmaxf(remainingMainDim, 0);
1000 if (flexibleChildrenCount + nonFlexibleChildrenCount - 1 != 0) {
1001 betweenMainDim = remainingMainDim /
1002 (flexibleChildrenCount + nonFlexibleChildrenCount - 1);
1006 } else if (justifyContent == CSS_JUSTIFY_SPACE_AROUND) {
1007 // Space on the edges is half of the space between elements
1008 betweenMainDim = remainingMainDim /
1009 (flexibleChildrenCount + nonFlexibleChildrenCount);
1010 leadingMainDim = betweenMainDim / 2;
1014 // <Loop C> Position elements in the main axis and compute dimensions
1016 // At this point, all the children have their dimensions set. We need to
1017 // find their position. In order to do that, we accumulate data in
1018 // variables that are also useful to compute the total dimensions of the
1020 mainDim += leadingMainDim;
1022 for (i = firstComplexMain; i < endLine; ++i) {
1023 child = node->get_child(node->context, i);
1025 if (child->style.position_type == CSS_POSITION_ABSOLUTE &&
1026 isPosDefined(child, leading[mainAxis])) {
1027 // In case the child is position absolute and has left/top being
1028 // defined, we override the position to whatever the user said
1029 // (and margin/border).
1030 child->layout.position[pos[mainAxis]] = getPosition(child, leading[mainAxis]) +
1031 getLeadingBorder(node, mainAxis) +
1032 getLeadingMargin(child, mainAxis);
1034 // If the child is position absolute (without top/left) or relative,
1035 // we put it at the current accumulated offset.
1036 child->layout.position[pos[mainAxis]] += mainDim;
1038 // Define the trailing position accordingly.
1039 if (isMainDimDefined) {
1040 setTrailingPosition(node, child, mainAxis);
1043 // Now that we placed the element, we need to update the variables
1044 // We only need to do that for relative elements. Absolute elements
1045 // do not take part in that phase.
1046 if (child->style.position_type == CSS_POSITION_RELATIVE) {
1047 // The main dimension is the sum of all the elements dimension plus
1049 mainDim += betweenMainDim + getDimWithMargin(child, mainAxis);
1050 // The cross dimension is the max of the elements dimension since there
1051 // can only be one element in that cross dimension.
1052 crossDim = fmaxf(crossDim, boundAxis(child, crossAxis, getDimWithMargin(child, crossAxis)));
1057 float containerCrossAxis = node->layout.dimensions[dim[crossAxis]];
1058 if (!isCrossDimDefined) {
1059 containerCrossAxis = fmaxf(
1060 // For the cross dim, we add both sides at the end because the value
1061 // is aggregate via a max function. Intermediate negative values
1062 // can mess this computation otherwise
1063 boundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross),
1064 paddingAndBorderAxisCross
1068 // <Loop D> Position elements in the cross axis
1069 for (i = firstComplexCross; i < endLine; ++i) {
1070 child = node->get_child(node->context, i);
1072 if (child->style.position_type == CSS_POSITION_ABSOLUTE &&
1073 isPosDefined(child, leading[crossAxis])) {
1074 // In case the child is absolutely positionned and has a
1075 // top/left/bottom/right being set, we override all the previously
1076 // computed positions to set it correctly.
1077 child->layout.position[pos[crossAxis]] = getPosition(child, leading[crossAxis]) +
1078 getLeadingBorder(node, crossAxis) +
1079 getLeadingMargin(child, crossAxis);
1082 float leadingCrossDim = leadingPaddingAndBorderCross;
1084 // For a relative children, we're either using alignItems (parent) or
1085 // alignSelf (child) in order to determine the position in the cross axis
1086 if (child->style.position_type == CSS_POSITION_RELATIVE) {
1088 // This variable is intentionally re-defined as the code is transpiled to a block scope language
1089 css_align_t alignItem = getAlignItem(node, child);
1091 if (alignItem == CSS_ALIGN_STRETCH) {
1092 // You can only stretch if the dimension has not already been defined
1094 if (!isStyleDimDefined(child, crossAxis)) {
1095 float dimCrossAxis = child->layout.dimensions[dim[crossAxis]];
1096 child->layout.dimensions[dim[crossAxis]] = fmaxf(
1097 boundAxis(child, crossAxis, containerCrossAxis -
1098 paddingAndBorderAxisCross - getMarginAxis(child, crossAxis)),
1099 // You never want to go smaller than padding
1100 getPaddingAndBorderAxis(child, crossAxis)
1103 // If the size has changed, and this child has children we need to re-layout this child
1104 if (dimCrossAxis != child->layout.dimensions[dim[crossAxis]] && child->children_count > 0) {
1105 // Reset child margins before re-layout as they are added back in layoutNode and would be doubled
1106 child->layout.position[leading[mainAxis]] -= getLeadingMargin(child, mainAxis) +
1107 getRelativePosition(child, mainAxis);
1108 child->layout.position[trailing[mainAxis]] -= getTrailingMargin(child, mainAxis) +
1109 getRelativePosition(child, mainAxis);
1110 child->layout.position[leading[crossAxis]] -= getLeadingMargin(child, crossAxis) +
1111 getRelativePosition(child, crossAxis);
1112 child->layout.position[trailing[crossAxis]] -= getTrailingMargin(child, crossAxis) +
1113 getRelativePosition(child, crossAxis);
1115 layoutNode(child, maxWidth, maxHeight, direction);
1118 } else if (alignItem != CSS_ALIGN_FLEX_START) {
1119 // The remaining space between the parent dimensions+padding and child
1120 // dimensions+margin.
1121 float remainingCrossDim = containerCrossAxis -
1122 paddingAndBorderAxisCross - getDimWithMargin(child, crossAxis);
1124 if (alignItem == CSS_ALIGN_CENTER) {
1125 leadingCrossDim += remainingCrossDim / 2;
1126 } else { // CSS_ALIGN_FLEX_END
1127 leadingCrossDim += remainingCrossDim;
1132 // And we apply the position
1133 child->layout.position[pos[crossAxis]] += linesCrossDim + leadingCrossDim;
1135 // Define the trailing position accordingly.
1136 if (isCrossDimDefined) {
1137 setTrailingPosition(node, child, crossAxis);
1142 linesCrossDim += crossDim;
1143 linesMainDim = fmaxf(linesMainDim, mainDim);
1145 startLine = endLine;
1150 // Note(prenaux): More than one line, we need to layout the crossAxis
1151 // according to alignContent.
1153 // Note that we could probably remove <Loop D> and handle the one line case
1154 // here too, but for the moment this is safer since it won't interfere with
1155 // previously working code.
1158 // http://www.w3.org/TR/2012/CR-css3-flexbox-20120918/#layout-algorithm
1161 if (linesCount > 1 && isCrossDimDefined) {
1162 float nodeCrossAxisInnerSize = node->layout.dimensions[dim[crossAxis]] -
1163 paddingAndBorderAxisCross;
1164 float remainingAlignContentDim = nodeCrossAxisInnerSize - linesCrossDim;
1166 float crossDimLead = 0;
1167 float currentLead = leadingPaddingAndBorderCross;
1169 css_align_t alignContent = node->style.align_content;
1170 if (alignContent == CSS_ALIGN_FLEX_END) {
1171 currentLead += remainingAlignContentDim;
1172 } else if (alignContent == CSS_ALIGN_CENTER) {
1173 currentLead += remainingAlignContentDim / 2;
1174 } else if (alignContent == CSS_ALIGN_STRETCH) {
1175 if (nodeCrossAxisInnerSize > linesCrossDim) {
1176 crossDimLead = (remainingAlignContentDim / linesCount);
1181 for (i = 0; i < linesCount; ++i) {
1182 int startIndex = endIndex;
1184 // compute the line's height and find the endIndex
1185 float lineHeight = 0;
1186 for (ii = startIndex; ii < childCount; ++ii) {
1187 child = node->get_child(node->context, ii);
1188 if (child->style.position_type != CSS_POSITION_RELATIVE) {
1191 if (child->line_index != i) {
1194 if (isLayoutDimDefined(child, crossAxis)) {
1197 child->layout.dimensions[dim[crossAxis]] + getMarginAxis(child, crossAxis)
1202 lineHeight += crossDimLead;
1204 for (ii = startIndex; ii < endIndex; ++ii) {
1205 child = node->get_child(node->context, ii);
1206 if (child->style.position_type != CSS_POSITION_RELATIVE) {
1210 css_align_t alignContentAlignItem = getAlignItem(node, child);
1211 if (alignContentAlignItem == CSS_ALIGN_FLEX_START) {
1212 child->layout.position[pos[crossAxis]] = currentLead + getLeadingMargin(child, crossAxis);
1213 } else if (alignContentAlignItem == CSS_ALIGN_FLEX_END) {
1214 child->layout.position[pos[crossAxis]] = currentLead + lineHeight - getTrailingMargin(child, crossAxis) - child->layout.dimensions[dim[crossAxis]];
1215 } else if (alignContentAlignItem == CSS_ALIGN_CENTER) {
1216 float childHeight = child->layout.dimensions[dim[crossAxis]];
1217 child->layout.position[pos[crossAxis]] = currentLead + (lineHeight - childHeight) / 2;
1218 } else if (alignContentAlignItem == CSS_ALIGN_STRETCH) {
1219 child->layout.position[pos[crossAxis]] = currentLead + getLeadingMargin(child, crossAxis);
1220 // TODO(prenaux): Correctly set the height of items with undefined
1221 // (auto) crossAxis dimension.
1225 currentLead += lineHeight;
1229 bool needsMainTrailingPos = false;
1230 bool needsCrossTrailingPos = false;
1232 // If the user didn't specify a width or height, and it has not been set
1233 // by the container, then we set it via the children.
1234 if (!isMainDimDefined) {
1235 node->layout.dimensions[dim[mainAxis]] = fmaxf(
1236 // We're missing the last padding at this point to get the final
1238 boundAxis(node, mainAxis, linesMainDim + getTrailingPaddingAndBorder(node, mainAxis)),
1239 // We can never assign a width smaller than the padding and borders
1240 paddingAndBorderAxisMain
1243 if (mainAxis == CSS_FLEX_DIRECTION_ROW_REVERSE ||
1244 mainAxis == CSS_FLEX_DIRECTION_COLUMN_REVERSE) {
1245 needsMainTrailingPos = true;
1249 if (!isCrossDimDefined) {
1250 node->layout.dimensions[dim[crossAxis]] = fmaxf(
1251 // For the cross dim, we add both sides at the end because the value
1252 // is aggregate via a max function. Intermediate negative values
1253 // can mess this computation otherwise
1254 boundAxis(node, crossAxis, linesCrossDim + paddingAndBorderAxisCross),
1255 paddingAndBorderAxisCross
1258 if (crossAxis == CSS_FLEX_DIRECTION_ROW_REVERSE ||
1259 crossAxis == CSS_FLEX_DIRECTION_COLUMN_REVERSE) {
1260 needsCrossTrailingPos = true;
1264 // <Loop F> Set trailing position if necessary
1265 if (needsMainTrailingPos || needsCrossTrailingPos) {
1266 for (i = 0; i < childCount; ++i) {
1267 child = node->get_child(node->context, i);
1269 if (needsMainTrailingPos) {
1270 setTrailingPosition(node, child, mainAxis);
1273 if (needsCrossTrailingPos) {
1274 setTrailingPosition(node, child, crossAxis);
1279 // <Loop G> Calculate dimensions for absolutely positioned elements
1280 currentAbsoluteChild = firstAbsoluteChild;
1281 while (currentAbsoluteChild != NULL) {
1282 // Pre-fill dimensions when using absolute position and both offsets for
1283 // the axis are defined (either both left and right or top and bottom).
1284 for (ii = 0; ii < 2; ii++) {
1285 axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN;
1287 if (isLayoutDimDefined(node, axis) &&
1288 !isStyleDimDefined(currentAbsoluteChild, axis) &&
1289 isPosDefined(currentAbsoluteChild, leading[axis]) &&
1290 isPosDefined(currentAbsoluteChild, trailing[axis])) {
1291 currentAbsoluteChild->layout.dimensions[dim[axis]] = fmaxf(
1292 boundAxis(currentAbsoluteChild, axis, node->layout.dimensions[dim[axis]] -
1293 getBorderAxis(node, axis) -
1294 getMarginAxis(currentAbsoluteChild, axis) -
1295 getPosition(currentAbsoluteChild, leading[axis]) -
1296 getPosition(currentAbsoluteChild, trailing[axis])
1298 // You never want to go smaller than padding
1299 getPaddingAndBorderAxis(currentAbsoluteChild, axis)
1303 if (isPosDefined(currentAbsoluteChild, trailing[axis]) &&
1304 !isPosDefined(currentAbsoluteChild, leading[axis])) {
1305 currentAbsoluteChild->layout.position[leading[axis]] =
1306 node->layout.dimensions[dim[axis]] -
1307 currentAbsoluteChild->layout.dimensions[dim[axis]] -
1308 getPosition(currentAbsoluteChild, trailing[axis]);
1312 child = currentAbsoluteChild;
1313 currentAbsoluteChild = currentAbsoluteChild->next_absolute_child;
1314 child->next_absolute_child = NULL;
1316 /** END_GENERATED **/
1319 void layoutNode(css_node_t *node, float parentMaxWidth, float parentMaxHeight, css_direction_t parentDirection) {
1320 css_layout_t *layout = &node->layout;
1321 css_direction_t direction = node->style.direction;
1322 layout->should_update = true;
1325 !node->is_dirty(node->context) &&
1326 eq(layout->last_requested_dimensions[CSS_WIDTH], layout->dimensions[CSS_WIDTH]) &&
1327 eq(layout->last_requested_dimensions[CSS_HEIGHT], layout->dimensions[CSS_HEIGHT]) &&
1328 eq(layout->last_parent_max_width, parentMaxWidth) &&
1329 eq(layout->last_parent_max_height, parentMaxHeight) &&
1330 eq(layout->last_direction, direction);
1333 layout->dimensions[CSS_WIDTH] = layout->last_dimensions[CSS_WIDTH];
1334 layout->dimensions[CSS_HEIGHT] = layout->last_dimensions[CSS_HEIGHT];
1335 layout->position[CSS_TOP] = layout->last_position[CSS_TOP];
1336 layout->position[CSS_LEFT] = layout->last_position[CSS_LEFT];
1338 layout->last_requested_dimensions[CSS_WIDTH] = layout->dimensions[CSS_WIDTH];
1339 layout->last_requested_dimensions[CSS_HEIGHT] = layout->dimensions[CSS_HEIGHT];
1340 layout->last_parent_max_width = parentMaxWidth;
1341 layout->last_parent_max_height = parentMaxHeight;
1342 layout->last_direction = direction;
1345 for (i = 0, childCount = node->children_count; i < childCount; i++) {
1346 resetNodeLayout(node->get_child(node->context, i));
1349 layoutNodeImpl(node, parentMaxWidth, parentMaxHeight, parentDirection);
1351 layout->last_dimensions[CSS_WIDTH] = layout->dimensions[CSS_WIDTH];
1352 layout->last_dimensions[CSS_HEIGHT] = layout->dimensions[CSS_HEIGHT];
1353 layout->last_position[CSS_TOP] = layout->position[CSS_TOP];
1354 layout->last_position[CSS_LEFT] = layout->position[CSS_LEFT];
1357 #if defined(FLEXBOX_LAYOUT_NODE_DEBUG)
1359 print_css_node(node, (css_print_options_t)(CSS_PRINT_STYLE | CSS_PRINT_CHILDREN));
1361 print_css_node(node, (css_print_options_t)(CSS_PRINT_LAYOUT | CSS_PRINT_CHILDREN));
1363 #endif // defined(FLEXBOX_LAYOUT_NODE_DEBUG)
1366 void resetNodeLayout(css_node_t *node) {
1367 node->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
1368 node->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
1369 node->layout.position[CSS_LEFT] = 0;
1370 node->layout.position[CSS_TOP] = 0;