From 30f8380095110f936be8083ac2e8971a1b825504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20W=C3=B6hrl?= Date: Wed, 15 Feb 2017 13:35:24 -0800 Subject: [PATCH] flex-wrap: wrap-reverse support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: I couldn't resist to do this 😄 #394 This adds ```flex-wrap: wrap-reverse``` I think we hit a edge case here: https://stackoverflow.com/questions/33891709/when-flexbox-items-wrap-in-column-mode-container-does-not-grow-its-width as is differs here from chrome, but I think that yoga is here more correct. So I haven't added this test yet as this would fail against chrome, as chrome outputs a width of 30 for root, whereas yoga gets a width of 60 here, which I think is correct. Strangely the output of ```flex-wrap:wrap``` is in jsfiddle also only with a (visual) width of 30 on chrome, while the tests gets generated with 60. ```html
``` Looking forward what you think here emilsjolander Closes https://github.com/facebook/yoga/pull/398 Reviewed By: astreet Differential Revision: D4564711 Pulled By: emilsjolander fbshipit-source-id: 33dc055abd8444b2aa7796ef90bd7ec99e961bb8 --- .../main/java/com/facebook/yoga/YogaWrap.java | 4 ++- ReactCommon/yoga/yoga/YGEnums.h | 3 ++- ReactCommon/yoga/yoga/Yoga.c | 26 ++++++++++++++----- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaWrap.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaWrap.java index 8109c56cc..6e88ad72d 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaWrap.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaWrap.java @@ -14,7 +14,8 @@ import com.facebook.proguard.annotations.DoNotStrip; @DoNotStrip public enum YogaWrap { NO_WRAP(0), - WRAP(1); + WRAP(1), + WRAP_REVERSE(2); private int mIntValue; @@ -30,6 +31,7 @@ public enum YogaWrap { switch (value) { case 0: return NO_WRAP; case 1: return WRAP; + case 2: return WRAP_REVERSE; default: throw new IllegalArgumentException("Unknown enum value: " + value); } } diff --git a/ReactCommon/yoga/yoga/YGEnums.h b/ReactCommon/yoga/yoga/YGEnums.h index f25343340..e466ad7b7 100644 --- a/ReactCommon/yoga/yoga/YGEnums.h +++ b/ReactCommon/yoga/yoga/YGEnums.h @@ -124,10 +124,11 @@ typedef YG_ENUM_BEGIN(YGUnit) { YGUnitAuto, } YG_ENUM_END(YGUnit); -#define YGWrapCount 2 +#define YGWrapCount 3 typedef YG_ENUM_BEGIN(YGWrap) { YGWrapNoWrap, YGWrapWrap, + YGWrapWrapReverse, } YG_ENUM_END(YGWrap); YG_EXTERN_C_END diff --git a/ReactCommon/yoga/yoga/Yoga.c b/ReactCommon/yoga/yoga/Yoga.c index f799a617b..ccb947d5e 100644 --- a/ReactCommon/yoga/yoga/Yoga.c +++ b/ReactCommon/yoga/yoga/Yoga.c @@ -1072,7 +1072,8 @@ static float YGBaseline(const YGNodeRef node) { } YGNodeRef baselineChild = NULL; - for (uint32_t i = 0; i < YGNodeGetChildCount(node); i++) { + const uint32_t childCount = YGNodeGetChildCount(node); + for (uint32_t i = 0; i < childCount; i++) { const YGNodeRef child = YGNodeGetChild(node, i); if (child->lineIndex > 0) { break; @@ -1130,7 +1131,8 @@ static bool YGIsBaselineLayout(const YGNodeRef node) { if (node->style.alignItems == YGAlignBaseline) { return true; } - for (uint32_t i = 0; i < YGNodeGetChildCount(node); i++) { + const uint32_t childCount = YGNodeGetChildCount(node); + for (uint32_t i = 0; i < childCount; i++) { const YGNodeRef child = YGNodeGetChild(node, i); if (child->style.positionType == YGPositionTypeRelative && child->style.alignSelf == YGAlignBaseline) { @@ -1735,7 +1737,8 @@ static void YGZeroOutLayoutRecursivly(const YGNodeRef node) { node->layout.position[YGEdgeBottom] = 0; node->layout.position[YGEdgeLeft] = 0; node->layout.position[YGEdgeRight] = 0; - for (uint32_t i = 0; i < YGNodeGetChildCount(node); i++) { + const uint32_t childCount = YGNodeGetChildCount(node); + for (uint32_t i = 0; i < childCount; i++) { const YGNodeRef child = YGNodeListGet(node->children, i); YGZeroOutLayoutRecursivly(child); } @@ -1759,9 +1762,6 @@ static void YGZeroOutLayoutRecursivly(const YGNodeRef node) { // * The 'visibility' property is always assumed to be 'visible'. Values of // 'collapse' // and 'hidden' are not supported. -// * The 'wrap' property supports only 'nowrap' (which is the default) or -// 'wrap'. The -// rarely-used 'wrap-reverse' is not supported. // * There is no support for forced breaks. // * It does not support vertical inline directions (top-to-bottom or // bottom-to-top text). @@ -1911,7 +1911,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction); const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis); const YGJustify justifyContent = node->style.justifyContent; - const bool isNodeFlexWrap = node->style.flexWrap == YGWrapWrap; + const bool isNodeFlexWrap = node->style.flexWrap != YGWrapNoWrap; const float mainAxisParentSize = isMainAxisRow ? parentWidth : parentHeight; const float crossAxisParentSize = isMainAxisRow ? parentHeight : parentWidth; @@ -2929,6 +2929,18 @@ static void YGNodelayoutImpl(const YGNodeRef node, paddingAndBorderAxisCross); } + // As we only wrapped in normal direction yet, we need to reverse the positions on wrap-reverse. + if (performLayout && node->style.flexWrap == YGWrapWrapReverse) { + for (uint32_t i = 0; i < childCount; i++) { + const YGNodeRef child = YGNodeGetChild(node, i); + if (child->style.positionType == YGPositionTypeRelative) { + child->layout.position[pos[crossAxis]] = node->layout.measuredDimensions[dim[crossAxis]] - + child->layout.position[pos[crossAxis]] - + child->layout.measuredDimensions[dim[crossAxis]]; + } + } + } + if (performLayout) { // STEP 10: SIZING AND POSITIONING ABSOLUTE CHILDREN for (currentAbsoluteChild = firstAbsoluteChild; currentAbsoluteChild != NULL;