From 8ef551174b79dbed2f5dc50e6f98be19138b6c16 Mon Sep 17 00:00:00 2001 From: Emil Sjolander Date: Mon, 11 Apr 2016 14:54:55 -0700 Subject: [PATCH] backout update of css-layout. breaks ios <9 Reviewed By: javache Differential Revision: D3164127 fb-gh-sync-id: 3926430f365711466ba93cd2eb7c91f31ef0c7f8 fbshipit-source-id: 3926430f365711466ba93cd2eb7c91f31ef0c7f8 --- Libraries/Text/RCTShadowText.m | 10 +- Libraries/Text/RCTTextManager.m | 5 +- React/Layout/Layout.c | 2612 ++++++++--------- React/Layout/Layout.h | 282 +- .../facebook/csslayout/CSSMeasureMode.java | 18 - .../java/com/facebook/csslayout/CSSNode.java | 8 +- .../com/facebook/csslayout/LayoutEngine.java | 210 +- .../main/java/com/facebook/csslayout/README | 2 +- .../com/facebook/csslayout/README.facebook | 2 +- .../views/art/ARTSurfaceViewManager.java | 9 +- .../progressbar/ProgressBarShadowNode.java | 9 +- .../views/slider/ReactSliderManager.java | 9 +- .../views/switchview/ReactSwitchManager.java | 9 +- .../react/views/text/ReactTextShadowNode.java | 12 +- .../textinput/ReactTextInputShadowNode.java | 12 +- 15 files changed, 1555 insertions(+), 1654 deletions(-) delete mode 100644 ReactAndroid/src/main/java/com/facebook/csslayout/CSSMeasureMode.java diff --git a/Libraries/Text/RCTShadowText.m b/Libraries/Text/RCTShadowText.m index deeab91fe..a3286a88b 100644 --- a/Libraries/Text/RCTShadowText.m +++ b/Libraries/Text/RCTShadowText.m @@ -30,10 +30,10 @@ NSString *const RCTReactTagAttributeName = @"ReactTagAttributeName"; CGFloat _effectiveLetterSpacing; } -static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t widthMode, float height, css_measure_mode_t heightMode) +static css_dim_t RCTMeasure(void *context, float width, float height) { RCTShadowText *shadowText = (__bridge RCTShadowText *)context; - NSTextStorage *textStorage = [shadowText buildTextStorageForWidth:width widthMode:widthMode]; + NSTextStorage *textStorage = [shadowText buildTextStorageForWidth:width]; NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject; NSTextContainer *textContainer = layoutManager.textContainers.firstObject; CGSize computedSize = [layoutManager usedRectForTextContainer:textContainer].size; @@ -89,7 +89,7 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width UIEdgeInsets padding = self.paddingAsInsets; CGFloat width = self.frame.size.width - (padding.left + padding.right); - NSTextStorage *textStorage = [self buildTextStorageForWidth:width widthMode:CSS_MEASURE_MODE_EXACTLY]; + NSTextStorage *textStorage = [self buildTextStorageForWidth:width]; [applierBlocks addObject:^(NSDictionary *viewRegistry) { RCTText *view = viewRegistry[self.reactTag]; view.textStorage = textStorage; @@ -106,7 +106,7 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width [self dirtyPropagation]; } -- (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width widthMode:(css_measure_mode_t)widthMode +- (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width { if (_cachedTextStorage && width == _cachedTextStorageWidth) { return _cachedTextStorage; @@ -121,7 +121,7 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width textContainer.lineFragmentPadding = 0.0; textContainer.lineBreakMode = _numberOfLines > 0 ? NSLineBreakByTruncatingTail : NSLineBreakByClipping; textContainer.maximumNumberOfLines = _numberOfLines; - textContainer.size = (CGSize){widthMode == CSS_MEASURE_MODE_UNDEFINED ? CGFLOAT_MAX : width, CGFLOAT_MAX}; + textContainer.size = (CGSize){isnan(width) ? CGFLOAT_MAX : width, CGFLOAT_MAX}; [layoutManager addTextContainer:textContainer]; [layoutManager ensureLayoutForTextContainer:textContainer]; diff --git a/Libraries/Text/RCTTextManager.m b/Libraries/Text/RCTTextManager.m index f817ae499..2a7e4d98b 100644 --- a/Libraries/Text/RCTTextManager.m +++ b/Libraries/Text/RCTTextManager.m @@ -9,7 +9,6 @@ #import "RCTTextManager.h" -#import "Layout.h" #import "RCTAccessibilityManager.h" #import "RCTAssert.h" #import "RCTConvert.h" @@ -22,7 +21,7 @@ @interface RCTShadowText (Private) -- (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width widthMode:(css_measure_mode_t)widthMode; +- (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width; @end @@ -135,7 +134,7 @@ RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor) UIEdgeInsets padding = shadowText.paddingAsInsets; CGFloat width = shadowText.frame.size.width - (padding.left + padding.right); - NSTextStorage *textStorage = [shadowText buildTextStorageForWidth:width widthMode:CSS_MEASURE_MODE_EXACTLY]; + NSTextStorage *textStorage = [shadowText buildTextStorageForWidth:width]; [uiBlocks addObject:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { RCTTextView *textView = viewRegistry[reactTag]; diff --git a/React/Layout/Layout.c b/React/Layout/Layout.c index c8f086b0e..b998c9efa 100644 --- a/React/Layout/Layout.c +++ b/React/Layout/Layout.c @@ -19,1317 +19,1301 @@ * of patent rights can be found in the PATENTS file in the same directory. */ - #include - #include - #include - #include - - // in concatenated header, don't include Layout.h it's already at the top - #ifndef CSS_LAYOUT_IMPLEMENTATION - #include "Layout.h" - #endif - - #ifdef _MSC_VER - #include - #define isnan _isnan - - /* define fmaxf if < VC12 */ - #if _MSC_VER < 1800 - __forceinline const float fmaxf(const float a, const float b) { - return (a > b) ? a : b; - } - #endif - #endif - - bool isUndefined(float value) { - return isnan(value); - } - - static bool eq(float a, float b) { - if (isUndefined(a)) { - return isUndefined(b); - } - return fabs(a - b) < 0.0001; - } - - void init_css_node(css_node_t *node) { - node->style.align_items = CSS_ALIGN_STRETCH; - node->style.align_content = CSS_ALIGN_FLEX_START; - - node->style.direction = CSS_DIRECTION_INHERIT; - node->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN; - - // Some of the fields default to undefined and not 0 - node->style.dimensions[CSS_WIDTH] = CSS_UNDEFINED; - node->style.dimensions[CSS_HEIGHT] = CSS_UNDEFINED; - - node->style.minDimensions[CSS_WIDTH] = CSS_UNDEFINED; - node->style.minDimensions[CSS_HEIGHT] = CSS_UNDEFINED; - - node->style.maxDimensions[CSS_WIDTH] = CSS_UNDEFINED; - node->style.maxDimensions[CSS_HEIGHT] = CSS_UNDEFINED; - - node->style.position[CSS_LEFT] = CSS_UNDEFINED; - node->style.position[CSS_TOP] = CSS_UNDEFINED; - node->style.position[CSS_RIGHT] = CSS_UNDEFINED; - node->style.position[CSS_BOTTOM] = CSS_UNDEFINED; - - node->style.margin[CSS_START] = CSS_UNDEFINED; - node->style.margin[CSS_END] = CSS_UNDEFINED; - node->style.padding[CSS_START] = CSS_UNDEFINED; - node->style.padding[CSS_END] = CSS_UNDEFINED; - node->style.border[CSS_START] = CSS_UNDEFINED; - node->style.border[CSS_END] = CSS_UNDEFINED; - - node->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED; - node->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED; - - // Such that the comparison is always going to be false - node->layout.last_requested_dimensions[CSS_WIDTH] = -1; - node->layout.last_requested_dimensions[CSS_HEIGHT] = -1; - node->layout.last_parent_max_width = -1; - node->layout.last_parent_max_height = -1; - node->layout.last_direction = (css_direction_t)-1; - node->layout.should_update = true; - } - - css_node_t *new_css_node() { - css_node_t *node = (css_node_t *)calloc(1, sizeof(*node)); - init_css_node(node); - return node; - } - - void free_css_node(css_node_t *node) { - free(node); - } - - static void indent(int n) { - for (int i = 0; i < n; ++i) { - printf(" "); - } - } - - static void print_number_0(const char *str, float number) { - if (!eq(number, 0)) { - printf("%s: %g, ", str, number); - } - } - - static void print_number_nan(const char *str, float number) { - if (!isnan(number)) { - printf("%s: %g, ", str, number); - } - } - - static bool four_equal(float four[4]) { - return - eq(four[0], four[1]) && - eq(four[0], four[2]) && - eq(four[0], four[3]); - } - - - static void print_css_node_rec( - css_node_t *node, - css_print_options_t options, - int level - ) { - indent(level); - printf("{"); - - if (node->print) { - node->print(node->context); - } - - if (options & CSS_PRINT_LAYOUT) { - printf("layout: {"); - printf("width: %g, ", node->layout.dimensions[CSS_WIDTH]); - printf("height: %g, ", node->layout.dimensions[CSS_HEIGHT]); - printf("top: %g, ", node->layout.position[CSS_TOP]); - printf("left: %g", node->layout.position[CSS_LEFT]); - printf("}, "); - } - - if (options & CSS_PRINT_STYLE) { - if (node->style.flex_direction == CSS_FLEX_DIRECTION_COLUMN) { - printf("flexDirection: 'column', "); - } else if (node->style.flex_direction == CSS_FLEX_DIRECTION_COLUMN_REVERSE) { - printf("flexDirection: 'columnReverse', "); - } else if (node->style.flex_direction == CSS_FLEX_DIRECTION_ROW) { - printf("flexDirection: 'row', "); - } else if (node->style.flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE) { - printf("flexDirection: 'rowReverse', "); - } - - if (node->style.justify_content == CSS_JUSTIFY_CENTER) { - printf("justifyContent: 'center', "); - } else if (node->style.justify_content == CSS_JUSTIFY_FLEX_END) { - printf("justifyContent: 'flex-end', "); - } else if (node->style.justify_content == CSS_JUSTIFY_SPACE_AROUND) { - printf("justifyContent: 'space-around', "); - } else if (node->style.justify_content == CSS_JUSTIFY_SPACE_BETWEEN) { - printf("justifyContent: 'space-between', "); - } - - if (node->style.align_items == CSS_ALIGN_CENTER) { - printf("alignItems: 'center', "); - } else if (node->style.align_items == CSS_ALIGN_FLEX_END) { - printf("alignItems: 'flex-end', "); - } else if (node->style.align_items == CSS_ALIGN_STRETCH) { - printf("alignItems: 'stretch', "); - } - - if (node->style.align_content == CSS_ALIGN_CENTER) { - printf("alignContent: 'center', "); - } else if (node->style.align_content == CSS_ALIGN_FLEX_END) { - printf("alignContent: 'flex-end', "); - } else if (node->style.align_content == CSS_ALIGN_STRETCH) { - printf("alignContent: 'stretch', "); - } - - if (node->style.align_self == CSS_ALIGN_FLEX_START) { - printf("alignSelf: 'flex-start', "); - } else if (node->style.align_self == CSS_ALIGN_CENTER) { - printf("alignSelf: 'center', "); - } else if (node->style.align_self == CSS_ALIGN_FLEX_END) { - printf("alignSelf: 'flex-end', "); - } else if (node->style.align_self == CSS_ALIGN_STRETCH) { - printf("alignSelf: 'stretch', "); - } - - print_number_nan("flex", node->style.flex); - - if (four_equal(node->style.margin)) { - print_number_0("margin", node->style.margin[CSS_LEFT]); - } else { - print_number_0("marginLeft", node->style.margin[CSS_LEFT]); - print_number_0("marginRight", node->style.margin[CSS_RIGHT]); - print_number_0("marginTop", node->style.margin[CSS_TOP]); - print_number_0("marginBottom", node->style.margin[CSS_BOTTOM]); - print_number_0("marginStart", node->style.margin[CSS_START]); - print_number_0("marginEnd", node->style.margin[CSS_END]); - } - - if (four_equal(node->style.padding)) { - print_number_0("padding", node->style.margin[CSS_LEFT]); - } else { - print_number_0("paddingLeft", node->style.padding[CSS_LEFT]); - print_number_0("paddingRight", node->style.padding[CSS_RIGHT]); - print_number_0("paddingTop", node->style.padding[CSS_TOP]); - print_number_0("paddingBottom", node->style.padding[CSS_BOTTOM]); - print_number_0("paddingStart", node->style.padding[CSS_START]); - print_number_0("paddingEnd", node->style.padding[CSS_END]); - } - - if (four_equal(node->style.border)) { - print_number_0("borderWidth", node->style.border[CSS_LEFT]); - } else { - print_number_0("borderLeftWidth", node->style.border[CSS_LEFT]); - print_number_0("borderRightWidth", node->style.border[CSS_RIGHT]); - print_number_0("borderTopWidth", node->style.border[CSS_TOP]); - print_number_0("borderBottomWidth", node->style.border[CSS_BOTTOM]); - print_number_0("borderStartWidth", node->style.border[CSS_START]); - print_number_0("borderEndWidth", node->style.border[CSS_END]); - } - - print_number_nan("width", node->style.dimensions[CSS_WIDTH]); - print_number_nan("height", node->style.dimensions[CSS_HEIGHT]); - - if (node->style.position_type == CSS_POSITION_ABSOLUTE) { - printf("position: 'absolute', "); - } - - print_number_nan("left", node->style.position[CSS_LEFT]); - print_number_nan("right", node->style.position[CSS_RIGHT]); - print_number_nan("top", node->style.position[CSS_TOP]); - print_number_nan("bottom", node->style.position[CSS_BOTTOM]); - } - - if (options & CSS_PRINT_CHILDREN && node->children_count > 0) { - printf("children: [\n"); - for (int i = 0; i < node->children_count; ++i) { - print_css_node_rec(node->get_child(node->context, i), options, level + 1); - } - indent(level); - printf("]},\n"); - } else { - printf("},\n"); - } - } - - void print_css_node(css_node_t *node, css_print_options_t options) { - print_css_node_rec(node, options, 0); - } - - - static css_position_t leading[4] = { - /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_TOP, - /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_BOTTOM, - /* CSS_FLEX_DIRECTION_ROW = */ CSS_LEFT, - /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_RIGHT - }; - static css_position_t trailing[4] = { - /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_BOTTOM, - /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_TOP, - /* CSS_FLEX_DIRECTION_ROW = */ CSS_RIGHT, - /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_LEFT - }; - static css_position_t pos[4] = { - /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_TOP, - /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_BOTTOM, - /* CSS_FLEX_DIRECTION_ROW = */ CSS_LEFT, - /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_RIGHT - }; - static css_dimension_t dim[4] = { - /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_HEIGHT, - /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_HEIGHT, - /* CSS_FLEX_DIRECTION_ROW = */ CSS_WIDTH, - /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_WIDTH - }; - - static bool isRowDirection(css_flex_direction_t flex_direction) { - return flex_direction == CSS_FLEX_DIRECTION_ROW || - flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE; - } - - static bool isColumnDirection(css_flex_direction_t flex_direction) { - return flex_direction == CSS_FLEX_DIRECTION_COLUMN || - flex_direction == CSS_FLEX_DIRECTION_COLUMN_REVERSE; - } - - static float getLeadingMargin(css_node_t *node, css_flex_direction_t axis) { - if (isRowDirection(axis) && !isUndefined(node->style.margin[CSS_START])) { - return node->style.margin[CSS_START]; - } - - return node->style.margin[leading[axis]]; - } - - static float getTrailingMargin(css_node_t *node, css_flex_direction_t axis) { - if (isRowDirection(axis) && !isUndefined(node->style.margin[CSS_END])) { - return node->style.margin[CSS_END]; - } - - return node->style.margin[trailing[axis]]; - } - - static float getLeadingPadding(css_node_t *node, css_flex_direction_t axis) { - if (isRowDirection(axis) && - !isUndefined(node->style.padding[CSS_START]) && - node->style.padding[CSS_START] >= 0) { - return node->style.padding[CSS_START]; - } - - if (node->style.padding[leading[axis]] >= 0) { - return node->style.padding[leading[axis]]; - } - - return 0; - } - - static float getTrailingPadding(css_node_t *node, css_flex_direction_t axis) { - if (isRowDirection(axis) && - !isUndefined(node->style.padding[CSS_END]) && - node->style.padding[CSS_END] >= 0) { - return node->style.padding[CSS_END]; - } - - if (node->style.padding[trailing[axis]] >= 0) { - return node->style.padding[trailing[axis]]; - } - - return 0; - } - - static float getLeadingBorder(css_node_t *node, css_flex_direction_t axis) { - if (isRowDirection(axis) && - !isUndefined(node->style.border[CSS_START]) && - node->style.border[CSS_START] >= 0) { - return node->style.border[CSS_START]; - } - - if (node->style.border[leading[axis]] >= 0) { - return node->style.border[leading[axis]]; - } - - return 0; - } - - static float getTrailingBorder(css_node_t *node, css_flex_direction_t axis) { - if (isRowDirection(axis) && - !isUndefined(node->style.border[CSS_END]) && - node->style.border[CSS_END] >= 0) { - return node->style.border[CSS_END]; - } - - if (node->style.border[trailing[axis]] >= 0) { - return node->style.border[trailing[axis]]; - } - - return 0; - } - - static float getLeadingPaddingAndBorder(css_node_t *node, css_flex_direction_t axis) { - return getLeadingPadding(node, axis) + getLeadingBorder(node, axis); - } - - static float getTrailingPaddingAndBorder(css_node_t *node, css_flex_direction_t axis) { - return getTrailingPadding(node, axis) + getTrailingBorder(node, axis); - } - - static float getBorderAxis(css_node_t *node, css_flex_direction_t axis) { - return getLeadingBorder(node, axis) + getTrailingBorder(node, axis); - } - - static float getMarginAxis(css_node_t *node, css_flex_direction_t axis) { - return getLeadingMargin(node, axis) + getTrailingMargin(node, axis); - } - - static float getPaddingAndBorderAxis(css_node_t *node, css_flex_direction_t axis) { - return getLeadingPaddingAndBorder(node, axis) + getTrailingPaddingAndBorder(node, axis); - } - - static css_align_t getAlignItem(css_node_t *node, css_node_t *child) { - if (child->style.align_self != CSS_ALIGN_AUTO) { - return child->style.align_self; - } - return node->style.align_items; - } - - static css_direction_t resolveDirection(css_node_t *node, css_direction_t parentDirection) { - css_direction_t direction = node->style.direction; - - if (direction == CSS_DIRECTION_INHERIT) { - direction = parentDirection > CSS_DIRECTION_INHERIT ? parentDirection : CSS_DIRECTION_LTR; - } - - return direction; - } - - static css_flex_direction_t getFlexDirection(css_node_t *node) { - return node->style.flex_direction; - } - - static css_flex_direction_t resolveAxis(css_flex_direction_t flex_direction, css_direction_t direction) { - if (direction == CSS_DIRECTION_RTL) { - if (flex_direction == CSS_FLEX_DIRECTION_ROW) { - return CSS_FLEX_DIRECTION_ROW_REVERSE; - } else if (flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE) { - return CSS_FLEX_DIRECTION_ROW; - } - } - - return flex_direction; - } - - static css_flex_direction_t getCrossFlexDirection(css_flex_direction_t flex_direction, css_direction_t direction) { - if (isColumnDirection(flex_direction)) { - return resolveAxis(CSS_FLEX_DIRECTION_ROW, direction); - } else { - return CSS_FLEX_DIRECTION_COLUMN; - } - } - - static float getFlex(css_node_t *node) { - return node->style.flex; - } - - static bool isFlex(css_node_t *node) { - return ( - node->style.position_type == CSS_POSITION_RELATIVE && - getFlex(node) > 0 - ); - } - - static bool isFlexWrap(css_node_t *node) { - return node->style.flex_wrap == CSS_WRAP; - } - - static float getDimWithMargin(css_node_t *node, css_flex_direction_t axis) { - return node->layout.dimensions[dim[axis]] + - getLeadingMargin(node, axis) + - getTrailingMargin(node, axis); - } - - static bool isStyleDimDefined(css_node_t *node, css_flex_direction_t axis) { - float value = node->style.dimensions[dim[axis]]; - return !isUndefined(value) && value >= 0.0; - } - - static bool isLayoutDimDefined(css_node_t *node, css_flex_direction_t axis) { - float value = node->layout.dimensions[dim[axis]]; - return !isUndefined(value) && value >= 0.0; - } - - static bool isPosDefined(css_node_t *node, css_position_t position) { - return !isUndefined(node->style.position[position]); - } - - static bool isMeasureDefined(css_node_t *node) { - return node->measure; - } - - static float getPosition(css_node_t *node, css_position_t position) { - float result = node->style.position[position]; - if (!isUndefined(result)) { - return result; - } - return 0; - } - - static float boundAxis(css_node_t *node, css_flex_direction_t axis, float value) { - float min = CSS_UNDEFINED; - float max = CSS_UNDEFINED; - - if (isColumnDirection(axis)) { - min = node->style.minDimensions[CSS_HEIGHT]; - max = node->style.maxDimensions[CSS_HEIGHT]; - } else if (isRowDirection(axis)) { - min = node->style.minDimensions[CSS_WIDTH]; - max = node->style.maxDimensions[CSS_WIDTH]; - } - - float boundValue = value; - - if (!isUndefined(max) && max >= 0.0 && boundValue > max) { - boundValue = max; - } - if (!isUndefined(min) && min >= 0.0 && boundValue < min) { - boundValue = min; - } - - return boundValue; - } - - // When the user specifically sets a value for width or height - static void setDimensionFromStyle(css_node_t *node, css_flex_direction_t axis) { - // The parent already computed us a width or height. We just skip it - if (isLayoutDimDefined(node, axis)) { - return; - } - // We only run if there's a width or height defined - if (!isStyleDimDefined(node, axis)) { - return; - } - - // The dimensions can never be smaller than the padding and border - node->layout.dimensions[dim[axis]] = fmaxf( - boundAxis(node, axis, node->style.dimensions[dim[axis]]), - getPaddingAndBorderAxis(node, axis) - ); - } - - static void setTrailingPosition(css_node_t *node, css_node_t *child, css_flex_direction_t axis) { - child->layout.position[trailing[axis]] = node->layout.dimensions[dim[axis]] - - child->layout.dimensions[dim[axis]] - child->layout.position[pos[axis]]; - } - - // If both left and right are defined, then use left. Otherwise return - // +left or -right depending on which is defined. - static float getRelativePosition(css_node_t *node, css_flex_direction_t axis) { - float lead = node->style.position[leading[axis]]; - if (!isUndefined(lead)) { - return lead; - } - return -getPosition(node, trailing[axis]); - } - - static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentMaxHeight, css_direction_t parentDirection) { - /** START_GENERATED **/ - css_direction_t direction = resolveDirection(node, parentDirection); - css_flex_direction_t mainAxis = resolveAxis(getFlexDirection(node), direction); - css_flex_direction_t crossAxis = getCrossFlexDirection(mainAxis, direction); - css_flex_direction_t resolvedRowAxis = resolveAxis(CSS_FLEX_DIRECTION_ROW, direction); - - // Handle width and height style attributes - setDimensionFromStyle(node, mainAxis); - setDimensionFromStyle(node, crossAxis); - - // Set the resolved resolution in the node's layout - node->layout.direction = direction; - - // The position is set by the parent, but we need to complete it with a - // delta composed of the margin and left/top/right/bottom - node->layout.position[leading[mainAxis]] += getLeadingMargin(node, mainAxis) + - getRelativePosition(node, mainAxis); - node->layout.position[trailing[mainAxis]] += getTrailingMargin(node, mainAxis) + - getRelativePosition(node, mainAxis); - node->layout.position[leading[crossAxis]] += getLeadingMargin(node, crossAxis) + - getRelativePosition(node, crossAxis); - node->layout.position[trailing[crossAxis]] += getTrailingMargin(node, crossAxis) + - getRelativePosition(node, crossAxis); - - // Inline immutable values from the target node to avoid excessive method - // invocations during the layout calculation. - int childCount = node->children_count; - float paddingAndBorderAxisResolvedRow = getPaddingAndBorderAxis(node, resolvedRowAxis); - float paddingAndBorderAxisColumn = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN); - - if (isMeasureDefined(node)) { - bool isResolvedRowDimDefined = isLayoutDimDefined(node, resolvedRowAxis); - - float width = CSS_UNDEFINED; - css_measure_mode_t widthMode = CSS_MEASURE_MODE_UNDEFINED; - if (isStyleDimDefined(node, resolvedRowAxis)) { - width = node->style.dimensions[CSS_WIDTH]; - widthMode = CSS_MEASURE_MODE_EXACTLY; - } else if (isResolvedRowDimDefined) { - width = node->layout.dimensions[dim[resolvedRowAxis]]; - widthMode = CSS_MEASURE_MODE_EXACTLY; - } else { - width = parentMaxWidth - - getMarginAxis(node, resolvedRowAxis); - widthMode = CSS_MEASURE_MODE_AT_MOST; - } - width -= paddingAndBorderAxisResolvedRow; - if (isUndefined(width)) { - widthMode = CSS_MEASURE_MODE_UNDEFINED; - } - - float height = CSS_UNDEFINED; - css_measure_mode_t heightMode = CSS_MEASURE_MODE_UNDEFINED; - if (isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) { - height = node->style.dimensions[CSS_HEIGHT]; - heightMode = CSS_MEASURE_MODE_EXACTLY; - } else if (isLayoutDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) { - height = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]; - heightMode = CSS_MEASURE_MODE_EXACTLY; - } else { - height = parentMaxHeight - - getMarginAxis(node, resolvedRowAxis); - heightMode = CSS_MEASURE_MODE_AT_MOST; - } - height -= getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN); - if (isUndefined(height)) { - heightMode = CSS_MEASURE_MODE_UNDEFINED; - } - - // We only need to give a dimension for the text if we haven't got any - // for it computed yet. It can either be from the style attribute or because - // the element is flexible. - bool isRowUndefined = !isStyleDimDefined(node, resolvedRowAxis) && !isResolvedRowDimDefined; - bool isColumnUndefined = !isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN) && - isUndefined(node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]); - - // Let's not measure the text if we already know both dimensions - if (isRowUndefined || isColumnUndefined) { - css_dim_t measureDim = node->measure( - node->context, - - width, - widthMode, - height, - heightMode - ); - if (isRowUndefined) { - node->layout.dimensions[CSS_WIDTH] = measureDim.dimensions[CSS_WIDTH] + - paddingAndBorderAxisResolvedRow; - } - if (isColumnUndefined) { - node->layout.dimensions[CSS_HEIGHT] = measureDim.dimensions[CSS_HEIGHT] + - paddingAndBorderAxisColumn; - } - } - if (childCount == 0) { - return; - } - } - - bool isNodeFlexWrap = isFlexWrap(node); - - css_justify_t justifyContent = node->style.justify_content; - - float leadingPaddingAndBorderMain = getLeadingPaddingAndBorder(node, mainAxis); - float leadingPaddingAndBorderCross = getLeadingPaddingAndBorder(node, crossAxis); - float paddingAndBorderAxisMain = getPaddingAndBorderAxis(node, mainAxis); - float paddingAndBorderAxisCross = getPaddingAndBorderAxis(node, crossAxis); - - bool isMainDimDefined = isLayoutDimDefined(node, mainAxis); - bool isCrossDimDefined = isLayoutDimDefined(node, crossAxis); - bool isMainRowDirection = isRowDirection(mainAxis); - - int i; - int ii; - css_node_t* child; - css_flex_direction_t axis; - - css_node_t* firstAbsoluteChild = NULL; - css_node_t* currentAbsoluteChild = NULL; - - float definedMainDim = CSS_UNDEFINED; - if (isMainDimDefined) { - definedMainDim = node->layout.dimensions[dim[mainAxis]] - paddingAndBorderAxisMain; - } - - // We want to execute the next two loops one per line with flex-wrap - int startLine = 0; - int endLine = 0; - // int nextOffset = 0; - int alreadyComputedNextLayout = 0; - // We aggregate the total dimensions of the container in those two variables - float linesCrossDim = 0; - float linesMainDim = 0; - int linesCount = 0; - while (endLine < childCount) { - // Layout non flexible children and count children by type - - // mainContentDim is accumulation of the dimensions and margin of all the - // non flexible children. This will be used in order to either set the - // dimensions of the node if none already exist, or to compute the - // remaining space left for the flexible children. - float mainContentDim = 0; - - // There are three kind of children, non flexible, flexible and absolute. - // We need to know how many there are in order to distribute the space. - int flexibleChildrenCount = 0; - float totalFlexible = 0; - int nonFlexibleChildrenCount = 0; - - // Use the line loop to position children in the main axis for as long - // as they are using a simple stacking behaviour. Children that are - // immediately stacked in the initial loop will not be touched again - // in . - bool isSimpleStackMain = - (isMainDimDefined && justifyContent == CSS_JUSTIFY_FLEX_START) || - (!isMainDimDefined && justifyContent != CSS_JUSTIFY_CENTER); - int firstComplexMain = (isSimpleStackMain ? childCount : startLine); - - // Use the initial line loop to position children in the cross axis for - // as long as they are relatively positioned with alignment STRETCH or - // FLEX_START. Children that are immediately stacked in the initial loop - // will not be touched again in . - bool isSimpleStackCross = true; - int firstComplexCross = childCount; - - css_node_t* firstFlexChild = NULL; - css_node_t* currentFlexChild = NULL; - - float mainDim = leadingPaddingAndBorderMain; - float crossDim = 0; - - float maxWidth = CSS_UNDEFINED; - float maxHeight = CSS_UNDEFINED; - for (i = startLine; i < childCount; ++i) { - child = node->get_child(node->context, i); - child->line_index = linesCount; - - child->next_absolute_child = NULL; - child->next_flex_child = NULL; - - css_align_t alignItem = getAlignItem(node, child); - - // Pre-fill cross axis dimensions when the child is using stretch before - // we call the recursive layout pass - if (alignItem == CSS_ALIGN_STRETCH && - child->style.position_type == CSS_POSITION_RELATIVE && - isCrossDimDefined && - !isStyleDimDefined(child, crossAxis)) { - child->layout.dimensions[dim[crossAxis]] = fmaxf( - boundAxis(child, crossAxis, node->layout.dimensions[dim[crossAxis]] - - paddingAndBorderAxisCross - getMarginAxis(child, crossAxis)), - // You never want to go smaller than padding - getPaddingAndBorderAxis(child, crossAxis) - ); - } else if (child->style.position_type == CSS_POSITION_ABSOLUTE) { - // Store a private linked list of absolutely positioned children - // so that we can efficiently traverse them later. - if (firstAbsoluteChild == NULL) { - firstAbsoluteChild = child; - } - if (currentAbsoluteChild != NULL) { - currentAbsoluteChild->next_absolute_child = child; - } - currentAbsoluteChild = child; - - // Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both - // left and right or top and bottom). - for (ii = 0; ii < 2; ii++) { - axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; - if (isLayoutDimDefined(node, axis) && - !isStyleDimDefined(child, axis) && - isPosDefined(child, leading[axis]) && - isPosDefined(child, trailing[axis])) { - child->layout.dimensions[dim[axis]] = fmaxf( - boundAxis(child, axis, node->layout.dimensions[dim[axis]] - - getPaddingAndBorderAxis(node, axis) - - getMarginAxis(child, axis) - - getPosition(child, leading[axis]) - - getPosition(child, trailing[axis])), - // You never want to go smaller than padding - getPaddingAndBorderAxis(child, axis) - ); - } - } - } - - float nextContentDim = 0; - - // It only makes sense to consider a child flexible if we have a computed - // dimension for the node-> - if (isMainDimDefined && isFlex(child)) { - flexibleChildrenCount++; - totalFlexible += child->style.flex; - - // Store a private linked list of flexible children so that we can - // efficiently traverse them later. - if (firstFlexChild == NULL) { - firstFlexChild = child; - } - if (currentFlexChild != NULL) { - currentFlexChild->next_flex_child = child; - } - currentFlexChild = child; - - // Even if we don't know its exact size yet, we already know the padding, - // border and margin. We'll use this partial information, which represents - // the smallest possible size for the child, to compute the remaining - // available space. - nextContentDim = getPaddingAndBorderAxis(child, mainAxis) + - getMarginAxis(child, mainAxis); - - } else { - maxWidth = CSS_UNDEFINED; - maxHeight = CSS_UNDEFINED; - - if (!isMainRowDirection) { - if (isLayoutDimDefined(node, resolvedRowAxis)) { - maxWidth = node->layout.dimensions[dim[resolvedRowAxis]] - - paddingAndBorderAxisResolvedRow; - } else { - maxWidth = parentMaxWidth - - getMarginAxis(node, resolvedRowAxis) - - paddingAndBorderAxisResolvedRow; - } - } else { - if (isLayoutDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) { - maxHeight = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] - - paddingAndBorderAxisColumn; - } else { - maxHeight = parentMaxHeight - - getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN) - - paddingAndBorderAxisColumn; - } - } - - // This is the main recursive call. We layout non flexible children. - if (alreadyComputedNextLayout == 0) { - layoutNode(child, maxWidth, maxHeight, direction); - } - - // Absolute positioned elements do not take part of the layout, so we - // don't use them to compute mainContentDim - if (child->style.position_type == CSS_POSITION_RELATIVE) { - nonFlexibleChildrenCount++; - // At this point we know the final size and margin of the element. - nextContentDim = getDimWithMargin(child, mainAxis); - } - } - - // The element we are about to add would make us go to the next line - if (isNodeFlexWrap && - isMainDimDefined && - mainContentDim + nextContentDim > definedMainDim && - // If there's only one element, then it's bigger than the content - // and needs its own line - i != startLine) { - nonFlexibleChildrenCount--; - alreadyComputedNextLayout = 1; - break; - } - - // Disable simple stacking in the main axis for the current line as - // we found a non-trivial child-> The remaining children will be laid out - // in . - if (isSimpleStackMain && - (child->style.position_type != CSS_POSITION_RELATIVE || isFlex(child))) { - isSimpleStackMain = false; - firstComplexMain = i; - } - - // Disable simple stacking in the cross axis for the current line as - // we found a non-trivial child-> The remaining children will be laid out - // in . - if (isSimpleStackCross && - (child->style.position_type != CSS_POSITION_RELATIVE || - (alignItem != CSS_ALIGN_STRETCH && alignItem != CSS_ALIGN_FLEX_START) || - (alignItem == CSS_ALIGN_STRETCH && !isCrossDimDefined))) { - isSimpleStackCross = false; - firstComplexCross = i; - } - - if (isSimpleStackMain) { - child->layout.position[pos[mainAxis]] += mainDim; - if (isMainDimDefined) { - setTrailingPosition(node, child, mainAxis); - } - - mainDim += getDimWithMargin(child, mainAxis); - crossDim = fmaxf(crossDim, boundAxis(child, crossAxis, getDimWithMargin(child, crossAxis))); - } - - if (isSimpleStackCross) { - child->layout.position[pos[crossAxis]] += linesCrossDim + leadingPaddingAndBorderCross; - if (isCrossDimDefined) { - setTrailingPosition(node, child, crossAxis); - } - } - - alreadyComputedNextLayout = 0; - mainContentDim += nextContentDim; - endLine = i + 1; - } - - // Layout flexible children and allocate empty space - - // In order to position the elements in the main axis, we have two - // controls. The space between the beginning and the first element - // and the space between each two elements. - float leadingMainDim = 0; - float betweenMainDim = 0; - - // The remaining available space that needs to be allocated - float remainingMainDim = 0; - if (isMainDimDefined) { - remainingMainDim = definedMainDim - mainContentDim; - } else { - remainingMainDim = fmaxf(mainContentDim, 0) - mainContentDim; - } - - // If there are flexible children in the mix, they are going to fill the - // remaining space - if (flexibleChildrenCount != 0) { - float flexibleMainDim = remainingMainDim / totalFlexible; - float baseMainDim; - float boundMainDim; - - // If the flex share of remaining space doesn't meet min/max bounds, - // remove this child from flex calculations. - currentFlexChild = firstFlexChild; - while (currentFlexChild != NULL) { - baseMainDim = flexibleMainDim * currentFlexChild->style.flex + - getPaddingAndBorderAxis(currentFlexChild, mainAxis); - boundMainDim = boundAxis(currentFlexChild, mainAxis, baseMainDim); - - if (baseMainDim != boundMainDim) { - remainingMainDim -= boundMainDim; - totalFlexible -= currentFlexChild->style.flex; - } - - currentFlexChild = currentFlexChild->next_flex_child; - } - flexibleMainDim = remainingMainDim / totalFlexible; - - // The non flexible children can overflow the container, in this case - // we should just assume that there is no space available. - if (flexibleMainDim < 0) { - flexibleMainDim = 0; - } - - currentFlexChild = firstFlexChild; - while (currentFlexChild != NULL) { - // At this point we know the final size of the element in the main - // dimension - currentFlexChild->layout.dimensions[dim[mainAxis]] = boundAxis(currentFlexChild, mainAxis, - flexibleMainDim * currentFlexChild->style.flex + - getPaddingAndBorderAxis(currentFlexChild, mainAxis) - ); - - maxWidth = CSS_UNDEFINED; - if (isLayoutDimDefined(node, resolvedRowAxis)) { - maxWidth = node->layout.dimensions[dim[resolvedRowAxis]] - - paddingAndBorderAxisResolvedRow; - } else if (!isMainRowDirection) { - maxWidth = parentMaxWidth - - getMarginAxis(node, resolvedRowAxis) - - paddingAndBorderAxisResolvedRow; - } - maxHeight = CSS_UNDEFINED; - if (isLayoutDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) { - maxHeight = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] - - paddingAndBorderAxisColumn; - } else if (isMainRowDirection) { - maxHeight = parentMaxHeight - - getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN) - - paddingAndBorderAxisColumn; - } - - // And we recursively call the layout algorithm for this child - layoutNode(currentFlexChild, maxWidth, maxHeight, direction); - - child = currentFlexChild; - currentFlexChild = currentFlexChild->next_flex_child; - child->next_flex_child = NULL; - } - - // We use justifyContent to figure out how to allocate the remaining - // space available - } else if (justifyContent != CSS_JUSTIFY_FLEX_START) { - if (justifyContent == CSS_JUSTIFY_CENTER) { - leadingMainDim = remainingMainDim / 2; - } else if (justifyContent == CSS_JUSTIFY_FLEX_END) { - leadingMainDim = remainingMainDim; - } else if (justifyContent == CSS_JUSTIFY_SPACE_BETWEEN) { - remainingMainDim = fmaxf(remainingMainDim, 0); - if (flexibleChildrenCount + nonFlexibleChildrenCount - 1 != 0) { - betweenMainDim = remainingMainDim / - (flexibleChildrenCount + nonFlexibleChildrenCount - 1); - } else { - betweenMainDim = 0; - } - } else if (justifyContent == CSS_JUSTIFY_SPACE_AROUND) { - // Space on the edges is half of the space between elements - betweenMainDim = remainingMainDim / - (flexibleChildrenCount + nonFlexibleChildrenCount); - leadingMainDim = betweenMainDim / 2; - } - } - - // Position elements in the main axis and compute dimensions - - // At this point, all the children have their dimensions set. We need to - // find their position. In order to do that, we accumulate data in - // variables that are also useful to compute the total dimensions of the - // container! - mainDim += leadingMainDim; - - for (i = firstComplexMain; i < endLine; ++i) { - child = node->get_child(node->context, i); - - if (child->style.position_type == CSS_POSITION_ABSOLUTE && - isPosDefined(child, leading[mainAxis])) { - // In case the child is position absolute and has left/top being - // defined, we override the position to whatever the user said - // (and margin/border). - child->layout.position[pos[mainAxis]] = getPosition(child, leading[mainAxis]) + - getLeadingBorder(node, mainAxis) + - getLeadingMargin(child, mainAxis); - } else { - // If the child is position absolute (without top/left) or relative, - // we put it at the current accumulated offset. - child->layout.position[pos[mainAxis]] += mainDim; - - // Define the trailing position accordingly. - if (isMainDimDefined) { - setTrailingPosition(node, child, mainAxis); - } - - // Now that we placed the element, we need to update the variables - // We only need to do that for relative elements. Absolute elements - // do not take part in that phase. - if (child->style.position_type == CSS_POSITION_RELATIVE) { - // The main dimension is the sum of all the elements dimension plus - // the spacing. - mainDim += betweenMainDim + getDimWithMargin(child, mainAxis); - // The cross dimension is the max of the elements dimension since there - // can only be one element in that cross dimension. - crossDim = fmaxf(crossDim, boundAxis(child, crossAxis, getDimWithMargin(child, crossAxis))); - } - } - } - - float containerCrossAxis = node->layout.dimensions[dim[crossAxis]]; - if (!isCrossDimDefined) { - containerCrossAxis = fmaxf( - // For the cross dim, we add both sides at the end because the value - // is aggregate via a max function. Intermediate negative values - // can mess this computation otherwise - boundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross), - paddingAndBorderAxisCross - ); - } - - // Position elements in the cross axis - for (i = firstComplexCross; i < endLine; ++i) { - child = node->get_child(node->context, i); - - if (child->style.position_type == CSS_POSITION_ABSOLUTE && - isPosDefined(child, leading[crossAxis])) { - // In case the child is absolutely positionned and has a - // top/left/bottom/right being set, we override all the previously - // computed positions to set it correctly. - child->layout.position[pos[crossAxis]] = getPosition(child, leading[crossAxis]) + - getLeadingBorder(node, crossAxis) + - getLeadingMargin(child, crossAxis); - - } else { - float leadingCrossDim = leadingPaddingAndBorderCross; - - // For a relative children, we're either using alignItems (parent) or - // alignSelf (child) in order to determine the position in the cross axis - if (child->style.position_type == CSS_POSITION_RELATIVE) { - /*eslint-disable */ - // This variable is intentionally re-defined as the code is transpiled to a block scope language - css_align_t alignItem = getAlignItem(node, child); - /*eslint-enable */ - if (alignItem == CSS_ALIGN_STRETCH) { - // You can only stretch if the dimension has not already been defined - // previously. - if (!isStyleDimDefined(child, crossAxis)) { - float dimCrossAxis = child->layout.dimensions[dim[crossAxis]]; - child->layout.dimensions[dim[crossAxis]] = fmaxf( - boundAxis(child, crossAxis, containerCrossAxis - - paddingAndBorderAxisCross - getMarginAxis(child, crossAxis)), - // You never want to go smaller than padding - getPaddingAndBorderAxis(child, crossAxis) - ); - - // If the size has changed, and this child has children we need to re-layout this child - if (dimCrossAxis != child->layout.dimensions[dim[crossAxis]] && child->children_count > 0) { - // Reset child margins before re-layout as they are added back in layoutNode and would be doubled - child->layout.position[leading[mainAxis]] -= getLeadingMargin(child, mainAxis) + - getRelativePosition(child, mainAxis); - child->layout.position[trailing[mainAxis]] -= getTrailingMargin(child, mainAxis) + - getRelativePosition(child, mainAxis); - child->layout.position[leading[crossAxis]] -= getLeadingMargin(child, crossAxis) + - getRelativePosition(child, crossAxis); - child->layout.position[trailing[crossAxis]] -= getTrailingMargin(child, crossAxis) + - getRelativePosition(child, crossAxis); - - layoutNode(child, maxWidth, maxHeight, direction); - } - } - } else if (alignItem != CSS_ALIGN_FLEX_START) { - // The remaining space between the parent dimensions+padding and child - // dimensions+margin. - float remainingCrossDim = containerCrossAxis - - paddingAndBorderAxisCross - getDimWithMargin(child, crossAxis); - - if (alignItem == CSS_ALIGN_CENTER) { - leadingCrossDim += remainingCrossDim / 2; - } else { // CSS_ALIGN_FLEX_END - leadingCrossDim += remainingCrossDim; - } - } - } - - // And we apply the position - child->layout.position[pos[crossAxis]] += linesCrossDim + leadingCrossDim; - - // Define the trailing position accordingly. - if (isCrossDimDefined) { - setTrailingPosition(node, child, crossAxis); - } - } - } - - linesCrossDim += crossDim; - linesMainDim = fmaxf(linesMainDim, mainDim); - linesCount += 1; - startLine = endLine; - } - - // - // - // Note(prenaux): More than one line, we need to layout the crossAxis - // according to alignContent. - // - // Note that we could probably remove and handle the one line case - // here too, but for the moment this is safer since it won't interfere with - // previously working code. - // - // See specs: - // http://www.w3.org/TR/2012/CR-css3-flexbox-20120918/#layout-algorithm - // section 9.4 - // - if (linesCount > 1 && isCrossDimDefined) { - float nodeCrossAxisInnerSize = node->layout.dimensions[dim[crossAxis]] - - paddingAndBorderAxisCross; - float remainingAlignContentDim = nodeCrossAxisInnerSize - linesCrossDim; - - float crossDimLead = 0; - float currentLead = leadingPaddingAndBorderCross; - - css_align_t alignContent = node->style.align_content; - if (alignContent == CSS_ALIGN_FLEX_END) { - currentLead += remainingAlignContentDim; - } else if (alignContent == CSS_ALIGN_CENTER) { - currentLead += remainingAlignContentDim / 2; - } else if (alignContent == CSS_ALIGN_STRETCH) { - if (nodeCrossAxisInnerSize > linesCrossDim) { - crossDimLead = (remainingAlignContentDim / linesCount); - } - } - - int endIndex = 0; - for (i = 0; i < linesCount; ++i) { - int startIndex = endIndex; - - // compute the line's height and find the endIndex - float lineHeight = 0; - for (ii = startIndex; ii < childCount; ++ii) { - child = node->get_child(node->context, ii); - if (child->style.position_type != CSS_POSITION_RELATIVE) { - continue; - } - if (child->line_index != i) { - break; - } - if (isLayoutDimDefined(child, crossAxis)) { - lineHeight = fmaxf( - lineHeight, - child->layout.dimensions[dim[crossAxis]] + getMarginAxis(child, crossAxis) - ); - } - } - endIndex = ii; - lineHeight += crossDimLead; - - for (ii = startIndex; ii < endIndex; ++ii) { - child = node->get_child(node->context, ii); - if (child->style.position_type != CSS_POSITION_RELATIVE) { - continue; - } - - css_align_t alignContentAlignItem = getAlignItem(node, child); - if (alignContentAlignItem == CSS_ALIGN_FLEX_START) { - child->layout.position[pos[crossAxis]] = currentLead + getLeadingMargin(child, crossAxis); - } else if (alignContentAlignItem == CSS_ALIGN_FLEX_END) { - child->layout.position[pos[crossAxis]] = currentLead + lineHeight - getTrailingMargin(child, crossAxis) - child->layout.dimensions[dim[crossAxis]]; - } else if (alignContentAlignItem == CSS_ALIGN_CENTER) { - float childHeight = child->layout.dimensions[dim[crossAxis]]; - child->layout.position[pos[crossAxis]] = currentLead + (lineHeight - childHeight) / 2; - } else if (alignContentAlignItem == CSS_ALIGN_STRETCH) { - child->layout.position[pos[crossAxis]] = currentLead + getLeadingMargin(child, crossAxis); - // TODO(prenaux): Correctly set the height of items with undefined - // (auto) crossAxis dimension. - } - } - - currentLead += lineHeight; - } - } - - bool needsMainTrailingPos = false; - bool needsCrossTrailingPos = false; - - // If the user didn't specify a width or height, and it has not been set - // by the container, then we set it via the children. - if (!isMainDimDefined) { - node->layout.dimensions[dim[mainAxis]] = fmaxf( - // We're missing the last padding at this point to get the final - // dimension - boundAxis(node, mainAxis, linesMainDim + getTrailingPaddingAndBorder(node, mainAxis)), - // We can never assign a width smaller than the padding and borders - paddingAndBorderAxisMain - ); - - if (mainAxis == CSS_FLEX_DIRECTION_ROW_REVERSE || - mainAxis == CSS_FLEX_DIRECTION_COLUMN_REVERSE) { - needsMainTrailingPos = true; - } - } - - if (!isCrossDimDefined) { - node->layout.dimensions[dim[crossAxis]] = fmaxf( - // For the cross dim, we add both sides at the end because the value - // is aggregate via a max function. Intermediate negative values - // can mess this computation otherwise - boundAxis(node, crossAxis, linesCrossDim + paddingAndBorderAxisCross), - paddingAndBorderAxisCross - ); - - if (crossAxis == CSS_FLEX_DIRECTION_ROW_REVERSE || - crossAxis == CSS_FLEX_DIRECTION_COLUMN_REVERSE) { - needsCrossTrailingPos = true; - } - } - - // Set trailing position if necessary - if (needsMainTrailingPos || needsCrossTrailingPos) { - for (i = 0; i < childCount; ++i) { - child = node->get_child(node->context, i); - - if (needsMainTrailingPos) { - setTrailingPosition(node, child, mainAxis); - } - - if (needsCrossTrailingPos) { - setTrailingPosition(node, child, crossAxis); - } - } - } - - // Calculate dimensions for absolutely positioned elements - currentAbsoluteChild = firstAbsoluteChild; - while (currentAbsoluteChild != NULL) { - // Pre-fill dimensions when using absolute position and both offsets for - // the axis are defined (either both left and right or top and bottom). - for (ii = 0; ii < 2; ii++) { - axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; - - if (isLayoutDimDefined(node, axis) && - !isStyleDimDefined(currentAbsoluteChild, axis) && - isPosDefined(currentAbsoluteChild, leading[axis]) && - isPosDefined(currentAbsoluteChild, trailing[axis])) { - currentAbsoluteChild->layout.dimensions[dim[axis]] = fmaxf( - boundAxis(currentAbsoluteChild, axis, node->layout.dimensions[dim[axis]] - - getBorderAxis(node, axis) - - getMarginAxis(currentAbsoluteChild, axis) - - getPosition(currentAbsoluteChild, leading[axis]) - - getPosition(currentAbsoluteChild, trailing[axis]) - ), - // You never want to go smaller than padding - getPaddingAndBorderAxis(currentAbsoluteChild, axis) - ); - } - - if (isPosDefined(currentAbsoluteChild, trailing[axis]) && - !isPosDefined(currentAbsoluteChild, leading[axis])) { - currentAbsoluteChild->layout.position[leading[axis]] = - node->layout.dimensions[dim[axis]] - - currentAbsoluteChild->layout.dimensions[dim[axis]] - - getPosition(currentAbsoluteChild, trailing[axis]); - } - } - - child = currentAbsoluteChild; - currentAbsoluteChild = currentAbsoluteChild->next_absolute_child; - child->next_absolute_child = NULL; - } - /** END_GENERATED **/ - } - - void layoutNode(css_node_t *node, float parentMaxWidth, float parentMaxHeight, css_direction_t parentDirection) { - css_layout_t *layout = &node->layout; - css_direction_t direction = node->style.direction; - layout->should_update = true; - - bool skipLayout = - !node->is_dirty(node->context) && - eq(layout->last_requested_dimensions[CSS_WIDTH], layout->dimensions[CSS_WIDTH]) && - eq(layout->last_requested_dimensions[CSS_HEIGHT], layout->dimensions[CSS_HEIGHT]) && - eq(layout->last_parent_max_width, parentMaxWidth) && - eq(layout->last_parent_max_height, parentMaxHeight) && - eq(layout->last_direction, direction); - - if (skipLayout) { - layout->dimensions[CSS_WIDTH] = layout->last_dimensions[CSS_WIDTH]; - layout->dimensions[CSS_HEIGHT] = layout->last_dimensions[CSS_HEIGHT]; - layout->position[CSS_TOP] = layout->last_position[CSS_TOP]; - layout->position[CSS_LEFT] = layout->last_position[CSS_LEFT]; - } else { - layout->last_requested_dimensions[CSS_WIDTH] = layout->dimensions[CSS_WIDTH]; - layout->last_requested_dimensions[CSS_HEIGHT] = layout->dimensions[CSS_HEIGHT]; - layout->last_parent_max_width = parentMaxWidth; - layout->last_parent_max_height = parentMaxHeight; - layout->last_direction = direction; - - for (int i = 0, childCount = node->children_count; i < childCount; i++) { - resetNodeLayout(node->get_child(node->context, i)); - } - - layoutNodeImpl(node, parentMaxWidth, parentMaxHeight, parentDirection); - - layout->last_dimensions[CSS_WIDTH] = layout->dimensions[CSS_WIDTH]; - layout->last_dimensions[CSS_HEIGHT] = layout->dimensions[CSS_HEIGHT]; - layout->last_position[CSS_TOP] = layout->position[CSS_TOP]; - layout->last_position[CSS_LEFT] = layout->position[CSS_LEFT]; - } - } - - void resetNodeLayout(css_node_t *node) { - node->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED; - node->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED; - node->layout.position[CSS_LEFT] = 0; - node->layout.position[CSS_TOP] = 0; - } +#include +#include +#include +#include + +// in concatenated header, don't include Layout.h it's already at the top +#ifndef CSS_LAYOUT_IMPLEMENTATION +#include "Layout.h" +#endif + +#ifdef _MSC_VER +#include +#define isnan _isnan + +/* define fmaxf if < VC12 */ +#if _MSC_VER < 1800 +__forceinline const float fmaxf(const float a, const float b) { + return (a > b) ? a : b; +} +#endif +#endif + +bool isUndefined(float value) { + return isnan(value); +} + +static bool eq(float a, float b) { + if (isUndefined(a)) { + return isUndefined(b); + } + return fabs(a - b) < 0.0001; +} + +void init_css_node(css_node_t *node) { + node->style.align_items = CSS_ALIGN_STRETCH; + node->style.align_content = CSS_ALIGN_FLEX_START; + + node->style.direction = CSS_DIRECTION_INHERIT; + node->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN; + + // Some of the fields default to undefined and not 0 + node->style.dimensions[CSS_WIDTH] = CSS_UNDEFINED; + node->style.dimensions[CSS_HEIGHT] = CSS_UNDEFINED; + + node->style.minDimensions[CSS_WIDTH] = CSS_UNDEFINED; + node->style.minDimensions[CSS_HEIGHT] = CSS_UNDEFINED; + + node->style.maxDimensions[CSS_WIDTH] = CSS_UNDEFINED; + node->style.maxDimensions[CSS_HEIGHT] = CSS_UNDEFINED; + + node->style.position[CSS_LEFT] = CSS_UNDEFINED; + node->style.position[CSS_TOP] = CSS_UNDEFINED; + node->style.position[CSS_RIGHT] = CSS_UNDEFINED; + node->style.position[CSS_BOTTOM] = CSS_UNDEFINED; + + node->style.margin[CSS_START] = CSS_UNDEFINED; + node->style.margin[CSS_END] = CSS_UNDEFINED; + node->style.padding[CSS_START] = CSS_UNDEFINED; + node->style.padding[CSS_END] = CSS_UNDEFINED; + node->style.border[CSS_START] = CSS_UNDEFINED; + node->style.border[CSS_END] = CSS_UNDEFINED; + + node->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED; + node->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED; + + // Such that the comparison is always going to be false + node->layout.last_requested_dimensions[CSS_WIDTH] = -1; + node->layout.last_requested_dimensions[CSS_HEIGHT] = -1; + node->layout.last_parent_max_width = -1; + node->layout.last_parent_max_height = -1; + node->layout.last_direction = (css_direction_t)-1; + node->layout.should_update = true; +} + +css_node_t *new_css_node() { + css_node_t *node = (css_node_t *)calloc(1, sizeof(*node)); + init_css_node(node); + return node; +} + +void free_css_node(css_node_t *node) { + free(node); +} + +static void indent(int n) { + for (int i = 0; i < n; ++i) { + printf(" "); + } +} + +static void print_number_0(const char *str, float number) { + if (!eq(number, 0)) { + printf("%s: %g, ", str, number); + } +} + +static void print_number_nan(const char *str, float number) { + if (!isnan(number)) { + printf("%s: %g, ", str, number); + } +} + +static bool four_equal(float four[4]) { + return + eq(four[0], four[1]) && + eq(four[0], four[2]) && + eq(four[0], four[3]); +} + + +static void print_css_node_rec( + css_node_t *node, + css_print_options_t options, + int level +) { + indent(level); + printf("{"); + + if (node->print) { + node->print(node->context); + } + + if (options & CSS_PRINT_LAYOUT) { + printf("layout: {"); + printf("width: %g, ", node->layout.dimensions[CSS_WIDTH]); + printf("height: %g, ", node->layout.dimensions[CSS_HEIGHT]); + printf("top: %g, ", node->layout.position[CSS_TOP]); + printf("left: %g", node->layout.position[CSS_LEFT]); + printf("}, "); + } + + if (options & CSS_PRINT_STYLE) { + if (node->style.flex_direction == CSS_FLEX_DIRECTION_COLUMN) { + printf("flexDirection: 'column', "); + } else if (node->style.flex_direction == CSS_FLEX_DIRECTION_COLUMN_REVERSE) { + printf("flexDirection: 'columnReverse', "); + } else if (node->style.flex_direction == CSS_FLEX_DIRECTION_ROW) { + printf("flexDirection: 'row', "); + } else if (node->style.flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE) { + printf("flexDirection: 'rowReverse', "); + } + + if (node->style.justify_content == CSS_JUSTIFY_CENTER) { + printf("justifyContent: 'center', "); + } else if (node->style.justify_content == CSS_JUSTIFY_FLEX_END) { + printf("justifyContent: 'flex-end', "); + } else if (node->style.justify_content == CSS_JUSTIFY_SPACE_AROUND) { + printf("justifyContent: 'space-around', "); + } else if (node->style.justify_content == CSS_JUSTIFY_SPACE_BETWEEN) { + printf("justifyContent: 'space-between', "); + } + + if (node->style.align_items == CSS_ALIGN_CENTER) { + printf("alignItems: 'center', "); + } else if (node->style.align_items == CSS_ALIGN_FLEX_END) { + printf("alignItems: 'flex-end', "); + } else if (node->style.align_items == CSS_ALIGN_STRETCH) { + printf("alignItems: 'stretch', "); + } + + if (node->style.align_content == CSS_ALIGN_CENTER) { + printf("alignContent: 'center', "); + } else if (node->style.align_content == CSS_ALIGN_FLEX_END) { + printf("alignContent: 'flex-end', "); + } else if (node->style.align_content == CSS_ALIGN_STRETCH) { + printf("alignContent: 'stretch', "); + } + + if (node->style.align_self == CSS_ALIGN_FLEX_START) { + printf("alignSelf: 'flex-start', "); + } else if (node->style.align_self == CSS_ALIGN_CENTER) { + printf("alignSelf: 'center', "); + } else if (node->style.align_self == CSS_ALIGN_FLEX_END) { + printf("alignSelf: 'flex-end', "); + } else if (node->style.align_self == CSS_ALIGN_STRETCH) { + printf("alignSelf: 'stretch', "); + } + + print_number_nan("flex", node->style.flex); + + if (four_equal(node->style.margin)) { + print_number_0("margin", node->style.margin[CSS_LEFT]); + } else { + print_number_0("marginLeft", node->style.margin[CSS_LEFT]); + print_number_0("marginRight", node->style.margin[CSS_RIGHT]); + print_number_0("marginTop", node->style.margin[CSS_TOP]); + print_number_0("marginBottom", node->style.margin[CSS_BOTTOM]); + print_number_0("marginStart", node->style.margin[CSS_START]); + print_number_0("marginEnd", node->style.margin[CSS_END]); + } + + if (four_equal(node->style.padding)) { + print_number_0("padding", node->style.margin[CSS_LEFT]); + } else { + print_number_0("paddingLeft", node->style.padding[CSS_LEFT]); + print_number_0("paddingRight", node->style.padding[CSS_RIGHT]); + print_number_0("paddingTop", node->style.padding[CSS_TOP]); + print_number_0("paddingBottom", node->style.padding[CSS_BOTTOM]); + print_number_0("paddingStart", node->style.padding[CSS_START]); + print_number_0("paddingEnd", node->style.padding[CSS_END]); + } + + if (four_equal(node->style.border)) { + print_number_0("borderWidth", node->style.border[CSS_LEFT]); + } else { + print_number_0("borderLeftWidth", node->style.border[CSS_LEFT]); + print_number_0("borderRightWidth", node->style.border[CSS_RIGHT]); + print_number_0("borderTopWidth", node->style.border[CSS_TOP]); + print_number_0("borderBottomWidth", node->style.border[CSS_BOTTOM]); + print_number_0("borderStartWidth", node->style.border[CSS_START]); + print_number_0("borderEndWidth", node->style.border[CSS_END]); + } + + print_number_nan("width", node->style.dimensions[CSS_WIDTH]); + print_number_nan("height", node->style.dimensions[CSS_HEIGHT]); + + if (node->style.position_type == CSS_POSITION_ABSOLUTE) { + printf("position: 'absolute', "); + } + + print_number_nan("left", node->style.position[CSS_LEFT]); + print_number_nan("right", node->style.position[CSS_RIGHT]); + print_number_nan("top", node->style.position[CSS_TOP]); + print_number_nan("bottom", node->style.position[CSS_BOTTOM]); + } + + if (options & CSS_PRINT_CHILDREN && node->children_count > 0) { + printf("children: [\n"); + for (int i = 0; i < node->children_count; ++i) { + print_css_node_rec(node->get_child(node->context, i), options, level + 1); + } + indent(level); + printf("]},\n"); + } else { + printf("},\n"); + } +} + +void print_css_node(css_node_t *node, css_print_options_t options) { + print_css_node_rec(node, options, 0); +} + + +static css_position_t leading[4] = { + /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_TOP, + /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_BOTTOM, + /* CSS_FLEX_DIRECTION_ROW = */ CSS_LEFT, + /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_RIGHT +}; +static css_position_t trailing[4] = { + /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_BOTTOM, + /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_TOP, + /* CSS_FLEX_DIRECTION_ROW = */ CSS_RIGHT, + /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_LEFT +}; +static css_position_t pos[4] = { + /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_TOP, + /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_BOTTOM, + /* CSS_FLEX_DIRECTION_ROW = */ CSS_LEFT, + /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_RIGHT +}; +static css_dimension_t dim[4] = { + /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_HEIGHT, + /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_HEIGHT, + /* CSS_FLEX_DIRECTION_ROW = */ CSS_WIDTH, + /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_WIDTH +}; + +static bool isRowDirection(css_flex_direction_t flex_direction) { + return flex_direction == CSS_FLEX_DIRECTION_ROW || + flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE; +} + +static bool isColumnDirection(css_flex_direction_t flex_direction) { + return flex_direction == CSS_FLEX_DIRECTION_COLUMN || + flex_direction == CSS_FLEX_DIRECTION_COLUMN_REVERSE; +} + +static float getLeadingMargin(css_node_t *node, css_flex_direction_t axis) { + if (isRowDirection(axis) && !isUndefined(node->style.margin[CSS_START])) { + return node->style.margin[CSS_START]; + } + + return node->style.margin[leading[axis]]; +} + +static float getTrailingMargin(css_node_t *node, css_flex_direction_t axis) { + if (isRowDirection(axis) && !isUndefined(node->style.margin[CSS_END])) { + return node->style.margin[CSS_END]; + } + + return node->style.margin[trailing[axis]]; +} + +static float getLeadingPadding(css_node_t *node, css_flex_direction_t axis) { + if (isRowDirection(axis) && + !isUndefined(node->style.padding[CSS_START]) && + node->style.padding[CSS_START] >= 0) { + return node->style.padding[CSS_START]; + } + + if (node->style.padding[leading[axis]] >= 0) { + return node->style.padding[leading[axis]]; + } + + return 0; +} + +static float getTrailingPadding(css_node_t *node, css_flex_direction_t axis) { + if (isRowDirection(axis) && + !isUndefined(node->style.padding[CSS_END]) && + node->style.padding[CSS_END] >= 0) { + return node->style.padding[CSS_END]; + } + + if (node->style.padding[trailing[axis]] >= 0) { + return node->style.padding[trailing[axis]]; + } + + return 0; +} + +static float getLeadingBorder(css_node_t *node, css_flex_direction_t axis) { + if (isRowDirection(axis) && + !isUndefined(node->style.border[CSS_START]) && + node->style.border[CSS_START] >= 0) { + return node->style.border[CSS_START]; + } + + if (node->style.border[leading[axis]] >= 0) { + return node->style.border[leading[axis]]; + } + + return 0; +} + +static float getTrailingBorder(css_node_t *node, css_flex_direction_t axis) { + if (isRowDirection(axis) && + !isUndefined(node->style.border[CSS_END]) && + node->style.border[CSS_END] >= 0) { + return node->style.border[CSS_END]; + } + + if (node->style.border[trailing[axis]] >= 0) { + return node->style.border[trailing[axis]]; + } + + return 0; +} + +static float getLeadingPaddingAndBorder(css_node_t *node, css_flex_direction_t axis) { + return getLeadingPadding(node, axis) + getLeadingBorder(node, axis); +} + +static float getTrailingPaddingAndBorder(css_node_t *node, css_flex_direction_t axis) { + return getTrailingPadding(node, axis) + getTrailingBorder(node, axis); +} + +static float getBorderAxis(css_node_t *node, css_flex_direction_t axis) { + return getLeadingBorder(node, axis) + getTrailingBorder(node, axis); +} + +static float getMarginAxis(css_node_t *node, css_flex_direction_t axis) { + return getLeadingMargin(node, axis) + getTrailingMargin(node, axis); +} + +static float getPaddingAndBorderAxis(css_node_t *node, css_flex_direction_t axis) { + return getLeadingPaddingAndBorder(node, axis) + getTrailingPaddingAndBorder(node, axis); +} + +static css_align_t getAlignItem(css_node_t *node, css_node_t *child) { + if (child->style.align_self != CSS_ALIGN_AUTO) { + return child->style.align_self; + } + return node->style.align_items; +} + +static css_direction_t resolveDirection(css_node_t *node, css_direction_t parentDirection) { + css_direction_t direction = node->style.direction; + + if (direction == CSS_DIRECTION_INHERIT) { + direction = parentDirection > CSS_DIRECTION_INHERIT ? parentDirection : CSS_DIRECTION_LTR; + } + + return direction; +} + +static css_flex_direction_t getFlexDirection(css_node_t *node) { + return node->style.flex_direction; +} + +static css_flex_direction_t resolveAxis(css_flex_direction_t flex_direction, css_direction_t direction) { + if (direction == CSS_DIRECTION_RTL) { + if (flex_direction == CSS_FLEX_DIRECTION_ROW) { + return CSS_FLEX_DIRECTION_ROW_REVERSE; + } else if (flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE) { + return CSS_FLEX_DIRECTION_ROW; + } + } + + return flex_direction; +} + +static css_flex_direction_t getCrossFlexDirection(css_flex_direction_t flex_direction, css_direction_t direction) { + if (isColumnDirection(flex_direction)) { + return resolveAxis(CSS_FLEX_DIRECTION_ROW, direction); + } else { + return CSS_FLEX_DIRECTION_COLUMN; + } +} + +static float getFlex(css_node_t *node) { + return node->style.flex; +} + +static bool isFlex(css_node_t *node) { + return ( + node->style.position_type == CSS_POSITION_RELATIVE && + getFlex(node) > 0 + ); +} + +static bool isFlexWrap(css_node_t *node) { + return node->style.flex_wrap == CSS_WRAP; +} + +static float getDimWithMargin(css_node_t *node, css_flex_direction_t axis) { + return node->layout.dimensions[dim[axis]] + + getLeadingMargin(node, axis) + + getTrailingMargin(node, axis); +} + +static bool isStyleDimDefined(css_node_t *node, css_flex_direction_t axis) { + float value = node->style.dimensions[dim[axis]]; + return !isUndefined(value) && value >= 0.0; +} + +static bool isLayoutDimDefined(css_node_t *node, css_flex_direction_t axis) { + float value = node->layout.dimensions[dim[axis]]; + return !isUndefined(value) && value >= 0.0; +} + +static bool isPosDefined(css_node_t *node, css_position_t position) { + return !isUndefined(node->style.position[position]); +} + +static bool isMeasureDefined(css_node_t *node) { + return node->measure; +} + +static float getPosition(css_node_t *node, css_position_t position) { + float result = node->style.position[position]; + if (!isUndefined(result)) { + return result; + } + return 0; +} + +static float boundAxis(css_node_t *node, css_flex_direction_t axis, float value) { + float min = CSS_UNDEFINED; + float max = CSS_UNDEFINED; + + if (isColumnDirection(axis)) { + min = node->style.minDimensions[CSS_HEIGHT]; + max = node->style.maxDimensions[CSS_HEIGHT]; + } else if (isRowDirection(axis)) { + min = node->style.minDimensions[CSS_WIDTH]; + max = node->style.maxDimensions[CSS_WIDTH]; + } + + float boundValue = value; + + if (!isUndefined(max) && max >= 0.0 && boundValue > max) { + boundValue = max; + } + if (!isUndefined(min) && min >= 0.0 && boundValue < min) { + boundValue = min; + } + + return boundValue; +} + +// When the user specifically sets a value for width or height +static void setDimensionFromStyle(css_node_t *node, css_flex_direction_t axis) { + // The parent already computed us a width or height. We just skip it + if (isLayoutDimDefined(node, axis)) { + return; + } + // We only run if there's a width or height defined + if (!isStyleDimDefined(node, axis)) { + return; + } + + // The dimensions can never be smaller than the padding and border + node->layout.dimensions[dim[axis]] = fmaxf( + boundAxis(node, axis, node->style.dimensions[dim[axis]]), + getPaddingAndBorderAxis(node, axis) + ); +} + +static void setTrailingPosition(css_node_t *node, css_node_t *child, css_flex_direction_t axis) { + child->layout.position[trailing[axis]] = node->layout.dimensions[dim[axis]] - + child->layout.dimensions[dim[axis]] - child->layout.position[pos[axis]]; + } + +// If both left and right are defined, then use left. Otherwise return +// +left or -right depending on which is defined. +static float getRelativePosition(css_node_t *node, css_flex_direction_t axis) { + float lead = node->style.position[leading[axis]]; + if (!isUndefined(lead)) { + return lead; + } + return -getPosition(node, trailing[axis]); +} + +static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentMaxHeight, css_direction_t parentDirection) { + /** START_GENERATED **/ + css_direction_t direction = resolveDirection(node, parentDirection); + css_flex_direction_t mainAxis = resolveAxis(getFlexDirection(node), direction); + css_flex_direction_t crossAxis = getCrossFlexDirection(mainAxis, direction); + css_flex_direction_t resolvedRowAxis = resolveAxis(CSS_FLEX_DIRECTION_ROW, direction); + + // Handle width and height style attributes + setDimensionFromStyle(node, mainAxis); + setDimensionFromStyle(node, crossAxis); + + // Set the resolved resolution in the node's layout + node->layout.direction = direction; + + // The position is set by the parent, but we need to complete it with a + // delta composed of the margin and left/top/right/bottom + node->layout.position[leading[mainAxis]] += getLeadingMargin(node, mainAxis) + + getRelativePosition(node, mainAxis); + node->layout.position[trailing[mainAxis]] += getTrailingMargin(node, mainAxis) + + getRelativePosition(node, mainAxis); + node->layout.position[leading[crossAxis]] += getLeadingMargin(node, crossAxis) + + getRelativePosition(node, crossAxis); + node->layout.position[trailing[crossAxis]] += getTrailingMargin(node, crossAxis) + + getRelativePosition(node, crossAxis); + + // Inline immutable values from the target node to avoid excessive method + // invocations during the layout calculation. + int childCount = node->children_count; + float paddingAndBorderAxisResolvedRow = getPaddingAndBorderAxis(node, resolvedRowAxis); + float paddingAndBorderAxisColumn = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN); + + if (isMeasureDefined(node)) { + bool isResolvedRowDimDefined = isLayoutDimDefined(node, resolvedRowAxis); + + float width = CSS_UNDEFINED; + if (isStyleDimDefined(node, resolvedRowAxis)) { + width = node->style.dimensions[CSS_WIDTH]; + } else if (isResolvedRowDimDefined) { + width = node->layout.dimensions[dim[resolvedRowAxis]]; + } else { + width = parentMaxWidth - + getMarginAxis(node, resolvedRowAxis); + } + width -= paddingAndBorderAxisResolvedRow; + + float height = CSS_UNDEFINED; + if (isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) { + height = node->style.dimensions[CSS_HEIGHT]; + } else if (isLayoutDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) { + height = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]; + } else { + height = parentMaxHeight - + getMarginAxis(node, resolvedRowAxis); + } + height -= getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN); + + // We only need to give a dimension for the text if we haven't got any + // for it computed yet. It can either be from the style attribute or because + // the element is flexible. + bool isRowUndefined = !isStyleDimDefined(node, resolvedRowAxis) && !isResolvedRowDimDefined; + bool isColumnUndefined = !isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN) && + isUndefined(node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]); + + // Let's not measure the text if we already know both dimensions + if (isRowUndefined || isColumnUndefined) { + css_dim_t measureDim = node->measure( + node->context, + + width, + height + ); + if (isRowUndefined) { + node->layout.dimensions[CSS_WIDTH] = measureDim.dimensions[CSS_WIDTH] + + paddingAndBorderAxisResolvedRow; + } + if (isColumnUndefined) { + node->layout.dimensions[CSS_HEIGHT] = measureDim.dimensions[CSS_HEIGHT] + + paddingAndBorderAxisColumn; + } + } + if (childCount == 0) { + return; + } + } + + bool isNodeFlexWrap = isFlexWrap(node); + + css_justify_t justifyContent = node->style.justify_content; + + float leadingPaddingAndBorderMain = getLeadingPaddingAndBorder(node, mainAxis); + float leadingPaddingAndBorderCross = getLeadingPaddingAndBorder(node, crossAxis); + float paddingAndBorderAxisMain = getPaddingAndBorderAxis(node, mainAxis); + float paddingAndBorderAxisCross = getPaddingAndBorderAxis(node, crossAxis); + + bool isMainDimDefined = isLayoutDimDefined(node, mainAxis); + bool isCrossDimDefined = isLayoutDimDefined(node, crossAxis); + bool isMainRowDirection = isRowDirection(mainAxis); + + int i; + int ii; + css_node_t* child; + css_flex_direction_t axis; + + css_node_t* firstAbsoluteChild = NULL; + css_node_t* currentAbsoluteChild = NULL; + + float definedMainDim = CSS_UNDEFINED; + if (isMainDimDefined) { + definedMainDim = node->layout.dimensions[dim[mainAxis]] - paddingAndBorderAxisMain; + } + + // We want to execute the next two loops one per line with flex-wrap + int startLine = 0; + int endLine = 0; + // int nextOffset = 0; + int alreadyComputedNextLayout = 0; + // We aggregate the total dimensions of the container in those two variables + float linesCrossDim = 0; + float linesMainDim = 0; + int linesCount = 0; + while (endLine < childCount) { + // Layout non flexible children and count children by type + + // mainContentDim is accumulation of the dimensions and margin of all the + // non flexible children. This will be used in order to either set the + // dimensions of the node if none already exist, or to compute the + // remaining space left for the flexible children. + float mainContentDim = 0; + + // There are three kind of children, non flexible, flexible and absolute. + // We need to know how many there are in order to distribute the space. + int flexibleChildrenCount = 0; + float totalFlexible = 0; + int nonFlexibleChildrenCount = 0; + + // Use the line loop to position children in the main axis for as long + // as they are using a simple stacking behaviour. Children that are + // immediately stacked in the initial loop will not be touched again + // in . + bool isSimpleStackMain = + (isMainDimDefined && justifyContent == CSS_JUSTIFY_FLEX_START) || + (!isMainDimDefined && justifyContent != CSS_JUSTIFY_CENTER); + int firstComplexMain = (isSimpleStackMain ? childCount : startLine); + + // Use the initial line loop to position children in the cross axis for + // as long as they are relatively positioned with alignment STRETCH or + // FLEX_START. Children that are immediately stacked in the initial loop + // will not be touched again in . + bool isSimpleStackCross = true; + int firstComplexCross = childCount; + + css_node_t* firstFlexChild = NULL; + css_node_t* currentFlexChild = NULL; + + float mainDim = leadingPaddingAndBorderMain; + float crossDim = 0; + + float maxWidth = CSS_UNDEFINED; + float maxHeight = CSS_UNDEFINED; + for (i = startLine; i < childCount; ++i) { + child = node->get_child(node->context, i); + child->line_index = linesCount; + + child->next_absolute_child = NULL; + child->next_flex_child = NULL; + + css_align_t alignItem = getAlignItem(node, child); + + // Pre-fill cross axis dimensions when the child is using stretch before + // we call the recursive layout pass + if (alignItem == CSS_ALIGN_STRETCH && + child->style.position_type == CSS_POSITION_RELATIVE && + isCrossDimDefined && + !isStyleDimDefined(child, crossAxis)) { + child->layout.dimensions[dim[crossAxis]] = fmaxf( + boundAxis(child, crossAxis, node->layout.dimensions[dim[crossAxis]] - + paddingAndBorderAxisCross - getMarginAxis(child, crossAxis)), + // You never want to go smaller than padding + getPaddingAndBorderAxis(child, crossAxis) + ); + } else if (child->style.position_type == CSS_POSITION_ABSOLUTE) { + // Store a private linked list of absolutely positioned children + // so that we can efficiently traverse them later. + if (firstAbsoluteChild == NULL) { + firstAbsoluteChild = child; + } + if (currentAbsoluteChild != NULL) { + currentAbsoluteChild->next_absolute_child = child; + } + currentAbsoluteChild = child; + + // Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both + // left and right or top and bottom). + for (ii = 0; ii < 2; ii++) { + axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; + if (isLayoutDimDefined(node, axis) && + !isStyleDimDefined(child, axis) && + isPosDefined(child, leading[axis]) && + isPosDefined(child, trailing[axis])) { + child->layout.dimensions[dim[axis]] = fmaxf( + boundAxis(child, axis, node->layout.dimensions[dim[axis]] - + getPaddingAndBorderAxis(node, axis) - + getMarginAxis(child, axis) - + getPosition(child, leading[axis]) - + getPosition(child, trailing[axis])), + // You never want to go smaller than padding + getPaddingAndBorderAxis(child, axis) + ); + } + } + } + + float nextContentDim = 0; + + // It only makes sense to consider a child flexible if we have a computed + // dimension for the node-> + if (isMainDimDefined && isFlex(child)) { + flexibleChildrenCount++; + totalFlexible += child->style.flex; + + // Store a private linked list of flexible children so that we can + // efficiently traverse them later. + if (firstFlexChild == NULL) { + firstFlexChild = child; + } + if (currentFlexChild != NULL) { + currentFlexChild->next_flex_child = child; + } + currentFlexChild = child; + + // Even if we don't know its exact size yet, we already know the padding, + // border and margin. We'll use this partial information, which represents + // the smallest possible size for the child, to compute the remaining + // available space. + nextContentDim = getPaddingAndBorderAxis(child, mainAxis) + + getMarginAxis(child, mainAxis); + + } else { + maxWidth = CSS_UNDEFINED; + maxHeight = CSS_UNDEFINED; + + if (!isMainRowDirection) { + if (isLayoutDimDefined(node, resolvedRowAxis)) { + maxWidth = node->layout.dimensions[dim[resolvedRowAxis]] - + paddingAndBorderAxisResolvedRow; + } else { + maxWidth = parentMaxWidth - + getMarginAxis(node, resolvedRowAxis) - + paddingAndBorderAxisResolvedRow; + } + } else { + if (isLayoutDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) { + maxHeight = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] - + paddingAndBorderAxisColumn; + } else { + maxHeight = parentMaxHeight - + getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN) - + paddingAndBorderAxisColumn; + } + } + + // This is the main recursive call. We layout non flexible children. + if (alreadyComputedNextLayout == 0) { + layoutNode(child, maxWidth, maxHeight, direction); + } + + // Absolute positioned elements do not take part of the layout, so we + // don't use them to compute mainContentDim + if (child->style.position_type == CSS_POSITION_RELATIVE) { + nonFlexibleChildrenCount++; + // At this point we know the final size and margin of the element. + nextContentDim = getDimWithMargin(child, mainAxis); + } + } + + // The element we are about to add would make us go to the next line + if (isNodeFlexWrap && + isMainDimDefined && + mainContentDim + nextContentDim > definedMainDim && + // If there's only one element, then it's bigger than the content + // and needs its own line + i != startLine) { + nonFlexibleChildrenCount--; + alreadyComputedNextLayout = 1; + break; + } + + // Disable simple stacking in the main axis for the current line as + // we found a non-trivial child-> The remaining children will be laid out + // in . + if (isSimpleStackMain && + (child->style.position_type != CSS_POSITION_RELATIVE || isFlex(child))) { + isSimpleStackMain = false; + firstComplexMain = i; + } + + // Disable simple stacking in the cross axis for the current line as + // we found a non-trivial child-> The remaining children will be laid out + // in . + if (isSimpleStackCross && + (child->style.position_type != CSS_POSITION_RELATIVE || + (alignItem != CSS_ALIGN_STRETCH && alignItem != CSS_ALIGN_FLEX_START) || + (alignItem == CSS_ALIGN_STRETCH && !isCrossDimDefined))) { + isSimpleStackCross = false; + firstComplexCross = i; + } + + if (isSimpleStackMain) { + child->layout.position[pos[mainAxis]] += mainDim; + if (isMainDimDefined) { + setTrailingPosition(node, child, mainAxis); + } + + mainDim += getDimWithMargin(child, mainAxis); + crossDim = fmaxf(crossDim, boundAxis(child, crossAxis, getDimWithMargin(child, crossAxis))); + } + + if (isSimpleStackCross) { + child->layout.position[pos[crossAxis]] += linesCrossDim + leadingPaddingAndBorderCross; + if (isCrossDimDefined) { + setTrailingPosition(node, child, crossAxis); + } + } + + alreadyComputedNextLayout = 0; + mainContentDim += nextContentDim; + endLine = i + 1; + } + + // Layout flexible children and allocate empty space + + // In order to position the elements in the main axis, we have two + // controls. The space between the beginning and the first element + // and the space between each two elements. + float leadingMainDim = 0; + float betweenMainDim = 0; + + // The remaining available space that needs to be allocated + float remainingMainDim = 0; + if (isMainDimDefined) { + remainingMainDim = definedMainDim - mainContentDim; + } else { + remainingMainDim = fmaxf(mainContentDim, 0) - mainContentDim; + } + + // If there are flexible children in the mix, they are going to fill the + // remaining space + if (flexibleChildrenCount != 0) { + float flexibleMainDim = remainingMainDim / totalFlexible; + float baseMainDim; + float boundMainDim; + + // If the flex share of remaining space doesn't meet min/max bounds, + // remove this child from flex calculations. + currentFlexChild = firstFlexChild; + while (currentFlexChild != NULL) { + baseMainDim = flexibleMainDim * currentFlexChild->style.flex + + getPaddingAndBorderAxis(currentFlexChild, mainAxis); + boundMainDim = boundAxis(currentFlexChild, mainAxis, baseMainDim); + + if (baseMainDim != boundMainDim) { + remainingMainDim -= boundMainDim; + totalFlexible -= currentFlexChild->style.flex; + } + + currentFlexChild = currentFlexChild->next_flex_child; + } + flexibleMainDim = remainingMainDim / totalFlexible; + + // The non flexible children can overflow the container, in this case + // we should just assume that there is no space available. + if (flexibleMainDim < 0) { + flexibleMainDim = 0; + } + + currentFlexChild = firstFlexChild; + while (currentFlexChild != NULL) { + // At this point we know the final size of the element in the main + // dimension + currentFlexChild->layout.dimensions[dim[mainAxis]] = boundAxis(currentFlexChild, mainAxis, + flexibleMainDim * currentFlexChild->style.flex + + getPaddingAndBorderAxis(currentFlexChild, mainAxis) + ); + + maxWidth = CSS_UNDEFINED; + if (isLayoutDimDefined(node, resolvedRowAxis)) { + maxWidth = node->layout.dimensions[dim[resolvedRowAxis]] - + paddingAndBorderAxisResolvedRow; + } else if (!isMainRowDirection) { + maxWidth = parentMaxWidth - + getMarginAxis(node, resolvedRowAxis) - + paddingAndBorderAxisResolvedRow; + } + maxHeight = CSS_UNDEFINED; + if (isLayoutDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) { + maxHeight = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] - + paddingAndBorderAxisColumn; + } else if (isMainRowDirection) { + maxHeight = parentMaxHeight - + getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN) - + paddingAndBorderAxisColumn; + } + + // And we recursively call the layout algorithm for this child + layoutNode(currentFlexChild, maxWidth, maxHeight, direction); + + child = currentFlexChild; + currentFlexChild = currentFlexChild->next_flex_child; + child->next_flex_child = NULL; + } + + // We use justifyContent to figure out how to allocate the remaining + // space available + } else if (justifyContent != CSS_JUSTIFY_FLEX_START) { + if (justifyContent == CSS_JUSTIFY_CENTER) { + leadingMainDim = remainingMainDim / 2; + } else if (justifyContent == CSS_JUSTIFY_FLEX_END) { + leadingMainDim = remainingMainDim; + } else if (justifyContent == CSS_JUSTIFY_SPACE_BETWEEN) { + remainingMainDim = fmaxf(remainingMainDim, 0); + if (flexibleChildrenCount + nonFlexibleChildrenCount - 1 != 0) { + betweenMainDim = remainingMainDim / + (flexibleChildrenCount + nonFlexibleChildrenCount - 1); + } else { + betweenMainDim = 0; + } + } else if (justifyContent == CSS_JUSTIFY_SPACE_AROUND) { + // Space on the edges is half of the space between elements + betweenMainDim = remainingMainDim / + (flexibleChildrenCount + nonFlexibleChildrenCount); + leadingMainDim = betweenMainDim / 2; + } + } + + // Position elements in the main axis and compute dimensions + + // At this point, all the children have their dimensions set. We need to + // find their position. In order to do that, we accumulate data in + // variables that are also useful to compute the total dimensions of the + // container! + mainDim += leadingMainDim; + + for (i = firstComplexMain; i < endLine; ++i) { + child = node->get_child(node->context, i); + + if (child->style.position_type == CSS_POSITION_ABSOLUTE && + isPosDefined(child, leading[mainAxis])) { + // In case the child is position absolute and has left/top being + // defined, we override the position to whatever the user said + // (and margin/border). + child->layout.position[pos[mainAxis]] = getPosition(child, leading[mainAxis]) + + getLeadingBorder(node, mainAxis) + + getLeadingMargin(child, mainAxis); + } else { + // If the child is position absolute (without top/left) or relative, + // we put it at the current accumulated offset. + child->layout.position[pos[mainAxis]] += mainDim; + + // Define the trailing position accordingly. + if (isMainDimDefined) { + setTrailingPosition(node, child, mainAxis); + } + + // Now that we placed the element, we need to update the variables + // We only need to do that for relative elements. Absolute elements + // do not take part in that phase. + if (child->style.position_type == CSS_POSITION_RELATIVE) { + // The main dimension is the sum of all the elements dimension plus + // the spacing. + mainDim += betweenMainDim + getDimWithMargin(child, mainAxis); + // The cross dimension is the max of the elements dimension since there + // can only be one element in that cross dimension. + crossDim = fmaxf(crossDim, boundAxis(child, crossAxis, getDimWithMargin(child, crossAxis))); + } + } + } + + float containerCrossAxis = node->layout.dimensions[dim[crossAxis]]; + if (!isCrossDimDefined) { + containerCrossAxis = fmaxf( + // For the cross dim, we add both sides at the end because the value + // is aggregate via a max function. Intermediate negative values + // can mess this computation otherwise + boundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross), + paddingAndBorderAxisCross + ); + } + + // Position elements in the cross axis + for (i = firstComplexCross; i < endLine; ++i) { + child = node->get_child(node->context, i); + + if (child->style.position_type == CSS_POSITION_ABSOLUTE && + isPosDefined(child, leading[crossAxis])) { + // In case the child is absolutely positionned and has a + // top/left/bottom/right being set, we override all the previously + // computed positions to set it correctly. + child->layout.position[pos[crossAxis]] = getPosition(child, leading[crossAxis]) + + getLeadingBorder(node, crossAxis) + + getLeadingMargin(child, crossAxis); + + } else { + float leadingCrossDim = leadingPaddingAndBorderCross; + + // For a relative children, we're either using alignItems (parent) or + // alignSelf (child) in order to determine the position in the cross axis + if (child->style.position_type == CSS_POSITION_RELATIVE) { + /*eslint-disable */ + // This variable is intentionally re-defined as the code is transpiled to a block scope language + css_align_t alignItem = getAlignItem(node, child); + /*eslint-enable */ + if (alignItem == CSS_ALIGN_STRETCH) { + // You can only stretch if the dimension has not already been defined + // previously. + if (!isStyleDimDefined(child, crossAxis)) { + float dimCrossAxis = child->layout.dimensions[dim[crossAxis]]; + child->layout.dimensions[dim[crossAxis]] = fmaxf( + boundAxis(child, crossAxis, containerCrossAxis - + paddingAndBorderAxisCross - getMarginAxis(child, crossAxis)), + // You never want to go smaller than padding + getPaddingAndBorderAxis(child, crossAxis) + ); + + // If the size has changed, and this child has children we need to re-layout this child + if (dimCrossAxis != child->layout.dimensions[dim[crossAxis]] && child->children_count > 0) { + // Reset child margins before re-layout as they are added back in layoutNode and would be doubled + child->layout.position[leading[mainAxis]] -= getLeadingMargin(child, mainAxis) + + getRelativePosition(child, mainAxis); + child->layout.position[trailing[mainAxis]] -= getTrailingMargin(child, mainAxis) + + getRelativePosition(child, mainAxis); + child->layout.position[leading[crossAxis]] -= getLeadingMargin(child, crossAxis) + + getRelativePosition(child, crossAxis); + child->layout.position[trailing[crossAxis]] -= getTrailingMargin(child, crossAxis) + + getRelativePosition(child, crossAxis); + + layoutNode(child, maxWidth, maxHeight, direction); + } + } + } else if (alignItem != CSS_ALIGN_FLEX_START) { + // The remaining space between the parent dimensions+padding and child + // dimensions+margin. + float remainingCrossDim = containerCrossAxis - + paddingAndBorderAxisCross - getDimWithMargin(child, crossAxis); + + if (alignItem == CSS_ALIGN_CENTER) { + leadingCrossDim += remainingCrossDim / 2; + } else { // CSS_ALIGN_FLEX_END + leadingCrossDim += remainingCrossDim; + } + } + } + + // And we apply the position + child->layout.position[pos[crossAxis]] += linesCrossDim + leadingCrossDim; + + // Define the trailing position accordingly. + if (isCrossDimDefined) { + setTrailingPosition(node, child, crossAxis); + } + } + } + + linesCrossDim += crossDim; + linesMainDim = fmaxf(linesMainDim, mainDim); + linesCount += 1; + startLine = endLine; + } + + // + // + // Note(prenaux): More than one line, we need to layout the crossAxis + // according to alignContent. + // + // Note that we could probably remove and handle the one line case + // here too, but for the moment this is safer since it won't interfere with + // previously working code. + // + // See specs: + // http://www.w3.org/TR/2012/CR-css3-flexbox-20120918/#layout-algorithm + // section 9.4 + // + if (linesCount > 1 && isCrossDimDefined) { + float nodeCrossAxisInnerSize = node->layout.dimensions[dim[crossAxis]] - + paddingAndBorderAxisCross; + float remainingAlignContentDim = nodeCrossAxisInnerSize - linesCrossDim; + + float crossDimLead = 0; + float currentLead = leadingPaddingAndBorderCross; + + css_align_t alignContent = node->style.align_content; + if (alignContent == CSS_ALIGN_FLEX_END) { + currentLead += remainingAlignContentDim; + } else if (alignContent == CSS_ALIGN_CENTER) { + currentLead += remainingAlignContentDim / 2; + } else if (alignContent == CSS_ALIGN_STRETCH) { + if (nodeCrossAxisInnerSize > linesCrossDim) { + crossDimLead = (remainingAlignContentDim / linesCount); + } + } + + int endIndex = 0; + for (i = 0; i < linesCount; ++i) { + int startIndex = endIndex; + + // compute the line's height and find the endIndex + float lineHeight = 0; + for (ii = startIndex; ii < childCount; ++ii) { + child = node->get_child(node->context, ii); + if (child->style.position_type != CSS_POSITION_RELATIVE) { + continue; + } + if (child->line_index != i) { + break; + } + if (isLayoutDimDefined(child, crossAxis)) { + lineHeight = fmaxf( + lineHeight, + child->layout.dimensions[dim[crossAxis]] + getMarginAxis(child, crossAxis) + ); + } + } + endIndex = ii; + lineHeight += crossDimLead; + + for (ii = startIndex; ii < endIndex; ++ii) { + child = node->get_child(node->context, ii); + if (child->style.position_type != CSS_POSITION_RELATIVE) { + continue; + } + + css_align_t alignContentAlignItem = getAlignItem(node, child); + if (alignContentAlignItem == CSS_ALIGN_FLEX_START) { + child->layout.position[pos[crossAxis]] = currentLead + getLeadingMargin(child, crossAxis); + } else if (alignContentAlignItem == CSS_ALIGN_FLEX_END) { + child->layout.position[pos[crossAxis]] = currentLead + lineHeight - getTrailingMargin(child, crossAxis) - child->layout.dimensions[dim[crossAxis]]; + } else if (alignContentAlignItem == CSS_ALIGN_CENTER) { + float childHeight = child->layout.dimensions[dim[crossAxis]]; + child->layout.position[pos[crossAxis]] = currentLead + (lineHeight - childHeight) / 2; + } else if (alignContentAlignItem == CSS_ALIGN_STRETCH) { + child->layout.position[pos[crossAxis]] = currentLead + getLeadingMargin(child, crossAxis); + // TODO(prenaux): Correctly set the height of items with undefined + // (auto) crossAxis dimension. + } + } + + currentLead += lineHeight; + } + } + + bool needsMainTrailingPos = false; + bool needsCrossTrailingPos = false; + + // If the user didn't specify a width or height, and it has not been set + // by the container, then we set it via the children. + if (!isMainDimDefined) { + node->layout.dimensions[dim[mainAxis]] = fmaxf( + // We're missing the last padding at this point to get the final + // dimension + boundAxis(node, mainAxis, linesMainDim + getTrailingPaddingAndBorder(node, mainAxis)), + // We can never assign a width smaller than the padding and borders + paddingAndBorderAxisMain + ); + + if (mainAxis == CSS_FLEX_DIRECTION_ROW_REVERSE || + mainAxis == CSS_FLEX_DIRECTION_COLUMN_REVERSE) { + needsMainTrailingPos = true; + } + } + + if (!isCrossDimDefined) { + node->layout.dimensions[dim[crossAxis]] = fmaxf( + // For the cross dim, we add both sides at the end because the value + // is aggregate via a max function. Intermediate negative values + // can mess this computation otherwise + boundAxis(node, crossAxis, linesCrossDim + paddingAndBorderAxisCross), + paddingAndBorderAxisCross + ); + + if (crossAxis == CSS_FLEX_DIRECTION_ROW_REVERSE || + crossAxis == CSS_FLEX_DIRECTION_COLUMN_REVERSE) { + needsCrossTrailingPos = true; + } + } + + // Set trailing position if necessary + if (needsMainTrailingPos || needsCrossTrailingPos) { + for (i = 0; i < childCount; ++i) { + child = node->get_child(node->context, i); + + if (needsMainTrailingPos) { + setTrailingPosition(node, child, mainAxis); + } + + if (needsCrossTrailingPos) { + setTrailingPosition(node, child, crossAxis); + } + } + } + + // Calculate dimensions for absolutely positioned elements + currentAbsoluteChild = firstAbsoluteChild; + while (currentAbsoluteChild != NULL) { + // Pre-fill dimensions when using absolute position and both offsets for + // the axis are defined (either both left and right or top and bottom). + for (ii = 0; ii < 2; ii++) { + axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; + + if (isLayoutDimDefined(node, axis) && + !isStyleDimDefined(currentAbsoluteChild, axis) && + isPosDefined(currentAbsoluteChild, leading[axis]) && + isPosDefined(currentAbsoluteChild, trailing[axis])) { + currentAbsoluteChild->layout.dimensions[dim[axis]] = fmaxf( + boundAxis(currentAbsoluteChild, axis, node->layout.dimensions[dim[axis]] - + getBorderAxis(node, axis) - + getMarginAxis(currentAbsoluteChild, axis) - + getPosition(currentAbsoluteChild, leading[axis]) - + getPosition(currentAbsoluteChild, trailing[axis]) + ), + // You never want to go smaller than padding + getPaddingAndBorderAxis(currentAbsoluteChild, axis) + ); + } + + if (isPosDefined(currentAbsoluteChild, trailing[axis]) && + !isPosDefined(currentAbsoluteChild, leading[axis])) { + currentAbsoluteChild->layout.position[leading[axis]] = + node->layout.dimensions[dim[axis]] - + currentAbsoluteChild->layout.dimensions[dim[axis]] - + getPosition(currentAbsoluteChild, trailing[axis]); + } + } + + child = currentAbsoluteChild; + currentAbsoluteChild = currentAbsoluteChild->next_absolute_child; + child->next_absolute_child = NULL; + } + /** END_GENERATED **/ +} + +void layoutNode(css_node_t *node, float parentMaxWidth, float parentMaxHeight, css_direction_t parentDirection) { + css_layout_t *layout = &node->layout; + css_direction_t direction = node->style.direction; + layout->should_update = true; + + bool skipLayout = + !node->is_dirty(node->context) && + eq(layout->last_requested_dimensions[CSS_WIDTH], layout->dimensions[CSS_WIDTH]) && + eq(layout->last_requested_dimensions[CSS_HEIGHT], layout->dimensions[CSS_HEIGHT]) && + eq(layout->last_parent_max_width, parentMaxWidth) && + eq(layout->last_parent_max_height, parentMaxHeight) && + eq(layout->last_direction, direction); + + if (skipLayout) { + layout->dimensions[CSS_WIDTH] = layout->last_dimensions[CSS_WIDTH]; + layout->dimensions[CSS_HEIGHT] = layout->last_dimensions[CSS_HEIGHT]; + layout->position[CSS_TOP] = layout->last_position[CSS_TOP]; + layout->position[CSS_LEFT] = layout->last_position[CSS_LEFT]; + } else { + layout->last_requested_dimensions[CSS_WIDTH] = layout->dimensions[CSS_WIDTH]; + layout->last_requested_dimensions[CSS_HEIGHT] = layout->dimensions[CSS_HEIGHT]; + layout->last_parent_max_width = parentMaxWidth; + layout->last_parent_max_height = parentMaxHeight; + layout->last_direction = direction; + + for (int i = 0, childCount = node->children_count; i < childCount; i++) { + resetNodeLayout(node->get_child(node->context, i)); + } + + layoutNodeImpl(node, parentMaxWidth, parentMaxHeight, parentDirection); + + layout->last_dimensions[CSS_WIDTH] = layout->dimensions[CSS_WIDTH]; + layout->last_dimensions[CSS_HEIGHT] = layout->dimensions[CSS_HEIGHT]; + layout->last_position[CSS_TOP] = layout->position[CSS_TOP]; + layout->last_position[CSS_LEFT] = layout->position[CSS_LEFT]; + } +} + +void resetNodeLayout(css_node_t *node) { + node->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED; + node->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED; + node->layout.position[CSS_LEFT] = 0; + node->layout.position[CSS_TOP] = 0; +} diff --git a/React/Layout/Layout.h b/React/Layout/Layout.h index b2de9cea7..5abd1e572 100644 --- a/React/Layout/Layout.h +++ b/React/Layout/Layout.h @@ -19,171 +19,165 @@ * of patent rights can be found in the PATENTS file in the same directory. */ - #ifndef __LAYOUT_H - #define __LAYOUT_H +#ifndef __LAYOUT_H +#define __LAYOUT_H - #include - #ifndef __cplusplus - #include - #endif +#include +#ifndef __cplusplus +#include +#endif - // Not defined in MSVC++ - #ifndef NAN - static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff}; - #define NAN (*(const float *)__nan) - #endif +// Not defined in MSVC++ +#ifndef NAN +static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff}; +#define NAN (*(const float *)__nan) +#endif - #define CSS_UNDEFINED NAN +#define CSS_UNDEFINED NAN - typedef enum { - CSS_DIRECTION_INHERIT = 0, - CSS_DIRECTION_LTR, - CSS_DIRECTION_RTL - } css_direction_t; +typedef enum { + CSS_DIRECTION_INHERIT = 0, + CSS_DIRECTION_LTR, + CSS_DIRECTION_RTL +} css_direction_t; - typedef enum { - CSS_FLEX_DIRECTION_COLUMN = 0, - CSS_FLEX_DIRECTION_COLUMN_REVERSE, - CSS_FLEX_DIRECTION_ROW, - CSS_FLEX_DIRECTION_ROW_REVERSE - } css_flex_direction_t; +typedef enum { + CSS_FLEX_DIRECTION_COLUMN = 0, + CSS_FLEX_DIRECTION_COLUMN_REVERSE, + CSS_FLEX_DIRECTION_ROW, + CSS_FLEX_DIRECTION_ROW_REVERSE +} css_flex_direction_t; - typedef enum { - CSS_JUSTIFY_FLEX_START = 0, - CSS_JUSTIFY_CENTER, - CSS_JUSTIFY_FLEX_END, - CSS_JUSTIFY_SPACE_BETWEEN, - CSS_JUSTIFY_SPACE_AROUND - } css_justify_t; +typedef enum { + CSS_JUSTIFY_FLEX_START = 0, + CSS_JUSTIFY_CENTER, + CSS_JUSTIFY_FLEX_END, + CSS_JUSTIFY_SPACE_BETWEEN, + CSS_JUSTIFY_SPACE_AROUND +} css_justify_t; - // Note: auto is only a valid value for alignSelf. It is NOT a valid value for - // alignItems. - typedef enum { - CSS_ALIGN_AUTO = 0, - CSS_ALIGN_FLEX_START, - CSS_ALIGN_CENTER, - CSS_ALIGN_FLEX_END, - CSS_ALIGN_STRETCH - } css_align_t; +// Note: auto is only a valid value for alignSelf. It is NOT a valid value for +// alignItems. +typedef enum { + CSS_ALIGN_AUTO = 0, + CSS_ALIGN_FLEX_START, + CSS_ALIGN_CENTER, + CSS_ALIGN_FLEX_END, + CSS_ALIGN_STRETCH +} css_align_t; - typedef enum { - CSS_POSITION_RELATIVE = 0, - CSS_POSITION_ABSOLUTE - } css_position_type_t; +typedef enum { + CSS_POSITION_RELATIVE = 0, + CSS_POSITION_ABSOLUTE +} css_position_type_t; - typedef enum { - CSS_NOWRAP = 0, - CSS_WRAP - } css_wrap_type_t; +typedef enum { + CSS_NOWRAP = 0, + CSS_WRAP +} css_wrap_type_t; - // Note: left and top are shared between position[2] and position[4], so - // they have to be before right and bottom. - typedef enum { - CSS_LEFT = 0, - CSS_TOP, - CSS_RIGHT, - CSS_BOTTOM, - CSS_START, - CSS_END, - CSS_POSITION_COUNT - } css_position_t; +// Note: left and top are shared between position[2] and position[4], so +// they have to be before right and bottom. +typedef enum { + CSS_LEFT = 0, + CSS_TOP, + CSS_RIGHT, + CSS_BOTTOM, + CSS_START, + CSS_END, + CSS_POSITION_COUNT +} css_position_t; - typedef enum { - CSS_MEASURE_MODE_UNDEFINED = 0, - CSS_MEASURE_MODE_EXACTLY, - CSS_MEASURE_MODE_AT_MOST - } css_measure_mode_t; +typedef enum { + CSS_WIDTH = 0, + CSS_HEIGHT +} css_dimension_t; - typedef enum { - CSS_WIDTH = 0, - CSS_HEIGHT - } css_dimension_t; +typedef struct { + float position[4]; + float dimensions[2]; + css_direction_t direction; - typedef struct { - float position[4]; - float dimensions[2]; - css_direction_t direction; + // Instead of recomputing the entire layout every single time, we + // cache some information to break early when nothing changed + bool should_update; + float last_requested_dimensions[2]; + float last_parent_max_width; + float last_parent_max_height; + float last_dimensions[2]; + float last_position[2]; + css_direction_t last_direction; +} css_layout_t; - // Instead of recomputing the entire layout every single time, we - // cache some information to break early when nothing changed - bool should_update; - float last_requested_dimensions[2]; - float last_parent_max_width; - float last_parent_max_height; - float last_dimensions[2]; - float last_position[2]; - css_direction_t last_direction; - } css_layout_t; +typedef struct { + float dimensions[2]; +} css_dim_t; - typedef struct { - float dimensions[2]; - } css_dim_t; +typedef struct { + css_direction_t direction; + css_flex_direction_t flex_direction; + css_justify_t justify_content; + css_align_t align_content; + css_align_t align_items; + css_align_t align_self; + css_position_type_t position_type; + css_wrap_type_t flex_wrap; + float flex; + float margin[6]; + float position[4]; + /** + * You should skip all the rules that contain negative values for the + * following attributes. For example: + * {padding: 10, paddingLeft: -5} + * should output: + * {left: 10 ...} + * the following two are incorrect: + * {left: -5 ...} + * {left: 0 ...} + */ + float padding[6]; + float border[6]; + float dimensions[2]; + float minDimensions[2]; + float maxDimensions[2]; +} css_style_t; - typedef struct { - css_direction_t direction; - css_flex_direction_t flex_direction; - css_justify_t justify_content; - css_align_t align_content; - css_align_t align_items; - css_align_t align_self; - css_position_type_t position_type; - css_wrap_type_t flex_wrap; - float flex; - float margin[6]; - float position[4]; - /** - * You should skip all the rules that contain negative values for the - * following attributes. For example: - * {padding: 10, paddingLeft: -5} - * should output: - * {left: 10 ...} - * the following two are incorrect: - * {left: -5 ...} - * {left: 0 ...} - */ - float padding[6]; - float border[6]; - float dimensions[2]; - float minDimensions[2]; - float maxDimensions[2]; - } css_style_t; +typedef struct css_node css_node_t; +struct css_node { + css_style_t style; + css_layout_t layout; + int children_count; + int line_index; - typedef struct css_node css_node_t; - struct css_node { - css_style_t style; - css_layout_t layout; - int children_count; - int line_index; + css_node_t *next_absolute_child; + css_node_t *next_flex_child; - css_node_t *next_absolute_child; - css_node_t *next_flex_child; + css_dim_t (*measure)(void *context, float width, float height); + void (*print)(void *context); + struct css_node* (*get_child)(void *context, int i); + bool (*is_dirty)(void *context); + void *context; +}; - css_dim_t (*measure)(void *context, float width, css_measure_mode_t widthMode, float height, css_measure_mode_t heightMode); - void (*print)(void *context); - struct css_node* (*get_child)(void *context, int i); - bool (*is_dirty)(void *context); - void *context; - }; +// Lifecycle of nodes and children +css_node_t *new_css_node(void); +void init_css_node(css_node_t *node); +void free_css_node(css_node_t *node); - // Lifecycle of nodes and children - css_node_t *new_css_node(void); - void init_css_node(css_node_t *node); - void free_css_node(css_node_t *node); +// Print utilities +typedef enum { + CSS_PRINT_LAYOUT = 1, + CSS_PRINT_STYLE = 2, + CSS_PRINT_CHILDREN = 4, +} css_print_options_t; +void print_css_node(css_node_t *node, css_print_options_t options); - // Print utilities - typedef enum { - CSS_PRINT_LAYOUT = 1, - CSS_PRINT_STYLE = 2, - CSS_PRINT_CHILDREN = 4, - } css_print_options_t; - void print_css_node(css_node_t *node, css_print_options_t options); +bool isUndefined(float value); - bool isUndefined(float value); +// Function that computes the layout! +void layoutNode(css_node_t *node, float maxWidth, float maxHeight, css_direction_t parentDirection); - // Function that computes the layout! - void layoutNode(css_node_t *node, float maxWidth, float maxHeight, css_direction_t parentDirection); +// Reset the calculated layout values for a given node. You should call this before `layoutNode`. +void resetNodeLayout(css_node_t *node); - // Reset the calculated layout values for a given node. You should call this before `layoutNode`. - void resetNodeLayout(css_node_t *node); - - #endif +#endif diff --git a/ReactAndroid/src/main/java/com/facebook/csslayout/CSSMeasureMode.java b/ReactAndroid/src/main/java/com/facebook/csslayout/CSSMeasureMode.java deleted file mode 100644 index 6306af91d..000000000 --- a/ReactAndroid/src/main/java/com/facebook/csslayout/CSSMeasureMode.java +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -// NOTE: this file is auto-copied from https://github.com/facebook/css-layout -// @generated SignedSource<<39eafaefe66358c3854d67910eaf0dc2>> - -package com.facebook.csslayout; - -public enum CSSMeasureMode { - UNDEFINED, - EXACTLY, - AT_MOST, -} diff --git a/ReactAndroid/src/main/java/com/facebook/csslayout/CSSNode.java b/ReactAndroid/src/main/java/com/facebook/csslayout/CSSNode.java index 348b695e0..46827fb92 100644 --- a/ReactAndroid/src/main/java/com/facebook/csslayout/CSSNode.java +++ b/ReactAndroid/src/main/java/com/facebook/csslayout/CSSNode.java @@ -7,7 +7,7 @@ */ // NOTE: this file is auto-copied from https://github.com/facebook/css-layout -// @generated SignedSource<> +// @generated SignedSource<<1f520d46cbfddbbea0661a8fb6a00748>> package com.facebook.csslayout; @@ -56,7 +56,7 @@ public class CSSNode { * * NB: measure is NOT guaranteed to be threadsafe/re-entrant safe! */ - public void measure(CSSNode node, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode, MeasureOutput measureOutput); + public void measure(CSSNode node, float width, float height, MeasureOutput measureOutput); } // VisibleForTesting @@ -128,13 +128,13 @@ public class CSSNode { return mMeasureFunction != null; } - /*package*/ MeasureOutput measure(MeasureOutput measureOutput, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode) { + /*package*/ MeasureOutput measure(MeasureOutput measureOutput, float width, float height) { if (!isMeasureDefined()) { throw new RuntimeException("Measure function isn't defined!"); } measureOutput.height = CSSConstants.UNDEFINED; measureOutput.width = CSSConstants.UNDEFINED; - Assertions.assertNotNull(mMeasureFunction).measure(this, width, widthMode, height, heightMode, measureOutput); + Assertions.assertNotNull(mMeasureFunction).measure(this, width, height, measureOutput); return measureOutput; } diff --git a/ReactAndroid/src/main/java/com/facebook/csslayout/LayoutEngine.java b/ReactAndroid/src/main/java/com/facebook/csslayout/LayoutEngine.java index 5b9cc60f1..0e6f3f675 100644 --- a/ReactAndroid/src/main/java/com/facebook/csslayout/LayoutEngine.java +++ b/ReactAndroid/src/main/java/com/facebook/csslayout/LayoutEngine.java @@ -7,7 +7,7 @@ */ // NOTE: this file is auto-copied from https://github.com/facebook/css-layout -// @generated SignedSource<<9224a1489ee541a447ede3657538f5bc>> +// @generated SignedSource<<1d6f1ec2d1fbd24c5176f48d5005c0d5>> package com.facebook.csslayout; @@ -227,19 +227,19 @@ public class LayoutEngine { float parentMaxHeight, CSSDirection parentDirection) { /** START_GENERATED **/ - + CSSDirection direction = resolveDirection(node, parentDirection); int mainAxis = resolveAxis(getFlexDirection(node), direction); int crossAxis = getCrossFlexDirection(mainAxis, direction); int resolvedRowAxis = resolveAxis(CSS_FLEX_DIRECTION_ROW, direction); - + // Handle width and height style attributes setDimensionFromStyle(node, mainAxis); setDimensionFromStyle(node, crossAxis); - + // Set the resolved resolution in the node's layout node.layout.direction = direction; - + // The position is set by the parent, but we need to complete it with a // delta composed of the margin and left/top/right/bottom node.layout.position[leading[mainAxis]] += node.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + @@ -250,68 +250,52 @@ public class LayoutEngine { getRelativePosition(node, crossAxis); node.layout.position[trailing[crossAxis]] += node.style.margin.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis]) + getRelativePosition(node, crossAxis); - + // Inline immutable values from the target node to avoid excessive method // invocations during the layout calculation. int childCount = node.getChildCount(); float paddingAndBorderAxisResolvedRow = ((node.style.padding.getWithFallback(leadingSpacing[resolvedRowAxis], leading[resolvedRowAxis]) + node.style.border.getWithFallback(leadingSpacing[resolvedRowAxis], leading[resolvedRowAxis])) + (node.style.padding.getWithFallback(trailingSpacing[resolvedRowAxis], trailing[resolvedRowAxis]) + node.style.border.getWithFallback(trailingSpacing[resolvedRowAxis], trailing[resolvedRowAxis]))); float paddingAndBorderAxisColumn = ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]))); - + if (isMeasureDefined(node)) { boolean isResolvedRowDimDefined = (!Float.isNaN(node.layout.dimensions[dim[resolvedRowAxis]]) && node.layout.dimensions[dim[resolvedRowAxis]] >= 0.0); - + float width = CSSConstants.UNDEFINED; - CSSMeasureMode widthMode = CSSMeasureMode.UNDEFINED; if ((!Float.isNaN(node.style.dimensions[dim[resolvedRowAxis]]) && node.style.dimensions[dim[resolvedRowAxis]] >= 0.0)) { width = node.style.dimensions[DIMENSION_WIDTH]; - widthMode = CSSMeasureMode.EXACTLY; } else if (isResolvedRowDimDefined) { width = node.layout.dimensions[dim[resolvedRowAxis]]; - widthMode = CSSMeasureMode.EXACTLY; } else { width = parentMaxWidth - (node.style.margin.getWithFallback(leadingSpacing[resolvedRowAxis], leading[resolvedRowAxis]) + node.style.margin.getWithFallback(trailingSpacing[resolvedRowAxis], trailing[resolvedRowAxis])); - widthMode = CSSMeasureMode.AT_MOST; } width -= paddingAndBorderAxisResolvedRow; - if (Float.isNaN(width)) { - widthMode = CSSMeasureMode.UNDEFINED; - } - + float height = CSSConstants.UNDEFINED; - CSSMeasureMode heightMode = CSSMeasureMode.UNDEFINED; if ((!Float.isNaN(node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]) && node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) { height = node.style.dimensions[DIMENSION_HEIGHT]; - heightMode = CSSMeasureMode.EXACTLY; } else if ((!Float.isNaN(node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]) && node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) { height = node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]; - heightMode = CSSMeasureMode.EXACTLY; } else { height = parentMaxHeight - (node.style.margin.getWithFallback(leadingSpacing[resolvedRowAxis], leading[resolvedRowAxis]) + node.style.margin.getWithFallback(trailingSpacing[resolvedRowAxis], trailing[resolvedRowAxis])); - heightMode = CSSMeasureMode.AT_MOST; } height -= ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]))); - if (Float.isNaN(height)) { - heightMode = CSSMeasureMode.UNDEFINED; - } - + // We only need to give a dimension for the text if we haven't got any // for it computed yet. It can either be from the style attribute or because // the element is flexible. boolean isRowUndefined = !(!Float.isNaN(node.style.dimensions[dim[resolvedRowAxis]]) && node.style.dimensions[dim[resolvedRowAxis]] >= 0.0) && !isResolvedRowDimDefined; boolean isColumnUndefined = !(!Float.isNaN(node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]) && node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0) && Float.isNaN(node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]); - + // Let's not measure the text if we already know both dimensions if (isRowUndefined || isColumnUndefined) { MeasureOutput measureDim = node.measure( - + layoutContext.measureOutput, width, - widthMode, - height, - heightMode + height ); if (isRowUndefined) { node.layout.dimensions[DIMENSION_WIDTH] = measureDim.width + @@ -326,33 +310,33 @@ public class LayoutEngine { return; } } - + boolean isNodeFlexWrap = (node.style.flexWrap == CSSWrap.WRAP); - + CSSJustify justifyContent = node.style.justifyContent; - + float leadingPaddingAndBorderMain = (node.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + node.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])); float leadingPaddingAndBorderCross = (node.style.padding.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + node.style.border.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis])); float paddingAndBorderAxisMain = ((node.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + node.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (node.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + node.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]))); float paddingAndBorderAxisCross = ((node.style.padding.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + node.style.border.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis])) + (node.style.padding.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis]) + node.style.border.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis]))); - + boolean isMainDimDefined = (!Float.isNaN(node.layout.dimensions[dim[mainAxis]]) && node.layout.dimensions[dim[mainAxis]] >= 0.0); boolean isCrossDimDefined = (!Float.isNaN(node.layout.dimensions[dim[crossAxis]]) && node.layout.dimensions[dim[crossAxis]] >= 0.0); boolean isMainRowDirection = (mainAxis == CSS_FLEX_DIRECTION_ROW || mainAxis == CSS_FLEX_DIRECTION_ROW_REVERSE); - + int i; int ii; CSSNode child; int axis; - + CSSNode firstAbsoluteChild = null; CSSNode currentAbsoluteChild = null; - + float definedMainDim = CSSConstants.UNDEFINED; if (isMainDimDefined) { definedMainDim = node.layout.dimensions[dim[mainAxis]] - paddingAndBorderAxisMain; } - + // We want to execute the next two loops one per line with flex-wrap int startLine = 0; int endLine = 0; @@ -364,19 +348,19 @@ public class LayoutEngine { int linesCount = 0; while (endLine < childCount) { // Layout non flexible children and count children by type - + // mainContentDim is accumulation of the dimensions and margin of all the // non flexible children. This will be used in order to either set the // dimensions of the node if none already exist, or to compute the // remaining space left for the flexible children. float mainContentDim = 0; - + // There are three kind of children, non flexible, flexible and absolute. // We need to know how many there are in order to distribute the space. int flexibleChildrenCount = 0; float totalFlexible = 0; int nonFlexibleChildrenCount = 0; - + // Use the line loop to position children in the main axis for as long // as they are using a simple stacking behaviour. Children that are // immediately stacked in the initial loop will not be touched again @@ -385,31 +369,31 @@ public class LayoutEngine { (isMainDimDefined && justifyContent == CSSJustify.FLEX_START) || (!isMainDimDefined && justifyContent != CSSJustify.CENTER); int firstComplexMain = (isSimpleStackMain ? childCount : startLine); - + // Use the initial line loop to position children in the cross axis for // as long as they are relatively positioned with alignment STRETCH or // FLEX_START. Children that are immediately stacked in the initial loop // will not be touched again in . boolean isSimpleStackCross = true; int firstComplexCross = childCount; - + CSSNode firstFlexChild = null; CSSNode currentFlexChild = null; - + float mainDim = leadingPaddingAndBorderMain; float crossDim = 0; - + float maxWidth = CSSConstants.UNDEFINED; float maxHeight = CSSConstants.UNDEFINED; for (i = startLine; i < childCount; ++i) { child = node.getChildAt(i); child.lineIndex = linesCount; - + child.nextAbsoluteChild = null; child.nextFlexChild = null; - + CSSAlign alignItem = getAlignItem(node, child); - + // Pre-fill cross axis dimensions when the child is using stretch before // we call the recursive layout pass if (alignItem == CSSAlign.STRETCH && @@ -432,7 +416,7 @@ public class LayoutEngine { currentAbsoluteChild.nextAbsoluteChild = child; } currentAbsoluteChild = child; - + // Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both // left and right or top and bottom). for (ii = 0; ii < 2; ii++) { @@ -453,15 +437,15 @@ public class LayoutEngine { } } } - + float nextContentDim = 0; - + // It only makes sense to consider a child flexible if we have a computed // dimension for the node. if (isMainDimDefined && (child.style.positionType == CSSPositionType.RELATIVE && child.style.flex > 0)) { flexibleChildrenCount++; totalFlexible += child.style.flex; - + // Store a private linked list of flexible children so that we can // efficiently traverse them later. if (firstFlexChild == null) { @@ -471,18 +455,18 @@ public class LayoutEngine { currentFlexChild.nextFlexChild = child; } currentFlexChild = child; - + // Even if we don't know its exact size yet, we already know the padding, // border and margin. We'll use this partial information, which represents // the smallest possible size for the child, to compute the remaining // available space. nextContentDim = ((child.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (child.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + child.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]))) + (child.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis])); - + } else { maxWidth = CSSConstants.UNDEFINED; maxHeight = CSSConstants.UNDEFINED; - + if (!isMainRowDirection) { if ((!Float.isNaN(node.layout.dimensions[dim[resolvedRowAxis]]) && node.layout.dimensions[dim[resolvedRowAxis]] >= 0.0)) { maxWidth = node.layout.dimensions[dim[resolvedRowAxis]] - @@ -502,12 +486,12 @@ public class LayoutEngine { paddingAndBorderAxisColumn; } } - + // This is the main recursive call. We layout non flexible children. if (alreadyComputedNextLayout == 0) { layoutNode(layoutContext, child, maxWidth, maxHeight, direction); } - + // Absolute positioned elements do not take part of the layout, so we // don't use them to compute mainContentDim if (child.style.positionType == CSSPositionType.RELATIVE) { @@ -516,7 +500,7 @@ public class LayoutEngine { nextContentDim = (child.layout.dimensions[dim[mainAxis]] + child.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis])); } } - + // The element we are about to add would make us go to the next line if (isNodeFlexWrap && isMainDimDefined && @@ -528,7 +512,7 @@ public class LayoutEngine { alreadyComputedNextLayout = 1; break; } - + // Disable simple stacking in the main axis for the current line as // we found a non-trivial child. The remaining children will be laid out // in . @@ -537,7 +521,7 @@ public class LayoutEngine { isSimpleStackMain = false; firstComplexMain = i; } - + // Disable simple stacking in the cross axis for the current line as // we found a non-trivial child. The remaining children will be laid out // in . @@ -548,37 +532,37 @@ public class LayoutEngine { isSimpleStackCross = false; firstComplexCross = i; } - + if (isSimpleStackMain) { child.layout.position[pos[mainAxis]] += mainDim; if (isMainDimDefined) { child.layout.position[trailing[mainAxis]] = node.layout.dimensions[dim[mainAxis]] - child.layout.dimensions[dim[mainAxis]] - child.layout.position[pos[mainAxis]]; } - + mainDim += (child.layout.dimensions[dim[mainAxis]] + child.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis])); crossDim = Math.max(crossDim, boundAxis(child, crossAxis, (child.layout.dimensions[dim[crossAxis]] + child.style.margin.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + child.style.margin.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis])))); } - + if (isSimpleStackCross) { child.layout.position[pos[crossAxis]] += linesCrossDim + leadingPaddingAndBorderCross; if (isCrossDimDefined) { child.layout.position[trailing[crossAxis]] = node.layout.dimensions[dim[crossAxis]] - child.layout.dimensions[dim[crossAxis]] - child.layout.position[pos[crossAxis]]; } } - + alreadyComputedNextLayout = 0; mainContentDim += nextContentDim; endLine = i + 1; } - + // Layout flexible children and allocate empty space - + // In order to position the elements in the main axis, we have two // controls. The space between the beginning and the first element // and the space between each two elements. float leadingMainDim = 0; float betweenMainDim = 0; - + // The remaining available space that needs to be allocated float remainingMainDim = 0; if (isMainDimDefined) { @@ -586,14 +570,14 @@ public class LayoutEngine { } else { remainingMainDim = Math.max(mainContentDim, 0) - mainContentDim; } - + // If there are flexible children in the mix, they are going to fill the // remaining space if (flexibleChildrenCount != 0) { float flexibleMainDim = remainingMainDim / totalFlexible; float baseMainDim; float boundMainDim; - + // If the flex share of remaining space doesn't meet min/max bounds, // remove this child from flex calculations. currentFlexChild = firstFlexChild; @@ -601,22 +585,22 @@ public class LayoutEngine { baseMainDim = flexibleMainDim * currentFlexChild.style.flex + ((currentFlexChild.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + currentFlexChild.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (currentFlexChild.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + currentFlexChild.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]))); boundMainDim = boundAxis(currentFlexChild, mainAxis, baseMainDim); - + if (baseMainDim != boundMainDim) { remainingMainDim -= boundMainDim; totalFlexible -= currentFlexChild.style.flex; } - + currentFlexChild = currentFlexChild.nextFlexChild; } flexibleMainDim = remainingMainDim / totalFlexible; - + // The non flexible children can overflow the container, in this case // we should just assume that there is no space available. if (flexibleMainDim < 0) { flexibleMainDim = 0; } - + currentFlexChild = firstFlexChild; while (currentFlexChild != null) { // At this point we know the final size of the element in the main @@ -625,7 +609,7 @@ public class LayoutEngine { flexibleMainDim * currentFlexChild.style.flex + ((currentFlexChild.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + currentFlexChild.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (currentFlexChild.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + currentFlexChild.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]))) ); - + maxWidth = CSSConstants.UNDEFINED; if ((!Float.isNaN(node.layout.dimensions[dim[resolvedRowAxis]]) && node.layout.dimensions[dim[resolvedRowAxis]] >= 0.0)) { maxWidth = node.layout.dimensions[dim[resolvedRowAxis]] - @@ -644,15 +628,15 @@ public class LayoutEngine { (node.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN])) - paddingAndBorderAxisColumn; } - + // And we recursively call the layout algorithm for this child layoutNode(layoutContext, currentFlexChild, maxWidth, maxHeight, direction); - + child = currentFlexChild; currentFlexChild = currentFlexChild.nextFlexChild; child.nextFlexChild = null; } - + // We use justifyContent to figure out how to allocate the remaining // space available } else if (justifyContent != CSSJustify.FLEX_START) { @@ -675,18 +659,18 @@ public class LayoutEngine { leadingMainDim = betweenMainDim / 2; } } - + // Position elements in the main axis and compute dimensions - + // At this point, all the children have their dimensions set. We need to // find their position. In order to do that, we accumulate data in // variables that are also useful to compute the total dimensions of the // container! mainDim += leadingMainDim; - + for (i = firstComplexMain; i < endLine; ++i) { child = node.getChildAt(i); - + if (child.style.positionType == CSSPositionType.ABSOLUTE && !Float.isNaN(child.style.position[leading[mainAxis]])) { // In case the child is position absolute and has left/top being @@ -699,12 +683,12 @@ public class LayoutEngine { // If the child is position absolute (without top/left) or relative, // we put it at the current accumulated offset. child.layout.position[pos[mainAxis]] += mainDim; - + // Define the trailing position accordingly. if (isMainDimDefined) { child.layout.position[trailing[mainAxis]] = node.layout.dimensions[dim[mainAxis]] - child.layout.dimensions[dim[mainAxis]] - child.layout.position[pos[mainAxis]]; } - + // Now that we placed the element, we need to update the variables // We only need to do that for relative elements. Absolute elements // do not take part in that phase. @@ -718,7 +702,7 @@ public class LayoutEngine { } } } - + float containerCrossAxis = node.layout.dimensions[dim[crossAxis]]; if (!isCrossDimDefined) { containerCrossAxis = Math.max( @@ -729,11 +713,11 @@ public class LayoutEngine { paddingAndBorderAxisCross ); } - + // Position elements in the cross axis for (i = firstComplexCross; i < endLine; ++i) { child = node.getChildAt(i); - + if (child.style.positionType == CSSPositionType.ABSOLUTE && !Float.isNaN(child.style.position[leading[crossAxis]])) { // In case the child is absolutely positionned and has a @@ -742,10 +726,10 @@ public class LayoutEngine { child.layout.position[pos[crossAxis]] = (Float.isNaN(child.style.position[leading[crossAxis]]) ? 0 : child.style.position[leading[crossAxis]]) + node.style.border.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + child.style.margin.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]); - + } else { float leadingCrossDim = leadingPaddingAndBorderCross; - + // For a relative children, we're either using alignItems (parent) or // alignSelf (child) in order to determine the position in the cross axis if (child.style.positionType == CSSPositionType.RELATIVE) { @@ -764,7 +748,7 @@ public class LayoutEngine { // You never want to go smaller than padding ((child.style.padding.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + child.style.border.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis])) + (child.style.padding.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis]) + child.style.border.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis]))) ); - + // If the size has changed, and this child has children we need to re-layout this child if (dimCrossAxis != child.layout.dimensions[dim[crossAxis]] && child.getChildCount() > 0) { // Reset child margins before re-layout as they are added back in layoutNode and would be doubled @@ -776,7 +760,7 @@ public class LayoutEngine { getRelativePosition(child, crossAxis); child.layout.position[trailing[crossAxis]] -= child.style.margin.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis]) + getRelativePosition(child, crossAxis); - + layoutNode(layoutContext, child, maxWidth, maxHeight, direction); } } @@ -785,7 +769,7 @@ public class LayoutEngine { // dimensions+margin. float remainingCrossDim = containerCrossAxis - paddingAndBorderAxisCross - (child.layout.dimensions[dim[crossAxis]] + child.style.margin.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + child.style.margin.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis])); - + if (alignItem == CSSAlign.CENTER) { leadingCrossDim += remainingCrossDim / 2; } else { // CSSAlign.FLEX_END @@ -793,23 +777,23 @@ public class LayoutEngine { } } } - + // And we apply the position child.layout.position[pos[crossAxis]] += linesCrossDim + leadingCrossDim; - + // Define the trailing position accordingly. if (isCrossDimDefined) { child.layout.position[trailing[crossAxis]] = node.layout.dimensions[dim[crossAxis]] - child.layout.dimensions[dim[crossAxis]] - child.layout.position[pos[crossAxis]]; } } } - + linesCrossDim += crossDim; linesMainDim = Math.max(linesMainDim, mainDim); linesCount += 1; startLine = endLine; } - + // // // Note(prenaux): More than one line, we need to layout the crossAxis @@ -827,10 +811,10 @@ public class LayoutEngine { float nodeCrossAxisInnerSize = node.layout.dimensions[dim[crossAxis]] - paddingAndBorderAxisCross; float remainingAlignContentDim = nodeCrossAxisInnerSize - linesCrossDim; - + float crossDimLead = 0; float currentLead = leadingPaddingAndBorderCross; - + CSSAlign alignContent = node.style.alignContent; if (alignContent == CSSAlign.FLEX_END) { currentLead += remainingAlignContentDim; @@ -841,11 +825,11 @@ public class LayoutEngine { crossDimLead = (remainingAlignContentDim / linesCount); } } - + int endIndex = 0; for (i = 0; i < linesCount; ++i) { int startIndex = endIndex; - + // compute the line's height and find the endIndex float lineHeight = 0; for (ii = startIndex; ii < childCount; ++ii) { @@ -865,13 +849,13 @@ public class LayoutEngine { } endIndex = ii; lineHeight += crossDimLead; - + for (ii = startIndex; ii < endIndex; ++ii) { child = node.getChildAt(ii); if (child.style.positionType != CSSPositionType.RELATIVE) { continue; } - + CSSAlign alignContentAlignItem = getAlignItem(node, child); if (alignContentAlignItem == CSSAlign.FLEX_START) { child.layout.position[pos[crossAxis]] = currentLead + child.style.margin.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]); @@ -886,14 +870,14 @@ public class LayoutEngine { // (auto) crossAxis dimension. } } - + currentLead += lineHeight; } } - + boolean needsMainTrailingPos = false; boolean needsCrossTrailingPos = false; - + // If the user didn't specify a width or height, and it has not been set // by the container, then we set it via the children. if (!isMainDimDefined) { @@ -904,13 +888,13 @@ public class LayoutEngine { // We can never assign a width smaller than the padding and borders paddingAndBorderAxisMain ); - + if (mainAxis == CSS_FLEX_DIRECTION_ROW_REVERSE || mainAxis == CSS_FLEX_DIRECTION_COLUMN_REVERSE) { needsMainTrailingPos = true; } } - + if (!isCrossDimDefined) { node.layout.dimensions[dim[crossAxis]] = Math.max( // For the cross dim, we add both sides at the end because the value @@ -919,28 +903,28 @@ public class LayoutEngine { boundAxis(node, crossAxis, linesCrossDim + paddingAndBorderAxisCross), paddingAndBorderAxisCross ); - + if (crossAxis == CSS_FLEX_DIRECTION_ROW_REVERSE || crossAxis == CSS_FLEX_DIRECTION_COLUMN_REVERSE) { needsCrossTrailingPos = true; } } - + // Set trailing position if necessary if (needsMainTrailingPos || needsCrossTrailingPos) { for (i = 0; i < childCount; ++i) { child = node.getChildAt(i); - + if (needsMainTrailingPos) { child.layout.position[trailing[mainAxis]] = node.layout.dimensions[dim[mainAxis]] - child.layout.dimensions[dim[mainAxis]] - child.layout.position[pos[mainAxis]]; } - + if (needsCrossTrailingPos) { child.layout.position[trailing[crossAxis]] = node.layout.dimensions[dim[crossAxis]] - child.layout.dimensions[dim[crossAxis]] - child.layout.position[pos[crossAxis]]; } } } - + // Calculate dimensions for absolutely positioned elements currentAbsoluteChild = firstAbsoluteChild; while (currentAbsoluteChild != null) { @@ -948,7 +932,7 @@ public class LayoutEngine { // the axis are defined (either both left and right or top and bottom). for (ii = 0; ii < 2; ii++) { axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; - + if ((!Float.isNaN(node.layout.dimensions[dim[axis]]) && node.layout.dimensions[dim[axis]] >= 0.0) && !(!Float.isNaN(currentAbsoluteChild.style.dimensions[dim[axis]]) && currentAbsoluteChild.style.dimensions[dim[axis]] >= 0.0) && !Float.isNaN(currentAbsoluteChild.style.position[leading[axis]]) && @@ -964,7 +948,7 @@ public class LayoutEngine { ((currentAbsoluteChild.style.padding.getWithFallback(leadingSpacing[axis], leading[axis]) + currentAbsoluteChild.style.border.getWithFallback(leadingSpacing[axis], leading[axis])) + (currentAbsoluteChild.style.padding.getWithFallback(trailingSpacing[axis], trailing[axis]) + currentAbsoluteChild.style.border.getWithFallback(trailingSpacing[axis], trailing[axis]))) ); } - + if (!Float.isNaN(currentAbsoluteChild.style.position[trailing[axis]]) && !!Float.isNaN(currentAbsoluteChild.style.position[leading[axis]])) { currentAbsoluteChild.layout.position[leading[axis]] = @@ -973,7 +957,7 @@ public class LayoutEngine { (Float.isNaN(currentAbsoluteChild.style.position[trailing[axis]]) ? 0 : currentAbsoluteChild.style.position[trailing[axis]]); } } - + child = currentAbsoluteChild; currentAbsoluteChild = currentAbsoluteChild.nextAbsoluteChild; child.nextAbsoluteChild = null; diff --git a/ReactAndroid/src/main/java/com/facebook/csslayout/README b/ReactAndroid/src/main/java/com/facebook/csslayout/README index 92aafb8d0..2859f0a63 100644 --- a/ReactAndroid/src/main/java/com/facebook/csslayout/README +++ b/ReactAndroid/src/main/java/com/facebook/csslayout/README @@ -1,7 +1,7 @@ The source of truth for css-layout is: https://github.com/facebook/css-layout The code here should be kept in sync with GitHub. -HEAD at the time this code was synced: https://github.com/facebook/css-layout/commit/b0d00ad33850d83450139d994bded89d20ddac32 +HEAD at the time this code was synced: https://github.com/facebook/css-layout/commit/68e0b0cc58dcdf023651905d39c0e8147141b123 There is generated code in: - README (this file) diff --git a/ReactAndroid/src/main/java/com/facebook/csslayout/README.facebook b/ReactAndroid/src/main/java/com/facebook/csslayout/README.facebook index 637f6609e..7cdf630c2 100644 --- a/ReactAndroid/src/main/java/com/facebook/csslayout/README.facebook +++ b/ReactAndroid/src/main/java/com/facebook/csslayout/README.facebook @@ -1,7 +1,7 @@ The source of truth for css-layout is: https://github.com/facebook/css-layout The code here should be kept in sync with GitHub. -HEAD at the time this code was synced: https://github.com/facebook/css-layout/commit/b0d00ad33850d83450139d994bded89d20ddac32 +HEAD at the time this code was synced: https://github.com/facebook/css-layout/commit/68e0b0cc58dcdf023651905d39c0e8147141b123 There is generated code in: - README.facebook (this file) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewManager.java index 45963735e..98fc5293b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewManager.java @@ -11,7 +11,6 @@ package com.facebook.react.views.art; import android.graphics.Bitmap; -import com.facebook.csslayout.CSSMeasureMode; import com.facebook.csslayout.CSSNode; import com.facebook.csslayout.MeasureOutput; import com.facebook.react.uimanager.BaseViewManager; @@ -28,13 +27,7 @@ public class ARTSurfaceViewManager extends private static final CSSNode.MeasureFunction MEASURE_FUNCTION = new CSSNode.MeasureFunction() { @Override - public void measure( - CSSNode node, - float width, - CSSMeasureMode widthMode, - float height, - CSSMeasureMode heightMode, - MeasureOutput measureOutput) { + public void measure(CSSNode node, float width, float height, MeasureOutput measureOutput) { throw new IllegalStateException("SurfaceView should have explicit width and height set"); } }; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java index ce85293fb..aeafdac6a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java @@ -19,7 +19,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; -import com.facebook.csslayout.CSSMeasureMode; import com.facebook.csslayout.CSSNode; import com.facebook.csslayout.MeasureOutput; import com.facebook.react.uimanager.LayoutShadowNode; @@ -52,13 +51,7 @@ public class ProgressBarShadowNode extends LayoutShadowNode implements CSSNode.M } @Override - public void measure( - CSSNode node, - float width, - CSSMeasureMode widthMode, - float height, - CSSMeasureMode heightMode, - MeasureOutput measureOutput) { + public void measure(CSSNode node, float width, float height, MeasureOutput measureOutput) { final int style = ReactProgressBarViewManager.getStyleFromString(getStyle()); if (!mMeasured.contains(style)) { ProgressBar progressBar = ReactProgressBarViewManager.createProgressBar(getThemedContext(), style); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java index ec3f66d80..7270457da 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java @@ -15,7 +15,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.SeekBar; -import com.facebook.csslayout.CSSMeasureMode; import com.facebook.csslayout.CSSNode; import com.facebook.csslayout.MeasureOutput; import com.facebook.react.bridge.ReactContext; @@ -51,13 +50,7 @@ public class ReactSliderManager extends SimpleViewManager { } @Override - public void measure( - CSSNode node, - float width, - CSSMeasureMode widthMode, - float height, - CSSMeasureMode heightMode, - MeasureOutput measureOutput) { + public void measure(CSSNode node, float width, float height, MeasureOutput measureOutput) { if (!mMeasured) { SeekBar reactSlider = new ReactSlider(getThemedContext(), null, STYLE); final int spec = View.MeasureSpec.makeMeasureSpec( diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java index 1db17fc22..f99b3c7a7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java @@ -14,7 +14,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.CompoundButton; -import com.facebook.csslayout.CSSMeasureMode; import com.facebook.csslayout.CSSNode; import com.facebook.csslayout.MeasureOutput; import com.facebook.react.bridge.ReactContext; @@ -45,13 +44,7 @@ public class ReactSwitchManager extends SimpleViewManager { } @Override - public void measure( - CSSNode node, - float width, - CSSMeasureMode widthMode, - float height, - CSSMeasureMode heightMode, - MeasureOutput measureOutput) { + public void measure(CSSNode node, float width, float height, MeasureOutput measureOutput) { if (!mMeasured) { // Create a switch with the default config and measure it; since we don't (currently) // support setting custom switch text, this is fine, as all switches will measure the same diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java index e377d3c25..36996a1f8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java @@ -28,7 +28,6 @@ import android.text.style.ForegroundColorSpan; import android.widget.TextView; import com.facebook.csslayout.CSSConstants; -import com.facebook.csslayout.CSSMeasureMode; import com.facebook.csslayout.CSSNode; import com.facebook.csslayout.MeasureOutput; import com.facebook.infer.annotation.Assertions; @@ -194,13 +193,7 @@ public class ReactTextShadowNode extends LayoutShadowNode { private static final CSSNode.MeasureFunction TEXT_MEASURE_FUNCTION = new CSSNode.MeasureFunction() { @Override - public void measure( - CSSNode node, - float width, - CSSMeasureMode widthMode, - float height, - CSSMeasureMode heightMode, - MeasureOutput measureOutput) { + public void measure(CSSNode node, float width, float height, MeasureOutput measureOutput) { // TODO(5578671): Handle text direction (see View#getTextDirectionHeuristic) ReactTextShadowNode reactCSSNode = (ReactTextShadowNode) node; TextPaint textPaint = sTextPaintInstance; @@ -213,7 +206,8 @@ public class ReactTextShadowNode extends LayoutShadowNode { Layout.getDesiredWidth(text, textPaint) : Float.NaN; // technically, width should never be negative, but there is currently a bug in - boolean unconstrainedWidth = widthMode == CSSMeasureMode.UNDEFINED || width < 0; + // LayoutEngine where a negative value can be passed. + boolean unconstrainedWidth = CSSConstants.isUndefined(width) || width < 0; if (boring == null && (unconstrainedWidth || diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java index d3b4b6841..69bb72774 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java @@ -16,8 +16,6 @@ import android.util.TypedValue; import android.view.ViewGroup; import android.widget.EditText; -import com.facebook.csslayout.CSSConstants; -import com.facebook.csslayout.CSSMeasureMode; import com.facebook.csslayout.CSSNode; import com.facebook.csslayout.MeasureOutput; import com.facebook.csslayout.Spacing; @@ -65,17 +63,11 @@ public class ReactTextInputShadowNode extends ReactTextShadowNode implements } @Override - public void measure( - CSSNode node, - float width, - CSSMeasureMode widthMode, - float height, - CSSMeasureMode heightMode, - MeasureOutput measureOutput) { + public void measure(CSSNode node, float width, float height, MeasureOutput measureOutput) { // measure() should never be called before setThemedContext() EditText editText = Assertions.assertNotNull(mEditText); - measureOutput.width = widthMode == CSSMeasureMode.UNDEFINED ? CSSConstants.UNDEFINED : width; + measureOutput.width = width; editText.setTextSize( TypedValue.COMPLEX_UNIT_PX, mFontSize == UNSET ?