diff --git a/lib/Yoga.hs b/lib/Yoga.hs
--- a/lib/Yoga.hs
+++ b/lib/Yoga.hs
@@ -476,8 +476,8 @@
   (result, y, cs) <- renderNodeWithChildren parentInfo x children ptr f
   return $ (result, Container y cs)
 foldRenderTree parentInfo (Leaf x) ptr f = do
-  (result, y, []) <- renderNodeWithChildren parentInfo x [] ptr f
-  return $ (result, Leaf y)
+  (result, y, cs) <- renderNodeWithChildren parentInfo x [] ptr f
+  return $ cs `seq` (result, Leaf y)
 
 -- | Renders a layout with the user-supplied function. For each return value
 -- of type '(b, c)', we append the first result to the output of the previous
diff --git a/yoga.cabal b/yoga.cabal
--- a/yoga.cabal
+++ b/yoga.cabal
@@ -2,7 +2,7 @@
 -- see http://haskell.org/cabal/users-guide/
 
 name:                yoga
-version:             0.0.0.2
+version:             0.0.0.3
 synopsis:            Bindings to Facebook's Yoga layout library
 description:         The <https://facebook.github.com/yoga Yoga> library from
                      <https://facebook.github.com/ Facebook> is a fast layout engine
@@ -50,11 +50,23 @@
                     YGNodePrint.h
                     Yoga.h
                     Yoga-internal.h
+                    YGConfig.h
+                    YGFloatOptional.h
+                    YGLayout.h
+                    YGNode.h
+                    Utils.h
+
   c-sources:        yoga/YGNodePrint.cpp
                     yoga/Yoga.cpp
                     yoga/YGEnums.cpp
+                    yoga/YGConfig.cpp
+                    yoga/YGFloatOptional.cpp
+                    yoga/YGLayout.cpp
+                    yoga/YGNode.cpp
+                    yoga/YGStyle.cpp
+                    yoga/Utils.cpp
 
-  cc-options:       -Dnullptr=NULL
+  cc-options:       -Dnullptr=0
   extra-libraries:  stdc++
 
   exposed-modules:
diff --git a/yoga/Utils.cpp b/yoga/Utils.cpp
new file mode 100644
--- /dev/null
+++ b/yoga/Utils.cpp
@@ -0,0 +1,70 @@
+/*
+ *  Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ *  This source code is licensed under the MIT license found in the LICENSE
+ *  file in the root directory of this source tree.
+ *
+ */
+#include "Utils.h"
+
+using namespace facebook;
+
+YGFlexDirection YGFlexDirectionCross(
+    const YGFlexDirection flexDirection,
+    const YGDirection direction) {
+  return YGFlexDirectionIsColumn(flexDirection)
+      ? YGResolveFlexDirection(YGFlexDirectionRow, direction)
+      : YGFlexDirectionColumn;
+}
+
+float YGFloatMax(const float a, const float b) {
+  if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) {
+    return fmaxf(a, b);
+  }
+  return yoga::isUndefined(a) ? b : a;
+}
+
+float YGFloatMin(const float a, const float b) {
+  if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) {
+    return fminf(a, b);
+  }
+
+  return yoga::isUndefined(a) ? b : a;
+}
+
+bool YGValueEqual(const YGValue a, const YGValue b) {
+  if (a.unit != b.unit) {
+    return false;
+  }
+
+  if (a.unit == YGUnitUndefined ||
+      (yoga::isUndefined(a.value) && yoga::isUndefined(b.value))) {
+    return true;
+  }
+
+  return fabs(a.value - b.value) < 0.0001f;
+}
+
+bool YGFloatsEqual(const float a, const float b) {
+  if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) {
+    return fabs(a - b) < 0.0001f;
+  }
+  return yoga::isUndefined(a) && yoga::isUndefined(b);
+}
+
+float YGFloatSanitize(const float& val) {
+  return yoga::isUndefined(val) ? 0 : val;
+}
+
+float YGUnwrapFloatOptional(const YGFloatOptional& op) {
+  return op.isUndefined() ? YGUndefined : op.getValue();
+}
+
+YGFloatOptional YGFloatOptionalMax(
+    const YGFloatOptional& op1,
+    const YGFloatOptional& op2) {
+  if (!op1.isUndefined() && !op2.isUndefined()) {
+    return op1.getValue() > op2.getValue() ? op1 : op2;
+  }
+  return op1.isUndefined() ? op2 : op1;
+}
diff --git a/yoga/Utils.h b/yoga/Utils.h
new file mode 100644
--- /dev/null
+++ b/yoga/Utils.h
@@ -0,0 +1,148 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#pragma once
+#include "YGNode.h"
+#include "Yoga-internal.h"
+
+// This struct is an helper model to hold the data for step 4 of flexbox
+// algo, which is collecting the flex items in a line.
+//
+// - itemsOnLine: Number of items which can fit in a line considering the
+// available Inner dimension, the flex items computed flexbasis and their
+// margin. It may be different than the difference between start and end
+// indicates because we skip over absolute-positioned items.
+//
+// - sizeConsumedOnCurrentLine: It is accumulation of the dimensions and margin
+// of all the children on the current line. 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.
+//
+// - totalFlexGrowFactors: total flex grow factors of flex items which are to be
+// layed in the current line
+//
+// - totalFlexShrinkFactors: total flex shrink factors of flex items which are
+// to be layed in the current line
+//
+// - endOfLineIndex: Its the end index of the last flex item which was examined
+// and it may or may not be part of the current line(as it may be absolutely
+// positioned or inculding it may have caused to overshoot availableInnerDim)
+//
+// - relativeChildren: Maintain a vector of the child nodes that can shrink
+// and/or grow.
+
+struct YGCollectFlexItemsRowValues {
+  uint32_t itemsOnLine;
+  float sizeConsumedOnCurrentLine;
+  float totalFlexGrowFactors;
+  float totalFlexShrinkScaledFactors;
+  uint32_t endOfLineIndex;
+  std::vector<YGNodeRef> relativeChildren;
+  float remainingFreeSpace;
+  // The size of the mainDim for the row after considering size, padding, margin
+  // and border of flex items. This is used to calculate maxLineDim after going
+  // through all the rows to decide on the main axis size of owner.
+  float mainDim;
+  // The size of the crossDim for the row after considering size, padding,
+  // margin and border of flex items. Used for calculating containers crossSize.
+  float crossDim;
+};
+
+bool YGValueEqual(const YGValue a, const YGValue b);
+
+// This custom float equality function returns true if either absolute
+// difference between two floats is less than 0.0001f or both are undefined.
+bool YGFloatsEqual(const float a, const float b);
+
+// We need custom max function, since we want that, if one argument is
+// YGUndefined then the max funtion should return the other argument as the max
+// value. We wouldn't have needed a custom max function if YGUndefined was NAN
+// as fmax has the same behaviour, but with NAN we cannot use `-ffast-math`
+// compiler flag.
+float YGFloatMax(const float a, const float b);
+
+YGFloatOptional YGFloatOptionalMax(
+    const YGFloatOptional& op1,
+    const YGFloatOptional& op2);
+
+// We need custom min function, since we want that, if one argument is
+// YGUndefined then the min funtion should return the other argument as the min
+// value. We wouldn't have needed a custom min function if YGUndefined was NAN
+// as fmin has the same behaviour, but with NAN we cannot use `-ffast-math`
+// compiler flag.
+float YGFloatMin(const float a, const float b);
+
+// This custom float comparision function compares the array of float with
+// YGFloatsEqual, as the default float comparision operator will not work(Look
+// at the comments of YGFloatsEqual function).
+template <std::size_t size>
+bool YGFloatArrayEqual(
+    const std::array<float, size>& val1,
+    const std::array<float, size>& val2) {
+  bool areEqual = true;
+  for (std::size_t i = 0; i < size && areEqual; ++i) {
+    areEqual = YGFloatsEqual(val1[i], val2[i]);
+  }
+  return areEqual;
+}
+
+// This function returns 0 if YGFloatIsUndefined(val) is true and val otherwise
+float YGFloatSanitize(const float& val);
+
+// This function unwraps optional and returns YGUndefined if not defined or
+// op.value otherwise
+// TODO: Get rid off this function
+float YGUnwrapFloatOptional(const YGFloatOptional& op);
+
+YGFlexDirection YGFlexDirectionCross(
+    const YGFlexDirection flexDirection,
+    const YGDirection direction);
+
+inline bool YGFlexDirectionIsRow(const YGFlexDirection flexDirection) {
+  return flexDirection == YGFlexDirectionRow ||
+      flexDirection == YGFlexDirectionRowReverse;
+}
+
+inline YGFloatOptional YGResolveValue(const YGValue value, const float ownerSize) {
+  switch (value.unit) {
+    case YGUnitUndefined:
+    case YGUnitAuto:
+      return YGFloatOptional();
+    case YGUnitPoint:
+      return YGFloatOptional(value.value);
+    case YGUnitPercent:
+      return YGFloatOptional(
+          static_cast<float>(value.value * ownerSize * 0.01));
+  }
+  return YGFloatOptional();
+}
+
+inline bool YGFlexDirectionIsColumn(const YGFlexDirection flexDirection) {
+  return flexDirection == YGFlexDirectionColumn ||
+      flexDirection == YGFlexDirectionColumnReverse;
+}
+
+inline YGFlexDirection YGResolveFlexDirection(
+    const YGFlexDirection flexDirection,
+    const YGDirection direction) {
+  if (direction == YGDirectionRTL) {
+    if (flexDirection == YGFlexDirectionRow) {
+      return YGFlexDirectionRowReverse;
+    } else if (flexDirection == YGFlexDirectionRowReverse) {
+      return YGFlexDirectionRow;
+    }
+  }
+
+  return flexDirection;
+}
+
+static inline YGFloatOptional YGResolveValueMargin(
+    const YGValue value,
+    const float ownerSize) {
+  return value.unit == YGUnitAuto ? YGFloatOptional(0)
+                                  : YGResolveValue(value, ownerSize);
+}
diff --git a/yoga/YGConfig.cpp b/yoga/YGConfig.cpp
new file mode 100644
--- /dev/null
+++ b/yoga/YGConfig.cpp
@@ -0,0 +1,22 @@
+/*
+ *  Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ *  This source code is licensed under the MIT license found in the LICENSE
+ *  file in the root directory of this source tree.
+ *
+ */
+#include "YGConfig.h"
+
+const std::array<bool, YGExperimentalFeatureCount>
+    kYGDefaultExperimentalFeatures = {{false}};
+
+YGConfig::YGConfig(YGLogger logger)
+    : experimentalFeatures(kYGDefaultExperimentalFeatures),
+      useWebDefaults(false),
+      useLegacyStretchBehaviour(false),
+      shouldDiffLayoutWithoutLegacyStretchBehaviour(false),
+      pointScaleFactor(1.0f),
+      logger(logger),
+      cloneNodeCallback(nullptr),
+      context(nullptr),
+      printTree(false) {}
diff --git a/yoga/YGConfig.h b/yoga/YGConfig.h
new file mode 100644
--- /dev/null
+++ b/yoga/YGConfig.h
@@ -0,0 +1,24 @@
+/*
+ *  Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ *  This source code is licensed under the MIT license found in the LICENSE
+ *  file in the root directory of this source tree.
+ *
+ */
+#pragma once
+#include "Yoga-internal.h"
+#include "Yoga.h"
+
+struct YGConfig {
+  std::array<bool, YGExperimentalFeatureCount> experimentalFeatures;
+  bool useWebDefaults;
+  bool useLegacyStretchBehaviour;
+  bool shouldDiffLayoutWithoutLegacyStretchBehaviour;
+  float pointScaleFactor;
+  YGLogger logger;
+  YGCloneNodeFunc cloneNodeCallback;
+  void* context;
+  bool printTree;
+
+  YGConfig(YGLogger logger);
+};
diff --git a/yoga/YGEnums.cpp b/yoga/YGEnums.cpp
--- a/yoga/YGEnums.cpp
+++ b/yoga/YGEnums.cpp
@@ -1,228 +1,226 @@
-/**
- * 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.
- */
-
-#include "YGEnums.h"
-
-const char *YGAlignToString(const YGAlign value){
-  switch(value){
-    case YGAlignAuto:
-      return "auto";
-    case YGAlignFlexStart:
-      return "flex-start";
-    case YGAlignCenter:
-      return "center";
-    case YGAlignFlexEnd:
-      return "flex-end";
-    case YGAlignStretch:
-      return "stretch";
-    case YGAlignBaseline:
-      return "baseline";
-    case YGAlignSpaceBetween:
-      return "space-between";
-    case YGAlignSpaceAround:
-      return "space-around";
-  }
-  return "unknown";
-}
-
-const char *YGDimensionToString(const YGDimension value){
-  switch(value){
-    case YGDimensionWidth:
-      return "width";
-    case YGDimensionHeight:
-      return "height";
-  }
-  return "unknown";
-}
-
-const char *YGDirectionToString(const YGDirection value){
-  switch(value){
-    case YGDirectionInherit:
-      return "inherit";
-    case YGDirectionLTR:
-      return "ltr";
-    case YGDirectionRTL:
-      return "rtl";
-  }
-  return "unknown";
-}
-
-const char *YGDisplayToString(const YGDisplay value){
-  switch(value){
-    case YGDisplayFlex:
-      return "flex";
-    case YGDisplayNone:
-      return "none";
-  }
-  return "unknown";
-}
-
-const char *YGEdgeToString(const YGEdge value){
-  switch(value){
-    case YGEdgeLeft:
-      return "left";
-    case YGEdgeTop:
-      return "top";
-    case YGEdgeRight:
-      return "right";
-    case YGEdgeBottom:
-      return "bottom";
-    case YGEdgeStart:
-      return "start";
-    case YGEdgeEnd:
-      return "end";
-    case YGEdgeHorizontal:
-      return "horizontal";
-    case YGEdgeVertical:
-      return "vertical";
-    case YGEdgeAll:
-      return "all";
-  }
-  return "unknown";
-}
-
-const char *YGExperimentalFeatureToString(const YGExperimentalFeature value){
-  switch(value){
-    case YGExperimentalFeatureWebFlexBasis:
-      return "web-flex-basis";
-  }
-  return "unknown";
-}
-
-const char *YGFlexDirectionToString(const YGFlexDirection value){
-  switch(value){
-    case YGFlexDirectionColumn:
-      return "column";
-    case YGFlexDirectionColumnReverse:
-      return "column-reverse";
-    case YGFlexDirectionRow:
-      return "row";
-    case YGFlexDirectionRowReverse:
-      return "row-reverse";
-  }
-  return "unknown";
-}
-
-const char *YGJustifyToString(const YGJustify value){
-  switch(value){
-    case YGJustifyFlexStart:
-      return "flex-start";
-    case YGJustifyCenter:
-      return "center";
-    case YGJustifyFlexEnd:
-      return "flex-end";
-    case YGJustifySpaceBetween:
-      return "space-between";
-    case YGJustifySpaceAround:
-      return "space-around";
-    case YGJustifySpaceEvenly:
-      return "space-evenly";
-  }
-  return "unknown";
-}
-
-const char *YGLogLevelToString(const YGLogLevel value){
-  switch(value){
-    case YGLogLevelError:
-      return "error";
-    case YGLogLevelWarn:
-      return "warn";
-    case YGLogLevelInfo:
-      return "info";
-    case YGLogLevelDebug:
-      return "debug";
-    case YGLogLevelVerbose:
-      return "verbose";
-    case YGLogLevelFatal:
-      return "fatal";
-  }
-  return "unknown";
-}
-
-const char *YGMeasureModeToString(const YGMeasureMode value){
-  switch(value){
-    case YGMeasureModeUndefined:
-      return "undefined";
-    case YGMeasureModeExactly:
-      return "exactly";
-    case YGMeasureModeAtMost:
-      return "at-most";
-  }
-  return "unknown";
-}
-
-const char *YGNodeTypeToString(const YGNodeType value){
-  switch(value){
-    case YGNodeTypeDefault:
-      return "default";
-    case YGNodeTypeText:
-      return "text";
-  }
-  return "unknown";
-}
-
-const char *YGOverflowToString(const YGOverflow value){
-  switch(value){
-    case YGOverflowVisible:
-      return "visible";
-    case YGOverflowHidden:
-      return "hidden";
-    case YGOverflowScroll:
-      return "scroll";
-  }
-  return "unknown";
-}
-
-const char *YGPositionTypeToString(const YGPositionType value){
-  switch(value){
-    case YGPositionTypeRelative:
-      return "relative";
-    case YGPositionTypeAbsolute:
-      return "absolute";
-  }
-  return "unknown";
-}
-
-const char *YGPrintOptionsToString(const YGPrintOptions value){
-  switch(value){
-    case YGPrintOptionsLayout:
-      return "layout";
-    case YGPrintOptionsStyle:
-      return "style";
-    case YGPrintOptionsChildren:
-      return "children";
-  }
-  return "unknown";
-}
-
-const char *YGUnitToString(const YGUnit value){
-  switch(value){
-    case YGUnitUndefined:
-      return "undefined";
-    case YGUnitPoint:
-      return "point";
-    case YGUnitPercent:
-      return "percent";
-    case YGUnitAuto:
-      return "auto";
-  }
-  return "unknown";
-}
-
-const char *YGWrapToString(const YGWrap value){
-  switch(value){
-    case YGWrapNoWrap:
-      return "no-wrap";
-    case YGWrapWrap:
-      return "wrap";
-    case YGWrapWrapReverse:
-      return "wrap-reverse";
-  }
-  return "unknown";
-}
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include "YGEnums.h"
+
+const char *YGAlignToString(const YGAlign value){
+  switch(value){
+    case YGAlignAuto:
+      return "auto";
+    case YGAlignFlexStart:
+      return "flex-start";
+    case YGAlignCenter:
+      return "center";
+    case YGAlignFlexEnd:
+      return "flex-end";
+    case YGAlignStretch:
+      return "stretch";
+    case YGAlignBaseline:
+      return "baseline";
+    case YGAlignSpaceBetween:
+      return "space-between";
+    case YGAlignSpaceAround:
+      return "space-around";
+  }
+  return "unknown";
+}
+
+const char *YGDimensionToString(const YGDimension value){
+  switch(value){
+    case YGDimensionWidth:
+      return "width";
+    case YGDimensionHeight:
+      return "height";
+  }
+  return "unknown";
+}
+
+const char *YGDirectionToString(const YGDirection value){
+  switch(value){
+    case YGDirectionInherit:
+      return "inherit";
+    case YGDirectionLTR:
+      return "ltr";
+    case YGDirectionRTL:
+      return "rtl";
+  }
+  return "unknown";
+}
+
+const char *YGDisplayToString(const YGDisplay value){
+  switch(value){
+    case YGDisplayFlex:
+      return "flex";
+    case YGDisplayNone:
+      return "none";
+  }
+  return "unknown";
+}
+
+const char *YGEdgeToString(const YGEdge value){
+  switch(value){
+    case YGEdgeLeft:
+      return "left";
+    case YGEdgeTop:
+      return "top";
+    case YGEdgeRight:
+      return "right";
+    case YGEdgeBottom:
+      return "bottom";
+    case YGEdgeStart:
+      return "start";
+    case YGEdgeEnd:
+      return "end";
+    case YGEdgeHorizontal:
+      return "horizontal";
+    case YGEdgeVertical:
+      return "vertical";
+    case YGEdgeAll:
+      return "all";
+  }
+  return "unknown";
+}
+
+const char *YGExperimentalFeatureToString(const YGExperimentalFeature value){
+  switch(value){
+    case YGExperimentalFeatureWebFlexBasis:
+      return "web-flex-basis";
+  }
+  return "unknown";
+}
+
+const char *YGFlexDirectionToString(const YGFlexDirection value){
+  switch(value){
+    case YGFlexDirectionColumn:
+      return "column";
+    case YGFlexDirectionColumnReverse:
+      return "column-reverse";
+    case YGFlexDirectionRow:
+      return "row";
+    case YGFlexDirectionRowReverse:
+      return "row-reverse";
+  }
+  return "unknown";
+}
+
+const char *YGJustifyToString(const YGJustify value){
+  switch(value){
+    case YGJustifyFlexStart:
+      return "flex-start";
+    case YGJustifyCenter:
+      return "center";
+    case YGJustifyFlexEnd:
+      return "flex-end";
+    case YGJustifySpaceBetween:
+      return "space-between";
+    case YGJustifySpaceAround:
+      return "space-around";
+    case YGJustifySpaceEvenly:
+      return "space-evenly";
+  }
+  return "unknown";
+}
+
+const char *YGLogLevelToString(const YGLogLevel value){
+  switch(value){
+    case YGLogLevelError:
+      return "error";
+    case YGLogLevelWarn:
+      return "warn";
+    case YGLogLevelInfo:
+      return "info";
+    case YGLogLevelDebug:
+      return "debug";
+    case YGLogLevelVerbose:
+      return "verbose";
+    case YGLogLevelFatal:
+      return "fatal";
+  }
+  return "unknown";
+}
+
+const char *YGMeasureModeToString(const YGMeasureMode value){
+  switch(value){
+    case YGMeasureModeUndefined:
+      return "undefined";
+    case YGMeasureModeExactly:
+      return "exactly";
+    case YGMeasureModeAtMost:
+      return "at-most";
+  }
+  return "unknown";
+}
+
+const char *YGNodeTypeToString(const YGNodeType value){
+  switch(value){
+    case YGNodeTypeDefault:
+      return "default";
+    case YGNodeTypeText:
+      return "text";
+  }
+  return "unknown";
+}
+
+const char *YGOverflowToString(const YGOverflow value){
+  switch(value){
+    case YGOverflowVisible:
+      return "visible";
+    case YGOverflowHidden:
+      return "hidden";
+    case YGOverflowScroll:
+      return "scroll";
+  }
+  return "unknown";
+}
+
+const char *YGPositionTypeToString(const YGPositionType value){
+  switch(value){
+    case YGPositionTypeRelative:
+      return "relative";
+    case YGPositionTypeAbsolute:
+      return "absolute";
+  }
+  return "unknown";
+}
+
+const char *YGPrintOptionsToString(const YGPrintOptions value){
+  switch(value){
+    case YGPrintOptionsLayout:
+      return "layout";
+    case YGPrintOptionsStyle:
+      return "style";
+    case YGPrintOptionsChildren:
+      return "children";
+  }
+  return "unknown";
+}
+
+const char *YGUnitToString(const YGUnit value){
+  switch(value){
+    case YGUnitUndefined:
+      return "undefined";
+    case YGUnitPoint:
+      return "point";
+    case YGUnitPercent:
+      return "percent";
+    case YGUnitAuto:
+      return "auto";
+  }
+  return "unknown";
+}
+
+const char *YGWrapToString(const YGWrap value){
+  switch(value){
+    case YGWrapNoWrap:
+      return "no-wrap";
+    case YGWrapWrap:
+      return "wrap";
+    case YGWrapWrapReverse:
+      return "wrap-reverse";
+  }
+  return "unknown";
+}
diff --git a/yoga/YGEnums.h b/yoga/YGEnums.h
--- a/yoga/YGEnums.h
+++ b/yoga/YGEnums.h
@@ -1,157 +1,155 @@
-/**
- * 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.
- */
-
-#pragma once
-
-#include "YGMacros.h"
-
-YG_EXTERN_C_BEGIN
-
-#define YGAlignCount 8
-typedef YG_ENUM_BEGIN(YGAlign) {
-  YGAlignAuto,
-  YGAlignFlexStart,
-  YGAlignCenter,
-  YGAlignFlexEnd,
-  YGAlignStretch,
-  YGAlignBaseline,
-  YGAlignSpaceBetween,
-  YGAlignSpaceAround,
-} YG_ENUM_END(YGAlign);
-WIN_EXPORT const char *YGAlignToString(const YGAlign value);
-
-#define YGDimensionCount 2
-typedef YG_ENUM_BEGIN(YGDimension) {
-  YGDimensionWidth,
-  YGDimensionHeight,
-} YG_ENUM_END(YGDimension);
-WIN_EXPORT const char *YGDimensionToString(const YGDimension value);
-
-#define YGDirectionCount 3
-typedef YG_ENUM_BEGIN(YGDirection) {
-  YGDirectionInherit,
-  YGDirectionLTR,
-  YGDirectionRTL,
-} YG_ENUM_END(YGDirection);
-WIN_EXPORT const char *YGDirectionToString(const YGDirection value);
-
-#define YGDisplayCount 2
-typedef YG_ENUM_BEGIN(YGDisplay) {
-  YGDisplayFlex,
-  YGDisplayNone,
-} YG_ENUM_END(YGDisplay);
-WIN_EXPORT const char *YGDisplayToString(const YGDisplay value);
-
-#define YGEdgeCount 9
-typedef YG_ENUM_BEGIN(YGEdge) {
-  YGEdgeLeft,
-  YGEdgeTop,
-  YGEdgeRight,
-  YGEdgeBottom,
-  YGEdgeStart,
-  YGEdgeEnd,
-  YGEdgeHorizontal,
-  YGEdgeVertical,
-  YGEdgeAll,
-} YG_ENUM_END(YGEdge);
-WIN_EXPORT const char *YGEdgeToString(const YGEdge value);
-
-#define YGExperimentalFeatureCount 1
-typedef YG_ENUM_BEGIN(YGExperimentalFeature) {
-  YGExperimentalFeatureWebFlexBasis,
-} YG_ENUM_END(YGExperimentalFeature);
-WIN_EXPORT const char *YGExperimentalFeatureToString(const YGExperimentalFeature value);
-
-#define YGFlexDirectionCount 4
-typedef YG_ENUM_BEGIN(YGFlexDirection) {
-  YGFlexDirectionColumn,
-  YGFlexDirectionColumnReverse,
-  YGFlexDirectionRow,
-  YGFlexDirectionRowReverse,
-} YG_ENUM_END(YGFlexDirection);
-WIN_EXPORT const char *YGFlexDirectionToString(const YGFlexDirection value);
-
-#define YGJustifyCount 6
-typedef YG_ENUM_BEGIN(YGJustify){
-    YGJustifyFlexStart,
-    YGJustifyCenter,
-    YGJustifyFlexEnd,
-    YGJustifySpaceBetween,
-    YGJustifySpaceAround,
-    YGJustifySpaceEvenly,
-} YG_ENUM_END(YGJustify);
-WIN_EXPORT const char *YGJustifyToString(const YGJustify value);
-
-#define YGLogLevelCount 6
-typedef YG_ENUM_BEGIN(YGLogLevel) {
-  YGLogLevelError,
-  YGLogLevelWarn,
-  YGLogLevelInfo,
-  YGLogLevelDebug,
-  YGLogLevelVerbose,
-  YGLogLevelFatal,
-} YG_ENUM_END(YGLogLevel);
-WIN_EXPORT const char *YGLogLevelToString(const YGLogLevel value);
-
-#define YGMeasureModeCount 3
-typedef YG_ENUM_BEGIN(YGMeasureMode) {
-  YGMeasureModeUndefined,
-  YGMeasureModeExactly,
-  YGMeasureModeAtMost,
-} YG_ENUM_END(YGMeasureMode);
-WIN_EXPORT const char *YGMeasureModeToString(const YGMeasureMode value);
-
-#define YGNodeTypeCount 2
-typedef YG_ENUM_BEGIN(YGNodeType) {
-  YGNodeTypeDefault,
-  YGNodeTypeText,
-} YG_ENUM_END(YGNodeType);
-WIN_EXPORT const char *YGNodeTypeToString(const YGNodeType value);
-
-#define YGOverflowCount 3
-typedef YG_ENUM_BEGIN(YGOverflow) {
-  YGOverflowVisible,
-  YGOverflowHidden,
-  YGOverflowScroll,
-} YG_ENUM_END(YGOverflow);
-WIN_EXPORT const char *YGOverflowToString(const YGOverflow value);
-
-#define YGPositionTypeCount 2
-typedef YG_ENUM_BEGIN(YGPositionType) {
-  YGPositionTypeRelative,
-  YGPositionTypeAbsolute,
-} YG_ENUM_END(YGPositionType);
-WIN_EXPORT const char *YGPositionTypeToString(const YGPositionType value);
-
-#define YGPrintOptionsCount 3
-typedef YG_ENUM_BEGIN(YGPrintOptions) {
-  YGPrintOptionsLayout = 1,
-  YGPrintOptionsStyle = 2,
-  YGPrintOptionsChildren = 4,
-} YG_ENUM_END(YGPrintOptions);
-WIN_EXPORT const char *YGPrintOptionsToString(const YGPrintOptions value);
-
-#define YGUnitCount 4
-typedef YG_ENUM_BEGIN(YGUnit) {
-  YGUnitUndefined,
-  YGUnitPoint,
-  YGUnitPercent,
-  YGUnitAuto,
-} YG_ENUM_END(YGUnit);
-WIN_EXPORT const char *YGUnitToString(const YGUnit value);
-
-#define YGWrapCount 3
-typedef YG_ENUM_BEGIN(YGWrap) {
-  YGWrapNoWrap,
-  YGWrapWrap,
-  YGWrapWrapReverse,
-} YG_ENUM_END(YGWrap);
-WIN_EXPORT const char *YGWrapToString(const YGWrap value);
-
-YG_EXTERN_C_END
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#pragma once
+
+#include "YGMacros.h"
+
+YG_EXTERN_C_BEGIN
+
+#define YGAlignCount 8
+typedef YG_ENUM_BEGIN(YGAlign) {
+  YGAlignAuto,
+  YGAlignFlexStart,
+  YGAlignCenter,
+  YGAlignFlexEnd,
+  YGAlignStretch,
+  YGAlignBaseline,
+  YGAlignSpaceBetween,
+  YGAlignSpaceAround,
+} YG_ENUM_END(YGAlign);
+WIN_EXPORT const char *YGAlignToString(const YGAlign value);
+
+#define YGDimensionCount 2
+typedef YG_ENUM_BEGIN(YGDimension) {
+  YGDimensionWidth,
+  YGDimensionHeight,
+} YG_ENUM_END(YGDimension);
+WIN_EXPORT const char *YGDimensionToString(const YGDimension value);
+
+#define YGDirectionCount 3
+typedef YG_ENUM_BEGIN(YGDirection) {
+  YGDirectionInherit,
+  YGDirectionLTR,
+  YGDirectionRTL,
+} YG_ENUM_END(YGDirection);
+WIN_EXPORT const char *YGDirectionToString(const YGDirection value);
+
+#define YGDisplayCount 2
+typedef YG_ENUM_BEGIN(YGDisplay) {
+  YGDisplayFlex,
+  YGDisplayNone,
+} YG_ENUM_END(YGDisplay);
+WIN_EXPORT const char *YGDisplayToString(const YGDisplay value);
+
+#define YGEdgeCount 9
+typedef YG_ENUM_BEGIN(YGEdge) {
+  YGEdgeLeft,
+  YGEdgeTop,
+  YGEdgeRight,
+  YGEdgeBottom,
+  YGEdgeStart,
+  YGEdgeEnd,
+  YGEdgeHorizontal,
+  YGEdgeVertical,
+  YGEdgeAll,
+} YG_ENUM_END(YGEdge);
+WIN_EXPORT const char *YGEdgeToString(const YGEdge value);
+
+#define YGExperimentalFeatureCount 1
+typedef YG_ENUM_BEGIN(YGExperimentalFeature) {
+  YGExperimentalFeatureWebFlexBasis,
+} YG_ENUM_END(YGExperimentalFeature);
+WIN_EXPORT const char *YGExperimentalFeatureToString(const YGExperimentalFeature value);
+
+#define YGFlexDirectionCount 4
+typedef YG_ENUM_BEGIN(YGFlexDirection) {
+  YGFlexDirectionColumn,
+  YGFlexDirectionColumnReverse,
+  YGFlexDirectionRow,
+  YGFlexDirectionRowReverse,
+} YG_ENUM_END(YGFlexDirection);
+WIN_EXPORT const char *YGFlexDirectionToString(const YGFlexDirection value);
+
+#define YGJustifyCount 6
+typedef YG_ENUM_BEGIN(YGJustify){
+    YGJustifyFlexStart,
+    YGJustifyCenter,
+    YGJustifyFlexEnd,
+    YGJustifySpaceBetween,
+    YGJustifySpaceAround,
+    YGJustifySpaceEvenly,
+} YG_ENUM_END(YGJustify);
+WIN_EXPORT const char *YGJustifyToString(const YGJustify value);
+
+#define YGLogLevelCount 6
+typedef YG_ENUM_BEGIN(YGLogLevel) {
+  YGLogLevelError,
+  YGLogLevelWarn,
+  YGLogLevelInfo,
+  YGLogLevelDebug,
+  YGLogLevelVerbose,
+  YGLogLevelFatal,
+} YG_ENUM_END(YGLogLevel);
+WIN_EXPORT const char *YGLogLevelToString(const YGLogLevel value);
+
+#define YGMeasureModeCount 3
+typedef YG_ENUM_BEGIN(YGMeasureMode) {
+  YGMeasureModeUndefined,
+  YGMeasureModeExactly,
+  YGMeasureModeAtMost,
+} YG_ENUM_END(YGMeasureMode);
+WIN_EXPORT const char *YGMeasureModeToString(const YGMeasureMode value);
+
+#define YGNodeTypeCount 2
+typedef YG_ENUM_BEGIN(YGNodeType) {
+  YGNodeTypeDefault,
+  YGNodeTypeText,
+} YG_ENUM_END(YGNodeType);
+WIN_EXPORT const char *YGNodeTypeToString(const YGNodeType value);
+
+#define YGOverflowCount 3
+typedef YG_ENUM_BEGIN(YGOverflow) {
+  YGOverflowVisible,
+  YGOverflowHidden,
+  YGOverflowScroll,
+} YG_ENUM_END(YGOverflow);
+WIN_EXPORT const char *YGOverflowToString(const YGOverflow value);
+
+#define YGPositionTypeCount 2
+typedef YG_ENUM_BEGIN(YGPositionType) {
+  YGPositionTypeRelative,
+  YGPositionTypeAbsolute,
+} YG_ENUM_END(YGPositionType);
+WIN_EXPORT const char *YGPositionTypeToString(const YGPositionType value);
+
+#define YGPrintOptionsCount 3
+typedef YG_ENUM_BEGIN(YGPrintOptions) {
+  YGPrintOptionsLayout = 1,
+  YGPrintOptionsStyle = 2,
+  YGPrintOptionsChildren = 4,
+} YG_ENUM_END(YGPrintOptions);
+WIN_EXPORT const char *YGPrintOptionsToString(const YGPrintOptions value);
+
+#define YGUnitCount 4
+typedef YG_ENUM_BEGIN(YGUnit) {
+  YGUnitUndefined,
+  YGUnitPoint,
+  YGUnitPercent,
+  YGUnitAuto,
+} YG_ENUM_END(YGUnit);
+WIN_EXPORT const char *YGUnitToString(const YGUnit value);
+
+#define YGWrapCount 3
+typedef YG_ENUM_BEGIN(YGWrap) {
+  YGWrapNoWrap,
+  YGWrapWrap,
+  YGWrapWrapReverse,
+} YG_ENUM_END(YGWrap);
+WIN_EXPORT const char *YGWrapToString(const YGWrap value);
+
+YG_EXTERN_C_END
diff --git a/yoga/YGFloatOptional.cpp b/yoga/YGFloatOptional.cpp
new file mode 100644
--- /dev/null
+++ b/yoga/YGFloatOptional.cpp
@@ -0,0 +1,84 @@
+/*
+ *  Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ *  This source code is licensed under the MIT license found in the LICENSE
+ *  file in the root directory of this source tree.
+ *
+ */
+#include "YGFloatOptional.h"
+#include <cstdlib>
+#include <iostream>
+#include "Yoga.h"
+#include "Yoga-internal.h"
+
+using namespace facebook;
+
+YGFloatOptional::YGFloatOptional(float value) {
+  if (yoga::isUndefined(value)) {
+    isUndefined_ = true;
+    value_ = 0;
+  } else {
+    value_ = value;
+    isUndefined_ = false;
+  }
+}
+
+float YGFloatOptional::getValue() const {
+  if (isUndefined_) {
+    // Abort, accessing a value of an undefined float optional
+    std::cerr << "Tried to get value of an undefined YGFloatOptional\n";
+    std::exit(EXIT_FAILURE);
+  }
+  return value_;
+}
+
+bool YGFloatOptional::operator==(const YGFloatOptional& op) const {
+  if (isUndefined_ == op.isUndefined()) {
+    return isUndefined_ || value_ == op.getValue();
+  }
+  return false;
+}
+
+bool YGFloatOptional::operator!=(const YGFloatOptional& op) const {
+  return !(*this == op);
+}
+
+bool YGFloatOptional::operator==(float val) const {
+  if (yoga::isUndefined(val) == isUndefined_) {
+    return isUndefined_ || val == value_;
+  }
+  return false;
+}
+
+bool YGFloatOptional::operator!=(float val) const {
+  return !(*this == val);
+}
+
+YGFloatOptional YGFloatOptional::operator+(const YGFloatOptional& op) {
+  if (!isUndefined_ && !op.isUndefined_) {
+    return YGFloatOptional(value_ + op.value_);
+  }
+  return YGFloatOptional();
+}
+
+bool YGFloatOptional::operator>(const YGFloatOptional& op) const {
+  if (isUndefined_ || op.isUndefined_) {
+    return false;
+  }
+  return value_ > op.value_;
+}
+
+bool YGFloatOptional::operator<(const YGFloatOptional& op) const {
+  if (isUndefined_ || op.isUndefined_) {
+    return false;
+  }
+  return value_ < op.value_;
+}
+
+bool YGFloatOptional::operator>=(const YGFloatOptional& op) const {
+  return *this == op || *this > op;
+}
+
+bool YGFloatOptional::operator<=(const YGFloatOptional& op) const {
+  return *this == op || *this < op;
+}
diff --git a/yoga/YGFloatOptional.h b/yoga/YGFloatOptional.h
new file mode 100644
--- /dev/null
+++ b/yoga/YGFloatOptional.h
@@ -0,0 +1,44 @@
+/*
+ *  Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ *  This source code is licensed under the MIT license found in the LICENSE
+ *  file in the root directory of this source tree.
+ *
+ */
+#pragma once
+
+struct YGFloatOptional {
+ private:
+  float value_;
+  bool isUndefined_;
+
+ public:
+  explicit YGFloatOptional(float value);
+  explicit YGFloatOptional() : value_(0), isUndefined_(true) {}
+
+  // Program will terminate if the value of an undefined is accessed. Please
+  // make sure to check if the optional is defined before calling this function.
+  // To check if float optional is defined, use `isUndefined()`.
+  float getValue() const;
+
+  // Sets the value of float optional, and thus isUndefined is assigned false.
+  void setValue(float val) {
+    value_ = val;
+    isUndefined_ = false;
+  }
+
+  bool isUndefined() const {
+    return isUndefined_;
+  }
+
+  YGFloatOptional operator+(const YGFloatOptional& op);
+  bool operator>(const YGFloatOptional& op) const;
+  bool operator<(const YGFloatOptional& op) const;
+  bool operator>=(const YGFloatOptional& op) const;
+  bool operator<=(const YGFloatOptional& op) const;
+  bool operator==(const YGFloatOptional& op) const;
+  bool operator!=(const YGFloatOptional& op) const;
+
+  bool operator==(float val) const;
+  bool operator!=(float val) const;
+};
diff --git a/yoga/YGLayout.cpp b/yoga/YGLayout.cpp
new file mode 100644
--- /dev/null
+++ b/yoga/YGLayout.cpp
@@ -0,0 +1,63 @@
+/*
+ *  Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ *  This source code is licensed under the MIT license found in the LICENSE
+ *  file in the root directory of this source tree.
+ *
+ */
+#include "YGLayout.h"
+#include "Utils.h"
+
+using namespace facebook;
+
+const std::array<float, 2> kYGDefaultDimensionValues = {
+    {YGUndefined, YGUndefined}};
+
+YGLayout::YGLayout()
+    : position(),
+      dimensions(kYGDefaultDimensionValues),
+      margin(),
+      border(),
+      padding(),
+      direction(YGDirectionInherit),
+      computedFlexBasisGeneration(0),
+      computedFlexBasis(YGFloatOptional()),
+      hadOverflow(false),
+      generationCount(0),
+      lastOwnerDirection((YGDirection)-1),
+      nextCachedMeasurementsIndex(0),
+      cachedMeasurements(),
+      measuredDimensions(kYGDefaultDimensionValues),
+      cachedLayout(YGCachedMeasurement()),
+      didUseLegacyFlag(false),
+      doesLegacyStretchFlagAffectsLayout(false) {}
+
+bool YGLayout::operator==(YGLayout layout) const {
+  bool isEqual = YGFloatArrayEqual(position, layout.position) &&
+      YGFloatArrayEqual(dimensions, layout.dimensions) &&
+      YGFloatArrayEqual(margin, layout.margin) &&
+      YGFloatArrayEqual(border, layout.border) &&
+      YGFloatArrayEqual(padding, layout.padding) &&
+      direction == layout.direction && hadOverflow == layout.hadOverflow &&
+      lastOwnerDirection == layout.lastOwnerDirection &&
+      nextCachedMeasurementsIndex == layout.nextCachedMeasurementsIndex &&
+      cachedLayout == layout.cachedLayout &&
+      computedFlexBasis == layout.computedFlexBasis;
+
+  for (uint32_t i = 0; i < YG_MAX_CACHED_RESULT_COUNT && isEqual; ++i) {
+    isEqual = isEqual && cachedMeasurements[i] == layout.cachedMeasurements[i];
+  }
+
+  if (!yoga::isUndefined(measuredDimensions[0]) ||
+      !yoga::isUndefined(layout.measuredDimensions[0])) {
+    isEqual =
+        isEqual && (measuredDimensions[0] == layout.measuredDimensions[0]);
+  }
+  if (!yoga::isUndefined(measuredDimensions[1]) ||
+      !yoga::isUndefined(layout.measuredDimensions[1])) {
+    isEqual =
+        isEqual && (measuredDimensions[1] == layout.measuredDimensions[1]);
+  }
+
+  return isEqual;
+}
diff --git a/yoga/YGLayout.h b/yoga/YGLayout.h
new file mode 100644
--- /dev/null
+++ b/yoga/YGLayout.h
@@ -0,0 +1,44 @@
+/*
+ *  Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ *  This source code is licensed under the MIT license found in the LICENSE
+ *  file in the root directory of this source tree.
+ *
+ */
+#pragma once
+#include "YGFloatOptional.h"
+#include "Yoga-internal.h"
+
+struct YGLayout {
+  std::array<float, 4> position;
+  std::array<float, 2> dimensions;
+  std::array<float, 6> margin;
+  std::array<float, 6> border;
+  std::array<float, 6> padding;
+  YGDirection direction;
+
+  uint32_t computedFlexBasisGeneration;
+  YGFloatOptional computedFlexBasis;
+  bool hadOverflow;
+
+  // Instead of recomputing the entire layout every single time, we
+  // cache some information to break early when nothing changed
+  uint32_t generationCount;
+  YGDirection lastOwnerDirection;
+
+  uint32_t nextCachedMeasurementsIndex;
+  std::array<YGCachedMeasurement, YG_MAX_CACHED_RESULT_COUNT>
+      cachedMeasurements;
+  std::array<float, 2> measuredDimensions;
+
+  YGCachedMeasurement cachedLayout;
+  bool didUseLegacyFlag;
+  bool doesLegacyStretchFlagAffectsLayout;
+
+  YGLayout();
+
+  bool operator==(YGLayout layout) const;
+  bool operator!=(YGLayout layout) const {
+    return !(*this == layout);
+  }
+};
diff --git a/yoga/YGMacros.h b/yoga/YGMacros.h
--- a/yoga/YGMacros.h
+++ b/yoga/YGMacros.h
@@ -1,47 +1,41 @@
-/**
- * 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.
- */
-
-#pragma once
-
-#ifdef __cplusplus
-#define YG_EXTERN_C_BEGIN extern "C" {
-#define YG_EXTERN_C_END }
-#else
-#define YG_EXTERN_C_BEGIN
-#define YG_EXTERN_C_END
-#endif
-
-#ifdef _WINDLL
-#define WIN_EXPORT __declspec(dllexport)
-#else
-#define WIN_EXPORT
-#endif
-
-#ifdef WINARMDLL
-#define WIN_STRUCT(type) type *
-#define WIN_STRUCT_REF(value) &value
-#else
-#define WIN_STRUCT(type) type
-#define WIN_STRUCT_REF(value) value
-#endif
-
-#ifndef FB_ASSERTIONS_ENABLED
-#define FB_ASSERTIONS_ENABLED 1
-#endif
-
-#ifdef NS_ENUM
-// Cannot use NSInteger as NSInteger has a different size than int (which is the default type of a
-// enum).
-// Therefor when linking the Yoga C library into obj-c the header is a missmatch for the Yoga ABI.
-#define YG_ENUM_BEGIN(name) NS_ENUM(int, name)
-#define YG_ENUM_END(name)
-#else
-#define YG_ENUM_BEGIN(name) enum name
-#define YG_ENUM_END(name) name
-#endif
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+#define YG_EXTERN_C_BEGIN extern "C" {
+#define YG_EXTERN_C_END }
+#else
+#define YG_EXTERN_C_BEGIN
+#define YG_EXTERN_C_END
+#endif
+
+#ifdef _WINDLL
+#define WIN_EXPORT __declspec(dllexport)
+#else
+#define WIN_EXPORT
+#endif
+
+#ifdef WINARMDLL
+#define WIN_STRUCT(type) type *
+#define WIN_STRUCT_REF(value) &value
+#else
+#define WIN_STRUCT(type) type
+#define WIN_STRUCT_REF(value) value
+#endif
+
+#ifdef NS_ENUM
+// Cannot use NSInteger as NSInteger has a different size than int (which is the default type of a
+// enum).
+// Therefor when linking the Yoga C library into obj-c the header is a missmatch for the Yoga ABI.
+#define YG_ENUM_BEGIN(name) NS_ENUM(int, name)
+#define YG_ENUM_END(name)
+#else
+#define YG_ENUM_BEGIN(name) enum name
+#define YG_ENUM_END(name) name
+#endif
diff --git a/yoga/YGNode.cpp b/yoga/YGNode.cpp
new file mode 100644
--- /dev/null
+++ b/yoga/YGNode.cpp
@@ -0,0 +1,554 @@
+/*
+ *  Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ *  This source code is licensed under the MIT license found in the LICENSE
+ *  file in the root directory of this source tree.
+ *
+ */
+#include "YGNode.h"
+#include <iostream>
+#include "Utils.h"
+
+using namespace facebook;
+
+YGFloatOptional YGNode::getLeadingPosition(
+    const YGFlexDirection& axis,
+    const float& axisSize) const {
+  if (YGFlexDirectionIsRow(axis)) {
+    const YGValue* leadingPosition =
+        YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined);
+    if (leadingPosition->unit != YGUnitUndefined) {
+      return YGResolveValue(*leadingPosition, axisSize);
+    }
+  }
+
+  const YGValue* leadingPosition =
+      YGComputedEdgeValue(style_.position, leading[axis], &YGValueUndefined);
+
+  return leadingPosition->unit == YGUnitUndefined
+      ? YGFloatOptional(0)
+      : YGResolveValue(*leadingPosition, axisSize);
+}
+
+YGFloatOptional YGNode::getTrailingPosition(
+    const YGFlexDirection& axis,
+    const float& axisSize) const {
+  if (YGFlexDirectionIsRow(axis)) {
+    const YGValue* trailingPosition =
+        YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined);
+    if (trailingPosition->unit != YGUnitUndefined) {
+      return YGResolveValue(*trailingPosition, axisSize);
+    }
+  }
+
+  const YGValue* trailingPosition =
+      YGComputedEdgeValue(style_.position, trailing[axis], &YGValueUndefined);
+
+  return trailingPosition->unit == YGUnitUndefined
+      ? YGFloatOptional(0)
+      : YGResolveValue(*trailingPosition, axisSize);
+}
+
+bool YGNode::isLeadingPositionDefined(const YGFlexDirection& axis) const {
+  return (YGFlexDirectionIsRow(axis) &&
+          YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined)
+                  ->unit != YGUnitUndefined) ||
+      YGComputedEdgeValue(style_.position, leading[axis], &YGValueUndefined)
+          ->unit != YGUnitUndefined;
+}
+
+bool YGNode::isTrailingPosDefined(const YGFlexDirection& axis) const {
+  return (YGFlexDirectionIsRow(axis) &&
+          YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined)
+                  ->unit != YGUnitUndefined) ||
+      YGComputedEdgeValue(style_.position, trailing[axis], &YGValueUndefined)
+          ->unit != YGUnitUndefined;
+}
+
+YGFloatOptional YGNode::getLeadingMargin(
+    const YGFlexDirection& axis,
+    const float& widthSize) const {
+  if (YGFlexDirectionIsRow(axis) &&
+      style_.margin[YGEdgeStart].unit != YGUnitUndefined) {
+    return YGResolveValueMargin(style_.margin[YGEdgeStart], widthSize);
+  }
+
+  return YGResolveValueMargin(
+      *YGComputedEdgeValue(style_.margin, leading[axis], &YGValueZero),
+      widthSize);
+}
+
+YGFloatOptional YGNode::getTrailingMargin(
+    const YGFlexDirection& axis,
+    const float& widthSize) const {
+  if (YGFlexDirectionIsRow(axis) &&
+      style_.margin[YGEdgeEnd].unit != YGUnitUndefined) {
+    return YGResolveValueMargin(style_.margin[YGEdgeEnd], widthSize);
+  }
+
+  return YGResolveValueMargin(
+      *YGComputedEdgeValue(style_.margin, trailing[axis], &YGValueZero),
+      widthSize);
+}
+
+YGFloatOptional YGNode::getMarginForAxis(
+    const YGFlexDirection& axis,
+    const float& widthSize) const {
+  return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize);
+}
+
+// Setters
+
+void YGNode::setMeasureFunc(YGMeasureFunc measureFunc) {
+  if (measureFunc == nullptr) {
+    measure_ = nullptr;
+    // TODO: t18095186 Move nodeType to opt-in function and mark appropriate
+    // places in Litho
+    nodeType_ = YGNodeTypeDefault;
+  } else {
+    YGAssertWithNode(
+        this,
+        children_.size() == 0,
+        "Cannot set measure function: Nodes with measure functions cannot have children.");
+    measure_ = measureFunc;
+    // TODO: t18095186 Move nodeType to opt-in function and mark appropriate
+    // places in Litho
+    setNodeType(YGNodeTypeText);
+  }
+
+  measure_ = measureFunc;
+}
+
+void YGNode::replaceChild(YGNodeRef child, uint32_t index) {
+  children_[index] = child;
+}
+
+void YGNode::replaceChild(YGNodeRef oldChild, YGNodeRef newChild) {
+  std::replace(children_.begin(), children_.end(), oldChild, newChild);
+}
+
+void YGNode::insertChild(YGNodeRef child, uint32_t index) {
+  children_.insert(children_.begin() + index, child);
+}
+
+void YGNode::setDirty(bool isDirty) {
+  if (isDirty == isDirty_) {
+    return;
+  }
+  isDirty_ = isDirty;
+  if (isDirty && dirtied_) {
+    dirtied_(this);
+  }
+}
+
+bool YGNode::removeChild(YGNodeRef child) {
+  std::vector<YGNodeRef>::iterator p =
+      std::find(children_.begin(), children_.end(), child);
+  if (p != children_.end()) {
+    children_.erase(p);
+    return true;
+  }
+  return false;
+}
+
+void YGNode::removeChild(uint32_t index) {
+  children_.erase(children_.begin() + index);
+}
+
+void YGNode::setLayoutDirection(YGDirection direction) {
+  layout_.direction = direction;
+}
+
+void YGNode::setLayoutMargin(float margin, int index) {
+  layout_.margin[index] = margin;
+}
+
+void YGNode::setLayoutBorder(float border, int index) {
+  layout_.border[index] = border;
+}
+
+void YGNode::setLayoutPadding(float padding, int index) {
+  layout_.padding[index] = padding;
+}
+
+void YGNode::setLayoutLastOwnerDirection(YGDirection direction) {
+  layout_.lastOwnerDirection = direction;
+}
+
+void YGNode::setLayoutComputedFlexBasis(
+    const YGFloatOptional& computedFlexBasis) {
+  layout_.computedFlexBasis = computedFlexBasis;
+}
+
+void YGNode::setLayoutPosition(float position, int index) {
+  layout_.position[index] = position;
+}
+
+void YGNode::setLayoutComputedFlexBasisGeneration(
+    uint32_t computedFlexBasisGeneration) {
+  layout_.computedFlexBasisGeneration = computedFlexBasisGeneration;
+}
+
+void YGNode::setLayoutMeasuredDimension(float measuredDimension, int index) {
+  layout_.measuredDimensions[index] = measuredDimension;
+}
+
+void YGNode::setLayoutHadOverflow(bool hadOverflow) {
+  layout_.hadOverflow = hadOverflow;
+}
+
+void YGNode::setLayoutDimension(float dimension, int index) {
+  layout_.dimensions[index] = dimension;
+}
+
+// If both left and right are defined, then use left. Otherwise return
+// +left or -right depending on which is defined.
+YGFloatOptional YGNode::relativePosition(
+    const YGFlexDirection& axis,
+    const float& axisSize) const {
+  if (isLeadingPositionDefined(axis)) {
+    return getLeadingPosition(axis, axisSize);
+  }
+
+  YGFloatOptional trailingPosition = getTrailingPosition(axis, axisSize);
+  if (!trailingPosition.isUndefined()) {
+    trailingPosition.setValue(-1 * trailingPosition.getValue());
+  }
+  return trailingPosition;
+}
+
+void YGNode::setPosition(
+    const YGDirection direction,
+    const float mainSize,
+    const float crossSize,
+    const float ownerWidth) {
+  /* Root nodes should be always layouted as LTR, so we don't return negative
+   * values. */
+  const YGDirection directionRespectingRoot =
+      owner_ != nullptr ? direction : YGDirectionLTR;
+  const YGFlexDirection mainAxis =
+      YGResolveFlexDirection(style_.flexDirection, directionRespectingRoot);
+  const YGFlexDirection crossAxis =
+      YGFlexDirectionCross(mainAxis, directionRespectingRoot);
+
+  const YGFloatOptional relativePositionMain =
+      relativePosition(mainAxis, mainSize);
+  const YGFloatOptional relativePositionCross =
+      relativePosition(crossAxis, crossSize);
+
+  setLayoutPosition(
+      YGUnwrapFloatOptional(
+          getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain),
+      leading[mainAxis]);
+  setLayoutPosition(
+      YGUnwrapFloatOptional(
+          getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain),
+      trailing[mainAxis]);
+  setLayoutPosition(
+      YGUnwrapFloatOptional(
+          getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross),
+      leading[crossAxis]);
+  setLayoutPosition(
+      YGUnwrapFloatOptional(
+          getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross),
+      trailing[crossAxis]);
+}
+
+YGNode& YGNode::operator=(const YGNode& node) {
+  if (&node == this) {
+    return *this;
+  }
+
+  for (auto child : children_) {
+    delete child;
+  }
+
+  context_ = node.getContext();
+  print_ = node.getPrintFunc();
+  hasNewLayout_ = node.getHasNewLayout();
+  nodeType_ = node.getNodeType();
+  measure_ = node.getMeasure();
+  baseline_ = node.getBaseline();
+  dirtied_ = node.getDirtied();
+  style_ = node.style_;
+  layout_ = node.layout_;
+  lineIndex_ = node.getLineIndex();
+  owner_ = node.getOwner();
+  children_ = node.getChildren();
+  config_ = node.getConfig();
+  isDirty_ = node.isDirty();
+  resolvedDimensions_ = node.getResolvedDimensions();
+
+  return *this;
+}
+
+YGValue YGNode::marginLeadingValue(const YGFlexDirection axis) const {
+  if (YGFlexDirectionIsRow(axis) &&
+      style_.margin[YGEdgeStart].unit != YGUnitUndefined) {
+    return style_.margin[YGEdgeStart];
+  } else {
+    return style_.margin[leading[axis]];
+  }
+}
+
+YGValue YGNode::marginTrailingValue(const YGFlexDirection axis) const {
+  if (YGFlexDirectionIsRow(axis) &&
+      style_.margin[YGEdgeEnd].unit != YGUnitUndefined) {
+    return style_.margin[YGEdgeEnd];
+  } else {
+    return style_.margin[trailing[axis]];
+  }
+}
+
+YGValue YGNode::resolveFlexBasisPtr() const {
+  YGValue flexBasis = style_.flexBasis;
+  if (flexBasis.unit != YGUnitAuto && flexBasis.unit != YGUnitUndefined) {
+    return flexBasis;
+  }
+  if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
+    return config_->useWebDefaults ? YGValueAuto : YGValueZero;
+  }
+  return YGValueAuto;
+}
+
+void YGNode::resolveDimension() {
+  for (uint32_t dim = YGDimensionWidth; dim < YGDimensionCount; dim++) {
+    if (getStyle().maxDimensions[dim].unit != YGUnitUndefined &&
+        YGValueEqual(
+            getStyle().maxDimensions[dim], style_.minDimensions[dim])) {
+      resolvedDimensions_[dim] = style_.maxDimensions[dim];
+    } else {
+      resolvedDimensions_[dim] = style_.dimensions[dim];
+    }
+  }
+}
+
+YGDirection YGNode::resolveDirection(const YGDirection ownerDirection) {
+  if (style_.direction == YGDirectionInherit) {
+    return ownerDirection > YGDirectionInherit ? ownerDirection
+                                               : YGDirectionLTR;
+  } else {
+    return style_.direction;
+  }
+}
+
+void YGNode::clearChildren() {
+  children_.clear();
+  children_.shrink_to_fit();
+}
+
+// Other Methods
+
+void YGNode::cloneChildrenIfNeeded() {
+  // YGNodeRemoveChild in yoga.cpp has a forked variant of this algorithm
+  // optimized for deletions.
+
+  const uint32_t childCount = static_cast<uint32_t>(children_.size());
+  if (childCount == 0) {
+    // This is an empty set. Nothing to clone.
+    return;
+  }
+
+  const YGNodeRef firstChild = children_.front();
+  if (firstChild->getOwner() == this) {
+    // If the first child has this node as its owner, we assume that it is
+    // already unique. We can do this because if we have it has a child, that
+    // means that its owner was at some point cloned which made that subtree
+    // immutable. We also assume that all its sibling are cloned as well.
+    return;
+  }
+
+  const YGCloneNodeFunc cloneNodeCallback = config_->cloneNodeCallback;
+  for (uint32_t i = 0; i < childCount; ++i) {
+    const YGNodeRef oldChild = children_[i];
+    YGNodeRef newChild = nullptr;
+    if (cloneNodeCallback) {
+      newChild = cloneNodeCallback(oldChild, this, i);
+    }
+    if (newChild == nullptr) {
+      newChild = YGNodeClone(oldChild);
+    }
+    replaceChild(newChild, i);
+    newChild->setOwner(this);
+  }
+}
+
+void YGNode::markDirtyAndPropogate() {
+  if (!isDirty_) {
+    setDirty(true);
+    setLayoutComputedFlexBasis(YGFloatOptional());
+    if (owner_) {
+      owner_->markDirtyAndPropogate();
+    }
+  }
+}
+
+void YGNode::markDirtyAndPropogateDownwards() {
+  isDirty_ = true;
+  for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) {
+    childNode->markDirtyAndPropogateDownwards();
+  });
+}
+
+float YGNode::resolveFlexGrow() {
+  // Root nodes flexGrow should always be 0
+  if (owner_ == nullptr) {
+    return 0.0;
+  }
+  if (!style_.flexGrow.isUndefined()) {
+    return style_.flexGrow.getValue();
+  }
+  if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
+    return style_.flex.getValue();
+  }
+  return kDefaultFlexGrow;
+}
+
+float YGNode::resolveFlexShrink() {
+  if (owner_ == nullptr) {
+    return 0.0;
+  }
+  if (!style_.flexShrink.isUndefined()) {
+    return style_.flexShrink.getValue();
+  }
+  if (!config_->useWebDefaults && !style_.flex.isUndefined() &&
+      style_.flex.getValue() < 0.0f) {
+    return -style_.flex.getValue();
+  }
+  return config_->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink;
+}
+
+bool YGNode::isNodeFlexible() {
+  return (
+      (style_.positionType == YGPositionTypeRelative) &&
+      (resolveFlexGrow() != 0 || resolveFlexShrink() != 0));
+}
+
+float YGNode::getLeadingBorder(const YGFlexDirection& axis) const {
+  if (YGFlexDirectionIsRow(axis) &&
+      style_.border[YGEdgeStart].unit != YGUnitUndefined &&
+      !yoga::isUndefined(style_.border[YGEdgeStart].value) &&
+      style_.border[YGEdgeStart].value >= 0.0f) {
+    return style_.border[YGEdgeStart].value;
+  }
+
+  float computedEdgeValue =
+      YGComputedEdgeValue(style_.border, leading[axis], &YGValueZero)->value;
+  return YGFloatMax(computedEdgeValue, 0.0f);
+}
+
+float YGNode::getTrailingBorder(const YGFlexDirection& flexDirection) const {
+  if (YGFlexDirectionIsRow(flexDirection) &&
+      style_.border[YGEdgeEnd].unit != YGUnitUndefined &&
+      !yoga::isUndefined(style_.border[YGEdgeEnd].value) &&
+      style_.border[YGEdgeEnd].value >= 0.0f) {
+    return style_.border[YGEdgeEnd].value;
+  }
+
+  float computedEdgeValue =
+      YGComputedEdgeValue(style_.border, trailing[flexDirection], &YGValueZero)
+          ->value;
+  return YGFloatMax(computedEdgeValue, 0.0f);
+}
+
+YGFloatOptional YGNode::getLeadingPadding(
+    const YGFlexDirection& axis,
+    const float& widthSize) const {
+  const YGFloatOptional& paddingEdgeStart =
+      YGResolveValue(style_.padding[YGEdgeStart], widthSize);
+  if (YGFlexDirectionIsRow(axis) &&
+      style_.padding[YGEdgeStart].unit != YGUnitUndefined &&
+      !paddingEdgeStart.isUndefined() && paddingEdgeStart.getValue() > 0.0f) {
+    return paddingEdgeStart;
+  }
+
+  YGFloatOptional resolvedValue = YGResolveValue(
+      *YGComputedEdgeValue(style_.padding, leading[axis], &YGValueZero),
+      widthSize);
+  return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
+}
+
+YGFloatOptional YGNode::getTrailingPadding(
+    const YGFlexDirection& axis,
+    const float& widthSize) const {
+  if (YGFlexDirectionIsRow(axis) &&
+      style_.padding[YGEdgeEnd].unit != YGUnitUndefined &&
+      !YGResolveValue(style_.padding[YGEdgeEnd], widthSize).isUndefined() &&
+      YGResolveValue(style_.padding[YGEdgeEnd], widthSize).getValue() >= 0.0f) {
+    return YGResolveValue(style_.padding[YGEdgeEnd], widthSize);
+  }
+
+  YGFloatOptional resolvedValue = YGResolveValue(
+      *YGComputedEdgeValue(style_.padding, trailing[axis], &YGValueZero),
+      widthSize);
+
+  return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
+}
+
+YGFloatOptional YGNode::getLeadingPaddingAndBorder(
+    const YGFlexDirection& axis,
+    const float& widthSize) const {
+  return getLeadingPadding(axis, widthSize) +
+      YGFloatOptional(getLeadingBorder(axis));
+}
+
+YGFloatOptional YGNode::getTrailingPaddingAndBorder(
+    const YGFlexDirection& axis,
+    const float& widthSize) const {
+  return getTrailingPadding(axis, widthSize) +
+      YGFloatOptional(getTrailingBorder(axis));
+}
+
+bool YGNode::didUseLegacyFlag() {
+  bool didUseLegacyFlag = layout_.didUseLegacyFlag;
+  if (didUseLegacyFlag) {
+    return true;
+  }
+  for (const auto& child : children_) {
+    if (child->layout_.didUseLegacyFlag) {
+      didUseLegacyFlag = true;
+      break;
+    }
+  }
+  return didUseLegacyFlag;
+}
+
+void YGNode::setAndPropogateUseLegacyFlag(bool useLegacyFlag) {
+  config_->useLegacyStretchBehaviour = useLegacyFlag;
+  for_each(children_.begin(), children_.end(), [=](YGNodeRef childNode) {
+    childNode->getConfig()->useLegacyStretchBehaviour = useLegacyFlag;
+  });
+}
+
+void YGNode::setLayoutDoesLegacyFlagAffectsLayout(
+    bool doesLegacyFlagAffectsLayout) {
+  layout_.doesLegacyStretchFlagAffectsLayout = doesLegacyFlagAffectsLayout;
+}
+
+void YGNode::setLayoutDidUseLegacyFlag(bool didUseLegacyFlag) {
+  layout_.didUseLegacyFlag = didUseLegacyFlag;
+}
+
+bool YGNode::isLayoutTreeEqualToNode(const YGNode& node) const {
+  if (children_.size() != node.children_.size()) {
+    return false;
+  }
+  if (layout_ != node.layout_) {
+    return false;
+  }
+  if (children_.size() == 0) {
+    return true;
+  }
+
+  bool isLayoutTreeEqual = true;
+  YGNodeRef otherNodeChildren = nullptr;
+  for (std::vector<YGNodeRef>::size_type i = 0; i < children_.size(); ++i) {
+    otherNodeChildren = node.children_[i];
+    isLayoutTreeEqual =
+        children_[i]->isLayoutTreeEqualToNode(*otherNodeChildren);
+    if (!isLayoutTreeEqual) {
+      return false;
+    }
+  }
+  return isLayoutTreeEqual;
+}
diff --git a/yoga/YGNode.h b/yoga/YGNode.h
new file mode 100644
--- /dev/null
+++ b/yoga/YGNode.h
@@ -0,0 +1,273 @@
+/*
+ *  Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ *  This source code is licensed under the MIT license found in the LICENSE
+ *  file in the root directory of this source tree.
+ *
+ */
+#pragma once
+#include <stdio.h>
+#include "YGConfig.h"
+#include "YGLayout.h"
+#include "YGStyle.h"
+#include "Yoga-internal.h"
+
+struct YGNode {
+ private:
+  void* context_ = nullptr;
+  YGPrintFunc print_ = nullptr;
+  bool hasNewLayout_ = true;
+  YGNodeType nodeType_ = YGNodeTypeDefault;
+  YGMeasureFunc measure_ = nullptr;
+  YGBaselineFunc baseline_ = nullptr;
+  YGDirtiedFunc dirtied_ = nullptr;
+  YGStyle style_ = {};
+  YGLayout layout_ = {};
+  uint32_t lineIndex_ = 0;
+  YGNodeRef owner_ = nullptr;
+  YGVector children_ = {};
+  YGConfigRef config_ = nullptr;
+  bool isDirty_ = false;
+  std::array<YGValue, 2> resolvedDimensions_ = {
+      {YGValueUndefined, YGValueUndefined}};
+
+  YGFloatOptional relativePosition(
+      const YGFlexDirection& axis,
+      const float& axisSize) const;
+
+ public:
+  YGNode() = default;
+  ~YGNode() = default; // cleanup of owner/children relationships in YGNodeFree
+  explicit YGNode(const YGConfigRef newConfig) : config_(newConfig){};
+  YGNode(const YGNode& node) = default;
+  YGNode& operator=(const YGNode& node);
+
+  // Getters
+  void* getContext() const {
+    return context_;
+  }
+
+  YGPrintFunc getPrintFunc() const {
+    return print_;
+  }
+
+  bool getHasNewLayout() const {
+    return hasNewLayout_;
+  }
+
+  YGNodeType getNodeType() const {
+    return nodeType_;
+  }
+
+  YGMeasureFunc getMeasure() const {
+    return measure_;
+  }
+
+  YGBaselineFunc getBaseline() const {
+    return baseline_;
+  }
+
+  YGDirtiedFunc getDirtied() const {
+    return dirtied_;
+  }
+
+  // For Performance reasons passing as reference.
+  YGStyle& getStyle() {
+    return style_;
+  }
+
+  const YGStyle& getStyle() const {
+    return style_;
+  }
+
+  // For Performance reasons passing as reference.
+  YGLayout& getLayout() {
+    return layout_;
+  }
+
+  const YGLayout& getLayout() const {
+    return layout_;
+  }
+
+  uint32_t getLineIndex() const {
+    return lineIndex_;
+  }
+
+  // returns the YGNodeRef that owns this YGNode. An owner is used to identify
+  // the YogaTree that a YGNode belongs to.
+  // This method will return the parent of the YGNode when a YGNode only belongs
+  // to one YogaTree or nullptr when the YGNode is shared between two or more
+  // YogaTrees.
+  YGNodeRef getOwner() const {
+    return owner_;
+  }
+
+  // Deprecated, use getOwner() instead.
+  YGNodeRef getParent() const {
+    return getOwner();
+  }
+
+  const YGVector& getChildren() const {
+    return children_;
+  }
+
+  YGNodeRef getChild(uint32_t index) const {
+    return children_.at(index);
+  }
+
+  YGConfigRef getConfig() const {
+    return config_;
+  }
+
+  bool isDirty() const {
+    return isDirty_;
+  }
+
+  std::array<YGValue, 2> getResolvedDimensions() const {
+    return resolvedDimensions_;
+  }
+
+  YGValue getResolvedDimension(int index) const {
+    return resolvedDimensions_[index];
+  }
+
+  // Methods related to positions, margin, padding and border
+  YGFloatOptional getLeadingPosition(
+      const YGFlexDirection& axis,
+      const float& axisSize) const;
+  bool isLeadingPositionDefined(const YGFlexDirection& axis) const;
+  bool isTrailingPosDefined(const YGFlexDirection& axis) const;
+  YGFloatOptional getTrailingPosition(
+      const YGFlexDirection& axis,
+      const float& axisSize) const;
+  YGFloatOptional getLeadingMargin(
+      const YGFlexDirection& axis,
+      const float& widthSize) const;
+  YGFloatOptional getTrailingMargin(
+      const YGFlexDirection& axis,
+      const float& widthSize) const;
+  float getLeadingBorder(const YGFlexDirection& flexDirection) const;
+  float getTrailingBorder(const YGFlexDirection& flexDirection) const;
+  YGFloatOptional getLeadingPadding(
+      const YGFlexDirection& axis,
+      const float& widthSize) const;
+  YGFloatOptional getTrailingPadding(
+      const YGFlexDirection& axis,
+      const float& widthSize) const;
+  YGFloatOptional getLeadingPaddingAndBorder(
+      const YGFlexDirection& axis,
+      const float& widthSize) const;
+  YGFloatOptional getTrailingPaddingAndBorder(
+      const YGFlexDirection& axis,
+      const float& widthSize) const;
+  YGFloatOptional getMarginForAxis(
+      const YGFlexDirection& axis,
+      const float& widthSize) const;
+  // Setters
+
+  void setContext(void* context) {
+    context_ = context;
+  }
+
+  void setPrintFunc(YGPrintFunc printFunc) {
+    print_ = printFunc;
+  }
+
+  void setHasNewLayout(bool hasNewLayout) {
+    hasNewLayout_ = hasNewLayout;
+  }
+
+  void setNodeType(YGNodeType nodeType) {
+    nodeType_ = nodeType;
+  }
+
+  void setStyleFlexDirection(YGFlexDirection direction) {
+    style_.flexDirection = direction;
+  }
+
+  void setStyleAlignContent(YGAlign alignContent) {
+    style_.alignContent = alignContent;
+  }
+
+  void setMeasureFunc(YGMeasureFunc measureFunc);
+
+  void setBaseLineFunc(YGBaselineFunc baseLineFunc) {
+    baseline_ = baseLineFunc;
+  }
+
+  void setDirtiedFunc(YGDirtiedFunc dirtiedFunc) {
+    dirtied_ = dirtiedFunc;
+  }
+
+  void setStyle(const YGStyle& style) {
+    style_ = style;
+  }
+
+  void setLayout(const YGLayout& layout) {
+    layout_ = layout;
+  }
+
+  void setLineIndex(uint32_t lineIndex) {
+    lineIndex_ = lineIndex;
+  }
+
+  void setOwner(YGNodeRef owner) {
+    owner_ = owner;
+  }
+
+  void setChildren(const YGVector& children) {
+    children_ = children;
+  }
+
+  // TODO: rvalue override for setChildren
+
+  void setConfig(YGConfigRef config) {
+    config_ = config;
+  }
+
+  void setDirty(bool isDirty);
+  void setLayoutLastOwnerDirection(YGDirection direction);
+  void setLayoutComputedFlexBasis(const YGFloatOptional& computedFlexBasis);
+  void setLayoutComputedFlexBasisGeneration(
+      uint32_t computedFlexBasisGeneration);
+  void setLayoutMeasuredDimension(float measuredDimension, int index);
+  void setLayoutHadOverflow(bool hadOverflow);
+  void setLayoutDimension(float dimension, int index);
+  void setLayoutDirection(YGDirection direction);
+  void setLayoutMargin(float margin, int index);
+  void setLayoutBorder(float border, int index);
+  void setLayoutPadding(float padding, int index);
+  void setLayoutPosition(float position, int index);
+  void setPosition(
+      const YGDirection direction,
+      const float mainSize,
+      const float crossSize,
+      const float ownerWidth);
+  void setAndPropogateUseLegacyFlag(bool useLegacyFlag);
+  void setLayoutDoesLegacyFlagAffectsLayout(bool doesLegacyFlagAffectsLayout);
+  void setLayoutDidUseLegacyFlag(bool didUseLegacyFlag);
+  void markDirtyAndPropogateDownwards();
+
+  // Other methods
+  YGValue marginLeadingValue(const YGFlexDirection axis) const;
+  YGValue marginTrailingValue(const YGFlexDirection axis) const;
+  YGValue resolveFlexBasisPtr() const;
+  void resolveDimension();
+  YGDirection resolveDirection(const YGDirection ownerDirection);
+  void clearChildren();
+  /// Replaces the occurrences of oldChild with newChild
+  void replaceChild(YGNodeRef oldChild, YGNodeRef newChild);
+  void replaceChild(YGNodeRef child, uint32_t index);
+  void insertChild(YGNodeRef child, uint32_t index);
+  /// Removes the first occurrence of child
+  bool removeChild(YGNodeRef child);
+  void removeChild(uint32_t index);
+
+  void cloneChildrenIfNeeded();
+  void markDirtyAndPropogate();
+  float resolveFlexGrow();
+  float resolveFlexShrink();
+  bool isNodeFlexible();
+  bool didUseLegacyFlag();
+  bool isLayoutTreeEqualToNode(const YGNode& node) const;
+};
diff --git a/yoga/YGNodePrint.cpp b/yoga/YGNodePrint.cpp
--- a/yoga/YGNodePrint.cpp
+++ b/yoga/YGNodePrint.cpp
@@ -1,220 +1,231 @@
-/*
- * Copyright (c) 2017-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.
- */
-
-#include "YGNodePrint.h"
-#include <stdarg.h>
-#include "YGEnums.h"
-#include "Yoga-internal.h"
-
-namespace facebook {
-namespace yoga {
-typedef std::string string;
-
-static void indent(string* base, uint32_t level) {
-  for (uint32_t i = 0; i < level; ++i) {
-    base->append("  ");
-  }
-}
-
-static bool areFourValuesEqual(const YGValue four[4]) {
-  return YGValueEqual(four[0], four[1]) && YGValueEqual(four[0], four[2]) &&
-      YGValueEqual(four[0], four[3]);
-}
-
-static void appendFormatedString(string* str, const char* fmt, ...) {
-  char buffer[1024];
-  va_list args;
-  va_start(args, fmt);
-  va_list argsCopy;
-  va_copy(argsCopy, args);
-  va_end(args);
-  vsnprintf(buffer, 1024, fmt, argsCopy);
-  va_end(argsCopy);
-  string result = string(buffer);
-  str->append(result);
-}
-
-static void
-appendFloatIfNotUndefined(string* base, const string key, const float num) {
-  if (!YGFloatIsUndefined(num)) {
-    appendFormatedString(base, "%s: %g; ", key.c_str(), num);
-  }
-}
-
-static void appendNumberIfNotUndefined(
-    string* base,
-    const string key,
-    const YGValue* const number) {
-  if (number->unit != YGUnitUndefined) {
-    if (number->unit == YGUnitAuto) {
-      base->append(key + ": auto; ");
-    } else {
-      string unit = number->unit == YGUnitPoint ? "px" : "%%";
-      appendFormatedString(
-          base, "%s: %g%s; ", key.c_str(), number->value, unit.c_str());
-    }
-  }
-}
-
-static void appendNumberIfNotAuto(
-    string* base,
-    const string key,
-    const YGValue* const number) {
-  if (number->unit != YGUnitAuto) {
-    appendNumberIfNotUndefined(base, key, number);
-  }
-}
-
-static void appendNumberIfNotZero(
-    string* base,
-    const string str,
-    const YGValue* const number) {
-  if (!YGFloatsEqual(number->value, 0)) {
-    appendNumberIfNotUndefined(base, str, number);
-  }
-}
-
-static void appendEdges(string* base, const string key, const YGValue* edges) {
-  if (areFourValuesEqual(edges)) {
-    appendNumberIfNotZero(base, key, &edges[YGEdgeLeft]);
-  } else {
-    for (int edge = YGEdgeLeft; edge != YGEdgeAll; ++edge) {
-      string str = key + "-" + YGEdgeToString(static_cast<YGEdge>(edge));
-      appendNumberIfNotZero(base, str, &edges[edge]);
-    }
-  }
-}
-
-static void appendEdgeIfNotUndefined(
-    string* base,
-    const string str,
-    const YGValue* edges,
-    const YGEdge edge) {
-  appendNumberIfNotUndefined(
-      base, str, YGComputedEdgeValue(edges, edge, &YGValueUndefined));
-}
-
-void YGNodeToString(
-    std::string* str,
-    YGNodeRef node,
-    YGPrintOptions options,
-    uint32_t level) {
-  indent(str, level);
-  appendFormatedString(str, "<div ");
-  if (node->print != nullptr) {
-    node->print(node);
-  }
-
-  if (options & YGPrintOptionsLayout) {
-    appendFormatedString(str, "layout=\"");
-    appendFormatedString(
-        str, "width: %g; ", node->layout.dimensions[YGDimensionWidth]);
-    appendFormatedString(
-        str, "height: %g; ", node->layout.dimensions[YGDimensionHeight]);
-    appendFormatedString(str, "top: %g; ", node->layout.position[YGEdgeTop]);
-    appendFormatedString(str, "left: %g;", node->layout.position[YGEdgeLeft]);
-    appendFormatedString(str, "\" ");
-  }
-
-  if (options & YGPrintOptionsStyle) {
-    appendFormatedString(str, "style=\"");
-    if (node->style.flexDirection != gYGNodeDefaults.style.flexDirection) {
-      appendFormatedString(
-          str,
-          "flex-direction: %s; ",
-          YGFlexDirectionToString(node->style.flexDirection));
-    }
-    if (node->style.justifyContent != gYGNodeDefaults.style.justifyContent) {
-      appendFormatedString(
-          str,
-          "justify-content: %s; ",
-          YGJustifyToString(node->style.justifyContent));
-    }
-    if (node->style.alignItems != gYGNodeDefaults.style.alignItems) {
-      appendFormatedString(
-          str, "align-items: %s; ", YGAlignToString(node->style.alignItems));
-    }
-    if (node->style.alignContent != gYGNodeDefaults.style.alignContent) {
-      appendFormatedString(
-          str,
-          "align-content: %s; ",
-          YGAlignToString(node->style.alignContent));
-    }
-    if (node->style.alignSelf != gYGNodeDefaults.style.alignSelf) {
-      appendFormatedString(
-          str, "align-self: %s; ", YGAlignToString(node->style.alignSelf));
-    }
-    appendFloatIfNotUndefined(str, "flex-grow", node->style.flexGrow);
-    appendFloatIfNotUndefined(str, "flex-shrink", node->style.flexShrink);
-    appendNumberIfNotAuto(str, "flex-basis", &node->style.flexBasis);
-    appendFloatIfNotUndefined(str, "flex", node->style.flex);
-
-    if (node->style.flexWrap != gYGNodeDefaults.style.flexWrap) {
-      appendFormatedString(
-          str, "flexWrap: %s; ", YGWrapToString(node->style.flexWrap));
-    }
-
-    if (node->style.overflow != gYGNodeDefaults.style.overflow) {
-      appendFormatedString(
-          str, "overflow: %s; ", YGOverflowToString(node->style.overflow));
-    }
-
-    if (node->style.display != gYGNodeDefaults.style.display) {
-      appendFormatedString(
-          str, "display: %s; ", YGDisplayToString(node->style.display));
-    }
-    appendEdges(str, "margin", node->style.margin);
-    appendEdges(str, "padding", node->style.padding);
-    appendEdges(str, "border", node->style.border);
-
-    appendNumberIfNotAuto(
-        str, "width", &node->style.dimensions[YGDimensionWidth]);
-    appendNumberIfNotAuto(
-        str, "height", &node->style.dimensions[YGDimensionHeight]);
-    appendNumberIfNotAuto(
-        str, "max-width", &node->style.maxDimensions[YGDimensionWidth]);
-    appendNumberIfNotAuto(
-        str, "max-height", &node->style.maxDimensions[YGDimensionHeight]);
-    appendNumberIfNotAuto(
-        str, "min-width", &node->style.minDimensions[YGDimensionWidth]);
-    appendNumberIfNotAuto(
-        str, "min-height", &node->style.minDimensions[YGDimensionHeight]);
-
-    if (node->style.positionType != gYGNodeDefaults.style.positionType) {
-      appendFormatedString(
-          str,
-          "position: %s; ",
-          YGPositionTypeToString(node->style.positionType));
-    }
-
-    appendEdgeIfNotUndefined(str, "left", node->style.position, YGEdgeLeft);
-    appendEdgeIfNotUndefined(str, "right", node->style.position, YGEdgeRight);
-    appendEdgeIfNotUndefined(str, "top", node->style.position, YGEdgeTop);
-    appendEdgeIfNotUndefined(str, "bottom", node->style.position, YGEdgeBottom);
-    appendFormatedString(str, "\" ");
-
-    if (node->measure != nullptr) {
-      appendFormatedString(str, "has-custom-measure=\"true\"");
-    }
-  }
-  appendFormatedString(str, ">");
-
-  const uint32_t childCount = node->children.size();
-  if (options & YGPrintOptionsChildren && childCount > 0) {
-    for (uint32_t i = 0; i < childCount; i++) {
-      appendFormatedString(str, "\n");
-      YGNodeToString(str, YGNodeGetChild(node, i), options, level + 1);
-    }
-    appendFormatedString(str, "\n");
-    indent(str, level);
-  }
-  appendFormatedString(str, "</div>");
-}
-} // namespace yoga
-} // namespace facebook
+/*
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include "YGNodePrint.h"
+#include <stdarg.h>
+#include "YGEnums.h"
+#include "YGNode.h"
+#include "Yoga-internal.h"
+
+namespace facebook {
+namespace yoga {
+typedef std::string string;
+
+static void indent(string* base, uint32_t level) {
+  for (uint32_t i = 0; i < level; ++i) {
+    base->append("  ");
+  }
+}
+
+static bool areFourValuesEqual(const std::array<YGValue, YGEdgeCount>& four) {
+  return YGValueEqual(four[0], four[1]) && YGValueEqual(four[0], four[2]) &&
+      YGValueEqual(four[0], four[3]);
+}
+
+static void appendFormatedString(string* str, const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  va_list argsCopy;
+  va_copy(argsCopy, args);
+  std::vector<char> buf(1 + vsnprintf(NULL, 0, fmt, args));
+  va_end(args);
+  vsnprintf(buf.data(), buf.size(), fmt, argsCopy);
+  va_end(argsCopy);
+  string result = string(buf.begin(), buf.end() - 1);
+  str->append(result);
+}
+
+static void appendFloatOptionalIfDefined(
+    string* base,
+    const string key,
+    const YGFloatOptional num) {
+  if (!num.isUndefined()) {
+    appendFormatedString(base, "%s: %g; ", key.c_str(), num.getValue());
+  }
+}
+
+static void appendNumberIfNotUndefined(
+    string* base,
+    const string key,
+    const YGValue number) {
+  if (number.unit != YGUnitUndefined) {
+    if (number.unit == YGUnitAuto) {
+      base->append(key + ": auto; ");
+    } else {
+      string unit = number.unit == YGUnitPoint ? "px" : "%%";
+      appendFormatedString(
+          base, "%s: %g%s; ", key.c_str(), number.value, unit.c_str());
+    }
+  }
+}
+
+static void
+appendNumberIfNotAuto(string* base, const string& key, const YGValue number) {
+  if (number.unit != YGUnitAuto) {
+    appendNumberIfNotUndefined(base, key, number);
+  }
+}
+
+static void
+appendNumberIfNotZero(string* base, const string& str, const YGValue number) {
+
+  if (number.unit == YGUnitAuto) {
+    base->append(str + ": auto; ");
+  } else if (!YGFloatsEqual(number.value, 0)) {
+    appendNumberIfNotUndefined(base, str, number);
+  }
+}
+
+static void appendEdges(
+    string* base,
+    const string& key,
+    const std::array<YGValue, YGEdgeCount>& edges) {
+  if (areFourValuesEqual(edges)) {
+    appendNumberIfNotZero(base, key, edges[YGEdgeLeft]);
+  } else {
+    for (int edge = YGEdgeLeft; edge != YGEdgeAll; ++edge) {
+      string str = key + "-" + YGEdgeToString(static_cast<YGEdge>(edge));
+      appendNumberIfNotZero(base, str, edges[edge]);
+    }
+  }
+}
+
+static void appendEdgeIfNotUndefined(
+    string* base,
+    const string& str,
+    const std::array<YGValue, YGEdgeCount>& edges,
+    const YGEdge edge) {
+  appendNumberIfNotUndefined(
+      base, str, *YGComputedEdgeValue(edges, edge, &YGValueUndefined));
+}
+
+void YGNodeToString(
+    std::string* str,
+    YGNodeRef node,
+    YGPrintOptions options,
+    uint32_t level) {
+  indent(str, level);
+  appendFormatedString(str, "<div ");
+  if (node->getPrintFunc() != nullptr) {
+    node->getPrintFunc()(node);
+  }
+
+  if (options & YGPrintOptionsLayout) {
+    appendFormatedString(str, "layout=\"");
+    appendFormatedString(
+        str, "width: %g; ", node->getLayout().dimensions[YGDimensionWidth]);
+    appendFormatedString(
+        str, "height: %g; ", node->getLayout().dimensions[YGDimensionHeight]);
+    appendFormatedString(
+        str, "top: %g; ", node->getLayout().position[YGEdgeTop]);
+    appendFormatedString(
+        str, "left: %g;", node->getLayout().position[YGEdgeLeft]);
+    appendFormatedString(str, "\" ");
+  }
+
+  if (options & YGPrintOptionsStyle) {
+    appendFormatedString(str, "style=\"");
+    if (node->getStyle().flexDirection != YGNode().getStyle().flexDirection) {
+      appendFormatedString(
+          str,
+          "flex-direction: %s; ",
+          YGFlexDirectionToString(node->getStyle().flexDirection));
+    }
+    if (node->getStyle().justifyContent != YGNode().getStyle().justifyContent) {
+      appendFormatedString(
+          str,
+          "justify-content: %s; ",
+          YGJustifyToString(node->getStyle().justifyContent));
+    }
+    if (node->getStyle().alignItems != YGNode().getStyle().alignItems) {
+      appendFormatedString(
+          str,
+          "align-items: %s; ",
+          YGAlignToString(node->getStyle().alignItems));
+    }
+    if (node->getStyle().alignContent != YGNode().getStyle().alignContent) {
+      appendFormatedString(
+          str,
+          "align-content: %s; ",
+          YGAlignToString(node->getStyle().alignContent));
+    }
+    if (node->getStyle().alignSelf != YGNode().getStyle().alignSelf) {
+      appendFormatedString(
+          str, "align-self: %s; ", YGAlignToString(node->getStyle().alignSelf));
+    }
+    appendFloatOptionalIfDefined(str, "flex-grow", node->getStyle().flexGrow);
+    appendFloatOptionalIfDefined(
+        str, "flex-shrink", node->getStyle().flexShrink);
+    appendNumberIfNotAuto(str, "flex-basis", node->getStyle().flexBasis);
+    appendFloatOptionalIfDefined(str, "flex", node->getStyle().flex);
+
+    if (node->getStyle().flexWrap != YGNode().getStyle().flexWrap) {
+      appendFormatedString(
+          str, "flexWrap: %s; ", YGWrapToString(node->getStyle().flexWrap));
+    }
+
+    if (node->getStyle().overflow != YGNode().getStyle().overflow) {
+      appendFormatedString(
+          str, "overflow: %s; ", YGOverflowToString(node->getStyle().overflow));
+    }
+
+    if (node->getStyle().display != YGNode().getStyle().display) {
+      appendFormatedString(
+          str, "display: %s; ", YGDisplayToString(node->getStyle().display));
+    }
+    appendEdges(str, "margin", node->getStyle().margin);
+    appendEdges(str, "padding", node->getStyle().padding);
+    appendEdges(str, "border", node->getStyle().border);
+
+    appendNumberIfNotAuto(
+        str, "width", node->getStyle().dimensions[YGDimensionWidth]);
+    appendNumberIfNotAuto(
+        str, "height", node->getStyle().dimensions[YGDimensionHeight]);
+    appendNumberIfNotAuto(
+        str, "max-width", node->getStyle().maxDimensions[YGDimensionWidth]);
+    appendNumberIfNotAuto(
+        str, "max-height", node->getStyle().maxDimensions[YGDimensionHeight]);
+    appendNumberIfNotAuto(
+        str, "min-width", node->getStyle().minDimensions[YGDimensionWidth]);
+    appendNumberIfNotAuto(
+        str, "min-height", node->getStyle().minDimensions[YGDimensionHeight]);
+
+    if (node->getStyle().positionType != YGNode().getStyle().positionType) {
+      appendFormatedString(
+          str,
+          "position: %s; ",
+          YGPositionTypeToString(node->getStyle().positionType));
+    }
+
+    appendEdgeIfNotUndefined(
+        str, "left", node->getStyle().position, YGEdgeLeft);
+    appendEdgeIfNotUndefined(
+        str, "right", node->getStyle().position, YGEdgeRight);
+    appendEdgeIfNotUndefined(str, "top", node->getStyle().position, YGEdgeTop);
+    appendEdgeIfNotUndefined(
+        str, "bottom", node->getStyle().position, YGEdgeBottom);
+    appendFormatedString(str, "\" ");
+
+    if (node->getMeasure() != nullptr) {
+      appendFormatedString(str, "has-custom-measure=\"true\"");
+    }
+  }
+  appendFormatedString(str, ">");
+
+  const uint32_t childCount = static_cast<uint32_t>(node->getChildren().size());
+  if (options & YGPrintOptionsChildren && childCount > 0) {
+    for (uint32_t i = 0; i < childCount; i++) {
+      appendFormatedString(str, "\n");
+      YGNodeToString(str, YGNodeGetChild(node, i), options, level + 1);
+    }
+    appendFormatedString(str, "\n");
+    indent(str, level);
+  }
+  appendFormatedString(str, "</div>");
+}
+} // namespace yoga
+} // namespace facebook
diff --git a/yoga/YGNodePrint.h b/yoga/YGNodePrint.h
--- a/yoga/YGNodePrint.h
+++ b/yoga/YGNodePrint.h
@@ -1,24 +1,22 @@
-/**
- * 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.
- */
-#pragma once
-#include <string>
-
-#include "Yoga.h"
-
-namespace facebook {
-namespace yoga {
-
-void YGNodeToString(
-    std::string* str,
-    YGNodeRef node,
-    YGPrintOptions options,
-    uint32_t level);
-
-} // namespace yoga
-} // namespace facebook
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+#pragma once
+#include <string>
+
+#include "Yoga.h"
+
+namespace facebook {
+namespace yoga {
+
+void YGNodeToString(
+    std::string* str,
+    YGNodeRef node,
+    YGPrintOptions options,
+    uint32_t level);
+
+} // namespace yoga
+} // namespace facebook
diff --git a/yoga/YGStyle.cpp b/yoga/YGStyle.cpp
new file mode 100644
--- /dev/null
+++ b/yoga/YGStyle.cpp
@@ -0,0 +1,100 @@
+/*
+ *  Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ *  This source code is licensed under the MIT license found in the LICENSE
+ *  file in the root directory of this source tree.
+ *
+ */
+#include "YGStyle.h"
+
+const YGValue kYGValueUndefined = {0, YGUnitUndefined};
+
+const YGValue kYGValueAuto = {0, YGUnitAuto};
+
+const std::array<YGValue, YGEdgeCount> kYGDefaultEdgeValuesUnit = {
+    {kYGValueUndefined,
+     kYGValueUndefined,
+     kYGValueUndefined,
+     kYGValueUndefined,
+     kYGValueUndefined,
+     kYGValueUndefined,
+     kYGValueUndefined,
+     kYGValueUndefined,
+     kYGValueUndefined}};
+
+const std::array<YGValue, 2> kYGDefaultDimensionValuesAutoUnit = {
+    {kYGValueAuto, kYGValueAuto}};
+
+const std::array<YGValue, 2> kYGDefaultDimensionValuesUnit = {
+    {kYGValueUndefined, kYGValueUndefined}};
+
+YGStyle::YGStyle()
+    : direction(YGDirectionInherit),
+      flexDirection(YGFlexDirectionColumn),
+      justifyContent(YGJustifyFlexStart),
+      alignContent(YGAlignFlexStart),
+      alignItems(YGAlignStretch),
+      alignSelf(YGAlignAuto),
+      positionType(YGPositionTypeRelative),
+      flexWrap(YGWrapNoWrap),
+      overflow(YGOverflowVisible),
+      display(YGDisplayFlex),
+      flex(YGFloatOptional()),
+      flexGrow(YGFloatOptional()),
+      flexShrink(YGFloatOptional()),
+      flexBasis(kYGValueAuto),
+      margin(kYGDefaultEdgeValuesUnit),
+      position(kYGDefaultEdgeValuesUnit),
+      padding(kYGDefaultEdgeValuesUnit),
+      border(kYGDefaultEdgeValuesUnit),
+      dimensions(kYGDefaultDimensionValuesAutoUnit),
+      minDimensions(kYGDefaultDimensionValuesUnit),
+      maxDimensions(kYGDefaultDimensionValuesUnit),
+      aspectRatio(YGFloatOptional()) {}
+
+// Yoga specific properties, not compatible with flexbox specification
+bool YGStyle::operator==(const YGStyle& style) {
+  bool areNonFloatValuesEqual = direction == style.direction &&
+      flexDirection == style.flexDirection &&
+      justifyContent == style.justifyContent &&
+      alignContent == style.alignContent && alignItems == style.alignItems &&
+      alignSelf == style.alignSelf && positionType == style.positionType &&
+      flexWrap == style.flexWrap && overflow == style.overflow &&
+      display == style.display && YGValueEqual(flexBasis, style.flexBasis) &&
+      YGValueArrayEqual(margin, style.margin) &&
+      YGValueArrayEqual(position, style.position) &&
+      YGValueArrayEqual(padding, style.padding) &&
+      YGValueArrayEqual(border, style.border) &&
+      YGValueArrayEqual(dimensions, style.dimensions) &&
+      YGValueArrayEqual(minDimensions, style.minDimensions) &&
+      YGValueArrayEqual(maxDimensions, style.maxDimensions);
+
+  areNonFloatValuesEqual =
+      areNonFloatValuesEqual && flex.isUndefined() == style.flex.isUndefined();
+  if (areNonFloatValuesEqual && !flex.isUndefined() &&
+      !style.flex.isUndefined()) {
+    areNonFloatValuesEqual =
+        areNonFloatValuesEqual && flex.getValue() == style.flex.getValue();
+  }
+
+  areNonFloatValuesEqual = areNonFloatValuesEqual &&
+      flexGrow.isUndefined() == style.flexGrow.isUndefined();
+  if (areNonFloatValuesEqual && !flexGrow.isUndefined()) {
+    areNonFloatValuesEqual = areNonFloatValuesEqual &&
+        flexGrow.getValue() == style.flexGrow.getValue();
+  }
+
+  areNonFloatValuesEqual = areNonFloatValuesEqual &&
+      flexShrink.isUndefined() == style.flexShrink.isUndefined();
+  if (areNonFloatValuesEqual && !style.flexShrink.isUndefined()) {
+    areNonFloatValuesEqual = areNonFloatValuesEqual &&
+        flexShrink.getValue() == style.flexShrink.getValue();
+  }
+
+  if (!(aspectRatio.isUndefined() && style.aspectRatio.isUndefined())) {
+    areNonFloatValuesEqual = areNonFloatValuesEqual &&
+        aspectRatio.getValue() == style.aspectRatio.getValue();
+  }
+
+  return areNonFloatValuesEqual;
+}
diff --git a/yoga/Yoga-internal.h b/yoga/Yoga-internal.h
--- a/yoga/Yoga-internal.h
+++ b/yoga/Yoga-internal.h
@@ -1,230 +1,120 @@
-/**
- * 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.
- */
-
-#pragma once
-#include <vector>
-
-#include "Yoga.h"
-
-typedef std::vector<YGNodeRef> YGVector;
-
-YG_EXTERN_C_BEGIN
-
-WIN_EXPORT float YGRoundValueToPixelGrid(const float value,
-                                         const float pointScaleFactor,
-                                         const bool forceCeil,
-                                         const bool forceFloor);
-
-YG_EXTERN_C_END
-
-typedef struct YGCachedMeasurement {
-  float availableWidth;
-  float availableHeight;
-  YGMeasureMode widthMeasureMode;
-  YGMeasureMode heightMeasureMode;
-
-  float computedWidth;
-  float computedHeight;
-} YGCachedMeasurement;
-
-// This value was chosen based on empiracle data. Even the most complicated
-// layouts should not require more than 16 entries to fit within the cache.
-#define YG_MAX_CACHED_RESULT_COUNT 16
-
-typedef struct YGLayout {
-  float position[4];
-  float dimensions[2];
-  float margin[6];
-  float border[6];
-  float padding[6];
-  YGDirection direction;
-
-  uint32_t computedFlexBasisGeneration;
-  float computedFlexBasis;
-  bool hadOverflow;
-
-  // Instead of recomputing the entire layout every single time, we
-  // cache some information to break early when nothing changed
-  uint32_t generationCount;
-  YGDirection lastParentDirection;
-
-  uint32_t nextCachedMeasurementsIndex;
-  YGCachedMeasurement cachedMeasurements[YG_MAX_CACHED_RESULT_COUNT];
-  float measuredDimensions[2];
-
-  YGCachedMeasurement cachedLayout;
-} YGLayout;
-
-typedef struct YGStyle {
-  YGDirection direction;
-  YGFlexDirection flexDirection;
-  YGJustify justifyContent;
-  YGAlign alignContent;
-  YGAlign alignItems;
-  YGAlign alignSelf;
-  YGPositionType positionType;
-  YGWrap flexWrap;
-  YGOverflow overflow;
-  YGDisplay display;
-  float flex;
-  float flexGrow;
-  float flexShrink;
-  YGValue flexBasis;
-  YGValue margin[YGEdgeCount];
-  YGValue position[YGEdgeCount];
-  YGValue padding[YGEdgeCount];
-  YGValue border[YGEdgeCount];
-  YGValue dimensions[2];
-  YGValue minDimensions[2];
-  YGValue maxDimensions[2];
-
-  // Yoga specific properties, not compatible with flexbox specification
-  float aspectRatio;
-} YGStyle;
-
-typedef struct YGConfig {
-  bool experimentalFeatures[YGExperimentalFeatureCount + 1];
-  bool useWebDefaults;
-  bool useLegacyStretchBehaviour;
-  float pointScaleFactor;
-  YGLogger logger;
-  YGNodeClonedFunc cloneNodeCallback;
-  void* context;
-} YGConfig;
-
-typedef struct YGNode {
-  YGStyle style;
-  YGLayout layout;
-  uint32_t lineIndex;
-
-  YGNodeRef parent;
-  YGVector children;
-
-  struct YGNode* nextChild;
-
-  YGMeasureFunc measure;
-  YGBaselineFunc baseline;
-  YGPrintFunc print;
-  YGConfigRef config;
-  void* context;
-
-  bool isDirty;
-  bool hasNewLayout;
-  YGNodeType nodeType;
-
-  YGValue const* resolvedDimensions[2];
-} YGNode;
-
-#define YG_UNDEFINED_VALUES \
-  { .value = YGUndefined, .unit = YGUnitUndefined }
-
-#define YG_AUTO_VALUES \
-  { .value = YGUndefined, .unit = YGUnitAuto }
-
-#define YG_DEFAULT_EDGE_VALUES_UNIT                                            \
-  {                                                                            \
-    [YGEdgeLeft] = YG_UNDEFINED_VALUES, [YGEdgeTop] = YG_UNDEFINED_VALUES,     \
-    [YGEdgeRight] = YG_UNDEFINED_VALUES, [YGEdgeBottom] = YG_UNDEFINED_VALUES, \
-    [YGEdgeStart] = YG_UNDEFINED_VALUES, [YGEdgeEnd] = YG_UNDEFINED_VALUES,    \
-    [YGEdgeHorizontal] = YG_UNDEFINED_VALUES,                                  \
-    [YGEdgeVertical] = YG_UNDEFINED_VALUES, [YGEdgeAll] = YG_UNDEFINED_VALUES, \
-  }
-
-#define YG_DEFAULT_DIMENSION_VALUES \
-  { [YGDimensionWidth] = YGUndefined, [YGDimensionHeight] = YGUndefined, }
-
-#define YG_DEFAULT_DIMENSION_VALUES_UNIT       \
-  {                                            \
-    [YGDimensionWidth] = YG_UNDEFINED_VALUES,  \
-    [YGDimensionHeight] = YG_UNDEFINED_VALUES, \
-  }
-
-#define YG_DEFAULT_DIMENSION_VALUES_AUTO_UNIT \
-  { [YGDimensionWidth] = YG_AUTO_VALUES, [YGDimensionHeight] = YG_AUTO_VALUES, }
-
-static const float kDefaultFlexGrow = 0.0f;
-static const float kDefaultFlexShrink = 0.0f;
-static const float kWebDefaultFlexShrink = 1.0f;
-
-static const YGStyle gYGNodeStyleDefaults = {
-    .direction = YGDirectionInherit,
-    .flexDirection = YGFlexDirectionColumn,
-    .justifyContent = YGJustifyFlexStart,
-    .alignContent = YGAlignFlexStart,
-    .alignItems = YGAlignStretch,
-    .alignSelf = YGAlignAuto,
-    .positionType = YGPositionTypeRelative,
-    .flexWrap = YGWrapNoWrap,
-    .overflow = YGOverflowVisible,
-    .display = YGDisplayFlex,
-    .flex = YGUndefined,
-    .flexGrow = YGUndefined,
-    .flexShrink = YGUndefined,
-    .flexBasis = YG_AUTO_VALUES,
-    .margin = YG_DEFAULT_EDGE_VALUES_UNIT,
-    .position = YG_DEFAULT_EDGE_VALUES_UNIT,
-    .padding = YG_DEFAULT_EDGE_VALUES_UNIT,
-    .border = YG_DEFAULT_EDGE_VALUES_UNIT,
-    .dimensions = YG_DEFAULT_DIMENSION_VALUES_AUTO_UNIT,
-    .minDimensions = YG_DEFAULT_DIMENSION_VALUES_UNIT,
-    .maxDimensions = YG_DEFAULT_DIMENSION_VALUES_UNIT,
-    .aspectRatio = YGUndefined,
-};
-
-static const YGLayout gYGNodeLayoutDefaults = {
-    .position = {},
-    .dimensions = YG_DEFAULT_DIMENSION_VALUES,
-    .margin = {},
-    .border = {},
-    .padding = {},
-    .direction = YGDirectionInherit,
-    .computedFlexBasisGeneration = 0,
-    .computedFlexBasis = YGUndefined,
-    .hadOverflow = false,
-    .generationCount = 0,
-    .lastParentDirection = (YGDirection)-1,
-    .nextCachedMeasurementsIndex = 0,
-    .cachedMeasurements = {},
-    .measuredDimensions = YG_DEFAULT_DIMENSION_VALUES,
-    .cachedLayout =
-        {
-            .availableWidth = 0,
-            .availableHeight = 0,
-            .widthMeasureMode = (YGMeasureMode)-1,
-            .heightMeasureMode = (YGMeasureMode)-1,
-            .computedWidth = -1,
-            .computedHeight = -1,
-        },
-};
-
-static const YGNode gYGNodeDefaults = {
-    .style = gYGNodeStyleDefaults,
-    .layout = gYGNodeLayoutDefaults,
-    .lineIndex = 0,
-    .parent = nullptr,
-    .children = YGVector(),
-    .nextChild = nullptr,
-    .measure = nullptr,
-    .baseline = nullptr,
-    .print = nullptr,
-    .config = nullptr,
-    .context = nullptr,
-    .isDirty = false,
-    .hasNewLayout = true,
-    .nodeType = YGNodeTypeDefault,
-    .resolvedDimensions = {[YGDimensionWidth] = &YGValueUndefined,
-                           [YGDimensionHeight] = &YGValueUndefined},
-};
-
-extern bool YGFloatsEqual(const float a, const float b);
-extern bool YGValueEqual(const YGValue a, const YGValue b);
-extern const YGValue* YGComputedEdgeValue(
-    const YGValue edges[YGEdgeCount],
-    const YGEdge edge,
-    const YGValue* const defaultValue);
+/*
+ *  Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ *  This source code is licensed under the MIT license found in the LICENSE
+ *  file in the root directory of this source tree.
+ *
+ */
+#pragma once
+#include <algorithm>
+#include <array>
+#include <cmath>
+#include <vector>
+#include "Yoga.h"
+
+using YGVector = std::vector<YGNodeRef>;
+
+YG_EXTERN_C_BEGIN
+
+WIN_EXPORT float YGRoundValueToPixelGrid(
+    const float value,
+    const float pointScaleFactor,
+    const bool forceCeil,
+    const bool forceFloor);
+
+YG_EXTERN_C_END
+
+namespace facebook {
+namespace yoga {
+
+inline bool isUndefined(float value) {
+  // Value of a float in the case of it being not defined is 10.1E20. Earlier
+  // it used to be NAN, the benefit of which was that if NAN is involved in any
+  // mathematical expression the result was NAN. But since we want to have
+  // `-ffast-math` flag being used by compiler which assumes that the floating
+  // point values are not NAN and Inf, we represent YGUndefined as 10.1E20. But
+  // now if YGUndefined is involved in any mathematical operations this
+  // value(10.1E20) would change. So the following check makes sure that if the
+  // value is outside a range (-10E8, 10E8) then it is undefined.
+  return value >= 10E8 || value <= -10E8;
+}
+
+} // namespace yoga
+} // namespace facebook
+
+using namespace facebook;
+
+extern const std::array<YGEdge, 4> trailing;
+extern const std::array<YGEdge, 4> leading;
+extern bool YGValueEqual(const YGValue a, const YGValue b);
+extern const YGValue YGValueUndefined;
+extern const YGValue YGValueAuto;
+extern const YGValue YGValueZero;
+
+template <std::size_t size>
+bool YGValueArrayEqual(
+    const std::array<YGValue, size> val1,
+    const std::array<YGValue, size> val2) {
+  bool areEqual = true;
+  for (uint32_t i = 0; i < size && areEqual; ++i) {
+    areEqual = YGValueEqual(val1[i], val2[i]);
+  }
+  return areEqual;
+}
+
+struct YGCachedMeasurement {
+  float availableWidth;
+  float availableHeight;
+  YGMeasureMode widthMeasureMode;
+  YGMeasureMode heightMeasureMode;
+
+  float computedWidth;
+  float computedHeight;
+
+  YGCachedMeasurement()
+      : availableWidth(0),
+        availableHeight(0),
+        widthMeasureMode((YGMeasureMode)-1),
+        heightMeasureMode((YGMeasureMode)-1),
+        computedWidth(-1),
+        computedHeight(-1) {}
+
+  bool operator==(YGCachedMeasurement measurement) const {
+    bool isEqual = widthMeasureMode == measurement.widthMeasureMode &&
+        heightMeasureMode == measurement.heightMeasureMode;
+
+    if (!yoga::isUndefined(availableWidth) ||
+        !yoga::isUndefined(measurement.availableWidth)) {
+      isEqual = isEqual && availableWidth == measurement.availableWidth;
+    }
+    if (!yoga::isUndefined(availableHeight) ||
+        !yoga::isUndefined(measurement.availableHeight)) {
+      isEqual = isEqual && availableHeight == measurement.availableHeight;
+    }
+    if (!yoga::isUndefined(computedWidth) ||
+        !yoga::isUndefined(measurement.computedWidth)) {
+      isEqual = isEqual && computedWidth == measurement.computedWidth;
+    }
+    if (!yoga::isUndefined(computedHeight) ||
+        !yoga::isUndefined(measurement.computedHeight)) {
+      isEqual = isEqual && computedHeight == measurement.computedHeight;
+    }
+
+    return isEqual;
+  }
+};
+
+// This value was chosen based on empiracle data. Even the most complicated
+// layouts should not require more than 16 entries to fit within the cache.
+#define YG_MAX_CACHED_RESULT_COUNT 16
+
+static const float kDefaultFlexGrow = 0.0f;
+static const float kDefaultFlexShrink = 0.0f;
+static const float kWebDefaultFlexShrink = 1.0f;
+
+extern bool YGFloatsEqual(const float a, const float b);
+extern bool YGValueEqual(const YGValue a, const YGValue b);
+extern const YGValue* YGComputedEdgeValue(
+    const std::array<YGValue, YGEdgeCount>& edges,
+    const YGEdge edge,
+    const YGValue* const defaultValue);
diff --git a/yoga/Yoga.cpp b/yoga/Yoga.cpp
--- a/yoga/Yoga.cpp
+++ b/yoga/Yoga.cpp
@@ -1,3533 +1,4316 @@
-/**
- * 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.
- */
-
-#include "Yoga.h"
-#include <string.h>
-#include <algorithm>
-#include "YGNodePrint.h"
-#include "Yoga-internal.h"
-
-#ifdef _MSC_VER
-#include <float.h>
-#ifndef isnan
-#define isnan _isnan
-#endif
-#ifndef __cplusplus
-#define inline __inline
-#endif
-
-/* 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
-
-#ifdef ANDROID
-static int YGAndroidLog(const YGConfigRef config,
-                        const YGNodeRef node,
-                        YGLogLevel level,
-                        const char *format,
-                        va_list args);
-#else
-static int YGDefaultLog(const YGConfigRef config,
-                        const YGNodeRef node,
-                        YGLogLevel level,
-                        const char *format,
-                        va_list args);
-#endif
-
-static YGConfig gYGConfigDefaults = {
-    .experimentalFeatures =
-        {
-            [YGExperimentalFeatureWebFlexBasis] = false,
-        },
-    .useWebDefaults = false,
-    .useLegacyStretchBehaviour = false,
-    .pointScaleFactor = 1.0f,
-#ifdef ANDROID
-    .logger = &YGAndroidLog,
-#else
-    .logger = &YGDefaultLog,
-#endif
-    .cloneNodeCallback = nullptr,
-    .context = nullptr,
-};
-
-static void YGNodeMarkDirtyInternal(const YGNodeRef node);
-
-static YGValue YGValueZero = {.value = 0, .unit = YGUnitPoint};
-
-static bool YGNodeListDelete(YGVector& list, const YGNodeRef node) {
-  std::vector<YGNodeRef>::iterator p =
-      std::find(list.begin(), list.end(), node);
-  if (p != list.end()) {
-    list.erase(p);
-    return true;
-  }
-  return false;
-}
-
-#ifdef ANDROID
-#include <android/log.h>
-static int YGAndroidLog(const YGConfigRef config,
-                        const YGNodeRef node,
-                        YGLogLevel level,
-                        const char *format,
-                        va_list args) {
-  int androidLevel = YGLogLevelDebug;
-  switch (level) {
-    case YGLogLevelFatal:
-      androidLevel = ANDROID_LOG_FATAL;
-      break;
-    case YGLogLevelError:
-      androidLevel = ANDROID_LOG_ERROR;
-      break;
-    case YGLogLevelWarn:
-      androidLevel = ANDROID_LOG_WARN;
-      break;
-    case YGLogLevelInfo:
-      androidLevel = ANDROID_LOG_INFO;
-      break;
-    case YGLogLevelDebug:
-      androidLevel = ANDROID_LOG_DEBUG;
-      break;
-    case YGLogLevelVerbose:
-      androidLevel = ANDROID_LOG_VERBOSE;
-      break;
-  }
-  const int result = __android_log_vprint(androidLevel, "yoga", format, args);
-  return result;
-}
-#else
-#define YG_UNUSED(x) (void)(x);
-
-static int YGDefaultLog(const YGConfigRef config,
-                        const YGNodeRef node,
-                        YGLogLevel level,
-                        const char *format,
-                        va_list args) {
-  YG_UNUSED(config);
-  YG_UNUSED(node);
-  switch (level) {
-    case YGLogLevelError:
-    case YGLogLevelFatal:
-      return vfprintf(stderr, format, args);
-    case YGLogLevelWarn:
-    case YGLogLevelInfo:
-    case YGLogLevelDebug:
-    case YGLogLevelVerbose:
-    default:
-      return vprintf(format, args);
-  }
-}
-
-#undef YG_UNUSED
-#endif
-
-bool YGFloatIsUndefined(const float value) {
-  return isnan(value);
-}
-
-const YGValue* YGComputedEdgeValue(
-    const YGValue edges[YGEdgeCount],
-    const YGEdge edge,
-    const YGValue* const defaultValue) {
-  if (edges[edge].unit != YGUnitUndefined) {
-    return &edges[edge];
-  }
-
-  if ((edge == YGEdgeTop || edge == YGEdgeBottom) &&
-      edges[YGEdgeVertical].unit != YGUnitUndefined) {
-    return &edges[YGEdgeVertical];
-  }
-
-  if ((edge == YGEdgeLeft || edge == YGEdgeRight || edge == YGEdgeStart || edge == YGEdgeEnd) &&
-      edges[YGEdgeHorizontal].unit != YGUnitUndefined) {
-    return &edges[YGEdgeHorizontal];
-  }
-
-  if (edges[YGEdgeAll].unit != YGUnitUndefined) {
-    return &edges[YGEdgeAll];
-  }
-
-  if (edge == YGEdgeStart || edge == YGEdgeEnd) {
-    return &YGValueUndefined;
-  }
-
-  return defaultValue;
-}
-
-static inline float YGResolveValue(const YGValue *const value, const float parentSize) {
-  switch (value->unit) {
-    case YGUnitUndefined:
-    case YGUnitAuto:
-      return YGUndefined;
-    case YGUnitPoint:
-      return value->value;
-    case YGUnitPercent:
-      return value->value * parentSize / 100.0f;
-  }
-  return YGUndefined;
-}
-
-static inline float YGResolveValueMargin(const YGValue *const value, const float parentSize) {
-  return value->unit == YGUnitAuto ? 0 : YGResolveValue(value, parentSize);
-}
-
-int32_t gNodeInstanceCount = 0;
-int32_t gConfigInstanceCount = 0;
-
-WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) {
-  const YGNodeRef node = (const YGNodeRef)malloc(sizeof(YGNode));
-  YGAssertWithConfig(
-      config, node != nullptr, "Could not allocate memory for node");
-  gNodeInstanceCount++;
-
-  memcpy(node, &gYGNodeDefaults, sizeof(YGNode));
-  if (config->useWebDefaults) {
-    node->style.flexDirection = YGFlexDirectionRow;
-    node->style.alignContent = YGAlignStretch;
-  }
-  node->config = config;
-  return node;
-}
-
-YGNodeRef YGNodeNew(void) {
-  return YGNodeNewWithConfig(&gYGConfigDefaults);
-}
-
-YGNodeRef YGNodeClone(YGNodeRef oldNode) {
-  YGNodeRef node = new YGNode(*oldNode);
-  YGAssertWithConfig(
-      oldNode->config, node != nullptr, "Could not allocate memory for node");
-  gNodeInstanceCount++;
-  node->parent = nullptr;
-  return node;
-}
-
-void YGNodeFree(const YGNodeRef node) {
-  if (node->parent) {
-    YGNodeListDelete(node->parent->children, node);
-    node->parent = nullptr;
-  }
-
-  const uint32_t childCount = YGNodeGetChildCount(node);
-  for (uint32_t i = 0; i < childCount; i++) {
-    const YGNodeRef child = YGNodeGetChild(node, i);
-    child->parent = nullptr;
-  }
-
-  YGVector().swap(node->children);
-  free(node);
-  gNodeInstanceCount--;
-}
-
-void YGNodeFreeRecursive(const YGNodeRef root) {
-  while (YGNodeGetChildCount(root) > 0) {
-    const YGNodeRef child = YGNodeGetChild(root, 0);
-    if (child->parent != root) {
-      // Don't free shared nodes that we don't own.
-      break;
-    }
-    YGNodeRemoveChild(root, child);
-    YGNodeFreeRecursive(child);
-  }
-  YGNodeFree(root);
-}
-
-void YGNodeReset(const YGNodeRef node) {
-  YGAssertWithNode(node,
-                   YGNodeGetChildCount(node) == 0,
-                   "Cannot reset a node which still has children attached");
-  YGAssertWithNode(
-      node,
-      node->parent == nullptr,
-      "Cannot reset a node still attached to a parent");
-
-  YGVector().swap(node->children);
-
-  const YGConfigRef config = node->config;
-  memcpy(node, &gYGNodeDefaults, sizeof(YGNode));
-  if (config->useWebDefaults) {
-    node->style.flexDirection = YGFlexDirectionRow;
-    node->style.alignContent = YGAlignStretch;
-  }
-  node->config = config;
-}
-
-int32_t YGNodeGetInstanceCount(void) {
-  return gNodeInstanceCount;
-}
-
-int32_t YGConfigGetInstanceCount(void) {
-  return gConfigInstanceCount;
-}
-
-// Export only for C#
-YGConfigRef YGConfigGetDefault() {
-  return &gYGConfigDefaults;
-}
-
-YGConfigRef YGConfigNew(void) {
-  const YGConfigRef config = (const YGConfigRef)malloc(sizeof(YGConfig));
-  YGAssert(config != nullptr, "Could not allocate memory for config");
-
-  gConfigInstanceCount++;
-  memcpy(config, &gYGConfigDefaults, sizeof(YGConfig));
-  return config;
-}
-
-void YGConfigFree(const YGConfigRef config) {
-  free(config);
-  gConfigInstanceCount--;
-}
-
-void YGConfigCopy(const YGConfigRef dest, const YGConfigRef src) {
-  memcpy(dest, src, sizeof(YGConfig));
-}
-
-static void YGNodeMarkDirtyInternal(const YGNodeRef node) {
-  if (!node->isDirty) {
-    node->isDirty = true;
-    node->layout.computedFlexBasis = YGUndefined;
-    if (node->parent) {
-      YGNodeMarkDirtyInternal(node->parent);
-    }
-  }
-}
-
-void YGNodeSetMeasureFunc(const YGNodeRef node, YGMeasureFunc measureFunc) {
-  if (measureFunc == nullptr) {
-    node->measure = nullptr;
-    // TODO: t18095186 Move nodeType to opt-in function and mark appropriate places in Litho
-    node->nodeType = YGNodeTypeDefault;
-  } else {
-    YGAssertWithNode(
-        node,
-        YGNodeGetChildCount(node) == 0,
-        "Cannot set measure function: Nodes with measure functions cannot have children.");
-    node->measure = measureFunc;
-    // TODO: t18095186 Move nodeType to opt-in function and mark appropriate places in Litho
-    node->nodeType = YGNodeTypeText;
-  }
-}
-
-YGMeasureFunc YGNodeGetMeasureFunc(const YGNodeRef node) {
-  return node->measure;
-}
-
-void YGNodeSetBaselineFunc(const YGNodeRef node, YGBaselineFunc baselineFunc) {
-  node->baseline = baselineFunc;
-}
-
-YGBaselineFunc YGNodeGetBaselineFunc(const YGNodeRef node) {
-  return node->baseline;
-}
-
-static void YGCloneChildrenIfNeeded(const YGNodeRef parent) {
-  // YGNodeRemoveChild has a forked variant of this algorithm optimized for deletions.
-  const uint32_t childCount = YGNodeGetChildCount(parent);
-  if (childCount == 0) {
-    // This is an empty set. Nothing to clone.
-    return;
-  }
-
-  const YGNodeRef firstChild = YGNodeGetChild(parent, 0);
-  if (firstChild->parent == parent) {
-    // If the first child has this node as its parent, we assume that it is already unique.
-    // We can do this because if we have it has a child, that means that its parent was at some
-    // point cloned which made that subtree immutable.
-    // We also assume that all its sibling are cloned as well.
-    return;
-  }
-
-  const YGNodeClonedFunc cloneNodeCallback = parent->config->cloneNodeCallback;
-  for (uint32_t i = 0; i < childCount; i++) {
-    const YGNodeRef oldChild = parent->children[i];
-    const YGNodeRef newChild = YGNodeClone(oldChild);
-    parent->children[i] = newChild;
-    newChild->parent = parent;
-    if (cloneNodeCallback) {
-      cloneNodeCallback(oldChild, newChild, parent, i);
-    }
-  }
-}
-
-void YGNodeInsertChild(const YGNodeRef node, const YGNodeRef child, const uint32_t index) {
-  YGAssertWithNode(
-      node,
-      child->parent == nullptr,
-      "Child already has a parent, it must be removed first.");
-  YGAssertWithNode(
-      node,
-      node->measure == nullptr,
-      "Cannot add child: Nodes with measure functions cannot have children.");
-
-  YGCloneChildrenIfNeeded(node);
-  node->children.insert(node->children.begin() + index, child);
-  child->parent = node;
-  YGNodeMarkDirtyInternal(node);
-}
-
-void YGNodeRemoveChild(const YGNodeRef parent, const YGNodeRef excludedChild) {
-  // This algorithm is a forked variant from YGCloneChildrenIfNeeded that excludes a child.
-  const uint32_t childCount = YGNodeGetChildCount(parent);
-
-  if (childCount == 0) {
-    // This is an empty set. Nothing to remove.
-    return;
-  }
-  const YGNodeRef firstChild = YGNodeGetChild(parent, 0);
-  if (firstChild->parent == parent) {
-    // If the first child has this node as its parent, we assume that it is already unique.
-    // We can now try to delete a child in this list.
-    if (YGNodeListDelete(parent->children, excludedChild)) {
-      excludedChild->layout = gYGNodeDefaults.layout; // layout is no longer valid
-      excludedChild->parent = nullptr;
-      YGNodeMarkDirtyInternal(parent);
-    }
-    return;
-  }
-  // Otherwise we have to clone the node list except for the child we're trying to delete.
-  // We don't want to simply clone all children, because then the host will need to free
-  // the clone of the child that was just deleted.
-  const YGNodeClonedFunc cloneNodeCallback = parent->config->cloneNodeCallback;
-  uint32_t nextInsertIndex = 0;
-  for (uint32_t i = 0; i < childCount; i++) {
-    const YGNodeRef oldChild = parent->children[i];
-    if (excludedChild == oldChild) {
-      // Ignore the deleted child. Don't reset its layout or parent since it is still valid
-      // in the other parent. However, since this parent has now changed, we need to mark it
-      // as dirty.
-      YGNodeMarkDirtyInternal(parent);
-      continue;
-    }
-    const YGNodeRef newChild = YGNodeClone(oldChild);
-    parent->children[nextInsertIndex] = newChild;
-    newChild->parent = parent;
-    if (cloneNodeCallback) {
-      cloneNodeCallback(oldChild, newChild, parent, nextInsertIndex);
-    }
-    nextInsertIndex++;
-  }
-  while (nextInsertIndex < childCount) {
-    parent->children.erase(parent->children.begin() + nextInsertIndex);
-    nextInsertIndex++;
-  }
-}
-
-void YGNodeRemoveAllChildren(const YGNodeRef parent) {
-  const uint32_t childCount = YGNodeGetChildCount(parent);
-  if (childCount == 0) {
-    // This is an empty set already. Nothing to do.
-    return;
-  }
-  const YGNodeRef firstChild = YGNodeGetChild(parent, 0);
-  if (firstChild->parent == parent) {
-    // If the first child has this node as its parent, we assume that this child set is unique.
-    for (uint32_t i = 0; i < childCount; i++) {
-      const YGNodeRef oldChild = YGNodeGetChild(parent, i);
-      oldChild->layout = gYGNodeDefaults.layout; // layout is no longer valid
-      oldChild->parent = nullptr;
-    }
-    YGVector().swap(parent->children);
-    YGNodeMarkDirtyInternal(parent);
-    return;
-  }
-  // Otherwise, we are not the owner of the child set. We don't have to do anything to clear it.
-  parent->children = YGVector();
-  YGNodeMarkDirtyInternal(parent);
-}
-
-YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index) {
-  if (index < node->children.size()) {
-    return node->children[index];
-  }
-  return nullptr;
-}
-
-YGNodeRef YGNodeGetParent(const YGNodeRef node) {
-  return node->parent;
-}
-
-uint32_t YGNodeGetChildCount(const YGNodeRef node) {
-  return node->children.size();
-}
-
-void YGNodeMarkDirty(const YGNodeRef node) {
-  YGAssertWithNode(
-      node,
-      node->measure != nullptr,
-      "Only leaf nodes with custom measure functions"
-      "should manually mark themselves as dirty");
-
-  YGNodeMarkDirtyInternal(node);
-}
-
-bool YGNodeIsDirty(const YGNodeRef node) {
-  return node->isDirty;
-}
-
-void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode) {
-  if (memcmp(&dstNode->style, &srcNode->style, sizeof(YGStyle)) != 0) {
-    memcpy(&dstNode->style, &srcNode->style, sizeof(YGStyle));
-    YGNodeMarkDirtyInternal(dstNode);
-  }
-}
-
-static inline float YGResolveFlexGrow(const YGNodeRef node) {
-  // Root nodes flexGrow should always be 0
-  if (node->parent == nullptr) {
-    return 0.0;
-  }
-  if (!YGFloatIsUndefined(node->style.flexGrow)) {
-    return node->style.flexGrow;
-  }
-  if (!YGFloatIsUndefined(node->style.flex) && node->style.flex > 0.0f) {
-    return node->style.flex;
-  }
-  return kDefaultFlexGrow;
-}
-
-float YGNodeStyleGetFlexGrow(const YGNodeRef node) {
-  return YGFloatIsUndefined(node->style.flexGrow) ? kDefaultFlexGrow : node->style.flexGrow;
-}
-
-float YGNodeStyleGetFlexShrink(const YGNodeRef node) {
-  return YGFloatIsUndefined(node->style.flexShrink)
-             ? (node->config->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink)
-             : node->style.flexShrink;
-}
-
-static inline float YGNodeResolveFlexShrink(const YGNodeRef node) {
-  // Root nodes flexShrink should always be 0
-  if (node->parent == nullptr) {
-    return 0.0;
-  }
-  if (!YGFloatIsUndefined(node->style.flexShrink)) {
-    return node->style.flexShrink;
-  }
-  if (!node->config->useWebDefaults && !YGFloatIsUndefined(node->style.flex) &&
-      node->style.flex < 0.0f) {
-    return -node->style.flex;
-  }
-  return node->config->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink;
-}
-
-static inline const YGValue *YGNodeResolveFlexBasisPtr(const YGNodeRef node) {
-  if (node->style.flexBasis.unit != YGUnitAuto && node->style.flexBasis.unit != YGUnitUndefined) {
-    return &node->style.flexBasis;
-  }
-  if (!YGFloatIsUndefined(node->style.flex) && node->style.flex > 0.0f) {
-    return node->config->useWebDefaults ? &YGValueAuto : &YGValueZero;
-  }
-  return &YGValueAuto;
-}
-
-#define YG_NODE_PROPERTY_IMPL(type, name, paramName, instanceName) \
-  void YGNodeSet##name(const YGNodeRef node, type paramName) {     \
-    node->instanceName = paramName;                                \
-  }                                                                \
-                                                                   \
-  type YGNodeGet##name(const YGNodeRef node) {                     \
-    return node->instanceName;                                     \
-  }
-
-#define YG_NODE_STYLE_PROPERTY_SETTER_IMPL(type, name, paramName, instanceName) \
-  void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) {       \
-    if (node->style.instanceName != paramName) {                                \
-      node->style.instanceName = paramName;                                     \
-      YGNodeMarkDirtyInternal(node);                                            \
-    }                                                                           \
-  }
-
-#define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL(                               \
-    type, name, paramName, instanceName)                                       \
-  void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) {      \
-    YGValue value = {                                                          \
-        .value = paramName,                                                    \
-        .unit = YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
-    };                                                                         \
-    if ((node->style.instanceName.value != value.value &&                      \
-         value.unit != YGUnitUndefined) ||                                     \
-        node->style.instanceName.unit != value.unit) {                         \
-      node->style.instanceName = value;                                        \
-      YGNodeMarkDirtyInternal(node);                                           \
-    }                                                                          \
-  }                                                                            \
-                                                                               \
-  void YGNodeStyleSet##name##Percent(                                          \
-      const YGNodeRef node, const type paramName) {                            \
-    YGValue value = {                                                          \
-        .value = paramName,                                                    \
-        .unit =                                                                \
-            YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent,   \
-    };                                                                         \
-    if ((node->style.instanceName.value != value.value &&                      \
-         value.unit != YGUnitUndefined) ||                                     \
-        node->style.instanceName.unit != value.unit) {                         \
-      node->style.instanceName = value;                                        \
-      YGNodeMarkDirtyInternal(node);                                           \
-    }                                                                          \
-  }
-
-#define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL(                          \
-    type, name, paramName, instanceName)                                       \
-  void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) {      \
-    YGValue value = {                                                          \
-        .value = paramName,                                                    \
-        .unit = YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
-    };                                                                         \
-    if ((node->style.instanceName.value != value.value &&                      \
-         value.unit != YGUnitUndefined) ||                                     \
-        node->style.instanceName.unit != value.unit) {                         \
-      node->style.instanceName = value;                                        \
-      YGNodeMarkDirtyInternal(node);                                           \
-    }                                                                          \
-  }                                                                            \
-                                                                               \
-  void YGNodeStyleSet##name##Percent(                                          \
-      const YGNodeRef node, const type paramName) {                            \
-    if (node->style.instanceName.value != paramName ||                         \
-        node->style.instanceName.unit != YGUnitPercent) {                      \
-      node->style.instanceName.value = paramName;                              \
-      node->style.instanceName.unit =                                          \
-          YGFloatIsUndefined(paramName) ? YGUnitAuto : YGUnitPercent;          \
-      YGNodeMarkDirtyInternal(node);                                           \
-    }                                                                          \
-  }                                                                            \
-                                                                               \
-  void YGNodeStyleSet##name##Auto(const YGNodeRef node) {                      \
-    if (node->style.instanceName.unit != YGUnitAuto) {                         \
-      node->style.instanceName.value = YGUndefined;                            \
-      node->style.instanceName.unit = YGUnitAuto;                              \
-      YGNodeMarkDirtyInternal(node);                                           \
-    }                                                                          \
-  }
-
-#define YG_NODE_STYLE_PROPERTY_IMPL(type, name, paramName, instanceName)  \
-  YG_NODE_STYLE_PROPERTY_SETTER_IMPL(type, name, paramName, instanceName) \
-                                                                          \
-  type YGNodeStyleGet##name(const YGNodeRef node) {                       \
-    return node->style.instanceName;                                      \
-  }
-
-#define YG_NODE_STYLE_PROPERTY_UNIT_IMPL(type, name, paramName, instanceName)   \
-  YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL(float, name, paramName, instanceName) \
-                                                                                \
-  type YGNodeStyleGet##name(const YGNodeRef node) {                             \
-    return node->style.instanceName;                                            \
-  }
-
-#define YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(type, name, paramName, instanceName)   \
-  YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL(float, name, paramName, instanceName) \
-                                                                                     \
-  type YGNodeStyleGet##name(const YGNodeRef node) {                                  \
-    return node->style.instanceName;                                                 \
-  }
-
-#define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(type, name, instanceName) \
-  void YGNodeStyleSet##name##Auto(const YGNodeRef node, const YGEdge edge) { \
-    if (node->style.instanceName[edge].unit != YGUnitAuto) {                 \
-      node->style.instanceName[edge].value = YGUndefined;                    \
-      node->style.instanceName[edge].unit = YGUnitAuto;                      \
-      YGNodeMarkDirtyInternal(node);                                         \
-    }                                                                        \
-  }
-
-#define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(                                 \
-    type, name, paramName, instanceName)                                       \
-  void YGNodeStyleSet##name(                                                   \
-      const YGNodeRef node, const YGEdge edge, const float paramName) {        \
-    YGValue value = {                                                          \
-        .value = paramName,                                                    \
-        .unit = YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
-    };                                                                         \
-    if ((node->style.instanceName[edge].value != value.value &&                \
-         value.unit != YGUnitUndefined) ||                                     \
-        node->style.instanceName[edge].unit != value.unit) {                   \
-      node->style.instanceName[edge] = value;                                  \
-      YGNodeMarkDirtyInternal(node);                                           \
-    }                                                                          \
-  }                                                                            \
-                                                                               \
-  void YGNodeStyleSet##name##Percent(                                          \
-      const YGNodeRef node, const YGEdge edge, const float paramName) {        \
-    YGValue value = {                                                          \
-        .value = paramName,                                                    \
-        .unit =                                                                \
-            YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent,   \
-    };                                                                         \
-    if ((node->style.instanceName[edge].value != value.value &&                \
-         value.unit != YGUnitUndefined) ||                                     \
-        node->style.instanceName[edge].unit != value.unit) {                   \
-      node->style.instanceName[edge] = value;                                  \
-      YGNodeMarkDirtyInternal(node);                                           \
-    }                                                                          \
-  }                                                                            \
-                                                                               \
-  WIN_STRUCT(type)                                                             \
-  YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) {              \
-    return WIN_STRUCT_REF(node->style.instanceName[edge]);                     \
-  }
-
-#define YG_NODE_STYLE_EDGE_PROPERTY_IMPL(type, name, paramName, instanceName)  \
-  void YGNodeStyleSet##name(                                                   \
-      const YGNodeRef node, const YGEdge edge, const float paramName) {        \
-    YGValue value = {                                                          \
-        .value = paramName,                                                    \
-        .unit = YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
-    };                                                                         \
-    if ((node->style.instanceName[edge].value != value.value &&                \
-         value.unit != YGUnitUndefined) ||                                     \
-        node->style.instanceName[edge].unit != value.unit) {                   \
-      node->style.instanceName[edge] = value;                                  \
-      YGNodeMarkDirtyInternal(node);                                           \
-    }                                                                          \
-  }                                                                            \
-                                                                               \
-  float YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) {        \
-    return node->style.instanceName[edge].value;                               \
-  }
-
-#define YG_NODE_LAYOUT_PROPERTY_IMPL(type, name, instanceName) \
-  type YGNodeLayoutGet##name(const YGNodeRef node) {           \
-    return node->layout.instanceName;                          \
-  }
-
-#define YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(type, name, instanceName) \
-  type YGNodeLayoutGet##name(const YGNodeRef node, const YGEdge edge) { \
-    YGAssertWithNode(                                                   \
-        node,                                                           \
-        edge <= YGEdgeEnd,                                              \
-        "Cannot get layout properties of multi-edge shorthands");       \
-                                                                        \
-    if (edge == YGEdgeLeft) {                                           \
-      if (node->layout.direction == YGDirectionRTL) {                   \
-        return node->layout.instanceName[YGEdgeEnd];                    \
-      } else {                                                          \
-        return node->layout.instanceName[YGEdgeStart];                  \
-      }                                                                 \
-    }                                                                   \
-                                                                        \
-    if (edge == YGEdgeRight) {                                          \
-      if (node->layout.direction == YGDirectionRTL) {                   \
-        return node->layout.instanceName[YGEdgeStart];                  \
-      } else {                                                          \
-        return node->layout.instanceName[YGEdgeEnd];                    \
-      }                                                                 \
-    }                                                                   \
-                                                                        \
-    return node->layout.instanceName[edge];                             \
-  }
-
-YG_NODE_PROPERTY_IMPL(void *, Context, context, context);
-YG_NODE_PROPERTY_IMPL(YGPrintFunc, PrintFunc, printFunc, print);
-YG_NODE_PROPERTY_IMPL(bool, HasNewLayout, hasNewLayout, hasNewLayout);
-YG_NODE_PROPERTY_IMPL(YGNodeType, NodeType, nodeType, nodeType);
-
-YG_NODE_STYLE_PROPERTY_IMPL(YGDirection, Direction, direction, direction);
-YG_NODE_STYLE_PROPERTY_IMPL(YGFlexDirection, FlexDirection, flexDirection, flexDirection);
-YG_NODE_STYLE_PROPERTY_IMPL(YGJustify, JustifyContent, justifyContent, justifyContent);
-YG_NODE_STYLE_PROPERTY_IMPL(YGAlign, AlignContent, alignContent, alignContent);
-YG_NODE_STYLE_PROPERTY_IMPL(YGAlign, AlignItems, alignItems, alignItems);
-YG_NODE_STYLE_PROPERTY_IMPL(YGAlign, AlignSelf, alignSelf, alignSelf);
-YG_NODE_STYLE_PROPERTY_IMPL(YGPositionType, PositionType, positionType, positionType);
-YG_NODE_STYLE_PROPERTY_IMPL(YGWrap, FlexWrap, flexWrap, flexWrap);
-YG_NODE_STYLE_PROPERTY_IMPL(YGOverflow, Overflow, overflow, overflow);
-YG_NODE_STYLE_PROPERTY_IMPL(YGDisplay, Display, display, display);
-
-YG_NODE_STYLE_PROPERTY_IMPL(float, Flex, flex, flex);
-YG_NODE_STYLE_PROPERTY_SETTER_IMPL(float, FlexGrow, flexGrow, flexGrow);
-YG_NODE_STYLE_PROPERTY_SETTER_IMPL(float, FlexShrink, flexShrink, flexShrink);
-YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, FlexBasis, flexBasis, flexBasis);
-
-YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Position, position, position);
-YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Margin, margin, margin);
-YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Margin, margin);
-YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Padding, padding, padding);
-YG_NODE_STYLE_EDGE_PROPERTY_IMPL(float, Border, border, border);
-
-YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Width, width, dimensions[YGDimensionWidth]);
-YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Height, height, dimensions[YGDimensionHeight]);
-YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MinWidth, minWidth, minDimensions[YGDimensionWidth]);
-YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MinHeight, minHeight, minDimensions[YGDimensionHeight]);
-YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MaxWidth, maxWidth, maxDimensions[YGDimensionWidth]);
-YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MaxHeight, maxHeight, maxDimensions[YGDimensionHeight]);
-
-// Yoga specific properties, not compatible with flexbox specification
-YG_NODE_STYLE_PROPERTY_IMPL(float, AspectRatio, aspectRatio, aspectRatio);
-
-YG_NODE_LAYOUT_PROPERTY_IMPL(float, Left, position[YGEdgeLeft]);
-YG_NODE_LAYOUT_PROPERTY_IMPL(float, Top, position[YGEdgeTop]);
-YG_NODE_LAYOUT_PROPERTY_IMPL(float, Right, position[YGEdgeRight]);
-YG_NODE_LAYOUT_PROPERTY_IMPL(float, Bottom, position[YGEdgeBottom]);
-YG_NODE_LAYOUT_PROPERTY_IMPL(float, Width, dimensions[YGDimensionWidth]);
-YG_NODE_LAYOUT_PROPERTY_IMPL(float, Height, dimensions[YGDimensionHeight]);
-YG_NODE_LAYOUT_PROPERTY_IMPL(YGDirection, Direction, direction);
-YG_NODE_LAYOUT_PROPERTY_IMPL(bool, HadOverflow, hadOverflow);
-
-YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Margin, margin);
-YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Border, border);
-YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Padding, padding);
-
-uint32_t gCurrentGenerationCount = 0;
-
-bool YGLayoutNodeInternal(const YGNodeRef node,
-                          const float availableWidth,
-                          const float availableHeight,
-                          const YGDirection parentDirection,
-                          const YGMeasureMode widthMeasureMode,
-                          const YGMeasureMode heightMeasureMode,
-                          const float parentWidth,
-                          const float parentHeight,
-                          const bool performLayout,
-                          const char *reason,
-                          const YGConfigRef config);
-
-bool YGValueEqual(const YGValue a, const YGValue b) {
-  if (a.unit != b.unit) {
-    return false;
-  }
-
-  if (a.unit == YGUnitUndefined) {
-    return true;
-  }
-
-  return fabs(a.value - b.value) < 0.0001f;
-}
-
-static inline void YGResolveDimensions(YGNodeRef node) {
-  for (uint32_t dim = YGDimensionWidth; dim < YGDimensionCount; dim++) {
-    if (node->style.maxDimensions[dim].unit != YGUnitUndefined &&
-        YGValueEqual(node->style.maxDimensions[dim], node->style.minDimensions[dim])) {
-      node->resolvedDimensions[dim] = &node->style.maxDimensions[dim];
-    } else {
-      node->resolvedDimensions[dim] = &node->style.dimensions[dim];
-    }
-  }
-}
-
-bool YGFloatsEqual(const float a, const float b) {
-  if (YGFloatIsUndefined(a)) {
-    return YGFloatIsUndefined(b);
-  }
-  return fabs(a - b) < 0.0001f;
-}
-
-static void YGNodePrintInternal(const YGNodeRef node,
-                                const YGPrintOptions options) {
-  std::string str;
-  facebook::yoga::YGNodeToString(&str, node, options, 0);
-  YGLog(node, YGLogLevelDebug, str.c_str());
-}
-
-void YGNodePrint(const YGNodeRef node, const YGPrintOptions options) {
-  YGNodePrintInternal(node, options);
-}
-
-static const YGEdge leading[4] = {
-        [YGFlexDirectionColumn] = YGEdgeTop,
-        [YGFlexDirectionColumnReverse] = YGEdgeBottom,
-        [YGFlexDirectionRow] = YGEdgeLeft,
-        [YGFlexDirectionRowReverse] = YGEdgeRight,
-};
-static const YGEdge trailing[4] = {
-        [YGFlexDirectionColumn] = YGEdgeBottom,
-        [YGFlexDirectionColumnReverse] = YGEdgeTop,
-        [YGFlexDirectionRow] = YGEdgeRight,
-        [YGFlexDirectionRowReverse] = YGEdgeLeft,
-};
-static const YGEdge pos[4] = {
-        [YGFlexDirectionColumn] = YGEdgeTop,
-        [YGFlexDirectionColumnReverse] = YGEdgeBottom,
-        [YGFlexDirectionRow] = YGEdgeLeft,
-        [YGFlexDirectionRowReverse] = YGEdgeRight,
-};
-static const YGDimension dim[4] = {
-        [YGFlexDirectionColumn] = YGDimensionHeight,
-        [YGFlexDirectionColumnReverse] = YGDimensionHeight,
-        [YGFlexDirectionRow] = YGDimensionWidth,
-        [YGFlexDirectionRowReverse] = YGDimensionWidth,
-};
-
-static inline bool YGFlexDirectionIsRow(const YGFlexDirection flexDirection) {
-  return flexDirection == YGFlexDirectionRow || flexDirection == YGFlexDirectionRowReverse;
-}
-
-static inline bool YGFlexDirectionIsColumn(const YGFlexDirection flexDirection) {
-  return flexDirection == YGFlexDirectionColumn || flexDirection == YGFlexDirectionColumnReverse;
-}
-
-static inline float YGNodeLeadingMargin(const YGNodeRef node,
-                                        const YGFlexDirection axis,
-                                        const float widthSize) {
-  if (YGFlexDirectionIsRow(axis) && node->style.margin[YGEdgeStart].unit != YGUnitUndefined) {
-    return YGResolveValueMargin(&node->style.margin[YGEdgeStart], widthSize);
-  }
-
-  return YGResolveValueMargin(YGComputedEdgeValue(node->style.margin, leading[axis], &YGValueZero),
-                              widthSize);
-}
-
-static float YGNodeTrailingMargin(const YGNodeRef node,
-                                  const YGFlexDirection axis,
-                                  const float widthSize) {
-  if (YGFlexDirectionIsRow(axis) && node->style.margin[YGEdgeEnd].unit != YGUnitUndefined) {
-    return YGResolveValueMargin(&node->style.margin[YGEdgeEnd], widthSize);
-  }
-
-  return YGResolveValueMargin(YGComputedEdgeValue(node->style.margin, trailing[axis], &YGValueZero),
-                              widthSize);
-}
-
-static float YGNodeLeadingPadding(const YGNodeRef node,
-                                  const YGFlexDirection axis,
-                                  const float widthSize) {
-  if (YGFlexDirectionIsRow(axis) && node->style.padding[YGEdgeStart].unit != YGUnitUndefined &&
-      YGResolveValue(&node->style.padding[YGEdgeStart], widthSize) >= 0.0f) {
-    return YGResolveValue(&node->style.padding[YGEdgeStart], widthSize);
-  }
-
-  return fmaxf(YGResolveValue(YGComputedEdgeValue(node->style.padding, leading[axis], &YGValueZero),
-                              widthSize),
-               0.0f);
-}
-
-static float YGNodeTrailingPadding(const YGNodeRef node,
-                                   const YGFlexDirection axis,
-                                   const float widthSize) {
-  if (YGFlexDirectionIsRow(axis) && node->style.padding[YGEdgeEnd].unit != YGUnitUndefined &&
-      YGResolveValue(&node->style.padding[YGEdgeEnd], widthSize) >= 0.0f) {
-    return YGResolveValue(&node->style.padding[YGEdgeEnd], widthSize);
-  }
-
-  return fmaxf(YGResolveValue(YGComputedEdgeValue(node->style.padding, trailing[axis], &YGValueZero),
-                              widthSize),
-               0.0f);
-}
-
-static float YGNodeLeadingBorder(const YGNodeRef node, const YGFlexDirection axis) {
-  if (YGFlexDirectionIsRow(axis) && node->style.border[YGEdgeStart].unit != YGUnitUndefined &&
-      node->style.border[YGEdgeStart].value >= 0.0f) {
-    return node->style.border[YGEdgeStart].value;
-  }
-
-  return fmaxf(YGComputedEdgeValue(node->style.border, leading[axis], &YGValueZero)->value, 0.0f);
-}
-
-static float YGNodeTrailingBorder(const YGNodeRef node, const YGFlexDirection axis) {
-  if (YGFlexDirectionIsRow(axis) && node->style.border[YGEdgeEnd].unit != YGUnitUndefined &&
-      node->style.border[YGEdgeEnd].value >= 0.0f) {
-    return node->style.border[YGEdgeEnd].value;
-  }
-
-  return fmaxf(YGComputedEdgeValue(node->style.border, trailing[axis], &YGValueZero)->value, 0.0f);
-}
-
-static inline float YGNodeLeadingPaddingAndBorder(const YGNodeRef node,
-                                                  const YGFlexDirection axis,
-                                                  const float widthSize) {
-  return YGNodeLeadingPadding(node, axis, widthSize) + YGNodeLeadingBorder(node, axis);
-}
-
-static inline float YGNodeTrailingPaddingAndBorder(const YGNodeRef node,
-                                                   const YGFlexDirection axis,
-                                                   const float widthSize) {
-  return YGNodeTrailingPadding(node, axis, widthSize) + YGNodeTrailingBorder(node, axis);
-}
-
-static inline float YGNodeMarginForAxis(const YGNodeRef node,
-                                        const YGFlexDirection axis,
-                                        const float widthSize) {
-  return YGNodeLeadingMargin(node, axis, widthSize) + YGNodeTrailingMargin(node, axis, widthSize);
-}
-
-static inline float YGNodePaddingAndBorderForAxis(const YGNodeRef node,
-                                                  const YGFlexDirection axis,
-                                                  const float widthSize) {
-  return YGNodeLeadingPaddingAndBorder(node, axis, widthSize) +
-         YGNodeTrailingPaddingAndBorder(node, axis, widthSize);
-}
-
-static inline YGAlign YGNodeAlignItem(const YGNodeRef node, const YGNodeRef child) {
-  const YGAlign align =
-      child->style.alignSelf == YGAlignAuto ? node->style.alignItems : child->style.alignSelf;
-  if (align == YGAlignBaseline && YGFlexDirectionIsColumn(node->style.flexDirection)) {
-    return YGAlignFlexStart;
-  }
-  return align;
-}
-
-static inline YGDirection YGNodeResolveDirection(const YGNodeRef node,
-                                                 const YGDirection parentDirection) {
-  if (node->style.direction == YGDirectionInherit) {
-    return parentDirection > YGDirectionInherit ? parentDirection : YGDirectionLTR;
-  } else {
-    return node->style.direction;
-  }
-}
-
-static float YGBaseline(const YGNodeRef node) {
-  if (node->baseline != nullptr) {
-    const float baseline = node->baseline(node,
-                                          node->layout.measuredDimensions[YGDimensionWidth],
-                                          node->layout.measuredDimensions[YGDimensionHeight]);
-    YGAssertWithNode(node,
-                     !YGFloatIsUndefined(baseline),
-                     "Expect custom baseline function to not return NaN");
-    return baseline;
-  }
-
-  YGNodeRef baselineChild = nullptr;
-  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;
-    }
-    if (child->style.positionType == YGPositionTypeAbsolute) {
-      continue;
-    }
-    if (YGNodeAlignItem(node, child) == YGAlignBaseline) {
-      baselineChild = child;
-      break;
-    }
-
-    if (baselineChild == nullptr) {
-      baselineChild = child;
-    }
-  }
-
-  if (baselineChild == nullptr) {
-    return node->layout.measuredDimensions[YGDimensionHeight];
-  }
-
-  const float baseline = YGBaseline(baselineChild);
-  return baseline + baselineChild->layout.position[YGEdgeTop];
-}
-
-static inline YGFlexDirection YGResolveFlexDirection(const YGFlexDirection flexDirection,
-                                                     const YGDirection direction) {
-  if (direction == YGDirectionRTL) {
-    if (flexDirection == YGFlexDirectionRow) {
-      return YGFlexDirectionRowReverse;
-    } else if (flexDirection == YGFlexDirectionRowReverse) {
-      return YGFlexDirectionRow;
-    }
-  }
-
-  return flexDirection;
-}
-
-static YGFlexDirection YGFlexDirectionCross(const YGFlexDirection flexDirection,
-                                            const YGDirection direction) {
-  return YGFlexDirectionIsColumn(flexDirection)
-             ? YGResolveFlexDirection(YGFlexDirectionRow, direction)
-             : YGFlexDirectionColumn;
-}
-
-static inline bool YGNodeIsFlex(const YGNodeRef node) {
-  return (node->style.positionType == YGPositionTypeRelative &&
-          (YGResolveFlexGrow(node) != 0 || YGNodeResolveFlexShrink(node) != 0));
-}
-
-static bool YGIsBaselineLayout(const YGNodeRef node) {
-  if (YGFlexDirectionIsColumn(node->style.flexDirection)) {
-    return false;
-  }
-  if (node->style.alignItems == YGAlignBaseline) {
-    return true;
-  }
-  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) {
-      return true;
-    }
-  }
-
-  return false;
-}
-
-static inline float YGNodeDimWithMargin(const YGNodeRef node,
-                                        const YGFlexDirection axis,
-                                        const float widthSize) {
-  return node->layout.measuredDimensions[dim[axis]] + YGNodeLeadingMargin(node, axis, widthSize) +
-         YGNodeTrailingMargin(node, axis, widthSize);
-}
-
-static inline bool YGNodeIsStyleDimDefined(const YGNodeRef node,
-                                           const YGFlexDirection axis,
-                                           const float parentSize) {
-  return !(node->resolvedDimensions[dim[axis]]->unit == YGUnitAuto ||
-           node->resolvedDimensions[dim[axis]]->unit == YGUnitUndefined ||
-           (node->resolvedDimensions[dim[axis]]->unit == YGUnitPoint &&
-            node->resolvedDimensions[dim[axis]]->value < 0.0f) ||
-           (node->resolvedDimensions[dim[axis]]->unit == YGUnitPercent &&
-            (node->resolvedDimensions[dim[axis]]->value < 0.0f || YGFloatIsUndefined(parentSize))));
-}
-
-static inline bool YGNodeIsLayoutDimDefined(const YGNodeRef node, const YGFlexDirection axis) {
-  const float value = node->layout.measuredDimensions[dim[axis]];
-  return !YGFloatIsUndefined(value) && value >= 0.0f;
-}
-
-static inline bool YGNodeIsLeadingPosDefined(const YGNodeRef node, const YGFlexDirection axis) {
-  return (YGFlexDirectionIsRow(axis) &&
-          YGComputedEdgeValue(node->style.position, YGEdgeStart, &YGValueUndefined)->unit !=
-              YGUnitUndefined) ||
-         YGComputedEdgeValue(node->style.position, leading[axis], &YGValueUndefined)->unit !=
-             YGUnitUndefined;
-}
-
-static inline bool YGNodeIsTrailingPosDefined(const YGNodeRef node, const YGFlexDirection axis) {
-  return (YGFlexDirectionIsRow(axis) &&
-          YGComputedEdgeValue(node->style.position, YGEdgeEnd, &YGValueUndefined)->unit !=
-              YGUnitUndefined) ||
-         YGComputedEdgeValue(node->style.position, trailing[axis], &YGValueUndefined)->unit !=
-             YGUnitUndefined;
-}
-
-static float YGNodeLeadingPosition(const YGNodeRef node,
-                                   const YGFlexDirection axis,
-                                   const float axisSize) {
-  if (YGFlexDirectionIsRow(axis)) {
-    const YGValue *leadingPosition =
-        YGComputedEdgeValue(node->style.position, YGEdgeStart, &YGValueUndefined);
-    if (leadingPosition->unit != YGUnitUndefined) {
-      return YGResolveValue(leadingPosition, axisSize);
-    }
-  }
-
-  const YGValue *leadingPosition =
-      YGComputedEdgeValue(node->style.position, leading[axis], &YGValueUndefined);
-
-  return leadingPosition->unit == YGUnitUndefined ? 0.0f
-                                                  : YGResolveValue(leadingPosition, axisSize);
-}
-
-static float YGNodeTrailingPosition(const YGNodeRef node,
-                                    const YGFlexDirection axis,
-                                    const float axisSize) {
-  if (YGFlexDirectionIsRow(axis)) {
-    const YGValue *trailingPosition =
-        YGComputedEdgeValue(node->style.position, YGEdgeEnd, &YGValueUndefined);
-    if (trailingPosition->unit != YGUnitUndefined) {
-      return YGResolveValue(trailingPosition, axisSize);
-    }
-  }
-
-  const YGValue *trailingPosition =
-      YGComputedEdgeValue(node->style.position, trailing[axis], &YGValueUndefined);
-
-  return trailingPosition->unit == YGUnitUndefined ? 0.0f
-                                                   : YGResolveValue(trailingPosition, axisSize);
-}
-
-static float YGNodeBoundAxisWithinMinAndMax(const YGNodeRef node,
-                                            const YGFlexDirection axis,
-                                            const float value,
-                                            const float axisSize) {
-  float min = YGUndefined;
-  float max = YGUndefined;
-
-  if (YGFlexDirectionIsColumn(axis)) {
-    min = YGResolveValue(&node->style.minDimensions[YGDimensionHeight], axisSize);
-    max = YGResolveValue(&node->style.maxDimensions[YGDimensionHeight], axisSize);
-  } else if (YGFlexDirectionIsRow(axis)) {
-    min = YGResolveValue(&node->style.minDimensions[YGDimensionWidth], axisSize);
-    max = YGResolveValue(&node->style.maxDimensions[YGDimensionWidth], axisSize);
-  }
-
-  float boundValue = value;
-
-  if (!YGFloatIsUndefined(max) && max >= 0.0f && boundValue > max) {
-    boundValue = max;
-  }
-
-  if (!YGFloatIsUndefined(min) && min >= 0.0f && boundValue < min) {
-    boundValue = min;
-  }
-
-  return boundValue;
-}
-
-static inline YGValue *YGMarginLeadingValue(const YGNodeRef node, const YGFlexDirection axis) {
-  if (YGFlexDirectionIsRow(axis) && node->style.margin[YGEdgeStart].unit != YGUnitUndefined) {
-    return &node->style.margin[YGEdgeStart];
-  } else {
-    return &node->style.margin[leading[axis]];
-  }
-}
-
-static inline YGValue *YGMarginTrailingValue(const YGNodeRef node, const YGFlexDirection axis) {
-  if (YGFlexDirectionIsRow(axis) && node->style.margin[YGEdgeEnd].unit != YGUnitUndefined) {
-    return &node->style.margin[YGEdgeEnd];
-  } else {
-    return &node->style.margin[trailing[axis]];
-  }
-}
-
-// Like YGNodeBoundAxisWithinMinAndMax but also ensures that the value doesn't go
-// below the
-// padding and border amount.
-static inline float YGNodeBoundAxis(const YGNodeRef node,
-                                    const YGFlexDirection axis,
-                                    const float value,
-                                    const float axisSize,
-                                    const float widthSize) {
-  return fmaxf(YGNodeBoundAxisWithinMinAndMax(node, axis, value, axisSize),
-               YGNodePaddingAndBorderForAxis(node, axis, widthSize));
-}
-
-static void YGNodeSetChildTrailingPosition(const YGNodeRef node,
-                                           const YGNodeRef child,
-                                           const YGFlexDirection axis) {
-  const float size = child->layout.measuredDimensions[dim[axis]];
-  child->layout.position[trailing[axis]] =
-      node->layout.measuredDimensions[dim[axis]] - size - 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 YGNodeRelativePosition(const YGNodeRef node,
-                                    const YGFlexDirection axis,
-                                    const float axisSize) {
-  return YGNodeIsLeadingPosDefined(node, axis) ? YGNodeLeadingPosition(node, axis, axisSize)
-                                               : -YGNodeTrailingPosition(node, axis, axisSize);
-}
-
-static void YGConstrainMaxSizeForMode(const YGNodeRef node,
-                                      const enum YGFlexDirection axis,
-                                      const float parentAxisSize,
-                                      const float parentWidth,
-                                      YGMeasureMode *mode,
-                                      float *size) {
-  const float maxSize = YGResolveValue(&node->style.maxDimensions[dim[axis]], parentAxisSize) +
-                        YGNodeMarginForAxis(node, axis, parentWidth);
-  switch (*mode) {
-    case YGMeasureModeExactly:
-    case YGMeasureModeAtMost:
-      *size = (YGFloatIsUndefined(maxSize) || *size < maxSize) ? *size : maxSize;
-      break;
-    case YGMeasureModeUndefined:
-      if (!YGFloatIsUndefined(maxSize)) {
-        *mode = YGMeasureModeAtMost;
-        *size = maxSize;
-      }
-      break;
-  }
-}
-
-static void YGNodeSetPosition(const YGNodeRef node,
-                              const YGDirection direction,
-                              const float mainSize,
-                              const float crossSize,
-                              const float parentWidth) {
-  /* Root nodes should be always layouted as LTR, so we don't return negative values. */
-  const YGDirection directionRespectingRoot =
-      node->parent != nullptr ? direction : YGDirectionLTR;
-  const YGFlexDirection mainAxis =
-      YGResolveFlexDirection(node->style.flexDirection, directionRespectingRoot);
-  const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, directionRespectingRoot);
-
-  const float relativePositionMain = YGNodeRelativePosition(node, mainAxis, mainSize);
-  const float relativePositionCross = YGNodeRelativePosition(node, crossAxis, crossSize);
-
-  node->layout.position[leading[mainAxis]] =
-      YGNodeLeadingMargin(node, mainAxis, parentWidth) + relativePositionMain;
-  node->layout.position[trailing[mainAxis]] =
-      YGNodeTrailingMargin(node, mainAxis, parentWidth) + relativePositionMain;
-  node->layout.position[leading[crossAxis]] =
-      YGNodeLeadingMargin(node, crossAxis, parentWidth) + relativePositionCross;
-  node->layout.position[trailing[crossAxis]] =
-      YGNodeTrailingMargin(node, crossAxis, parentWidth) + relativePositionCross;
-}
-
-static void YGNodeComputeFlexBasisForChild(const YGNodeRef node,
-                                           const YGNodeRef child,
-                                           const float width,
-                                           const YGMeasureMode widthMode,
-                                           const float height,
-                                           const float parentWidth,
-                                           const float parentHeight,
-                                           const YGMeasureMode heightMode,
-                                           const YGDirection direction,
-                                           const YGConfigRef config) {
-  const YGFlexDirection mainAxis = YGResolveFlexDirection(node->style.flexDirection, direction);
-  const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
-  const float mainAxisSize = isMainAxisRow ? width : height;
-  const float mainAxisParentSize = isMainAxisRow ? parentWidth : parentHeight;
-
-  float childWidth;
-  float childHeight;
-  YGMeasureMode childWidthMeasureMode;
-  YGMeasureMode childHeightMeasureMode;
-
-  const float resolvedFlexBasis =
-      YGResolveValue(YGNodeResolveFlexBasisPtr(child), mainAxisParentSize);
-  const bool isRowStyleDimDefined = YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, parentWidth);
-  const bool isColumnStyleDimDefined =
-      YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, parentHeight);
-
-  if (!YGFloatIsUndefined(resolvedFlexBasis) && !YGFloatIsUndefined(mainAxisSize)) {
-    if (YGFloatIsUndefined(child->layout.computedFlexBasis) ||
-        (YGConfigIsExperimentalFeatureEnabled(child->config, YGExperimentalFeatureWebFlexBasis) &&
-         child->layout.computedFlexBasisGeneration != gCurrentGenerationCount)) {
-      child->layout.computedFlexBasis =
-          fmaxf(resolvedFlexBasis, YGNodePaddingAndBorderForAxis(child, mainAxis, parentWidth));
-    }
-  } else if (isMainAxisRow && isRowStyleDimDefined) {
-    // The width is definite, so use that as the flex basis.
-    child->layout.computedFlexBasis =
-        fmaxf(YGResolveValue(child->resolvedDimensions[YGDimensionWidth], parentWidth),
-              YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, parentWidth));
-  } else if (!isMainAxisRow && isColumnStyleDimDefined) {
-    // The height is definite, so use that as the flex basis.
-    child->layout.computedFlexBasis =
-        fmaxf(YGResolveValue(child->resolvedDimensions[YGDimensionHeight], parentHeight),
-              YGNodePaddingAndBorderForAxis(child, YGFlexDirectionColumn, parentWidth));
-  } else {
-    // Compute the flex basis and hypothetical main size (i.e. the clamped
-    // flex basis).
-    childWidth = YGUndefined;
-    childHeight = YGUndefined;
-    childWidthMeasureMode = YGMeasureModeUndefined;
-    childHeightMeasureMode = YGMeasureModeUndefined;
-
-    const float marginRow = YGNodeMarginForAxis(child, YGFlexDirectionRow, parentWidth);
-    const float marginColumn = YGNodeMarginForAxis(child, YGFlexDirectionColumn, parentWidth);
-
-    if (isRowStyleDimDefined) {
-      childWidth =
-          YGResolveValue(child->resolvedDimensions[YGDimensionWidth], parentWidth) + marginRow;
-      childWidthMeasureMode = YGMeasureModeExactly;
-    }
-    if (isColumnStyleDimDefined) {
-      childHeight =
-          YGResolveValue(child->resolvedDimensions[YGDimensionHeight], parentHeight) + marginColumn;
-      childHeightMeasureMode = YGMeasureModeExactly;
-    }
-
-    // The W3C spec doesn't say anything about the 'overflow' property,
-    // but all major browsers appear to implement the following logic.
-    if ((!isMainAxisRow && node->style.overflow == YGOverflowScroll) ||
-        node->style.overflow != YGOverflowScroll) {
-      if (YGFloatIsUndefined(childWidth) && !YGFloatIsUndefined(width)) {
-        childWidth = width;
-        childWidthMeasureMode = YGMeasureModeAtMost;
-      }
-    }
-
-    if ((isMainAxisRow && node->style.overflow == YGOverflowScroll) ||
-        node->style.overflow != YGOverflowScroll) {
-      if (YGFloatIsUndefined(childHeight) && !YGFloatIsUndefined(height)) {
-        childHeight = height;
-        childHeightMeasureMode = YGMeasureModeAtMost;
-      }
-    }
-
-    if (!YGFloatIsUndefined(child->style.aspectRatio)) {
-      if (!isMainAxisRow && childWidthMeasureMode == YGMeasureModeExactly) {
-        childHeight = (childWidth - marginRow) / child->style.aspectRatio;
-        childHeightMeasureMode = YGMeasureModeExactly;
-      } else if (isMainAxisRow && childHeightMeasureMode == YGMeasureModeExactly) {
-        childWidth = (childHeight - marginColumn) * child->style.aspectRatio;
-        childWidthMeasureMode = YGMeasureModeExactly;
-      }
-    }
-
-    // If child has no defined size in the cross axis and is set to stretch,
-    // set the cross
-    // axis to be measured exactly with the available inner width
-
-    const bool hasExactWidth = !YGFloatIsUndefined(width) && widthMode == YGMeasureModeExactly;
-    const bool childWidthStretch = YGNodeAlignItem(node, child) == YGAlignStretch &&
-                                   childWidthMeasureMode != YGMeasureModeExactly;
-    if (!isMainAxisRow && !isRowStyleDimDefined && hasExactWidth && childWidthStretch) {
-      childWidth = width;
-      childWidthMeasureMode = YGMeasureModeExactly;
-      if (!YGFloatIsUndefined(child->style.aspectRatio)) {
-        childHeight = (childWidth - marginRow) / child->style.aspectRatio;
-        childHeightMeasureMode = YGMeasureModeExactly;
-      }
-    }
-
-    const bool hasExactHeight = !YGFloatIsUndefined(height) && heightMode == YGMeasureModeExactly;
-    const bool childHeightStretch = YGNodeAlignItem(node, child) == YGAlignStretch &&
-                                    childHeightMeasureMode != YGMeasureModeExactly;
-    if (isMainAxisRow && !isColumnStyleDimDefined && hasExactHeight && childHeightStretch) {
-      childHeight = height;
-      childHeightMeasureMode = YGMeasureModeExactly;
-
-      if (!YGFloatIsUndefined(child->style.aspectRatio)) {
-        childWidth = (childHeight - marginColumn) * child->style.aspectRatio;
-        childWidthMeasureMode = YGMeasureModeExactly;
-      }
-    }
-
-    YGConstrainMaxSizeForMode(
-        child, YGFlexDirectionRow, parentWidth, parentWidth, &childWidthMeasureMode, &childWidth);
-    YGConstrainMaxSizeForMode(child,
-                              YGFlexDirectionColumn,
-                              parentHeight,
-                              parentWidth,
-                              &childHeightMeasureMode,
-                              &childHeight);
-
-    // Measure the child
-    YGLayoutNodeInternal(child,
-                         childWidth,
-                         childHeight,
-                         direction,
-                         childWidthMeasureMode,
-                         childHeightMeasureMode,
-                         parentWidth,
-                         parentHeight,
-                         false,
-                         "measure",
-                         config);
-
-    child->layout.computedFlexBasis =
-        fmaxf(child->layout.measuredDimensions[dim[mainAxis]],
-              YGNodePaddingAndBorderForAxis(child, mainAxis, parentWidth));
-  }
-
-  child->layout.computedFlexBasisGeneration = gCurrentGenerationCount;
-}
-
-static void YGNodeAbsoluteLayoutChild(const YGNodeRef node,
-                                      const YGNodeRef child,
-                                      const float width,
-                                      const YGMeasureMode widthMode,
-                                      const float height,
-                                      const YGDirection direction,
-                                      const YGConfigRef config) {
-  const YGFlexDirection mainAxis = YGResolveFlexDirection(node->style.flexDirection, direction);
-  const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction);
-  const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
-
-  float childWidth = YGUndefined;
-  float childHeight = YGUndefined;
-  YGMeasureMode childWidthMeasureMode = YGMeasureModeUndefined;
-  YGMeasureMode childHeightMeasureMode = YGMeasureModeUndefined;
-
-  const float marginRow = YGNodeMarginForAxis(child, YGFlexDirectionRow, width);
-  const float marginColumn = YGNodeMarginForAxis(child, YGFlexDirectionColumn, width);
-
-  if (YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, width)) {
-    childWidth = YGResolveValue(child->resolvedDimensions[YGDimensionWidth], width) + marginRow;
-  } else {
-    // If the child doesn't have a specified width, compute the width based
-    // on the left/right
-    // offsets if they're defined.
-    if (YGNodeIsLeadingPosDefined(child, YGFlexDirectionRow) &&
-        YGNodeIsTrailingPosDefined(child, YGFlexDirectionRow)) {
-      childWidth = node->layout.measuredDimensions[YGDimensionWidth] -
-                   (YGNodeLeadingBorder(node, YGFlexDirectionRow) +
-                    YGNodeTrailingBorder(node, YGFlexDirectionRow)) -
-                   (YGNodeLeadingPosition(child, YGFlexDirectionRow, width) +
-                    YGNodeTrailingPosition(child, YGFlexDirectionRow, width));
-      childWidth = YGNodeBoundAxis(child, YGFlexDirectionRow, childWidth, width, width);
-    }
-  }
-
-  if (YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, height)) {
-    childHeight =
-        YGResolveValue(child->resolvedDimensions[YGDimensionHeight], height) + marginColumn;
-  } else {
-    // If the child doesn't have a specified height, compute the height
-    // based on the top/bottom
-    // offsets if they're defined.
-    if (YGNodeIsLeadingPosDefined(child, YGFlexDirectionColumn) &&
-        YGNodeIsTrailingPosDefined(child, YGFlexDirectionColumn)) {
-      childHeight = node->layout.measuredDimensions[YGDimensionHeight] -
-                    (YGNodeLeadingBorder(node, YGFlexDirectionColumn) +
-                     YGNodeTrailingBorder(node, YGFlexDirectionColumn)) -
-                    (YGNodeLeadingPosition(child, YGFlexDirectionColumn, height) +
-                     YGNodeTrailingPosition(child, YGFlexDirectionColumn, height));
-      childHeight = YGNodeBoundAxis(child, YGFlexDirectionColumn, childHeight, height, width);
-    }
-  }
-
-  // Exactly one dimension needs to be defined for us to be able to do aspect ratio
-  // calculation. One dimension being the anchor and the other being flexible.
-  if (YGFloatIsUndefined(childWidth) ^ YGFloatIsUndefined(childHeight)) {
-    if (!YGFloatIsUndefined(child->style.aspectRatio)) {
-      if (YGFloatIsUndefined(childWidth)) {
-        childWidth = marginRow + (childHeight - marginColumn) * child->style.aspectRatio;
-      } else if (YGFloatIsUndefined(childHeight)) {
-        childHeight = marginColumn + (childWidth - marginRow) / child->style.aspectRatio;
-      }
-    }
-  }
-
-  // If we're still missing one or the other dimension, measure the content.
-  if (YGFloatIsUndefined(childWidth) || YGFloatIsUndefined(childHeight)) {
-    childWidthMeasureMode =
-        YGFloatIsUndefined(childWidth) ? YGMeasureModeUndefined : YGMeasureModeExactly;
-    childHeightMeasureMode =
-        YGFloatIsUndefined(childHeight) ? YGMeasureModeUndefined : YGMeasureModeExactly;
-
-    // If the size of the parent is defined then try to constrain the absolute child to that size
-    // as well. This allows text within the absolute child to wrap to the size of its parent.
-    // This is the same behavior as many browsers implement.
-    if (!isMainAxisRow && YGFloatIsUndefined(childWidth) && widthMode != YGMeasureModeUndefined &&
-        width > 0) {
-      childWidth = width;
-      childWidthMeasureMode = YGMeasureModeAtMost;
-    }
-
-    YGLayoutNodeInternal(child,
-                         childWidth,
-                         childHeight,
-                         direction,
-                         childWidthMeasureMode,
-                         childHeightMeasureMode,
-                         childWidth,
-                         childHeight,
-                         false,
-                         "abs-measure",
-                         config);
-    childWidth = child->layout.measuredDimensions[YGDimensionWidth] +
-                 YGNodeMarginForAxis(child, YGFlexDirectionRow, width);
-    childHeight = child->layout.measuredDimensions[YGDimensionHeight] +
-                  YGNodeMarginForAxis(child, YGFlexDirectionColumn, width);
-  }
-
-  YGLayoutNodeInternal(child,
-                       childWidth,
-                       childHeight,
-                       direction,
-                       YGMeasureModeExactly,
-                       YGMeasureModeExactly,
-                       childWidth,
-                       childHeight,
-                       true,
-                       "abs-layout",
-                       config);
-
-  if (YGNodeIsTrailingPosDefined(child, mainAxis) && !YGNodeIsLeadingPosDefined(child, mainAxis)) {
-    child->layout.position[leading[mainAxis]] =
-        node->layout.measuredDimensions[dim[mainAxis]] -
-        child->layout.measuredDimensions[dim[mainAxis]] - YGNodeTrailingBorder(node, mainAxis) -
-        YGNodeTrailingMargin(child, mainAxis, width) -
-        YGNodeTrailingPosition(child, mainAxis, isMainAxisRow ? width : height);
-  } else if (!YGNodeIsLeadingPosDefined(child, mainAxis) &&
-             node->style.justifyContent == YGJustifyCenter) {
-    child->layout.position[leading[mainAxis]] = (node->layout.measuredDimensions[dim[mainAxis]] -
-                                                 child->layout.measuredDimensions[dim[mainAxis]]) /
-                                                2.0f;
-  } else if (!YGNodeIsLeadingPosDefined(child, mainAxis) &&
-             node->style.justifyContent == YGJustifyFlexEnd) {
-    child->layout.position[leading[mainAxis]] = (node->layout.measuredDimensions[dim[mainAxis]] -
-                                                 child->layout.measuredDimensions[dim[mainAxis]]);
-  }
-
-  if (YGNodeIsTrailingPosDefined(child, crossAxis) &&
-      !YGNodeIsLeadingPosDefined(child, crossAxis)) {
-    child->layout.position[leading[crossAxis]] =
-        node->layout.measuredDimensions[dim[crossAxis]] -
-        child->layout.measuredDimensions[dim[crossAxis]] - YGNodeTrailingBorder(node, crossAxis) -
-        YGNodeTrailingMargin(child, crossAxis, width) -
-        YGNodeTrailingPosition(child, crossAxis, isMainAxisRow ? height : width);
-  } else if (!YGNodeIsLeadingPosDefined(child, crossAxis) &&
-             YGNodeAlignItem(node, child) == YGAlignCenter) {
-    child->layout.position[leading[crossAxis]] =
-        (node->layout.measuredDimensions[dim[crossAxis]] -
-         child->layout.measuredDimensions[dim[crossAxis]]) /
-        2.0f;
-  } else if (!YGNodeIsLeadingPosDefined(child, crossAxis) &&
-             ((YGNodeAlignItem(node, child) == YGAlignFlexEnd) ^
-              (node->style.flexWrap == YGWrapWrapReverse))) {
-    child->layout.position[leading[crossAxis]] = (node->layout.measuredDimensions[dim[crossAxis]] -
-                                                  child->layout.measuredDimensions[dim[crossAxis]]);
-  }
-}
-
-static void YGNodeWithMeasureFuncSetMeasuredDimensions(const YGNodeRef node,
-                                                       const float availableWidth,
-                                                       const float availableHeight,
-                                                       const YGMeasureMode widthMeasureMode,
-                                                       const YGMeasureMode heightMeasureMode,
-                                                       const float parentWidth,
-                                                       const float parentHeight) {
-  YGAssertWithNode(
-      node,
-      node->measure != nullptr,
-      "Expected node to have custom measure function");
-
-  const float paddingAndBorderAxisRow =
-      YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, availableWidth);
-  const float paddingAndBorderAxisColumn =
-      YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, availableWidth);
-  const float marginAxisRow = YGNodeMarginForAxis(node, YGFlexDirectionRow, availableWidth);
-  const float marginAxisColumn = YGNodeMarginForAxis(node, YGFlexDirectionColumn, availableWidth);
-
-  // We want to make sure we don't call measure with negative size
-  const float innerWidth = YGFloatIsUndefined(availableWidth)
-                               ? availableWidth
-                               : fmaxf(0, availableWidth - marginAxisRow - paddingAndBorderAxisRow);
-  const float innerHeight =
-      YGFloatIsUndefined(availableHeight)
-          ? availableHeight
-          : fmaxf(0, availableHeight - marginAxisColumn - paddingAndBorderAxisColumn);
-
-  if (widthMeasureMode == YGMeasureModeExactly && heightMeasureMode == YGMeasureModeExactly) {
-    // Don't bother sizing the text if both dimensions are already defined.
-    node->layout.measuredDimensions[YGDimensionWidth] = YGNodeBoundAxis(
-        node, YGFlexDirectionRow, availableWidth - marginAxisRow, parentWidth, parentWidth);
-    node->layout.measuredDimensions[YGDimensionHeight] = YGNodeBoundAxis(
-        node, YGFlexDirectionColumn, availableHeight - marginAxisColumn, parentHeight, parentWidth);
-  } else {
-    // Measure the text under the current constraints.
-    const YGSize measuredSize =
-        node->measure(node, innerWidth, widthMeasureMode, innerHeight, heightMeasureMode);
-
-    node->layout.measuredDimensions[YGDimensionWidth] =
-        YGNodeBoundAxis(node,
-                        YGFlexDirectionRow,
-                        (widthMeasureMode == YGMeasureModeUndefined ||
-                         widthMeasureMode == YGMeasureModeAtMost)
-                            ? measuredSize.width + paddingAndBorderAxisRow
-                            : availableWidth - marginAxisRow,
-                        parentWidth,
-                        parentWidth);
-    node->layout.measuredDimensions[YGDimensionHeight] =
-        YGNodeBoundAxis(node,
-                        YGFlexDirectionColumn,
-                        (heightMeasureMode == YGMeasureModeUndefined ||
-                         heightMeasureMode == YGMeasureModeAtMost)
-                            ? measuredSize.height + paddingAndBorderAxisColumn
-                            : availableHeight - marginAxisColumn,
-                        parentHeight,
-                        parentWidth);
-  }
-}
-
-// For nodes with no children, use the available values if they were provided,
-// or the minimum size as indicated by the padding and border sizes.
-static void YGNodeEmptyContainerSetMeasuredDimensions(const YGNodeRef node,
-                                                      const float availableWidth,
-                                                      const float availableHeight,
-                                                      const YGMeasureMode widthMeasureMode,
-                                                      const YGMeasureMode heightMeasureMode,
-                                                      const float parentWidth,
-                                                      const float parentHeight) {
-  const float paddingAndBorderAxisRow =
-      YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, parentWidth);
-  const float paddingAndBorderAxisColumn =
-      YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, parentWidth);
-  const float marginAxisRow = YGNodeMarginForAxis(node, YGFlexDirectionRow, parentWidth);
-  const float marginAxisColumn = YGNodeMarginForAxis(node, YGFlexDirectionColumn, parentWidth);
-
-  node->layout.measuredDimensions[YGDimensionWidth] =
-      YGNodeBoundAxis(node,
-                      YGFlexDirectionRow,
-                      (widthMeasureMode == YGMeasureModeUndefined ||
-                       widthMeasureMode == YGMeasureModeAtMost)
-                          ? paddingAndBorderAxisRow
-                          : availableWidth - marginAxisRow,
-                      parentWidth,
-                      parentWidth);
-  node->layout.measuredDimensions[YGDimensionHeight] =
-      YGNodeBoundAxis(node,
-                      YGFlexDirectionColumn,
-                      (heightMeasureMode == YGMeasureModeUndefined ||
-                       heightMeasureMode == YGMeasureModeAtMost)
-                          ? paddingAndBorderAxisColumn
-                          : availableHeight - marginAxisColumn,
-                      parentHeight,
-                      parentWidth);
-}
-
-static bool YGNodeFixedSizeSetMeasuredDimensions(const YGNodeRef node,
-                                                 const float availableWidth,
-                                                 const float availableHeight,
-                                                 const YGMeasureMode widthMeasureMode,
-                                                 const YGMeasureMode heightMeasureMode,
-                                                 const float parentWidth,
-                                                 const float parentHeight) {
-  if ((widthMeasureMode == YGMeasureModeAtMost && availableWidth <= 0.0f) ||
-      (heightMeasureMode == YGMeasureModeAtMost && availableHeight <= 0.0f) ||
-      (widthMeasureMode == YGMeasureModeExactly && heightMeasureMode == YGMeasureModeExactly)) {
-    const float marginAxisColumn = YGNodeMarginForAxis(node, YGFlexDirectionColumn, parentWidth);
-    const float marginAxisRow = YGNodeMarginForAxis(node, YGFlexDirectionRow, parentWidth);
-
-    node->layout.measuredDimensions[YGDimensionWidth] =
-        YGNodeBoundAxis(node,
-                        YGFlexDirectionRow,
-                        YGFloatIsUndefined(availableWidth) ||
-                                (widthMeasureMode == YGMeasureModeAtMost && availableWidth < 0.0f)
-                            ? 0.0f
-                            : availableWidth - marginAxisRow,
-                        parentWidth,
-                        parentWidth);
-
-    node->layout.measuredDimensions[YGDimensionHeight] =
-        YGNodeBoundAxis(node,
-                        YGFlexDirectionColumn,
-                        YGFloatIsUndefined(availableHeight) ||
-                                (heightMeasureMode == YGMeasureModeAtMost && availableHeight < 0.0f)
-                            ? 0.0f
-                            : availableHeight - marginAxisColumn,
-                        parentHeight,
-                        parentWidth);
-
-    return true;
-  }
-
-  return false;
-}
-
-static void YGZeroOutLayoutRecursivly(const YGNodeRef node) {
-  memset(&(node->layout), 0, sizeof(YGLayout));
-  node->hasNewLayout = true;
-  YGCloneChildrenIfNeeded(node);
-  const uint32_t childCount = YGNodeGetChildCount(node);
-  for (uint32_t i = 0; i < childCount; i++) {
-    const YGNodeRef child = node->children[i];
-    YGZeroOutLayoutRecursivly(child);
-  }
-}
-
-//
-// This is the main routine that implements a subset of the flexbox layout
-// algorithm
-// described in the W3C YG documentation: https://www.w3.org/TR/YG3-flexbox/.
-//
-// Limitations of this algorithm, compared to the full standard:
-//  * Display property is always assumed to be 'flex' except for Text nodes,
-//  which
-//    are assumed to be 'inline-flex'.
-//  * The 'zIndex' property (or any form of z ordering) is not supported. Nodes
-//  are
-//    stacked in document order.
-//  * The 'order' property is not supported. The order of flex items is always
-//  defined
-//    by document order.
-//  * The 'visibility' property is always assumed to be 'visible'. Values of
-//  'collapse'
-//    and 'hidden' are not supported.
-//  * There is no support for forced breaks.
-//  * It does not support vertical inline directions (top-to-bottom or
-//  bottom-to-top text).
-//
-// Deviations from standard:
-//  * Section 4.5 of the spec indicates that all flex items have a default
-//  minimum
-//    main size. For text blocks, for example, this is the width of the widest
-//    word.
-//    Calculating the minimum width is expensive, so we forego it and assume a
-//    default
-//    minimum main size of 0.
-//  * Min/Max sizes in the main axis are not honored when resolving flexible
-//  lengths.
-//  * The spec indicates that the default value for 'flexDirection' is 'row',
-//  but
-//    the algorithm below assumes a default of 'column'.
-//
-// Input parameters:
-//    - node: current node to be sized and layed out
-//    - availableWidth & availableHeight: available size to be used for sizing
-//    the node
-//      or YGUndefined if the size is not available; interpretation depends on
-//      layout
-//      flags
-//    - parentDirection: the inline (text) direction within the parent
-//    (left-to-right or
-//      right-to-left)
-//    - widthMeasureMode: indicates the sizing rules for the width (see below
-//    for explanation)
-//    - heightMeasureMode: indicates the sizing rules for the height (see below
-//    for explanation)
-//    - performLayout: specifies whether the caller is interested in just the
-//    dimensions
-//      of the node or it requires the entire node and its subtree to be layed
-//      out
-//      (with final positions)
-//
-// Details:
-//    This routine is called recursively to lay out subtrees of flexbox
-//    elements. It uses the
-//    information in node.style, which is treated as a read-only input. It is
-//    responsible for
-//    setting the layout.direction and layout.measuredDimensions fields for the
-//    input node as well
-//    as the layout.position and layout.lineIndex fields for its child nodes.
-//    The
-//    layout.measuredDimensions field includes any border or padding for the
-//    node but does
-//    not include margins.
-//
-//    The spec describes four different layout modes: "fill available", "max
-//    content", "min
-//    content",
-//    and "fit content". Of these, we don't use "min content" because we don't
-//    support default
-//    minimum main sizes (see above for details). Each of our measure modes maps
-//    to a layout mode
-//    from the spec (https://www.w3.org/TR/YG3-sizing/#terms):
-//      - YGMeasureModeUndefined: max content
-//      - YGMeasureModeExactly: fill available
-//      - YGMeasureModeAtMost: fit content
-//
-//    When calling YGNodelayoutImpl and YGLayoutNodeInternal, if the caller passes
-//    an available size of
-//    undefined then it must also pass a measure mode of YGMeasureModeUndefined
-//    in that dimension.
-//
-static void YGNodelayoutImpl(const YGNodeRef node,
-                             const float availableWidth,
-                             const float availableHeight,
-                             const YGDirection parentDirection,
-                             const YGMeasureMode widthMeasureMode,
-                             const YGMeasureMode heightMeasureMode,
-                             const float parentWidth,
-                             const float parentHeight,
-                             const bool performLayout,
-                             const YGConfigRef config) {
-  YGAssertWithNode(node,
-                   YGFloatIsUndefined(availableWidth) ? widthMeasureMode == YGMeasureModeUndefined
-                                                      : true,
-                   "availableWidth is indefinite so widthMeasureMode must be "
-                   "YGMeasureModeUndefined");
-  YGAssertWithNode(node,
-                   YGFloatIsUndefined(availableHeight) ? heightMeasureMode == YGMeasureModeUndefined
-                                                       : true,
-                   "availableHeight is indefinite so heightMeasureMode must be "
-                   "YGMeasureModeUndefined");
-
-  // Set the resolved resolution in the node's layout.
-  const YGDirection direction = YGNodeResolveDirection(node, parentDirection);
-  node->layout.direction = direction;
-
-  const YGFlexDirection flexRowDirection = YGResolveFlexDirection(YGFlexDirectionRow, direction);
-  const YGFlexDirection flexColumnDirection =
-      YGResolveFlexDirection(YGFlexDirectionColumn, direction);
-
-  node->layout.margin[YGEdgeStart] = YGNodeLeadingMargin(node, flexRowDirection, parentWidth);
-  node->layout.margin[YGEdgeEnd] = YGNodeTrailingMargin(node, flexRowDirection, parentWidth);
-  node->layout.margin[YGEdgeTop] = YGNodeLeadingMargin(node, flexColumnDirection, parentWidth);
-  node->layout.margin[YGEdgeBottom] = YGNodeTrailingMargin(node, flexColumnDirection, parentWidth);
-
-  node->layout.border[YGEdgeStart] = YGNodeLeadingBorder(node, flexRowDirection);
-  node->layout.border[YGEdgeEnd] = YGNodeTrailingBorder(node, flexRowDirection);
-  node->layout.border[YGEdgeTop] = YGNodeLeadingBorder(node, flexColumnDirection);
-  node->layout.border[YGEdgeBottom] = YGNodeTrailingBorder(node, flexColumnDirection);
-
-  node->layout.padding[YGEdgeStart] = YGNodeLeadingPadding(node, flexRowDirection, parentWidth);
-  node->layout.padding[YGEdgeEnd] = YGNodeTrailingPadding(node, flexRowDirection, parentWidth);
-  node->layout.padding[YGEdgeTop] = YGNodeLeadingPadding(node, flexColumnDirection, parentWidth);
-  node->layout.padding[YGEdgeBottom] =
-      YGNodeTrailingPadding(node, flexColumnDirection, parentWidth);
-
-  if (node->measure) {
-    YGNodeWithMeasureFuncSetMeasuredDimensions(node,
-                                               availableWidth,
-                                               availableHeight,
-                                               widthMeasureMode,
-                                               heightMeasureMode,
-                                               parentWidth,
-                                               parentHeight);
-    return;
-  }
-
-  const uint32_t childCount = node->children.size();
-  if (childCount == 0) {
-    YGNodeEmptyContainerSetMeasuredDimensions(node,
-                                              availableWidth,
-                                              availableHeight,
-                                              widthMeasureMode,
-                                              heightMeasureMode,
-                                              parentWidth,
-                                              parentHeight);
-    return;
-  }
-
-  // If we're not being asked to perform a full layout we can skip the algorithm if we already know
-  // the size
-  if (!performLayout && YGNodeFixedSizeSetMeasuredDimensions(node,
-                                                             availableWidth,
-                                                             availableHeight,
-                                                             widthMeasureMode,
-                                                             heightMeasureMode,
-                                                             parentWidth,
-                                                             parentHeight)) {
-    return;
-  }
-
-  // At this point we know we're going to perform work. Ensure that each child has a mutable copy.
-  YGCloneChildrenIfNeeded(node);
-
-  // Reset layout flags, as they could have changed.
-  node->layout.hadOverflow = false;
-
-  // STEP 1: CALCULATE VALUES FOR REMAINDER OF ALGORITHM
-  const YGFlexDirection mainAxis = YGResolveFlexDirection(node->style.flexDirection, direction);
-  const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction);
-  const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
-  const YGJustify justifyContent = node->style.justifyContent;
-  const bool isNodeFlexWrap = node->style.flexWrap != YGWrapNoWrap;
-
-  const float mainAxisParentSize = isMainAxisRow ? parentWidth : parentHeight;
-  const float crossAxisParentSize = isMainAxisRow ? parentHeight : parentWidth;
-
-  YGNodeRef firstAbsoluteChild = nullptr;
-  YGNodeRef currentAbsoluteChild = nullptr;
-
-  const float leadingPaddingAndBorderMain =
-      YGNodeLeadingPaddingAndBorder(node, mainAxis, parentWidth);
-  const float trailingPaddingAndBorderMain =
-      YGNodeTrailingPaddingAndBorder(node, mainAxis, parentWidth);
-  const float leadingPaddingAndBorderCross =
-      YGNodeLeadingPaddingAndBorder(node, crossAxis, parentWidth);
-  const float paddingAndBorderAxisMain = YGNodePaddingAndBorderForAxis(node, mainAxis, parentWidth);
-  const float paddingAndBorderAxisCross =
-      YGNodePaddingAndBorderForAxis(node, crossAxis, parentWidth);
-
-  YGMeasureMode measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode;
-  YGMeasureMode measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode;
-
-  const float paddingAndBorderAxisRow =
-      isMainAxisRow ? paddingAndBorderAxisMain : paddingAndBorderAxisCross;
-  const float paddingAndBorderAxisColumn =
-      isMainAxisRow ? paddingAndBorderAxisCross : paddingAndBorderAxisMain;
-
-  const float marginAxisRow = YGNodeMarginForAxis(node, YGFlexDirectionRow, parentWidth);
-  const float marginAxisColumn = YGNodeMarginForAxis(node, YGFlexDirectionColumn, parentWidth);
-
-  // STEP 2: DETERMINE AVAILABLE SIZE IN MAIN AND CROSS DIRECTIONS
-  const float minInnerWidth =
-      YGResolveValue(&node->style.minDimensions[YGDimensionWidth], parentWidth) -
-      paddingAndBorderAxisRow;
-  const float maxInnerWidth =
-      YGResolveValue(&node->style.maxDimensions[YGDimensionWidth], parentWidth) -
-      paddingAndBorderAxisRow;
-  const float minInnerHeight =
-      YGResolveValue(&node->style.minDimensions[YGDimensionHeight], parentHeight) -
-      paddingAndBorderAxisColumn;
-  const float maxInnerHeight =
-      YGResolveValue(&node->style.maxDimensions[YGDimensionHeight], parentHeight) -
-      paddingAndBorderAxisColumn;
-  const float minInnerMainDim = isMainAxisRow ? minInnerWidth : minInnerHeight;
-  const float maxInnerMainDim = isMainAxisRow ? maxInnerWidth : maxInnerHeight;
-
-  // Max dimension overrides predefined dimension value; Min dimension in turn overrides both of the
-  // above
-  float availableInnerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow;
-  if (!YGFloatIsUndefined(availableInnerWidth)) {
-    // We want to make sure our available width does not violate min and max constraints
-    availableInnerWidth = fmaxf(fminf(availableInnerWidth, maxInnerWidth), minInnerWidth);
-  }
-
-  float availableInnerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn;
-  if (!YGFloatIsUndefined(availableInnerHeight)) {
-    // We want to make sure our available height does not violate min and max constraints
-    availableInnerHeight = fmaxf(fminf(availableInnerHeight, maxInnerHeight), minInnerHeight);
-  }
-
-  float availableInnerMainDim = isMainAxisRow ? availableInnerWidth : availableInnerHeight;
-  const float availableInnerCrossDim = isMainAxisRow ? availableInnerHeight : availableInnerWidth;
-
-  // If there is only one child with flexGrow + flexShrink it means we can set the
-  // computedFlexBasis to 0 instead of measuring and shrinking / flexing the child to exactly
-  // match the remaining space
-  YGNodeRef singleFlexChild = nullptr;
-  if (measureModeMainDim == YGMeasureModeExactly) {
-    for (uint32_t i = 0; i < childCount; i++) {
-      const YGNodeRef child = YGNodeGetChild(node, i);
-      if (singleFlexChild) {
-        if (YGNodeIsFlex(child)) {
-          // There is already a flexible child, abort.
-          singleFlexChild = nullptr;
-          break;
-        }
-      } else if (YGResolveFlexGrow(child) > 0.0f && YGNodeResolveFlexShrink(child) > 0.0f) {
-        singleFlexChild = child;
-      }
-    }
-  }
-
-  float totalOuterFlexBasis = 0;
-
-  // STEP 3: DETERMINE FLEX BASIS FOR EACH ITEM
-  for (uint32_t i = 0; i < childCount; i++) {
-    const YGNodeRef child = node->children[i];
-    if (child->style.display == YGDisplayNone) {
-      YGZeroOutLayoutRecursivly(child);
-      child->hasNewLayout = true;
-      child->isDirty = false;
-      continue;
-    }
-    YGResolveDimensions(child);
-    if (performLayout) {
-      // Set the initial position (relative to the parent).
-      const YGDirection childDirection = YGNodeResolveDirection(child, direction);
-      YGNodeSetPosition(child,
-                        childDirection,
-                        availableInnerMainDim,
-                        availableInnerCrossDim,
-                        availableInnerWidth);
-    }
-
-    // Absolute-positioned children don't participate in flex layout. Add them
-    // to a list that we can process later.
-    if (child->style.positionType == YGPositionTypeAbsolute) {
-      // Store a private linked list of absolutely positioned children
-      // so that we can efficiently traverse them later.
-      if (firstAbsoluteChild == nullptr) {
-        firstAbsoluteChild = child;
-      }
-      if (currentAbsoluteChild != nullptr) {
-        currentAbsoluteChild->nextChild = child;
-      }
-      currentAbsoluteChild = child;
-      child->nextChild = nullptr;
-    } else {
-      if (child == singleFlexChild) {
-        child->layout.computedFlexBasisGeneration = gCurrentGenerationCount;
-        child->layout.computedFlexBasis = 0;
-      } else {
-        YGNodeComputeFlexBasisForChild(node,
-                                       child,
-                                       availableInnerWidth,
-                                       widthMeasureMode,
-                                       availableInnerHeight,
-                                       availableInnerWidth,
-                                       availableInnerHeight,
-                                       heightMeasureMode,
-                                       direction,
-                                       config);
-      }
-    }
-
-    totalOuterFlexBasis +=
-        child->layout.computedFlexBasis + YGNodeMarginForAxis(child, mainAxis, availableInnerWidth);
-    ;
-  }
-
-  const bool flexBasisOverflows = measureModeMainDim == YGMeasureModeUndefined
-                                      ? false
-                                      : totalOuterFlexBasis > availableInnerMainDim;
-  if (isNodeFlexWrap && flexBasisOverflows && measureModeMainDim == YGMeasureModeAtMost) {
-    measureModeMainDim = YGMeasureModeExactly;
-  }
-
-  // STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
-
-  // Indexes of children that represent the first and last items in the line.
-  uint32_t startOfLineIndex = 0;
-  uint32_t endOfLineIndex = 0;
-
-  // Number of lines.
-  uint32_t lineCount = 0;
-
-  // Accumulated cross dimensions of all lines so far.
-  float totalLineCrossDim = 0;
-
-  // Max main dimension of all the lines.
-  float maxLineMainDim = 0;
-
-  for (; endOfLineIndex < childCount; lineCount++, startOfLineIndex = endOfLineIndex) {
-    // Number of items on the currently line. May be different than the
-    // difference
-    // between start and end indicates because we skip over absolute-positioned
-    // items.
-    uint32_t itemsOnLine = 0;
-
-    // sizeConsumedOnCurrentLine is accumulation of the dimensions and margin
-    // of all the children on the current line. 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 sizeConsumedOnCurrentLine = 0;
-    float sizeConsumedOnCurrentLineIncludingMinConstraint = 0;
-
-    float totalFlexGrowFactors = 0;
-    float totalFlexShrinkScaledFactors = 0;
-
-    // Maintain a linked list of the child nodes that can shrink and/or grow.
-    YGNodeRef firstRelativeChild = nullptr;
-    YGNodeRef currentRelativeChild = nullptr;
-
-    // Add items to the current line until it's full or we run out of items.
-    for (uint32_t i = startOfLineIndex; i < childCount; i++, endOfLineIndex++) {
-      const YGNodeRef child = node->children[i];
-      if (child->style.display == YGDisplayNone) {
-        continue;
-      }
-      child->lineIndex = lineCount;
-
-      if (child->style.positionType != YGPositionTypeAbsolute) {
-        const float childMarginMainAxis = YGNodeMarginForAxis(child, mainAxis, availableInnerWidth);
-        const float flexBasisWithMaxConstraints =
-            fminf(YGResolveValue(&child->style.maxDimensions[dim[mainAxis]], mainAxisParentSize),
-                  child->layout.computedFlexBasis);
-        const float flexBasisWithMinAndMaxConstraints =
-            fmaxf(YGResolveValue(&child->style.minDimensions[dim[mainAxis]], mainAxisParentSize),
-                  flexBasisWithMaxConstraints);
-
-        // If this is a multi-line flow and this item pushes us over the
-        // available size, we've
-        // hit the end of the current line. Break out of the loop and lay out
-        // the current line.
-        if (sizeConsumedOnCurrentLineIncludingMinConstraint + flexBasisWithMinAndMaxConstraints +
-                    childMarginMainAxis >
-                availableInnerMainDim &&
-            isNodeFlexWrap && itemsOnLine > 0) {
-          break;
-        }
-
-        sizeConsumedOnCurrentLineIncludingMinConstraint +=
-            flexBasisWithMinAndMaxConstraints + childMarginMainAxis;
-        sizeConsumedOnCurrentLine += flexBasisWithMinAndMaxConstraints + childMarginMainAxis;
-        itemsOnLine++;
-
-        if (YGNodeIsFlex(child)) {
-          totalFlexGrowFactors += YGResolveFlexGrow(child);
-
-          // Unlike the grow factor, the shrink factor is scaled relative to the child dimension.
-          totalFlexShrinkScaledFactors +=
-              -YGNodeResolveFlexShrink(child) * child->layout.computedFlexBasis;
-        }
-
-        // Store a private linked list of children that need to be layed out.
-        if (firstRelativeChild == nullptr) {
-          firstRelativeChild = child;
-        }
-        if (currentRelativeChild != nullptr) {
-          currentRelativeChild->nextChild = child;
-        }
-        currentRelativeChild = child;
-        child->nextChild = nullptr;
-      }
-    }
-
-    // The total flex factor needs to be floored to 1.
-    if (totalFlexGrowFactors > 0 && totalFlexGrowFactors < 1) {
-      totalFlexGrowFactors = 1;
-    }
-
-    // The total flex shrink factor needs to be floored to 1.
-    if (totalFlexShrinkScaledFactors > 0 && totalFlexShrinkScaledFactors < 1) {
-      totalFlexShrinkScaledFactors = 1;
-    }
-
-    // If we don't need to measure the cross axis, we can skip the entire flex
-    // step.
-    const bool canSkipFlex = !performLayout && measureModeCrossDim == YGMeasureModeExactly;
-
-    // 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;
-
-    // STEP 5: RESOLVING FLEXIBLE LENGTHS ON MAIN AXIS
-    // Calculate the remaining available space that needs to be allocated.
-    // If the main dimension size isn't known, it is computed based on
-    // the line length, so there's no more space left to distribute.
-
-    bool sizeBasedOnContent = false;
-    // If we don't measure with exact main dimension we want to ensure we don't violate min and max
-    if (measureModeMainDim != YGMeasureModeExactly) {
-      if (!YGFloatIsUndefined(minInnerMainDim) && sizeConsumedOnCurrentLine < minInnerMainDim) {
-        availableInnerMainDim = minInnerMainDim;
-      } else if (!YGFloatIsUndefined(maxInnerMainDim) &&
-                 sizeConsumedOnCurrentLine > maxInnerMainDim) {
-        availableInnerMainDim = maxInnerMainDim;
-      } else {
-        if (!node->config->useLegacyStretchBehaviour &&
-            (totalFlexGrowFactors == 0 || YGResolveFlexGrow(node) == 0)) {
-          // If we don't have any children to flex or we can't flex the node itself,
-          // space we've used is all space we need. Root node also should be shrunk to minimum
-          availableInnerMainDim = sizeConsumedOnCurrentLine;
-        }
-        sizeBasedOnContent = !node->config->useLegacyStretchBehaviour;
-      }
-    }
-
-    float remainingFreeSpace = 0;
-    if (!sizeBasedOnContent && !YGFloatIsUndefined(availableInnerMainDim)) {
-      remainingFreeSpace = availableInnerMainDim - sizeConsumedOnCurrentLine;
-    } else if (sizeConsumedOnCurrentLine < 0) {
-      // availableInnerMainDim is indefinite which means the node is being sized based on its
-      // content.
-      // sizeConsumedOnCurrentLine is negative which means the node will allocate 0 points for
-      // its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
-      remainingFreeSpace = -sizeConsumedOnCurrentLine;
-    }
-
-    const float originalRemainingFreeSpace = remainingFreeSpace;
-    float deltaFreeSpace = 0;
-
-    if (!canSkipFlex) {
-      float childFlexBasis;
-      float flexShrinkScaledFactor;
-      float flexGrowFactor;
-      float baseMainSize;
-      float boundMainSize;
-
-      // Do two passes over the flex items to figure out how to distribute the
-      // remaining space.
-      // The first pass finds the items whose min/max constraints trigger,
-      // freezes them at those
-      // sizes, and excludes those sizes from the remaining space. The second
-      // pass sets the size
-      // of each flexible item. It distributes the remaining space amongst the
-      // items whose min/max
-      // constraints didn't trigger in pass 1. For the other items, it sets
-      // their sizes by forcing
-      // their min/max constraints to trigger again.
-      //
-      // This two pass approach for resolving min/max constraints deviates from
-      // the spec. The
-      // spec (https://www.w3.org/TR/YG-flexbox-1/#resolve-flexible-lengths)
-      // describes a process
-      // that needs to be repeated a variable number of times. The algorithm
-      // implemented here
-      // won't handle all cases but it was simpler to implement and it mitigates
-      // performance
-      // concerns because we know exactly how many passes it'll do.
-
-      // First pass: detect the flex items whose min/max constraints trigger
-      float deltaFlexShrinkScaledFactors = 0;
-      float deltaFlexGrowFactors = 0;
-      currentRelativeChild = firstRelativeChild;
-      while (currentRelativeChild != nullptr) {
-        childFlexBasis =
-            fminf(YGResolveValue(&currentRelativeChild->style.maxDimensions[dim[mainAxis]],
-                                 mainAxisParentSize),
-                  fmaxf(YGResolveValue(&currentRelativeChild->style.minDimensions[dim[mainAxis]],
-                                       mainAxisParentSize),
-                        currentRelativeChild->layout.computedFlexBasis));
-
-        if (remainingFreeSpace < 0) {
-          flexShrinkScaledFactor = -YGNodeResolveFlexShrink(currentRelativeChild) * childFlexBasis;
-
-          // Is this child able to shrink?
-          if (flexShrinkScaledFactor != 0) {
-            baseMainSize =
-                childFlexBasis +
-                remainingFreeSpace / totalFlexShrinkScaledFactors * flexShrinkScaledFactor;
-            boundMainSize = YGNodeBoundAxis(currentRelativeChild,
-                                            mainAxis,
-                                            baseMainSize,
-                                            availableInnerMainDim,
-                                            availableInnerWidth);
-            if (baseMainSize != boundMainSize) {
-              // By excluding this item's size and flex factor from remaining,
-              // this item's
-              // min/max constraints should also trigger in the second pass
-              // resulting in the
-              // item's size calculation being identical in the first and second
-              // passes.
-              deltaFreeSpace -= boundMainSize - childFlexBasis;
-              deltaFlexShrinkScaledFactors -= flexShrinkScaledFactor;
-            }
-          }
-        } else if (remainingFreeSpace > 0) {
-          flexGrowFactor = YGResolveFlexGrow(currentRelativeChild);
-
-          // Is this child able to grow?
-          if (flexGrowFactor != 0) {
-            baseMainSize =
-                childFlexBasis + remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor;
-            boundMainSize = YGNodeBoundAxis(currentRelativeChild,
-                                            mainAxis,
-                                            baseMainSize,
-                                            availableInnerMainDim,
-                                            availableInnerWidth);
-
-            if (baseMainSize != boundMainSize) {
-              // By excluding this item's size and flex factor from remaining,
-              // this item's
-              // min/max constraints should also trigger in the second pass
-              // resulting in the
-              // item's size calculation being identical in the first and second
-              // passes.
-              deltaFreeSpace -= boundMainSize - childFlexBasis;
-              deltaFlexGrowFactors -= flexGrowFactor;
-            }
-          }
-        }
-
-        currentRelativeChild = currentRelativeChild->nextChild;
-      }
-
-      totalFlexShrinkScaledFactors += deltaFlexShrinkScaledFactors;
-      totalFlexGrowFactors += deltaFlexGrowFactors;
-      remainingFreeSpace += deltaFreeSpace;
-
-      // Second pass: resolve the sizes of the flexible items
-      deltaFreeSpace = 0;
-      currentRelativeChild = firstRelativeChild;
-      while (currentRelativeChild != nullptr) {
-        childFlexBasis =
-            fminf(YGResolveValue(&currentRelativeChild->style.maxDimensions[dim[mainAxis]],
-                                 mainAxisParentSize),
-                  fmaxf(YGResolveValue(&currentRelativeChild->style.minDimensions[dim[mainAxis]],
-                                       mainAxisParentSize),
-                        currentRelativeChild->layout.computedFlexBasis));
-        float updatedMainSize = childFlexBasis;
-
-        if (remainingFreeSpace < 0) {
-          flexShrinkScaledFactor = -YGNodeResolveFlexShrink(currentRelativeChild) * childFlexBasis;
-          // Is this child able to shrink?
-          if (flexShrinkScaledFactor != 0) {
-            float childSize;
-
-            if (totalFlexShrinkScaledFactors == 0) {
-              childSize = childFlexBasis + flexShrinkScaledFactor;
-            } else {
-              childSize =
-                  childFlexBasis +
-                  (remainingFreeSpace / totalFlexShrinkScaledFactors) * flexShrinkScaledFactor;
-            }
-
-            updatedMainSize = YGNodeBoundAxis(currentRelativeChild,
-                                              mainAxis,
-                                              childSize,
-                                              availableInnerMainDim,
-                                              availableInnerWidth);
-          }
-        } else if (remainingFreeSpace > 0) {
-          flexGrowFactor = YGResolveFlexGrow(currentRelativeChild);
-
-          // Is this child able to grow?
-          if (flexGrowFactor != 0) {
-            updatedMainSize =
-                YGNodeBoundAxis(currentRelativeChild,
-                                mainAxis,
-                                childFlexBasis +
-                                    remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor,
-                                availableInnerMainDim,
-                                availableInnerWidth);
-          }
-        }
-
-        deltaFreeSpace -= updatedMainSize - childFlexBasis;
-
-        const float marginMain =
-            YGNodeMarginForAxis(currentRelativeChild, mainAxis, availableInnerWidth);
-        const float marginCross =
-            YGNodeMarginForAxis(currentRelativeChild, crossAxis, availableInnerWidth);
-
-        float childCrossSize;
-        float childMainSize = updatedMainSize + marginMain;
-        YGMeasureMode childCrossMeasureMode;
-        YGMeasureMode childMainMeasureMode = YGMeasureModeExactly;
-
-        if (!YGFloatIsUndefined(currentRelativeChild->style.aspectRatio)) {
-          childCrossSize =
-              isMainAxisRow
-                  ? (childMainSize - marginMain) / currentRelativeChild->style.aspectRatio
-                  : (childMainSize - marginMain) * currentRelativeChild->style.aspectRatio;
-          childCrossMeasureMode = YGMeasureModeExactly;
-
-          childCrossSize += marginCross;
-        } else if (!YGFloatIsUndefined(availableInnerCrossDim) &&
-                   !YGNodeIsStyleDimDefined(currentRelativeChild,
-                                            crossAxis,
-                                            availableInnerCrossDim) &&
-                   measureModeCrossDim == YGMeasureModeExactly &&
-                   !(isNodeFlexWrap && flexBasisOverflows) &&
-                   YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch &&
-                   YGMarginLeadingValue(currentRelativeChild, crossAxis)->unit != YGUnitAuto &&
-                   YGMarginTrailingValue(currentRelativeChild, crossAxis)->unit != YGUnitAuto) {
-          childCrossSize = availableInnerCrossDim;
-          childCrossMeasureMode = YGMeasureModeExactly;
-        } else if (!YGNodeIsStyleDimDefined(currentRelativeChild,
-                                            crossAxis,
-                                            availableInnerCrossDim)) {
-          childCrossSize = availableInnerCrossDim;
-          childCrossMeasureMode =
-              YGFloatIsUndefined(childCrossSize) ? YGMeasureModeUndefined : YGMeasureModeAtMost;
-        } else {
-          childCrossSize = YGResolveValue(currentRelativeChild->resolvedDimensions[dim[crossAxis]],
-                                          availableInnerCrossDim) +
-                           marginCross;
-          const bool isLoosePercentageMeasurement =
-              currentRelativeChild->resolvedDimensions[dim[crossAxis]]->unit == YGUnitPercent &&
-              measureModeCrossDim != YGMeasureModeExactly;
-          childCrossMeasureMode = YGFloatIsUndefined(childCrossSize) || isLoosePercentageMeasurement
-                                      ? YGMeasureModeUndefined
-                                      : YGMeasureModeExactly;
-        }
-
-        YGConstrainMaxSizeForMode(currentRelativeChild,
-                                  mainAxis,
-                                  availableInnerMainDim,
-                                  availableInnerWidth,
-                                  &childMainMeasureMode,
-                                  &childMainSize);
-        YGConstrainMaxSizeForMode(currentRelativeChild,
-                                  crossAxis,
-                                  availableInnerCrossDim,
-                                  availableInnerWidth,
-                                  &childCrossMeasureMode,
-                                  &childCrossSize);
-
-        const bool requiresStretchLayout =
-            !YGNodeIsStyleDimDefined(currentRelativeChild, crossAxis, availableInnerCrossDim) &&
-            YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch &&
-            YGMarginLeadingValue(currentRelativeChild, crossAxis)->unit != YGUnitAuto &&
-            YGMarginTrailingValue(currentRelativeChild, crossAxis)->unit != YGUnitAuto;
-
-        const float childWidth = isMainAxisRow ? childMainSize : childCrossSize;
-        const float childHeight = !isMainAxisRow ? childMainSize : childCrossSize;
-
-        const YGMeasureMode childWidthMeasureMode =
-            isMainAxisRow ? childMainMeasureMode : childCrossMeasureMode;
-        const YGMeasureMode childHeightMeasureMode =
-            !isMainAxisRow ? childMainMeasureMode : childCrossMeasureMode;
-
-        // Recursively call the layout algorithm for this child with the updated
-        // main size.
-        YGLayoutNodeInternal(currentRelativeChild,
-                             childWidth,
-                             childHeight,
-                             direction,
-                             childWidthMeasureMode,
-                             childHeightMeasureMode,
-                             availableInnerWidth,
-                             availableInnerHeight,
-                             performLayout && !requiresStretchLayout,
-                             "flex",
-                             config);
-        node->layout.hadOverflow |= currentRelativeChild->layout.hadOverflow;
-
-        currentRelativeChild = currentRelativeChild->nextChild;
-      }
-    }
-
-    remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace;
-    node->layout.hadOverflow |= (remainingFreeSpace < 0);
-
-    // STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
-
-    // At this point, all the children have their dimensions set in the main
-    // axis.
-    // Their dimensions are also set in the cross axis with the exception of
-    // items
-    // that are aligned "stretch". We need to compute these stretch values and
-    // set the final positions.
-
-    // If we are using "at most" rules in the main axis. Calculate the remaining space when
-    // constraint by the min size defined for the main axis.
-
-    if (measureModeMainDim == YGMeasureModeAtMost && remainingFreeSpace > 0) {
-      if (node->style.minDimensions[dim[mainAxis]].unit != YGUnitUndefined &&
-          YGResolveValue(&node->style.minDimensions[dim[mainAxis]], mainAxisParentSize) >= 0) {
-        remainingFreeSpace =
-            fmaxf(0,
-                  YGResolveValue(&node->style.minDimensions[dim[mainAxis]], mainAxisParentSize) -
-                      (availableInnerMainDim - remainingFreeSpace));
-      } else {
-        remainingFreeSpace = 0;
-      }
-    }
-
-    int numberOfAutoMarginsOnCurrentLine = 0;
-    for (uint32_t i = startOfLineIndex; i < endOfLineIndex; i++) {
-      const YGNodeRef child = node->children[i];
-      if (child->style.positionType == YGPositionTypeRelative) {
-        if (YGMarginLeadingValue(child, mainAxis)->unit == YGUnitAuto) {
-          numberOfAutoMarginsOnCurrentLine++;
-        }
-        if (YGMarginTrailingValue(child, mainAxis)->unit == YGUnitAuto) {
-          numberOfAutoMarginsOnCurrentLine++;
-        }
-      }
-    }
-
-    if (numberOfAutoMarginsOnCurrentLine == 0) {
-      switch (justifyContent) {
-        case YGJustifyCenter:
-          leadingMainDim = remainingFreeSpace / 2;
-          break;
-        case YGJustifyFlexEnd:
-          leadingMainDim = remainingFreeSpace;
-          break;
-        case YGJustifySpaceBetween:
-          if (itemsOnLine > 1) {
-            betweenMainDim = fmaxf(remainingFreeSpace, 0) / (itemsOnLine - 1);
-          } else {
-            betweenMainDim = 0;
-          }
-          break;
-        case YGJustifySpaceEvenly:
-          // Space is distributed evenly across all elements
-          betweenMainDim = remainingFreeSpace / (itemsOnLine + 1);
-          leadingMainDim = betweenMainDim;
-          break;
-        case YGJustifySpaceAround:
-          // Space on the edges is half of the space between elements
-          betweenMainDim = remainingFreeSpace / itemsOnLine;
-          leadingMainDim = betweenMainDim / 2;
-          break;
-        case YGJustifyFlexStart:
-          break;
-      }
-    }
-
-    float mainDim = leadingPaddingAndBorderMain + leadingMainDim;
-    float crossDim = 0;
-
-    for (uint32_t i = startOfLineIndex; i < endOfLineIndex; i++) {
-      const YGNodeRef child = node->children[i];
-      if (child->style.display == YGDisplayNone) {
-        continue;
-      }
-      if (child->style.positionType == YGPositionTypeAbsolute &&
-          YGNodeIsLeadingPosDefined(child, mainAxis)) {
-        if (performLayout) {
-          // 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]] =
-              YGNodeLeadingPosition(child, mainAxis, availableInnerMainDim) +
-              YGNodeLeadingBorder(node, mainAxis) +
-              YGNodeLeadingMargin(child, mainAxis, availableInnerWidth);
-        }
-      } else {
-        // Now that we placed the element, we need to update the variables.
-        // We need to do that only for relative elements. Absolute elements
-        // do not take part in that phase.
-        if (child->style.positionType == YGPositionTypeRelative) {
-          if (YGMarginLeadingValue(child, mainAxis)->unit == YGUnitAuto) {
-            mainDim += remainingFreeSpace / numberOfAutoMarginsOnCurrentLine;
-          }
-
-          if (performLayout) {
-            child->layout.position[pos[mainAxis]] += mainDim;
-          }
-
-          if (YGMarginTrailingValue(child, mainAxis)->unit == YGUnitAuto) {
-            mainDim += remainingFreeSpace / numberOfAutoMarginsOnCurrentLine;
-          }
-
-          if (canSkipFlex) {
-            // If we skipped the flex step, then we can't rely on the
-            // measuredDims because
-            // they weren't computed. This means we can't call YGNodeDimWithMargin.
-            mainDim += betweenMainDim + YGNodeMarginForAxis(child, mainAxis, availableInnerWidth) +
-                       child->layout.computedFlexBasis;
-            crossDim = availableInnerCrossDim;
-          } else {
-            // The main dimension is the sum of all the elements dimension plus the spacing.
-            mainDim += betweenMainDim + YGNodeDimWithMargin(child, mainAxis, availableInnerWidth);
-
-            // The cross dimension is the max of the elements dimension since
-            // there can only be one element in that cross dimension.
-            crossDim = fmaxf(crossDim, YGNodeDimWithMargin(child, crossAxis, availableInnerWidth));
-          }
-        } else if (performLayout) {
-          child->layout.position[pos[mainAxis]] +=
-              YGNodeLeadingBorder(node, mainAxis) + leadingMainDim;
-        }
-      }
-    }
-
-    mainDim += trailingPaddingAndBorderMain;
-
-    float containerCrossAxis = availableInnerCrossDim;
-    if (measureModeCrossDim == YGMeasureModeUndefined ||
-        measureModeCrossDim == YGMeasureModeAtMost) {
-      // Compute the cross axis from the max cross dimension of the children.
-      containerCrossAxis = YGNodeBoundAxis(node,
-                                           crossAxis,
-                                           crossDim + paddingAndBorderAxisCross,
-                                           crossAxisParentSize,
-                                           parentWidth) -
-                           paddingAndBorderAxisCross;
-    }
-
-    // If there's no flex wrap, the cross dimension is defined by the container.
-    if (!isNodeFlexWrap && measureModeCrossDim == YGMeasureModeExactly) {
-      crossDim = availableInnerCrossDim;
-    }
-
-    // Clamp to the min/max size specified on the container.
-    crossDim = YGNodeBoundAxis(node,
-                               crossAxis,
-                               crossDim + paddingAndBorderAxisCross,
-                               crossAxisParentSize,
-                               parentWidth) -
-               paddingAndBorderAxisCross;
-
-    // STEP 7: CROSS-AXIS ALIGNMENT
-    // We can skip child alignment if we're just measuring the container.
-    if (performLayout) {
-      for (uint32_t i = startOfLineIndex; i < endOfLineIndex; i++) {
-        const YGNodeRef child = node->children[i];
-        if (child->style.display == YGDisplayNone) {
-          continue;
-        }
-        if (child->style.positionType == YGPositionTypeAbsolute) {
-          // If the child is absolutely positioned and has a
-          // top/left/bottom/right
-          // set, override all the previously computed positions to set it
-          // correctly.
-          const bool isChildLeadingPosDefined = YGNodeIsLeadingPosDefined(child, crossAxis);
-          if (isChildLeadingPosDefined) {
-            child->layout.position[pos[crossAxis]] =
-                YGNodeLeadingPosition(child, crossAxis, availableInnerCrossDim) +
-                YGNodeLeadingBorder(node, crossAxis) +
-                YGNodeLeadingMargin(child, crossAxis, availableInnerWidth);
-          }
-          // If leading position is not defined or calculations result in Nan, default to border + margin
-          if (!isChildLeadingPosDefined || YGFloatIsUndefined(child->layout.position[pos[crossAxis]])) {
-            child->layout.position[pos[crossAxis]] =
-                YGNodeLeadingBorder(node, crossAxis) +
-                YGNodeLeadingMargin(child, crossAxis, availableInnerWidth);
-          }
-        } 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
-          const YGAlign alignItem = YGNodeAlignItem(node, child);
-
-          // If the child uses align stretch, we need to lay it out one more
-          // time, this time
-          // forcing the cross-axis size to be the computed cross size for the
-          // current line.
-          if (alignItem == YGAlignStretch &&
-              YGMarginLeadingValue(child, crossAxis)->unit != YGUnitAuto &&
-              YGMarginTrailingValue(child, crossAxis)->unit != YGUnitAuto) {
-            // If the child defines a definite size for its cross axis, there's
-            // no need to stretch.
-            if (!YGNodeIsStyleDimDefined(child, crossAxis, availableInnerCrossDim)) {
-              float childMainSize = child->layout.measuredDimensions[dim[mainAxis]];
-              float childCrossSize =
-                  !YGFloatIsUndefined(child->style.aspectRatio)
-                      ? ((YGNodeMarginForAxis(child, crossAxis, availableInnerWidth) +
-                          (isMainAxisRow ? childMainSize / child->style.aspectRatio
-                                         : childMainSize * child->style.aspectRatio)))
-                      : crossDim;
-
-              childMainSize += YGNodeMarginForAxis(child, mainAxis, availableInnerWidth);
-
-              YGMeasureMode childMainMeasureMode = YGMeasureModeExactly;
-              YGMeasureMode childCrossMeasureMode = YGMeasureModeExactly;
-              YGConstrainMaxSizeForMode(child,
-                                        mainAxis,
-                                        availableInnerMainDim,
-                                        availableInnerWidth,
-                                        &childMainMeasureMode,
-                                        &childMainSize);
-              YGConstrainMaxSizeForMode(child,
-                                        crossAxis,
-                                        availableInnerCrossDim,
-                                        availableInnerWidth,
-                                        &childCrossMeasureMode,
-                                        &childCrossSize);
-
-              const float childWidth = isMainAxisRow ? childMainSize : childCrossSize;
-              const float childHeight = !isMainAxisRow ? childMainSize : childCrossSize;
-
-              const YGMeasureMode childWidthMeasureMode =
-                  YGFloatIsUndefined(childWidth) ? YGMeasureModeUndefined : YGMeasureModeExactly;
-              const YGMeasureMode childHeightMeasureMode =
-                  YGFloatIsUndefined(childHeight) ? YGMeasureModeUndefined : YGMeasureModeExactly;
-
-              YGLayoutNodeInternal(child,
-                                   childWidth,
-                                   childHeight,
-                                   direction,
-                                   childWidthMeasureMode,
-                                   childHeightMeasureMode,
-                                   availableInnerWidth,
-                                   availableInnerHeight,
-                                   true,
-                                   "stretch",
-                                   config);
-            }
-          } else {
-            const float remainingCrossDim =
-                containerCrossAxis - YGNodeDimWithMargin(child, crossAxis, availableInnerWidth);
-
-            if (YGMarginLeadingValue(child, crossAxis)->unit == YGUnitAuto &&
-                YGMarginTrailingValue(child, crossAxis)->unit == YGUnitAuto) {
-              leadingCrossDim += fmaxf(0.0f, remainingCrossDim / 2);
-            } else if (YGMarginTrailingValue(child, crossAxis)->unit == YGUnitAuto) {
-              // No-Op
-            } else if (YGMarginLeadingValue(child, crossAxis)->unit == YGUnitAuto) {
-              leadingCrossDim += fmaxf(0.0f, remainingCrossDim);
-            } else if (alignItem == YGAlignFlexStart) {
-              // No-Op
-            } else if (alignItem == YGAlignCenter) {
-              leadingCrossDim += remainingCrossDim / 2;
-            } else {
-              leadingCrossDim += remainingCrossDim;
-            }
-          }
-          // And we apply the position
-          child->layout.position[pos[crossAxis]] += totalLineCrossDim + leadingCrossDim;
-        }
-      }
-    }
-
-    totalLineCrossDim += crossDim;
-    maxLineMainDim = fmaxf(maxLineMainDim, mainDim);
-  }
-
-  // STEP 8: MULTI-LINE CONTENT ALIGNMENT
-  if (performLayout && (lineCount > 1 || YGIsBaselineLayout(node)) &&
-      !YGFloatIsUndefined(availableInnerCrossDim)) {
-    const float remainingAlignContentDim = availableInnerCrossDim - totalLineCrossDim;
-
-    float crossDimLead = 0;
-    float currentLead = leadingPaddingAndBorderCross;
-
-    switch (node->style.alignContent) {
-      case YGAlignFlexEnd:
-        currentLead += remainingAlignContentDim;
-        break;
-      case YGAlignCenter:
-        currentLead += remainingAlignContentDim / 2;
-        break;
-      case YGAlignStretch:
-        if (availableInnerCrossDim > totalLineCrossDim) {
-          crossDimLead = remainingAlignContentDim / lineCount;
-        }
-        break;
-      case YGAlignSpaceAround:
-        if (availableInnerCrossDim > totalLineCrossDim) {
-          currentLead += remainingAlignContentDim / (2 * lineCount);
-          if (lineCount > 1) {
-            crossDimLead = remainingAlignContentDim / lineCount;
-          }
-        } else {
-          currentLead += remainingAlignContentDim / 2;
-        }
-        break;
-      case YGAlignSpaceBetween:
-        if (availableInnerCrossDim > totalLineCrossDim && lineCount > 1) {
-          crossDimLead = remainingAlignContentDim / (lineCount - 1);
-        }
-        break;
-      case YGAlignAuto:
-      case YGAlignFlexStart:
-      case YGAlignBaseline:
-        break;
-    }
-
-    uint32_t endIndex = 0;
-    for (uint32_t i = 0; i < lineCount; i++) {
-      const uint32_t startIndex = endIndex;
-      uint32_t ii;
-
-      // compute the line's height and find the endIndex
-      float lineHeight = 0;
-      float maxAscentForCurrentLine = 0;
-      float maxDescentForCurrentLine = 0;
-      for (ii = startIndex; ii < childCount; ii++) {
-        const YGNodeRef child = node->children[ii];
-        if (child->style.display == YGDisplayNone) {
-          continue;
-        }
-        if (child->style.positionType == YGPositionTypeRelative) {
-          if (child->lineIndex != i) {
-            break;
-          }
-          if (YGNodeIsLayoutDimDefined(child, crossAxis)) {
-            lineHeight = fmaxf(lineHeight,
-                               child->layout.measuredDimensions[dim[crossAxis]] +
-                                   YGNodeMarginForAxis(child, crossAxis, availableInnerWidth));
-          }
-          if (YGNodeAlignItem(node, child) == YGAlignBaseline) {
-            const float ascent =
-                YGBaseline(child) +
-                YGNodeLeadingMargin(child, YGFlexDirectionColumn, availableInnerWidth);
-            const float descent =
-                child->layout.measuredDimensions[YGDimensionHeight] +
-                YGNodeMarginForAxis(child, YGFlexDirectionColumn, availableInnerWidth) - ascent;
-            maxAscentForCurrentLine = fmaxf(maxAscentForCurrentLine, ascent);
-            maxDescentForCurrentLine = fmaxf(maxDescentForCurrentLine, descent);
-            lineHeight = fmaxf(lineHeight, maxAscentForCurrentLine + maxDescentForCurrentLine);
-          }
-        }
-      }
-      endIndex = ii;
-      lineHeight += crossDimLead;
-
-      if (performLayout) {
-        for (ii = startIndex; ii < endIndex; ii++) {
-          const YGNodeRef child = node->children[ii];
-          if (child->style.display == YGDisplayNone) {
-            continue;
-          }
-          if (child->style.positionType == YGPositionTypeRelative) {
-            switch (YGNodeAlignItem(node, child)) {
-              case YGAlignFlexStart: {
-                child->layout.position[pos[crossAxis]] =
-                    currentLead + YGNodeLeadingMargin(child, crossAxis, availableInnerWidth);
-                break;
-              }
-              case YGAlignFlexEnd: {
-                child->layout.position[pos[crossAxis]] =
-                    currentLead + lineHeight -
-                    YGNodeTrailingMargin(child, crossAxis, availableInnerWidth) -
-                    child->layout.measuredDimensions[dim[crossAxis]];
-                break;
-              }
-              case YGAlignCenter: {
-                float childHeight = child->layout.measuredDimensions[dim[crossAxis]];
-                child->layout.position[pos[crossAxis]] =
-                    currentLead + (lineHeight - childHeight) / 2;
-                break;
-              }
-              case YGAlignStretch: {
-                child->layout.position[pos[crossAxis]] =
-                    currentLead + YGNodeLeadingMargin(child, crossAxis, availableInnerWidth);
-
-                // Remeasure child with the line height as it as been only measured with the
-                // parents height yet.
-                if (!YGNodeIsStyleDimDefined(child, crossAxis, availableInnerCrossDim)) {
-                  const float childWidth =
-                      isMainAxisRow ? (child->layout.measuredDimensions[YGDimensionWidth] +
-                                       YGNodeMarginForAxis(child, mainAxis, availableInnerWidth))
-                                    : lineHeight;
-
-                  const float childHeight =
-                      !isMainAxisRow ? (child->layout.measuredDimensions[YGDimensionHeight] +
-                                        YGNodeMarginForAxis(child, crossAxis, availableInnerWidth))
-                                     : lineHeight;
-
-                  if (!(YGFloatsEqual(childWidth,
-                                      child->layout.measuredDimensions[YGDimensionWidth]) &&
-                        YGFloatsEqual(childHeight,
-                                      child->layout.measuredDimensions[YGDimensionHeight]))) {
-                    YGLayoutNodeInternal(child,
-                                         childWidth,
-                                         childHeight,
-                                         direction,
-                                         YGMeasureModeExactly,
-                                         YGMeasureModeExactly,
-                                         availableInnerWidth,
-                                         availableInnerHeight,
-                                         true,
-                                         "multiline-stretch",
-                                         config);
-                  }
-                }
-                break;
-              }
-              case YGAlignBaseline: {
-                child->layout.position[YGEdgeTop] =
-                    currentLead + maxAscentForCurrentLine - YGBaseline(child) +
-                    YGNodeLeadingPosition(child, YGFlexDirectionColumn, availableInnerCrossDim);
-                break;
-              }
-              case YGAlignAuto:
-              case YGAlignSpaceBetween:
-              case YGAlignSpaceAround:
-                break;
-            }
-          }
-        }
-      }
-
-      currentLead += lineHeight;
-    }
-  }
-
-  // STEP 9: COMPUTING FINAL DIMENSIONS
-  node->layout.measuredDimensions[YGDimensionWidth] = YGNodeBoundAxis(
-      node, YGFlexDirectionRow, availableWidth - marginAxisRow, parentWidth, parentWidth);
-  node->layout.measuredDimensions[YGDimensionHeight] = YGNodeBoundAxis(
-      node, YGFlexDirectionColumn, availableHeight - marginAxisColumn, parentHeight, parentWidth);
-
-  // If the user didn't specify a width or height for the node, set the
-  // dimensions based on the children.
-  if (measureModeMainDim == YGMeasureModeUndefined ||
-      (node->style.overflow != YGOverflowScroll && measureModeMainDim == YGMeasureModeAtMost)) {
-    // Clamp the size to the min/max size, if specified, and make sure it
-    // doesn't go below the padding and border amount.
-    node->layout.measuredDimensions[dim[mainAxis]] =
-        YGNodeBoundAxis(node, mainAxis, maxLineMainDim, mainAxisParentSize, parentWidth);
-  } else if (measureModeMainDim == YGMeasureModeAtMost &&
-             node->style.overflow == YGOverflowScroll) {
-    node->layout.measuredDimensions[dim[mainAxis]] = fmaxf(
-        fminf(availableInnerMainDim + paddingAndBorderAxisMain,
-              YGNodeBoundAxisWithinMinAndMax(node, mainAxis, maxLineMainDim, mainAxisParentSize)),
-        paddingAndBorderAxisMain);
-  }
-
-  if (measureModeCrossDim == YGMeasureModeUndefined ||
-      (node->style.overflow != YGOverflowScroll && measureModeCrossDim == YGMeasureModeAtMost)) {
-    // Clamp the size to the min/max size, if specified, and make sure it
-    // doesn't go below the padding and border amount.
-    node->layout.measuredDimensions[dim[crossAxis]] =
-        YGNodeBoundAxis(node,
-                        crossAxis,
-                        totalLineCrossDim + paddingAndBorderAxisCross,
-                        crossAxisParentSize,
-                        parentWidth);
-  } else if (measureModeCrossDim == YGMeasureModeAtMost &&
-             node->style.overflow == YGOverflowScroll) {
-    node->layout.measuredDimensions[dim[crossAxis]] =
-        fmaxf(fminf(availableInnerCrossDim + paddingAndBorderAxisCross,
-                    YGNodeBoundAxisWithinMinAndMax(node,
-                                                   crossAxis,
-                                                   totalLineCrossDim + paddingAndBorderAxisCross,
-                                                   crossAxisParentSize)),
-              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 != nullptr;
-         currentAbsoluteChild = currentAbsoluteChild->nextChild) {
-      YGNodeAbsoluteLayoutChild(node,
-                                currentAbsoluteChild,
-                                availableInnerWidth,
-                                isMainAxisRow ? measureModeMainDim : measureModeCrossDim,
-                                availableInnerHeight,
-                                direction,
-                                config);
-    }
-
-    // STEP 11: SETTING TRAILING POSITIONS FOR CHILDREN
-    const bool needsMainTrailingPos =
-        mainAxis == YGFlexDirectionRowReverse || mainAxis == YGFlexDirectionColumnReverse;
-    const bool needsCrossTrailingPos =
-        crossAxis == YGFlexDirectionRowReverse || crossAxis == YGFlexDirectionColumnReverse;
-
-    // Set trailing position if necessary.
-    if (needsMainTrailingPos || needsCrossTrailingPos) {
-      for (uint32_t i = 0; i < childCount; i++) {
-        const YGNodeRef child = node->children[i];
-        if (child->style.display == YGDisplayNone) {
-          continue;
-        }
-        if (needsMainTrailingPos) {
-          YGNodeSetChildTrailingPosition(node, child, mainAxis);
-        }
-
-        if (needsCrossTrailingPos) {
-          YGNodeSetChildTrailingPosition(node, child, crossAxis);
-        }
-      }
-    }
-  }
-}
-
-uint32_t gDepth = 0;
-bool gPrintTree = false;
-bool gPrintChanges = false;
-bool gPrintSkips = false;
-
-static const char *spacer = "                                                            ";
-
-static const char *YGSpacer(const unsigned long level) {
-  const size_t spacerLen = strlen(spacer);
-  if (level > spacerLen) {
-    return &spacer[0];
-  } else {
-    return &spacer[spacerLen - level];
-  }
-}
-
-static const char *YGMeasureModeName(const YGMeasureMode mode, const bool performLayout) {
-  const char *kMeasureModeNames[YGMeasureModeCount] = {"UNDEFINED", "EXACTLY", "AT_MOST"};
-  const char *kLayoutModeNames[YGMeasureModeCount] = {"LAY_UNDEFINED",
-                                                      "LAY_EXACTLY",
-                                                      "LAY_AT_"
-                                                      "MOST"};
-
-  if (mode >= YGMeasureModeCount) {
-    return "";
-  }
-
-  return performLayout ? kLayoutModeNames[mode] : kMeasureModeNames[mode];
-}
-
-static inline bool YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(YGMeasureMode sizeMode,
-                                                                     float size,
-                                                                     float lastComputedSize) {
-  return sizeMode == YGMeasureModeExactly && YGFloatsEqual(size, lastComputedSize);
-}
-
-static inline bool YGMeasureModeOldSizeIsUnspecifiedAndStillFits(YGMeasureMode sizeMode,
-                                                                 float size,
-                                                                 YGMeasureMode lastSizeMode,
-                                                                 float lastComputedSize) {
-  return sizeMode == YGMeasureModeAtMost && lastSizeMode == YGMeasureModeUndefined &&
-         (size >= lastComputedSize || YGFloatsEqual(size, lastComputedSize));
-}
-
-static inline bool YGMeasureModeNewMeasureSizeIsStricterAndStillValid(YGMeasureMode sizeMode,
-                                                                      float size,
-                                                                      YGMeasureMode lastSizeMode,
-                                                                      float lastSize,
-                                                                      float lastComputedSize) {
-  return lastSizeMode == YGMeasureModeAtMost && sizeMode == YGMeasureModeAtMost &&
-         lastSize > size && (lastComputedSize <= size || YGFloatsEqual(size, lastComputedSize));
-}
-
-float YGRoundValueToPixelGrid(const float value,
-                              const float pointScaleFactor,
-                              const bool forceCeil,
-                              const bool forceFloor) {
-  float scaledValue = value * pointScaleFactor;
-  float fractial = fmodf(scaledValue, 1.0);
-  if (YGFloatsEqual(fractial, 0)) {
-    // First we check if the value is already rounded
-    scaledValue = scaledValue - fractial;
-  } else if (YGFloatsEqual(fractial, 1.0)) {
-    scaledValue = scaledValue - fractial + 1.0;
-  } else if (forceCeil) {
-    // Next we check if we need to use forced rounding
-    scaledValue = scaledValue - fractial + 1.0f;
-  } else if (forceFloor) {
-    scaledValue = scaledValue - fractial;
-  } else {
-    // Finally we just round the value
-    scaledValue = scaledValue - fractial +
-        (fractial > 0.5f || YGFloatsEqual(fractial, 0.5f) ? 1.0f : 0.0f);
-  }
-  return scaledValue / pointScaleFactor;
-}
-
-bool YGNodeCanUseCachedMeasurement(const YGMeasureMode widthMode,
-                                   const float width,
-                                   const YGMeasureMode heightMode,
-                                   const float height,
-                                   const YGMeasureMode lastWidthMode,
-                                   const float lastWidth,
-                                   const YGMeasureMode lastHeightMode,
-                                   const float lastHeight,
-                                   const float lastComputedWidth,
-                                   const float lastComputedHeight,
-                                   const float marginRow,
-                                   const float marginColumn,
-                                   const YGConfigRef config) {
-  if (lastComputedHeight < 0 || lastComputedWidth < 0) {
-    return false;
-  }
-  bool useRoundedComparison =
-      config != nullptr && config->pointScaleFactor != 0;
-  const float effectiveWidth =
-      useRoundedComparison ? YGRoundValueToPixelGrid(width, config->pointScaleFactor, false, false)
-                           : width;
-  const float effectiveHeight =
-      useRoundedComparison ? YGRoundValueToPixelGrid(height, config->pointScaleFactor, false, false)
-                           : height;
-  const float effectiveLastWidth =
-      useRoundedComparison
-          ? YGRoundValueToPixelGrid(lastWidth, config->pointScaleFactor, false, false)
-          : lastWidth;
-  const float effectiveLastHeight =
-      useRoundedComparison
-          ? YGRoundValueToPixelGrid(lastHeight, config->pointScaleFactor, false, false)
-          : lastHeight;
-
-  const bool hasSameWidthSpec =
-      lastWidthMode == widthMode && YGFloatsEqual(effectiveLastWidth, effectiveWidth);
-  const bool hasSameHeightSpec =
-      lastHeightMode == heightMode && YGFloatsEqual(effectiveLastHeight, effectiveHeight);
-
-  const bool widthIsCompatible =
-      hasSameWidthSpec || YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(widthMode,
-                                                                            width - marginRow,
-                                                                            lastComputedWidth) ||
-      YGMeasureModeOldSizeIsUnspecifiedAndStillFits(widthMode,
-                                                    width - marginRow,
-                                                    lastWidthMode,
-                                                    lastComputedWidth) ||
-      YGMeasureModeNewMeasureSizeIsStricterAndStillValid(
-          widthMode, width - marginRow, lastWidthMode, lastWidth, lastComputedWidth);
-
-  const bool heightIsCompatible =
-      hasSameHeightSpec || YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(heightMode,
-                                                                             height - marginColumn,
-                                                                             lastComputedHeight) ||
-      YGMeasureModeOldSizeIsUnspecifiedAndStillFits(heightMode,
-                                                    height - marginColumn,
-                                                    lastHeightMode,
-                                                    lastComputedHeight) ||
-      YGMeasureModeNewMeasureSizeIsStricterAndStillValid(
-          heightMode, height - marginColumn, lastHeightMode, lastHeight, lastComputedHeight);
-
-  return widthIsCompatible && heightIsCompatible;
-}
-
-//
-// This is a wrapper around the YGNodelayoutImpl function. It determines
-// whether the layout request is redundant and can be skipped.
-//
-// Parameters:
-//  Input parameters are the same as YGNodelayoutImpl (see above)
-//  Return parameter is true if layout was performed, false if skipped
-//
-bool YGLayoutNodeInternal(const YGNodeRef node,
-                          const float availableWidth,
-                          const float availableHeight,
-                          const YGDirection parentDirection,
-                          const YGMeasureMode widthMeasureMode,
-                          const YGMeasureMode heightMeasureMode,
-                          const float parentWidth,
-                          const float parentHeight,
-                          const bool performLayout,
-                          const char *reason,
-                          const YGConfigRef config) {
-  YGLayout *layout = &node->layout;
-
-  gDepth++;
-
-  const bool needToVisitNode =
-      (node->isDirty && layout->generationCount != gCurrentGenerationCount) ||
-      layout->lastParentDirection != parentDirection;
-
-  if (needToVisitNode) {
-    // Invalidate the cached results.
-    layout->nextCachedMeasurementsIndex = 0;
-    layout->cachedLayout.widthMeasureMode = (YGMeasureMode) -1;
-    layout->cachedLayout.heightMeasureMode = (YGMeasureMode) -1;
-    layout->cachedLayout.computedWidth = -1;
-    layout->cachedLayout.computedHeight = -1;
-  }
-
-  YGCachedMeasurement* cachedResults = nullptr;
-
-  // Determine whether the results are already cached. We maintain a separate
-  // cache for layouts and measurements. A layout operation modifies the
-  // positions
-  // and dimensions for nodes in the subtree. The algorithm assumes that each
-  // node
-  // gets layed out a maximum of one time per tree layout, but multiple
-  // measurements
-  // may be required to resolve all of the flex dimensions.
-  // We handle nodes with measure functions specially here because they are the
-  // most
-  // expensive to measure, so it's worth avoiding redundant measurements if at
-  // all possible.
-  if (node->measure) {
-    const float marginAxisRow = YGNodeMarginForAxis(node, YGFlexDirectionRow, parentWidth);
-    const float marginAxisColumn = YGNodeMarginForAxis(node, YGFlexDirectionColumn, parentWidth);
-
-    // First, try to use the layout cache.
-    if (YGNodeCanUseCachedMeasurement(widthMeasureMode,
-                                      availableWidth,
-                                      heightMeasureMode,
-                                      availableHeight,
-                                      layout->cachedLayout.widthMeasureMode,
-                                      layout->cachedLayout.availableWidth,
-                                      layout->cachedLayout.heightMeasureMode,
-                                      layout->cachedLayout.availableHeight,
-                                      layout->cachedLayout.computedWidth,
-                                      layout->cachedLayout.computedHeight,
-                                      marginAxisRow,
-                                      marginAxisColumn,
-                                      config)) {
-      cachedResults = &layout->cachedLayout;
-    } else {
-      // Try to use the measurement cache.
-      for (uint32_t i = 0; i < layout->nextCachedMeasurementsIndex; i++) {
-        if (YGNodeCanUseCachedMeasurement(widthMeasureMode,
-                                          availableWidth,
-                                          heightMeasureMode,
-                                          availableHeight,
-                                          layout->cachedMeasurements[i].widthMeasureMode,
-                                          layout->cachedMeasurements[i].availableWidth,
-                                          layout->cachedMeasurements[i].heightMeasureMode,
-                                          layout->cachedMeasurements[i].availableHeight,
-                                          layout->cachedMeasurements[i].computedWidth,
-                                          layout->cachedMeasurements[i].computedHeight,
-                                          marginAxisRow,
-                                          marginAxisColumn,
-                                          config)) {
-          cachedResults = &layout->cachedMeasurements[i];
-          break;
-        }
-      }
-    }
-  } else if (performLayout) {
-    if (YGFloatsEqual(layout->cachedLayout.availableWidth, availableWidth) &&
-        YGFloatsEqual(layout->cachedLayout.availableHeight, availableHeight) &&
-        layout->cachedLayout.widthMeasureMode == widthMeasureMode &&
-        layout->cachedLayout.heightMeasureMode == heightMeasureMode) {
-      cachedResults = &layout->cachedLayout;
-    }
-  } else {
-    for (uint32_t i = 0; i < layout->nextCachedMeasurementsIndex; i++) {
-      if (YGFloatsEqual(layout->cachedMeasurements[i].availableWidth, availableWidth) &&
-          YGFloatsEqual(layout->cachedMeasurements[i].availableHeight, availableHeight) &&
-          layout->cachedMeasurements[i].widthMeasureMode == widthMeasureMode &&
-          layout->cachedMeasurements[i].heightMeasureMode == heightMeasureMode) {
-        cachedResults = &layout->cachedMeasurements[i];
-        break;
-      }
-    }
-  }
-
-  if (!needToVisitNode && cachedResults != nullptr) {
-    layout->measuredDimensions[YGDimensionWidth] = cachedResults->computedWidth;
-    layout->measuredDimensions[YGDimensionHeight] = cachedResults->computedHeight;
-
-    if (gPrintChanges && gPrintSkips) {
-      YGLog(node, YGLogLevelVerbose, "%s%d.{[skipped] ", YGSpacer(gDepth), gDepth);
-      if (node->print) {
-        node->print(node);
-      }
-      YGLog(
-          node,
-          YGLogLevelVerbose,
-          "wm: %s, hm: %s, aw: %f ah: %f => d: (%f, %f) %s\n",
-          YGMeasureModeName(widthMeasureMode, performLayout),
-          YGMeasureModeName(heightMeasureMode, performLayout),
-          availableWidth,
-          availableHeight,
-          cachedResults->computedWidth,
-          cachedResults->computedHeight,
-          reason);
-    }
-  } else {
-    if (gPrintChanges) {
-      YGLog(
-          node,
-          YGLogLevelVerbose,
-          "%s%d.{%s",
-          YGSpacer(gDepth),
-          gDepth,
-          needToVisitNode ? "*" : "");
-      if (node->print) {
-        node->print(node);
-      }
-      YGLog(
-          node,
-          YGLogLevelVerbose,
-          "wm: %s, hm: %s, aw: %f ah: %f %s\n",
-          YGMeasureModeName(widthMeasureMode, performLayout),
-          YGMeasureModeName(heightMeasureMode, performLayout),
-          availableWidth,
-          availableHeight,
-          reason);
-    }
-
-    YGNodelayoutImpl(node,
-                     availableWidth,
-                     availableHeight,
-                     parentDirection,
-                     widthMeasureMode,
-                     heightMeasureMode,
-                     parentWidth,
-                     parentHeight,
-                     performLayout,
-                     config);
-
-    if (gPrintChanges) {
-      YGLog(
-          node,
-          YGLogLevelVerbose,
-          "%s%d.}%s",
-          YGSpacer(gDepth),
-          gDepth,
-          needToVisitNode ? "*" : "");
-      if (node->print) {
-        node->print(node);
-      }
-      YGLog(
-          node,
-          YGLogLevelVerbose,
-          "wm: %s, hm: %s, d: (%f, %f) %s\n",
-          YGMeasureModeName(widthMeasureMode, performLayout),
-          YGMeasureModeName(heightMeasureMode, performLayout),
-          layout->measuredDimensions[YGDimensionWidth],
-          layout->measuredDimensions[YGDimensionHeight],
-          reason);
-    }
-
-    layout->lastParentDirection = parentDirection;
-
-    if (cachedResults == nullptr) {
-      if (layout->nextCachedMeasurementsIndex == YG_MAX_CACHED_RESULT_COUNT) {
-        if (gPrintChanges) {
-          YGLog(node, YGLogLevelVerbose, "Out of cache entries!\n");
-        }
-        layout->nextCachedMeasurementsIndex = 0;
-      }
-
-      YGCachedMeasurement *newCacheEntry;
-      if (performLayout) {
-        // Use the single layout cache entry.
-        newCacheEntry = &layout->cachedLayout;
-      } else {
-        // Allocate a new measurement cache entry.
-        newCacheEntry = &layout->cachedMeasurements[layout->nextCachedMeasurementsIndex];
-        layout->nextCachedMeasurementsIndex++;
-      }
-
-      newCacheEntry->availableWidth = availableWidth;
-      newCacheEntry->availableHeight = availableHeight;
-      newCacheEntry->widthMeasureMode = widthMeasureMode;
-      newCacheEntry->heightMeasureMode = heightMeasureMode;
-      newCacheEntry->computedWidth = layout->measuredDimensions[YGDimensionWidth];
-      newCacheEntry->computedHeight = layout->measuredDimensions[YGDimensionHeight];
-    }
-  }
-
-  if (performLayout) {
-    node->layout.dimensions[YGDimensionWidth] = node->layout.measuredDimensions[YGDimensionWidth];
-    node->layout.dimensions[YGDimensionHeight] = node->layout.measuredDimensions[YGDimensionHeight];
-    node->hasNewLayout = true;
-    node->isDirty = false;
-  }
-
-  gDepth--;
-  layout->generationCount = gCurrentGenerationCount;
-  return (needToVisitNode || cachedResults == nullptr);
-}
-
-void YGConfigSetPointScaleFactor(const YGConfigRef config, const float pixelsInPoint) {
-  YGAssertWithConfig(config, pixelsInPoint >= 0.0f, "Scale factor should not be less than zero");
-
-  // We store points for Pixel as we will use it for rounding
-  if (pixelsInPoint == 0.0f) {
-    // Zero is used to skip rounding
-    config->pointScaleFactor = 0.0f;
-  } else {
-    config->pointScaleFactor = pixelsInPoint;
-  }
-}
-
-static void YGRoundToPixelGrid(const YGNodeRef node,
-                               const float pointScaleFactor,
-                               const float absoluteLeft,
-                               const float absoluteTop) {
-  if (pointScaleFactor == 0.0f) {
-    return;
-  }
-
-  const float nodeLeft = node->layout.position[YGEdgeLeft];
-  const float nodeTop = node->layout.position[YGEdgeTop];
-
-  const float nodeWidth = node->layout.dimensions[YGDimensionWidth];
-  const float nodeHeight = node->layout.dimensions[YGDimensionHeight];
-
-  const float absoluteNodeLeft = absoluteLeft + nodeLeft;
-  const float absoluteNodeTop = absoluteTop + nodeTop;
-
-  const float absoluteNodeRight = absoluteNodeLeft + nodeWidth;
-  const float absoluteNodeBottom = absoluteNodeTop + nodeHeight;
-
-  // If a node has a custom measure function we never want to round down its size as this could
-  // lead to unwanted text truncation.
-  const bool textRounding = node->nodeType == YGNodeTypeText;
-
-  node->layout.position[YGEdgeLeft] =
-      YGRoundValueToPixelGrid(nodeLeft, pointScaleFactor, false, textRounding);
-  node->layout.position[YGEdgeTop] =
-      YGRoundValueToPixelGrid(nodeTop, pointScaleFactor, false, textRounding);
-
-  // We multiply dimension by scale factor and if the result is close to the whole number, we don't
-  // have any fraction
-  // To verify if the result is close to whole number we want to check both floor and ceil numbers
-  const bool hasFractionalWidth = !YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 0) &&
-                                  !YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 1.0);
-  const bool hasFractionalHeight = !YGFloatsEqual(fmodf(nodeHeight * pointScaleFactor, 1.0), 0) &&
-                                   !YGFloatsEqual(fmodf(nodeHeight * pointScaleFactor, 1.0), 1.0);
-
-  node->layout.dimensions[YGDimensionWidth] =
-      YGRoundValueToPixelGrid(absoluteNodeRight,
-                              pointScaleFactor,
-                              (textRounding && hasFractionalWidth),
-                              (textRounding && !hasFractionalWidth)) -
-      YGRoundValueToPixelGrid(absoluteNodeLeft, pointScaleFactor, false, textRounding);
-  node->layout.dimensions[YGDimensionHeight] =
-      YGRoundValueToPixelGrid(absoluteNodeBottom,
-                              pointScaleFactor,
-                              (textRounding && hasFractionalHeight),
-                              (textRounding && !hasFractionalHeight)) -
-      YGRoundValueToPixelGrid(absoluteNodeTop, pointScaleFactor, false, textRounding);
-
-  const uint32_t childCount = node->children.size();
-  for (uint32_t i = 0; i < childCount; i++) {
-    YGRoundToPixelGrid(YGNodeGetChild(node, i), pointScaleFactor, absoluteNodeLeft, absoluteNodeTop);
-  }
-}
-
-void YGNodeCalculateLayout(const YGNodeRef node,
-                           const float parentWidth,
-                           const float parentHeight,
-                           const YGDirection parentDirection) {
-  // Increment the generation count. This will force the recursive routine to
-  // visit
-  // all dirty nodes at least once. Subsequent visits will be skipped if the
-  // input
-  // parameters don't change.
-  gCurrentGenerationCount++;
-
-  YGResolveDimensions(node);
-
-  float width = YGUndefined;
-  YGMeasureMode widthMeasureMode = YGMeasureModeUndefined;
-  if (YGNodeIsStyleDimDefined(node, YGFlexDirectionRow, parentWidth)) {
-    width = YGResolveValue(node->resolvedDimensions[dim[YGFlexDirectionRow]], parentWidth) +
-            YGNodeMarginForAxis(node, YGFlexDirectionRow, parentWidth);
-    widthMeasureMode = YGMeasureModeExactly;
-  } else if (YGResolveValue(&node->style.maxDimensions[YGDimensionWidth], parentWidth) >= 0.0f) {
-    width = YGResolveValue(&node->style.maxDimensions[YGDimensionWidth], parentWidth);
-    widthMeasureMode = YGMeasureModeAtMost;
-  } else {
-    width = parentWidth;
-    widthMeasureMode = YGFloatIsUndefined(width) ? YGMeasureModeUndefined : YGMeasureModeExactly;
-  }
-
-  float height = YGUndefined;
-  YGMeasureMode heightMeasureMode = YGMeasureModeUndefined;
-  if (YGNodeIsStyleDimDefined(node, YGFlexDirectionColumn, parentHeight)) {
-    height = YGResolveValue(node->resolvedDimensions[dim[YGFlexDirectionColumn]], parentHeight) +
-             YGNodeMarginForAxis(node, YGFlexDirectionColumn, parentWidth);
-    heightMeasureMode = YGMeasureModeExactly;
-  } else if (YGResolveValue(&node->style.maxDimensions[YGDimensionHeight], parentHeight) >= 0.0f) {
-    height = YGResolveValue(&node->style.maxDimensions[YGDimensionHeight], parentHeight);
-    heightMeasureMode = YGMeasureModeAtMost;
-  } else {
-    height = parentHeight;
-    heightMeasureMode = YGFloatIsUndefined(height) ? YGMeasureModeUndefined : YGMeasureModeExactly;
-  }
-
-  if (YGLayoutNodeInternal(node,
-                           width,
-                           height,
-                           parentDirection,
-                           widthMeasureMode,
-                           heightMeasureMode,
-                           parentWidth,
-                           parentHeight,
-                           true,
-                           "initial",
-                           node->config)) {
-    YGNodeSetPosition(node, node->layout.direction, parentWidth, parentHeight, parentWidth);
-    YGRoundToPixelGrid(node, node->config->pointScaleFactor, 0.0f, 0.0f);
-
-    if (gPrintTree) {
-      YGNodePrint(
-          node,
-          (YGPrintOptions)(
-              YGPrintOptionsLayout | YGPrintOptionsChildren |
-              YGPrintOptionsStyle));
-    }
-  }
-}
-
-void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) {
-  if (logger != nullptr) {
-    config->logger = logger;
-  } else {
-#ifdef ANDROID
-    config->logger = &YGAndroidLog;
-#else
-    config->logger = &YGDefaultLog;
-#endif
-  }
-}
-
-static void YGVLog(const YGConfigRef config,
-                   const YGNodeRef node,
-                   YGLogLevel level,
-                   const char *format,
-                   va_list args) {
-  const YGConfigRef logConfig = config != nullptr ? config : &gYGConfigDefaults;
-  logConfig->logger(logConfig, node, level, format, args);
-
-  if (level == YGLogLevelFatal) {
-    abort();
-  }
-}
-
-void YGLogWithConfig(const YGConfigRef config, YGLogLevel level, const char *format, ...) {
-  va_list args;
-  va_start(args, format);
-  YGVLog(config, nullptr, level, format, args);
-  va_end(args);
-}
-
-void YGLog(const YGNodeRef node, YGLogLevel level, const char *format, ...) {
-  va_list args;
-  va_start(args, format);
-  YGVLog(node == nullptr ? nullptr : node->config, node, level, format, args);
-  va_end(args);
-}
-
-void YGAssert(const bool condition, const char *message) {
-  if (!condition) {
-    YGLog(nullptr, YGLogLevelFatal, "%s\n", message);
-  }
-}
-
-void YGAssertWithNode(const YGNodeRef node, const bool condition, const char *message) {
-  if (!condition) {
-    YGLog(node, YGLogLevelFatal, "%s\n", message);
-  }
-}
-
-void YGAssertWithConfig(const YGConfigRef config, const bool condition, const char *message) {
-  if (!condition) {
-    YGLogWithConfig(config, YGLogLevelFatal, "%s\n", message);
-  }
-}
-
-void YGConfigSetExperimentalFeatureEnabled(const YGConfigRef config,
-                                           const YGExperimentalFeature feature,
-                                           const bool enabled) {
-  config->experimentalFeatures[feature] = enabled;
-}
-
-inline bool YGConfigIsExperimentalFeatureEnabled(const YGConfigRef config,
-                                                 const YGExperimentalFeature feature) {
-  return config->experimentalFeatures[feature];
-}
-
-void YGConfigSetUseWebDefaults(const YGConfigRef config, const bool enabled) {
-  config->useWebDefaults = enabled;
-}
-
-void YGConfigSetUseLegacyStretchBehaviour(const YGConfigRef config,
-                                          const bool useLegacyStretchBehaviour) {
-  config->useLegacyStretchBehaviour = useLegacyStretchBehaviour;
-}
-
-bool YGConfigGetUseWebDefaults(const YGConfigRef config) {
-  return config->useWebDefaults;
-}
-
-void YGConfigSetContext(const YGConfigRef config, void *context) {
-  config->context = context;
-}
-
-void *YGConfigGetContext(const YGConfigRef config) {
-  return config->context;
-}
-
-void YGConfigSetNodeClonedFunc(const YGConfigRef config, const YGNodeClonedFunc callback) {
-  config->cloneNodeCallback = callback;
-}
+/*
+ *  Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ *  This source code is licensed under the MIT license found in the LICENSE
+ *  file in the root directory of this source tree.
+ *
+ */
+
+#include "Yoga.h"
+#include <float.h>
+#include <string.h>
+#include <algorithm>
+#include "Utils.h"
+#include "YGNode.h"
+#include "YGNodePrint.h"
+#include "Yoga-internal.h"
+#ifdef _MSC_VER
+#include <float.h>
+
+/* define fmaxf if < VC12 */
+#if _MSC_VER < 1800
+__forceinline const float fmaxf(const float a, const float b) {
+  if (!YGFloatIsUndefined(a) && !YGFloatIsUndefined(b)) {
+    return (a > b) ? a : b;
+  }
+  return YGFloatIsUndefined(a) ? b : a;
+}
+#endif
+#endif
+
+#ifdef ANDROID
+static int YGAndroidLog(
+    const YGConfigRef config,
+    const YGNodeRef node,
+    YGLogLevel level,
+    const char* format,
+    va_list args);
+#else
+static int YGDefaultLog(
+    const YGConfigRef config,
+    const YGNodeRef node,
+    YGLogLevel level,
+    const char* format,
+    va_list args);
+#endif
+
+const YGValue YGValueZero = {0, YGUnitPoint};
+const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined};
+const YGValue YGValueAuto = {YGUndefined, YGUnitAuto};
+
+bool operator==(const YGValue& lhs, const YGValue& rhs) {
+  if ((lhs.unit == YGUnitUndefined && rhs.unit == YGUnitUndefined) ||
+      (lhs.unit == YGUnitAuto && rhs.unit == YGUnitAuto)) {
+    return true;
+  }
+
+  return lhs.unit == rhs.unit && lhs.value == rhs.value;
+}
+
+bool operator!=(const YGValue& lhs, const YGValue& rhs) {
+  return !(lhs == rhs);
+}
+
+#ifdef ANDROID
+#include <android/log.h>
+static int YGAndroidLog(
+    const YGConfigRef config,
+    const YGNodeRef node,
+    YGLogLevel level,
+    const char* format,
+    va_list args) {
+  int androidLevel = YGLogLevelDebug;
+  switch (level) {
+    case YGLogLevelFatal:
+      androidLevel = ANDROID_LOG_FATAL;
+      break;
+    case YGLogLevelError:
+      androidLevel = ANDROID_LOG_ERROR;
+      break;
+    case YGLogLevelWarn:
+      androidLevel = ANDROID_LOG_WARN;
+      break;
+    case YGLogLevelInfo:
+      androidLevel = ANDROID_LOG_INFO;
+      break;
+    case YGLogLevelDebug:
+      androidLevel = ANDROID_LOG_DEBUG;
+      break;
+    case YGLogLevelVerbose:
+      androidLevel = ANDROID_LOG_VERBOSE;
+      break;
+  }
+  const int result = __android_log_vprint(androidLevel, "yoga", format, args);
+  return result;
+}
+#else
+#define YG_UNUSED(x) (void)(x);
+
+static int YGDefaultLog(
+    const YGConfigRef config,
+    const YGNodeRef node,
+    YGLogLevel level,
+    const char* format,
+    va_list args) {
+  YG_UNUSED(config);
+  YG_UNUSED(node);
+  switch (level) {
+    case YGLogLevelError:
+    case YGLogLevelFatal:
+      return vfprintf(stderr, format, args);
+    case YGLogLevelWarn:
+    case YGLogLevelInfo:
+    case YGLogLevelDebug:
+    case YGLogLevelVerbose:
+    default:
+      return vprintf(format, args);
+  }
+}
+
+#undef YG_UNUSED
+#endif
+
+bool YGFloatIsUndefined(const float value) {
+  return facebook::yoga::isUndefined(value);
+}
+
+const YGValue* YGComputedEdgeValue(
+    const std::array<YGValue, YGEdgeCount>& edges,
+    const YGEdge edge,
+    const YGValue* const defaultValue) {
+  if (edges[edge].unit != YGUnitUndefined) {
+    return &edges[edge];
+  }
+
+  if ((edge == YGEdgeTop || edge == YGEdgeBottom) &&
+      edges[YGEdgeVertical].unit != YGUnitUndefined) {
+    return &edges[YGEdgeVertical];
+  }
+
+  if ((edge == YGEdgeLeft || edge == YGEdgeRight || edge == YGEdgeStart ||
+       edge == YGEdgeEnd) &&
+      edges[YGEdgeHorizontal].unit != YGUnitUndefined) {
+    return &edges[YGEdgeHorizontal];
+  }
+
+  if (edges[YGEdgeAll].unit != YGUnitUndefined) {
+    return &edges[YGEdgeAll];
+  }
+
+  if (edge == YGEdgeStart || edge == YGEdgeEnd) {
+    return &YGValueUndefined;
+  }
+
+  return defaultValue;
+}
+
+void* YGNodeGetContext(YGNodeRef node) {
+  return node->getContext();
+}
+
+void YGNodeSetContext(YGNodeRef node, void* context) {
+  return node->setContext(context);
+}
+
+YGMeasureFunc YGNodeGetMeasureFunc(YGNodeRef node) {
+  return node->getMeasure();
+}
+
+void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc) {
+  node->setMeasureFunc(measureFunc);
+}
+
+YGBaselineFunc YGNodeGetBaselineFunc(YGNodeRef node) {
+  return node->getBaseline();
+}
+
+void YGNodeSetBaselineFunc(YGNodeRef node, YGBaselineFunc baselineFunc) {
+  node->setBaseLineFunc(baselineFunc);
+}
+
+YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeRef node) {
+  return node->getDirtied();
+}
+
+void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc) {
+  node->setDirtiedFunc(dirtiedFunc);
+}
+
+YGPrintFunc YGNodeGetPrintFunc(YGNodeRef node) {
+  return node->getPrintFunc();
+}
+
+void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc) {
+  node->setPrintFunc(printFunc);
+}
+
+bool YGNodeGetHasNewLayout(YGNodeRef node) {
+  return node->getHasNewLayout();
+}
+
+void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled) {
+  config->printTree = enabled;
+}
+
+void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout) {
+  node->setHasNewLayout(hasNewLayout);
+}
+
+YGNodeType YGNodeGetNodeType(YGNodeRef node) {
+  return node->getNodeType();
+}
+
+void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType) {
+  return node->setNodeType(nodeType);
+}
+
+bool YGNodeIsDirty(YGNodeRef node) {
+  return node->isDirty();
+}
+
+bool YGNodeLayoutGetDidUseLegacyFlag(const YGNodeRef node) {
+  return node->didUseLegacyFlag();
+}
+
+void YGNodeMarkDirtyAndPropogateToDescendants(const YGNodeRef node) {
+  return node->markDirtyAndPropogateDownwards();
+}
+
+int32_t gNodeInstanceCount = 0;
+int32_t gConfigInstanceCount = 0;
+
+WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) {
+  const YGNodeRef node = new YGNode();
+  YGAssertWithConfig(
+      config, node != nullptr, "Could not allocate memory for node");
+  gNodeInstanceCount++;
+
+  if (config->useWebDefaults) {
+    node->setStyleFlexDirection(YGFlexDirectionRow);
+    node->setStyleAlignContent(YGAlignStretch);
+  }
+  node->setConfig(config);
+  return node;
+}
+
+YGConfigRef YGConfigGetDefault() {
+  static YGConfigRef defaultConfig = YGConfigNew();
+  return defaultConfig;
+}
+
+YGNodeRef YGNodeNew(void) {
+  return YGNodeNewWithConfig(YGConfigGetDefault());
+}
+
+YGNodeRef YGNodeClone(YGNodeRef oldNode) {
+  YGNodeRef node = new YGNode(*oldNode);
+  YGAssertWithConfig(
+      oldNode->getConfig(),
+      node != nullptr,
+      "Could not allocate memory for node");
+  gNodeInstanceCount++;
+  node->setOwner(nullptr);
+  return node;
+}
+
+static YGConfigRef YGConfigClone(const YGConfig& oldConfig) {
+  const YGConfigRef config = new YGConfig(oldConfig);
+  YGAssert(config != nullptr, "Could not allocate memory for config");
+  if (config == nullptr) {
+    abort();
+  }
+  gConfigInstanceCount++;
+  return config;
+}
+
+static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) {
+  YGNodeRef node = YGNodeClone(oldNode);
+  YGVector vec = YGVector();
+  vec.reserve(oldNode->getChildren().size());
+  YGNodeRef childNode = nullptr;
+  for (auto* item : oldNode->getChildren()) {
+    childNode = YGNodeDeepClone(item);
+    childNode->setOwner(node);
+    vec.push_back(childNode);
+  }
+  node->setChildren(vec);
+
+  if (oldNode->getConfig() != nullptr) {
+    node->setConfig(YGConfigClone(*(oldNode->getConfig())));
+  }
+
+  return node;
+}
+
+void YGNodeFree(const YGNodeRef node) {
+  if (YGNodeRef owner = node->getOwner()) {
+    owner->removeChild(node);
+    node->setOwner(nullptr);
+  }
+
+  const uint32_t childCount = YGNodeGetChildCount(node);
+  for (uint32_t i = 0; i < childCount; i++) {
+    const YGNodeRef child = YGNodeGetChild(node, i);
+    child->setOwner(nullptr);
+  }
+
+  node->clearChildren();
+  delete node;
+  gNodeInstanceCount--;
+}
+
+static void YGConfigFreeRecursive(const YGNodeRef root) {
+  if (root->getConfig() != nullptr) {
+    gConfigInstanceCount--;
+    delete root->getConfig();
+  }
+  // Delete configs recursively for childrens
+  for (auto* child : root->getChildren()) {
+    YGConfigFreeRecursive(child);
+  }
+}
+
+void YGNodeFreeRecursive(const YGNodeRef root) {
+  while (YGNodeGetChildCount(root) > 0) {
+    const YGNodeRef child = YGNodeGetChild(root, 0);
+    if (child->getOwner() != root) {
+      // Don't free shared nodes that we don't own.
+      break;
+    }
+    YGNodeRemoveChild(root, child);
+    YGNodeFreeRecursive(child);
+  }
+  YGNodeFree(root);
+}
+
+void YGNodeReset(const YGNodeRef node) {
+  YGAssertWithNode(
+      node,
+      YGNodeGetChildCount(node) == 0,
+      "Cannot reset a node which still has children attached");
+  YGAssertWithNode(
+      node,
+      node->getOwner() == nullptr,
+      "Cannot reset a node still attached to a owner");
+
+  node->clearChildren();
+
+  const YGConfigRef config = node->getConfig();
+  *node = YGNode();
+  if (config->useWebDefaults) {
+    node->setStyleFlexDirection(YGFlexDirectionRow);
+    node->setStyleAlignContent(YGAlignStretch);
+  }
+  node->setConfig(config);
+}
+
+int32_t YGNodeGetInstanceCount(void) {
+  return gNodeInstanceCount;
+}
+
+int32_t YGConfigGetInstanceCount(void) {
+  return gConfigInstanceCount;
+}
+
+YGConfigRef YGConfigNew(void) {
+#ifdef ANDROID
+  const YGConfigRef config = new YGConfig(YGAndroidLog);
+#else
+  const YGConfigRef config = new YGConfig(YGDefaultLog);
+#endif
+  gConfigInstanceCount++;
+  return config;
+}
+
+void YGConfigFree(const YGConfigRef config) {
+  delete config;
+  gConfigInstanceCount--;
+}
+
+void YGConfigCopy(const YGConfigRef dest, const YGConfigRef src) {
+  memcpy(dest, src, sizeof(YGConfig));
+}
+
+void YGNodeInsertChild(
+    const YGNodeRef node,
+    const YGNodeRef child,
+    const uint32_t index) {
+  YGAssertWithNode(
+      node,
+      child->getOwner() == nullptr,
+      "Child already has a owner, it must be removed first.");
+
+  YGAssertWithNode(
+      node,
+      node->getMeasure() == nullptr,
+      "Cannot add child: Nodes with measure functions cannot have children.");
+
+  node->cloneChildrenIfNeeded();
+  node->insertChild(child, index);
+  YGNodeRef owner = child->getOwner() ? nullptr : node;
+  child->setOwner(owner);
+  node->markDirtyAndPropogate();
+}
+
+void YGNodeInsertSharedChild(
+    const YGNodeRef node,
+    const YGNodeRef child,
+    const uint32_t index) {
+  YGAssertWithNode(
+      node,
+      node->getMeasure() == nullptr,
+      "Cannot add child: Nodes with measure functions cannot have children.");
+
+  node->insertChild(child, index);
+  child->setOwner(nullptr);
+  node->markDirtyAndPropogate();
+}
+
+void YGNodeRemoveChild(const YGNodeRef owner, const YGNodeRef excludedChild) {
+  // This algorithm is a forked variant from cloneChildrenIfNeeded in YGNode
+  // that excludes a child.
+  const uint32_t childCount = YGNodeGetChildCount(owner);
+
+  if (childCount == 0) {
+    // This is an empty set. Nothing to remove.
+    return;
+  }
+  const YGNodeRef firstChild = YGNodeGetChild(owner, 0);
+  if (firstChild->getOwner() == owner) {
+    // If the first child has this node as its owner, we assume that it is
+    // already unique. We can now try to delete a child in this list.
+    if (owner->removeChild(excludedChild)) {
+      excludedChild->setLayout(
+          YGNode().getLayout()); // layout is no longer valid
+      excludedChild->setOwner(nullptr);
+      owner->markDirtyAndPropogate();
+    }
+    return;
+  }
+  // Otherwise we have to clone the node list except for the child we're trying
+  // to delete. We don't want to simply clone all children, because then the
+  // host will need to free the clone of the child that was just deleted.
+  const YGCloneNodeFunc cloneNodeCallback =
+      owner->getConfig()->cloneNodeCallback;
+  uint32_t nextInsertIndex = 0;
+  for (uint32_t i = 0; i < childCount; i++) {
+    const YGNodeRef oldChild = owner->getChild(i);
+    if (excludedChild == oldChild) {
+      // Ignore the deleted child. Don't reset its layout or owner since it is
+      // still valid in the other owner. However, since this owner has now
+      // changed, we need to mark it as dirty.
+      owner->markDirtyAndPropogate();
+      continue;
+    }
+    YGNodeRef newChild = nullptr;
+    if (cloneNodeCallback) {
+      newChild = cloneNodeCallback(oldChild, owner, nextInsertIndex);
+    }
+    if (newChild == nullptr) {
+      newChild = YGNodeClone(oldChild);
+    }
+    owner->replaceChild(newChild, nextInsertIndex);
+    newChild->setOwner(owner);
+
+    nextInsertIndex++;
+  }
+  while (nextInsertIndex < childCount) {
+    owner->removeChild(nextInsertIndex);
+    nextInsertIndex++;
+  }
+}
+
+void YGNodeRemoveAllChildren(const YGNodeRef owner) {
+  const uint32_t childCount = YGNodeGetChildCount(owner);
+  if (childCount == 0) {
+    // This is an empty set already. Nothing to do.
+    return;
+  }
+  const YGNodeRef firstChild = YGNodeGetChild(owner, 0);
+  if (firstChild->getOwner() == owner) {
+    // If the first child has this node as its owner, we assume that this child
+    // set is unique.
+    for (uint32_t i = 0; i < childCount; i++) {
+      const YGNodeRef oldChild = YGNodeGetChild(owner, i);
+      oldChild->setLayout(YGNode().getLayout()); // layout is no longer valid
+      oldChild->setOwner(nullptr);
+    }
+    owner->clearChildren();
+    owner->markDirtyAndPropogate();
+    return;
+  }
+  // Otherwise, we are not the owner of the child set. We don't have to do
+  // anything to clear it.
+  owner->setChildren(YGVector());
+  owner->markDirtyAndPropogate();
+}
+
+static void YGNodeSetChildrenInternal(
+    YGNodeRef const owner,
+    const std::vector<YGNodeRef>& children) {
+  if (!owner) {
+    return;
+  }
+  if (children.size() == 0) {
+    if (YGNodeGetChildCount(owner) > 0) {
+      for (YGNodeRef const child : owner->getChildren()) {
+        child->setLayout(YGLayout());
+        child->setOwner(nullptr);
+      }
+      owner->setChildren(YGVector());
+      owner->markDirtyAndPropogate();
+    }
+  } else {
+    if (YGNodeGetChildCount(owner) > 0) {
+      for (YGNodeRef const oldChild : owner->getChildren()) {
+        // Our new children may have nodes in common with the old children. We
+        // don't reset these common nodes.
+        if (std::find(children.begin(), children.end(), oldChild) ==
+            children.end()) {
+          oldChild->setLayout(YGLayout());
+          oldChild->setOwner(nullptr);
+        }
+      }
+    }
+    owner->setChildren(children);
+    for (YGNodeRef child : children) {
+      child->setOwner(owner);
+    }
+    owner->markDirtyAndPropogate();
+  }
+}
+
+void YGNodeSetChildren(
+    YGNodeRef const owner,
+    const YGNodeRef c[],
+    const uint32_t count) {
+  const YGVector children = {c, c + count};
+  YGNodeSetChildrenInternal(owner, children);
+}
+
+void YGNodeSetChildren(
+    YGNodeRef const owner,
+    const std::vector<YGNodeRef>& children) {
+  YGNodeSetChildrenInternal(owner, children);
+}
+
+YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index) {
+  if (index < node->getChildren().size()) {
+    return node->getChild(index);
+  }
+  return nullptr;
+}
+
+uint32_t YGNodeGetChildCount(const YGNodeRef node) {
+  return static_cast<uint32_t>(node->getChildren().size());
+}
+
+YGNodeRef YGNodeGetOwner(const YGNodeRef node) {
+  return node->getOwner();
+}
+
+YGNodeRef YGNodeGetParent(const YGNodeRef node) {
+  return node->getOwner();
+}
+
+void YGNodeMarkDirty(const YGNodeRef node) {
+  YGAssertWithNode(
+      node,
+      node->getMeasure() != nullptr,
+      "Only leaf nodes with custom measure functions"
+      "should manually mark themselves as dirty");
+
+  node->markDirtyAndPropogate();
+}
+
+void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode) {
+  if (!(dstNode->getStyle() == srcNode->getStyle())) {
+    dstNode->setStyle(srcNode->getStyle());
+    dstNode->markDirtyAndPropogate();
+  }
+}
+
+float YGNodeStyleGetFlexGrow(const YGNodeRef node) {
+  return node->getStyle().flexGrow.isUndefined()
+      ? kDefaultFlexGrow
+      : node->getStyle().flexGrow.getValue();
+}
+
+float YGNodeStyleGetFlexShrink(const YGNodeRef node) {
+  return node->getStyle().flexShrink.isUndefined()
+      ? (node->getConfig()->useWebDefaults ? kWebDefaultFlexShrink
+                                           : kDefaultFlexShrink)
+      : node->getStyle().flexShrink.getValue();
+}
+
+namespace {
+
+template <typename T, T YGStyle::*P>
+struct StyleProp {
+  static T get(YGNodeRef node) {
+    return node->getStyle().*P;
+  }
+  static void set(YGNodeRef node, T newValue) {
+    if (node->getStyle().*P != newValue) {
+      node->getStyle().*P = newValue;
+      node->markDirtyAndPropogate();
+    }
+  }
+};
+
+struct Value {
+  template <YGUnit U>
+  static YGValue create(float value) {
+    return {
+        YGFloatSanitize(value),
+        YGFloatIsUndefined(value) ? YGUnitUndefined : U,
+    };
+  }
+};
+
+template <YGStyle::Dimensions YGStyle::*P>
+struct DimensionProp {
+  template <YGDimension idx>
+  static WIN_STRUCT(YGValue) get(YGNodeRef node) {
+    YGValue value = (node->getStyle().*P)[idx];
+    if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) {
+      value.value = YGUndefined;
+    }
+    return WIN_STRUCT_REF(value);
+  }
+
+  template <YGDimension idx, YGUnit U>
+  static void set(YGNodeRef node, float newValue) {
+    YGValue value = Value::create<U>(newValue);
+    if (((node->getStyle().*P)[idx].value != value.value &&
+         value.unit != YGUnitUndefined) ||
+        (node->getStyle().*P)[idx].unit != value.unit) {
+      (node->getStyle().*P)[idx] = value;
+      node->markDirtyAndPropogate();
+    }
+  }
+};
+
+} // namespace
+
+#define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL(                        \
+    type, name, paramName, instanceName)                                     \
+  void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) {    \
+    YGValue value = {                                                        \
+        YGFloatSanitize(paramName),                                          \
+        YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint,       \
+    };                                                                       \
+    if ((node->getStyle().instanceName.value != value.value &&               \
+         value.unit != YGUnitUndefined) ||                                   \
+        node->getStyle().instanceName.unit != value.unit) {                  \
+      node->getStyle().instanceName = value;                                 \
+      node->markDirtyAndPropogate();                                         \
+    }                                                                        \
+  }                                                                          \
+                                                                             \
+  void YGNodeStyleSet##name##Percent(                                        \
+      const YGNodeRef node, const type paramName) {                          \
+    if (node->getStyle().instanceName.value != YGFloatSanitize(paramName) || \
+        node->getStyle().instanceName.unit != YGUnitPercent) {               \
+      node->getStyle().instanceName = YGFloatIsUndefined(paramName)          \
+          ? YGValue{0, YGUnitAuto}                                           \
+          : YGValue{paramName, YGUnitPercent};                               \
+      node->markDirtyAndPropogate();                                         \
+    }                                                                        \
+  }                                                                          \
+                                                                             \
+  void YGNodeStyleSet##name##Auto(const YGNodeRef node) {                    \
+    if (node->getStyle().instanceName.unit != YGUnitAuto) {                  \
+      node->getStyle().instanceName = {0, YGUnitAuto};                       \
+      node->markDirtyAndPropogate();                                         \
+    }                                                                        \
+  }
+
+#define YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(                       \
+    type, name, paramName, instanceName)                             \
+  YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL(                      \
+      float, name, paramName, instanceName)                          \
+                                                                     \
+  type YGNodeStyleGet##name(const YGNodeRef node) {                  \
+    YGValue value = node->getStyle().instanceName;                   \
+    if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \
+      value.value = YGUndefined;                                     \
+    }                                                                \
+    return value;                                                    \
+  }
+
+#define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(type, name, instanceName) \
+  void YGNodeStyleSet##name##Auto(const YGNodeRef node, const YGEdge edge) { \
+    if (node->getStyle().instanceName[edge].unit != YGUnitAuto) {            \
+      node->getStyle().instanceName[edge] = {0, YGUnitAuto};                 \
+      node->markDirtyAndPropogate();                                         \
+    }                                                                        \
+  }
+
+#define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(                           \
+    type, name, paramName, instanceName)                                 \
+  void YGNodeStyleSet##name(                                             \
+      const YGNodeRef node, const YGEdge edge, const float paramName) {  \
+    YGValue value = {                                                    \
+        YGFloatSanitize(paramName),                                      \
+        YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint,   \
+    };                                                                   \
+    if ((node->getStyle().instanceName[edge].value != value.value &&     \
+         value.unit != YGUnitUndefined) ||                               \
+        node->getStyle().instanceName[edge].unit != value.unit) {        \
+      node->getStyle().instanceName[edge] = value;                       \
+      node->markDirtyAndPropogate();                                     \
+    }                                                                    \
+  }                                                                      \
+                                                                         \
+  void YGNodeStyleSet##name##Percent(                                    \
+      const YGNodeRef node, const YGEdge edge, const float paramName) {  \
+    YGValue value = {                                                    \
+        YGFloatSanitize(paramName),                                      \
+        YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \
+    };                                                                   \
+    if ((node->getStyle().instanceName[edge].value != value.value &&     \
+         value.unit != YGUnitUndefined) ||                               \
+        node->getStyle().instanceName[edge].unit != value.unit) {        \
+      node->getStyle().instanceName[edge] = value;                       \
+      node->markDirtyAndPropogate();                                     \
+    }                                                                    \
+  }                                                                      \
+                                                                         \
+  WIN_STRUCT(type)                                                       \
+  YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) {        \
+    YGValue value = node->getStyle().instanceName[edge];                 \
+    if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) {     \
+      value.value = YGUndefined;                                         \
+    }                                                                    \
+    return WIN_STRUCT_REF(value);                                        \
+  }
+
+#define YG_NODE_LAYOUT_PROPERTY_IMPL(type, name, instanceName) \
+  type YGNodeLayoutGet##name(const YGNodeRef node) {           \
+    return node->getLayout().instanceName;                     \
+  }
+
+#define YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(type, name, instanceName) \
+  type YGNodeLayoutGet##name(const YGNodeRef node, const YGEdge edge) { \
+    YGAssertWithNode(                                                   \
+        node,                                                           \
+        edge <= YGEdgeEnd,                                              \
+        "Cannot get layout properties of multi-edge shorthands");       \
+                                                                        \
+    if (edge == YGEdgeLeft) {                                           \
+      if (node->getLayout().direction == YGDirectionRTL) {              \
+        return node->getLayout().instanceName[YGEdgeEnd];               \
+      } else {                                                          \
+        return node->getLayout().instanceName[YGEdgeStart];             \
+      }                                                                 \
+    }                                                                   \
+                                                                        \
+    if (edge == YGEdgeRight) {                                          \
+      if (node->getLayout().direction == YGDirectionRTL) {              \
+        return node->getLayout().instanceName[YGEdgeStart];             \
+      } else {                                                          \
+        return node->getLayout().instanceName[YGEdgeEnd];               \
+      }                                                                 \
+    }                                                                   \
+                                                                        \
+    return node->getLayout().instanceName[edge];                        \
+  }
+
+void YGNodeStyleSetDirection(
+    const YGNodeRef node,
+    const YGDirection direction) {
+  StyleProp<YGDirection, &YGStyle::direction>::set(node, direction);
+}
+YGDirection YGNodeStyleGetDirection(const YGNodeRef node) {
+  return StyleProp<YGDirection, &YGStyle::direction>::get(node);
+}
+
+void YGNodeStyleSetFlexDirection(
+    const YGNodeRef node,
+    const YGFlexDirection flexDirection) {
+  StyleProp<YGFlexDirection, &YGStyle::flexDirection>::set(node, flexDirection);
+}
+YGFlexDirection YGNodeStyleGetFlexDirection(const YGNodeRef node) {
+  return StyleProp<YGFlexDirection, &YGStyle::flexDirection>::get(node);
+}
+
+void YGNodeStyleSetJustifyContent(
+    const YGNodeRef node,
+    const YGJustify justifyContent) {
+  StyleProp<YGJustify, &YGStyle::justifyContent>::set(node, justifyContent);
+}
+YGJustify YGNodeStyleGetJustifyContent(const YGNodeRef node) {
+  return StyleProp<YGJustify, &YGStyle::justifyContent>::get(node);
+}
+
+void YGNodeStyleSetAlignContent(
+    const YGNodeRef node,
+    const YGAlign alignContent) {
+  StyleProp<YGAlign, &YGStyle::alignContent>::set(node, alignContent);
+}
+YGAlign YGNodeStyleGetAlignContent(const YGNodeRef node) {
+  return StyleProp<YGAlign, &YGStyle::alignContent>::get(node);
+}
+
+void YGNodeStyleSetAlignItems(const YGNodeRef node, const YGAlign alignItems) {
+  StyleProp<YGAlign, &YGStyle::alignItems>::set(node, alignItems);
+}
+YGAlign YGNodeStyleGetAlignItems(const YGNodeRef node) {
+  return StyleProp<YGAlign, &YGStyle::alignItems>::get(node);
+}
+
+void YGNodeStyleSetAlignSelf(const YGNodeRef node, const YGAlign alignSelf) {
+  StyleProp<YGAlign, &YGStyle::alignSelf>::set(node, alignSelf);
+}
+YGAlign YGNodeStyleGetAlignSelf(const YGNodeRef node) {
+  return StyleProp<YGAlign, &YGStyle::alignSelf>::get(node);
+}
+
+void YGNodeStyleSetPositionType(
+    const YGNodeRef node,
+    const YGPositionType positionType) {
+  StyleProp<YGPositionType, &YGStyle::positionType>::set(node, positionType);
+}
+YGPositionType YGNodeStyleGetPositionType(const YGNodeRef node) {
+  return StyleProp<YGPositionType, &YGStyle::positionType>::get(node);
+}
+
+void YGNodeStyleSetFlexWrap(const YGNodeRef node, const YGWrap flexWrap) {
+  StyleProp<YGWrap, &YGStyle::flexWrap>::set(node, flexWrap);
+}
+YGWrap YGNodeStyleGetFlexWrap(const YGNodeRef node) {
+  return StyleProp<YGWrap, &YGStyle::flexWrap>::get(node);
+}
+
+void YGNodeStyleSetOverflow(const YGNodeRef node, const YGOverflow overflow) {
+  StyleProp<YGOverflow, &YGStyle::overflow>::set(node, overflow);
+}
+YGOverflow YGNodeStyleGetOverflow(const YGNodeRef node) {
+  return StyleProp<YGOverflow, &YGStyle::overflow>::get(node);
+}
+
+void YGNodeStyleSetDisplay(const YGNodeRef node, const YGDisplay display) {
+  StyleProp<YGDisplay, &YGStyle::display>::set(node, display);
+}
+YGDisplay YGNodeStyleGetDisplay(const YGNodeRef node) {
+  return StyleProp<YGDisplay, &YGStyle::display>::get(node);
+}
+
+// TODO(T26792433): Change the API to accept YGFloatOptional.
+void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) {
+  if (node->getStyle().flex != flex) {
+    node->getStyle().flex =
+        YGFloatIsUndefined(flex) ? YGFloatOptional() : YGFloatOptional(flex);
+    node->markDirtyAndPropogate();
+  }
+}
+
+// TODO(T26792433): Change the API to accept YGFloatOptional.
+float YGNodeStyleGetFlex(const YGNodeRef node) {
+  return node->getStyle().flex.isUndefined() ? YGUndefined
+                                             : node->getStyle().flex.getValue();
+}
+
+// TODO(T26792433): Change the API to accept YGFloatOptional.
+void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) {
+  if (node->getStyle().flexGrow != flexGrow) {
+    node->getStyle().flexGrow = YGFloatIsUndefined(flexGrow)
+        ? YGFloatOptional()
+        : YGFloatOptional(flexGrow);
+    node->markDirtyAndPropogate();
+  }
+}
+
+// TODO(T26792433): Change the API to accept YGFloatOptional.
+void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) {
+  if (node->getStyle().flexShrink != flexShrink) {
+    node->getStyle().flexShrink = YGFloatIsUndefined(flexShrink)
+        ? YGFloatOptional()
+        : YGFloatOptional(flexShrink);
+    node->markDirtyAndPropogate();
+  }
+}
+
+YGValue YGNodeStyleGetFlexBasis(const YGNodeRef node) {
+  YGValue flexBasis = node->getStyle().flexBasis;
+  if (flexBasis.unit == YGUnitUndefined || flexBasis.unit == YGUnitAuto) {
+    // TODO(T26792433): Get rid off the use of YGUndefined at client side
+    flexBasis.value = YGUndefined;
+  }
+  return flexBasis;
+}
+
+void YGNodeStyleSetFlexBasis(const YGNodeRef node, const float flexBasis) {
+  YGValue value = {
+      YGFloatSanitize(flexBasis),
+      YGFloatIsUndefined(flexBasis) ? YGUnitUndefined : YGUnitPoint,
+  };
+  if ((node->getStyle().flexBasis.value != value.value &&
+       value.unit != YGUnitUndefined) ||
+      node->getStyle().flexBasis.unit != value.unit) {
+    node->getStyle().flexBasis = value;
+    node->markDirtyAndPropogate();
+  }
+}
+
+void YGNodeStyleSetFlexBasisPercent(
+    const YGNodeRef node,
+    const float flexBasisPercent) {
+  if (node->getStyle().flexBasis.value != flexBasisPercent ||
+      node->getStyle().flexBasis.unit != YGUnitPercent) {
+    node->getStyle().flexBasis = YGFloatIsUndefined(flexBasisPercent)
+        ? YGValue{0, YGUnitAuto}
+        : YGValue{flexBasisPercent, YGUnitPercent};
+    node->markDirtyAndPropogate();
+  }
+}
+
+void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) {
+  if (node->getStyle().flexBasis.unit != YGUnitAuto) {
+    node->getStyle().flexBasis = {0, YGUnitAuto};
+    node->markDirtyAndPropogate();
+  }
+}
+
+YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Position, position, position);
+YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Margin, margin, margin);
+YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Margin, margin);
+YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Padding, padding, padding);
+
+// TODO(T26792433): Change the API to accept YGFloatOptional.
+void YGNodeStyleSetBorder(
+    const YGNodeRef node,
+    const YGEdge edge,
+    const float border) {
+  YGValue value = {
+      YGFloatSanitize(border),
+      YGFloatIsUndefined(border) ? YGUnitUndefined : YGUnitPoint,
+  };
+  if ((node->getStyle().border[edge].value != value.value &&
+       value.unit != YGUnitUndefined) ||
+      node->getStyle().border[edge].unit != value.unit) {
+    node->getStyle().border[edge] = value;
+    node->markDirtyAndPropogate();
+  }
+}
+
+float YGNodeStyleGetBorder(const YGNodeRef node, const YGEdge edge) {
+  if (node->getStyle().border[edge].unit == YGUnitUndefined ||
+      node->getStyle().border[edge].unit == YGUnitAuto) {
+    // TODO(T26792433): Rather than returning YGUndefined, change the api to
+    // return YGFloatOptional.
+    return YGUndefined;
+  }
+
+  return node->getStyle().border[edge].value;
+}
+
+// Yoga specific properties, not compatible with flexbox specification
+
+// TODO(T26792433): Change the API to accept YGFloatOptional.
+float YGNodeStyleGetAspectRatio(const YGNodeRef node) {
+  const YGFloatOptional op = node->getStyle().aspectRatio;
+  return op.isUndefined() ? YGUndefined : op.getValue();
+}
+
+// TODO(T26792433): Change the API to accept YGFloatOptional.
+void YGNodeStyleSetAspectRatio(const YGNodeRef node, const float aspectRatio) {
+  if (node->getStyle().aspectRatio != aspectRatio) {
+    node->getStyle().aspectRatio = YGFloatOptional(aspectRatio);
+    node->markDirtyAndPropogate();
+  }
+}
+
+YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(
+    YGValue,
+    Width,
+    width,
+    dimensions[YGDimensionWidth]);
+YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(
+    YGValue,
+    Height,
+    height,
+    dimensions[YGDimensionHeight]);
+
+void YGNodeStyleSetMinWidth(const YGNodeRef node, const float minWidth) {
+  DimensionProp<&YGStyle::minDimensions>::set<YGDimensionWidth, YGUnitPoint>(
+      node, minWidth);
+}
+void YGNodeStyleSetMinWidthPercent(const YGNodeRef node, const float minWidth) {
+  DimensionProp<&YGStyle::minDimensions>::set<YGDimensionWidth, YGUnitPercent>(
+      node, minWidth);
+}
+YGValue YGNodeStyleGetMinWidth(const YGNodeRef node) {
+  return DimensionProp<&YGStyle::minDimensions>::get<YGDimensionWidth>(node);
+};
+
+void YGNodeStyleSetMinHeight(const YGNodeRef node, const float minHeight) {
+  DimensionProp<&YGStyle::minDimensions>::set<YGDimensionHeight, YGUnitPoint>(
+      node, minHeight);
+}
+void YGNodeStyleSetMinHeightPercent(
+    const YGNodeRef node,
+    const float minHeight) {
+  DimensionProp<&YGStyle::minDimensions>::set<YGDimensionHeight, YGUnitPercent>(
+      node, minHeight);
+}
+YGValue YGNodeStyleGetMinHeight(const YGNodeRef node) {
+  return DimensionProp<&YGStyle::minDimensions>::get<YGDimensionHeight>(node);
+};
+
+void YGNodeStyleSetMaxWidth(const YGNodeRef node, const float maxWidth) {
+  DimensionProp<&YGStyle::maxDimensions>::set<YGDimensionWidth, YGUnitPoint>(
+      node, maxWidth);
+}
+void YGNodeStyleSetMaxWidthPercent(const YGNodeRef node, const float maxWidth) {
+  DimensionProp<&YGStyle::maxDimensions>::set<YGDimensionWidth, YGUnitPercent>(
+      node, maxWidth);
+}
+YGValue YGNodeStyleGetMaxWidth(const YGNodeRef node) {
+  return DimensionProp<&YGStyle::maxDimensions>::get<YGDimensionWidth>(node);
+};
+
+void YGNodeStyleSetMaxHeight(const YGNodeRef node, const float maxHeight) {
+  DimensionProp<&YGStyle::maxDimensions>::set<YGDimensionHeight, YGUnitPoint>(
+      node, maxHeight);
+}
+void YGNodeStyleSetMaxHeightPercent(
+    const YGNodeRef node,
+    const float maxHeight) {
+  DimensionProp<&YGStyle::maxDimensions>::set<YGDimensionHeight, YGUnitPercent>(
+      node, maxHeight);
+}
+YGValue YGNodeStyleGetMaxHeight(const YGNodeRef node) {
+  return DimensionProp<&YGStyle::maxDimensions>::get<YGDimensionHeight>(node);
+};
+
+YG_NODE_LAYOUT_PROPERTY_IMPL(float, Left, position[YGEdgeLeft]);
+YG_NODE_LAYOUT_PROPERTY_IMPL(float, Top, position[YGEdgeTop]);
+YG_NODE_LAYOUT_PROPERTY_IMPL(float, Right, position[YGEdgeRight]);
+YG_NODE_LAYOUT_PROPERTY_IMPL(float, Bottom, position[YGEdgeBottom]);
+YG_NODE_LAYOUT_PROPERTY_IMPL(float, Width, dimensions[YGDimensionWidth]);
+YG_NODE_LAYOUT_PROPERTY_IMPL(float, Height, dimensions[YGDimensionHeight]);
+YG_NODE_LAYOUT_PROPERTY_IMPL(YGDirection, Direction, direction);
+YG_NODE_LAYOUT_PROPERTY_IMPL(bool, HadOverflow, hadOverflow);
+
+YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Margin, margin);
+YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Border, border);
+YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Padding, padding);
+
+bool YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(const YGNodeRef node) {
+  return node->getLayout().doesLegacyStretchFlagAffectsLayout;
+}
+
+uint32_t gCurrentGenerationCount = 0;
+
+bool YGLayoutNodeInternal(
+    const YGNodeRef node,
+    const float availableWidth,
+    const float availableHeight,
+    const YGDirection ownerDirection,
+    const YGMeasureMode widthMeasureMode,
+    const YGMeasureMode heightMeasureMode,
+    const float ownerWidth,
+    const float ownerHeight,
+    const bool performLayout,
+    const char* reason,
+    const YGConfigRef config);
+
+static void YGNodePrintInternal(
+    const YGNodeRef node,
+    const YGPrintOptions options) {
+  std::string str;
+  facebook::yoga::YGNodeToString(&str, node, options, 0);
+  YGLog(node, YGLogLevelDebug, str.c_str());
+}
+
+void YGNodePrint(const YGNodeRef node, const YGPrintOptions options) {
+  YGNodePrintInternal(node, options);
+}
+
+const std::array<YGEdge, 4> leading = {
+    {YGEdgeTop, YGEdgeBottom, YGEdgeLeft, YGEdgeRight}};
+
+const std::array<YGEdge, 4> trailing = {
+    {YGEdgeBottom, YGEdgeTop, YGEdgeRight, YGEdgeLeft}};
+static const std::array<YGEdge, 4> pos = {{
+    YGEdgeTop,
+    YGEdgeBottom,
+    YGEdgeLeft,
+    YGEdgeRight,
+}};
+
+static const std::array<YGDimension, 4> dim = {
+    {YGDimensionHeight, YGDimensionHeight, YGDimensionWidth, YGDimensionWidth}};
+
+static inline float YGNodePaddingAndBorderForAxis(
+    const YGNodeRef node,
+    const YGFlexDirection axis,
+    const float widthSize) {
+  return YGUnwrapFloatOptional(
+      node->getLeadingPaddingAndBorder(axis, widthSize) +
+      node->getTrailingPaddingAndBorder(axis, widthSize));
+}
+
+static inline YGAlign YGNodeAlignItem(
+    const YGNodeRef node,
+    const YGNodeRef child) {
+  const YGAlign align = child->getStyle().alignSelf == YGAlignAuto
+      ? node->getStyle().alignItems
+      : child->getStyle().alignSelf;
+  if (align == YGAlignBaseline &&
+      YGFlexDirectionIsColumn(node->getStyle().flexDirection)) {
+    return YGAlignFlexStart;
+  }
+  return align;
+}
+
+static float YGBaseline(const YGNodeRef node) {
+  if (node->getBaseline() != nullptr) {
+    const float baseline = node->getBaseline()(
+        node,
+        node->getLayout().measuredDimensions[YGDimensionWidth],
+        node->getLayout().measuredDimensions[YGDimensionHeight]);
+    YGAssertWithNode(
+        node,
+        !YGFloatIsUndefined(baseline),
+        "Expect custom baseline function to not return NaN");
+    return baseline;
+  }
+
+  YGNodeRef baselineChild = nullptr;
+  const uint32_t childCount = YGNodeGetChildCount(node);
+  for (uint32_t i = 0; i < childCount; i++) {
+    const YGNodeRef child = YGNodeGetChild(node, i);
+    if (child->getLineIndex() > 0) {
+      break;
+    }
+    if (child->getStyle().positionType == YGPositionTypeAbsolute) {
+      continue;
+    }
+    if (YGNodeAlignItem(node, child) == YGAlignBaseline) {
+      baselineChild = child;
+      break;
+    }
+
+    if (baselineChild == nullptr) {
+      baselineChild = child;
+    }
+  }
+
+  if (baselineChild == nullptr) {
+    return node->getLayout().measuredDimensions[YGDimensionHeight];
+  }
+
+  const float baseline = YGBaseline(baselineChild);
+  return baseline + baselineChild->getLayout().position[YGEdgeTop];
+}
+
+static bool YGIsBaselineLayout(const YGNodeRef node) {
+  if (YGFlexDirectionIsColumn(node->getStyle().flexDirection)) {
+    return false;
+  }
+  if (node->getStyle().alignItems == YGAlignBaseline) {
+    return true;
+  }
+  const uint32_t childCount = YGNodeGetChildCount(node);
+  for (uint32_t i = 0; i < childCount; i++) {
+    const YGNodeRef child = YGNodeGetChild(node, i);
+    if (child->getStyle().positionType == YGPositionTypeRelative &&
+        child->getStyle().alignSelf == YGAlignBaseline) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+static inline float YGNodeDimWithMargin(
+    const YGNodeRef node,
+    const YGFlexDirection axis,
+    const float widthSize) {
+  return node->getLayout().measuredDimensions[dim[axis]] +
+      YGUnwrapFloatOptional(
+             node->getLeadingMargin(axis, widthSize) +
+             node->getTrailingMargin(axis, widthSize));
+}
+
+static inline bool YGNodeIsStyleDimDefined(
+    const YGNodeRef node,
+    const YGFlexDirection axis,
+    const float ownerSize) {
+  bool isUndefined =
+      YGFloatIsUndefined(node->getResolvedDimension(dim[axis]).value);
+  return !(
+      node->getResolvedDimension(dim[axis]).unit == YGUnitAuto ||
+      node->getResolvedDimension(dim[axis]).unit == YGUnitUndefined ||
+      (node->getResolvedDimension(dim[axis]).unit == YGUnitPoint &&
+       !isUndefined && node->getResolvedDimension(dim[axis]).value < 0.0f) ||
+      (node->getResolvedDimension(dim[axis]).unit == YGUnitPercent &&
+       !isUndefined &&
+       (node->getResolvedDimension(dim[axis]).value < 0.0f ||
+        YGFloatIsUndefined(ownerSize))));
+}
+
+static inline bool YGNodeIsLayoutDimDefined(
+    const YGNodeRef node,
+    const YGFlexDirection axis) {
+  const float value = node->getLayout().measuredDimensions[dim[axis]];
+  return !YGFloatIsUndefined(value) && value >= 0.0f;
+}
+
+static YGFloatOptional YGNodeBoundAxisWithinMinAndMax(
+    const YGNodeRef node,
+    const YGFlexDirection& axis,
+    const float& value,
+    const float& axisSize) {
+  YGFloatOptional min;
+  YGFloatOptional max;
+
+  if (YGFlexDirectionIsColumn(axis)) {
+    min = YGResolveValue(
+        node->getStyle().minDimensions[YGDimensionHeight], axisSize);
+    max = YGResolveValue(
+        node->getStyle().maxDimensions[YGDimensionHeight], axisSize);
+  } else if (YGFlexDirectionIsRow(axis)) {
+    min = YGResolveValue(
+        node->getStyle().minDimensions[YGDimensionWidth], axisSize);
+    max = YGResolveValue(
+        node->getStyle().maxDimensions[YGDimensionWidth], axisSize);
+  }
+
+  if (!max.isUndefined() && max.getValue() >= 0 && value > max.getValue()) {
+    return max;
+  }
+
+  if (!min.isUndefined() && min.getValue() >= 0 && value < min.getValue()) {
+    return min;
+  }
+
+  return YGFloatOptional(value);
+}
+
+// Like YGNodeBoundAxisWithinMinAndMax but also ensures that the value doesn't
+// go below the padding and border amount.
+static inline float YGNodeBoundAxis(
+    const YGNodeRef node,
+    const YGFlexDirection axis,
+    const float value,
+    const float axisSize,
+    const float widthSize) {
+  return YGFloatMax(
+      YGUnwrapFloatOptional(
+          YGNodeBoundAxisWithinMinAndMax(node, axis, value, axisSize)),
+      YGNodePaddingAndBorderForAxis(node, axis, widthSize));
+}
+
+static void YGNodeSetChildTrailingPosition(
+    const YGNodeRef node,
+    const YGNodeRef child,
+    const YGFlexDirection axis) {
+  const float size = child->getLayout().measuredDimensions[dim[axis]];
+  child->setLayoutPosition(
+      node->getLayout().measuredDimensions[dim[axis]] - size -
+          child->getLayout().position[pos[axis]],
+      trailing[axis]);
+}
+
+static void YGConstrainMaxSizeForMode(
+    const YGNodeRef node,
+    const enum YGFlexDirection axis,
+    const float ownerAxisSize,
+    const float ownerWidth,
+    YGMeasureMode* mode,
+    float* size) {
+  const YGFloatOptional maxSize =
+      YGResolveValue(node->getStyle().maxDimensions[dim[axis]], ownerAxisSize) +
+      YGFloatOptional(node->getMarginForAxis(axis, ownerWidth));
+  switch (*mode) {
+    case YGMeasureModeExactly:
+    case YGMeasureModeAtMost:
+      *size = (maxSize.isUndefined() || *size < maxSize.getValue())
+          ? *size
+          : maxSize.getValue();
+      break;
+    case YGMeasureModeUndefined:
+      if (!maxSize.isUndefined()) {
+        *mode = YGMeasureModeAtMost;
+        *size = maxSize.getValue();
+      }
+      break;
+  }
+}
+
+static void YGNodeComputeFlexBasisForChild(
+    const YGNodeRef node,
+    const YGNodeRef child,
+    const float width,
+    const YGMeasureMode widthMode,
+    const float height,
+    const float ownerWidth,
+    const float ownerHeight,
+    const YGMeasureMode heightMode,
+    const YGDirection direction,
+    const YGConfigRef config) {
+  const YGFlexDirection mainAxis =
+      YGResolveFlexDirection(node->getStyle().flexDirection, direction);
+  const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
+  const float mainAxisSize = isMainAxisRow ? width : height;
+  const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight;
+
+  float childWidth;
+  float childHeight;
+  YGMeasureMode childWidthMeasureMode;
+  YGMeasureMode childHeightMeasureMode;
+
+  const YGFloatOptional resolvedFlexBasis =
+      YGResolveValue(child->resolveFlexBasisPtr(), mainAxisownerSize);
+  const bool isRowStyleDimDefined =
+      YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, ownerWidth);
+  const bool isColumnStyleDimDefined =
+      YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, ownerHeight);
+
+  if (!resolvedFlexBasis.isUndefined() && !YGFloatIsUndefined(mainAxisSize)) {
+    if (child->getLayout().computedFlexBasis.isUndefined() ||
+        (YGConfigIsExperimentalFeatureEnabled(
+             child->getConfig(), YGExperimentalFeatureWebFlexBasis) &&
+         child->getLayout().computedFlexBasisGeneration !=
+             gCurrentGenerationCount)) {
+      const YGFloatOptional& paddingAndBorder = YGFloatOptional(
+          YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth));
+      child->setLayoutComputedFlexBasis(
+          YGFloatOptionalMax(resolvedFlexBasis, paddingAndBorder));
+    }
+  } else if (isMainAxisRow && isRowStyleDimDefined) {
+    // The width is definite, so use that as the flex basis.
+    const YGFloatOptional& paddingAndBorder = YGFloatOptional(
+        YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, ownerWidth));
+
+    child->setLayoutComputedFlexBasis(YGFloatOptionalMax(
+        YGResolveValue(
+            child->getResolvedDimension(YGDimensionWidth), ownerWidth),
+        paddingAndBorder));
+  } else if (!isMainAxisRow && isColumnStyleDimDefined) {
+    // The height is definite, so use that as the flex basis.
+    const YGFloatOptional& paddingAndBorder =
+        YGFloatOptional(YGNodePaddingAndBorderForAxis(
+            child, YGFlexDirectionColumn, ownerWidth));
+    child->setLayoutComputedFlexBasis(YGFloatOptionalMax(
+        YGResolveValue(
+            child->getResolvedDimension(YGDimensionHeight), ownerHeight),
+        paddingAndBorder));
+  } else {
+    // Compute the flex basis and hypothetical main size (i.e. the clamped
+    // flex basis).
+    childWidth = YGUndefined;
+    childHeight = YGUndefined;
+    childWidthMeasureMode = YGMeasureModeUndefined;
+    childHeightMeasureMode = YGMeasureModeUndefined;
+
+    auto marginRow = YGUnwrapFloatOptional(
+        child->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
+    auto marginColumn = YGUnwrapFloatOptional(
+        child->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
+
+    if (isRowStyleDimDefined) {
+      childWidth =
+          YGUnwrapFloatOptional(YGResolveValue(
+              child->getResolvedDimension(YGDimensionWidth), ownerWidth)) +
+          marginRow;
+      childWidthMeasureMode = YGMeasureModeExactly;
+    }
+    if (isColumnStyleDimDefined) {
+      childHeight =
+          YGUnwrapFloatOptional(YGResolveValue(
+              child->getResolvedDimension(YGDimensionHeight), ownerHeight)) +
+          marginColumn;
+      childHeightMeasureMode = YGMeasureModeExactly;
+    }
+
+    // The W3C spec doesn't say anything about the 'overflow' property,
+    // but all major browsers appear to implement the following logic.
+    if ((!isMainAxisRow && node->getStyle().overflow == YGOverflowScroll) ||
+        node->getStyle().overflow != YGOverflowScroll) {
+      if (YGFloatIsUndefined(childWidth) && !YGFloatIsUndefined(width)) {
+        childWidth = width;
+        childWidthMeasureMode = YGMeasureModeAtMost;
+      }
+    }
+
+    if ((isMainAxisRow && node->getStyle().overflow == YGOverflowScroll) ||
+        node->getStyle().overflow != YGOverflowScroll) {
+      if (YGFloatIsUndefined(childHeight) && !YGFloatIsUndefined(height)) {
+        childHeight = height;
+        childHeightMeasureMode = YGMeasureModeAtMost;
+      }
+    }
+
+    if (!child->getStyle().aspectRatio.isUndefined()) {
+      if (!isMainAxisRow && childWidthMeasureMode == YGMeasureModeExactly) {
+        childHeight = marginColumn +
+            (childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
+        childHeightMeasureMode = YGMeasureModeExactly;
+      } else if (
+          isMainAxisRow && childHeightMeasureMode == YGMeasureModeExactly) {
+        childWidth = marginRow +
+            (childHeight - marginColumn) *
+                child->getStyle().aspectRatio.getValue();
+        childWidthMeasureMode = YGMeasureModeExactly;
+      }
+    }
+
+    // If child has no defined size in the cross axis and is set to stretch,
+    // set the cross
+    // axis to be measured exactly with the available inner width
+
+    const bool hasExactWidth =
+        !YGFloatIsUndefined(width) && widthMode == YGMeasureModeExactly;
+    const bool childWidthStretch =
+        YGNodeAlignItem(node, child) == YGAlignStretch &&
+        childWidthMeasureMode != YGMeasureModeExactly;
+    if (!isMainAxisRow && !isRowStyleDimDefined && hasExactWidth &&
+        childWidthStretch) {
+      childWidth = width;
+      childWidthMeasureMode = YGMeasureModeExactly;
+      if (!child->getStyle().aspectRatio.isUndefined()) {
+        childHeight =
+            (childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
+        childHeightMeasureMode = YGMeasureModeExactly;
+      }
+    }
+
+    const bool hasExactHeight =
+        !YGFloatIsUndefined(height) && heightMode == YGMeasureModeExactly;
+    const bool childHeightStretch =
+        YGNodeAlignItem(node, child) == YGAlignStretch &&
+        childHeightMeasureMode != YGMeasureModeExactly;
+    if (isMainAxisRow && !isColumnStyleDimDefined && hasExactHeight &&
+        childHeightStretch) {
+      childHeight = height;
+      childHeightMeasureMode = YGMeasureModeExactly;
+
+      if (!child->getStyle().aspectRatio.isUndefined()) {
+        childWidth = (childHeight - marginColumn) *
+            child->getStyle().aspectRatio.getValue();
+        childWidthMeasureMode = YGMeasureModeExactly;
+      }
+    }
+
+    YGConstrainMaxSizeForMode(
+        child,
+        YGFlexDirectionRow,
+        ownerWidth,
+        ownerWidth,
+        &childWidthMeasureMode,
+        &childWidth);
+    YGConstrainMaxSizeForMode(
+        child,
+        YGFlexDirectionColumn,
+        ownerHeight,
+        ownerWidth,
+        &childHeightMeasureMode,
+        &childHeight);
+
+    // Measure the child
+    YGLayoutNodeInternal(
+        child,
+        childWidth,
+        childHeight,
+        direction,
+        childWidthMeasureMode,
+        childHeightMeasureMode,
+        ownerWidth,
+        ownerHeight,
+        false,
+        "measure",
+        config);
+
+    child->setLayoutComputedFlexBasis(YGFloatOptional(YGFloatMax(
+        child->getLayout().measuredDimensions[dim[mainAxis]],
+        YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth))));
+  }
+  child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount);
+}
+
+static void YGNodeAbsoluteLayoutChild(
+    const YGNodeRef node,
+    const YGNodeRef child,
+    const float width,
+    const YGMeasureMode widthMode,
+    const float height,
+    const YGDirection direction,
+    const YGConfigRef config) {
+  const YGFlexDirection mainAxis =
+      YGResolveFlexDirection(node->getStyle().flexDirection, direction);
+  const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction);
+  const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
+
+  float childWidth = YGUndefined;
+  float childHeight = YGUndefined;
+  YGMeasureMode childWidthMeasureMode = YGMeasureModeUndefined;
+  YGMeasureMode childHeightMeasureMode = YGMeasureModeUndefined;
+
+  auto marginRow =
+      YGUnwrapFloatOptional(child->getMarginForAxis(YGFlexDirectionRow, width));
+  auto marginColumn = YGUnwrapFloatOptional(
+      child->getMarginForAxis(YGFlexDirectionColumn, width));
+
+  if (YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, width)) {
+    childWidth = YGUnwrapFloatOptional(YGResolveValue(
+                     child->getResolvedDimension(YGDimensionWidth), width)) +
+        marginRow;
+  } else {
+    // If the child doesn't have a specified width, compute the width based
+    // on the left/right
+    // offsets if they're defined.
+    if (child->isLeadingPositionDefined(YGFlexDirectionRow) &&
+        child->isTrailingPosDefined(YGFlexDirectionRow)) {
+      childWidth = node->getLayout().measuredDimensions[YGDimensionWidth] -
+          (node->getLeadingBorder(YGFlexDirectionRow) +
+           node->getTrailingBorder(YGFlexDirectionRow)) -
+          YGUnwrapFloatOptional(
+                       child->getLeadingPosition(YGFlexDirectionRow, width) +
+                       child->getTrailingPosition(YGFlexDirectionRow, width));
+      childWidth =
+          YGNodeBoundAxis(child, YGFlexDirectionRow, childWidth, width, width);
+    }
+  }
+
+  if (YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, height)) {
+    childHeight = YGUnwrapFloatOptional(YGResolveValue(
+                      child->getResolvedDimension(YGDimensionHeight), height)) +
+        marginColumn;
+  } else {
+    // If the child doesn't have a specified height, compute the height
+    // based on the top/bottom
+    // offsets if they're defined.
+    if (child->isLeadingPositionDefined(YGFlexDirectionColumn) &&
+        child->isTrailingPosDefined(YGFlexDirectionColumn)) {
+      childHeight =
+          node->getLayout().measuredDimensions[YGDimensionHeight] -
+          (node->getLeadingBorder(YGFlexDirectionColumn) +
+           node->getTrailingBorder(YGFlexDirectionColumn)) -
+          YGUnwrapFloatOptional(
+              child->getLeadingPosition(YGFlexDirectionColumn, height) +
+              child->getTrailingPosition(YGFlexDirectionColumn, height));
+      childHeight = YGNodeBoundAxis(
+          child, YGFlexDirectionColumn, childHeight, height, width);
+    }
+  }
+
+  // Exactly one dimension needs to be defined for us to be able to do aspect
+  // ratio calculation. One dimension being the anchor and the other being
+  // flexible.
+  if (YGFloatIsUndefined(childWidth) ^ YGFloatIsUndefined(childHeight)) {
+    if (!child->getStyle().aspectRatio.isUndefined()) {
+      if (YGFloatIsUndefined(childWidth)) {
+        childWidth = marginRow +
+            (childHeight - marginColumn) *
+                child->getStyle().aspectRatio.getValue();
+      } else if (YGFloatIsUndefined(childHeight)) {
+        childHeight = marginColumn +
+            (childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
+      }
+    }
+  }
+
+  // If we're still missing one or the other dimension, measure the content.
+  if (YGFloatIsUndefined(childWidth) || YGFloatIsUndefined(childHeight)) {
+    childWidthMeasureMode = YGFloatIsUndefined(childWidth)
+        ? YGMeasureModeUndefined
+        : YGMeasureModeExactly;
+    childHeightMeasureMode = YGFloatIsUndefined(childHeight)
+        ? YGMeasureModeUndefined
+        : YGMeasureModeExactly;
+
+    // If the size of the owner is defined then try to constrain the absolute
+    // child to that size as well. This allows text within the absolute child to
+    // wrap to the size of its owner. This is the same behavior as many browsers
+    // implement.
+    if (!isMainAxisRow && YGFloatIsUndefined(childWidth) &&
+        widthMode != YGMeasureModeUndefined && !YGFloatIsUndefined(width) &&
+        width > 0) {
+      childWidth = width;
+      childWidthMeasureMode = YGMeasureModeAtMost;
+    }
+
+    YGLayoutNodeInternal(
+        child,
+        childWidth,
+        childHeight,
+        direction,
+        childWidthMeasureMode,
+        childHeightMeasureMode,
+        childWidth,
+        childHeight,
+        false,
+        "abs-measure",
+        config);
+    childWidth = child->getLayout().measuredDimensions[YGDimensionWidth] +
+        YGUnwrapFloatOptional(
+                     child->getMarginForAxis(YGFlexDirectionRow, width));
+    childHeight = child->getLayout().measuredDimensions[YGDimensionHeight] +
+        YGUnwrapFloatOptional(
+                      child->getMarginForAxis(YGFlexDirectionColumn, width));
+  }
+
+  YGLayoutNodeInternal(
+      child,
+      childWidth,
+      childHeight,
+      direction,
+      YGMeasureModeExactly,
+      YGMeasureModeExactly,
+      childWidth,
+      childHeight,
+      true,
+      "abs-layout",
+      config);
+
+  if (child->isTrailingPosDefined(mainAxis) &&
+      !child->isLeadingPositionDefined(mainAxis)) {
+    child->setLayoutPosition(
+        node->getLayout().measuredDimensions[dim[mainAxis]] -
+            child->getLayout().measuredDimensions[dim[mainAxis]] -
+            node->getTrailingBorder(mainAxis) -
+            YGUnwrapFloatOptional(child->getTrailingMargin(mainAxis, width)) -
+            YGUnwrapFloatOptional(child->getTrailingPosition(
+                mainAxis, isMainAxisRow ? width : height)),
+        leading[mainAxis]);
+  } else if (
+      !child->isLeadingPositionDefined(mainAxis) &&
+      node->getStyle().justifyContent == YGJustifyCenter) {
+    child->setLayoutPosition(
+        (node->getLayout().measuredDimensions[dim[mainAxis]] -
+         child->getLayout().measuredDimensions[dim[mainAxis]]) /
+            2.0f,
+        leading[mainAxis]);
+  } else if (
+      !child->isLeadingPositionDefined(mainAxis) &&
+      node->getStyle().justifyContent == YGJustifyFlexEnd) {
+    child->setLayoutPosition(
+        (node->getLayout().measuredDimensions[dim[mainAxis]] -
+         child->getLayout().measuredDimensions[dim[mainAxis]]),
+        leading[mainAxis]);
+  }
+
+  if (child->isTrailingPosDefined(crossAxis) &&
+      !child->isLeadingPositionDefined(crossAxis)) {
+    child->setLayoutPosition(
+        node->getLayout().measuredDimensions[dim[crossAxis]] -
+            child->getLayout().measuredDimensions[dim[crossAxis]] -
+            node->getTrailingBorder(crossAxis) -
+            YGUnwrapFloatOptional(child->getTrailingMargin(crossAxis, width)) -
+            YGUnwrapFloatOptional(child->getTrailingPosition(
+                crossAxis, isMainAxisRow ? height : width)),
+        leading[crossAxis]);
+
+  } else if (
+      !child->isLeadingPositionDefined(crossAxis) &&
+      YGNodeAlignItem(node, child) == YGAlignCenter) {
+    child->setLayoutPosition(
+        (node->getLayout().measuredDimensions[dim[crossAxis]] -
+         child->getLayout().measuredDimensions[dim[crossAxis]]) /
+            2.0f,
+        leading[crossAxis]);
+  } else if (
+      !child->isLeadingPositionDefined(crossAxis) &&
+      ((YGNodeAlignItem(node, child) == YGAlignFlexEnd) ^
+       (node->getStyle().flexWrap == YGWrapWrapReverse))) {
+    child->setLayoutPosition(
+        (node->getLayout().measuredDimensions[dim[crossAxis]] -
+         child->getLayout().measuredDimensions[dim[crossAxis]]),
+        leading[crossAxis]);
+  }
+}
+
+static void YGNodeWithMeasureFuncSetMeasuredDimensions(
+    const YGNodeRef node,
+    const float availableWidth,
+    const float availableHeight,
+    const YGMeasureMode widthMeasureMode,
+    const YGMeasureMode heightMeasureMode,
+    const float ownerWidth,
+    const float ownerHeight) {
+  YGAssertWithNode(
+      node,
+      node->getMeasure() != nullptr,
+      "Expected node to have custom measure function");
+
+  const float paddingAndBorderAxisRow =
+      YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, availableWidth);
+  const float paddingAndBorderAxisColumn = YGNodePaddingAndBorderForAxis(
+      node, YGFlexDirectionColumn, availableWidth);
+  const float marginAxisRow = YGUnwrapFloatOptional(
+      node->getMarginForAxis(YGFlexDirectionRow, availableWidth));
+  const float marginAxisColumn = YGUnwrapFloatOptional(
+      node->getMarginForAxis(YGFlexDirectionColumn, availableWidth));
+
+  // We want to make sure we don't call measure with negative size
+  const float innerWidth = YGFloatIsUndefined(availableWidth)
+      ? availableWidth
+      : YGFloatMax(0, availableWidth - marginAxisRow - paddingAndBorderAxisRow);
+  const float innerHeight = YGFloatIsUndefined(availableHeight)
+      ? availableHeight
+      : YGFloatMax(
+            0, availableHeight - marginAxisColumn - paddingAndBorderAxisColumn);
+
+  if (widthMeasureMode == YGMeasureModeExactly &&
+      heightMeasureMode == YGMeasureModeExactly) {
+    // Don't bother sizing the text if both dimensions are already defined.
+    node->setLayoutMeasuredDimension(
+        YGNodeBoundAxis(
+            node,
+            YGFlexDirectionRow,
+            availableWidth - marginAxisRow,
+            ownerWidth,
+            ownerWidth),
+        YGDimensionWidth);
+    node->setLayoutMeasuredDimension(
+        YGNodeBoundAxis(
+            node,
+            YGFlexDirectionColumn,
+            availableHeight - marginAxisColumn,
+            ownerHeight,
+            ownerWidth),
+        YGDimensionHeight);
+  } else {
+    // Measure the text under the current constraints.
+    const YGSize measuredSize = node->getMeasure()(
+        node, innerWidth, widthMeasureMode, innerHeight, heightMeasureMode);
+
+    node->setLayoutMeasuredDimension(
+        YGNodeBoundAxis(
+            node,
+            YGFlexDirectionRow,
+            (widthMeasureMode == YGMeasureModeUndefined ||
+             widthMeasureMode == YGMeasureModeAtMost)
+                ? measuredSize.width + paddingAndBorderAxisRow
+                : availableWidth - marginAxisRow,
+            ownerWidth,
+            ownerWidth),
+        YGDimensionWidth);
+
+    node->setLayoutMeasuredDimension(
+        YGNodeBoundAxis(
+            node,
+            YGFlexDirectionColumn,
+            (heightMeasureMode == YGMeasureModeUndefined ||
+             heightMeasureMode == YGMeasureModeAtMost)
+                ? measuredSize.height + paddingAndBorderAxisColumn
+                : availableHeight - marginAxisColumn,
+            ownerHeight,
+            ownerWidth),
+        YGDimensionHeight);
+  }
+}
+
+// For nodes with no children, use the available values if they were provided,
+// or the minimum size as indicated by the padding and border sizes.
+static void YGNodeEmptyContainerSetMeasuredDimensions(
+    const YGNodeRef node,
+    const float availableWidth,
+    const float availableHeight,
+    const YGMeasureMode widthMeasureMode,
+    const YGMeasureMode heightMeasureMode,
+    const float ownerWidth,
+    const float ownerHeight) {
+  const float paddingAndBorderAxisRow =
+      YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, ownerWidth);
+  const float paddingAndBorderAxisColumn =
+      YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, ownerWidth);
+  const float marginAxisRow = YGUnwrapFloatOptional(
+      node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
+  const float marginAxisColumn = YGUnwrapFloatOptional(
+      node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
+
+  node->setLayoutMeasuredDimension(
+      YGNodeBoundAxis(
+          node,
+          YGFlexDirectionRow,
+          (widthMeasureMode == YGMeasureModeUndefined ||
+           widthMeasureMode == YGMeasureModeAtMost)
+              ? paddingAndBorderAxisRow
+              : availableWidth - marginAxisRow,
+          ownerWidth,
+          ownerWidth),
+      YGDimensionWidth);
+
+  node->setLayoutMeasuredDimension(
+      YGNodeBoundAxis(
+          node,
+          YGFlexDirectionColumn,
+          (heightMeasureMode == YGMeasureModeUndefined ||
+           heightMeasureMode == YGMeasureModeAtMost)
+              ? paddingAndBorderAxisColumn
+              : availableHeight - marginAxisColumn,
+          ownerHeight,
+          ownerWidth),
+      YGDimensionHeight);
+}
+
+static bool YGNodeFixedSizeSetMeasuredDimensions(
+    const YGNodeRef node,
+    const float availableWidth,
+    const float availableHeight,
+    const YGMeasureMode widthMeasureMode,
+    const YGMeasureMode heightMeasureMode,
+    const float ownerWidth,
+    const float ownerHeight) {
+  if ((!YGFloatIsUndefined(availableWidth) &&
+       widthMeasureMode == YGMeasureModeAtMost && availableWidth <= 0.0f) ||
+      (!YGFloatIsUndefined(availableHeight) &&
+       heightMeasureMode == YGMeasureModeAtMost && availableHeight <= 0.0f) ||
+      (widthMeasureMode == YGMeasureModeExactly &&
+       heightMeasureMode == YGMeasureModeExactly)) {
+    auto marginAxisColumn = YGUnwrapFloatOptional(
+        node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
+    auto marginAxisRow = YGUnwrapFloatOptional(
+        node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
+
+    node->setLayoutMeasuredDimension(
+        YGNodeBoundAxis(
+            node,
+            YGFlexDirectionRow,
+            YGFloatIsUndefined(availableWidth) ||
+                    (widthMeasureMode == YGMeasureModeAtMost &&
+                     availableWidth < 0.0f)
+                ? 0.0f
+                : availableWidth - marginAxisRow,
+            ownerWidth,
+            ownerWidth),
+        YGDimensionWidth);
+
+    node->setLayoutMeasuredDimension(
+        YGNodeBoundAxis(
+            node,
+            YGFlexDirectionColumn,
+            YGFloatIsUndefined(availableHeight) ||
+                    (heightMeasureMode == YGMeasureModeAtMost &&
+                     availableHeight < 0.0f)
+                ? 0.0f
+                : availableHeight - marginAxisColumn,
+            ownerHeight,
+            ownerWidth),
+        YGDimensionHeight);
+    return true;
+  }
+
+  return false;
+}
+
+static void YGZeroOutLayoutRecursivly(const YGNodeRef node) {
+  memset(&(node->getLayout()), 0, sizeof(YGLayout));
+  node->setHasNewLayout(true);
+  node->cloneChildrenIfNeeded();
+  const uint32_t childCount = YGNodeGetChildCount(node);
+  for (uint32_t i = 0; i < childCount; i++) {
+    const YGNodeRef child = node->getChild(i);
+    YGZeroOutLayoutRecursivly(child);
+  }
+}
+
+static float YGNodeCalculateAvailableInnerDim(
+    const YGNodeRef node,
+    YGFlexDirection axis,
+    float availableDim,
+    float ownerDim) {
+  YGFlexDirection direction =
+      YGFlexDirectionIsRow(axis) ? YGFlexDirectionRow : YGFlexDirectionColumn;
+  YGDimension dimension =
+      YGFlexDirectionIsRow(axis) ? YGDimensionWidth : YGDimensionHeight;
+
+  const float margin =
+      YGUnwrapFloatOptional(node->getMarginForAxis(direction, ownerDim));
+  const float paddingAndBorder =
+      YGNodePaddingAndBorderForAxis(node, direction, ownerDim);
+
+  float availableInnerDim = availableDim - margin - paddingAndBorder;
+  // Max dimension overrides predefined dimension value; Min dimension in turn
+  // overrides both of the above
+  if (!YGFloatIsUndefined(availableInnerDim)) {
+    // We want to make sure our available height does not violate min and max
+    // constraints
+    const YGFloatOptional minDimensionOptional =
+        YGResolveValue(node->getStyle().minDimensions[dimension], ownerDim);
+    const float minInnerDim = minDimensionOptional.isUndefined()
+        ? 0.0f
+        : minDimensionOptional.getValue() - paddingAndBorder;
+
+    const YGFloatOptional maxDimensionOptional =
+        YGResolveValue(node->getStyle().maxDimensions[dimension], ownerDim);
+
+    const float maxInnerDim = maxDimensionOptional.isUndefined()
+        ? FLT_MAX
+        : maxDimensionOptional.getValue() - paddingAndBorder;
+    availableInnerDim =
+        YGFloatMax(YGFloatMin(availableInnerDim, maxInnerDim), minInnerDim);
+  }
+
+  return availableInnerDim;
+}
+
+static void YGNodeComputeFlexBasisForChildren(
+    const YGNodeRef node,
+    const float availableInnerWidth,
+    const float availableInnerHeight,
+    YGMeasureMode widthMeasureMode,
+    YGMeasureMode heightMeasureMode,
+    YGDirection direction,
+    YGFlexDirection mainAxis,
+    const YGConfigRef config,
+    bool performLayout,
+    float& totalOuterFlexBasis) {
+  YGNodeRef singleFlexChild = nullptr;
+  YGVector children = node->getChildren();
+  YGMeasureMode measureModeMainDim =
+      YGFlexDirectionIsRow(mainAxis) ? widthMeasureMode : heightMeasureMode;
+  // If there is only one child with flexGrow + flexShrink it means we can set
+  // the computedFlexBasis to 0 instead of measuring and shrinking / flexing the
+  // child to exactly match the remaining space
+  if (measureModeMainDim == YGMeasureModeExactly) {
+    for (auto child : children) {
+      if (child->isNodeFlexible()) {
+        if (singleFlexChild != nullptr ||
+            YGFloatsEqual(child->resolveFlexGrow(), 0.0f) ||
+            YGFloatsEqual(child->resolveFlexShrink(), 0.0f)) {
+          // There is already a flexible child, or this flexible child doesn't
+          // have flexGrow and flexShrink, abort
+          singleFlexChild = nullptr;
+          break;
+        } else {
+          singleFlexChild = child;
+        }
+      }
+    }
+  }
+
+  for (auto child : children) {
+    child->resolveDimension();
+    if (child->getStyle().display == YGDisplayNone) {
+      YGZeroOutLayoutRecursivly(child);
+      child->setHasNewLayout(true);
+      child->setDirty(false);
+      continue;
+    }
+    if (performLayout) {
+      // Set the initial position (relative to the owner).
+      const YGDirection childDirection = child->resolveDirection(direction);
+      const float mainDim = YGFlexDirectionIsRow(mainAxis)
+          ? availableInnerWidth
+          : availableInnerHeight;
+      const float crossDim = YGFlexDirectionIsRow(mainAxis)
+          ? availableInnerHeight
+          : availableInnerWidth;
+      child->setPosition(
+          childDirection, mainDim, crossDim, availableInnerWidth);
+    }
+
+    if (child->getStyle().positionType == YGPositionTypeAbsolute) {
+      continue;
+    }
+    if (child == singleFlexChild) {
+      child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount);
+      child->setLayoutComputedFlexBasis(YGFloatOptional(0));
+    } else {
+      YGNodeComputeFlexBasisForChild(
+          node,
+          child,
+          availableInnerWidth,
+          widthMeasureMode,
+          availableInnerHeight,
+          availableInnerWidth,
+          availableInnerHeight,
+          heightMeasureMode,
+          direction,
+          config);
+    }
+
+    totalOuterFlexBasis += YGUnwrapFloatOptional(
+        child->getLayout().computedFlexBasis +
+        child->getMarginForAxis(mainAxis, availableInnerWidth));
+  }
+}
+
+// This function assumes that all the children of node have their
+// computedFlexBasis properly computed(To do this use
+// YGNodeComputeFlexBasisForChildren function).
+// This function calculates YGCollectFlexItemsRowMeasurement
+static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues(
+    const YGNodeRef& node,
+    const YGDirection ownerDirection,
+    const float mainAxisownerSize,
+    const float availableInnerWidth,
+    const float availableInnerMainDim,
+    const uint32_t startOfLineIndex,
+    const uint32_t lineCount) {
+  YGCollectFlexItemsRowValues flexAlgoRowMeasurement = {};
+  flexAlgoRowMeasurement.relativeChildren.reserve(node->getChildren().size());
+
+  float sizeConsumedOnCurrentLineIncludingMinConstraint = 0;
+  const YGFlexDirection mainAxis = YGResolveFlexDirection(
+      node->getStyle().flexDirection, node->resolveDirection(ownerDirection));
+  const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
+
+  // Add items to the current line until it's full or we run out of items.
+  uint32_t endOfLineIndex = startOfLineIndex;
+  for (; endOfLineIndex < node->getChildren().size(); endOfLineIndex++) {
+    const YGNodeRef child = node->getChild(endOfLineIndex);
+    if (child->getStyle().display == YGDisplayNone ||
+        child->getStyle().positionType == YGPositionTypeAbsolute) {
+      continue;
+    }
+    child->setLineIndex(lineCount);
+    const float childMarginMainAxis = YGUnwrapFloatOptional(
+        child->getMarginForAxis(mainAxis, availableInnerWidth));
+    const float flexBasisWithMinAndMaxConstraints =
+        YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
+            child,
+            mainAxis,
+            YGUnwrapFloatOptional(child->getLayout().computedFlexBasis),
+            mainAxisownerSize));
+
+    // If this is a multi-line flow and this item pushes us over the
+    // available size, we've
+    // hit the end of the current line. Break out of the loop and lay out
+    // the current line.
+    if (sizeConsumedOnCurrentLineIncludingMinConstraint +
+                flexBasisWithMinAndMaxConstraints + childMarginMainAxis >
+            availableInnerMainDim &&
+        isNodeFlexWrap && flexAlgoRowMeasurement.itemsOnLine > 0) {
+      break;
+    }
+
+    sizeConsumedOnCurrentLineIncludingMinConstraint +=
+        flexBasisWithMinAndMaxConstraints + childMarginMainAxis;
+    flexAlgoRowMeasurement.sizeConsumedOnCurrentLine +=
+        flexBasisWithMinAndMaxConstraints + childMarginMainAxis;
+    flexAlgoRowMeasurement.itemsOnLine++;
+
+    if (child->isNodeFlexible()) {
+      flexAlgoRowMeasurement.totalFlexGrowFactors += child->resolveFlexGrow();
+
+      // Unlike the grow factor, the shrink factor is scaled relative to the
+      // child dimension.
+      flexAlgoRowMeasurement.totalFlexShrinkScaledFactors +=
+          -child->resolveFlexShrink() *
+          YGUnwrapFloatOptional(child->getLayout().computedFlexBasis);
+    }
+
+    flexAlgoRowMeasurement.relativeChildren.push_back(child);
+  }
+
+  // The total flex factor needs to be floored to 1.
+  if (flexAlgoRowMeasurement.totalFlexGrowFactors > 0 &&
+      flexAlgoRowMeasurement.totalFlexGrowFactors < 1) {
+    flexAlgoRowMeasurement.totalFlexGrowFactors = 1;
+  }
+
+  // The total flex shrink factor needs to be floored to 1.
+  if (flexAlgoRowMeasurement.totalFlexShrinkScaledFactors > 0 &&
+      flexAlgoRowMeasurement.totalFlexShrinkScaledFactors < 1) {
+    flexAlgoRowMeasurement.totalFlexShrinkScaledFactors = 1;
+  }
+  flexAlgoRowMeasurement.endOfLineIndex = endOfLineIndex;
+  return flexAlgoRowMeasurement;
+}
+
+// It distributes the free space to the flexible items and ensures that the size
+// of the flex items abide the min and max constraints. At the end of this
+// function the child nodes would have proper size. Prior using this function
+// please ensure that YGDistributeFreeSpaceFirstPass is called.
+static float YGDistributeFreeSpaceSecondPass(
+    YGCollectFlexItemsRowValues& collectedFlexItemsValues,
+    const YGNodeRef node,
+    const YGFlexDirection mainAxis,
+    const YGFlexDirection crossAxis,
+    const float mainAxisownerSize,
+    const float availableInnerMainDim,
+    const float availableInnerCrossDim,
+    const float availableInnerWidth,
+    const float availableInnerHeight,
+    const bool flexBasisOverflows,
+    const YGMeasureMode measureModeCrossDim,
+    const bool performLayout,
+    const YGConfigRef config) {
+  float childFlexBasis = 0;
+  float flexShrinkScaledFactor = 0;
+  float flexGrowFactor = 0;
+  float deltaFreeSpace = 0;
+  const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
+  const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
+
+  for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) {
+    childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
+        currentRelativeChild,
+        mainAxis,
+        YGUnwrapFloatOptional(
+            currentRelativeChild->getLayout().computedFlexBasis),
+        mainAxisownerSize));
+    float updatedMainSize = childFlexBasis;
+
+    if (!YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
+        collectedFlexItemsValues.remainingFreeSpace < 0) {
+      flexShrinkScaledFactor =
+          -currentRelativeChild->resolveFlexShrink() * childFlexBasis;
+      // Is this child able to shrink?
+      if (flexShrinkScaledFactor != 0) {
+        float childSize;
+
+        if (!YGFloatIsUndefined(
+                collectedFlexItemsValues.totalFlexShrinkScaledFactors) &&
+            collectedFlexItemsValues.totalFlexShrinkScaledFactors == 0) {
+          childSize = childFlexBasis + flexShrinkScaledFactor;
+        } else {
+          childSize = childFlexBasis +
+              (collectedFlexItemsValues.remainingFreeSpace /
+               collectedFlexItemsValues.totalFlexShrinkScaledFactors) *
+                  flexShrinkScaledFactor;
+        }
+
+        updatedMainSize = YGNodeBoundAxis(
+            currentRelativeChild,
+            mainAxis,
+            childSize,
+            availableInnerMainDim,
+            availableInnerWidth);
+      }
+    } else if (
+        !YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
+        collectedFlexItemsValues.remainingFreeSpace > 0) {
+      flexGrowFactor = currentRelativeChild->resolveFlexGrow();
+
+      // Is this child able to grow?
+      if (!YGFloatIsUndefined(flexGrowFactor) && flexGrowFactor != 0) {
+        updatedMainSize = YGNodeBoundAxis(
+            currentRelativeChild,
+            mainAxis,
+            childFlexBasis +
+                collectedFlexItemsValues.remainingFreeSpace /
+                    collectedFlexItemsValues.totalFlexGrowFactors *
+                    flexGrowFactor,
+            availableInnerMainDim,
+            availableInnerWidth);
+      }
+    }
+
+    deltaFreeSpace += updatedMainSize - childFlexBasis;
+
+    const float marginMain = YGUnwrapFloatOptional(
+        currentRelativeChild->getMarginForAxis(mainAxis, availableInnerWidth));
+    const float marginCross = YGUnwrapFloatOptional(
+        currentRelativeChild->getMarginForAxis(crossAxis, availableInnerWidth));
+
+    float childCrossSize;
+    float childMainSize = updatedMainSize + marginMain;
+    YGMeasureMode childCrossMeasureMode;
+    YGMeasureMode childMainMeasureMode = YGMeasureModeExactly;
+
+    if (!currentRelativeChild->getStyle().aspectRatio.isUndefined()) {
+      childCrossSize = isMainAxisRow ? (childMainSize - marginMain) /
+              currentRelativeChild->getStyle().aspectRatio.getValue()
+                                     : (childMainSize - marginMain) *
+              currentRelativeChild->getStyle().aspectRatio.getValue();
+      childCrossMeasureMode = YGMeasureModeExactly;
+
+      childCrossSize += marginCross;
+    } else if (
+        !YGFloatIsUndefined(availableInnerCrossDim) &&
+        !YGNodeIsStyleDimDefined(
+            currentRelativeChild, crossAxis, availableInnerCrossDim) &&
+        measureModeCrossDim == YGMeasureModeExactly &&
+        !(isNodeFlexWrap && flexBasisOverflows) &&
+        YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch &&
+        currentRelativeChild->marginLeadingValue(crossAxis).unit !=
+            YGUnitAuto &&
+        currentRelativeChild->marginTrailingValue(crossAxis).unit !=
+            YGUnitAuto) {
+      childCrossSize = availableInnerCrossDim;
+      childCrossMeasureMode = YGMeasureModeExactly;
+    } else if (!YGNodeIsStyleDimDefined(
+                   currentRelativeChild, crossAxis, availableInnerCrossDim)) {
+      childCrossSize = availableInnerCrossDim;
+      childCrossMeasureMode = YGFloatIsUndefined(childCrossSize)
+          ? YGMeasureModeUndefined
+          : YGMeasureModeAtMost;
+    } else {
+      childCrossSize =
+          YGUnwrapFloatOptional(YGResolveValue(
+              currentRelativeChild->getResolvedDimension(dim[crossAxis]),
+              availableInnerCrossDim)) +
+          marginCross;
+      const bool isLoosePercentageMeasurement =
+          currentRelativeChild->getResolvedDimension(dim[crossAxis]).unit ==
+              YGUnitPercent &&
+          measureModeCrossDim != YGMeasureModeExactly;
+      childCrossMeasureMode =
+          YGFloatIsUndefined(childCrossSize) || isLoosePercentageMeasurement
+          ? YGMeasureModeUndefined
+          : YGMeasureModeExactly;
+    }
+
+    YGConstrainMaxSizeForMode(
+        currentRelativeChild,
+        mainAxis,
+        availableInnerMainDim,
+        availableInnerWidth,
+        &childMainMeasureMode,
+        &childMainSize);
+    YGConstrainMaxSizeForMode(
+        currentRelativeChild,
+        crossAxis,
+        availableInnerCrossDim,
+        availableInnerWidth,
+        &childCrossMeasureMode,
+        &childCrossSize);
+
+    const bool requiresStretchLayout =
+        !YGNodeIsStyleDimDefined(
+            currentRelativeChild, crossAxis, availableInnerCrossDim) &&
+        YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch &&
+        currentRelativeChild->marginLeadingValue(crossAxis).unit !=
+            YGUnitAuto &&
+        currentRelativeChild->marginTrailingValue(crossAxis).unit != YGUnitAuto;
+
+    const float childWidth = isMainAxisRow ? childMainSize : childCrossSize;
+    const float childHeight = !isMainAxisRow ? childMainSize : childCrossSize;
+
+    const YGMeasureMode childWidthMeasureMode =
+        isMainAxisRow ? childMainMeasureMode : childCrossMeasureMode;
+    const YGMeasureMode childHeightMeasureMode =
+        !isMainAxisRow ? childMainMeasureMode : childCrossMeasureMode;
+
+    // Recursively call the layout algorithm for this child with the updated
+    // main size.
+    YGLayoutNodeInternal(
+        currentRelativeChild,
+        childWidth,
+        childHeight,
+        node->getLayout().direction,
+        childWidthMeasureMode,
+        childHeightMeasureMode,
+        availableInnerWidth,
+        availableInnerHeight,
+        performLayout && !requiresStretchLayout,
+        "flex",
+        config);
+    node->setLayoutHadOverflow(
+        node->getLayout().hadOverflow |
+        currentRelativeChild->getLayout().hadOverflow);
+  }
+  return deltaFreeSpace;
+}
+
+// It distributes the free space to the flexible items.For those flexible items
+// whose min and max constraints are triggered, those flex item's clamped size
+// is removed from the remaingfreespace.
+static void YGDistributeFreeSpaceFirstPass(
+    YGCollectFlexItemsRowValues& collectedFlexItemsValues,
+    const YGFlexDirection mainAxis,
+    const float mainAxisownerSize,
+    const float availableInnerMainDim,
+    const float availableInnerWidth) {
+  float flexShrinkScaledFactor = 0;
+  float flexGrowFactor = 0;
+  float baseMainSize = 0;
+  float boundMainSize = 0;
+  float deltaFreeSpace = 0;
+
+  for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) {
+    float childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
+        currentRelativeChild,
+        mainAxis,
+        YGUnwrapFloatOptional(
+            currentRelativeChild->getLayout().computedFlexBasis),
+        mainAxisownerSize));
+
+    if (collectedFlexItemsValues.remainingFreeSpace < 0) {
+      flexShrinkScaledFactor =
+          -currentRelativeChild->resolveFlexShrink() * childFlexBasis;
+
+      // Is this child able to shrink?
+      if (!YGFloatIsUndefined(flexShrinkScaledFactor) &&
+          flexShrinkScaledFactor != 0) {
+        baseMainSize = childFlexBasis +
+            collectedFlexItemsValues.remainingFreeSpace /
+                collectedFlexItemsValues.totalFlexShrinkScaledFactors *
+                flexShrinkScaledFactor;
+        boundMainSize = YGNodeBoundAxis(
+            currentRelativeChild,
+            mainAxis,
+            baseMainSize,
+            availableInnerMainDim,
+            availableInnerWidth);
+        if (!YGFloatIsUndefined(baseMainSize) &&
+            !YGFloatIsUndefined(boundMainSize) &&
+            baseMainSize != boundMainSize) {
+          // By excluding this item's size and flex factor from remaining,
+          // this item's
+          // min/max constraints should also trigger in the second pass
+          // resulting in the
+          // item's size calculation being identical in the first and second
+          // passes.
+          deltaFreeSpace += boundMainSize - childFlexBasis;
+          collectedFlexItemsValues.totalFlexShrinkScaledFactors -=
+              flexShrinkScaledFactor;
+        }
+      }
+    } else if (
+        !YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
+        collectedFlexItemsValues.remainingFreeSpace > 0) {
+      flexGrowFactor = currentRelativeChild->resolveFlexGrow();
+
+      // Is this child able to grow?
+      if (!YGFloatIsUndefined(flexGrowFactor) && flexGrowFactor != 0) {
+        baseMainSize = childFlexBasis +
+            collectedFlexItemsValues.remainingFreeSpace /
+                collectedFlexItemsValues.totalFlexGrowFactors * flexGrowFactor;
+        boundMainSize = YGNodeBoundAxis(
+            currentRelativeChild,
+            mainAxis,
+            baseMainSize,
+            availableInnerMainDim,
+            availableInnerWidth);
+
+        if (!YGFloatIsUndefined(baseMainSize) &&
+            !YGFloatIsUndefined(boundMainSize) &&
+            baseMainSize != boundMainSize) {
+          // By excluding this item's size and flex factor from remaining,
+          // this item's
+          // min/max constraints should also trigger in the second pass
+          // resulting in the
+          // item's size calculation being identical in the first and second
+          // passes.
+          deltaFreeSpace += boundMainSize - childFlexBasis;
+          collectedFlexItemsValues.totalFlexGrowFactors -= flexGrowFactor;
+        }
+      }
+    }
+  }
+  collectedFlexItemsValues.remainingFreeSpace -= deltaFreeSpace;
+}
+
+// Do two passes over the flex items to figure out how to distribute the
+// remaining space.
+// The first pass finds the items whose min/max constraints trigger,
+// freezes them at those
+// sizes, and excludes those sizes from the remaining space. The second
+// pass sets the size
+// of each flexible item. It distributes the remaining space amongst the
+// items whose min/max
+// constraints didn't trigger in pass 1. For the other items, it sets
+// their sizes by forcing
+// their min/max constraints to trigger again.
+//
+// This two pass approach for resolving min/max constraints deviates from
+// the spec. The
+// spec (https://www.w3.org/TR/YG-flexbox-1/#resolve-flexible-lengths)
+// describes a process
+// that needs to be repeated a variable number of times. The algorithm
+// implemented here
+// won't handle all cases but it was simpler to implement and it mitigates
+// performance
+// concerns because we know exactly how many passes it'll do.
+//
+// At the end of this function the child nodes would have the proper size
+// assigned to them.
+//
+static void YGResolveFlexibleLength(
+    const YGNodeRef node,
+    YGCollectFlexItemsRowValues& collectedFlexItemsValues,
+    const YGFlexDirection mainAxis,
+    const YGFlexDirection crossAxis,
+    const float mainAxisownerSize,
+    const float availableInnerMainDim,
+    const float availableInnerCrossDim,
+    const float availableInnerWidth,
+    const float availableInnerHeight,
+    const bool flexBasisOverflows,
+    const YGMeasureMode measureModeCrossDim,
+    const bool performLayout,
+    const YGConfigRef config) {
+  const float originalFreeSpace = collectedFlexItemsValues.remainingFreeSpace;
+  // First pass: detect the flex items whose min/max constraints trigger
+  YGDistributeFreeSpaceFirstPass(
+      collectedFlexItemsValues,
+      mainAxis,
+      mainAxisownerSize,
+      availableInnerMainDim,
+      availableInnerWidth);
+
+  // Second pass: resolve the sizes of the flexible items
+  const float distributedFreeSpace = YGDistributeFreeSpaceSecondPass(
+      collectedFlexItemsValues,
+      node,
+      mainAxis,
+      crossAxis,
+      mainAxisownerSize,
+      availableInnerMainDim,
+      availableInnerCrossDim,
+      availableInnerWidth,
+      availableInnerHeight,
+      flexBasisOverflows,
+      measureModeCrossDim,
+      performLayout,
+      config);
+
+  collectedFlexItemsValues.remainingFreeSpace =
+      originalFreeSpace - distributedFreeSpace;
+}
+
+static void YGJustifyMainAxis(
+    const YGNodeRef node,
+    YGCollectFlexItemsRowValues& collectedFlexItemsValues,
+    const uint32_t& startOfLineIndex,
+    const YGFlexDirection& mainAxis,
+    const YGFlexDirection& crossAxis,
+    const YGMeasureMode& measureModeMainDim,
+    const YGMeasureMode& measureModeCrossDim,
+    const float& mainAxisownerSize,
+    const float& ownerWidth,
+    const float& availableInnerMainDim,
+    const float& availableInnerCrossDim,
+    const float& availableInnerWidth,
+    const bool& performLayout) {
+  const YGStyle& style = node->getStyle();
+  const float leadingPaddingAndBorderMain = YGUnwrapFloatOptional(
+      node->getLeadingPaddingAndBorder(mainAxis, ownerWidth));
+  const float trailingPaddingAndBorderMain = YGUnwrapFloatOptional(
+      node->getTrailingPaddingAndBorder(mainAxis, ownerWidth));
+  // If we are using "at most" rules in the main axis, make sure that
+  // remainingFreeSpace is 0 when min main dimension is not given
+  if (measureModeMainDim == YGMeasureModeAtMost &&
+      collectedFlexItemsValues.remainingFreeSpace > 0) {
+    if (style.minDimensions[dim[mainAxis]].unit != YGUnitUndefined &&
+        !YGResolveValue(style.minDimensions[dim[mainAxis]], mainAxisownerSize)
+             .isUndefined()) {
+      // This condition makes sure that if the size of main dimension(after
+      // considering child nodes main dim, leading and trailing padding etc)
+      // falls below min dimension, then the remainingFreeSpace is reassigned
+      // considering the min dimension
+
+      // `minAvailableMainDim` denotes minimum available space in which child
+      // can be laid out, it will exclude space consumed by padding and border.
+      const float minAvailableMainDim =
+          YGUnwrapFloatOptional(YGResolveValue(
+              style.minDimensions[dim[mainAxis]], mainAxisownerSize)) -
+          leadingPaddingAndBorderMain - trailingPaddingAndBorderMain;
+      const float occupiedSpaceByChildNodes =
+          availableInnerMainDim - collectedFlexItemsValues.remainingFreeSpace;
+      collectedFlexItemsValues.remainingFreeSpace =
+          YGFloatMax(0, minAvailableMainDim - occupiedSpaceByChildNodes);
+    } else {
+      collectedFlexItemsValues.remainingFreeSpace = 0;
+    }
+  }
+
+  int numberOfAutoMarginsOnCurrentLine = 0;
+  for (uint32_t i = startOfLineIndex;
+       i < collectedFlexItemsValues.endOfLineIndex;
+       i++) {
+    const YGNodeRef child = node->getChild(i);
+    if (child->getStyle().positionType == YGPositionTypeRelative) {
+      if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) {
+        numberOfAutoMarginsOnCurrentLine++;
+      }
+      if (child->marginTrailingValue(mainAxis).unit == YGUnitAuto) {
+        numberOfAutoMarginsOnCurrentLine++;
+      }
+    }
+  }
+
+  // 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;
+  const YGJustify justifyContent = node->getStyle().justifyContent;
+
+  if (numberOfAutoMarginsOnCurrentLine == 0) {
+    switch (justifyContent) {
+      case YGJustifyCenter:
+        leadingMainDim = collectedFlexItemsValues.remainingFreeSpace / 2;
+        break;
+      case YGJustifyFlexEnd:
+        leadingMainDim = collectedFlexItemsValues.remainingFreeSpace;
+        break;
+      case YGJustifySpaceBetween:
+        if (collectedFlexItemsValues.itemsOnLine > 1) {
+          betweenMainDim =
+              YGFloatMax(collectedFlexItemsValues.remainingFreeSpace, 0) /
+              (collectedFlexItemsValues.itemsOnLine - 1);
+        } else {
+          betweenMainDim = 0;
+        }
+        break;
+      case YGJustifySpaceEvenly:
+        // Space is distributed evenly across all elements
+        betweenMainDim = collectedFlexItemsValues.remainingFreeSpace /
+            (collectedFlexItemsValues.itemsOnLine + 1);
+        leadingMainDim = betweenMainDim;
+        break;
+      case YGJustifySpaceAround:
+        // Space on the edges is half of the space between elements
+        betweenMainDim = collectedFlexItemsValues.remainingFreeSpace /
+            collectedFlexItemsValues.itemsOnLine;
+        leadingMainDim = betweenMainDim / 2;
+        break;
+      case YGJustifyFlexStart:
+        break;
+    }
+  }
+
+  collectedFlexItemsValues.mainDim =
+      leadingPaddingAndBorderMain + leadingMainDim;
+  collectedFlexItemsValues.crossDim = 0;
+
+  float maxAscentForCurrentLine = 0;
+  float maxDescentForCurrentLine = 0;
+  bool isNodeBaselineLayout = YGIsBaselineLayout(node);
+  for (uint32_t i = startOfLineIndex;
+       i < collectedFlexItemsValues.endOfLineIndex;
+       i++) {
+    const YGNodeRef child = node->getChild(i);
+    const YGStyle& childStyle = child->getStyle();
+    const YGLayout childLayout = child->getLayout();
+    if (childStyle.display == YGDisplayNone) {
+      continue;
+    }
+    if (childStyle.positionType == YGPositionTypeAbsolute &&
+        child->isLeadingPositionDefined(mainAxis)) {
+      if (performLayout) {
+        // 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->setLayoutPosition(
+            YGUnwrapFloatOptional(
+                child->getLeadingPosition(mainAxis, availableInnerMainDim)) +
+                node->getLeadingBorder(mainAxis) +
+                YGUnwrapFloatOptional(
+                    child->getLeadingMargin(mainAxis, availableInnerWidth)),
+            pos[mainAxis]);
+      }
+    } else {
+      // Now that we placed the element, we need to update the variables.
+      // We need to do that only for relative elements. Absolute elements
+      // do not take part in that phase.
+      if (childStyle.positionType == YGPositionTypeRelative) {
+        if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) {
+          collectedFlexItemsValues.mainDim +=
+              collectedFlexItemsValues.remainingFreeSpace /
+              numberOfAutoMarginsOnCurrentLine;
+        }
+
+        if (performLayout) {
+          child->setLayoutPosition(
+              childLayout.position[pos[mainAxis]] +
+                  collectedFlexItemsValues.mainDim,
+              pos[mainAxis]);
+        }
+
+        if (child->marginTrailingValue(mainAxis).unit == YGUnitAuto) {
+          collectedFlexItemsValues.mainDim +=
+              collectedFlexItemsValues.remainingFreeSpace /
+              numberOfAutoMarginsOnCurrentLine;
+        }
+        bool canSkipFlex =
+            !performLayout && measureModeCrossDim == YGMeasureModeExactly;
+        if (canSkipFlex) {
+          // If we skipped the flex step, then we can't rely on the
+          // measuredDims because
+          // they weren't computed. This means we can't call
+          // YGNodeDimWithMargin.
+          collectedFlexItemsValues.mainDim += betweenMainDim +
+              YGUnwrapFloatOptional(child->getMarginForAxis(
+                  mainAxis, availableInnerWidth)) +
+              YGUnwrapFloatOptional(childLayout.computedFlexBasis);
+          collectedFlexItemsValues.crossDim = availableInnerCrossDim;
+        } else {
+          // The main dimension is the sum of all the elements dimension plus
+          // the spacing.
+          collectedFlexItemsValues.mainDim += betweenMainDim +
+              YGNodeDimWithMargin(child, mainAxis, availableInnerWidth);
+
+          if (isNodeBaselineLayout) {
+            // If the child is baseline aligned then the cross dimension is
+            // calculated by adding maxAscent and maxDescent from the baseline.
+            const float ascent = YGBaseline(child) +
+                YGUnwrapFloatOptional(child->getLeadingMargin(
+                    YGFlexDirectionColumn, availableInnerWidth));
+            const float descent =
+                child->getLayout().measuredDimensions[YGDimensionHeight] +
+                YGUnwrapFloatOptional(child->getMarginForAxis(
+                    YGFlexDirectionColumn, availableInnerWidth)) -
+                ascent;
+
+            maxAscentForCurrentLine =
+                YGFloatMax(maxAscentForCurrentLine, ascent);
+            maxDescentForCurrentLine =
+                YGFloatMax(maxDescentForCurrentLine, descent);
+          } else {
+            // The cross dimension is the max of the elements dimension since
+            // there can only be one element in that cross dimension in the case
+            // when the items are not baseline aligned
+            collectedFlexItemsValues.crossDim = YGFloatMax(
+                collectedFlexItemsValues.crossDim,
+                YGNodeDimWithMargin(child, crossAxis, availableInnerWidth));
+          }
+        }
+      } else if (performLayout) {
+        child->setLayoutPosition(
+            childLayout.position[pos[mainAxis]] +
+                node->getLeadingBorder(mainAxis) + leadingMainDim,
+            pos[mainAxis]);
+      }
+    }
+  }
+  collectedFlexItemsValues.mainDim += trailingPaddingAndBorderMain;
+
+  if (isNodeBaselineLayout) {
+    collectedFlexItemsValues.crossDim =
+        maxAscentForCurrentLine + maxDescentForCurrentLine;
+  }
+}
+
+//
+// This is the main routine that implements a subset of the flexbox layout
+// algorithm
+// described in the W3C YG documentation: https://www.w3.org/TR/YG3-flexbox/.
+//
+// Limitations of this algorithm, compared to the full standard:
+//  * Display property is always assumed to be 'flex' except for Text nodes,
+//  which
+//    are assumed to be 'inline-flex'.
+//  * The 'zIndex' property (or any form of z ordering) is not supported. Nodes
+//  are
+//    stacked in document order.
+//  * The 'order' property is not supported. The order of flex items is always
+//  defined
+//    by document order.
+//  * The 'visibility' property is always assumed to be 'visible'. Values of
+//  'collapse'
+//    and 'hidden' are not supported.
+//  * There is no support for forced breaks.
+//  * It does not support vertical inline directions (top-to-bottom or
+//  bottom-to-top text).
+//
+// Deviations from standard:
+//  * Section 4.5 of the spec indicates that all flex items have a default
+//  minimum
+//    main size. For text blocks, for example, this is the width of the widest
+//    word.
+//    Calculating the minimum width is expensive, so we forego it and assume a
+//    default
+//    minimum main size of 0.
+//  * Min/Max sizes in the main axis are not honored when resolving flexible
+//  lengths.
+//  * The spec indicates that the default value for 'flexDirection' is 'row',
+//  but
+//    the algorithm below assumes a default of 'column'.
+//
+// Input parameters:
+//    - node: current node to be sized and layed out
+//    - availableWidth & availableHeight: available size to be used for sizing
+//    the node
+//      or YGUndefined if the size is not available; interpretation depends on
+//      layout
+//      flags
+//    - ownerDirection: the inline (text) direction within the owner
+//    (left-to-right or
+//      right-to-left)
+//    - widthMeasureMode: indicates the sizing rules for the width (see below
+//    for explanation)
+//    - heightMeasureMode: indicates the sizing rules for the height (see below
+//    for explanation)
+//    - performLayout: specifies whether the caller is interested in just the
+//    dimensions
+//      of the node or it requires the entire node and its subtree to be layed
+//      out
+//      (with final positions)
+//
+// Details:
+//    This routine is called recursively to lay out subtrees of flexbox
+//    elements. It uses the
+//    information in node.style, which is treated as a read-only input. It is
+//    responsible for
+//    setting the layout.direction and layout.measuredDimensions fields for the
+//    input node as well
+//    as the layout.position and layout.lineIndex fields for its child nodes.
+//    The
+//    layout.measuredDimensions field includes any border or padding for the
+//    node but does
+//    not include margins.
+//
+//    The spec describes four different layout modes: "fill available", "max
+//    content", "min
+//    content",
+//    and "fit content". Of these, we don't use "min content" because we don't
+//    support default
+//    minimum main sizes (see above for details). Each of our measure modes maps
+//    to a layout mode
+//    from the spec (https://www.w3.org/TR/YG3-sizing/#terms):
+//      - YGMeasureModeUndefined: max content
+//      - YGMeasureModeExactly: fill available
+//      - YGMeasureModeAtMost: fit content
+//
+//    When calling YGNodelayoutImpl and YGLayoutNodeInternal, if the caller
+//    passes an available size of undefined then it must also pass a measure
+//    mode of YGMeasureModeUndefined in that dimension.
+//
+static void YGNodelayoutImpl(
+    const YGNodeRef node,
+    const float availableWidth,
+    const float availableHeight,
+    const YGDirection ownerDirection,
+    const YGMeasureMode widthMeasureMode,
+    const YGMeasureMode heightMeasureMode,
+    const float ownerWidth,
+    const float ownerHeight,
+    const bool performLayout,
+    const YGConfigRef config) {
+  YGAssertWithNode(
+      node,
+      YGFloatIsUndefined(availableWidth)
+          ? widthMeasureMode == YGMeasureModeUndefined
+          : true,
+      "availableWidth is indefinite so widthMeasureMode must be "
+      "YGMeasureModeUndefined");
+  YGAssertWithNode(
+      node,
+      YGFloatIsUndefined(availableHeight)
+          ? heightMeasureMode == YGMeasureModeUndefined
+          : true,
+      "availableHeight is indefinite so heightMeasureMode must be "
+      "YGMeasureModeUndefined");
+
+  // Set the resolved resolution in the node's layout.
+  const YGDirection direction = node->resolveDirection(ownerDirection);
+  node->setLayoutDirection(direction);
+
+  const YGFlexDirection flexRowDirection =
+      YGResolveFlexDirection(YGFlexDirectionRow, direction);
+  const YGFlexDirection flexColumnDirection =
+      YGResolveFlexDirection(YGFlexDirectionColumn, direction);
+
+  node->setLayoutMargin(
+      YGUnwrapFloatOptional(
+          node->getLeadingMargin(flexRowDirection, ownerWidth)),
+      YGEdgeStart);
+  node->setLayoutMargin(
+      YGUnwrapFloatOptional(
+          node->getTrailingMargin(flexRowDirection, ownerWidth)),
+      YGEdgeEnd);
+  node->setLayoutMargin(
+      YGUnwrapFloatOptional(
+          node->getLeadingMargin(flexColumnDirection, ownerWidth)),
+      YGEdgeTop);
+  node->setLayoutMargin(
+      YGUnwrapFloatOptional(
+          node->getTrailingMargin(flexColumnDirection, ownerWidth)),
+      YGEdgeBottom);
+
+  node->setLayoutBorder(node->getLeadingBorder(flexRowDirection), YGEdgeStart);
+  node->setLayoutBorder(node->getTrailingBorder(flexRowDirection), YGEdgeEnd);
+  node->setLayoutBorder(node->getLeadingBorder(flexColumnDirection), YGEdgeTop);
+  node->setLayoutBorder(
+      node->getTrailingBorder(flexColumnDirection), YGEdgeBottom);
+
+  node->setLayoutPadding(
+      YGUnwrapFloatOptional(
+          node->getLeadingPadding(flexRowDirection, ownerWidth)),
+      YGEdgeStart);
+  node->setLayoutPadding(
+      YGUnwrapFloatOptional(
+          node->getTrailingPadding(flexRowDirection, ownerWidth)),
+      YGEdgeEnd);
+  node->setLayoutPadding(
+      YGUnwrapFloatOptional(
+          node->getLeadingPadding(flexColumnDirection, ownerWidth)),
+      YGEdgeTop);
+  node->setLayoutPadding(
+      YGUnwrapFloatOptional(
+          node->getTrailingPadding(flexColumnDirection, ownerWidth)),
+      YGEdgeBottom);
+
+  if (node->getMeasure() != nullptr) {
+    YGNodeWithMeasureFuncSetMeasuredDimensions(
+        node,
+        availableWidth,
+        availableHeight,
+        widthMeasureMode,
+        heightMeasureMode,
+        ownerWidth,
+        ownerHeight);
+    return;
+  }
+
+  const uint32_t childCount = YGNodeGetChildCount(node);
+  if (childCount == 0) {
+    YGNodeEmptyContainerSetMeasuredDimensions(
+        node,
+        availableWidth,
+        availableHeight,
+        widthMeasureMode,
+        heightMeasureMode,
+        ownerWidth,
+        ownerHeight);
+    return;
+  }
+
+  // If we're not being asked to perform a full layout we can skip the algorithm
+  // if we already know the size
+  if (!performLayout &&
+      YGNodeFixedSizeSetMeasuredDimensions(
+          node,
+          availableWidth,
+          availableHeight,
+          widthMeasureMode,
+          heightMeasureMode,
+          ownerWidth,
+          ownerHeight)) {
+    return;
+  }
+
+  // At this point we know we're going to perform work. Ensure that each child
+  // has a mutable copy.
+  node->cloneChildrenIfNeeded();
+  // Reset layout flags, as they could have changed.
+  node->setLayoutHadOverflow(false);
+
+  // STEP 1: CALCULATE VALUES FOR REMAINDER OF ALGORITHM
+  const YGFlexDirection mainAxis =
+      YGResolveFlexDirection(node->getStyle().flexDirection, direction);
+  const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction);
+  const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
+  const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
+
+  const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight;
+  const float crossAxisownerSize = isMainAxisRow ? ownerHeight : ownerWidth;
+
+  const float leadingPaddingAndBorderCross = YGUnwrapFloatOptional(
+      node->getLeadingPaddingAndBorder(crossAxis, ownerWidth));
+  const float paddingAndBorderAxisMain =
+      YGNodePaddingAndBorderForAxis(node, mainAxis, ownerWidth);
+  const float paddingAndBorderAxisCross =
+      YGNodePaddingAndBorderForAxis(node, crossAxis, ownerWidth);
+
+  YGMeasureMode measureModeMainDim =
+      isMainAxisRow ? widthMeasureMode : heightMeasureMode;
+  YGMeasureMode measureModeCrossDim =
+      isMainAxisRow ? heightMeasureMode : widthMeasureMode;
+
+  const float paddingAndBorderAxisRow =
+      isMainAxisRow ? paddingAndBorderAxisMain : paddingAndBorderAxisCross;
+  const float paddingAndBorderAxisColumn =
+      isMainAxisRow ? paddingAndBorderAxisCross : paddingAndBorderAxisMain;
+
+  const float marginAxisRow = YGUnwrapFloatOptional(
+      node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
+  const float marginAxisColumn = YGUnwrapFloatOptional(
+      node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
+
+  const float minInnerWidth =
+      YGUnwrapFloatOptional(YGResolveValue(
+          node->getStyle().minDimensions[YGDimensionWidth], ownerWidth)) -
+      paddingAndBorderAxisRow;
+  const float maxInnerWidth =
+      YGUnwrapFloatOptional(YGResolveValue(
+          node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)) -
+      paddingAndBorderAxisRow;
+  const float minInnerHeight =
+      YGUnwrapFloatOptional(YGResolveValue(
+          node->getStyle().minDimensions[YGDimensionHeight], ownerHeight)) -
+      paddingAndBorderAxisColumn;
+  const float maxInnerHeight =
+      YGUnwrapFloatOptional(YGResolveValue(
+          node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight)) -
+      paddingAndBorderAxisColumn;
+
+  const float minInnerMainDim = isMainAxisRow ? minInnerWidth : minInnerHeight;
+  const float maxInnerMainDim = isMainAxisRow ? maxInnerWidth : maxInnerHeight;
+
+  // STEP 2: DETERMINE AVAILABLE SIZE IN MAIN AND CROSS DIRECTIONS
+
+  float availableInnerWidth = YGNodeCalculateAvailableInnerDim(
+      node, YGFlexDirectionRow, availableWidth, ownerWidth);
+  float availableInnerHeight = YGNodeCalculateAvailableInnerDim(
+      node, YGFlexDirectionColumn, availableHeight, ownerHeight);
+
+  float availableInnerMainDim =
+      isMainAxisRow ? availableInnerWidth : availableInnerHeight;
+  const float availableInnerCrossDim =
+      isMainAxisRow ? availableInnerHeight : availableInnerWidth;
+
+  float totalOuterFlexBasis = 0;
+
+  // STEP 3: DETERMINE FLEX BASIS FOR EACH ITEM
+
+  YGNodeComputeFlexBasisForChildren(
+      node,
+      availableInnerWidth,
+      availableInnerHeight,
+      widthMeasureMode,
+      heightMeasureMode,
+      direction,
+      mainAxis,
+      config,
+      performLayout,
+      totalOuterFlexBasis);
+
+  const bool flexBasisOverflows = measureModeMainDim == YGMeasureModeUndefined
+      ? false
+      : totalOuterFlexBasis > availableInnerMainDim;
+  if (isNodeFlexWrap && flexBasisOverflows &&
+      measureModeMainDim == YGMeasureModeAtMost) {
+    measureModeMainDim = YGMeasureModeExactly;
+  }
+  // STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
+
+  // Indexes of children that represent the first and last items in the line.
+  uint32_t startOfLineIndex = 0;
+  uint32_t endOfLineIndex = 0;
+
+  // Number of lines.
+  uint32_t lineCount = 0;
+
+  // Accumulated cross dimensions of all lines so far.
+  float totalLineCrossDim = 0;
+
+  // Max main dimension of all the lines.
+  float maxLineMainDim = 0;
+  YGCollectFlexItemsRowValues collectedFlexItemsValues;
+  for (; endOfLineIndex < childCount;
+       lineCount++, startOfLineIndex = endOfLineIndex) {
+    collectedFlexItemsValues = YGCalculateCollectFlexItemsRowValues(
+        node,
+        ownerDirection,
+        mainAxisownerSize,
+        availableInnerWidth,
+        availableInnerMainDim,
+        startOfLineIndex,
+        lineCount);
+    endOfLineIndex = collectedFlexItemsValues.endOfLineIndex;
+
+    // If we don't need to measure the cross axis, we can skip the entire flex
+    // step.
+    const bool canSkipFlex =
+        !performLayout && measureModeCrossDim == YGMeasureModeExactly;
+
+    // STEP 5: RESOLVING FLEXIBLE LENGTHS ON MAIN AXIS
+    // Calculate the remaining available space that needs to be allocated.
+    // If the main dimension size isn't known, it is computed based on
+    // the line length, so there's no more space left to distribute.
+
+    bool sizeBasedOnContent = false;
+    // If we don't measure with exact main dimension we want to ensure we don't
+    // violate min and max
+    if (measureModeMainDim != YGMeasureModeExactly) {
+      if (!YGFloatIsUndefined(minInnerMainDim) &&
+          collectedFlexItemsValues.sizeConsumedOnCurrentLine <
+              minInnerMainDim) {
+        availableInnerMainDim = minInnerMainDim;
+      } else if (
+          !YGFloatIsUndefined(maxInnerMainDim) &&
+          collectedFlexItemsValues.sizeConsumedOnCurrentLine >
+              maxInnerMainDim) {
+        availableInnerMainDim = maxInnerMainDim;
+      } else {
+        if (!node->getConfig()->useLegacyStretchBehaviour &&
+            ((YGFloatIsUndefined(
+                  collectedFlexItemsValues.totalFlexGrowFactors) &&
+              collectedFlexItemsValues.totalFlexGrowFactors == 0) ||
+             (YGFloatIsUndefined(node->resolveFlexGrow()) &&
+              node->resolveFlexGrow() == 0))) {
+          // If we don't have any children to flex or we can't flex the node
+          // itself, space we've used is all space we need. Root node also
+          // should be shrunk to minimum
+          availableInnerMainDim =
+              collectedFlexItemsValues.sizeConsumedOnCurrentLine;
+        }
+
+        if (node->getConfig()->useLegacyStretchBehaviour) {
+          node->setLayoutDidUseLegacyFlag(true);
+        }
+        sizeBasedOnContent = !node->getConfig()->useLegacyStretchBehaviour;
+      }
+    }
+
+    if (!sizeBasedOnContent && !YGFloatIsUndefined(availableInnerMainDim)) {
+      collectedFlexItemsValues.remainingFreeSpace = availableInnerMainDim -
+          collectedFlexItemsValues.sizeConsumedOnCurrentLine;
+    } else if (collectedFlexItemsValues.sizeConsumedOnCurrentLine < 0) {
+      // availableInnerMainDim is indefinite which means the node is being sized
+      // based on its content. sizeConsumedOnCurrentLine is negative which means
+      // the node will allocate 0 points for its content. Consequently,
+      // remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
+      collectedFlexItemsValues.remainingFreeSpace =
+          -collectedFlexItemsValues.sizeConsumedOnCurrentLine;
+    }
+
+    if (!canSkipFlex) {
+      YGResolveFlexibleLength(
+          node,
+          collectedFlexItemsValues,
+          mainAxis,
+          crossAxis,
+          mainAxisownerSize,
+          availableInnerMainDim,
+          availableInnerCrossDim,
+          availableInnerWidth,
+          availableInnerHeight,
+          flexBasisOverflows,
+          measureModeCrossDim,
+          performLayout,
+          config);
+    }
+
+    node->setLayoutHadOverflow(
+        node->getLayout().hadOverflow |
+        (collectedFlexItemsValues.remainingFreeSpace < 0));
+
+    // STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
+
+    // At this point, all the children have their dimensions set in the main
+    // axis.
+    // Their dimensions are also set in the cross axis with the exception of
+    // items
+    // that are aligned "stretch". We need to compute these stretch values and
+    // set the final positions.
+
+    YGJustifyMainAxis(
+        node,
+        collectedFlexItemsValues,
+        startOfLineIndex,
+        mainAxis,
+        crossAxis,
+        measureModeMainDim,
+        measureModeCrossDim,
+        mainAxisownerSize,
+        ownerWidth,
+        availableInnerMainDim,
+        availableInnerCrossDim,
+        availableInnerWidth,
+        performLayout);
+
+    float containerCrossAxis = availableInnerCrossDim;
+    if (measureModeCrossDim == YGMeasureModeUndefined ||
+        measureModeCrossDim == YGMeasureModeAtMost) {
+      // Compute the cross axis from the max cross dimension of the children.
+      containerCrossAxis =
+          YGNodeBoundAxis(
+              node,
+              crossAxis,
+              collectedFlexItemsValues.crossDim + paddingAndBorderAxisCross,
+              crossAxisownerSize,
+              ownerWidth) -
+          paddingAndBorderAxisCross;
+    }
+
+    // If there's no flex wrap, the cross dimension is defined by the container.
+    if (!isNodeFlexWrap && measureModeCrossDim == YGMeasureModeExactly) {
+      collectedFlexItemsValues.crossDim = availableInnerCrossDim;
+    }
+
+    // Clamp to the min/max size specified on the container.
+    collectedFlexItemsValues.crossDim =
+        YGNodeBoundAxis(
+            node,
+            crossAxis,
+            collectedFlexItemsValues.crossDim + paddingAndBorderAxisCross,
+            crossAxisownerSize,
+            ownerWidth) -
+        paddingAndBorderAxisCross;
+
+    // STEP 7: CROSS-AXIS ALIGNMENT
+    // We can skip child alignment if we're just measuring the container.
+    if (performLayout) {
+      for (uint32_t i = startOfLineIndex; i < endOfLineIndex; i++) {
+        const YGNodeRef child = node->getChild(i);
+        if (child->getStyle().display == YGDisplayNone) {
+          continue;
+        }
+        if (child->getStyle().positionType == YGPositionTypeAbsolute) {
+          // If the child is absolutely positioned and has a
+          // top/left/bottom/right set, override
+          // all the previously computed positions to set it correctly.
+          const bool isChildLeadingPosDefined =
+              child->isLeadingPositionDefined(crossAxis);
+          if (isChildLeadingPosDefined) {
+            child->setLayoutPosition(
+                YGUnwrapFloatOptional(child->getLeadingPosition(
+                    crossAxis, availableInnerCrossDim)) +
+                    node->getLeadingBorder(crossAxis) +
+                    YGUnwrapFloatOptional(child->getLeadingMargin(
+                        crossAxis, availableInnerWidth)),
+                pos[crossAxis]);
+          }
+          // If leading position is not defined or calculations result in Nan,
+          // default to border + margin
+          if (!isChildLeadingPosDefined ||
+              YGFloatIsUndefined(child->getLayout().position[pos[crossAxis]])) {
+            child->setLayoutPosition(
+                node->getLeadingBorder(crossAxis) +
+                    YGUnwrapFloatOptional(child->getLeadingMargin(
+                        crossAxis, availableInnerWidth)),
+                pos[crossAxis]);
+          }
+        } else {
+          float leadingCrossDim = leadingPaddingAndBorderCross;
+
+          // For a relative children, we're either using alignItems (owner) or
+          // alignSelf (child) in order to determine the position in the cross
+          // axis
+          const YGAlign alignItem = YGNodeAlignItem(node, child);
+
+          // If the child uses align stretch, we need to lay it out one more
+          // time, this time
+          // forcing the cross-axis size to be the computed cross size for the
+          // current line.
+          if (alignItem == YGAlignStretch &&
+              child->marginLeadingValue(crossAxis).unit != YGUnitAuto &&
+              child->marginTrailingValue(crossAxis).unit != YGUnitAuto) {
+            // If the child defines a definite size for its cross axis, there's
+            // no need to stretch.
+            if (!YGNodeIsStyleDimDefined(
+                    child, crossAxis, availableInnerCrossDim)) {
+              float childMainSize =
+                  child->getLayout().measuredDimensions[dim[mainAxis]];
+              float childCrossSize =
+                  !child->getStyle().aspectRatio.isUndefined()
+                  ? ((YGUnwrapFloatOptional(child->getMarginForAxis(
+                          crossAxis, availableInnerWidth)) +
+                      (isMainAxisRow ? childMainSize /
+                               child->getStyle().aspectRatio.getValue()
+                                     : childMainSize *
+                               child->getStyle().aspectRatio.getValue())))
+                  : collectedFlexItemsValues.crossDim;
+
+              childMainSize += YGUnwrapFloatOptional(
+                  child->getMarginForAxis(mainAxis, availableInnerWidth));
+
+              YGMeasureMode childMainMeasureMode = YGMeasureModeExactly;
+              YGMeasureMode childCrossMeasureMode = YGMeasureModeExactly;
+              YGConstrainMaxSizeForMode(
+                  child,
+                  mainAxis,
+                  availableInnerMainDim,
+                  availableInnerWidth,
+                  &childMainMeasureMode,
+                  &childMainSize);
+              YGConstrainMaxSizeForMode(
+                  child,
+                  crossAxis,
+                  availableInnerCrossDim,
+                  availableInnerWidth,
+                  &childCrossMeasureMode,
+                  &childCrossSize);
+
+              const float childWidth =
+                  isMainAxisRow ? childMainSize : childCrossSize;
+              const float childHeight =
+                  !isMainAxisRow ? childMainSize : childCrossSize;
+
+              const YGMeasureMode childWidthMeasureMode =
+                  YGFloatIsUndefined(childWidth) ? YGMeasureModeUndefined
+                                                 : YGMeasureModeExactly;
+              const YGMeasureMode childHeightMeasureMode =
+                  YGFloatIsUndefined(childHeight) ? YGMeasureModeUndefined
+                                                  : YGMeasureModeExactly;
+
+              YGLayoutNodeInternal(
+                  child,
+                  childWidth,
+                  childHeight,
+                  direction,
+                  childWidthMeasureMode,
+                  childHeightMeasureMode,
+                  availableInnerWidth,
+                  availableInnerHeight,
+                  true,
+                  "stretch",
+                  config);
+            }
+          } else {
+            const float remainingCrossDim = containerCrossAxis -
+                YGNodeDimWithMargin(child, crossAxis, availableInnerWidth);
+
+            if (child->marginLeadingValue(crossAxis).unit == YGUnitAuto &&
+                child->marginTrailingValue(crossAxis).unit == YGUnitAuto) {
+              leadingCrossDim += YGFloatMax(0.0f, remainingCrossDim / 2);
+            } else if (
+                child->marginTrailingValue(crossAxis).unit == YGUnitAuto) {
+              // No-Op
+            } else if (
+                child->marginLeadingValue(crossAxis).unit == YGUnitAuto) {
+              leadingCrossDim += YGFloatMax(0.0f, remainingCrossDim);
+            } else if (alignItem == YGAlignFlexStart) {
+              // No-Op
+            } else if (alignItem == YGAlignCenter) {
+              leadingCrossDim += remainingCrossDim / 2;
+            } else {
+              leadingCrossDim += remainingCrossDim;
+            }
+          }
+          // And we apply the position
+          child->setLayoutPosition(
+              child->getLayout().position[pos[crossAxis]] + totalLineCrossDim +
+                  leadingCrossDim,
+              pos[crossAxis]);
+        }
+      }
+    }
+
+    totalLineCrossDim += collectedFlexItemsValues.crossDim;
+    maxLineMainDim =
+        YGFloatMax(maxLineMainDim, collectedFlexItemsValues.mainDim);
+  }
+
+  // STEP 8: MULTI-LINE CONTENT ALIGNMENT
+  // currentLead stores the size of the cross dim
+  if (performLayout && (lineCount > 1 || YGIsBaselineLayout(node))) {
+    float crossDimLead = 0;
+    float currentLead = leadingPaddingAndBorderCross;
+    if (!YGFloatIsUndefined(availableInnerCrossDim)) {
+      const float remainingAlignContentDim =
+          availableInnerCrossDim - totalLineCrossDim;
+      switch (node->getStyle().alignContent) {
+        case YGAlignFlexEnd:
+          currentLead += remainingAlignContentDim;
+          break;
+        case YGAlignCenter:
+          currentLead += remainingAlignContentDim / 2;
+          break;
+        case YGAlignStretch:
+          if (availableInnerCrossDim > totalLineCrossDim) {
+            crossDimLead = remainingAlignContentDim / lineCount;
+          }
+          break;
+        case YGAlignSpaceAround:
+          if (availableInnerCrossDim > totalLineCrossDim) {
+            currentLead += remainingAlignContentDim / (2 * lineCount);
+            if (lineCount > 1) {
+              crossDimLead = remainingAlignContentDim / lineCount;
+            }
+          } else {
+            currentLead += remainingAlignContentDim / 2;
+          }
+          break;
+        case YGAlignSpaceBetween:
+          if (availableInnerCrossDim > totalLineCrossDim && lineCount > 1) {
+            crossDimLead = remainingAlignContentDim / (lineCount - 1);
+          }
+          break;
+        case YGAlignAuto:
+        case YGAlignFlexStart:
+        case YGAlignBaseline:
+          break;
+      }
+    }
+    uint32_t endIndex = 0;
+    for (uint32_t i = 0; i < lineCount; i++) {
+      const uint32_t startIndex = endIndex;
+      uint32_t ii;
+
+      // compute the line's height and find the endIndex
+      float lineHeight = 0;
+      float maxAscentForCurrentLine = 0;
+      float maxDescentForCurrentLine = 0;
+      for (ii = startIndex; ii < childCount; ii++) {
+        const YGNodeRef child = node->getChild(ii);
+        if (child->getStyle().display == YGDisplayNone) {
+          continue;
+        }
+        if (child->getStyle().positionType == YGPositionTypeRelative) {
+          if (child->getLineIndex() != i) {
+            break;
+          }
+          if (YGNodeIsLayoutDimDefined(child, crossAxis)) {
+            lineHeight = YGFloatMax(
+                lineHeight,
+                child->getLayout().measuredDimensions[dim[crossAxis]] +
+                    YGUnwrapFloatOptional(child->getMarginForAxis(
+                        crossAxis, availableInnerWidth)));
+          }
+          if (YGNodeAlignItem(node, child) == YGAlignBaseline) {
+            const float ascent = YGBaseline(child) +
+                YGUnwrapFloatOptional(child->getLeadingMargin(
+                    YGFlexDirectionColumn, availableInnerWidth));
+            const float descent =
+                child->getLayout().measuredDimensions[YGDimensionHeight] +
+                YGUnwrapFloatOptional(child->getMarginForAxis(
+                    YGFlexDirectionColumn, availableInnerWidth)) -
+                ascent;
+            maxAscentForCurrentLine =
+                YGFloatMax(maxAscentForCurrentLine, ascent);
+            maxDescentForCurrentLine =
+                YGFloatMax(maxDescentForCurrentLine, descent);
+            lineHeight = YGFloatMax(
+                lineHeight, maxAscentForCurrentLine + maxDescentForCurrentLine);
+          }
+        }
+      }
+      endIndex = ii;
+      lineHeight += crossDimLead;
+
+      if (performLayout) {
+        for (ii = startIndex; ii < endIndex; ii++) {
+          const YGNodeRef child = node->getChild(ii);
+          if (child->getStyle().display == YGDisplayNone) {
+            continue;
+          }
+          if (child->getStyle().positionType == YGPositionTypeRelative) {
+            switch (YGNodeAlignItem(node, child)) {
+              case YGAlignFlexStart: {
+                child->setLayoutPosition(
+                    currentLead +
+                        YGUnwrapFloatOptional(child->getLeadingMargin(
+                            crossAxis, availableInnerWidth)),
+                    pos[crossAxis]);
+                break;
+              }
+              case YGAlignFlexEnd: {
+                child->setLayoutPosition(
+                    currentLead + lineHeight -
+                        YGUnwrapFloatOptional(child->getTrailingMargin(
+                            crossAxis, availableInnerWidth)) -
+                        child->getLayout().measuredDimensions[dim[crossAxis]],
+                    pos[crossAxis]);
+                break;
+              }
+              case YGAlignCenter: {
+                float childHeight =
+                    child->getLayout().measuredDimensions[dim[crossAxis]];
+
+                child->setLayoutPosition(
+                    currentLead + (lineHeight - childHeight) / 2,
+                    pos[crossAxis]);
+                break;
+              }
+              case YGAlignStretch: {
+                child->setLayoutPosition(
+                    currentLead +
+                        YGUnwrapFloatOptional(child->getLeadingMargin(
+                            crossAxis, availableInnerWidth)),
+                    pos[crossAxis]);
+
+                // Remeasure child with the line height as it as been only
+                // measured with the owners height yet.
+                if (!YGNodeIsStyleDimDefined(
+                        child, crossAxis, availableInnerCrossDim)) {
+                  const float childWidth = isMainAxisRow
+                      ? (child->getLayout()
+                             .measuredDimensions[YGDimensionWidth] +
+                         YGUnwrapFloatOptional(child->getMarginForAxis(
+                             mainAxis, availableInnerWidth)))
+                      : lineHeight;
+
+                  const float childHeight = !isMainAxisRow
+                      ? (child->getLayout()
+                             .measuredDimensions[YGDimensionHeight] +
+                         YGUnwrapFloatOptional(child->getMarginForAxis(
+                             crossAxis, availableInnerWidth)))
+                      : lineHeight;
+
+                  if (!(YGFloatsEqual(
+                            childWidth,
+                            child->getLayout()
+                                .measuredDimensions[YGDimensionWidth]) &&
+                        YGFloatsEqual(
+                            childHeight,
+                            child->getLayout()
+                                .measuredDimensions[YGDimensionHeight]))) {
+                    YGLayoutNodeInternal(
+                        child,
+                        childWidth,
+                        childHeight,
+                        direction,
+                        YGMeasureModeExactly,
+                        YGMeasureModeExactly,
+                        availableInnerWidth,
+                        availableInnerHeight,
+                        true,
+                        "multiline-stretch",
+                        config);
+                  }
+                }
+                break;
+              }
+              case YGAlignBaseline: {
+                child->setLayoutPosition(
+                    currentLead + maxAscentForCurrentLine - YGBaseline(child) +
+                        YGUnwrapFloatOptional(child->getLeadingPosition(
+                            YGFlexDirectionColumn, availableInnerCrossDim)),
+                    YGEdgeTop);
+
+                break;
+              }
+              case YGAlignAuto:
+              case YGAlignSpaceBetween:
+              case YGAlignSpaceAround:
+                break;
+            }
+          }
+        }
+      }
+      currentLead += lineHeight;
+    }
+  }
+
+  // STEP 9: COMPUTING FINAL DIMENSIONS
+
+  node->setLayoutMeasuredDimension(
+      YGNodeBoundAxis(
+          node,
+          YGFlexDirectionRow,
+          availableWidth - marginAxisRow,
+          ownerWidth,
+          ownerWidth),
+      YGDimensionWidth);
+
+  node->setLayoutMeasuredDimension(
+      YGNodeBoundAxis(
+          node,
+          YGFlexDirectionColumn,
+          availableHeight - marginAxisColumn,
+          ownerHeight,
+          ownerWidth),
+      YGDimensionHeight);
+
+  // If the user didn't specify a width or height for the node, set the
+  // dimensions based on the children.
+  if (measureModeMainDim == YGMeasureModeUndefined ||
+      (node->getStyle().overflow != YGOverflowScroll &&
+       measureModeMainDim == YGMeasureModeAtMost)) {
+    // Clamp the size to the min/max size, if specified, and make sure it
+    // doesn't go below the padding and border amount.
+    node->setLayoutMeasuredDimension(
+        YGNodeBoundAxis(
+            node, mainAxis, maxLineMainDim, mainAxisownerSize, ownerWidth),
+        dim[mainAxis]);
+
+  } else if (
+      measureModeMainDim == YGMeasureModeAtMost &&
+      node->getStyle().overflow == YGOverflowScroll) {
+    node->setLayoutMeasuredDimension(
+        YGFloatMax(
+            YGFloatMin(
+                availableInnerMainDim + paddingAndBorderAxisMain,
+                YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
+                    node, mainAxis, maxLineMainDim, mainAxisownerSize))),
+            paddingAndBorderAxisMain),
+        dim[mainAxis]);
+  }
+
+  if (measureModeCrossDim == YGMeasureModeUndefined ||
+      (node->getStyle().overflow != YGOverflowScroll &&
+       measureModeCrossDim == YGMeasureModeAtMost)) {
+    // Clamp the size to the min/max size, if specified, and make sure it
+    // doesn't go below the padding and border amount.
+    node->setLayoutMeasuredDimension(
+        YGNodeBoundAxis(
+            node,
+            crossAxis,
+            totalLineCrossDim + paddingAndBorderAxisCross,
+            crossAxisownerSize,
+            ownerWidth),
+        dim[crossAxis]);
+
+  } else if (
+      measureModeCrossDim == YGMeasureModeAtMost &&
+      node->getStyle().overflow == YGOverflowScroll) {
+    node->setLayoutMeasuredDimension(
+        YGFloatMax(
+            YGFloatMin(
+                availableInnerCrossDim + paddingAndBorderAxisCross,
+                YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
+                    node,
+                    crossAxis,
+                    totalLineCrossDim + paddingAndBorderAxisCross,
+                    crossAxisownerSize))),
+            paddingAndBorderAxisCross),
+        dim[crossAxis]);
+  }
+
+  // As we only wrapped in normal direction yet, we need to reverse the
+  // positions on wrap-reverse.
+  if (performLayout && node->getStyle().flexWrap == YGWrapWrapReverse) {
+    for (uint32_t i = 0; i < childCount; i++) {
+      const YGNodeRef child = YGNodeGetChild(node, i);
+      if (child->getStyle().positionType == YGPositionTypeRelative) {
+        child->setLayoutPosition(
+            node->getLayout().measuredDimensions[dim[crossAxis]] -
+                child->getLayout().position[pos[crossAxis]] -
+                child->getLayout().measuredDimensions[dim[crossAxis]],
+            pos[crossAxis]);
+      }
+    }
+  }
+
+  if (performLayout) {
+    // STEP 10: SIZING AND POSITIONING ABSOLUTE CHILDREN
+    for (auto child : node->getChildren()) {
+      if (child->getStyle().positionType != YGPositionTypeAbsolute) {
+        continue;
+      }
+      YGNodeAbsoluteLayoutChild(
+          node,
+          child,
+          availableInnerWidth,
+          isMainAxisRow ? measureModeMainDim : measureModeCrossDim,
+          availableInnerHeight,
+          direction,
+          config);
+    }
+
+    // STEP 11: SETTING TRAILING POSITIONS FOR CHILDREN
+    const bool needsMainTrailingPos = mainAxis == YGFlexDirectionRowReverse ||
+        mainAxis == YGFlexDirectionColumnReverse;
+    const bool needsCrossTrailingPos = crossAxis == YGFlexDirectionRowReverse ||
+        crossAxis == YGFlexDirectionColumnReverse;
+
+    // Set trailing position if necessary.
+    if (needsMainTrailingPos || needsCrossTrailingPos) {
+      for (uint32_t i = 0; i < childCount; i++) {
+        const YGNodeRef child = node->getChild(i);
+        if (child->getStyle().display == YGDisplayNone) {
+          continue;
+        }
+        if (needsMainTrailingPos) {
+          YGNodeSetChildTrailingPosition(node, child, mainAxis);
+        }
+
+        if (needsCrossTrailingPos) {
+          YGNodeSetChildTrailingPosition(node, child, crossAxis);
+        }
+      }
+    }
+  }
+}
+
+uint32_t gDepth = 0;
+bool gPrintChanges = false;
+bool gPrintSkips = false;
+
+static const char* spacer =
+    "                                                            ";
+
+static const char* YGSpacer(const unsigned long level) {
+  const size_t spacerLen = strlen(spacer);
+  if (level > spacerLen) {
+    return &spacer[0];
+  } else {
+    return &spacer[spacerLen - level];
+  }
+}
+
+static const char* YGMeasureModeName(
+    const YGMeasureMode mode,
+    const bool performLayout) {
+  const char* kMeasureModeNames[YGMeasureModeCount] = {
+      "UNDEFINED", "EXACTLY", "AT_MOST"};
+  const char* kLayoutModeNames[YGMeasureModeCount] = {"LAY_UNDEFINED",
+                                                      "LAY_EXACTLY",
+                                                      "LAY_AT_"
+                                                      "MOST"};
+
+  if (mode >= YGMeasureModeCount) {
+    return "";
+  }
+
+  return performLayout ? kLayoutModeNames[mode] : kMeasureModeNames[mode];
+}
+
+static inline bool YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(
+    YGMeasureMode sizeMode,
+    float size,
+    float lastComputedSize) {
+  return sizeMode == YGMeasureModeExactly &&
+      YGFloatsEqual(size, lastComputedSize);
+}
+
+static inline bool YGMeasureModeOldSizeIsUnspecifiedAndStillFits(
+    YGMeasureMode sizeMode,
+    float size,
+    YGMeasureMode lastSizeMode,
+    float lastComputedSize) {
+  return sizeMode == YGMeasureModeAtMost &&
+      lastSizeMode == YGMeasureModeUndefined &&
+      (size >= lastComputedSize || YGFloatsEqual(size, lastComputedSize));
+}
+
+static inline bool YGMeasureModeNewMeasureSizeIsStricterAndStillValid(
+    YGMeasureMode sizeMode,
+    float size,
+    YGMeasureMode lastSizeMode,
+    float lastSize,
+    float lastComputedSize) {
+  return lastSizeMode == YGMeasureModeAtMost &&
+      sizeMode == YGMeasureModeAtMost && !YGFloatIsUndefined(lastSize) &&
+      !YGFloatIsUndefined(size) && !YGFloatIsUndefined(lastComputedSize) &&
+      lastSize > size &&
+      (lastComputedSize <= size || YGFloatsEqual(size, lastComputedSize));
+}
+
+float YGRoundValueToPixelGrid(
+    const float value,
+    const float pointScaleFactor,
+    const bool forceCeil,
+    const bool forceFloor) {
+  float scaledValue = value * pointScaleFactor;
+  float fractial = fmodf(scaledValue, 1.0f);
+  if (YGFloatsEqual(fractial, 0)) {
+    // First we check if the value is already rounded
+    scaledValue = scaledValue - fractial;
+  } else if (YGFloatsEqual(fractial, 1.0f)) {
+    scaledValue = scaledValue - fractial + 1.0f;
+  } else if (forceCeil) {
+    // Next we check if we need to use forced rounding
+    scaledValue = scaledValue - fractial + 1.0f;
+  } else if (forceFloor) {
+    scaledValue = scaledValue - fractial;
+  } else {
+    // Finally we just round the value
+    scaledValue = scaledValue - fractial +
+        (!YGFloatIsUndefined(fractial) &&
+                 (fractial > 0.5f || YGFloatsEqual(fractial, 0.5f))
+             ? 1.0f
+             : 0.0f);
+  }
+  return (YGFloatIsUndefined(scaledValue) ||
+          YGFloatIsUndefined(pointScaleFactor))
+      ? YGUndefined
+      : scaledValue / pointScaleFactor;
+}
+
+bool YGNodeCanUseCachedMeasurement(
+    const YGMeasureMode widthMode,
+    const float width,
+    const YGMeasureMode heightMode,
+    const float height,
+    const YGMeasureMode lastWidthMode,
+    const float lastWidth,
+    const YGMeasureMode lastHeightMode,
+    const float lastHeight,
+    const float lastComputedWidth,
+    const float lastComputedHeight,
+    const float marginRow,
+    const float marginColumn,
+    const YGConfigRef config) {
+  if ((!YGFloatIsUndefined(lastComputedHeight) && lastComputedHeight < 0) ||
+      (!YGFloatIsUndefined(lastComputedWidth) && lastComputedWidth < 0)) {
+    return false;
+  }
+  bool useRoundedComparison =
+      config != nullptr && config->pointScaleFactor != 0;
+  const float effectiveWidth = useRoundedComparison
+      ? YGRoundValueToPixelGrid(width, config->pointScaleFactor, false, false)
+      : width;
+  const float effectiveHeight = useRoundedComparison
+      ? YGRoundValueToPixelGrid(height, config->pointScaleFactor, false, false)
+      : height;
+  const float effectiveLastWidth = useRoundedComparison
+      ? YGRoundValueToPixelGrid(
+            lastWidth, config->pointScaleFactor, false, false)
+      : lastWidth;
+  const float effectiveLastHeight = useRoundedComparison
+      ? YGRoundValueToPixelGrid(
+            lastHeight, config->pointScaleFactor, false, false)
+      : lastHeight;
+
+  const bool hasSameWidthSpec = lastWidthMode == widthMode &&
+      YGFloatsEqual(effectiveLastWidth, effectiveWidth);
+  const bool hasSameHeightSpec = lastHeightMode == heightMode &&
+      YGFloatsEqual(effectiveLastHeight, effectiveHeight);
+
+  const bool widthIsCompatible =
+      hasSameWidthSpec ||
+      YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(
+          widthMode, width - marginRow, lastComputedWidth) ||
+      YGMeasureModeOldSizeIsUnspecifiedAndStillFits(
+          widthMode, width - marginRow, lastWidthMode, lastComputedWidth) ||
+      YGMeasureModeNewMeasureSizeIsStricterAndStillValid(
+          widthMode,
+          width - marginRow,
+          lastWidthMode,
+          lastWidth,
+          lastComputedWidth);
+
+  const bool heightIsCompatible =
+      hasSameHeightSpec ||
+      YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(
+          heightMode, height - marginColumn, lastComputedHeight) ||
+      YGMeasureModeOldSizeIsUnspecifiedAndStillFits(
+          heightMode,
+          height - marginColumn,
+          lastHeightMode,
+          lastComputedHeight) ||
+      YGMeasureModeNewMeasureSizeIsStricterAndStillValid(
+          heightMode,
+          height - marginColumn,
+          lastHeightMode,
+          lastHeight,
+          lastComputedHeight);
+
+  return widthIsCompatible && heightIsCompatible;
+}
+
+//
+// This is a wrapper around the YGNodelayoutImpl function. It determines
+// whether the layout request is redundant and can be skipped.
+//
+// Parameters:
+//  Input parameters are the same as YGNodelayoutImpl (see above)
+//  Return parameter is true if layout was performed, false if skipped
+//
+bool YGLayoutNodeInternal(
+    const YGNodeRef node,
+    const float availableWidth,
+    const float availableHeight,
+    const YGDirection ownerDirection,
+    const YGMeasureMode widthMeasureMode,
+    const YGMeasureMode heightMeasureMode,
+    const float ownerWidth,
+    const float ownerHeight,
+    const bool performLayout,
+    const char* reason,
+    const YGConfigRef config) {
+  YGLayout* layout = &node->getLayout();
+
+  gDepth++;
+
+  const bool needToVisitNode =
+      (node->isDirty() && layout->generationCount != gCurrentGenerationCount) ||
+      layout->lastOwnerDirection != ownerDirection;
+
+  if (needToVisitNode) {
+    // Invalidate the cached results.
+    layout->nextCachedMeasurementsIndex = 0;
+    layout->cachedLayout.widthMeasureMode = (YGMeasureMode)-1;
+    layout->cachedLayout.heightMeasureMode = (YGMeasureMode)-1;
+    layout->cachedLayout.computedWidth = -1;
+    layout->cachedLayout.computedHeight = -1;
+  }
+
+  YGCachedMeasurement* cachedResults = nullptr;
+
+  // Determine whether the results are already cached. We maintain a separate
+  // cache for layouts and measurements. A layout operation modifies the
+  // positions
+  // and dimensions for nodes in the subtree. The algorithm assumes that each
+  // node
+  // gets layed out a maximum of one time per tree layout, but multiple
+  // measurements
+  // may be required to resolve all of the flex dimensions.
+  // We handle nodes with measure functions specially here because they are the
+  // most
+  // expensive to measure, so it's worth avoiding redundant measurements if at
+  // all possible.
+  if (node->getMeasure() != nullptr) {
+    const float marginAxisRow = YGUnwrapFloatOptional(
+        node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
+    const float marginAxisColumn = YGUnwrapFloatOptional(
+        node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
+
+    // First, try to use the layout cache.
+    if (YGNodeCanUseCachedMeasurement(
+            widthMeasureMode,
+            availableWidth,
+            heightMeasureMode,
+            availableHeight,
+            layout->cachedLayout.widthMeasureMode,
+            layout->cachedLayout.availableWidth,
+            layout->cachedLayout.heightMeasureMode,
+            layout->cachedLayout.availableHeight,
+            layout->cachedLayout.computedWidth,
+            layout->cachedLayout.computedHeight,
+            marginAxisRow,
+            marginAxisColumn,
+            config)) {
+      cachedResults = &layout->cachedLayout;
+    } else {
+      // Try to use the measurement cache.
+      for (uint32_t i = 0; i < layout->nextCachedMeasurementsIndex; i++) {
+        if (YGNodeCanUseCachedMeasurement(
+                widthMeasureMode,
+                availableWidth,
+                heightMeasureMode,
+                availableHeight,
+                layout->cachedMeasurements[i].widthMeasureMode,
+                layout->cachedMeasurements[i].availableWidth,
+                layout->cachedMeasurements[i].heightMeasureMode,
+                layout->cachedMeasurements[i].availableHeight,
+                layout->cachedMeasurements[i].computedWidth,
+                layout->cachedMeasurements[i].computedHeight,
+                marginAxisRow,
+                marginAxisColumn,
+                config)) {
+          cachedResults = &layout->cachedMeasurements[i];
+          break;
+        }
+      }
+    }
+  } else if (performLayout) {
+    if (YGFloatsEqual(layout->cachedLayout.availableWidth, availableWidth) &&
+        YGFloatsEqual(layout->cachedLayout.availableHeight, availableHeight) &&
+        layout->cachedLayout.widthMeasureMode == widthMeasureMode &&
+        layout->cachedLayout.heightMeasureMode == heightMeasureMode) {
+      cachedResults = &layout->cachedLayout;
+    }
+  } else {
+    for (uint32_t i = 0; i < layout->nextCachedMeasurementsIndex; i++) {
+      if (YGFloatsEqual(
+              layout->cachedMeasurements[i].availableWidth, availableWidth) &&
+          YGFloatsEqual(
+              layout->cachedMeasurements[i].availableHeight, availableHeight) &&
+          layout->cachedMeasurements[i].widthMeasureMode == widthMeasureMode &&
+          layout->cachedMeasurements[i].heightMeasureMode ==
+              heightMeasureMode) {
+        cachedResults = &layout->cachedMeasurements[i];
+        break;
+      }
+    }
+  }
+
+  if (!needToVisitNode && cachedResults != nullptr) {
+    layout->measuredDimensions[YGDimensionWidth] = cachedResults->computedWidth;
+    layout->measuredDimensions[YGDimensionHeight] =
+        cachedResults->computedHeight;
+
+    if (gPrintChanges && gPrintSkips) {
+      YGLog(
+          node,
+          YGLogLevelVerbose,
+          "%s%d.{[skipped] ",
+          YGSpacer(gDepth),
+          gDepth);
+      if (node->getPrintFunc() != nullptr) {
+        node->getPrintFunc()(node);
+      }
+      YGLog(
+          node,
+          YGLogLevelVerbose,
+          "wm: %s, hm: %s, aw: %f ah: %f => d: (%f, %f) %s\n",
+          YGMeasureModeName(widthMeasureMode, performLayout),
+          YGMeasureModeName(heightMeasureMode, performLayout),
+          availableWidth,
+          availableHeight,
+          cachedResults->computedWidth,
+          cachedResults->computedHeight,
+          reason);
+    }
+  } else {
+    if (gPrintChanges) {
+      YGLog(
+          node,
+          YGLogLevelVerbose,
+          "%s%d.{%s",
+          YGSpacer(gDepth),
+          gDepth,
+          needToVisitNode ? "*" : "");
+      if (node->getPrintFunc() != nullptr) {
+        node->getPrintFunc()(node);
+      }
+      YGLog(
+          node,
+          YGLogLevelVerbose,
+          "wm: %s, hm: %s, aw: %f ah: %f %s\n",
+          YGMeasureModeName(widthMeasureMode, performLayout),
+          YGMeasureModeName(heightMeasureMode, performLayout),
+          availableWidth,
+          availableHeight,
+          reason);
+    }
+
+    YGNodelayoutImpl(
+        node,
+        availableWidth,
+        availableHeight,
+        ownerDirection,
+        widthMeasureMode,
+        heightMeasureMode,
+        ownerWidth,
+        ownerHeight,
+        performLayout,
+        config);
+
+    if (gPrintChanges) {
+      YGLog(
+          node,
+          YGLogLevelVerbose,
+          "%s%d.}%s",
+          YGSpacer(gDepth),
+          gDepth,
+          needToVisitNode ? "*" : "");
+      if (node->getPrintFunc() != nullptr) {
+        node->getPrintFunc()(node);
+      }
+      YGLog(
+          node,
+          YGLogLevelVerbose,
+          "wm: %s, hm: %s, d: (%f, %f) %s\n",
+          YGMeasureModeName(widthMeasureMode, performLayout),
+          YGMeasureModeName(heightMeasureMode, performLayout),
+          layout->measuredDimensions[YGDimensionWidth],
+          layout->measuredDimensions[YGDimensionHeight],
+          reason);
+    }
+
+    layout->lastOwnerDirection = ownerDirection;
+
+    if (cachedResults == nullptr) {
+      if (layout->nextCachedMeasurementsIndex == YG_MAX_CACHED_RESULT_COUNT) {
+        if (gPrintChanges) {
+          YGLog(node, YGLogLevelVerbose, "Out of cache entries!\n");
+        }
+        layout->nextCachedMeasurementsIndex = 0;
+      }
+
+      YGCachedMeasurement* newCacheEntry;
+      if (performLayout) {
+        // Use the single layout cache entry.
+        newCacheEntry = &layout->cachedLayout;
+      } else {
+        // Allocate a new measurement cache entry.
+        newCacheEntry =
+            &layout->cachedMeasurements[layout->nextCachedMeasurementsIndex];
+        layout->nextCachedMeasurementsIndex++;
+      }
+
+      newCacheEntry->availableWidth = availableWidth;
+      newCacheEntry->availableHeight = availableHeight;
+      newCacheEntry->widthMeasureMode = widthMeasureMode;
+      newCacheEntry->heightMeasureMode = heightMeasureMode;
+      newCacheEntry->computedWidth =
+          layout->measuredDimensions[YGDimensionWidth];
+      newCacheEntry->computedHeight =
+          layout->measuredDimensions[YGDimensionHeight];
+    }
+  }
+
+  if (performLayout) {
+    node->setLayoutDimension(
+        node->getLayout().measuredDimensions[YGDimensionWidth],
+        YGDimensionWidth);
+    node->setLayoutDimension(
+        node->getLayout().measuredDimensions[YGDimensionHeight],
+        YGDimensionHeight);
+
+    node->setHasNewLayout(true);
+    node->setDirty(false);
+  }
+
+  gDepth--;
+  layout->generationCount = gCurrentGenerationCount;
+  return (needToVisitNode || cachedResults == nullptr);
+}
+
+void YGConfigSetPointScaleFactor(
+    const YGConfigRef config,
+    const float pixelsInPoint) {
+  YGAssertWithConfig(
+      config,
+      pixelsInPoint >= 0.0f,
+      "Scale factor should not be less than zero");
+
+  // We store points for Pixel as we will use it for rounding
+  if (pixelsInPoint == 0.0f) {
+    // Zero is used to skip rounding
+    config->pointScaleFactor = 0.0f;
+  } else {
+    config->pointScaleFactor = pixelsInPoint;
+  }
+}
+
+static void YGRoundToPixelGrid(
+    const YGNodeRef node,
+    const float pointScaleFactor,
+    const float absoluteLeft,
+    const float absoluteTop) {
+  if (pointScaleFactor == 0.0f) {
+    return;
+  }
+
+  const float nodeLeft = node->getLayout().position[YGEdgeLeft];
+  const float nodeTop = node->getLayout().position[YGEdgeTop];
+
+  const float nodeWidth = node->getLayout().dimensions[YGDimensionWidth];
+  const float nodeHeight = node->getLayout().dimensions[YGDimensionHeight];
+
+  const float absoluteNodeLeft = absoluteLeft + nodeLeft;
+  const float absoluteNodeTop = absoluteTop + nodeTop;
+
+  const float absoluteNodeRight = absoluteNodeLeft + nodeWidth;
+  const float absoluteNodeBottom = absoluteNodeTop + nodeHeight;
+
+  // If a node has a custom measure function we never want to round down its
+  // size as this could lead to unwanted text truncation.
+  const bool textRounding = node->getNodeType() == YGNodeTypeText;
+
+  node->setLayoutPosition(
+      YGRoundValueToPixelGrid(nodeLeft, pointScaleFactor, false, textRounding),
+      YGEdgeLeft);
+
+  node->setLayoutPosition(
+      YGRoundValueToPixelGrid(nodeTop, pointScaleFactor, false, textRounding),
+      YGEdgeTop);
+
+  // We multiply dimension by scale factor and if the result is close to the
+  // whole number, we don't have any fraction To verify if the result is close
+  // to whole number we want to check both floor and ceil numbers
+  const bool hasFractionalWidth =
+      !YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 0) &&
+      !YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 1.0);
+  const bool hasFractionalHeight =
+      !YGFloatsEqual(fmodf(nodeHeight * pointScaleFactor, 1.0), 0) &&
+      !YGFloatsEqual(fmodf(nodeHeight * pointScaleFactor, 1.0), 1.0);
+
+  node->setLayoutDimension(
+      YGRoundValueToPixelGrid(
+          absoluteNodeRight,
+          pointScaleFactor,
+          (textRounding && hasFractionalWidth),
+          (textRounding && !hasFractionalWidth)) -
+          YGRoundValueToPixelGrid(
+              absoluteNodeLeft, pointScaleFactor, false, textRounding),
+      YGDimensionWidth);
+
+  node->setLayoutDimension(
+      YGRoundValueToPixelGrid(
+          absoluteNodeBottom,
+          pointScaleFactor,
+          (textRounding && hasFractionalHeight),
+          (textRounding && !hasFractionalHeight)) -
+          YGRoundValueToPixelGrid(
+              absoluteNodeTop, pointScaleFactor, false, textRounding),
+      YGDimensionHeight);
+
+  const uint32_t childCount = YGNodeGetChildCount(node);
+  for (uint32_t i = 0; i < childCount; i++) {
+    YGRoundToPixelGrid(
+        YGNodeGetChild(node, i),
+        pointScaleFactor,
+        absoluteNodeLeft,
+        absoluteNodeTop);
+  }
+}
+
+void YGNodeCalculateLayout(
+    const YGNodeRef node,
+    const float ownerWidth,
+    const float ownerHeight,
+    const YGDirection ownerDirection) {
+  // Increment the generation count. This will force the recursive routine to
+  // visit
+  // all dirty nodes at least once. Subsequent visits will be skipped if the
+  // input
+  // parameters don't change.
+  gCurrentGenerationCount++;
+  node->resolveDimension();
+  float width = YGUndefined;
+  YGMeasureMode widthMeasureMode = YGMeasureModeUndefined;
+  if (YGNodeIsStyleDimDefined(node, YGFlexDirectionRow, ownerWidth)) {
+    width = YGUnwrapFloatOptional(
+        YGResolveValue(
+            node->getResolvedDimension(dim[YGFlexDirectionRow]), ownerWidth) +
+        node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
+    widthMeasureMode = YGMeasureModeExactly;
+  } else if (!YGResolveValue(
+                  node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)
+                  .isUndefined()) {
+    width = YGUnwrapFloatOptional(YGResolveValue(
+        node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth));
+    widthMeasureMode = YGMeasureModeAtMost;
+  } else {
+    width = ownerWidth;
+    widthMeasureMode = YGFloatIsUndefined(width) ? YGMeasureModeUndefined
+                                                 : YGMeasureModeExactly;
+  }
+
+  float height = YGUndefined;
+  YGMeasureMode heightMeasureMode = YGMeasureModeUndefined;
+  if (YGNodeIsStyleDimDefined(node, YGFlexDirectionColumn, ownerHeight)) {
+    height = YGUnwrapFloatOptional(
+        YGResolveValue(
+            node->getResolvedDimension(dim[YGFlexDirectionColumn]),
+            ownerHeight) +
+        node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
+    heightMeasureMode = YGMeasureModeExactly;
+  } else if (!YGResolveValue(
+                  node->getStyle().maxDimensions[YGDimensionHeight],
+                  ownerHeight)
+                  .isUndefined()) {
+    height = YGUnwrapFloatOptional(YGResolveValue(
+        node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight));
+    heightMeasureMode = YGMeasureModeAtMost;
+  } else {
+    height = ownerHeight;
+    heightMeasureMode = YGFloatIsUndefined(height) ? YGMeasureModeUndefined
+                                                   : YGMeasureModeExactly;
+  }
+  if (YGLayoutNodeInternal(
+          node,
+          width,
+          height,
+          ownerDirection,
+          widthMeasureMode,
+          heightMeasureMode,
+          ownerWidth,
+          ownerHeight,
+          true,
+          "initial",
+          node->getConfig())) {
+    node->setPosition(
+        node->getLayout().direction, ownerWidth, ownerHeight, ownerWidth);
+    YGRoundToPixelGrid(node, node->getConfig()->pointScaleFactor, 0.0f, 0.0f);
+
+    if (node->getConfig()->printTree) {
+      YGNodePrint(
+          node,
+          (YGPrintOptions)(
+              YGPrintOptionsLayout | YGPrintOptionsChildren |
+              YGPrintOptionsStyle));
+    }
+  }
+
+  // We want to get rid off `useLegacyStretchBehaviour` from YGConfig. But we
+  // aren't sure whether client's of yoga have gotten rid off this flag or not.
+  // So logging this in YGLayout would help to find out the call sites depending
+  // on this flag. This check would be removed once we are sure no one is
+  // dependent on this flag anymore. The flag
+  // `shouldDiffLayoutWithoutLegacyStretchBehaviour` in YGConfig will help to
+  // run experiments.
+  if (node->getConfig()->shouldDiffLayoutWithoutLegacyStretchBehaviour &&
+      node->didUseLegacyFlag()) {
+    const YGNodeRef originalNode = YGNodeDeepClone(node);
+    originalNode->resolveDimension();
+    // Recursively mark nodes as dirty
+    originalNode->markDirtyAndPropogateDownwards();
+    gCurrentGenerationCount++;
+    // Rerun the layout, and calculate the diff
+    originalNode->setAndPropogateUseLegacyFlag(false);
+    if (YGLayoutNodeInternal(
+            originalNode,
+            width,
+            height,
+            ownerDirection,
+            widthMeasureMode,
+            heightMeasureMode,
+            ownerWidth,
+            ownerHeight,
+            true,
+            "initial",
+            originalNode->getConfig())) {
+      originalNode->setPosition(
+          originalNode->getLayout().direction,
+          ownerWidth,
+          ownerHeight,
+          ownerWidth);
+      YGRoundToPixelGrid(
+          originalNode,
+          originalNode->getConfig()->pointScaleFactor,
+          0.0f,
+          0.0f);
+
+      // Set whether the two layouts are different or not.
+      node->setLayoutDoesLegacyFlagAffectsLayout(
+          !originalNode->isLayoutTreeEqualToNode(*node));
+
+      if (originalNode->getConfig()->printTree) {
+        YGNodePrint(
+            originalNode,
+            (YGPrintOptions)(
+                YGPrintOptionsLayout | YGPrintOptionsChildren |
+                YGPrintOptionsStyle));
+      }
+    }
+    YGConfigFreeRecursive(originalNode);
+    YGNodeFreeRecursive(originalNode);
+  }
+}
+
+void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) {
+  if (logger != nullptr) {
+    config->logger = logger;
+  } else {
+#ifdef ANDROID
+    config->logger = &YGAndroidLog;
+#else
+    config->logger = &YGDefaultLog;
+#endif
+  }
+}
+
+void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(
+    const YGConfigRef config,
+    const bool shouldDiffLayout) {
+  config->shouldDiffLayoutWithoutLegacyStretchBehaviour = shouldDiffLayout;
+}
+
+static void YGVLog(
+    const YGConfigRef config,
+    const YGNodeRef node,
+    YGLogLevel level,
+    const char* format,
+    va_list args) {
+  const YGConfigRef logConfig =
+      config != nullptr ? config : YGConfigGetDefault();
+  logConfig->logger(logConfig, node, level, format, args);
+
+  if (level == YGLogLevelFatal) {
+    abort();
+  }
+}
+
+void YGLogWithConfig(
+    const YGConfigRef config,
+    YGLogLevel level,
+    const char* format,
+    ...) {
+  va_list args;
+  va_start(args, format);
+  YGVLog(config, nullptr, level, format, args);
+  va_end(args);
+}
+
+void YGLog(const YGNodeRef node, YGLogLevel level, const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  YGVLog(
+      node == nullptr ? nullptr : node->getConfig(), node, level, format, args);
+  va_end(args);
+}
+
+void YGAssert(const bool condition, const char* message) {
+  if (!condition) {
+    YGLog(nullptr, YGLogLevelFatal, "%s\n", message);
+  }
+}
+
+void YGAssertWithNode(
+    const YGNodeRef node,
+    const bool condition,
+    const char* message) {
+  if (!condition) {
+    YGLog(node, YGLogLevelFatal, "%s\n", message);
+  }
+}
+
+void YGAssertWithConfig(
+    const YGConfigRef config,
+    const bool condition,
+    const char* message) {
+  if (!condition) {
+    YGLogWithConfig(config, YGLogLevelFatal, "%s\n", message);
+  }
+}
+
+void YGConfigSetExperimentalFeatureEnabled(
+    const YGConfigRef config,
+    const YGExperimentalFeature feature,
+    const bool enabled) {
+  config->experimentalFeatures[feature] = enabled;
+}
+
+inline bool YGConfigIsExperimentalFeatureEnabled(
+    const YGConfigRef config,
+    const YGExperimentalFeature feature) {
+  return config->experimentalFeatures[feature];
+}
+
+void YGConfigSetUseWebDefaults(const YGConfigRef config, const bool enabled) {
+  config->useWebDefaults = enabled;
+}
+
+void YGConfigSetUseLegacyStretchBehaviour(
+    const YGConfigRef config,
+    const bool useLegacyStretchBehaviour) {
+  config->useLegacyStretchBehaviour = useLegacyStretchBehaviour;
+}
+
+bool YGConfigGetUseWebDefaults(const YGConfigRef config) {
+  return config->useWebDefaults;
+}
+
+void YGConfigSetContext(const YGConfigRef config, void* context) {
+  config->context = context;
+}
+
+void* YGConfigGetContext(const YGConfigRef config) {
+  return config->context;
+}
+
+void YGConfigSetCloneNodeFunc(
+    const YGConfigRef config,
+    const YGCloneNodeFunc callback) {
+  config->cloneNodeCallback = callback;
+}
+
+static void YGTraverseChildrenPreOrder(
+    const YGVector& children,
+    const std::function<void(YGNodeRef node)>& f) {
+  for (YGNodeRef node : children) {
+    f(node);
+    YGTraverseChildrenPreOrder(node->getChildren(), f);
+  }
+}
+
+void YGTraversePreOrder(
+    YGNodeRef const node,
+    std::function<void(YGNodeRef node)>&& f) {
+  if (!node) {
+    return;
+  }
+  f(node);
+  YGTraverseChildrenPreOrder(node->getChildren(), f);
+}
diff --git a/yoga/Yoga.h b/yoga/Yoga.h
--- a/yoga/Yoga.h
+++ b/yoga/Yoga.h
@@ -1,283 +1,462 @@
-/**
- * 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.
- */
-
-#pragma once
-
-#include <assert.h>
-#include <math.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
-
-// Not defined in MSVC++
-#ifndef NAN
-static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};
-#define NAN (*(const float *) __nan)
-#endif
-
-#define YGUndefined NAN
-
-#include "YGEnums.h"
-#include "YGMacros.h"
-
-YG_EXTERN_C_BEGIN
-
-typedef struct YGSize {
-  float width;
-  float height;
-} YGSize;
-
-typedef struct YGValue {
-  float value;
-  YGUnit unit;
-} YGValue;
-
-static const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined};
-static const YGValue YGValueAuto = {YGUndefined, YGUnitAuto};
-
-typedef struct YGConfig *YGConfigRef;
-typedef struct YGNode *YGNodeRef;
-typedef YGSize (*YGMeasureFunc)(YGNodeRef node,
-                                float width,
-                                YGMeasureMode widthMode,
-                                float height,
-                                YGMeasureMode heightMode);
-typedef float (*YGBaselineFunc)(YGNodeRef node, const float width, const float height);
-typedef void (*YGPrintFunc)(YGNodeRef node);
-typedef int (*YGLogger)(const YGConfigRef config,
-                        const YGNodeRef node,
-                        YGLogLevel level,
-                        const char *format,
-                        va_list args);
-typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
-                                 YGNodeRef newNode,
-                                 YGNodeRef parent,
-                                 int childIndex);
-
-// YGNode
-WIN_EXPORT YGNodeRef YGNodeNew(void);
-WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config);
-WIN_EXPORT YGNodeRef YGNodeClone(const YGNodeRef node);
-WIN_EXPORT void YGNodeFree(const YGNodeRef node);
-WIN_EXPORT void YGNodeFreeRecursive(const YGNodeRef node);
-WIN_EXPORT void YGNodeReset(const YGNodeRef node);
-WIN_EXPORT int32_t YGNodeGetInstanceCount(void);
-
-WIN_EXPORT void YGNodeInsertChild(const YGNodeRef node,
-                                  const YGNodeRef child,
-                                  const uint32_t index);
-WIN_EXPORT void YGNodeRemoveChild(const YGNodeRef node, const YGNodeRef child);
-WIN_EXPORT void YGNodeRemoveAllChildren(const YGNodeRef node);
-WIN_EXPORT YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index);
-WIN_EXPORT YGNodeRef YGNodeGetParent(const YGNodeRef node);
-WIN_EXPORT uint32_t YGNodeGetChildCount(const YGNodeRef node);
-
-WIN_EXPORT void YGNodeCalculateLayout(const YGNodeRef node,
-                                      const float availableWidth,
-                                      const float availableHeight,
-                                      const YGDirection parentDirection);
-
-// Mark a node as dirty. Only valid for nodes with a custom measure function
-// set.
-// YG knows when to mark all other nodes as dirty but because nodes with
-// measure functions
-// depends on information not known to YG they must perform this dirty
-// marking manually.
-WIN_EXPORT void YGNodeMarkDirty(const YGNodeRef node);
-WIN_EXPORT bool YGNodeIsDirty(const YGNodeRef node);
-
-WIN_EXPORT void YGNodePrint(const YGNodeRef node, const YGPrintOptions options);
-
-WIN_EXPORT bool YGFloatIsUndefined(const float value);
-
-WIN_EXPORT bool YGNodeCanUseCachedMeasurement(const YGMeasureMode widthMode,
-                                              const float width,
-                                              const YGMeasureMode heightMode,
-                                              const float height,
-                                              const YGMeasureMode lastWidthMode,
-                                              const float lastWidth,
-                                              const YGMeasureMode lastHeightMode,
-                                              const float lastHeight,
-                                              const float lastComputedWidth,
-                                              const float lastComputedHeight,
-                                              const float marginRow,
-                                              const float marginColumn,
-                                              const YGConfigRef config);
-
-WIN_EXPORT void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode);
-
-#define YG_NODE_PROPERTY(type, name, paramName)                          \
-  WIN_EXPORT void YGNodeSet##name(const YGNodeRef node, type paramName); \
-  WIN_EXPORT type YGNodeGet##name(const YGNodeRef node);
-
-#define YG_NODE_STYLE_PROPERTY(type, name, paramName)                               \
-  WIN_EXPORT void YGNodeStyleSet##name(const YGNodeRef node, const type paramName); \
-  WIN_EXPORT type YGNodeStyleGet##name(const YGNodeRef node);
-
-#define YG_NODE_STYLE_PROPERTY_UNIT(type, name, paramName)                                    \
-  WIN_EXPORT void YGNodeStyleSet##name(const YGNodeRef node, const float paramName);          \
-  WIN_EXPORT void YGNodeStyleSet##name##Percent(const YGNodeRef node, const float paramName); \
-  WIN_EXPORT type YGNodeStyleGet##name(const YGNodeRef node);
-
-#define YG_NODE_STYLE_PROPERTY_UNIT_AUTO(type, name, paramName) \
-  YG_NODE_STYLE_PROPERTY_UNIT(type, name, paramName)            \
-  WIN_EXPORT void YGNodeStyleSet##name##Auto(const YGNodeRef node);
-
-#define YG_NODE_STYLE_EDGE_PROPERTY(type, name, paramName)    \
-  WIN_EXPORT void YGNodeStyleSet##name(const YGNodeRef node,  \
-                                       const YGEdge edge,     \
-                                       const type paramName); \
-  WIN_EXPORT type YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge);
-
-#define YG_NODE_STYLE_EDGE_PROPERTY_UNIT(type, name, paramName)         \
-  WIN_EXPORT void YGNodeStyleSet##name(const YGNodeRef node,            \
-                                       const YGEdge edge,               \
-                                       const float paramName);          \
-  WIN_EXPORT void YGNodeStyleSet##name##Percent(const YGNodeRef node,   \
-                                                const YGEdge edge,      \
-                                                const float paramName); \
-  WIN_EXPORT WIN_STRUCT(type) YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge);
-
-#define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO(type, name) \
-  WIN_EXPORT void YGNodeStyleSet##name##Auto(const YGNodeRef node, const YGEdge edge);
-
-#define YG_NODE_LAYOUT_PROPERTY(type, name) \
-  WIN_EXPORT type YGNodeLayoutGet##name(const YGNodeRef node);
-
-#define YG_NODE_LAYOUT_EDGE_PROPERTY(type, name) \
-  WIN_EXPORT type YGNodeLayoutGet##name(const YGNodeRef node, const YGEdge edge);
-
-YG_NODE_PROPERTY(void *, Context, context);
-YG_NODE_PROPERTY(YGMeasureFunc, MeasureFunc, measureFunc);
-YG_NODE_PROPERTY(YGBaselineFunc, BaselineFunc, baselineFunc)
-YG_NODE_PROPERTY(YGPrintFunc, PrintFunc, printFunc);
-YG_NODE_PROPERTY(bool, HasNewLayout, hasNewLayout);
-YG_NODE_PROPERTY(YGNodeType, NodeType, nodeType);
-
-YG_NODE_STYLE_PROPERTY(YGDirection, Direction, direction);
-YG_NODE_STYLE_PROPERTY(YGFlexDirection, FlexDirection, flexDirection);
-YG_NODE_STYLE_PROPERTY(YGJustify, JustifyContent, justifyContent);
-YG_NODE_STYLE_PROPERTY(YGAlign, AlignContent, alignContent);
-YG_NODE_STYLE_PROPERTY(YGAlign, AlignItems, alignItems);
-YG_NODE_STYLE_PROPERTY(YGAlign, AlignSelf, alignSelf);
-YG_NODE_STYLE_PROPERTY(YGPositionType, PositionType, positionType);
-YG_NODE_STYLE_PROPERTY(YGWrap, FlexWrap, flexWrap);
-YG_NODE_STYLE_PROPERTY(YGOverflow, Overflow, overflow);
-YG_NODE_STYLE_PROPERTY(YGDisplay, Display, display);
-
-YG_NODE_STYLE_PROPERTY(float, Flex, flex);
-YG_NODE_STYLE_PROPERTY(float, FlexGrow, flexGrow);
-YG_NODE_STYLE_PROPERTY(float, FlexShrink, flexShrink);
-YG_NODE_STYLE_PROPERTY_UNIT_AUTO(YGValue, FlexBasis, flexBasis);
-
-YG_NODE_STYLE_EDGE_PROPERTY_UNIT(YGValue, Position, position);
-YG_NODE_STYLE_EDGE_PROPERTY_UNIT(YGValue, Margin, margin);
-YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO(YGValue, Margin);
-YG_NODE_STYLE_EDGE_PROPERTY_UNIT(YGValue, Padding, padding);
-YG_NODE_STYLE_EDGE_PROPERTY(float, Border, border);
-
-YG_NODE_STYLE_PROPERTY_UNIT_AUTO(YGValue, Width, width);
-YG_NODE_STYLE_PROPERTY_UNIT_AUTO(YGValue, Height, height);
-YG_NODE_STYLE_PROPERTY_UNIT(YGValue, MinWidth, minWidth);
-YG_NODE_STYLE_PROPERTY_UNIT(YGValue, MinHeight, minHeight);
-YG_NODE_STYLE_PROPERTY_UNIT(YGValue, MaxWidth, maxWidth);
-YG_NODE_STYLE_PROPERTY_UNIT(YGValue, MaxHeight, maxHeight);
-
-// Yoga specific properties, not compatible with flexbox specification
-// Aspect ratio control the size of the undefined dimension of a node.
-// Aspect ratio is encoded as a floating point value width/height. e.g. A value of 2 leads to a node
-// with a width twice the size of its height while a value of 0.5 gives the opposite effect.
-//
-// - On a node with a set width/height aspect ratio control the size of the unset dimension
-// - On a node with a set flex basis aspect ratio controls the size of the node in the cross axis if
-// unset
-// - On a node with a measure function aspect ratio works as though the measure function measures
-// the flex basis
-// - On a node with flex grow/shrink aspect ratio controls the size of the node in the cross axis if
-// unset
-// - Aspect ratio takes min/max dimensions into account
-YG_NODE_STYLE_PROPERTY(float, AspectRatio, aspectRatio);
-
-YG_NODE_LAYOUT_PROPERTY(float, Left);
-YG_NODE_LAYOUT_PROPERTY(float, Top);
-YG_NODE_LAYOUT_PROPERTY(float, Right);
-YG_NODE_LAYOUT_PROPERTY(float, Bottom);
-YG_NODE_LAYOUT_PROPERTY(float, Width);
-YG_NODE_LAYOUT_PROPERTY(float, Height);
-YG_NODE_LAYOUT_PROPERTY(YGDirection, Direction);
-YG_NODE_LAYOUT_PROPERTY(bool, HadOverflow);
-
-// Get the computed values for these nodes after performing layout. If they were set using
-// point values then the returned value will be the same as YGNodeStyleGetXXX. However if
-// they were set using a percentage value then the returned value is the computed value used
-// during layout.
-YG_NODE_LAYOUT_EDGE_PROPERTY(float, Margin);
-YG_NODE_LAYOUT_EDGE_PROPERTY(float, Border);
-YG_NODE_LAYOUT_EDGE_PROPERTY(float, Padding);
-
-WIN_EXPORT void YGConfigSetLogger(const YGConfigRef config, YGLogger logger);
-WIN_EXPORT void YGLog(const YGNodeRef node, YGLogLevel level, const char *message, ...);
-WIN_EXPORT void YGLogWithConfig(const YGConfigRef config, YGLogLevel level, const char *format, ...);
-WIN_EXPORT void YGAssert(const bool condition, const char *message);
-WIN_EXPORT void YGAssertWithNode(const YGNodeRef node, const bool condition, const char *message);
-WIN_EXPORT void YGAssertWithConfig(const YGConfigRef config,
-                                   const bool condition,
-                                   const char *message);
-
-// Set this to number of pixels in 1 point to round calculation results
-// If you want to avoid rounding - set PointScaleFactor to 0
-WIN_EXPORT void YGConfigSetPointScaleFactor(const YGConfigRef config, const float pixelsInPoint);
-
-// Yoga previously had an error where containers would take the maximum space possible instead of
-// the minimum
-// like they are supposed to. In practice this resulted in implicit behaviour similar to align-self:
-// stretch;
-// Because this was such a long-standing bug we must allow legacy users to switch back to this
-// behaviour.
-WIN_EXPORT void YGConfigSetUseLegacyStretchBehaviour(const YGConfigRef config,
-                                                     const bool useLegacyStretchBehaviour);
-
-// YGConfig
-WIN_EXPORT YGConfigRef YGConfigNew(void);
-WIN_EXPORT void YGConfigFree(const YGConfigRef config);
-WIN_EXPORT void YGConfigCopy(const YGConfigRef dest, const YGConfigRef src);
-WIN_EXPORT int32_t YGConfigGetInstanceCount(void);
-
-WIN_EXPORT void YGConfigSetExperimentalFeatureEnabled(const YGConfigRef config,
-                                                      const YGExperimentalFeature feature,
-                                                      const bool enabled);
-WIN_EXPORT bool YGConfigIsExperimentalFeatureEnabled(const YGConfigRef config,
-                                                     const YGExperimentalFeature feature);
-
-// Using the web defaults is the prefered configuration for new projects.
-// Usage of non web defaults should be considered as legacy.
-WIN_EXPORT void YGConfigSetUseWebDefaults(const YGConfigRef config, const bool enabled);
-WIN_EXPORT bool YGConfigGetUseWebDefaults(const YGConfigRef config);
-
-WIN_EXPORT void YGConfigSetNodeClonedFunc(const YGConfigRef config,
-                                          const YGNodeClonedFunc callback);
-
-// Export only for C#
-WIN_EXPORT YGConfigRef YGConfigGetDefault(void);
-
-WIN_EXPORT void YGConfigSetContext(const YGConfigRef config, void *context);
-WIN_EXPORT void *YGConfigGetContext(const YGConfigRef config);
-
-WIN_EXPORT float YGRoundValueToPixelGrid(
-    const float value,
-    const float pointScaleFactor,
-    const bool forceCeil,
-    const bool forceFloor);
-
-YG_EXTERN_C_END
+/*
+ *  Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ *  This source code is licensed under the MIT license found in the LICENSE
+ *  file in the root directory of this source tree.
+ *
+ */
+#pragma once
+
+#include <assert.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+/** Large positive number signifies that the property(float) is undefined.
+ *Earlier we used to have YGundefined as NAN, but the downside of this is that
+ *we can't use -ffast-math compiler flag as it assumes all floating-point
+ *calculation involve and result into finite numbers. For more information
+ *regarding -ffast-math compiler flag in clang, have a look at
+ *https://clang.llvm.org/docs/UsersManual.html#cmdoption-ffast-math
+ **/
+#define YGUndefined 10E20F
+
+#include "YGEnums.h"
+#include "YGMacros.h"
+
+YG_EXTERN_C_BEGIN
+
+typedef struct YGSize {
+  float width;
+  float height;
+} YGSize;
+
+typedef struct YGValue {
+  float value;
+  YGUnit unit;
+} YGValue;
+
+extern const YGValue YGValueUndefined;
+extern const YGValue YGValueAuto;
+
+#ifdef __cplusplus
+
+extern bool operator==(const YGValue& lhs, const YGValue& rhs);
+extern bool operator!=(const YGValue& lhs, const YGValue& rhs);
+
+#endif
+
+typedef struct YGConfig* YGConfigRef;
+
+typedef struct YGNode* YGNodeRef;
+
+typedef YGSize (*YGMeasureFunc)(
+    YGNodeRef node,
+    float width,
+    YGMeasureMode widthMode,
+    float height,
+    YGMeasureMode heightMode);
+typedef float (
+    *YGBaselineFunc)(YGNodeRef node, const float width, const float height);
+typedef void (*YGDirtiedFunc)(YGNodeRef node);
+typedef void (*YGPrintFunc)(YGNodeRef node);
+typedef int (*YGLogger)(
+    const YGConfigRef config,
+    const YGNodeRef node,
+    YGLogLevel level,
+    const char* format,
+    va_list args);
+typedef YGNodeRef (
+    *YGCloneNodeFunc)(YGNodeRef oldNode, YGNodeRef owner, int childIndex);
+
+// YGNode
+WIN_EXPORT YGNodeRef YGNodeNew(void);
+WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config);
+WIN_EXPORT YGNodeRef YGNodeClone(const YGNodeRef node);
+WIN_EXPORT void YGNodeFree(const YGNodeRef node);
+WIN_EXPORT void YGNodeFreeRecursive(const YGNodeRef node);
+WIN_EXPORT void YGNodeReset(const YGNodeRef node);
+WIN_EXPORT int32_t YGNodeGetInstanceCount(void);
+
+WIN_EXPORT void YGNodeInsertChild(
+    const YGNodeRef node,
+    const YGNodeRef child,
+    const uint32_t index);
+
+// This function inserts the child YGNodeRef as a children of the node received
+// by parameter and set the Owner of the child object to null. This function is
+// expected to be called when using Yoga in persistent mode in order to share a
+// YGNodeRef object as a child of two different Yoga trees. The child YGNodeRef
+// is expected to be referenced from its original owner and from a clone of its
+// original owner.
+WIN_EXPORT void YGNodeInsertSharedChild(
+    const YGNodeRef node,
+    const YGNodeRef child,
+    const uint32_t index);
+WIN_EXPORT void YGNodeRemoveChild(const YGNodeRef node, const YGNodeRef child);
+WIN_EXPORT void YGNodeRemoveAllChildren(const YGNodeRef node);
+WIN_EXPORT YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index);
+WIN_EXPORT YGNodeRef YGNodeGetOwner(const YGNodeRef node);
+WIN_EXPORT YGNodeRef YGNodeGetParent(const YGNodeRef node);
+WIN_EXPORT uint32_t YGNodeGetChildCount(const YGNodeRef node);
+WIN_EXPORT void YGNodeSetChildren(
+    YGNodeRef const owner,
+    const YGNodeRef children[],
+    const uint32_t count);
+
+WIN_EXPORT void YGNodeCalculateLayout(
+    const YGNodeRef node,
+    const float availableWidth,
+    const float availableHeight,
+    const YGDirection ownerDirection);
+
+// Mark a node as dirty. Only valid for nodes with a custom measure function
+// set.
+// YG knows when to mark all other nodes as dirty but because nodes with
+// measure functions
+// depends on information not known to YG they must perform this dirty
+// marking manually.
+WIN_EXPORT void YGNodeMarkDirty(const YGNodeRef node);
+
+// This function marks the current node and all its descendants as dirty. This
+// function is added to test yoga benchmarks. This function is not expected to
+// be used in production as calling `YGCalculateLayout` will cause the
+// recalculation of each and every node.
+WIN_EXPORT void YGNodeMarkDirtyAndPropogateToDescendants(const YGNodeRef node);
+
+WIN_EXPORT void YGNodePrint(const YGNodeRef node, const YGPrintOptions options);
+
+WIN_EXPORT bool YGFloatIsUndefined(const float value);
+
+WIN_EXPORT bool YGNodeCanUseCachedMeasurement(
+    const YGMeasureMode widthMode,
+    const float width,
+    const YGMeasureMode heightMode,
+    const float height,
+    const YGMeasureMode lastWidthMode,
+    const float lastWidth,
+    const YGMeasureMode lastHeightMode,
+    const float lastHeight,
+    const float lastComputedWidth,
+    const float lastComputedHeight,
+    const float marginRow,
+    const float marginColumn,
+    const YGConfigRef config);
+
+WIN_EXPORT void YGNodeCopyStyle(
+    const YGNodeRef dstNode,
+    const YGNodeRef srcNode);
+
+WIN_EXPORT void* YGNodeGetContext(YGNodeRef node);
+WIN_EXPORT void YGNodeSetContext(YGNodeRef node, void* context);
+void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled);
+YGMeasureFunc YGNodeGetMeasureFunc(YGNodeRef node);
+WIN_EXPORT void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc);
+YGBaselineFunc YGNodeGetBaselineFunc(YGNodeRef node);
+void YGNodeSetBaselineFunc(YGNodeRef node, YGBaselineFunc baselineFunc);
+YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeRef node);
+void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc);
+YGPrintFunc YGNodeGetPrintFunc(YGNodeRef node);
+void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc);
+bool YGNodeGetHasNewLayout(YGNodeRef node);
+void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout);
+YGNodeType YGNodeGetNodeType(YGNodeRef node);
+void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType);
+bool YGNodeIsDirty(YGNodeRef node);
+bool YGNodeLayoutGetDidUseLegacyFlag(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetDirection(
+    const YGNodeRef node,
+    const YGDirection direction);
+WIN_EXPORT YGDirection YGNodeStyleGetDirection(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetFlexDirection(
+    const YGNodeRef node,
+    const YGFlexDirection flexDirection);
+WIN_EXPORT YGFlexDirection YGNodeStyleGetFlexDirection(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetJustifyContent(
+    const YGNodeRef node,
+    const YGJustify justifyContent);
+WIN_EXPORT YGJustify YGNodeStyleGetJustifyContent(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetAlignContent(
+    const YGNodeRef node,
+    const YGAlign alignContent);
+WIN_EXPORT YGAlign YGNodeStyleGetAlignContent(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetAlignItems(
+    const YGNodeRef node,
+    const YGAlign alignItems);
+WIN_EXPORT YGAlign YGNodeStyleGetAlignItems(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetAlignSelf(
+    const YGNodeRef node,
+    const YGAlign alignSelf);
+WIN_EXPORT YGAlign YGNodeStyleGetAlignSelf(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetPositionType(
+    const YGNodeRef node,
+    const YGPositionType positionType);
+WIN_EXPORT YGPositionType YGNodeStyleGetPositionType(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetFlexWrap(
+    const YGNodeRef node,
+    const YGWrap flexWrap);
+WIN_EXPORT YGWrap YGNodeStyleGetFlexWrap(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetOverflow(
+    const YGNodeRef node,
+    const YGOverflow overflow);
+WIN_EXPORT YGOverflow YGNodeStyleGetOverflow(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetDisplay(
+    const YGNodeRef node,
+    const YGDisplay display);
+WIN_EXPORT YGDisplay YGNodeStyleGetDisplay(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetFlex(const YGNodeRef node, const float flex);
+WIN_EXPORT float YGNodeStyleGetFlex(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetFlexGrow(
+    const YGNodeRef node,
+    const float flexGrow);
+WIN_EXPORT float YGNodeStyleGetFlexGrow(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetFlexShrink(
+    const YGNodeRef node,
+    const float flexShrink);
+WIN_EXPORT float YGNodeStyleGetFlexShrink(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetFlexBasis(
+    const YGNodeRef node,
+    const float flexBasis);
+WIN_EXPORT void YGNodeStyleSetFlexBasisPercent(
+    const YGNodeRef node,
+    const float flexBasis);
+WIN_EXPORT void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node);
+WIN_EXPORT YGValue YGNodeStyleGetFlexBasis(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetPosition(
+    const YGNodeRef node,
+    const YGEdge edge,
+    const float position);
+WIN_EXPORT void YGNodeStyleSetPositionPercent(
+    const YGNodeRef node,
+    const YGEdge edge,
+    const float position);
+WIN_EXPORT WIN_STRUCT(YGValue)
+    YGNodeStyleGetPosition(const YGNodeRef node, const YGEdge edge);
+
+WIN_EXPORT void YGNodeStyleSetMargin(
+    const YGNodeRef node,
+    const YGEdge edge,
+    const float margin);
+WIN_EXPORT void YGNodeStyleSetMarginPercent(
+    const YGNodeRef node,
+    const YGEdge edge,
+    const float margin);
+WIN_EXPORT void YGNodeStyleSetMarginAuto(
+    const YGNodeRef node,
+    const YGEdge edge);
+WIN_EXPORT YGValue
+YGNodeStyleGetMargin(const YGNodeRef node, const YGEdge edge);
+
+WIN_EXPORT void YGNodeStyleSetPadding(
+    const YGNodeRef node,
+    const YGEdge edge,
+    const float padding);
+WIN_EXPORT void YGNodeStyleSetPaddingPercent(
+    const YGNodeRef node,
+    const YGEdge edge,
+    const float padding);
+WIN_EXPORT YGValue
+YGNodeStyleGetPadding(const YGNodeRef node, const YGEdge edge);
+
+WIN_EXPORT void YGNodeStyleSetBorder(
+    const YGNodeRef node,
+    const YGEdge edge,
+    const float border);
+WIN_EXPORT float YGNodeStyleGetBorder(const YGNodeRef node, const YGEdge edge);
+
+WIN_EXPORT void YGNodeStyleSetWidth(const YGNodeRef node, const float width);
+WIN_EXPORT void YGNodeStyleSetWidthPercent(
+    const YGNodeRef node,
+    const float width);
+WIN_EXPORT void YGNodeStyleSetWidthAuto(const YGNodeRef node);
+WIN_EXPORT YGValue YGNodeStyleGetWidth(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetHeight(const YGNodeRef node, const float height);
+WIN_EXPORT void YGNodeStyleSetHeightPercent(
+    const YGNodeRef node,
+    const float height);
+WIN_EXPORT void YGNodeStyleSetHeightAuto(const YGNodeRef node);
+WIN_EXPORT YGValue YGNodeStyleGetHeight(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetMinWidth(
+    const YGNodeRef node,
+    const float minWidth);
+WIN_EXPORT void YGNodeStyleSetMinWidthPercent(
+    const YGNodeRef node,
+    const float minWidth);
+WIN_EXPORT YGValue YGNodeStyleGetMinWidth(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetMinHeight(
+    const YGNodeRef node,
+    const float minHeight);
+WIN_EXPORT void YGNodeStyleSetMinHeightPercent(
+    const YGNodeRef node,
+    const float minHeight);
+WIN_EXPORT YGValue YGNodeStyleGetMinHeight(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetMaxWidth(
+    const YGNodeRef node,
+    const float maxWidth);
+WIN_EXPORT void YGNodeStyleSetMaxWidthPercent(
+    const YGNodeRef node,
+    const float maxWidth);
+WIN_EXPORT YGValue YGNodeStyleGetMaxWidth(const YGNodeRef node);
+
+WIN_EXPORT void YGNodeStyleSetMaxHeight(
+    const YGNodeRef node,
+    const float maxHeight);
+WIN_EXPORT void YGNodeStyleSetMaxHeightPercent(
+    const YGNodeRef node,
+    const float maxHeight);
+WIN_EXPORT YGValue YGNodeStyleGetMaxHeight(const YGNodeRef node);
+
+// Yoga specific properties, not compatible with flexbox specification
+// Aspect ratio control the size of the undefined dimension of a node.
+// Aspect ratio is encoded as a floating point value width/height. e.g. A value
+// of 2 leads to a node with a width twice the size of its height while a value
+// of 0.5 gives the opposite effect.
+//
+// - On a node with a set width/height aspect ratio control the size of the
+// unset dimension
+// - On a node with a set flex basis aspect ratio controls the size of the node
+// in the cross axis if unset
+// - On a node with a measure function aspect ratio works as though the measure
+// function measures the flex basis
+// - On a node with flex grow/shrink aspect ratio controls the size of the node
+// in the cross axis if unset
+// - Aspect ratio takes min/max dimensions into account
+WIN_EXPORT void YGNodeStyleSetAspectRatio(
+    const YGNodeRef node,
+    const float aspectRatio);
+WIN_EXPORT float YGNodeStyleGetAspectRatio(const YGNodeRef node);
+
+WIN_EXPORT float YGNodeLayoutGetLeft(const YGNodeRef node);
+WIN_EXPORT float YGNodeLayoutGetTop(const YGNodeRef node);
+WIN_EXPORT float YGNodeLayoutGetRight(const YGNodeRef node);
+WIN_EXPORT float YGNodeLayoutGetBottom(const YGNodeRef node);
+WIN_EXPORT float YGNodeLayoutGetWidth(const YGNodeRef node);
+WIN_EXPORT float YGNodeLayoutGetHeight(const YGNodeRef node);
+WIN_EXPORT YGDirection YGNodeLayoutGetDirection(const YGNodeRef node);
+WIN_EXPORT bool YGNodeLayoutGetHadOverflow(const YGNodeRef node);
+bool YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(const YGNodeRef node);
+
+// Get the computed values for these nodes after performing layout. If they were
+// set using point values then the returned value will be the same as
+// YGNodeStyleGetXXX. However if they were set using a percentage value then the
+// returned value is the computed value used during layout.
+WIN_EXPORT float YGNodeLayoutGetMargin(const YGNodeRef node, const YGEdge edge);
+WIN_EXPORT float YGNodeLayoutGetBorder(const YGNodeRef node, const YGEdge edge);
+WIN_EXPORT float YGNodeLayoutGetPadding(
+    const YGNodeRef node,
+    const YGEdge edge);
+
+WIN_EXPORT void YGConfigSetLogger(const YGConfigRef config, YGLogger logger);
+WIN_EXPORT void
+YGLog(const YGNodeRef node, YGLogLevel level, const char* message, ...);
+WIN_EXPORT void YGLogWithConfig(
+    const YGConfigRef config,
+    YGLogLevel level,
+    const char* format,
+    ...);
+WIN_EXPORT void YGAssert(const bool condition, const char* message);
+WIN_EXPORT void YGAssertWithNode(
+    const YGNodeRef node,
+    const bool condition,
+    const char* message);
+WIN_EXPORT void YGAssertWithConfig(
+    const YGConfigRef config,
+    const bool condition,
+    const char* message);
+// Set this to number of pixels in 1 point to round calculation results
+// If you want to avoid rounding - set PointScaleFactor to 0
+WIN_EXPORT void YGConfigSetPointScaleFactor(
+    const YGConfigRef config,
+    const float pixelsInPoint);
+void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(
+    const YGConfigRef config,
+    const bool shouldDiffLayout);
+
+// Yoga previously had an error where containers would take the maximum space
+// possible instead of the minimum like they are supposed to. In practice this
+// resulted in implicit behaviour similar to align-self: stretch; Because this
+// was such a long-standing bug we must allow legacy users to switch back to
+// this behaviour.
+WIN_EXPORT void YGConfigSetUseLegacyStretchBehaviour(
+    const YGConfigRef config,
+    const bool useLegacyStretchBehaviour);
+
+// YGConfig
+WIN_EXPORT YGConfigRef YGConfigNew(void);
+WIN_EXPORT void YGConfigFree(const YGConfigRef config);
+WIN_EXPORT void YGConfigCopy(const YGConfigRef dest, const YGConfigRef src);
+WIN_EXPORT int32_t YGConfigGetInstanceCount(void);
+
+WIN_EXPORT void YGConfigSetExperimentalFeatureEnabled(
+    const YGConfigRef config,
+    const YGExperimentalFeature feature,
+    const bool enabled);
+WIN_EXPORT bool YGConfigIsExperimentalFeatureEnabled(
+    const YGConfigRef config,
+    const YGExperimentalFeature feature);
+
+// Using the web defaults is the prefered configuration for new projects.
+// Usage of non web defaults should be considered as legacy.
+WIN_EXPORT void YGConfigSetUseWebDefaults(
+    const YGConfigRef config,
+    const bool enabled);
+WIN_EXPORT bool YGConfigGetUseWebDefaults(const YGConfigRef config);
+
+WIN_EXPORT void YGConfigSetCloneNodeFunc(
+    const YGConfigRef config,
+    const YGCloneNodeFunc callback);
+
+// Export only for C#
+WIN_EXPORT YGConfigRef YGConfigGetDefault(void);
+
+WIN_EXPORT void YGConfigSetContext(const YGConfigRef config, void* context);
+WIN_EXPORT void* YGConfigGetContext(const YGConfigRef config);
+
+WIN_EXPORT float YGRoundValueToPixelGrid(
+    const float value,
+    const float pointScaleFactor,
+    const bool forceCeil,
+    const bool forceFloor);
+
+YG_EXTERN_C_END
+
+#ifdef __cplusplus
+
+#include <functional>
+#include <vector>
+
+// Calls f on each node in the tree including the given node argument.
+extern void YGTraversePreOrder(
+    YGNodeRef const node,
+    std::function<void(YGNodeRef node)>&& f);
+
+extern void YGNodeSetChildren(
+    YGNodeRef const owner,
+    const std::vector<YGNodeRef>& children);
+
+#endif
