packages feed

yoga 0.0.0.5 → 0.0.0.7

raw patch · 102 files changed

+11510/−7964 lines, 102 filesdep +hspecdep +hspec-discoverdep ~basesetup-changed

Dependencies added: hspec, hspec-discover

Dependency ranges changed: base

Files

LICENSE view
@@ -1,12 +1,12 @@-Copyright (c) 2016-present, Pavel Krajcevski-All rights reserved.--Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:--1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.--2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.--3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.-+Copyright (c) 2016-present, Pavel Krajcevski
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Setup.hs view
@@ -1,2 +1,2 @@-import Distribution.Simple-main = defaultMain+import Distribution.Simple
+main = defaultMain
examples/Main.hs view
@@ -1,28 +1,27 @@-module Main where-----------------------------------------------------------------------------------import qualified Yoga as Yoga-----------------------------------------------------------------------------------block :: Int -> Yoga.Layout Int-block = Yoga.exact 100.0 100.0--renderIntFn :: Yoga.LayoutInfo -> Int -> IO String-renderIntFn info x = do-  putStr $ concat ["Node ", show x, ": "]-  print info-  return ""--main :: IO ()-main = do-  let cs = [ block y | y <- [6..9]]-      cs2 = take 4 $ repeat $ Yoga.withPadding Yoga.Edge'Left 10.0 block 23-      mkHbox = Yoga.hbox . Yoga.startToEnd-  let tree =-        flip Yoga.vbox 3 $-        Yoga.startToEnd [-          mkHbox cs 0,-          ($ 1) (Yoga.withMargin Yoga.Edge'Top 10.0 $ mkHbox cs),-          mkHbox cs2 2]-  _ <- Yoga.render tree renderIntFn-  return ()+module Main where
+
+--------------------------------------------------------------------------------
+import qualified Yoga
+--------------------------------------------------------------------------------
+
+block :: Int -> Yoga.Layout Int
+block = Yoga.exact 100.0 100.0
+
+renderIntFn :: Yoga.LayoutInfo -> Int -> IO ()
+renderIntFn info x = do
+  putStr $ concat ["Node ", show x, ": "]
+  print info
+
+main :: IO ()
+main = do
+  let cs = [ block y | y <- [6..9]]
+      cs2 = replicate 4 $ Yoga.setPadding Yoga.Edge'Left 10.0 (block 23)
+      mkHbox = Yoga.hbox . Yoga.startToEnd
+  let tree =
+        flip Yoga.vbox 3 $
+        Yoga.startToEnd [
+          mkHbox cs 0,
+          Yoga.setMargin Yoga.Edge'Top 10.0 $ mkHbox cs 1,
+          mkHbox cs2 2]
+  _ <- Yoga.render tree renderIntFn
+  return ()
lib/Bindings/Yoga.hsc view
@@ -1,174 +1,282 @@-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE NoImplicitPrelude  #-}-{-# LANGUAGE StandaloneDeriving #-}-----------------------------------------------------------------------------------#include <Yoga.h>-#include <bindings.dsl.h>------------------------------------------------------------------------------------module Bindings.Yoga where--import Data.Data        (Data)-import Data.Typeable    (Typeable)-import Foreign.C.Types  (CFloat(..), CInt(..), CUInt(..))-import Foreign.Ptr      (FunPtr, Ptr, plusPtr)-import Foreign.Storable (Storable(..))--import Prelude (Eq, IO, Show)-import Prelude (($), return)-----------------------------------------------------------------------------------#starttype struct YGSize-#field width       , CFloat-#field height      , CFloat-#stoptype-deriving instance Typeable C'YGSize--#opaque_t YGNode-deriving instance Typeable C'YGNode-deriving instance Data     C'YGNode--#callback_t YGMeasureFunc, Ptr <YGNode> -> CFloat -> CInt -> CFloat -> CInt -> IO (Ptr <YGSize>)--#callback_t YGPrintFunc, Ptr <YGNode> -> IO ()-{---typedef int (*YGLogger)(YGLogLevel level, const char *format, va_list args);-WIN_EXPORT void YGSetLogger(YGLogger logger);-WIN_EXPORT void YGLog(YGLogLevel level, const char *message, ...);--typedef void *(*YGMalloc)(size_t size);-typedef void *(*YGCalloc)(size_t count, size_t size);-typedef void *(*YGRealloc)(void *ptr, size_t size);-typedef void (*YGFree)(void *ptr);-WIN_EXPORT void-YGSetMemoryFuncs(YGMalloc ygmalloc, YGCalloc yccalloc, YGRealloc ygrealloc, YGFree ygfree);--}--#ccall YGNodeNew, IO (Ptr <YGNode>)-#ccall YGNodeClone, Ptr <YGNode> -> IO (Ptr <YGNode>)-#ccall YGNodeFree, Ptr <YGNode> -> IO ()-#ccall YGNodeFreeRecursive, Ptr <YGNode> -> IO ()-#ccall YGNodeReset, Ptr <YGNode> -> IO ()-#ccall YGNodeGetInstanceCount, IO (CInt)--#ccall YGNodeInsertChild, Ptr <YGNode> -> Ptr <YGNode> -> CUInt -> IO ()-#ccall YGNodeRemoveChild, Ptr <YGNode> -> Ptr <YGNode> -> IO ()-#ccall YGNodeRemoveAllChildren, Ptr <YGNode> -> IO ()-#ccall YGNodeGetChild, Ptr <YGNode> -> CUInt -> IO (Ptr <YGNode>)-#ccall YGNodeGetParent, Ptr <YGNode> -> IO (Ptr <YGNode>)-#ccall YGNodeGetChildCount, Ptr <YGNode> -> IO (CUInt)--#ccall YGNodeCalculateLayout, Ptr <YGNode> -> CFloat -> CFloat -> CInt -> IO ()---- 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.--#ccall YGNodeMarkDirty, Ptr <YGNode> -> IO ()-#ccall YGNodeIsDirty, Ptr <YGNode> -> IO CInt--#ccall YGNodePrint, Ptr <YGNode> -> CInt -> IO ()--#ccall YGNodeCanUseCachedMeasurement, CInt -> CFloat -> CInt -> CFloat -> CInt -> CFloat -> CInt -> CFloat -> CFloat -> CFloat -> CFloat -> CFloat -> IO CInt--#ccall YGNodeCopyStyle, Ptr <YGNode> -> Ptr <YGNode> -> IO ()--#ccall YGNodeSetContext, Ptr <YGNode> -> Ptr () -> IO ()-#ccall YGNodeGetContext, Ptr <YGNode> -> IO (Ptr ())--#ccall YGNodeSetMeasureFunc, Ptr <YGNode> -> Ptr <YGMeasureFunc> -> IO ()-#ccall YGNodeGetMeasureFunc, Ptr <YGNode> -> IO (Ptr <YGMeasureFunc>)--#ccall YGNodeSetPrintFunc, Ptr <YGNode> -> Ptr <YGPrintFunc> -> IO ()-#ccall YGNodeGetPrintFunc, Ptr <YGNode> -> IO (Ptr <YGPrintFunc>)--#ccall YGNodeSetHasNewLayout, Ptr <YGNode> -> CInt -> IO ()-#ccall YGNodeGetHasNewLayout, Ptr <YGNode> -> IO CInt--#ccall YGNodeStyleSetDirection, Ptr <YGNode> -> CInt -> IO ()-#ccall YGNodeStyleGetDirection, Ptr <YGNode> -> IO CInt--#ccall YGNodeStyleSetFlexDirection, Ptr <YGNode> -> CInt -> IO ()-#ccall YGNodeStyleGetFlexDirection, Ptr <YGNode> -> IO CInt--#ccall YGNodeStyleSetJustifyContent, Ptr <YGNode> -> CInt -> IO ()-#ccall YGNodeStyleGetJustifyContent, Ptr <YGNode> -> IO CInt--#ccall YGNodeStyleSetAlignContent, Ptr <YGNode> -> CInt -> IO ()-#ccall YGNodeStyleGetAlignContent, Ptr <YGNode> -> IO CInt--#ccall YGNodeStyleSetAlignItems, Ptr <YGNode> -> CInt -> IO ()-#ccall YGNodeStyleGetAlignItems, Ptr <YGNode> -> IO CInt--#ccall YGNodeStyleSetAlignSelf, Ptr <YGNode> -> CInt -> IO ()-#ccall YGNodeStyleGetAlignSelf, Ptr <YGNode> -> IO CInt--#ccall YGNodeStyleSetPositionType, Ptr <YGNode> -> CInt -> IO ()-#ccall YGNodeStyleGetPositionType, Ptr <YGNode> -> IO CInt--#ccall YGNodeStyleSetFlexWrap, Ptr <YGNode> -> CInt -> IO ()-#ccall YGNodeStyleGetFlexWrap, Ptr <YGNode> -> IO CInt--#ccall YGNodeStyleSetOverflow, Ptr <YGNode> -> CInt -> IO ()-#ccall YGNodeStyleGetOverflow, Ptr <YGNode> -> IO CInt--#ccall YGNodeStyleSetFlex, Ptr <YGNode> -> CFloat -> IO ()-#ccall YGNodeStyleSetFlexGrow, Ptr <YGNode> -> CFloat -> IO ()-#ccall YGNodeStyleGetFlexGrow, Ptr <YGNode> -> IO CFloat-#ccall YGNodeStyleSetFlexShrink, Ptr <YGNode> -> CFloat -> IO ()-#ccall YGNodeStyleGetFlexShrink, Ptr <YGNode> -> IO CFloat-#ccall YGNodeStyleSetFlexBasis, Ptr <YGNode> -> CFloat -> IO ()-#ccall YGNodeStyleGetFlexBasis, Ptr <YGNode> -> IO CFloat--#ccall YGNodeStyleSetPosition, Ptr <YGNode> -> CInt -> CFloat -> IO ()-#ccall YGNodeStyleGetPosition, Ptr <YGNode> -> CInt -> IO CFloat--#ccall YGNodeStyleSetMargin, Ptr <YGNode> -> CInt -> CFloat -> IO ()-#ccall YGNodeStyleGetMargin, Ptr <YGNode> -> CInt -> IO CFloat--#ccall YGNodeStyleSetPadding, Ptr <YGNode> -> CInt -> CFloat -> IO ()-#ccall YGNodeStyleGetPadding, Ptr <YGNode> -> CInt -> IO CFloat--#ccall YGNodeStyleSetBorder, Ptr <YGNode> -> CInt -> CFloat -> IO ()-#ccall YGNodeStyleGetBorder, Ptr <YGNode> -> CInt -> IO CFloat--#ccall YGNodeStyleSetWidth, Ptr <YGNode> -> CFloat -> IO ()-#ccall YGNodeStyleGetWidth, Ptr <YGNode> -> IO CFloat-#ccall YGNodeStyleSetHeight, Ptr <YGNode> -> CFloat -> IO ()-#ccall YGNodeStyleGetHeight, Ptr <YGNode> -> IO CFloat--#ccall YGNodeStyleSetMinWidth, Ptr <YGNode> -> CFloat -> IO ()-#ccall YGNodeStyleGetMinWidth, Ptr <YGNode> -> IO CFloat-#ccall YGNodeStyleSetMinHeight, Ptr <YGNode> -> CFloat -> IO ()-#ccall YGNodeStyleGetMinHeight, Ptr <YGNode> -> IO CFloat--#ccall YGNodeStyleSetMaxWidth, Ptr <YGNode> -> CFloat -> IO ()-#ccall YGNodeStyleGetMaxWidth, Ptr <YGNode> -> IO CFloat-#ccall YGNodeStyleSetMaxHeight, Ptr <YGNode> -> CFloat -> IO ()-#ccall YGNodeStyleGetMaxHeight, Ptr <YGNode> -> IO CFloat---- Yoga specific properties, not compatible with flexbox specification--- Aspect ratio control the size of the undefined dimension of a node.--- - 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-#ccall YGNodeStyleSetAspectRatio, Ptr <YGNode> -> CFloat -> IO ()-#ccall YGNodeStyleGetAspectRatio, Ptr <YGNode> -> IO CFloat--#ccall YGNodeLayoutGetLeft, Ptr <YGNode> -> IO CFloat-#ccall YGNodeLayoutGetTop, Ptr <YGNode> -> IO CFloat-#ccall YGNodeLayoutGetRight, Ptr <YGNode> -> IO CFloat-#ccall YGNodeLayoutGetBottom, Ptr <YGNode> -> IO CFloat-#ccall YGNodeLayoutGetWidth, Ptr <YGNode> -> IO CFloat-#ccall YGNodeLayoutGetHeight, Ptr <YGNode> -> IO CFloat-#ccall YGNodeLayoutGetDirection, Ptr <YGNode> -> IO CInt+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE NoImplicitPrelude  #-}
+{-# LANGUAGE StandaloneDeriving #-}
+--------------------------------------------------------------------------------
+
+#include <Yoga.h>
+#include <bindings.dsl.h>
+
+--------------------------------------------------------------------------------
+
+module Bindings.Yoga where
+
+import Data.Data        (Data)
+import Data.Typeable    (Typeable)
+import Foreign.C.Types  (CFloat(..), CInt(..), CUInt(..), CBool(..), CDouble(..))
+import Foreign.Ptr      (FunPtr, Ptr, plusPtr)
+import Foreign.Storable (Storable(..))
+
+import Prelude (Eq, IO, Show)
+import Prelude (($), return)
+
+import Bindings.Yoga.Enums
+--------------------------------------------------------------------------------
+
+#starttype struct YGSize
+#field width       , CFloat
+#field height      , CFloat
+#stoptype
+deriving instance Typeable C'YGSize
+
+#opaque_t YGConfig
+deriving instance Typeable C'YGConfig
+deriving instance Data     C'YGConfig
+
+#opaque_t YGNode
+deriving instance Typeable C'YGNode
+deriving instance Data     C'YGNode
+
+#starttype struct YGValue
+#field value , CFloat
+#field unit  , <YGUnit>
+#stoptype
+deriving instance Typeable C'YGValue
+
+#globalvar YGValueAuto      , <YGValue>
+#globalvar YGValueUndefined , <YGValue>
+#globalvar YGValueZero      , <YGValue>
+
+#callback_t YGMeasureFunc, Ptr <YGNode> -> CFloat -> <YGMeasureMode> -> CFloat -> <YGMeasureMode> -> IO (Ptr <YGSize>)
+#callback_t YGBaselineFunc, Ptr <YGNode> -> CFloat -> CFloat -> IO CFloat
+#callback_t YGDirtiedFunc, Ptr <YGNode> -> IO ()
+-- #callback_t YGPrintFunc, Ptr <YGNode> -> IO ()
+-- #callback_t YGLogger, Ptr <YGConfig> -> Ptr <YGNode> -> <YGLogLevel> -> CString -> <va_list> -> IO CInt
+#callback_t YGCloneNodeFunc, Ptr <YGNode> -> Ptr <YGNode> -> CInt -> IO (Ptr <YGNode>)
+
+#ccall YGNodeNew, IO (Ptr <YGNode>)
+#ccall YGNodeNewWithConfig, Ptr <YGConfig> -> IO (Ptr <YGNode>)
+#ccall YGNodeClone, Ptr <YGNode> -> IO (Ptr <YGNode>)
+#ccall YGNodeFree, Ptr <YGNode> -> IO ()
+#ccall YGNodeFreeRecursive, Ptr <YGNode> -> IO ()
+#ccall YGNodeFinalize, Ptr <YGNode> -> IO ()
+#ccall YGNodeReset, Ptr <YGNode> -> IO ()
+
+#ccall YGNodeGetHasNewLayout, Ptr <YGNode> -> IO CBool
+#ccall YGNodeSetHasNewLayout, Ptr <YGNode> -> CBool -> IO ()
+
+-- 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.
+#ccall YGNodeMarkDirty, Ptr <YGNode> -> IO ()
+#ccall YGNodeIsDirty, Ptr <YGNode> -> IO CBool
+#ccall YGNodeGetDirtiedFunc, Ptr <YGNode> -> IO <YGDirtiedFunc>
+#ccall YGNodeSetDirtiedFunc, Ptr <YGNode> -> <YGDirtiedFunc> -> IO ()
+
+#ccall YGNodeInsertChild, Ptr <YGNode> -> Ptr <YGNode> -> CUInt -> IO ()
+#ccall YGNodeSwapChild, Ptr <YGNode> -> Ptr <YGNode> -> CUInt -> IO ()
+
+#ccall YGNodeRemoveChild, Ptr <YGNode> -> Ptr <YGNode> -> IO ()
+#ccall YGNodeRemoveAllChildren, Ptr <YGNode> -> IO ()
+#ccall YGNodeGetChild, Ptr <YGNode> -> CUInt -> IO (Ptr <YGNode>)
+#ccall YGNodeGetOwner, Ptr <YGNode> -> IO (Ptr <YGNode>)
+#ccall YGNodeGetParent, Ptr <YGNode> -> IO (Ptr <YGNode>)
+#ccall YGNodeGetChildCount, Ptr <YGNode> -> IO CUInt
+#ccall YGNodeSetChildren, Ptr <YGNode> -> Ptr (Ptr <YGNode>) -> CUInt -> IO ()
+
+#ccall YGNodeSetConfig, Ptr <YGNode> -> Ptr <YGConfig> -> IO ()
+#ccall YGNodeGetConfig, Ptr <YGNode> -> IO (Ptr <YGConfig>)
+
+#ccall YGNodeSetContext, Ptr <YGNode> -> Ptr () -> IO ()
+#ccall YGNodeGetContext, Ptr <YGNode> -> IO (Ptr ())
+
+#ccall YGNodeHasMeasureFunc, Ptr <YGNode> -> IO CBool
+#ccall YGNodeSetMeasureFunc, Ptr <YGNode> -> Ptr <YGMeasureFunc> -> IO ()
+
+#ccall YGNodeHasBaselineFunc, Ptr <YGNode> -> IO CBool
+#ccall YGNodeSetBaselineFunc, Ptr <YGNode> -> <YGBaselineFunc> -> IO ()
+#ccall YGNodeSetIsReferenceBaseline, Ptr <YGNode> -> CBool -> IO ()
+#ccall YGNodeIsReferenceBaseline, Ptr <YGNode> -> IO CBool
+
+#ccall YGNodeGetNodeType, Ptr <YGNode> -> IO <YGNodeType>
+#ccall YGNodeSetNodeType, Ptr <YGNode> -> <YGNodeType> -> IO ()
+
+-- #indef NDEBUG
+-- #ccall YGNodeSetPrintFunc, Ptr <YGNode> -> Ptr <YGPrintFunc> -> IO ()
+-- #ccall YGNodePrint, Ptr <YGNode> -> <YGPrintOptions> -> IO ()
+
+#ccall YGNodeSetAlwaysFormsContainingBlock, Ptr <YGNode> -> CBool -> IO ()
+
+#ccall YGNodeCalculateLayout, Ptr <YGNode> -> CFloat -> CFloat -> <YGDirection> -> IO ()
+
+#ccall YGFloatIsUndefined, CFloat -> IO CBool
+
+#ccall YGNodeCopyStyle, Ptr <YGNode> -> Ptr <YGNode> -> IO ()
+
+#ccall YGNodeStyleSetDirection, Ptr <YGNode> -> <YGDirection> -> IO ()
+#ccall YGNodeStyleGetDirection, Ptr <YGNode> -> IO <YGDirection>
+
+#ccall YGNodeStyleSetFlexDirection, Ptr <YGNode> -> <YGFlexDirection> -> IO ()
+#ccall YGNodeStyleGetFlexDirection, Ptr <YGNode> -> IO <YGFlexDirection>
+
+#ccall YGNodeStyleSetJustifyContent, Ptr <YGNode> -> <YGJustify> -> IO ()
+#ccall YGNodeStyleGetJustifyContent, Ptr <YGNode> -> IO <YGJustify>
+
+#ccall YGNodeStyleSetAlignContent, Ptr <YGNode> -> <YGAlign> -> IO ()
+#ccall YGNodeStyleGetAlignContent, Ptr <YGNode> -> IO <YGAlign>
+
+#ccall YGNodeStyleSetAlignItems, Ptr <YGNode> -> <YGAlign> -> IO ()
+#ccall YGNodeStyleGetAlignItems, Ptr <YGNode> -> IO <YGAlign>
+
+#ccall YGNodeStyleSetAlignSelf, Ptr <YGNode> -> <YGAlign> -> IO ()
+#ccall YGNodeStyleGetAlignSelf, Ptr <YGNode> -> IO <YGAlign>
+
+#ccall YGNodeStyleSetPositionType, Ptr <YGNode> -> <YGPositionType> -> IO ()
+#ccall YGNodeStyleGetPositionType, Ptr <YGNode> -> IO <YGPositionType>
+
+#ccall YGNodeStyleSetFlexWrap, Ptr <YGNode> -> <YGWrap> -> IO ()
+#ccall YGNodeStyleGetFlexWrap, Ptr <YGNode> -> IO <YGWrap>
+
+#ccall YGNodeStyleSetOverflow, Ptr <YGNode> -> <YGOverflow> -> IO ()
+#ccall YGNodeStyleGetOverflow, Ptr <YGNode> -> IO <YGOverflow>
+
+#ccall YGNodeStyleSetDisplay, Ptr <YGNode> -> <YGDisplay> -> IO ()
+#ccall YGNodeStyleGetDisplay, Ptr <YGNode> -> IO <YGDisplay>
+
+#ccall YGNodeStyleSetFlex, Ptr <YGNode> -> CFloat -> IO ()
+#ccall YGNodeStyleGetFlex, Ptr <YGNode> -> IO CFloat
+
+#ccall YGNodeStyleSetFlexGrow, Ptr <YGNode> -> CFloat -> IO ()
+#ccall YGNodeStyleGetFlexGrow, Ptr <YGNode> -> IO CFloat
+
+#ccall YGNodeStyleSetFlexShrink, Ptr <YGNode> -> CFloat -> IO ()
+#ccall YGNodeStyleGetFlexShrink, Ptr <YGNode> -> IO CFloat
+
+#ccall YGNodeStyleSetFlexBasis, Ptr <YGNode> -> CFloat -> IO ()
+#ccall YGNodeStyleSetFlexBasisPercent, Ptr <YGNode> -> CFloat -> IO ()
+#ccall YGNodeStyleSetFlexBasisAuto, Ptr <YGNode> -> IO ()
+-- #ccall YGNodeStyleGetFlexBasis, Ptr <YGNode> -> IO <YGValue>
+#ccall YGNodeStyleGetFlexBasisWrapper, Ptr <YGNode> -> IO (Ptr <YGValue>)
+
+#ccall YGNodeStyleSetPosition, Ptr <YGNode> -> <YGEdge> -> CFloat -> IO ()
+#ccall YGNodeStyleSetPositionPercent, Ptr <YGNode> -> <YGEdge> -> CFloat -> IO ()
+-- #ccall YGNodeStyleGetPosition, Ptr <YGNode> -> <YGEdge> -> IO <YGValue>
+#ccall YGNodeStyleGetPositionWrapper, Ptr <YGNode> -> <YGEdge> -> IO (Ptr <YGValue>)
+
+#ccall YGNodeStyleSetMargin, Ptr <YGNode> -> <YGEdge> -> CFloat -> IO ()
+#ccall YGNodeStyleSetMarginPercent, Ptr <YGNode> -> <YGEdge> -> CFloat -> IO ()
+#ccall YGNodeStyleSetMarginAuto, Ptr <YGNode> -> <YGEdge> -> IO ()
+-- #ccall YGNodeStyleGetMargin, Ptr <YGNode> -> <YGEdge> -> IO <YGValue>
+#ccall YGNodeStyleGetMarginWrapper, Ptr <YGNode> -> <YGEdge> -> IO (Ptr <YGValue>)
+
+#ccall YGNodeStyleSetPadding, Ptr <YGNode> -> <YGEdge> -> CFloat -> IO ()
+#ccall YGNodeStyleSetPaddingPercent, Ptr <YGNode> -> <YGEdge> -> CFloat -> IO ()
+-- #ccall YGNodeStyleGetPadding, Ptr <YGNode> -> <YGEdge> -> IO <YGValue>
+#ccall YGNodeStyleGetPaddingWrapper, Ptr <YGNode> -> <YGEdge> -> IO (Ptr <YGValue>)
+
+#ccall YGNodeStyleSetBorder, Ptr <YGNode> -> <YGEdge> -> CFloat -> IO ()
+#ccall YGNodeStyleGetBorder, Ptr <YGNode> -> <YGEdge> -> IO CFloat
+
+#ccall YGNodeStyleSetGap, Ptr <YGNode> -> <YGGutter> -> CFloat -> IO ()
+#ccall YGNodeStyleGetGap, Ptr <YGNode> -> <YGGutter> -> IO CFloat
+
+#ccall YGNodeStyleSetWidth, Ptr <YGNode> -> CFloat -> IO ()
+#ccall YGNodeStyleSetWidthPercent, Ptr <YGNode> -> CFloat -> IO ()
+#ccall YGNodeStyleSetWidthAuto, Ptr <YGNode> -> IO ()
+-- #ccall YGNodeStyleGetWidth, Ptr <YGNode> -> IO <YGValue>
+#ccall YGNodeStyleGetWidthWrapper, Ptr <YGNode> -> IO (Ptr <YGValue>)
+
+#ccall YGNodeStyleSetHeight, Ptr <YGNode> -> CFloat -> IO ()
+#ccall YGNodeStyleSetHeightPercent, Ptr <YGNode> -> CFloat -> IO ()
+#ccall YGNodeStyleSetHeightAuto, Ptr <YGNode> -> IO ()
+-- #ccall YGNodeStyleGetHeight, Ptr <YGNode> -> IO <YGValue>
+#ccall YGNodeStyleGetHeightWrapper, Ptr <YGNode> -> IO (Ptr <YGValue>)
+
+#ccall YGNodeStyleSetMinWidth, Ptr <YGNode> -> CFloat -> IO ()
+#ccall YGNodeStyleSetMinWidthPercent, Ptr <YGNode> -> CFloat -> IO ()
+-- #ccall YGNodeStyleGetMinWidth, Ptr <YGNode> -> IO <YGValue>
+#ccall YGNodeStyleGetMinWidthWrapper, Ptr <YGNode> -> IO (Ptr <YGValue>)
+
+#ccall YGNodeStyleSetMinHeight, Ptr <YGNode> -> CFloat -> IO ()
+#ccall YGNodeStyleSetMinHeightPercent, Ptr <YGNode> -> CFloat -> IO ()
+-- #ccall YGNodeStyleGetMinHeight, Ptr <YGNode> -> IO <YGValue>
+#ccall YGNodeStyleGetMinHeightWrapper, Ptr <YGNode> -> IO (Ptr <YGValue>)
+
+#ccall YGNodeStyleSetMaxWidth, Ptr <YGNode> -> CFloat -> IO ()
+#ccall YGNodeStyleSetMaxWidthPercent, Ptr <YGNode> -> CFloat -> IO ()
+-- #ccall YGNodeStyleGetMaxWidth, Ptr <YGNode> -> IO <YGValue>
+#ccall YGNodeStyleGetMaxWidthWrapper, Ptr <YGNode> -> IO (Ptr <YGValue>)
+
+#ccall YGNodeStyleSetMaxHeight, Ptr <YGNode> -> CFloat -> IO ()
+#ccall YGNodeStyleSetMaxHeightPercent, Ptr <YGNode> -> CFloat -> IO ()
+-- #ccall YGNodeStyleGetMaxHeight, Ptr <YGNode> -> IO <YGValue>
+#ccall YGNodeStyleGetMaxHeightWrapper, Ptr <YGNode> -> IO (Ptr <YGValue>)
+
+-- YGValue wrapper
+#ccall YGValueFree, Ptr <YGValue> -> IO ()
+
+-- 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
+#ccall YGNodeStyleSetAspectRatio, Ptr <YGNode> -> CFloat -> IO ()
+#ccall YGNodeStyleGetAspectRatio, Ptr <YGNode> -> IO CFloat
+
+#ccall YGNodeLayoutGetLeft, Ptr <YGNode> -> IO CFloat
+#ccall YGNodeLayoutGetTop, Ptr <YGNode> -> IO CFloat
+#ccall YGNodeLayoutGetRight, Ptr <YGNode> -> IO CFloat
+#ccall YGNodeLayoutGetBottom, Ptr <YGNode> -> IO CFloat
+#ccall YGNodeLayoutGetWidth, Ptr <YGNode> -> IO CFloat
+#ccall YGNodeLayoutGetHeight, Ptr <YGNode> -> IO CFloat
+#ccall YGNodeLayoutGetDirection, Ptr <YGNode> -> IO <YGDirection>
+#ccall YGNodeLayoutGetHadOverflow, Ptr <YGNode> -> IO CBool
+
+-- 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.
+#ccall YGNodeLayoutGetMargin, Ptr <YGNode> -> <YGEdge> -> IO CFloat
+#ccall YGNodeLayoutGetBorder, Ptr <YGNode> -> <YGEdge> -> IO CFloat
+#ccall YGNodeLayoutGetPadding, Ptr <YGNode> -> <YGEdge> -> IO CFloat
+
+-- YGConfig
+#ccall YGConfigNew, IO (Ptr <YGConfig>)
+#ccall YGConfigFree, Ptr <YGConfig> -> IO ()
+#ccall YGConfigGetDefault, IO (Ptr <YGConfig>)
+
+#ccall YGConfigSetExperimentalFeatureEnabled, Ptr <YGConfig> -> <YGExperimentalFeature> -> CBool -> IO ()
+#ccall YGConfigIsExperimentalFeatureEnabled, Ptr <YGConfig> -> <YGExperimentalFeature> -> IO CBool
+
+-- Using the web defaults is the preferred configuration for new projects. Usage
+-- of non web defaults should be considered as legacy.
+#ccall YGConfigSetUseWebDefaults, Ptr <YGConfig> -> CBool -> IO ()
+#ccall YGConfigGetUseWebDefaults, Ptr <YGConfig> -> IO CBool
+
+-- Set this to number of pixels in 1 point to round calculation results If you
+-- want to avoid rounding - set PointScaleFactor to 0
+#ccall YGConfigSetPointScaleFactor, Ptr <YGConfig> -> CFloat -> IO ()
+#ccall YGConfigGetPointScaleFactor, Ptr <YGConfig> -> IO CFloat
+
+#ccall YGConfigSetErrata, Ptr <YGConfig> -> <YGErrata> -> IO ()
+#ccall YGConfigGetErrata, Ptr <YGConfig> -> IO <YGErrata>
+
+#ccall YGConfigSetCloneNodeFunc, Ptr <YGConfig> -> <YGCloneNodeFunc> -> IO ()
+#ccall YGConfigSetPrintTreeFlag, Ptr <YGConfig> -> CBool -> IO ()
+
+#ccall YGConfigSetContext, Ptr <YGConfig> -> Ptr () -> IO ()
+#ccall YGConfigGetContext, Ptr <YGConfig> -> IO (Ptr ())
+
+#ccall YGRoundValueToPixelGrid, CDouble -> CDouble -> CBool -> CBool -> IO CFloat
lib/Bindings/Yoga/Enums.hsc view
@@ -1,100 +1,144 @@-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE NoImplicitPrelude  #-}-{-# LANGUAGE StandaloneDeriving #-}------------------------------------------------------------------------------------#include <Yoga.h>-#include <bindings.dsl.h>------------------------------------------------------------------------------------module Bindings.Yoga.Enums where--import Prelude (Num)---- typedef enum YGFlexDirection-#num YGFlexDirectionColumn-#num YGFlexDirectionColumnReverse-#num YGFlexDirectionRow-#num YGFlexDirectionRowReverse-#num YGFlexDirectionCount---- typedef enum YGMeasureMode {-#num YGMeasureModeUndefined-#num YGMeasureModeExactly-#num YGMeasureModeAtMost-#num YGMeasureModeCount---- typedef enum YGPrintOptions {-#num YGPrintOptionsLayout-#num YGPrintOptionsStyle-#num YGPrintOptionsChildren-#num YGPrintOptionsCount---- typedef enum YGEdge {-#num YGEdgeLeft-#num YGEdgeTop-#num YGEdgeRight-#num YGEdgeBottom-#num YGEdgeStart-#num YGEdgeEnd-#num YGEdgeHorizontal-#num YGEdgeVertical-#num YGEdgeAll-#num YGEdgeCount---- typedef enum YGPositionType {-#num YGPositionTypeRelative-#num YGPositionTypeAbsolute-#num YGPositionTypeCount---- typedef enum YGDimension {-#num YGDimensionWidth-#num YGDimensionHeight-#num YGDimensionCount---- typedef enum YGJustify {-#num YGJustifyFlexStart-#num YGJustifyCenter-#num YGJustifyFlexEnd-#num YGJustifySpaceBetween-#num YGJustifySpaceAround-#num YGJustifyCount---- typedef enum YGDirection {-#num YGDirectionInherit-#num YGDirectionLTR-#num YGDirectionRTL-#num YGDirectionCount---- typedef enum YGLogLevel {-#num YGLogLevelError-#num YGLogLevelWarn-#num YGLogLevelInfo-#num YGLogLevelDebug-#num YGLogLevelVerbose-#num YGLogLevelCount---- typedef enum YGWrap {-#num YGWrapNoWrap-#num YGWrapWrap-#num YGWrapCount---- typedef enum YGOverflow {-#num YGOverflowVisible-#num YGOverflowHidden-#num YGOverflowScroll-#num YGOverflowCount---- typedef enum YGExperimentalFeature {-#num YGExperimentalFeatureWebFlexBasis-#num YGExperimentalFeatureCount---- typedef enum YGAlign {-#num YGAlignAuto-#num YGAlignFlexStart-#num YGAlignCenter-#num YGAlignFlexEnd-#num YGAlignStretch-#num YGAlignCount+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE NoImplicitPrelude  #-}
+{-# LANGUAGE StandaloneDeriving #-}
+
+--------------------------------------------------------------------------------
+
+#include <Yoga.h>
+#include <bindings.dsl.h>
+
+--------------------------------------------------------------------------------
+
+module Bindings.Yoga.Enums where
+
+import Prelude (Num, IO)
+import Foreign.C.Types  (CUInt(..))
+import Foreign.C.String (CString)
+import Foreign.Ptr      (FunPtr)
+
+#integral_t enum YGAlign
+#num YGAlignAuto
+#num YGAlignFlexStart
+#num YGAlignCenter
+#num YGAlignFlexEnd
+#num YGAlignStretch
+#num YGAlignBaseline
+#num YGAlignSpaceBetween
+#num YGAlignSpaceAround
+#ccall YGAlignToString, <YGAlign> -> IO CString
+
+#integral_t enum YGDimension
+#num YGDimensionWidth
+#num YGDimensionHeight
+#ccall YGDimensionToString, <YGAlign> -> IO CString
+
+#integral_t enum YGDirection
+#num YGDirectionInherit
+#num YGDirectionLTR
+#num YGDirectionRTL
+#ccall YGDirectionToString, <YGAlign> -> IO CString
+
+#integral_t enum YGDisplay
+#num YGDisplayFlex
+#num YGDisplayNone
+#ccall YGDisplayToString, <YGAlign> -> IO CString
+
+#integral_t enum YGEdge
+#num YGEdgeLeft
+#num YGEdgeTop
+#num YGEdgeRight
+#num YGEdgeBottom
+#num YGEdgeStart
+#num YGEdgeEnd
+#num YGEdgeHorizontal
+#num YGEdgeVertical
+#num YGEdgeAll
+#ccall YGEdgeToString, <YGAlign> -> IO CString
+
+#integral_t enum YGErrata
+#num YGErrataNone
+#num YGErrataStretchFlexBasis
+#num YGErrataStartingEndingEdgeFromFlexDirection
+#num YGErrataPositionStaticBehavesLikeRelative
+#num YGErrataAbsolutePositioning
+#num YGErrataAll
+#num YGErrataClassic
+#ccall YGErrataToString, <YGAlign> -> IO CString
+
+#integral_t enum YGExperimentalFeature
+#num YGExperimentalFeatureWebFlexBasis
+#num YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge
+#ccall YGExperimentalFeatureToString, <YGAlign> -> IO CString
+
+#integral_t enum YGFlexDirection
+#num YGFlexDirectionColumn
+#num YGFlexDirectionColumnReverse
+#num YGFlexDirectionRow
+#num YGFlexDirectionRowReverse
+#ccall YGFlexDirectionToString, <YGAlign> -> IO CString
+
+#integral_t enum YGGutter
+#num YGGutterColumn
+#num YGGutterRow
+#num YGGutterAll
+#ccall YGGutterToString, <YGAlign> -> IO CString
+
+#integral_t enum YGJustify
+#num YGJustifyFlexStart
+#num YGJustifyCenter
+#num YGJustifyFlexEnd
+#num YGJustifySpaceBetween
+#num YGJustifySpaceAround
+#num YGJustifySpaceEvenly
+#ccall YGJustifyToString, <YGAlign> -> IO CString
+
+#integral_t enum YGLogLevel
+#num YGLogLevelError
+#num YGLogLevelWarn
+#num YGLogLevelInfo
+#num YGLogLevelDebug
+#num YGLogLevelVerbose
+#num YGLogLevelFatal
+#ccall YGLogLevelToString, <YGAlign> -> IO CString
+
+#integral_t enum YGMeasureMode
+#num YGMeasureModeUndefined
+#num YGMeasureModeExactly
+#num YGMeasureModeAtMost
+#ccall YGMeasureModeToString, <YGAlign> -> IO CString
+
+#integral_t enum YGNodeType
+#num YGNodeTypeDefault
+#num YGNodeTypeText
+#ccall YGNodeTypeToString, <YGAlign> -> IO CString
+
+#integral_t enum YGOverflow
+#num YGOverflowVisible
+#num YGOverflowHidden
+#num YGOverflowScroll
+#ccall YGOverflowToString, <YGAlign> -> IO CString
+
+#integral_t enum YGPositionType
+#num YGPositionTypeStatic
+#num YGPositionTypeRelative
+#num YGPositionTypeAbsolute
+#ccall YGPositionTypeToString, <YGAlign> -> IO CString
+
+#integral_t enum YGPrintOptions
+#num YGPrintOptionsLayout
+#num YGPrintOptionsStyle
+#num YGPrintOptionsChildren
+#ccall YGPrintOptionsToString, <YGAlign> -> IO CString
+
+#integral_t enum YGUnit
+#num YGUnitUndefined
+#num YGUnitPoint
+#num YGUnitPercent
+#num YGUnitAuto
+#ccall YGUnitToString, <YGAlign> -> IO CString
+
+#integral_t enum YGWrap
+#num YGWrapNoWrap
+#num YGWrapWrap
+#num YGWrapWrapReverse
+#ccall YGWrapToString, <YGAlign> -> IO CString
+ lib/Bindings/glue.c view
@@ -0,0 +1,46 @@+#include <Yoga.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+inline YGValue* YGValueCopy(YGValue value) {
+    YGValue* ret = malloc(sizeof(YGValue));
+    memcpy(ret, &value, sizeof(YGValue));
+
+    return ret;
+}
+
+void YGValueFree(YGValue* value) {
+    free(value);
+}
+
+YGValue* YGNodeStyleGetFlexBasisWrapper(YGNodeRef node) {
+    return YGValueCopy(YGNodeStyleGetFlexBasis(node));
+}
+YGValue* YGNodeStyleGetPositionWrapper(YGNodeRef node, YGEdge edge) {
+    return YGValueCopy(YGNodeStyleGetPosition(node, edge));
+}
+YGValue* YGNodeStyleGetMarginWrapper(YGNodeRef node, YGEdge edge) {
+    return YGValueCopy(YGNodeStyleGetMargin(node, edge));
+}
+YGValue* YGNodeStyleGetPaddingWrapper(YGNodeRef node, YGEdge edge) {
+    return YGValueCopy(YGNodeStyleGetPadding(node, edge));
+}
+YGValue* YGNodeStyleGetWidthWrapper(YGNodeRef node) {
+    return YGValueCopy(YGNodeStyleGetWidth(node));
+}
+YGValue* YGNodeStyleGetHeightWrapper(YGNodeRef node) {
+    return YGValueCopy(YGNodeStyleGetHeight(node));
+}
+YGValue* YGNodeStyleGetMinWidthWrapper(YGNodeRef node) {
+    return YGValueCopy(YGNodeStyleGetMinWidth(node));
+}
+YGValue* YGNodeStyleGetMinHeightWrapper(YGNodeRef node) {
+    return YGValueCopy(YGNodeStyleGetMinHeight(node));
+}
+YGValue* YGNodeStyleGetMaxWidthWrapper(YGNodeRef node) {
+    return YGValueCopy(YGNodeStyleGetMaxWidth(node));
+}
+YGValue* YGNodeStyleGetMaxHeightWrapper(YGNodeRef node) {
+    return YGValueCopy(YGNodeStyleGetMaxHeight(node));
+}
lib/Yoga.hs view
@@ -1,503 +1,510 @@-{-|-Module      : Yoga-Description : Bindings to Facebook's Yoga layout engine-Copyright   : (c) Pavel Krajcevski, 2017-License     : MIT-Maintainer  : Krajcevski@gmail.com-Stability   : experimental-Portability : POSIX--This module holds a high-level interface to the bindings associated with this-library that are maintained in "Bindings.Yoga". Application developers will-likely want to use this module to interface with the library, but are available-to use the C-level bindings if more control is desired.--These bindings are not affiliated with Facebook in any way, and have been-developed separately for the sole purpose of interfacing with their open source-library.--Full documentation can be found at <http://facebook.github.io/yoga>--}-module Yoga (-  -- ** Main datatype-  Layout,--  -- ** Children layouts-  -- | These layouts describe the way that children are ordered and spaced-  -- within their parent.-  Children, startToEnd, endToStart, centered, spaceBetween, spaceAround,-  wrapped,-  -  -- ** Containers-  hbox, vbox,-  hboxLeftToRight, hboxRightToLeft,-  vboxTopToBottom, vboxBottomToTop,--  -- ** Leaf nodes-  Size(..),-  shrinkable, growable, exact, withDimensions,--  -- ** Attributes-  Edge(..),-  stretched, withMargin, withPadding,--  -- ** Rendering-  LayoutInfo(..), RenderFn, render, foldRender,--) where----------------------------------------------------------------------------------import Bindings.Yoga-import Bindings.Yoga.Enums--import Control.Applicative-import Control.Monad hiding (mapM, forM_)--import Data.Foldable-import Data.Traversable-import Data.Monoid--import Foreign.C.Types (CFloat, CInt)-import Foreign.ForeignPtr--import GHC.Ptr (Ptr)--import Numeric.IEEE--import System.IO.Unsafe---- Last to avoid compiler warnings due to the Foldable/Traversable Proposal-import Prelude hiding (foldl, foldr, mapM)------------------------------------------------------------------------------------- | The main datatype in the high level bindings is a 'Layout'. Layouts are--- used to store a tree of nodes that represent the different components of a--- layout. Layouts can be composed by adding one as a sub-tree to another. The--- parent-child relationship dictates different parameters such as width, height--- and position. This type is opaque to the user in order to facilitate updates--- to the library. For more control, use the C-level bindings in Yoga.Bindings.-data Layout a-  = Root { _payload :: a,-           _children :: [Layout a],-           _rootPtr :: ForeignPtr C'YGNode }-  | Container { _payload :: a,-                _children :: [Layout a] }-  | Leaf { _payload :: a }-  deriving (Show, Eq, Ord)--withNativePtr :: Layout a -> (Ptr C'YGNode -> IO b) -> IO b-withNativePtr (Root _ _ ptr) f = withForeignPtr ptr f-withNativePtr _ _ = error "Internal: Only root nodes have pointers"---- | Children are a list of layouts annotated with a style for how they should--- be laid out in their container.-data Children a-  = StartToEnd [Layout a]-  | EndToStart [Layout a]-  | Centered [Layout a]-  | SpaceBetween [Layout a]-  | SpaceAround [Layout a]-  | Wrap (Children a)-  deriving (Show, Eq, Ord)--instance Functor Layout where-  fmap f (Root x cs ptr) = Root (f x) (fmap (fmap f) cs) ptr-  fmap f (Container x cs) = Container (f x) (fmap (fmap f) cs)-  fmap f (Leaf x) = Leaf (f x)--instance Foldable Layout where-  foldMap f (Root x cs _) = f x `mappend` (foldMap (foldMap f) cs)-  foldMap f (Container x cs) = f x `mappend` (foldMap (foldMap f) cs)-  foldMap f (Leaf x) = f x--  foldl f z (Root x cs _) = foldl (foldl f) (f z x) cs-  foldl f z (Container x cs) = foldl (foldl f) (f z x) cs-  foldl f z (Leaf x) = f z x--  foldr f z (Root x cs _) = f x $ foldr (flip $ foldr f) z cs-  foldr f z (Container x cs) = f x $ foldr (flip $ foldr f) z cs-  foldr f z (Leaf x) = f x z--instance Traversable Layout where-  traverse f (Root x cs ptr) =-    Root <$> f x <*> (sequenceA $ traverse f <$> cs) <*> pure ptr-  traverse f (Container x cs) =-    Container <$> f x <*> (sequenceA $ traverse f <$> cs)-  traverse f (Leaf x) = Leaf <$> f x--  sequenceA (Root x cs ptr) =-    Root <$> x <*> sequenceA (sequenceA <$> cs) <*> pure ptr-  sequenceA (Container x cs) =-    Container <$> x <*> sequenceA (sequenceA <$> cs)-  sequenceA (Leaf x) = Leaf <$> x--mkNode :: a -> IO (Layout a)-mkNode x = do-  ptr <- c'YGNodeNew-  Root x [] <$> newForeignPtr p'YGNodeFree ptr---- | Collects a list of layouts and orients them from start to end depending--- on the orientation of the parent (LTR vs RTL).-startToEnd :: [Layout a] -> Children a-startToEnd = StartToEnd---- | Collects a list of layouts and orients them from end to start depending--- on the orientation of the parent (LTR vs RTL).-endToStart :: [Layout a] -> Children a-endToStart = EndToStart---- | Collects a list of children and centers them within the parent.-centered :: [Layout a] -> Children a-centered = Centered---- | Collects a list of children that span the parent such that the space--- between each child is equal-spaceBetween :: [Layout a] -> Children a-spaceBetween = SpaceBetween---- | Collects a list of children that span the parent such that the space to the--- left and right of each child is equal.-spaceAround :: [Layout a] -> Children a-spaceAround = SpaceAround---- | Permits children to wrap to a new line if they exceed the bounds of their--- parent-wrapped :: Children a -> Children a-wrapped (Wrap xs) = Wrap xs-wrapped childs = childs--justifiedContainer :: CInt -> [Layout a] -> a -> IO (Layout a)-justifiedContainer just cs x = do-  ptr <- c'YGNodeNew-  c'YGNodeStyleSetJustifyContent ptr just-  c'YGNodeStyleSetFlexWrap ptr c'YGWrapNoWrap--  cs' <- flip mapM (zip cs [0..]) $ \((Root p children fptr), idx) -> do-    withForeignPtr fptr $ \oldptr -> do-      newptr <- c'YGNodeClone oldptr-      c'YGNodeInsertChild ptr newptr idx-      return $ if null children-               then Leaf p-               else Container p children-  Root x cs' <$> newForeignPtr p'YGNodeFreeRecursive ptr--assembleChildren :: Children a -> a -> IO (Layout a)-assembleChildren (StartToEnd cs) x = justifiedContainer c'YGJustifyFlexStart cs x-assembleChildren (EndToStart cs) x = justifiedContainer c'YGJustifyFlexEnd cs x-assembleChildren (Centered cs) x = justifiedContainer c'YGJustifyCenter cs x-assembleChildren (SpaceBetween cs) x =-  justifiedContainer c'YGJustifySpaceBetween cs x-assembleChildren (SpaceAround cs) x =-  justifiedContainer c'YGJustifySpaceAround cs x-assembleChildren (Wrap cs) x = assembleChildren cs x >>= wrapContainer-  where-    wrapContainer :: Layout a -> IO (Layout a)-    wrapContainer lyt = do-      withNativePtr lyt $ \ptr ->-        c'YGNodeStyleSetFlexWrap ptr c'YGWrapWrap-      return lyt--setContainerDirection :: CInt -> CInt -> Layout a -> IO ()-setContainerDirection dir flexDir lyt =-  withNativePtr lyt $ \ptr -> do-    c'YGNodeStyleSetDirection ptr dir-    c'YGNodeStyleSetFlexDirection ptr flexDir---- | Generates a layout from a group of children and a payload such that the--- children are laid out horizontally. The orientation (RTL vs LTR) is--- inherited from the parent-hbox :: Children a -> a -> Layout a-hbox cs x = unsafePerformIO $ do-  node <- assembleChildren cs x-  setContainerDirection c'YGDirectionInherit c'YGFlexDirectionRow node-  return node---- | Generates a layout from a group of children and a payload such that the--- children are laid out vertically. The orientation (top to bottom vs bottom to--- top) is inherited from the parent.-vbox :: Children a -> a -> Layout a-vbox cs x = unsafePerformIO $ do-  node <- assembleChildren cs x-  setContainerDirection c'YGDirectionInherit c'YGFlexDirectionColumn node-  return node---- | Generates a layout from a group of children and a payload such that the--- children are laid out horizontally from left to right.-hboxLeftToRight :: Children a -> a -> Layout a-hboxLeftToRight cs x = unsafePerformIO $ do-  node <- assembleChildren cs x-  setContainerDirection c'YGDirectionLTR c'YGFlexDirectionRow node-  return node---- | Generates a layout from a group of children and a payload such that the--- children are laid out horizontally from right to left.-hboxRightToLeft :: Children a -> a -> Layout a-hboxRightToLeft cs x = unsafePerformIO $ do-  node <- assembleChildren cs x-  setContainerDirection c'YGDirectionRTL c'YGFlexDirectionRow node-  return node---- | Generates a layout from a group of children and a payload such that the--- children are laid out vertically from top to bottom.-vboxTopToBottom :: Children a -> a -> Layout a-vboxTopToBottom cs x = unsafePerformIO $ do-  node <- assembleChildren cs x-  setContainerDirection c'YGDirectionLTR c'YGFlexDirectionColumn node-  return node---- | Generates a layout from a group of children and a payload such that the--- children are laid out vertically from bottom to top.-vboxBottomToTop :: Children a -> a -> Layout a-vboxBottomToTop cs x = unsafePerformIO $ do-  node <- assembleChildren cs x-  setContainerDirection c'YGDirectionRTL c'YGFlexDirectionColumn node-  return node---- | A 'Size' is used to set properties about given layouts. In general, the--- width and height of a node along with its position are laid out by Yoga's--- internal layout engine. However, the user may decide to set limits on how--- much internal nodes can shrink or grow. This datatype controls those--- properties-data Size-  = Exact Float-  | Min Float-  | Max Float-  | Range Float Float-    deriving (Read, Show, Eq, Ord)--setWidth :: Size -> Layout a -> IO ()-setWidth (Exact w) lyt =-  withNativePtr lyt $ \ptr -> c'YGNodeStyleSetWidth ptr $ realToFrac w-setWidth (Min w) lyt =-  withNativePtr lyt $ \ptr -> c'YGNodeStyleSetMinWidth ptr $ realToFrac w-setWidth (Max w) lyt =-  withNativePtr lyt $ \ptr -> c'YGNodeStyleSetMaxWidth ptr $ realToFrac w-setWidth (Range minWidth maxWidth) lyt =-  withNativePtr lyt $ \ptr -> do-    c'YGNodeStyleSetMinWidth ptr $ realToFrac minWidth-    c'YGNodeStyleSetMaxWidth ptr $ realToFrac maxWidth--setHeight :: Size -> Layout a -> IO ()-setHeight (Exact h) lyt =-  withNativePtr lyt $ \ptr -> c'YGNodeStyleSetHeight ptr $ realToFrac h-setHeight (Min h) lyt =-  withNativePtr lyt $ \ptr -> c'YGNodeStyleSetMinHeight ptr $ realToFrac h-setHeight (Max h) lyt =-  withNativePtr lyt $ \ptr -> c'YGNodeStyleSetMaxHeight ptr $ realToFrac h-setHeight (Range minHeight maxHeight) lyt =-  withNativePtr lyt $ \ptr -> do-    c'YGNodeStyleSetMinHeight ptr $ realToFrac minHeight-    c'YGNodeStyleSetMaxHeight ptr $ realToFrac maxHeight---- | Specifies layout may shrink up to the given size. The weight parameter--- is used to determine how much this layout will shrink in relation to any--- siblings.-shrinkable :: Float -> Size -> Size -> (b -> Layout a) -> b -> Layout a-shrinkable weight width height mkNodeFn x = unsafePerformIO $ do-  let n = mkNodeFn x-  setWidth width n-  setHeight height n-  withNativePtr n $ \ptr -> c'YGNodeStyleSetFlexShrink ptr $ realToFrac weight-  return n---- | Specifies layout may grow up to the given size. The weight parameter--- is used to determine how much this layout will grow in relation to any--- siblings.-growable :: Float -> Size -> Size -> (b -> Layout a) -> b -> Layout a-growable weight width height mkNodeFn x = unsafePerformIO $ do-  let n = mkNodeFn x-  setWidth width n-  setHeight height n-  withNativePtr n $ \ptr -> c'YGNodeStyleSetFlexGrow ptr $ realToFrac weight-  return n---- | Creates a layout with the exact width and height for the given payload.-exact :: Float -> Float -> a -> Layout a-exact width height x = unsafePerformIO $ do-  n <- mkNode x-  setWidth (Exact width) n-  setHeight (Exact height) n-  return n---- | Specifies the exact dimensions expected for a layout. Can be used for--- containers and such when there is not necessarily any rendering involved. -withDimensions :: Float -> Float -> (a -> Layout b) -> a -> Layout b-withDimensions width height mkNodeFn x = unsafePerformIO $ do-  let n = mkNodeFn x-  setWidth (Exact width) n-  setHeight (Exact height) n-  return n---- | Allows a container to stretch to fit its parent-stretched :: (b -> Layout a) -> b -> Layout a-stretched mkNodeFn x =-  let node = mkNodeFn x-  in unsafePerformIO $ do-    withNativePtr node $ \ptr -> c'YGNodeStyleSetAlignSelf ptr c'YGAlignStretch-    return node---- | Edges are used to describe the direction from which we want to alter an--- attribute of a node. They are currently only being used with 'withMargin' and--- 'withPadding'.-data Edge-  = Edge'Left-  | Edge'Top-  | Edge'Right-  | Edge'Bottom-  | Edge'Start-  | Edge'End-  | Edge'Horizontal-  | Edge'Vertical-  | Edge'All-  deriving (Eq, Ord, Bounded, Enum, Read, Show)--setMargin :: CInt -> Float -> Layout a -> IO (Layout a)-setMargin edge px node = do-  withNativePtr node $ \ptr -> c'YGNodeStyleSetMargin ptr edge $ realToFrac px-  return node---- | Transforms a layout generator to one which applies the given margin using--- continuation passing style. In this way we maintain the const-ness of layout--- nodes. E.g.:------ > let lyt = ($ payload) (withMargin Edge'Left 10.0 $ exact 200.0 300.0)-withMargin :: Edge -> Float -> (b -> Layout a) -> b -> Layout a-withMargin Edge'Left px mkNodeFn x =-  unsafePerformIO $ setMargin c'YGEdgeLeft px (mkNodeFn x)-withMargin Edge'Top px mkNodeFn x =-  unsafePerformIO $ setMargin c'YGEdgeTop px (mkNodeFn x)-withMargin Edge'Right px mkNodeFn x =-  unsafePerformIO $ setMargin c'YGEdgeRight px (mkNodeFn x)-withMargin Edge'Bottom px mkNodeFn x =-  unsafePerformIO $ setMargin c'YGEdgeBottom px (mkNodeFn x)-withMargin Edge'Start px mkNodeFn x =-  unsafePerformIO $ setMargin c'YGEdgeStart px (mkNodeFn x)-withMargin Edge'End px mkNodeFn x =-  unsafePerformIO $ setMargin c'YGEdgeEnd px (mkNodeFn x)-withMargin Edge'Horizontal px mkNodeFn x =-  unsafePerformIO $ setMargin c'YGEdgeHorizontal px (mkNodeFn x)-withMargin Edge'Vertical px mkNodeFn x =-  unsafePerformIO $ setMargin c'YGEdgeVertical px (mkNodeFn x)-withMargin Edge'All px mkNodeFn x =-  unsafePerformIO $ setMargin c'YGEdgeAll px (mkNodeFn x)--setPadding :: CInt -> Float -> Layout a -> IO (Layout a)-setPadding edge px node = do-  withNativePtr node $ \ptr ->-    c'YGNodeStyleSetPadding ptr edge $ realToFrac px-  return node---- | Transforms a layout generator to one which applies the given padding using--- continuation passing style. In this way we maintain the const-ness of layout--- nodes. E.g.:------ > let lyt = ($ payload) (withPadding Edge'Left 10.0 $ exact 200.0 300.0)-withPadding :: Edge -> Float -> (b -> Layout a) -> b -> Layout a-withPadding Edge'Left px mkNodeFn x =-  unsafePerformIO $ setPadding c'YGEdgeLeft px (mkNodeFn x)-withPadding Edge'Top px mkNodeFn x =-  unsafePerformIO $ setPadding c'YGEdgeTop px (mkNodeFn x)-withPadding Edge'Right px mkNodeFn x =-  unsafePerformIO $ setPadding c'YGEdgeRight px (mkNodeFn x)-withPadding Edge'Bottom px mkNodeFn x =-  unsafePerformIO $ setPadding c'YGEdgeBottom px (mkNodeFn x)-withPadding Edge'Start px mkNodeFn x =-  unsafePerformIO $ setPadding c'YGEdgeStart px (mkNodeFn x)-withPadding Edge'End px mkNodeFn x =-  unsafePerformIO $ setPadding c'YGEdgeEnd px (mkNodeFn x)-withPadding Edge'Horizontal px mkNodeFn x =-  unsafePerformIO $ setPadding c'YGEdgeHorizontal px (mkNodeFn x)-withPadding Edge'Vertical px mkNodeFn x =-  unsafePerformIO $ setPadding c'YGEdgeVertical px (mkNodeFn x)-withPadding Edge'All px mkNodeFn x =-  unsafePerformIO $ setPadding c'YGEdgeAll px (mkNodeFn x)------------------------------------------------------------------------------------- Rendering---- | Stores the calculated layout information for a given node. During--- rendering, the rendering function will take the payload and layout info to--- facilitate the renderer to do whatever it needs to with the given layout--- calculations.-data LayoutInfo = LayoutInfo {-  nodeTop :: Float,     -- ^ The y-coordinate of this node-  nodeLeft :: Float,    -- ^ The x-coordinate of this node-  nodeWidth :: Float,   -- ^ The width of this node-  nodeHeight :: Float   -- ^ The height of this node-} deriving (Eq, Show)--emptyInfo :: LayoutInfo-emptyInfo = LayoutInfo 0 0 0 0--layoutWithParent :: LayoutInfo -> LayoutInfo -> LayoutInfo-layoutWithParent parent child =-  let (x, y) = (nodeLeft parent, nodeTop parent)-      (x', y') = (nodeLeft child, nodeTop child)-  in child { nodeLeft = x + x', nodeTop = y + y' }---- | A 'RenderFn' takes a top-left position and a width and height of a node--- with the given payload. The function is expected to perform some monadic--- action in the 'Monad' m, and return a new payload of type b. This function is--- called on each node in order during a call to render.-type RenderFn m a b = LayoutInfo -> a -> m b--calculateLayout :: Ptr C'YGNode -> IO ()-calculateLayout ptr =-  let n = (nan :: CFloat)-  in c'YGNodeStyleGetDirection ptr >>= c'YGNodeCalculateLayout ptr n n--layoutInfo :: Ptr C'YGNode -> IO LayoutInfo-layoutInfo ptr = do-  left <- realToFrac <$> c'YGNodeLayoutGetLeft ptr-  top <- realToFrac <$> c'YGNodeLayoutGetTop ptr-  width <- realToFrac <$> c'YGNodeLayoutGetWidth ptr-  height <- realToFrac <$> c'YGNodeLayoutGetHeight ptr-  return $ LayoutInfo top left width height--renderNodeWithChildren :: (Functor m, Applicative m, Monad m, Monoid b) =>-                          LayoutInfo -> a -> [Layout a] -> Ptr C'YGNode-                          -> RenderFn m a (b, c)-                          -> m (b, c, [Layout c])-renderNodeWithChildren parentInfo x children ptr f = do-  info <- return $ unsafePerformIO $ layoutInfo ptr-  let thisInfo = layoutWithParent parentInfo info-  (m, y) <- f thisInfo x-  cs <- flip mapM (zip children [0..]) $ \(child, childIdx) -> do-    childPtr <- return $ unsafePerformIO $ c'YGNodeGetChild ptr childIdx-    foldRenderTree thisInfo child childPtr f-  return (mappend m . foldr mappend mempty . map fst $ cs, y, map snd cs)--foldRenderTree :: (Functor m, Applicative m, Monad m, Monoid b) =>-                  LayoutInfo -> Layout a -> Ptr C'YGNode -> RenderFn m a (b, c) ->-                  m (b, Layout c)-foldRenderTree parentInfo (Root x children fptr) ptr f = do-  (result, y, cs) <- renderNodeWithChildren parentInfo x children ptr f-  return $ (result, Root y cs fptr)-foldRenderTree parentInfo (Container x children) ptr f = do-  (result, y, cs) <- renderNodeWithChildren parentInfo x children ptr f-  return $ (result, Container y cs)-foldRenderTree parentInfo (Leaf x) ptr f = do-  (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--- node. The second result is stored as the new payload for the given node.--- Hence, the resulting monadic action produces a 'mappend'-ed set of 'b's and--- a new layout with payloads of type 'c'.-foldRender :: (Functor m, Applicative m, Monad m, Monoid b) =>-              Layout a -> RenderFn m a (b, c) -> m (b, Layout c)-foldRender lyt@(Root _ _ fptr) f = do-  rootPtr <- return $ unsafePerformIO $ withForeignPtr fptr $ \ptr -> do-    calculateLayout ptr-    return ptr-  foldRenderTree emptyInfo lyt rootPtr f-foldRender _ _ = error "Internal: Rendering must be done from the root node"---- | Renders a layout with the user-supplied function. The renderer traverses--- the tree from root node to children and transforms each payload using the--- user-supplied function.-render :: (Functor m, Applicative m, Monad m) =>-          Layout a -> RenderFn m a b -> m (Layout b)-render lyt f =-  let f' lytInfo x = ((,) ()) <$> f lytInfo x-  in snd <$> foldRender lyt f'+{-|
+Module      : Yoga
+Description : Bindings to Facebook's Yoga layout engine
+Copyright   : (c) Pavel Krajcevski, 2017
+License     : MIT
+Maintainer  : Krajcevski@gmail.com
+Stability   : experimental
+Portability : POSIX
+
+This module holds a high-level interface to the bindings associated with this
+library that are maintained in "Bindings.Yoga". Application developers will
+likely want to use this module to interface with the library, but are available
+to use the C-level bindings if more control is desired.
+
+These bindings are not affiliated with Facebook in any way, and have been
+developed separately for the sole purpose of interfacing with their open source
+library.
+
+Full documentation can be found at <http://facebook.github.io/yoga>
+-}
+{-# LANGUAGE TupleSections #-}
+module Yoga (
+  -- ** Main datatype
+  Layout,
+
+  -- ** Children layouts
+  -- | These layouts describe the way that children are ordered and spaced
+  -- within their parent.
+  Children, startToEnd, endToStart, centered, spaceBetween, spaceAround,
+  wrapped,
+  
+  -- ** Containers
+  hbox, vbox,
+  hboxLeftToRight, hboxRightToLeft,
+  vboxTopToBottom, vboxBottomToTop,
+
+  -- ** Leaf nodes
+  Size(..),
+  shrinkable, growable, exact, withDimensions,
+
+  -- ** Attributes
+  Edge(..), Gutter(..),
+  stretched, setMargin, setPadding, setBorder, setGap,
+
+  -- ** Rendering
+  LayoutInfo(..), RenderFn, render, foldRender,
+
+) where
+--------------------------------------------------------------------------------
+import Bindings.Yoga
+import Bindings.Yoga.Enums
+
+import Control.Applicative
+import Control.Monad hiding (mapM, forM_)
+import Control.Monad.IO.Class (MonadIO(..))
+
+import Data.Foldable
+import Data.Traversable
+import Data.Monoid
+
+import Foreign.C.Types (CFloat, CUInt)
+import Foreign.ForeignPtr
+
+import GHC.Ptr (Ptr)
+
+import Numeric.IEEE
+
+-- Last to avoid compiler warnings due to the Foldable/Traversable Proposal
+import Prelude hiding (foldl, foldr, mapM)
+--------------------------------------------------------------------------------
+
+data LayoutTree a
+  = Root { _payload :: a,
+           _children :: [LayoutTree a],
+           _rootPtr :: ForeignPtr C'YGNode }
+  | Container { _payload :: a,
+                _children :: [LayoutTree a] }
+  | Leaf { _payload :: a }
+  deriving (Show, Eq, Ord)
+
+-- | The main datatype in the high level bindings is a 'Layout'. Layouts are
+-- used to store a tree of nodes that represent the different components of a
+-- layout. Layouts can be composed by adding one as a sub-tree to another. The
+-- parent-child relationship dictates different parameters such as width, height
+-- and position. This type is opaque to the user in order to facilitate updates
+-- to the library. For more control, use the C-level bindings in Yoga.Bindings.
+newtype Layout a = Layout { generateLayout :: IO (LayoutTree a) }
+
+withNativePtr :: LayoutTree a -> (Ptr C'YGNode -> IO b) -> IO b
+withNativePtr (Root _ _ ptr) f = withForeignPtr ptr f
+withNativePtr _ _ = error "Internal: Only root nodes have pointers"
+
+-- | Children are a list of layouts annotated with a style for how they should
+-- be laid out in their container.
+data Children a
+  = StartToEnd [Layout a]
+  | EndToStart [Layout a]
+  | Centered [Layout a]
+  | SpaceBetween [Layout a]
+  | SpaceAround [Layout a]
+  | Wrap (Children a)
+
+instance Functor LayoutTree where
+  fmap f (Root x cs ptr) = Root (f x) (fmap (fmap f) cs) ptr
+  fmap f (Container x cs) = Container (f x) (fmap (fmap f) cs)
+  fmap f (Leaf x) = Leaf (f x)
+
+instance Foldable LayoutTree where
+  foldMap f (Root x cs _) = f x `mappend` foldMap (foldMap f) cs
+  foldMap f (Container x cs) = f x `mappend` foldMap (foldMap f) cs
+  foldMap f (Leaf x) = f x
+
+  foldl f z (Root x cs _) = foldl (foldl f) (f z x) cs
+  foldl f z (Container x cs) = foldl (foldl f) (f z x) cs
+  foldl f z (Leaf x) = f z x
+
+  foldr f z (Root x cs _) = f x $ foldr (flip $ foldr f) z cs
+  foldr f z (Container x cs) = f x $ foldr (flip $ foldr f) z cs
+  foldr f z (Leaf x) = f x z
+
+instance Traversable LayoutTree where
+  traverse f (Root x cs ptr) =
+    Root <$> f x <*> traverse (traverse f) cs <*> pure ptr
+  traverse f (Container x cs) =
+    Container <$> f x <*> traverse (traverse f) cs
+  traverse f (Leaf x) = Leaf <$> f x
+
+  sequenceA (Root x cs ptr) =
+    Root <$> x <*> traverse sequenceA cs <*> pure ptr
+  sequenceA (Container x cs) =
+    Container <$> x <*> traverse sequenceA cs
+  sequenceA (Leaf x) = Leaf <$> x
+
+mkNode :: a -> Layout a
+mkNode x = Layout $ do
+  ptr <- c'YGNodeNew
+  Root x [] <$> newForeignPtr p'YGNodeFree ptr
+
+-- | Collects a list of layouts and orients them from start to end depending
+-- on the orientation of the parent (LTR vs RTL).
+startToEnd :: [Layout a] -> Children a
+startToEnd = StartToEnd
+
+-- | Collects a list of layouts and orients them from end to start depending
+-- on the orientation of the parent (LTR vs RTL).
+endToStart :: [Layout a] -> Children a
+endToStart = EndToStart
+
+-- | Collects a list of children and centers them within the parent.
+centered :: [Layout a] -> Children a
+centered = Centered
+
+-- | Collects a list of children that span the parent such that the space
+-- between each child is equal
+spaceBetween :: [Layout a] -> Children a
+spaceBetween = SpaceBetween
+
+-- | Collects a list of children that span the parent such that the space to the
+-- left and right of each child is equal.
+spaceAround :: [Layout a] -> Children a
+spaceAround = SpaceAround
+
+-- | Permits children to wrap to a new line if they exceed the bounds of their
+-- parent
+wrapped :: Children a -> Children a
+wrapped (Wrap xs) = Wrap xs
+wrapped childs = childs
+
+justifiedContainer :: CUInt -> [Layout a] -> a -> Layout a
+justifiedContainer just cs x = Layout $ do
+  ptr <- c'YGNodeNew
+  c'YGNodeStyleSetJustifyContent ptr just
+  c'YGNodeStyleSetFlexWrap ptr c'YGWrapNoWrap
+
+  cs' <- forM cs $ \node -> do
+    nodeTree <- generateLayout node
+    case nodeTree of
+      Root p children fptr -> withForeignPtr fptr $ \oldptr -> do
+        newptr <- c'YGNodeClone oldptr
+        c'YGNodeInsertChild ptr newptr 0
+        return $ if null children
+                 then Leaf p
+                 else Container p children
+      _ -> error "Internal: expected root node"
+  Root x cs' <$> newForeignPtr p'YGNodeFreeRecursive ptr
+
+assembleChildren :: Children a -> a -> Layout a
+assembleChildren (StartToEnd cs) x = justifiedContainer c'YGJustifyFlexStart cs x
+assembleChildren (EndToStart cs) x = justifiedContainer c'YGJustifyFlexEnd cs x
+assembleChildren (Centered cs) x = justifiedContainer c'YGJustifyCenter cs x
+assembleChildren (SpaceBetween cs) x =
+  justifiedContainer c'YGJustifySpaceBetween cs x
+assembleChildren (SpaceAround cs) x =
+  justifiedContainer c'YGJustifySpaceAround cs x
+assembleChildren (Wrap cs) x = wrapContainer $ assembleChildren cs x
+  where
+    wrapContainer :: Layout a -> Layout a
+    wrapContainer lyt = Layout $ do
+      lytTree <- generateLayout lyt
+      withNativePtr lytTree $ \ptr ->
+        c'YGNodeStyleSetFlexWrap ptr c'YGWrapWrap
+      return lytTree
+
+setContainerDirection :: CUInt -> CUInt -> LayoutTree a -> IO ()
+setContainerDirection dir flexDir lyt =
+  withNativePtr lyt $ \ptr -> do
+    c'YGNodeStyleSetDirection ptr dir
+    c'YGNodeStyleSetFlexDirection ptr flexDir
+
+-- | Generates a layout from a group of children and a payload such that the
+-- children are laid out horizontally. The orientation (RTL vs LTR) is
+-- inherited from the parent
+hbox :: Children a -> a -> Layout a
+hbox cs x = Layout $ do
+  node <- generateLayout $ assembleChildren cs x
+  setContainerDirection c'YGDirectionInherit c'YGFlexDirectionRow node
+  return node
+
+-- | Generates a layout from a group of children and a payload such that the
+-- children are laid out vertically. The orientation (top to bottom vs bottom to
+-- top) is inherited from the parent.
+vbox :: Children a -> a -> Layout a
+vbox cs x = Layout $ do
+  node <- generateLayout $ assembleChildren cs x
+  setContainerDirection c'YGDirectionInherit c'YGFlexDirectionColumn node
+  return node
+
+-- | Generates a layout from a group of children and a payload such that the
+-- children are laid out horizontally from left to right.
+hboxLeftToRight :: Children a -> a -> Layout a
+hboxLeftToRight cs x = Layout $ do
+  node <- generateLayout $ assembleChildren cs x
+  setContainerDirection c'YGDirectionLTR c'YGFlexDirectionRow node
+  return node
+
+-- | Generates a layout from a group of children and a payload such that the
+-- children are laid out horizontally from right to left.
+hboxRightToLeft :: Children a -> a -> Layout a
+hboxRightToLeft cs x = Layout $ do
+  node <- generateLayout $ assembleChildren cs x
+  setContainerDirection c'YGDirectionRTL c'YGFlexDirectionRow node
+  return node
+
+-- | Generates a layout from a group of children and a payload such that the
+-- children are laid out vertically from top to bottom.
+vboxTopToBottom :: Children a -> a -> Layout a
+vboxTopToBottom cs x = Layout $ do
+  node <- generateLayout $ assembleChildren cs x
+  setContainerDirection c'YGDirectionLTR c'YGFlexDirectionColumn node
+  return node
+
+-- | Generates a layout from a group of children and a payload such that the
+-- children are laid out vertically from bottom to top.
+vboxBottomToTop :: Children a -> a -> Layout a
+vboxBottomToTop cs x = Layout $ do
+  node <- generateLayout $ assembleChildren cs x
+  setContainerDirection c'YGDirectionRTL c'YGFlexDirectionColumn node
+  return node
+
+-- | A 'Size' is used to set properties about given layouts. In general, the
+-- width and height of a node along with its position are laid out by Yoga's
+-- internal layout engine. However, the user may decide to set limits on how
+-- much internal nodes can shrink or grow. This datatype controls those
+-- properties
+data Size
+  = Exact Float
+  | Min Float
+  | Max Float
+  | Range Float Float
+    deriving (Read, Show, Eq, Ord)
+
+setWidth :: Size -> LayoutTree a -> IO ()
+setWidth (Exact w) lyt =
+  withNativePtr lyt $ \ptr -> c'YGNodeStyleSetWidth ptr $ realToFrac w
+setWidth (Min w) lyt =
+  withNativePtr lyt $ \ptr -> c'YGNodeStyleSetMinWidth ptr $ realToFrac w
+setWidth (Max w) lyt =
+  withNativePtr lyt $ \ptr -> c'YGNodeStyleSetMaxWidth ptr $ realToFrac w
+setWidth (Range minWidth maxWidth) lyt =
+  withNativePtr lyt $ \ptr -> do
+    c'YGNodeStyleSetMinWidth ptr $ realToFrac minWidth
+    c'YGNodeStyleSetMaxWidth ptr $ realToFrac maxWidth
+
+setHeight :: Size -> LayoutTree a -> IO ()
+setHeight (Exact h) lyt =
+  withNativePtr lyt $ \ptr -> c'YGNodeStyleSetHeight ptr $ realToFrac h
+setHeight (Min h) lyt =
+  withNativePtr lyt $ \ptr -> c'YGNodeStyleSetMinHeight ptr $ realToFrac h
+setHeight (Max h) lyt =
+  withNativePtr lyt $ \ptr -> c'YGNodeStyleSetMaxHeight ptr $ realToFrac h
+setHeight (Range minHeight maxHeight) lyt =
+  withNativePtr lyt $ \ptr -> do
+    c'YGNodeStyleSetMinHeight ptr $ realToFrac minHeight
+    c'YGNodeStyleSetMaxHeight ptr $ realToFrac maxHeight
+
+-- | Specifies layout may shrink up to the given size. The weight parameter
+-- is used to determine how much this layout will shrink in relation to any
+-- siblings.
+shrinkable :: Float -> Size -> Size -> Layout a -> Layout a
+shrinkable weight width height lyt = Layout $ do
+  n <- generateLayout lyt
+  setWidth width n
+  setHeight height n
+  withNativePtr n $ \ptr -> c'YGNodeStyleSetFlexShrink ptr $ realToFrac weight
+  return n
+
+-- | Specifies layout may grow up to the given size. The weight parameter
+-- is used to determine how much this layout will grow in relation to any
+-- siblings.
+growable :: Float -> Size -> Size -> Layout a -> Layout a
+growable weight width height lyt = Layout $ do
+  n <- generateLayout lyt
+  setWidth width n
+  setHeight height n
+  withNativePtr n $ \ptr -> c'YGNodeStyleSetFlexGrow ptr $ realToFrac weight
+  return n
+
+-- | Creates a layout with the exact width and height for the given payload.
+exact :: Float -> Float -> a -> Layout a
+exact width height x = Layout $ do
+  n <- generateLayout $ mkNode x
+  setWidth (Exact width) n
+  setHeight (Exact height) n
+  return n
+
+-- | Specifies the exact dimensions expected for a layout. Can be used for
+-- containers and such when there is not necessarily any rendering involved. 
+withDimensions :: Float -> Float -> Layout b -> Layout b
+withDimensions width height lyt = Layout $ do
+  n <- generateLayout lyt
+  setWidth (Exact width) n
+  setHeight (Exact height) n
+  return n
+
+-- | Allows a container to stretch to fit its parent
+stretched :: Layout a -> Layout a
+stretched lyt = Layout $ do
+  node <- generateLayout lyt
+  withNativePtr node $ \ptr -> c'YGNodeStyleSetAlignSelf ptr c'YGAlignStretch
+  return node
+
+-- | Edges are used to describe the direction from which we want to alter an
+-- attribute of a node.
+data Edge
+  = Edge'Left
+  | Edge'Top
+  | Edge'Right
+  | Edge'Bottom
+  | Edge'Start
+  | Edge'End
+  | Edge'Horizontal
+  | Edge'Vertical
+  | Edge'All
+  deriving (Eq, Ord, Bounded, Enum, Read, Show)
+
+edgeToCEdge :: Edge -> CUInt
+edgeToCEdge Edge'Left = c'YGEdgeLeft
+edgeToCEdge Edge'Top = c'YGEdgeTop
+edgeToCEdge Edge'Right = c'YGEdgeRight
+edgeToCEdge Edge'Bottom = c'YGEdgeBottom
+edgeToCEdge Edge'Start = c'YGEdgeStart
+edgeToCEdge Edge'End = c'YGEdgeEnd
+edgeToCEdge Edge'Horizontal = c'YGEdgeHorizontal
+edgeToCEdge Edge'Vertical = c'YGEdgeVertical
+edgeToCEdge Edge'All = c'YGEdgeAll
+
+-- | Overrides the margin for a layout with the given margin.
+setMargin :: Edge -> Float -> Layout a -> Layout a
+setMargin = setMargin' . edgeToCEdge
+  where
+    setMargin' edge px lyt = Layout $ do
+      node <- generateLayout lyt
+      withNativePtr node $ \ptr ->
+          c'YGNodeStyleSetMargin ptr edge $ realToFrac px
+      return node
+
+-- | Overrides the padding for a layout with the given padding.
+setPadding :: Edge -> Float -> Layout a -> Layout a
+setPadding = setPadding' . edgeToCEdge
+  where
+    setPadding' edge px lyt = Layout $ do
+      node <- generateLayout lyt
+      withNativePtr node $ \ptr ->
+        c'YGNodeStyleSetPadding ptr edge $ realToFrac px
+      return node
+
+-- | Overrides the border for a layout with the given border.
+setBorder :: Edge -> Float -> Layout a -> Layout a
+setBorder = setBorder' . edgeToCEdge
+  where
+    setBorder' edge px lyt = Layout $ do
+      node <- generateLayout lyt
+      withNativePtr node $ \ptr ->
+        c'YGNodeStyleSetBorder ptr edge $ realToFrac px
+      return node
+
+-- | Gutters are used to denote the size of a gap between elements.
+data Gutter
+  = Gutter'Column
+  | Gutter'Row
+  | Gutter'All
+  deriving (Eq, Ord, Bounded, Enum, Read, Show)
+
+-- | Overrides the gaps for a layout with the given gap size.
+setGap :: Gutter -> Float -> Layout a -> Layout a
+setGap = setGap' . gapToCGap
+  where
+    gapToCGap Gutter'Column = c'YGGutterColumn
+    gapToCGap Gutter'Row = c'YGGutterRow
+    gapToCGap Gutter'All = c'YGGutterAll
+
+    setGap' gutter px lyt = Layout $ do
+      node <- generateLayout lyt
+      withNativePtr node $ \ptr ->
+        c'YGNodeStyleSetGap ptr gutter $ realToFrac px
+      return node
+
+--------------------------------------------------------------------------------
+-- Rendering
+
+-- | Stores the calculated layout information for a given node. During
+-- rendering, the rendering function will take the payload and layout info to
+-- facilitate the renderer to do whatever it needs to with the given layout
+-- calculations.
+data LayoutInfo = LayoutInfo {
+  nodeTop :: Float,     -- ^ The y-coordinate of this node
+  nodeLeft :: Float,    -- ^ The x-coordinate of this node
+  nodeWidth :: Float,   -- ^ The width of this node
+  nodeHeight :: Float   -- ^ The height of this node
+} deriving (Eq, Show)
+
+emptyInfo :: LayoutInfo
+emptyInfo = LayoutInfo 0 0 0 0
+
+layoutWithParent :: LayoutInfo -> LayoutInfo -> LayoutInfo
+layoutWithParent parent child =
+  let (x, y) = (nodeLeft parent, nodeTop parent)
+      (x', y') = (nodeLeft child, nodeTop child)
+  in child { nodeLeft = x + x', nodeTop = y + y' }
+
+-- | A 'RenderFn' takes a top-left position and a width and height of a node
+-- with the given payload. The function is expected to perform some monadic
+-- action in the 'Monad' m, and return a new payload of type b. This function is
+-- called on each node in order during a call to render.
+type RenderFn m a b = LayoutInfo -> a -> m b
+
+calculateLayout :: Ptr C'YGNode -> IO ()
+calculateLayout ptr =
+  let n = (nan :: CFloat)
+  in c'YGNodeStyleGetDirection ptr >>= c'YGNodeCalculateLayout ptr n n
+
+layoutInfo :: Ptr C'YGNode -> IO LayoutInfo
+layoutInfo ptr = do
+  left <- realToFrac <$> c'YGNodeLayoutGetLeft ptr
+  top <- realToFrac <$> c'YGNodeLayoutGetTop ptr
+  width <- realToFrac <$> c'YGNodeLayoutGetWidth ptr
+  height <- realToFrac <$> c'YGNodeLayoutGetHeight ptr
+  return $ LayoutInfo top left width height
+
+renderNodeWithChildren :: (MonadIO m, Monoid b) =>
+                          LayoutInfo -> a -> [LayoutTree a] -> Ptr C'YGNode
+                          -> RenderFn m a (b, c)
+                          -> m (b, c, [LayoutTree c])
+renderNodeWithChildren parentInfo x children ptr f = do
+  info <- liftIO $ layoutInfo ptr
+  let thisInfo = layoutWithParent parentInfo info
+  (m, y) <- f thisInfo x
+  cs <- forM (zip children [0..]) $ \(child, childIdx) -> do
+    childPtr <- liftIO $ c'YGNodeGetChild ptr childIdx
+    foldRenderTree thisInfo child childPtr f
+  return (mappend m . foldr (mappend . fst) mempty $ cs, y, map snd cs)
+
+foldRenderTree :: (MonadIO m, Monoid b) =>
+                  LayoutInfo -> LayoutTree a -> Ptr C'YGNode -> RenderFn m a (b, c) ->
+                  m (b, LayoutTree c)
+foldRenderTree parentInfo (Root x children fptr) ptr f = do
+  (result, y, cs) <- renderNodeWithChildren parentInfo x children ptr f
+  return (result, Root y cs fptr)
+foldRenderTree parentInfo (Container x children) ptr f = do
+  (result, y, cs) <- renderNodeWithChildren parentInfo x children ptr f
+  return (result, Container y cs)
+foldRenderTree parentInfo (Leaf x) ptr f = do
+  (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
+-- node. The second result is stored as the new payload for the given node.
+-- Hence, the resulting monadic action produces a 'mappend'-ed set of 'b's and
+-- a new layout with payloads of type 'c'.
+foldRender :: (MonadIO m, Monoid b) =>
+              Layout a -> RenderFn m a (b, c) -> m (b, Layout c)
+foldRender lyt f = do
+  node <- liftIO $ generateLayout lyt
+  case node of
+    Root _ _ fptr -> do
+      rootPtr <- liftIO $ withForeignPtr fptr $ \ptr -> do
+        calculateLayout ptr
+        return ptr
+      (bs, tree) <- foldRenderTree emptyInfo node rootPtr f
+      return (bs, Layout $ return tree)
+    _ -> error "Internal: Rendering must be done from the root node"
+
+-- | Renders a layout with the user-supplied function. The renderer traverses
+-- the tree from root node to children and transforms each payload using the
+-- user-supplied function.
+render :: MonadIO m => Layout a -> RenderFn m a b -> m (Layout b)
+render lyt f =
+  let f' lytInfo x = (() ,) <$> f lytInfo x
+  in snd <$> foldRender lyt f'
+ test/Bindings/YogaSpec.hs view
@@ -0,0 +1,91 @@+module Bindings.YogaSpec where
+
+import Test.Hspec
+import Control.Monad.IO.Class
+import Foreign.Ptr (Ptr)
+import Foreign.Storable (peek)
+import Control.Exception (bracket)
+
+import Bindings.Yoga
+import Bindings.Yoga.Enums
+
+withNode :: MonadIO m => (Ptr C'YGNode -> IO a) -> m a 
+withNode f = liftIO $ bracket c'YGNodeNew c'YGNodeFree f
+
+withValue :: MonadIO m => IO (Ptr C'YGValue) -> (Ptr C'YGValue -> IO a) -> m a
+withValue m f = liftIO $ bracket m c'YGValueFree f
+
+spec :: Spec
+spec = do
+    describe "YGNodeStyleGetFlexBasisWrapper" $
+        it "wraps YGNodeStyleGetFlexBasis as intended" $ do
+            flexBasis <- withNode $ \node -> do
+                c'YGNodeStyleSetFlexBasis node 100.0
+                withValue (c'YGNodeStyleGetFlexBasisWrapper node) peek
+            c'YGValue'value flexBasis `shouldBe` 100.0
+
+    describe "YGNodeStyleGetPositionWrapper" $
+        it "wraps YGNodeStyleGetPosition as intended" $ do
+            position <- withNode $ \node -> do
+                c'YGNodeStyleSetPosition node c'YGEdgeLeft 150.0
+                withValue (c'YGNodeStyleGetPositionWrapper node c'YGEdgeLeft) peek
+            c'YGValue'value position `shouldBe` 150.0
+
+    describe "YGNodeStyleGetMarginWrapper" $
+        it "wraps YGNodeStyleGetMargin as intended" $ do
+            margin <- withNode $ \node -> do
+                c'YGNodeStyleSetMargin node c'YGEdgeLeft 250.0
+                withValue (c'YGNodeStyleGetMarginWrapper node c'YGEdgeLeft) peek
+            c'YGValue'value margin `shouldBe` 250.0
+
+    describe "YGNodeStyleGetPaddingWrapper" $
+        it "wraps YGNodeStyleGetPadding as intended" $ do
+            padding <- withNode $ \node -> do
+                c'YGNodeStyleSetPadding node c'YGEdgeLeft 125.0
+                withValue (c'YGNodeStyleGetPaddingWrapper node c'YGEdgeLeft) peek
+            c'YGValue'value padding `shouldBe` 125.0
+
+    describe "YGNodeStyleGetWidthWrapper" $
+        it "wraps YGNodeStyleGetWidth as intended" $ do
+            width <- withNode $ \node -> do
+                c'YGNodeStyleSetWidth node 125.0
+                withValue (c'YGNodeStyleGetWidthWrapper node) peek
+            c'YGValue'value width `shouldBe` 125.0
+
+    describe "YGNodeStyleGetHeightWrapper" $
+        it "wraps YGNodeStyleGetHeight as intended" $ do
+            height <- withNode $ \node -> do
+                c'YGNodeStyleSetHeight node 125.0
+                withValue (c'YGNodeStyleGetHeightWrapper node) peek
+            c'YGValue'value height `shouldBe` 125.0
+
+    describe "YGNodeStyleGetMinWidthWrapper" $
+        it "wraps YGNodeStyleGetMinWidth as intended" $ do
+            minWidth <- withNode $ \node -> do
+                c'YGNodeStyleSetMinWidth node 125.0
+                withValue (c'YGNodeStyleGetMinWidthWrapper node) peek
+            c'YGValue'value minWidth `shouldBe` 125.0
+
+    describe "YGNodeStyleGetMinHeightWrapper" $
+        it "wraps YGNodeStyleGetMinHeight as intended" $ do
+            minHeight <- withNode $ \node -> do
+                c'YGNodeStyleSetMinHeight node 125.0
+                withValue (c'YGNodeStyleGetMinHeightWrapper node) peek
+            c'YGValue'value minHeight `shouldBe` 125.0
+
+    describe "YGNodeStyleGetMaxWidthWrapper" $
+        it "wraps YGNodeStyleGetMaxWidth as intended" $ do
+            maxWidth <- withNode $ \node -> do
+                c'YGNodeStyleSetMaxWidth node 125.0
+                withValue (c'YGNodeStyleGetMaxWidthWrapper node) peek
+            c'YGValue'value maxWidth `shouldBe` 125.0
+
+    describe "YGNodeStyleGetMaxHeightWrapper" $
+        it "wraps YGNodeStyleGetMaxHeight as intended" $ do
+            maxHeight <- withNode $ \node -> do
+                c'YGNodeStyleSetMaxHeight node 125.0
+                withValue (c'YGNodeStyleGetMaxHeightWrapper node) peek
+            c'YGValue'value maxHeight `shouldBe` 125.0
+
+main :: IO ()
+main = hspec spec
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
yoga.cabal view
@@ -1,100 +1,171 @@--- Initial yoga.cabal generated by cabal init.  For further documentation, --- see http://haskell.org/cabal/users-guide/--name:                yoga-version:             0.0.0.5-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-                     written in C that implements flexbox. There are two-                     main ways to interface with these bindings. The high-level-                     bindings are stored in the Yoga module and provide a more-                     Haskell-like interface to the library. The other option is to-                     directly use the C-level bindings in "Bindings.Yoga". If you do-                     so you do so at your own risk (i.e. you must manage your own-                     memory).--                     The examples are not built nor included by default. Please-                     refer to the source tarball for examples on how to use this-                     library.--                     These bindings are not affiliated with Facebook in any way,-                     and have been developed separately for the sole purpose of-                     interfacing with their open source library.-license:             BSD3-license-file:        LICENSE-author:              Pavel Krajcevski-maintainer:          Krajcevski@gmail.com-copyright:           2017-present-category:            Graphics-build-type:          Simple-cabal-version:       >=1.10--source-repository head-  type:           git-  location:       https://www.github.com/Mokosha/yoga-hs.git--library-  default-language: Haskell2010-  hs-source-dirs:      lib--  ghc-options: -Wall-  if impl(ghc >= 8.0)-    ghc-options: -Wno-redundant-constraints-  if impl(ghc >= 6.8)-    ghc-options: -fwarn-tabs-  build-tools:      hsc2hs-  include-dirs:     yoga/-  install-includes: YGEnums.h-                    YGMacros.h-                    YGNodePrint.h-                    YGConfig.h-                    YGFloatOptional.h-                    YGLayout.h-                    YGNode.h-                    YGStyle.h-                    Yoga.h-                    Yoga-internal.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=0 -std=c++11-  extra-libraries:  stdc++--  exposed-modules:-    Bindings.Yoga-    Yoga--  other-modules:-    Bindings.Yoga.Enums--  build-depends:-    base            >= 4     && < 6,-    ieee754         >= 0.7,-    bindings-DSL--flag                 examples-  description:       Build examples-  default:           False--executable yoga-example-  default-language: Haskell2010-  main-is:        Main.hs-  hs-source-dirs: examples-  ghc-options:    -Wall -rtsopts -O3-  build-depends:  base          >  4,-                  yoga--  if flag(examples)-    buildable:    True-  else-    buildable:    False+cabal-version:       2.2
+-- Initial yoga.cabal generated by cabal init.  For further documentation, 
+-- see http://haskell.org/cabal/users-guide/
+
+name:                yoga
+version:             0.0.0.7
+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
+                     written in C that implements flexbox. There are two
+                     main ways to interface with these bindings. The high-level
+                     bindings are stored in the Yoga module and provide a more
+                     Haskell-like interface to the library. The other option is to
+                     directly use the C-level bindings in "Bindings.Yoga". If you do
+                     so you do so at your own risk (i.e. you must manage your own
+                     memory).
+
+                     The examples are not built nor included by default. Please
+                     refer to the source tarball for examples on how to use this
+                     library.
+
+                     These bindings are not affiliated with Facebook in any way,
+                     and have been developed separately for the sole purpose of
+                     interfacing with their open source library.
+license:             BSD-3-Clause
+license-file:        LICENSE
+author:              Pavel Krajcevski
+maintainer:          Krajcevski@gmail.com
+copyright:           2017-present
+category:            Graphics
+build-type:          Simple
+
+source-repository head
+  type:           git
+  location:       https://www.github.com/Mokosha/yoga-hs.git
+
+library
+  default-language: Haskell2010
+  hs-source-dirs:      lib
+
+  ghc-options: -Wall
+  if impl(ghc >= 8.0)
+    ghc-options:      -Wno-redundant-constraints
+  if impl(ghc >= 6.8)
+    ghc-options:      -fwarn-tabs
+  build-tool-depends: hsc2hs:hsc2hs >= 0.68
+  include-dirs:       yoga/
+                    , yoga/yoga/
+  install-includes:   YGConfig.h
+                      YGEnums.h
+                      YGMacros.h
+                      YGNode.h
+                      YGNodeLayout.h
+                      YGNodeStyle.h
+                      YGPixelGrid.h
+                      YGValue.h
+                      algorithm/AbsoluteLayout.h
+                      algorithm/Align.h
+                      algorithm/Baseline.h
+                      algorithm/BoundAxis.h
+                      algorithm/Cache.h
+                      algorithm/CalculateLayout.h
+                      algorithm/FlexDirection.h
+                      algorithm/FlexLine.h
+                      algorithm/PixelGrid.h
+                      algorithm/SizingMode.h
+                      algorithm/TrailingPosition.h
+                      config/Config.h
+                      debug/AssertFatal.h
+                      debug/Log.h
+                      debug/NodeToString.h
+                      enums/Align.h
+                      enums/Dimension.h
+                      enums/Direction.h
+                      enums/Display.h
+                      enums/Edge.h
+                      enums/Errata.h
+                      enums/ExperimentalFeature.h
+                      enums/FlexDirection.h
+                      enums/Gutter.h
+                      enums/Justify.h
+                      enums/LogLevel.h
+                      enums/MeasureMode.h
+                      enums/NodeType.h
+                      enums/Overflow.h
+                      enums/PositionType.h
+                      enums/PrintOptions.h
+                      enums/Unit.h
+                      enums/Wrap.h
+                      enums/YogaEnums.h
+                      event/event.h
+                      node/CachedMeasurement.h
+                      node/LayoutResults.h
+                      node/Node.h
+                      numeric/Comparison.h
+                      numeric/FloatOptional.h
+                      style/CompactValue.h
+                      style/Style.h
+                      style/StyleLength.h
+                      Yoga.h 
+
+  c-sources:          lib/Bindings/glue.c
+  cxx-sources:        yoga/yoga/YGConfig.cpp
+                      yoga/yoga/YGEnums.cpp
+                      yoga/yoga/YGNode.cpp
+                      yoga/yoga/YGNodeLayout.cpp
+                      yoga/yoga/YGNodeStyle.cpp
+                      yoga/yoga/YGPixelGrid.cpp
+                      yoga/yoga/YGValue.cpp
+                      yoga/yoga/algorithm/AbsoluteLayout.cpp
+                      yoga/yoga/algorithm/Baseline.cpp
+                      yoga/yoga/algorithm/Cache.cpp
+                      yoga/yoga/algorithm/CalculateLayout.cpp
+                      yoga/yoga/algorithm/FlexLine.cpp
+                      yoga/yoga/algorithm/PixelGrid.cpp
+                      yoga/yoga/config/Config.cpp
+                      yoga/yoga/debug/AssertFatal.cpp
+                      yoga/yoga/debug/Log.cpp
+                      yoga/yoga/debug/NodeToString.cpp
+                      yoga/yoga/event/event.cpp
+                      yoga/yoga/node/LayoutResults.cpp
+                      yoga/yoga/node/Node.cpp
+
+  cxx-options:        -fno-omit-frame-pointer
+                      -fexceptions
+                      -fvisibility=hidden
+                      -ffunction-sections
+                      -fdata-sections
+                      -std=c++20
+                      -DYG_ENABLE_EVENTS
+
+  extra-libraries:    stdc++
+
+  exposed-modules:
+    Bindings.Yoga
+    Bindings.Yoga.Enums
+    Yoga
+
+  build-depends:
+    base            >= 4     && < 6,
+    ieee754         >= 0.7,
+    bindings-DSL
+
+flag                 examples
+  description:       Build examples
+  default:           False
+
+executable yoga-example
+  default-language: Haskell2010
+  main-is:          Main.hs
+  hs-source-dirs:   examples
+  ghc-options:      -Wall -rtsopts -O3
+  build-depends:    base          >  4,
+                    yoga
+
+  if flag(examples)
+    buildable:    True
+  else
+    buildable:    False
+
+test-suite spec
+  default-language:    Haskell2010
+  hs-source-dirs:      test
+  type:                exitcode-stdio-1.0
+  main-is:             Spec.hs
+  other-modules:       Bindings.YogaSpec
+  build-tool-depends:  hspec-discover:hspec-discover
+  build-depends:       base > 4,
+                       hspec >= 2.7,
+                       hspec-discover >= 2.7,
+                       yoga
− yoga/Utils.cpp
@@ -1,70 +0,0 @@-/*- *  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;-}
− yoga/Utils.h
@@ -1,148 +0,0 @@-/**- * 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);-}
− yoga/YGConfig.cpp
@@ -1,22 +0,0 @@-/*- *  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) {}
− yoga/YGConfig.h
@@ -1,24 +0,0 @@-/*- *  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);-};
− yoga/YGEnums.cpp
@@ -1,226 +0,0 @@-/**- * 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";-}
− yoga/YGEnums.h
@@ -1,155 +0,0 @@-/**- * 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
− yoga/YGFloatOptional.cpp
@@ -1,84 +0,0 @@-/*- *  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;-}
− yoga/YGFloatOptional.h
@@ -1,44 +0,0 @@-/*- *  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;-};
− yoga/YGLayout.cpp
@@ -1,63 +0,0 @@-/*- *  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;-}
− yoga/YGLayout.h
@@ -1,44 +0,0 @@-/*- *  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);-  }-};
− yoga/YGMacros.h
@@ -1,41 +0,0 @@-/**- * 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
− yoga/YGNode.cpp
@@ -1,554 +0,0 @@-/*- *  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;-}
− yoga/YGNode.h
@@ -1,273 +0,0 @@-/*- *  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;-};
− yoga/YGNodePrint.cpp
@@ -1,231 +0,0 @@-/*- * 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
− yoga/YGNodePrint.h
@@ -1,22 +0,0 @@-/**- * 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
− yoga/YGStyle.cpp
@@ -1,100 +0,0 @@-/*- *  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;-}
− yoga/YGStyle.h
@@ -1,47 +0,0 @@-/*- *  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"-#include "Yoga.h"--struct YGStyle {-  using Dimensions = std::array<YGValue, 2>;--  YGDirection direction;-  YGFlexDirection flexDirection;-  YGJustify justifyContent;-  YGAlign alignContent;-  YGAlign alignItems;-  YGAlign alignSelf;-  YGPositionType positionType;-  YGWrap flexWrap;-  YGOverflow overflow;-  YGDisplay display;-  YGFloatOptional flex;-  YGFloatOptional flexGrow;-  YGFloatOptional flexShrink;-  YGValue flexBasis;-  std::array<YGValue, YGEdgeCount> margin;-  std::array<YGValue, YGEdgeCount> position;-  std::array<YGValue, YGEdgeCount> padding;-  std::array<YGValue, YGEdgeCount> border;-  Dimensions dimensions;-  Dimensions minDimensions;-  Dimensions maxDimensions;-  // Yoga specific properties, not compatible with flexbox specification-  YGFloatOptional aspectRatio;--  YGStyle();-  bool operator==(const YGStyle& style);--  bool operator!=(YGStyle style) {-    return !(*this == style);-  }-  ~YGStyle() = default;-};
− yoga/Yoga-internal.h
@@ -1,120 +0,0 @@-/*- *  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);
− yoga/Yoga.cpp
@@ -1,4316 +0,0 @@-/*- *  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);-}
− yoga/Yoga.h
@@ -1,462 +0,0 @@-/*- *  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
+ yoga/yoga/YGConfig.cpp view
@@ -0,0 +1,96 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>
+#include <yoga/debug/AssertFatal.h>
+#include <yoga/debug/Log.h>
+
+using namespace facebook;
+using namespace facebook::yoga;
+
+YGConfigRef YGConfigNew(void) {
+  return new yoga::Config(getDefaultLogger());
+}
+
+void YGConfigFree(const YGConfigRef config) {
+  delete resolveRef(config);
+}
+
+YGConfigConstRef YGConfigGetDefault() {
+  return &yoga::Config::getDefault();
+}
+
+void YGConfigSetUseWebDefaults(const YGConfigRef config, const bool enabled) {
+  resolveRef(config)->setUseWebDefaults(enabled);
+}
+
+bool YGConfigGetUseWebDefaults(const YGConfigConstRef config) {
+  return resolveRef(config)->useWebDefaults();
+}
+
+void YGConfigSetPointScaleFactor(
+    const YGConfigRef config,
+    const float pixelsInPoint) {
+  yoga::assertFatalWithConfig(
+      resolveRef(config),
+      pixelsInPoint >= 0.0f,
+      "Scale factor should not be less than zero");
+
+  resolveRef(config)->setPointScaleFactor(pixelsInPoint);
+}
+
+float YGConfigGetPointScaleFactor(const YGConfigConstRef config) {
+  return resolveRef(config)->getPointScaleFactor();
+}
+
+void YGConfigSetErrata(YGConfigRef config, YGErrata errata) {
+  resolveRef(config)->setErrata(scopedEnum(errata));
+}
+
+YGErrata YGConfigGetErrata(YGConfigConstRef config) {
+  return unscopedEnum(resolveRef(config)->getErrata());
+}
+
+void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) {
+  if (logger != nullptr) {
+    resolveRef(config)->setLogger(logger);
+  } else {
+    resolveRef(config)->setLogger(getDefaultLogger());
+  }
+}
+
+void YGConfigSetContext(const YGConfigRef config, void* context) {
+  resolveRef(config)->setContext(context);
+}
+
+void* YGConfigGetContext(const YGConfigConstRef config) {
+  return resolveRef(config)->getContext();
+}
+
+void YGConfigSetExperimentalFeatureEnabled(
+    const YGConfigRef config,
+    const YGExperimentalFeature feature,
+    const bool enabled) {
+  resolveRef(config)->setExperimentalFeatureEnabled(
+      scopedEnum(feature), enabled);
+}
+
+bool YGConfigIsExperimentalFeatureEnabled(
+    const YGConfigConstRef config,
+    const YGExperimentalFeature feature) {
+  return resolveRef(config)->isExperimentalFeatureEnabled(scopedEnum(feature));
+}
+
+void YGConfigSetCloneNodeFunc(
+    const YGConfigRef config,
+    const YGCloneNodeFunc callback) {
+  resolveRef(config)->setCloneNodeCallback(callback);
+}
+
+void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled) {
+  resolveRef(config)->setShouldPrintTree(enabled);
+}
+ yoga/yoga/YGConfig.h view
@@ -0,0 +1,163 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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 <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#include <yoga/YGEnums.h>
+#include <yoga/YGMacros.h>
+
+YG_EXTERN_C_BEGIN
+
+typedef struct YGNode* YGNodeRef;
+typedef const struct YGNode* YGNodeConstRef;
+
+/**
+ * Handle to a mutable Yoga configuration.
+ */
+typedef struct YGConfig* YGConfigRef;
+
+/**
+ * Handle to an immutable Yoga configruation.
+ */
+typedef const struct YGConfig* YGConfigConstRef;
+
+/**
+ * Allocates a set of configuration options. The configuration may be applied to
+ * multiple nodes (i.e. a single global config), or can be applied more
+ * granularly per-node.
+ */
+YG_EXPORT YGConfigRef YGConfigNew(void);
+
+/**
+ * Frees the associated Yoga configuration.
+ */
+YG_EXPORT void YGConfigFree(YGConfigRef config);
+
+/**
+ * Returns the default config values set by Yoga.
+ */
+YG_EXPORT YGConfigConstRef YGConfigGetDefault(void);
+
+/**
+ * Yoga by default creates new nodes with style defaults different from flexbox
+ * on web (e.g. `YGFlexDirectionColumn` and `YGPositionRelative`).
+ * `UseWebDefaults` instructs Yoga to instead use a default style consistent
+ * with the web.
+ */
+YG_EXPORT void YGConfigSetUseWebDefaults(YGConfigRef config, bool enabled);
+
+/**
+ * Whether the configuration is set to use web defaults.
+ */
+YG_EXPORT bool YGConfigGetUseWebDefaults(YGConfigConstRef config);
+
+/**
+ * Yoga will by deafult round final layout positions and dimensions to the
+ * nearst point. `pointScaleFactor` controls the density of the grid used for
+ * layout rounding (e.g. to round to the closest display pixel).
+ *
+ * May be set to 0.0f to avoid rounding the layout results.
+ */
+YG_EXPORT void YGConfigSetPointScaleFactor(
+    YGConfigRef config,
+    float pixelsInPoint);
+
+/**
+ * Get the currently set point scale factor.
+ */
+YG_EXPORT float YGConfigGetPointScaleFactor(YGConfigConstRef config);
+
+/**
+ * Configures how Yoga balances W3C conformance vs compatibility with layouts
+ * created against earlier versions of Yoga.
+ *
+ * By deafult Yoga will prioritize W3C conformance. `Errata` may be set to ask
+ * Yoga to produce specific incorrect behaviors. E.g. `YGConfigSetErrata(config,
+ * YGErrataPositionStaticBehavesLikeRelative)`.
+ *
+ * YGErrata is a bitmask, and multiple errata may be set at once. Predfined
+ * constants exist for convenience:
+ * 1. YGErrataNone: No errata
+ * 2. YGErrataClassic: Match layout behaviors of Yoga 1.x
+ * 3. YGErrataAll: Match layout behaviors of Yoga 1.x, including
+ * `UseLegacyStretchBehaviour`
+ */
+YG_EXPORT void YGConfigSetErrata(YGConfigRef config, YGErrata errata);
+
+/**
+ * Get the currently set errata.
+ */
+YG_EXPORT YGErrata YGConfigGetErrata(YGConfigConstRef config);
+
+/**
+ * Function pointer type for YGConfigSetLogger.
+ */
+typedef int (*YGLogger)(
+    YGConfigConstRef config,
+    YGNodeConstRef node,
+    YGLogLevel level,
+    const char* format,
+    va_list args);
+
+/**
+ * Set a custom log function for to use when logging diagnostics or fatal.
+ * errors.
+ */
+YG_EXPORT void YGConfigSetLogger(YGConfigRef config, YGLogger logger);
+
+/**
+ * Sets an arbitrary context pointer on the config which may be read from during
+ * callbacks.
+ */
+YG_EXPORT void YGConfigSetContext(YGConfigRef config, void* context);
+
+/**
+ * Gets the currently set context.
+ */
+YG_EXPORT void* YGConfigGetContext(YGConfigConstRef config);
+
+/**
+ * Function pointer type for YGConfigSetCloneNodeFunc.
+ */
+typedef YGNodeRef (*YGCloneNodeFunc)(
+    YGNodeConstRef oldNode,
+    YGNodeConstRef owner,
+    size_t childIndex);
+
+/**
+ * Enable an experimental/unsupported feature in Yoga.
+ */
+YG_EXPORT void YGConfigSetExperimentalFeatureEnabled(
+    YGConfigRef config,
+    YGExperimentalFeature feature,
+    bool enabled);
+
+/**
+ * Whether an experimental feature is set.
+ */
+YG_EXPORT bool YGConfigIsExperimentalFeatureEnabled(
+    YGConfigConstRef config,
+    YGExperimentalFeature feature);
+
+/**
+ * Sets a callback, called during layout, to create a new mutable Yoga node if
+ * Yoga must write to it and its owner is not its parent observed during layout.
+ */
+YG_EXPORT void YGConfigSetCloneNodeFunc(
+    YGConfigRef config,
+    YGCloneNodeFunc callback);
+
+/**
+ * Allows printing the Yoga node tree during layout for debugging purposes.
+ */
+YG_EXPORT void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled);
+
+YG_EXTERN_C_END
+ yoga/yoga/YGEnums.cpp view
@@ -0,0 +1,266 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#include <yoga/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";
+    case YGAlignSpaceEvenly:
+      return "space-evenly";
+  }
+  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* YGErrataToString(const YGErrata value) {
+  switch (value) {
+    case YGErrataNone:
+      return "none";
+    case YGErrataStretchFlexBasis:
+      return "stretch-flex-basis";
+    case YGErrataStartingEndingEdgeFromFlexDirection:
+      return "starting-ending-edge-from-flex-direction";
+    case YGErrataPositionStaticBehavesLikeRelative:
+      return "position-static-behaves-like-relative";
+    case YGErrataAbsolutePositioning:
+      return "absolute-positioning";
+    case YGErrataAll:
+      return "all";
+    case YGErrataClassic:
+      return "classic";
+  }
+  return "unknown";
+}
+
+const char* YGExperimentalFeatureToString(const YGExperimentalFeature value) {
+  switch (value) {
+    case YGExperimentalFeatureWebFlexBasis:
+      return "web-flex-basis";
+    case YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge:
+      return "absolute-percentage-against-padding-edge";
+  }
+  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* YGGutterToString(const YGGutter value) {
+  switch (value) {
+    case YGGutterColumn:
+      return "column";
+    case YGGutterRow:
+      return "row";
+    case YGGutterAll:
+      return "all";
+  }
+  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 YGPositionTypeStatic:
+      return "static";
+    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";
+}
+ yoga/yoga/YGEnums.h view
@@ -0,0 +1,145 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+#include <yoga/YGMacros.h>
+
+YG_EXTERN_C_BEGIN
+
+YG_ENUM_DECL(
+    YGAlign,
+    YGAlignAuto,
+    YGAlignFlexStart,
+    YGAlignCenter,
+    YGAlignFlexEnd,
+    YGAlignStretch,
+    YGAlignBaseline,
+    YGAlignSpaceBetween,
+    YGAlignSpaceAround,
+    YGAlignSpaceEvenly)
+
+YG_ENUM_DECL(
+    YGDimension,
+    YGDimensionWidth,
+    YGDimensionHeight)
+
+YG_ENUM_DECL(
+    YGDirection,
+    YGDirectionInherit,
+    YGDirectionLTR,
+    YGDirectionRTL)
+
+YG_ENUM_DECL(
+    YGDisplay,
+    YGDisplayFlex,
+    YGDisplayNone)
+
+YG_ENUM_DECL(
+    YGEdge,
+    YGEdgeLeft,
+    YGEdgeTop,
+    YGEdgeRight,
+    YGEdgeBottom,
+    YGEdgeStart,
+    YGEdgeEnd,
+    YGEdgeHorizontal,
+    YGEdgeVertical,
+    YGEdgeAll)
+
+YG_ENUM_DECL(
+    YGErrata,
+    YGErrataNone = 0,
+    YGErrataStretchFlexBasis = 1,
+    YGErrataStartingEndingEdgeFromFlexDirection = 2,
+    YGErrataPositionStaticBehavesLikeRelative = 4,
+    YGErrataAbsolutePositioning = 8,
+    YGErrataAll = 2147483647,
+    YGErrataClassic = 2147483646)
+YG_DEFINE_ENUM_FLAG_OPERATORS(YGErrata)
+
+YG_ENUM_DECL(
+    YGExperimentalFeature,
+    YGExperimentalFeatureWebFlexBasis,
+    YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge)
+
+YG_ENUM_DECL(
+    YGFlexDirection,
+    YGFlexDirectionColumn,
+    YGFlexDirectionColumnReverse,
+    YGFlexDirectionRow,
+    YGFlexDirectionRowReverse)
+
+YG_ENUM_DECL(
+    YGGutter,
+    YGGutterColumn,
+    YGGutterRow,
+    YGGutterAll)
+
+YG_ENUM_DECL(
+    YGJustify,
+    YGJustifyFlexStart,
+    YGJustifyCenter,
+    YGJustifyFlexEnd,
+    YGJustifySpaceBetween,
+    YGJustifySpaceAround,
+    YGJustifySpaceEvenly)
+
+YG_ENUM_DECL(
+    YGLogLevel,
+    YGLogLevelError,
+    YGLogLevelWarn,
+    YGLogLevelInfo,
+    YGLogLevelDebug,
+    YGLogLevelVerbose,
+    YGLogLevelFatal)
+
+YG_ENUM_DECL(
+    YGMeasureMode,
+    YGMeasureModeUndefined,
+    YGMeasureModeExactly,
+    YGMeasureModeAtMost)
+
+YG_ENUM_DECL(
+    YGNodeType,
+    YGNodeTypeDefault,
+    YGNodeTypeText)
+
+YG_ENUM_DECL(
+    YGOverflow,
+    YGOverflowVisible,
+    YGOverflowHidden,
+    YGOverflowScroll)
+
+YG_ENUM_DECL(
+    YGPositionType,
+    YGPositionTypeStatic,
+    YGPositionTypeRelative,
+    YGPositionTypeAbsolute)
+
+YG_ENUM_DECL(
+    YGPrintOptions,
+    YGPrintOptionsLayout = 1,
+    YGPrintOptionsStyle = 2,
+    YGPrintOptionsChildren = 4)
+YG_DEFINE_ENUM_FLAG_OPERATORS(YGPrintOptions)
+
+YG_ENUM_DECL(
+    YGUnit,
+    YGUnitUndefined,
+    YGUnitPoint,
+    YGUnitPercent,
+    YGUnitAuto)
+
+YG_ENUM_DECL(
+    YGWrap,
+    YGWrapNoWrap,
+    YGWrapWrap,
+    YGWrapWrapReverse)
+
+YG_EXTERN_C_END
+ yoga/yoga/YGMacros.h view
@@ -0,0 +1,93 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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
+#include <type_traits>
+#endif
+
+#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
+
+#if defined(__cplusplus)
+#define YG_DEPRECATED(message) [[deprecated(message)]]
+#elif defined(_MSC_VER)
+#define YG_DEPRECATED(message) __declspec(deprecated(message))
+#else
+#define YG_DEPRECATED(message) __attribute__((deprecated(message)))
+#endif
+
+#ifdef _WINDLL
+#define YG_EXPORT __declspec(dllexport)
+#elif !defined(_MSC_VER)
+#define YG_EXPORT __attribute__((visibility("default")))
+#else
+#define YG_EXPORT
+#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 mismatch 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
+
+#ifdef __cplusplus
+#define YG_DEFINE_ENUM_FLAG_OPERATORS(name)                       \
+  extern "C++" {                                                  \
+  constexpr name operator~(name a) {                              \
+    return static_cast<name>(                                     \
+        ~static_cast<std::underlying_type<name>::type>(a));       \
+  }                                                               \
+  constexpr name operator|(name a, name b) {                      \
+    return static_cast<name>(                                     \
+        static_cast<std::underlying_type<name>::type>(a) |        \
+        static_cast<std::underlying_type<name>::type>(b));        \
+  }                                                               \
+  constexpr name operator&(name a, name b) {                      \
+    return static_cast<name>(                                     \
+        static_cast<std::underlying_type<name>::type>(a) &        \
+        static_cast<std::underlying_type<name>::type>(b));        \
+  }                                                               \
+  constexpr name operator^(name a, name b) {                      \
+    return static_cast<name>(                                     \
+        static_cast<std::underlying_type<name>::type>(a) ^        \
+        static_cast<std::underlying_type<name>::type>(b));        \
+  }                                                               \
+  inline name& operator|=(name& a, name b) {                      \
+    return reinterpret_cast<name&>(                               \
+        reinterpret_cast<std::underlying_type<name>::type&>(a) |= \
+        static_cast<std::underlying_type<name>::type>(b));        \
+  }                                                               \
+  inline name& operator&=(name& a, name b) {                      \
+    return reinterpret_cast<name&>(                               \
+        reinterpret_cast<std::underlying_type<name>::type&>(a) &= \
+        static_cast<std::underlying_type<name>::type>(b));        \
+  }                                                               \
+  inline name& operator^=(name& a, name b) {                      \
+    return reinterpret_cast<name&>(                               \
+        reinterpret_cast<std::underlying_type<name>::type&>(a) ^= \
+        static_cast<std::underlying_type<name>::type>(b));        \
+  }                                                               \
+  }
+#else
+#define YG_DEFINE_ENUM_FLAG_OPERATORS(name)
+#endif
+
+#define YG_ENUM_DECL(NAME, ...)                               \
+  typedef YG_ENUM_BEGIN(NAME){__VA_ARGS__} YG_ENUM_END(NAME); \
+  YG_EXPORT const char* NAME##ToString(NAME);
+ yoga/yoga/YGNode.cpp view
@@ -0,0 +1,373 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>
+
+#include <yoga/algorithm/Cache.h>
+#include <yoga/algorithm/CalculateLayout.h>
+#include <yoga/debug/AssertFatal.h>
+#include <yoga/debug/Log.h>
+#include <yoga/debug/NodeToString.h>
+#include <yoga/event/event.h>
+#include <yoga/node/Node.h>
+
+using namespace facebook;
+using namespace facebook::yoga;
+
+YGNodeRef YGNodeNew(void) {
+  return YGNodeNewWithConfig(YGConfigGetDefault());
+}
+
+YGNodeRef YGNodeNewWithConfig(const YGConfigConstRef config) {
+  auto* node = new yoga::Node{resolveRef(config)};
+  yoga::assertFatal(
+      config != nullptr, "Tried to construct YGNode with null config");
+  Event::publish<Event::NodeAllocation>(node, {config});
+
+  return node;
+}
+
+YGNodeRef YGNodeClone(YGNodeConstRef oldNodeRef) {
+  auto oldNode = resolveRef(oldNodeRef);
+  const auto node = new yoga::Node(*oldNode);
+  Event::publish<Event::NodeAllocation>(node, {node->getConfig()});
+  node->setOwner(nullptr);
+  return node;
+}
+
+void YGNodeFree(const YGNodeRef nodeRef) {
+  const auto node = resolveRef(nodeRef);
+
+  if (auto owner = node->getOwner()) {
+    owner->removeChild(node);
+    node->setOwner(nullptr);
+  }
+
+  const size_t childCount = node->getChildCount();
+  for (size_t i = 0; i < childCount; i++) {
+    auto child = node->getChild(i);
+    child->setOwner(nullptr);
+  }
+
+  node->clearChildren();
+
+  Event::publish<Event::NodeDeallocation>(node, {YGNodeGetConfig(node)});
+  delete resolveRef(node);
+}
+
+void YGNodeFreeRecursive(YGNodeRef rootRef) {
+  const auto root = resolveRef(rootRef);
+
+  size_t skipped = 0;
+  while (root->getChildCount() > skipped) {
+    const auto child = root->getChild(skipped);
+    if (child->getOwner() != root) {
+      // Don't free shared nodes that we don't own.
+      skipped += 1;
+    } else {
+      YGNodeRemoveChild(root, child);
+      YGNodeFreeRecursive(child);
+    }
+  }
+  YGNodeFree(root);
+}
+
+void YGNodeFinalize(const YGNodeRef node) {
+  Event::publish<Event::NodeDeallocation>(node, {YGNodeGetConfig(node)});
+  delete resolveRef(node);
+}
+
+void YGNodeReset(YGNodeRef node) {
+  resolveRef(node)->reset();
+}
+
+void YGNodeCalculateLayout(
+    const YGNodeRef node,
+    const float ownerWidth,
+    const float ownerHeight,
+    const YGDirection ownerDirection) {
+  yoga::calculateLayout(
+      resolveRef(node), ownerWidth, ownerHeight, scopedEnum(ownerDirection));
+}
+
+bool YGNodeGetHasNewLayout(YGNodeConstRef node) {
+  return resolveRef(node)->getHasNewLayout();
+}
+
+void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout) {
+  resolveRef(node)->setHasNewLayout(hasNewLayout);
+}
+
+bool YGNodeIsDirty(YGNodeConstRef node) {
+  return resolveRef(node)->isDirty();
+}
+
+void YGNodeMarkDirty(const YGNodeRef nodeRef) {
+  const auto node = resolveRef(nodeRef);
+
+  yoga::assertFatalWithNode(
+      node,
+      node->hasMeasureFunc(),
+      "Only leaf nodes with custom measure functions "
+      "should manually mark themselves as dirty");
+
+  node->markDirtyAndPropagate();
+}
+
+void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc) {
+  resolveRef(node)->setDirtiedFunc(dirtiedFunc);
+}
+
+YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeConstRef node) {
+  return resolveRef(node)->getDirtiedFunc();
+}
+
+void YGNodeInsertChild(
+    const YGNodeRef ownerRef,
+    const YGNodeRef childRef,
+    const size_t index) {
+  auto owner = resolveRef(ownerRef);
+  auto child = resolveRef(childRef);
+
+  yoga::assertFatalWithNode(
+      owner,
+      child->getOwner() == nullptr,
+      "Child already has a owner, it must be removed first.");
+
+  yoga::assertFatalWithNode(
+      owner,
+      !owner->hasMeasureFunc(),
+      "Cannot add child: Nodes with measure functions cannot have children.");
+
+  owner->insertChild(child, index);
+  child->setOwner(owner);
+  owner->markDirtyAndPropagate();
+}
+
+void YGNodeSwapChild(
+    const YGNodeRef ownerRef,
+    const YGNodeRef childRef,
+    const size_t index) {
+  auto owner = resolveRef(ownerRef);
+  auto child = resolveRef(childRef);
+
+  owner->replaceChild(child, index);
+  child->setOwner(owner);
+}
+
+void YGNodeRemoveChild(
+    const YGNodeRef ownerRef,
+    const YGNodeRef excludedChildRef) {
+  auto owner = resolveRef(ownerRef);
+  auto excludedChild = resolveRef(excludedChildRef);
+
+  if (owner->getChildCount() == 0) {
+    // This is an empty set. Nothing to remove.
+    return;
+  }
+
+  // Children may be shared between parents, which is indicated by not having an
+  // owner. We only want to reset the child completely if it is owned
+  // exclusively by one node.
+  auto childOwner = excludedChild->getOwner();
+  if (owner->removeChild(excludedChild)) {
+    if (owner == childOwner) {
+      excludedChild->setLayout({}); // layout is no longer valid
+      excludedChild->setOwner(nullptr);
+    }
+    owner->markDirtyAndPropagate();
+  }
+}
+
+void YGNodeRemoveAllChildren(const YGNodeRef ownerRef) {
+  auto owner = resolveRef(ownerRef);
+
+  const size_t childCount = owner->getChildCount();
+  if (childCount == 0) {
+    // This is an empty set already. Nothing to do.
+    return;
+  }
+  auto* firstChild = owner->getChild(0);
+  if (firstChild->getOwner() == owner) {
+    // If the first child has this node as its owner, we assume that this child
+    // set is unique.
+    for (size_t i = 0; i < childCount; i++) {
+      yoga::Node* oldChild = owner->getChild(i);
+      oldChild->setLayout({}); // layout is no longer valid
+      oldChild->setOwner(nullptr);
+    }
+    owner->clearChildren();
+    owner->markDirtyAndPropagate();
+    return;
+  }
+  // Otherwise, we are not the owner of the child set. We don't have to do
+  // anything to clear it.
+  owner->setChildren({});
+  owner->markDirtyAndPropagate();
+}
+
+void YGNodeSetChildren(
+    const YGNodeRef ownerRef,
+    const YGNodeRef* childrenRefs,
+    const size_t count) {
+  auto owner = resolveRef(ownerRef);
+  auto children = reinterpret_cast<yoga::Node* const*>(childrenRefs);
+
+  if (!owner) {
+    return;
+  }
+
+  const std::vector<yoga::Node*> childrenVector = {children, children + count};
+  if (childrenVector.size() == 0) {
+    if (owner->getChildCount() > 0) {
+      for (auto* child : owner->getChildren()) {
+        child->setLayout({});
+        child->setOwner(nullptr);
+      }
+      owner->setChildren({});
+      owner->markDirtyAndPropagate();
+    }
+  } else {
+    if (owner->getChildCount() > 0) {
+      for (auto* 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(childrenVector.begin(), childrenVector.end(), oldChild) ==
+            childrenVector.end()) {
+          oldChild->setLayout({});
+          oldChild->setOwner(nullptr);
+        }
+      }
+    }
+    owner->setChildren(childrenVector);
+    for (yoga::Node* child : childrenVector) {
+      child->setOwner(owner);
+    }
+    owner->markDirtyAndPropagate();
+  }
+}
+
+YGNodeRef YGNodeGetChild(const YGNodeRef nodeRef, const size_t index) {
+  const auto node = resolveRef(nodeRef);
+
+  if (index < node->getChildren().size()) {
+    return node->getChild(index);
+  }
+  return nullptr;
+}
+
+size_t YGNodeGetChildCount(const YGNodeConstRef node) {
+  return resolveRef(node)->getChildren().size();
+}
+
+YGNodeRef YGNodeGetOwner(const YGNodeRef node) {
+  return resolveRef(node)->getOwner();
+}
+
+YGNodeRef YGNodeGetParent(const YGNodeRef node) {
+  return resolveRef(node)->getOwner();
+}
+
+void YGNodeSetConfig(YGNodeRef node, YGConfigRef config) {
+  resolveRef(node)->setConfig(resolveRef(config));
+}
+
+YGConfigConstRef YGNodeGetConfig(YGNodeRef node) {
+  return resolveRef(node)->getConfig();
+}
+
+void YGNodeSetContext(YGNodeRef node, void* context) {
+  return resolveRef(node)->setContext(context);
+}
+
+void* YGNodeGetContext(YGNodeConstRef node) {
+  return resolveRef(node)->getContext();
+}
+
+void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc) {
+  resolveRef(node)->setMeasureFunc(measureFunc);
+}
+
+bool YGNodeHasMeasureFunc(YGNodeConstRef node) {
+  return resolveRef(node)->hasMeasureFunc();
+}
+
+void YGNodeSetBaselineFunc(YGNodeRef node, YGBaselineFunc baselineFunc) {
+  resolveRef(node)->setBaselineFunc(baselineFunc);
+}
+
+bool YGNodeHasBaselineFunc(YGNodeConstRef node) {
+  return resolveRef(node)->hasBaselineFunc();
+}
+
+void YGNodeSetIsReferenceBaseline(YGNodeRef nodeRef, bool isReferenceBaseline) {
+  const auto node = resolveRef(nodeRef);
+  if (node->isReferenceBaseline() != isReferenceBaseline) {
+    node->setIsReferenceBaseline(isReferenceBaseline);
+    node->markDirtyAndPropagate();
+  }
+}
+
+bool YGNodeIsReferenceBaseline(YGNodeConstRef node) {
+  return resolveRef(node)->isReferenceBaseline();
+}
+
+void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType) {
+  return resolveRef(node)->setNodeType(scopedEnum(nodeType));
+}
+
+YGNodeType YGNodeGetNodeType(YGNodeConstRef node) {
+  return unscopedEnum(resolveRef(node)->getNodeType());
+}
+
+void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc) {
+  resolveRef(node)->setPrintFunc(printFunc);
+}
+
+void YGNodeSetAlwaysFormsContainingBlock(
+    YGNodeRef node,
+    bool alwaysFormsContainingBlock) {
+  resolveRef(node)->setAlwaysFormsContainingBlock(alwaysFormsContainingBlock);
+}
+
+#ifdef DEBUG
+void YGNodePrint(const YGNodeConstRef node, const YGPrintOptions options) {
+  yoga::print(resolveRef(node), scopedEnum(options));
+}
+#endif
+
+// TODO: This leaks internal details to the public API. Remove after removing
+// ComponentKit usage of it.
+bool YGNodeCanUseCachedMeasurement(
+    YGMeasureMode widthMode,
+    float availableWidth,
+    YGMeasureMode heightMode,
+    float availableHeight,
+    YGMeasureMode lastWidthMode,
+    float lastAvailableWidth,
+    YGMeasureMode lastHeightMode,
+    float lastAvailableHeight,
+    float lastComputedWidth,
+    float lastComputedHeight,
+    float marginRow,
+    float marginColumn,
+    YGConfigRef config) {
+  return yoga::canUseCachedMeasurement(
+      sizingMode(scopedEnum(widthMode)),
+      availableWidth,
+      sizingMode(scopedEnum(heightMode)),
+      availableHeight,
+      sizingMode(scopedEnum(lastWidthMode)),
+      lastAvailableWidth,
+      sizingMode(scopedEnum(lastHeightMode)),
+      lastAvailableHeight,
+      lastComputedWidth,
+      lastComputedHeight,
+      marginRow,
+      marginColumn,
+      resolveRef(config));
+}
+ yoga/yoga/YGNode.h view
@@ -0,0 +1,309 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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 <stdbool.h>
+#include <stddef.h>
+
+#include <yoga/YGConfig.h>
+#include <yoga/YGEnums.h>
+#include <yoga/YGMacros.h>
+
+YG_EXTERN_C_BEGIN
+
+/**
+ * Handle to a mutable Yoga Node.
+ */
+typedef struct YGNode* YGNodeRef;
+
+/**
+ * Handle to an immutable Yoga Node.
+ */
+typedef const struct YGNode* YGNodeConstRef;
+
+/**
+ * Heap allocates and returns a new Yoga node using Yoga settings.
+ */
+YG_EXPORT YGNodeRef YGNodeNew(void);
+
+/**
+ * Heap allocates and returns a new Yoga node, with customized settings.
+ */
+YG_EXPORT YGNodeRef YGNodeNewWithConfig(YGConfigConstRef config);
+
+/**
+ * Returns a mutable copy of an existing node, with the same context and
+ * children, but no owner set. Does not call the function set by
+ * YGConfigSetCloneNodeFunc().
+ */
+YG_EXPORT YGNodeRef YGNodeClone(YGNodeConstRef node);
+
+/**
+ * Frees the Yoga node, disconnecting it from its owner and children.
+ */
+YG_EXPORT void YGNodeFree(YGNodeRef node);
+
+/**
+ * Frees the subtree of Yoga nodes rooted at the given node.
+ */
+YG_EXPORT void YGNodeFreeRecursive(YGNodeRef node);
+
+/**
+ * Frees the Yoga node without disconnecting it from its owner or children.
+ * Allows garbage collecting Yoga nodes in parallel when the entire tree is
+ * unrechable.
+ */
+YG_EXPORT void YGNodeFinalize(YGNodeRef node);
+
+/**
+ * Resets the node to its default state.
+ */
+YG_EXPORT void YGNodeReset(YGNodeRef node);
+
+/**
+ * Calculates the layout of the tree rooted at the given node.
+ *
+ * Layout results may be read after calling YGNodeCalculateLayout() using
+ * functions like YGNodeLayoutGetLeft(), YGNodeLayoutGetTop(), etc.
+ *
+ * YGNodeGetHasNewLayout() may be read to know if the layout of the node or its
+ * subtrees may have changed since the last time YGNodeCalculate() was called.
+ */
+YG_EXPORT void YGNodeCalculateLayout(
+    YGNodeRef node,
+    float availableWidth,
+    float availableHeight,
+    YGDirection ownerDirection);
+
+/**
+ * Whether the given node may have new layout results. Must be reset by calling
+ * YGNodeSetHasNewLayout().
+ */
+YG_EXPORT bool YGNodeGetHasNewLayout(YGNodeConstRef node);
+
+/**
+ * Sets whether a nodes layout is considered new.
+ */
+YG_EXPORT void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout);
+
+/**
+ * Whether the node's layout results are dirty due to it or its children
+ * changing.
+ */
+YG_EXPORT bool YGNodeIsDirty(YGNodeConstRef node);
+
+/**
+ * Marks a node with custom measure function as dirty.
+ */
+YG_EXPORT void YGNodeMarkDirty(YGNodeRef node);
+
+typedef void (*YGDirtiedFunc)(YGNodeConstRef node);
+
+/**
+ * Called when a change is made to the Yoga tree which dirties this node.
+ */
+YG_EXPORT void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc);
+
+/**
+ * Returns a dirtied func if set.
+ */
+YG_EXPORT YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeConstRef node);
+
+/**
+ * Inserts a child node at the given index.
+ */
+YG_EXPORT void YGNodeInsertChild(YGNodeRef node, YGNodeRef child, size_t index);
+
+/**
+ * Replaces the child node at a given index with a new one.
+ */
+YG_EXPORT void YGNodeSwapChild(YGNodeRef node, YGNodeRef child, size_t index);
+
+/**
+ * Removes the given child node.
+ */
+YG_EXPORT void YGNodeRemoveChild(YGNodeRef node, YGNodeRef child);
+
+/**
+ * Removes all children nodes.
+ */
+YG_EXPORT void YGNodeRemoveAllChildren(YGNodeRef node);
+
+/**
+ * Sets children according to the given list of nodes.
+ */
+YG_EXPORT void
+YGNodeSetChildren(YGNodeRef owner, const YGNodeRef* children, size_t count);
+
+/**
+ * Get the child node at a given index.
+ */
+YG_EXPORT YGNodeRef YGNodeGetChild(YGNodeRef node, size_t index);
+
+/**
+ * The number of child nodes.
+ */
+YG_EXPORT size_t YGNodeGetChildCount(YGNodeConstRef node);
+
+/**
+ * Get the parent/owner currently set for a node.
+ */
+YG_EXPORT YGNodeRef YGNodeGetOwner(YGNodeRef node);
+
+/**
+ * Get the parent/owner currently set for a node.
+ */
+YG_EXPORT YGNodeRef YGNodeGetParent(YGNodeRef node);
+
+/**
+ * Set a new config for the node after creation.
+ */
+YG_EXPORT void YGNodeSetConfig(YGNodeRef node, YGConfigRef config);
+
+/**
+ * Get the config currently set on the node.
+ */
+YG_EXPORT YGConfigConstRef YGNodeGetConfig(YGNodeRef node);
+
+/**
+ * Sets extra data on the Yoga node which may be read from during callbacks.
+ */
+YG_EXPORT void YGNodeSetContext(YGNodeRef node, void* context);
+
+/**
+ * Returns the context or NULL if no context has been set.
+ */
+YG_EXPORT void* YGNodeGetContext(YGNodeConstRef node);
+
+typedef struct YGSize {
+  float width;
+  float height;
+} YGSize;
+
+/**
+ * Returns the computed dimensions of the node, following the contraints of
+ * `widthMode` and `heightMode`:
+ *
+ * YGMeasureModeUndefined: The parent has not imposed any constraint on the
+ * child. It can be whatever size it wants.
+ *
+ * YGMeasureModeAtMost: The child can be as large as it wants up to the
+ * specified size.
+ *
+ * YGMeasureModeExactly: The parent has determined an exact size for the
+ * child. The child is going to be given those bounds regardless of how big it
+ * wants to be.
+ *
+ * @returns the size of the leaf node, measured under the given contraints.
+ */
+typedef YGSize (*YGMeasureFunc)(
+    YGNodeConstRef node,
+    float width,
+    YGMeasureMode widthMode,
+    float height,
+    YGMeasureMode heightMode);
+
+/**
+ * Allows providing custom measurements for a Yoga leaf node (usually for
+ * measuring text). YGNodeMarkDirty() must be set if content effecting the
+ * measurements of the node changes.
+ */
+YG_EXPORT void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc);
+
+/**
+ * Whether a measure function is set.
+ */
+YG_EXPORT bool YGNodeHasMeasureFunc(YGNodeConstRef node);
+
+/**
+ * @returns a defined offet to baseline (ascent).
+ */
+typedef float (*YGBaselineFunc)(YGNodeConstRef node, float width, float height);
+
+/**
+ * Set a custom function for determining the text baseline for use in baseline
+ * alignment.
+ */
+YG_EXPORT void YGNodeSetBaselineFunc(
+    YGNodeRef node,
+    YGBaselineFunc baselineFunc);
+
+/**
+ * Whether a baseline function is set.
+ */
+YG_EXPORT bool YGNodeHasBaselineFunc(YGNodeConstRef node);
+
+/**
+ * Sets this node should be considered the reference baseline among siblings.
+ */
+YG_EXPORT void YGNodeSetIsReferenceBaseline(
+    YGNodeRef node,
+    bool isReferenceBaseline);
+
+/**
+ * Whether this node is set as the reference baseline.
+ */
+YG_EXPORT bool YGNodeIsReferenceBaseline(YGNodeConstRef node);
+
+/**
+ * Sets whether a leaf node's layout results may be truncated during layout
+ * rounding.
+ */
+YG_EXPORT void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType);
+
+/**
+ * Wwhether a leaf node's layout results may be truncated during layout
+ * rounding.
+ */
+YG_EXPORT YGNodeType YGNodeGetNodeType(YGNodeConstRef node);
+
+typedef void (*YGPrintFunc)(YGNodeConstRef node);
+
+/**
+ * Set a function to be called when configured to print nodes during layout for
+ * debugging.
+ */
+YG_EXPORT void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc);
+
+/**
+ * Make it so that this node will always form a containing block for any
+ * descendant nodes. This is useful for when a node has a property outside of
+ * of Yoga that will form a containing block. For example, transforms or some of
+ * the others listed in
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block
+ */
+YG_EXPORT void YGNodeSetAlwaysFormsContainingBlock(
+    YGNodeRef node,
+    bool alwaysFormsContainingBlock);
+
+/**
+ * Print a node to log output.
+ */
+YG_EXPORT void YGNodePrint(YGNodeConstRef node, YGPrintOptions options);
+
+/**
+ * @deprecated
+ */
+YG_DEPRECATED(
+    "YGNodeCanUseCachedMeasurement may be removed in a future version of Yoga")
+YG_EXPORT bool YGNodeCanUseCachedMeasurement(
+    YGMeasureMode widthMode,
+    float availableWidth,
+    YGMeasureMode heightMode,
+    float availableHeight,
+    YGMeasureMode lastWidthMode,
+    float lastAvailableWidth,
+    YGMeasureMode lastHeightMode,
+    float lastAvailableHeight,
+    float lastComputedWidth,
+    float lastComputedHeight,
+    float marginRow,
+    float marginColumn,
+    YGConfigRef config);
+
+YG_EXTERN_C_END
+ yoga/yoga/YGNodeLayout.cpp view
@@ -0,0 +1,92 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>
+#include <yoga/debug/AssertFatal.h>
+#include <yoga/enums/Edge.h>
+#include <yoga/node/Node.h>
+
+using namespace facebook;
+using namespace facebook::yoga;
+
+namespace {
+
+template <auto LayoutMember>
+float getResolvedLayoutProperty(const YGNodeConstRef nodeRef, const Edge edge) {
+  const auto node = resolveRef(nodeRef);
+  yoga::assertFatalWithNode(
+      node,
+      edge <= Edge::End,
+      "Cannot get layout properties of multi-edge shorthands");
+
+  if (edge == Edge::Start) {
+    if (node->getLayout().direction() == Direction::RTL) {
+      return (node->getLayout().*LayoutMember)(Edge::Right);
+    } else {
+      return (node->getLayout().*LayoutMember)(Edge::Left);
+    }
+  }
+
+  if (edge == Edge::End) {
+    if (node->getLayout().direction() == Direction::RTL) {
+      return (node->getLayout().*LayoutMember)(Edge::Left);
+    } else {
+      return (node->getLayout().*LayoutMember)(Edge::Right);
+    }
+  }
+
+  return (node->getLayout().*LayoutMember)(edge);
+}
+
+} // namespace
+
+float YGNodeLayoutGetLeft(const YGNodeConstRef node) {
+  return resolveRef(node)->getLayout().position(Edge::Left);
+}
+
+float YGNodeLayoutGetTop(const YGNodeConstRef node) {
+  return resolveRef(node)->getLayout().position(Edge::Top);
+}
+
+float YGNodeLayoutGetRight(const YGNodeConstRef node) {
+  return resolveRef(node)->getLayout().position(Edge::Right);
+}
+
+float YGNodeLayoutGetBottom(const YGNodeConstRef node) {
+  return resolveRef(node)->getLayout().position(Edge::Bottom);
+}
+
+float YGNodeLayoutGetWidth(const YGNodeConstRef node) {
+  return resolveRef(node)->getLayout().dimension(Dimension::Width);
+}
+
+float YGNodeLayoutGetHeight(const YGNodeConstRef node) {
+  return resolveRef(node)->getLayout().dimension(Dimension::Height);
+}
+
+YGDirection YGNodeLayoutGetDirection(const YGNodeConstRef node) {
+  return unscopedEnum(resolveRef(node)->getLayout().direction());
+}
+
+bool YGNodeLayoutGetHadOverflow(const YGNodeConstRef node) {
+  return resolveRef(node)->getLayout().hadOverflow();
+}
+
+float YGNodeLayoutGetMargin(YGNodeConstRef node, YGEdge edge) {
+  return getResolvedLayoutProperty<&LayoutResults::margin>(
+      node, scopedEnum(edge));
+}
+
+float YGNodeLayoutGetBorder(YGNodeConstRef node, YGEdge edge) {
+  return getResolvedLayoutProperty<&LayoutResults::border>(
+      node, scopedEnum(edge));
+}
+
+float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge) {
+  return getResolvedLayoutProperty<&LayoutResults::padding>(
+      node, scopedEnum(edge));
+}
+ yoga/yoga/YGNodeLayout.h view
@@ -0,0 +1,35 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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 <stdbool.h>
+
+#include <yoga/YGConfig.h>
+#include <yoga/YGEnums.h>
+#include <yoga/YGMacros.h>
+
+YG_EXTERN_C_BEGIN
+
+YG_EXPORT float YGNodeLayoutGetLeft(YGNodeConstRef node);
+YG_EXPORT float YGNodeLayoutGetTop(YGNodeConstRef node);
+YG_EXPORT float YGNodeLayoutGetRight(YGNodeConstRef node);
+YG_EXPORT float YGNodeLayoutGetBottom(YGNodeConstRef node);
+YG_EXPORT float YGNodeLayoutGetWidth(YGNodeConstRef node);
+YG_EXPORT float YGNodeLayoutGetHeight(YGNodeConstRef node);
+YG_EXPORT YGDirection YGNodeLayoutGetDirection(YGNodeConstRef node);
+YG_EXPORT bool YGNodeLayoutGetHadOverflow(YGNodeConstRef 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.
+YG_EXPORT float YGNodeLayoutGetMargin(YGNodeConstRef node, YGEdge edge);
+YG_EXPORT float YGNodeLayoutGetBorder(YGNodeConstRef node, YGEdge edge);
+YG_EXPORT float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge);
+
+YG_EXTERN_C_END
+ yoga/yoga/YGNodeStyle.cpp view
@@ -0,0 +1,388 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>
+#include <yoga/debug/AssertFatal.h>
+#include <yoga/node/Node.h>
+
+using namespace facebook;
+using namespace facebook::yoga;
+
+namespace {
+
+template <auto GetterT, auto SetterT, typename ValueT>
+void updateStyle(YGNodeRef node, ValueT value) {
+  auto& style = resolveRef(node)->getStyle();
+  if ((style.*GetterT)() != value) {
+    (style.*SetterT)(value);
+    resolveRef(node)->markDirtyAndPropagate();
+  }
+}
+
+template <auto GetterT, auto SetterT, typename IdxT, typename ValueT>
+void updateStyle(YGNodeRef node, IdxT idx, ValueT value) {
+  auto& style = resolveRef(node)->getStyle();
+  if ((style.*GetterT)(idx) != value) {
+    (style.*SetterT)(idx, value);
+    resolveRef(node)->markDirtyAndPropagate();
+  }
+}
+
+} // namespace
+
+void YGNodeCopyStyle(
+    const YGNodeRef dstNodeRef,
+    const YGNodeConstRef srcNodeRef) {
+  auto dstNode = resolveRef(dstNodeRef);
+  auto srcNode = resolveRef(srcNodeRef);
+
+  if (!(dstNode->getStyle() == srcNode->getStyle())) {
+    dstNode->setStyle(srcNode->getStyle());
+    dstNode->markDirtyAndPropagate();
+  }
+}
+
+void YGNodeStyleSetDirection(const YGNodeRef node, const YGDirection value) {
+  updateStyle<&Style::direction, &Style::setDirection>(node, scopedEnum(value));
+}
+
+YGDirection YGNodeStyleGetDirection(const YGNodeConstRef node) {
+  return unscopedEnum(resolveRef(node)->getStyle().direction());
+}
+
+void YGNodeStyleSetFlexDirection(
+    const YGNodeRef node,
+    const YGFlexDirection flexDirection) {
+  updateStyle<&Style::flexDirection, &Style::setFlexDirection>(
+      node, scopedEnum(flexDirection));
+}
+
+YGFlexDirection YGNodeStyleGetFlexDirection(const YGNodeConstRef node) {
+  return unscopedEnum(resolveRef(node)->getStyle().flexDirection());
+}
+
+void YGNodeStyleSetJustifyContent(
+    const YGNodeRef node,
+    const YGJustify justifyContent) {
+  updateStyle<&Style::justifyContent, &Style::setJustifyContent>(
+      node, scopedEnum(justifyContent));
+}
+
+YGJustify YGNodeStyleGetJustifyContent(const YGNodeConstRef node) {
+  return unscopedEnum(resolveRef(node)->getStyle().justifyContent());
+}
+
+void YGNodeStyleSetAlignContent(
+    const YGNodeRef node,
+    const YGAlign alignContent) {
+  updateStyle<&Style::alignContent, &Style::setAlignContent>(
+      node, scopedEnum(alignContent));
+}
+
+YGAlign YGNodeStyleGetAlignContent(const YGNodeConstRef node) {
+  return unscopedEnum(resolveRef(node)->getStyle().alignContent());
+}
+
+void YGNodeStyleSetAlignItems(const YGNodeRef node, const YGAlign alignItems) {
+  updateStyle<&Style::alignItems, &Style::setAlignItems>(
+      node, scopedEnum(alignItems));
+}
+
+YGAlign YGNodeStyleGetAlignItems(const YGNodeConstRef node) {
+  return unscopedEnum(resolveRef(node)->getStyle().alignItems());
+}
+
+void YGNodeStyleSetAlignSelf(const YGNodeRef node, const YGAlign alignSelf) {
+  updateStyle<&Style::alignSelf, &Style::setAlignSelf>(
+      node, scopedEnum(alignSelf));
+}
+
+YGAlign YGNodeStyleGetAlignSelf(const YGNodeConstRef node) {
+  return unscopedEnum(resolveRef(node)->getStyle().alignSelf());
+}
+
+void YGNodeStyleSetPositionType(
+    const YGNodeRef node,
+    const YGPositionType positionType) {
+  updateStyle<&Style::positionType, &Style::setPositionType>(
+      node, scopedEnum(positionType));
+}
+
+YGPositionType YGNodeStyleGetPositionType(const YGNodeConstRef node) {
+  return unscopedEnum(resolveRef(node)->getStyle().positionType());
+}
+
+void YGNodeStyleSetFlexWrap(const YGNodeRef node, const YGWrap flexWrap) {
+  updateStyle<&Style::flexWrap, &Style::setFlexWrap>(
+      node, scopedEnum(flexWrap));
+}
+
+YGWrap YGNodeStyleGetFlexWrap(const YGNodeConstRef node) {
+  return unscopedEnum(resolveRef(node)->getStyle().flexWrap());
+}
+
+void YGNodeStyleSetOverflow(const YGNodeRef node, const YGOverflow overflow) {
+  updateStyle<&Style::overflow, &Style::setOverflow>(
+      node, scopedEnum(overflow));
+}
+
+YGOverflow YGNodeStyleGetOverflow(const YGNodeConstRef node) {
+  return unscopedEnum(resolveRef(node)->getStyle().overflow());
+}
+
+void YGNodeStyleSetDisplay(const YGNodeRef node, const YGDisplay display) {
+  updateStyle<&Style::display, &Style::setDisplay>(node, scopedEnum(display));
+}
+
+YGDisplay YGNodeStyleGetDisplay(const YGNodeConstRef node) {
+  return unscopedEnum(resolveRef(node)->getStyle().display());
+}
+
+void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) {
+  updateStyle<&Style::flex, &Style::setFlex>(node, FloatOptional{flex});
+}
+
+float YGNodeStyleGetFlex(const YGNodeConstRef nodeRef) {
+  const auto node = resolveRef(nodeRef);
+  return node->getStyle().flex().isUndefined()
+      ? YGUndefined
+      : node->getStyle().flex().unwrap();
+}
+
+void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) {
+  updateStyle<&Style::flexGrow, &Style::setFlexGrow>(
+      node, FloatOptional{flexGrow});
+}
+
+float YGNodeStyleGetFlexGrow(const YGNodeConstRef nodeRef) {
+  const auto node = resolveRef(nodeRef);
+  return node->getStyle().flexGrow().isUndefined()
+      ? Style::DefaultFlexGrow
+      : node->getStyle().flexGrow().unwrap();
+}
+
+void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) {
+  updateStyle<&Style::flexShrink, &Style::setFlexShrink>(
+      node, FloatOptional{flexShrink});
+}
+
+float YGNodeStyleGetFlexShrink(const YGNodeConstRef nodeRef) {
+  const auto node = resolveRef(nodeRef);
+  return node->getStyle().flexShrink().isUndefined()
+      ? (node->getConfig()->useWebDefaults() ? Style::WebDefaultFlexShrink
+                                             : Style::DefaultFlexShrink)
+      : node->getStyle().flexShrink().unwrap();
+}
+
+void YGNodeStyleSetFlexBasis(const YGNodeRef node, const float flexBasis) {
+  updateStyle<&Style::flexBasis, &Style::setFlexBasis>(
+      node, value::points(flexBasis));
+}
+
+void YGNodeStyleSetFlexBasisPercent(
+    const YGNodeRef node,
+    const float flexBasisPercent) {
+  updateStyle<&Style::flexBasis, &Style::setFlexBasis>(
+      node, value::percent(flexBasisPercent));
+}
+
+void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) {
+  updateStyle<&Style::flexBasis, &Style::setFlexBasis>(node, value::ofAuto());
+}
+
+YGValue YGNodeStyleGetFlexBasis(const YGNodeConstRef node) {
+  return (YGValue)resolveRef(node)->getStyle().flexBasis();
+}
+
+void YGNodeStyleSetPosition(YGNodeRef node, YGEdge edge, float points) {
+  updateStyle<&Style::position, &Style::setPosition>(
+      node, scopedEnum(edge), value::points(points));
+}
+
+void YGNodeStyleSetPositionPercent(YGNodeRef node, YGEdge edge, float percent) {
+  updateStyle<&Style::position, &Style::setPosition>(
+      node, scopedEnum(edge), value::percent(percent));
+}
+
+YGValue YGNodeStyleGetPosition(YGNodeConstRef node, YGEdge edge) {
+  return (YGValue)resolveRef(node)->getStyle().position(scopedEnum(edge));
+}
+
+void YGNodeStyleSetMargin(YGNodeRef node, YGEdge edge, float points) {
+  updateStyle<&Style::margin, &Style::setMargin>(
+      node, scopedEnum(edge), value::points(points));
+}
+
+void YGNodeStyleSetMarginPercent(YGNodeRef node, YGEdge edge, float percent) {
+  updateStyle<&Style::margin, &Style::setMargin>(
+      node, scopedEnum(edge), value::percent(percent));
+}
+
+void YGNodeStyleSetMarginAuto(YGNodeRef node, YGEdge edge) {
+  updateStyle<&Style::margin, &Style::setMargin>(
+      node, scopedEnum(edge), value::ofAuto());
+}
+
+YGValue YGNodeStyleGetMargin(YGNodeConstRef node, YGEdge edge) {
+  return (YGValue)resolveRef(node)->getStyle().margin(scopedEnum(edge));
+}
+
+void YGNodeStyleSetPadding(YGNodeRef node, YGEdge edge, float points) {
+  updateStyle<&Style::padding, &Style::setPadding>(
+      node, scopedEnum(edge), value::points(points));
+}
+
+void YGNodeStyleSetPaddingPercent(YGNodeRef node, YGEdge edge, float percent) {
+  updateStyle<&Style::padding, &Style::setPadding>(
+      node, scopedEnum(edge), value::percent(percent));
+}
+
+YGValue YGNodeStyleGetPadding(YGNodeConstRef node, YGEdge edge) {
+  return (YGValue)resolveRef(node)->getStyle().padding(scopedEnum(edge));
+}
+
+void YGNodeStyleSetBorder(
+    const YGNodeRef node,
+    const YGEdge edge,
+    const float border) {
+  updateStyle<&Style::border, &Style::setBorder>(
+      node, scopedEnum(edge), value::points(border));
+}
+
+float YGNodeStyleGetBorder(const YGNodeConstRef node, const YGEdge edge) {
+  auto border = resolveRef(node)->getStyle().border(scopedEnum(edge));
+  if (border.isUndefined() || border.isAuto()) {
+    return YGUndefined;
+  }
+
+  return static_cast<YGValue>(border).value;
+}
+
+void YGNodeStyleSetGap(
+    const YGNodeRef node,
+    const YGGutter gutter,
+    const float gapLength) {
+  updateStyle<&Style::gap, &Style::setGap>(
+      node, scopedEnum(gutter), value::points(gapLength));
+}
+
+float YGNodeStyleGetGap(const YGNodeConstRef node, const YGGutter gutter) {
+  auto gapLength = resolveRef(node)->getStyle().gap(scopedEnum(gutter));
+  if (gapLength.isUndefined() || gapLength.isAuto()) {
+    return YGUndefined;
+  }
+
+  return static_cast<YGValue>(gapLength).value;
+}
+
+void YGNodeStyleSetAspectRatio(const YGNodeRef node, const float aspectRatio) {
+  updateStyle<&Style::aspectRatio, &Style::setAspectRatio>(
+      node, FloatOptional{aspectRatio});
+}
+
+float YGNodeStyleGetAspectRatio(const YGNodeConstRef node) {
+  const FloatOptional op = resolveRef(node)->getStyle().aspectRatio();
+  return op.isUndefined() ? YGUndefined : op.unwrap();
+}
+
+void YGNodeStyleSetWidth(YGNodeRef node, float points) {
+  updateStyle<&Style::dimension, &Style::setDimension>(
+      node, Dimension::Width, value::points(points));
+}
+
+void YGNodeStyleSetWidthPercent(YGNodeRef node, float percent) {
+  updateStyle<&Style::dimension, &Style::setDimension>(
+      node, Dimension::Width, value::percent(percent));
+}
+
+void YGNodeStyleSetWidthAuto(YGNodeRef node) {
+  updateStyle<&Style::dimension, &Style::setDimension>(
+      node, Dimension::Width, value::ofAuto());
+}
+
+YGValue YGNodeStyleGetWidth(YGNodeConstRef node) {
+  return (YGValue)resolveRef(node)->getStyle().dimension(Dimension::Width);
+}
+
+void YGNodeStyleSetHeight(YGNodeRef node, float points) {
+  updateStyle<&Style::dimension, &Style::setDimension>(
+      node, Dimension::Height, value::points(points));
+}
+
+void YGNodeStyleSetHeightPercent(YGNodeRef node, float percent) {
+  updateStyle<&Style::dimension, &Style::setDimension>(
+      node, Dimension::Height, value::percent(percent));
+}
+
+void YGNodeStyleSetHeightAuto(YGNodeRef node) {
+  updateStyle<&Style::dimension, &Style::setDimension>(
+      node, Dimension::Height, value::ofAuto());
+}
+
+YGValue YGNodeStyleGetHeight(YGNodeConstRef node) {
+  return (YGValue)resolveRef(node)->getStyle().dimension(Dimension::Height);
+}
+
+void YGNodeStyleSetMinWidth(const YGNodeRef node, const float minWidth) {
+  updateStyle<&Style::minDimension, &Style::setMinDimension>(
+      node, Dimension::Width, value::points(minWidth));
+}
+
+void YGNodeStyleSetMinWidthPercent(const YGNodeRef node, const float minWidth) {
+  updateStyle<&Style::minDimension, &Style::setMinDimension>(
+      node, Dimension::Width, value::percent(minWidth));
+}
+
+YGValue YGNodeStyleGetMinWidth(const YGNodeConstRef node) {
+  return (YGValue)resolveRef(node)->getStyle().minDimension(Dimension::Width);
+}
+
+void YGNodeStyleSetMinHeight(const YGNodeRef node, const float minHeight) {
+  updateStyle<&Style::minDimension, &Style::setMinDimension>(
+      node, Dimension::Height, value::points(minHeight));
+}
+
+void YGNodeStyleSetMinHeightPercent(
+    const YGNodeRef node,
+    const float minHeight) {
+  updateStyle<&Style::minDimension, &Style::setMinDimension>(
+      node, Dimension::Height, value::percent(minHeight));
+}
+
+YGValue YGNodeStyleGetMinHeight(const YGNodeConstRef node) {
+  return (YGValue)resolveRef(node)->getStyle().minDimension(Dimension::Height);
+}
+
+void YGNodeStyleSetMaxWidth(const YGNodeRef node, const float maxWidth) {
+  updateStyle<&Style::maxDimension, &Style::setMaxDimension>(
+      node, Dimension::Width, value::points(maxWidth));
+}
+
+void YGNodeStyleSetMaxWidthPercent(const YGNodeRef node, const float maxWidth) {
+  updateStyle<&Style::maxDimension, &Style::setMaxDimension>(
+      node, Dimension::Width, value::percent(maxWidth));
+}
+
+YGValue YGNodeStyleGetMaxWidth(const YGNodeConstRef node) {
+  return (YGValue)resolveRef(node)->getStyle().maxDimension(Dimension::Width);
+}
+
+void YGNodeStyleSetMaxHeight(const YGNodeRef node, const float maxHeight) {
+  updateStyle<&Style::maxDimension, &Style::setMaxDimension>(
+      node, Dimension::Height, value::points(maxHeight));
+}
+
+void YGNodeStyleSetMaxHeightPercent(
+    const YGNodeRef node,
+    const float maxHeight) {
+  updateStyle<&Style::maxDimension, &Style::setMaxDimension>(
+      node, Dimension::Height, value::percent(maxHeight));
+}
+
+YGValue YGNodeStyleGetMaxHeight(const YGNodeConstRef node) {
+  return (YGValue)resolveRef(node)->getStyle().maxDimension(Dimension::Height);
+}
+ yoga/yoga/YGNodeStyle.h view
@@ -0,0 +1,123 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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 <stddef.h>
+
+#include <yoga/YGNode.h>
+#include <yoga/YGValue.h>
+
+YG_EXTERN_C_BEGIN
+
+YG_EXPORT void YGNodeCopyStyle(YGNodeRef dstNode, YGNodeConstRef srcNode);
+
+YG_EXPORT void YGNodeStyleSetDirection(YGNodeRef node, YGDirection direction);
+YG_EXPORT YGDirection YGNodeStyleGetDirection(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetFlexDirection(
+    YGNodeRef node,
+    YGFlexDirection flexDirection);
+YG_EXPORT YGFlexDirection YGNodeStyleGetFlexDirection(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetJustifyContent(
+    YGNodeRef node,
+    YGJustify justifyContent);
+YG_EXPORT YGJustify YGNodeStyleGetJustifyContent(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetAlignContent(YGNodeRef node, YGAlign alignContent);
+YG_EXPORT YGAlign YGNodeStyleGetAlignContent(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetAlignItems(YGNodeRef node, YGAlign alignItems);
+YG_EXPORT YGAlign YGNodeStyleGetAlignItems(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetAlignSelf(YGNodeRef node, YGAlign alignSelf);
+YG_EXPORT YGAlign YGNodeStyleGetAlignSelf(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetPositionType(
+    YGNodeRef node,
+    YGPositionType positionType);
+YG_EXPORT YGPositionType YGNodeStyleGetPositionType(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetFlexWrap(YGNodeRef node, YGWrap flexWrap);
+YG_EXPORT YGWrap YGNodeStyleGetFlexWrap(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetOverflow(YGNodeRef node, YGOverflow overflow);
+YG_EXPORT YGOverflow YGNodeStyleGetOverflow(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetDisplay(YGNodeRef node, YGDisplay display);
+YG_EXPORT YGDisplay YGNodeStyleGetDisplay(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetFlex(YGNodeRef node, float flex);
+YG_EXPORT float YGNodeStyleGetFlex(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetFlexGrow(YGNodeRef node, float flexGrow);
+YG_EXPORT float YGNodeStyleGetFlexGrow(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetFlexShrink(YGNodeRef node, float flexShrink);
+YG_EXPORT float YGNodeStyleGetFlexShrink(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetFlexBasis(YGNodeRef node, float flexBasis);
+YG_EXPORT void YGNodeStyleSetFlexBasisPercent(YGNodeRef node, float flexBasis);
+YG_EXPORT void YGNodeStyleSetFlexBasisAuto(YGNodeRef node);
+YG_EXPORT YGValue YGNodeStyleGetFlexBasis(YGNodeConstRef node);
+
+YG_EXPORT void
+YGNodeStyleSetPosition(YGNodeRef node, YGEdge edge, float position);
+YG_EXPORT void
+YGNodeStyleSetPositionPercent(YGNodeRef node, YGEdge edge, float position);
+YG_EXPORT YGValue YGNodeStyleGetPosition(YGNodeConstRef node, YGEdge edge);
+
+YG_EXPORT void YGNodeStyleSetMargin(YGNodeRef node, YGEdge edge, float margin);
+YG_EXPORT void
+YGNodeStyleSetMarginPercent(YGNodeRef node, YGEdge edge, float margin);
+YG_EXPORT void YGNodeStyleSetMarginAuto(YGNodeRef node, YGEdge edge);
+YG_EXPORT YGValue YGNodeStyleGetMargin(YGNodeConstRef node, YGEdge edge);
+
+YG_EXPORT void
+YGNodeStyleSetPadding(YGNodeRef node, YGEdge edge, float padding);
+YG_EXPORT void
+YGNodeStyleSetPaddingPercent(YGNodeRef node, YGEdge edge, float padding);
+YG_EXPORT YGValue YGNodeStyleGetPadding(YGNodeConstRef node, YGEdge edge);
+
+YG_EXPORT void YGNodeStyleSetBorder(YGNodeRef node, YGEdge edge, float border);
+YG_EXPORT float YGNodeStyleGetBorder(YGNodeConstRef node, YGEdge edge);
+
+YG_EXPORT void
+YGNodeStyleSetGap(YGNodeRef node, YGGutter gutter, float gapLength);
+YG_EXPORT float YGNodeStyleGetGap(YGNodeConstRef node, YGGutter gutter);
+
+YG_EXPORT void YGNodeStyleSetWidth(YGNodeRef node, float width);
+YG_EXPORT void YGNodeStyleSetWidthPercent(YGNodeRef node, float width);
+YG_EXPORT void YGNodeStyleSetWidthAuto(YGNodeRef node);
+YG_EXPORT YGValue YGNodeStyleGetWidth(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetHeight(YGNodeRef node, float height);
+YG_EXPORT void YGNodeStyleSetHeightPercent(YGNodeRef node, float height);
+YG_EXPORT void YGNodeStyleSetHeightAuto(YGNodeRef node);
+YG_EXPORT YGValue YGNodeStyleGetHeight(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetMinWidth(YGNodeRef node, float minWidth);
+YG_EXPORT void YGNodeStyleSetMinWidthPercent(YGNodeRef node, float minWidth);
+YG_EXPORT YGValue YGNodeStyleGetMinWidth(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetMinHeight(YGNodeRef node, float minHeight);
+YG_EXPORT void YGNodeStyleSetMinHeightPercent(YGNodeRef node, float minHeight);
+YG_EXPORT YGValue YGNodeStyleGetMinHeight(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetMaxWidth(YGNodeRef node, float maxWidth);
+YG_EXPORT void YGNodeStyleSetMaxWidthPercent(YGNodeRef node, float maxWidth);
+YG_EXPORT YGValue YGNodeStyleGetMaxWidth(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetMaxHeight(YGNodeRef node, float maxHeight);
+YG_EXPORT void YGNodeStyleSetMaxHeightPercent(YGNodeRef node, float maxHeight);
+YG_EXPORT YGValue YGNodeStyleGetMaxHeight(YGNodeConstRef node);
+
+YG_EXPORT void YGNodeStyleSetAspectRatio(YGNodeRef node, float aspectRatio);
+YG_EXPORT float YGNodeStyleGetAspectRatio(YGNodeConstRef node);
+
+YG_EXTERN_C_END
+ yoga/yoga/YGPixelGrid.cpp view
@@ -0,0 +1,22 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>
+
+#include <yoga/algorithm/PixelGrid.h>
+
+using namespace facebook;
+using namespace facebook::yoga;
+
+float YGRoundValueToPixelGrid(
+    const double value,
+    const double pointScaleFactor,
+    const bool forceCeil,
+    const bool forceFloor) {
+  return yoga::roundValueToPixelGrid(
+      value, pointScaleFactor, forceCeil, forceFloor);
+}
+ yoga/yoga/YGPixelGrid.h view
@@ -0,0 +1,29 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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 <stdbool.h>
+
+#include <yoga/YGConfig.h>
+#include <yoga/YGEnums.h>
+#include <yoga/YGMacros.h>
+
+YG_EXTERN_C_BEGIN
+
+/**
+ * Rounds a point value to the nearest whole pixel, given a pointScaleFactor
+ * describing pixel density.
+ * @returns the rounded value in points
+ */
+YG_EXPORT float YGRoundValueToPixelGrid(
+    double value,
+    double pointScaleFactor,
+    bool forceCeil,
+    bool forceFloor);
+
+YG_EXTERN_C_END
+ yoga/yoga/YGValue.cpp view
@@ -0,0 +1,20 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/YGValue.h>
+#include <yoga/numeric/Comparison.h>
+
+using namespace facebook;
+using namespace facebook::yoga;
+
+const YGValue YGValueZero = {0, YGUnitPoint};
+const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined};
+const YGValue YGValueAuto = {YGUndefined, YGUnitAuto};
+
+bool YGFloatIsUndefined(const float value) {
+  return yoga::isUndefined(value);
+}
+ yoga/yoga/YGValue.h view
@@ -0,0 +1,84 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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 <stdbool.h>
+
+#include <yoga/YGEnums.h>
+#include <yoga/YGMacros.h>
+
+/**
+ * Float value to represent "undefined" in style values.
+ */
+#ifdef __cplusplus
+#include <limits>
+constexpr float YGUndefined = std::numeric_limits<float>::quiet_NaN();
+#else
+#include <math.h>
+#define YGUndefined NAN
+#endif
+
+YG_EXTERN_C_BEGIN
+
+/**
+ * Structure used to represent a dimension in a style.
+ */
+typedef struct YGValue {
+  float value;
+  YGUnit unit;
+} YGValue;
+
+/**
+ * Constant for a dimension of "auto".
+ */
+YG_EXPORT extern const YGValue YGValueAuto;
+
+/**
+ * Constant for a dimension which is not defined.
+ */
+YG_EXPORT extern const YGValue YGValueUndefined;
+
+/**
+ * Constant for a dimension that is zero-length.
+ */
+YG_EXPORT extern const YGValue YGValueZero;
+
+/**
+ * Whether a dimension represented as a float is defined.
+ */
+YG_EXPORT bool YGFloatIsUndefined(float value);
+
+YG_EXTERN_C_END
+
+// Equality operators for comparison of YGValue in C++
+#ifdef __cplusplus
+inline bool operator==(const YGValue& lhs, const YGValue& rhs) {
+  if (lhs.unit != rhs.unit) {
+    return false;
+  }
+
+  switch (lhs.unit) {
+    case YGUnitUndefined:
+    case YGUnitAuto:
+      return true;
+    case YGUnitPoint:
+    case YGUnitPercent:
+      return lhs.value == rhs.value;
+  }
+
+  return false;
+}
+
+inline bool operator!=(const YGValue& lhs, const YGValue& rhs) {
+  return !(lhs == rhs);
+}
+
+inline YGValue operator-(const YGValue& value) {
+  return {-value.value, value.unit};
+}
+#endif
+ yoga/yoga/Yoga.h view
@@ -0,0 +1,21 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>` includes all of Yoga's public headers.
+ */
+
+#include <yoga/YGConfig.h>
+#include <yoga/YGEnums.h>
+#include <yoga/YGMacros.h>
+#include <yoga/YGNode.h>
+#include <yoga/YGNodeLayout.h>
+#include <yoga/YGNodeStyle.h>
+#include <yoga/YGPixelGrid.h>
+#include <yoga/YGValue.h>
+ yoga/yoga/algorithm/AbsoluteLayout.cpp view
@@ -0,0 +1,556 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/algorithm/AbsoluteLayout.h>
+#include <yoga/algorithm/Align.h>
+#include <yoga/algorithm/BoundAxis.h>
+#include <yoga/algorithm/CalculateLayout.h>
+#include <yoga/algorithm/TrailingPosition.h>
+
+namespace facebook::yoga {
+
+static inline void setFlexStartLayoutPosition(
+    const yoga::Node* const parent,
+    yoga::Node* child,
+    const Direction direction,
+    const FlexDirection axis,
+    const float containingBlockWidth) {
+  child->setLayoutPosition(
+      child->getFlexStartMargin(axis, direction, containingBlockWidth) +
+          parent->getLayout().border(flexStartEdge(axis)) +
+          parent->getLayout().padding(flexStartEdge(axis)),
+      flexStartEdge(axis));
+}
+
+static inline void setFlexEndLayoutPosition(
+    const yoga::Node* const parent,
+    yoga::Node* child,
+    const Direction direction,
+    const FlexDirection axis,
+    const float containingBlockWidth) {
+  child->setLayoutPosition(
+      getPositionOfOppositeEdge(
+          parent->getLayout().border(flexEndEdge(axis)) +
+              parent->getLayout().padding(flexEndEdge(axis)) +
+              child->getFlexEndMargin(axis, direction, containingBlockWidth),
+          axis,
+          parent,
+          child),
+      flexStartEdge(axis));
+}
+
+static inline void setCenterLayoutPosition(
+    const yoga::Node* const parent,
+    yoga::Node* child,
+    const Direction direction,
+    const FlexDirection axis,
+    const float containingBlockWidth) {
+  const float parentContentBoxSize =
+      parent->getLayout().measuredDimension(dimension(axis)) -
+      parent->getLayout().border(flexStartEdge(axis)) -
+      parent->getLayout().border(flexEndEdge(axis)) -
+      parent->getLayout().padding(flexStartEdge(axis)) -
+      parent->getLayout().padding(flexEndEdge(axis));
+  const float childOuterSize =
+      child->getLayout().measuredDimension(dimension(axis)) +
+      child->getMarginForAxis(axis, containingBlockWidth);
+  child->setLayoutPosition(
+      (parentContentBoxSize - childOuterSize) / 2.0f +
+          parent->getLayout().border(flexStartEdge(axis)) +
+          parent->getLayout().padding(flexStartEdge(axis)) +
+          child->getFlexStartMargin(axis, direction, containingBlockWidth),
+      flexStartEdge(axis));
+}
+
+static void justifyAbsoluteChild(
+    const yoga::Node* const parent,
+    yoga::Node* child,
+    const Direction direction,
+    const FlexDirection mainAxis,
+    const float containingBlockWidth) {
+  const Justify parentJustifyContent = parent->getStyle().justifyContent();
+  switch (parentJustifyContent) {
+    case Justify::FlexStart:
+    case Justify::SpaceBetween:
+      setFlexStartLayoutPosition(
+          parent, child, direction, mainAxis, containingBlockWidth);
+      break;
+    case Justify::FlexEnd:
+      setFlexEndLayoutPosition(
+          parent, child, direction, mainAxis, containingBlockWidth);
+      break;
+    case Justify::Center:
+    case Justify::SpaceAround:
+    case Justify::SpaceEvenly:
+      setCenterLayoutPosition(
+          parent, child, direction, mainAxis, containingBlockWidth);
+      break;
+  }
+}
+
+static void alignAbsoluteChild(
+    const yoga::Node* const parent,
+    yoga::Node* child,
+    const Direction direction,
+    const FlexDirection crossAxis,
+    const float containingBlockWidth) {
+  Align itemAlign = resolveChildAlignment(parent, child);
+  const Wrap parentWrap = parent->getStyle().flexWrap();
+  if (parentWrap == Wrap::WrapReverse) {
+    if (itemAlign == Align::FlexEnd) {
+      itemAlign = Align::FlexStart;
+    } else if (itemAlign != Align::Center) {
+      itemAlign = Align::FlexEnd;
+    }
+  }
+
+  switch (itemAlign) {
+    case Align::Auto:
+    case Align::FlexStart:
+    case Align::Baseline:
+    case Align::SpaceAround:
+    case Align::SpaceBetween:
+    case Align::Stretch:
+    case Align::SpaceEvenly:
+      setFlexStartLayoutPosition(
+          parent, child, direction, crossAxis, containingBlockWidth);
+      break;
+    case Align::FlexEnd:
+      setFlexEndLayoutPosition(
+          parent, child, direction, crossAxis, containingBlockWidth);
+      break;
+    case Align::Center:
+      setCenterLayoutPosition(
+          parent, child, direction, crossAxis, containingBlockWidth);
+      break;
+  }
+}
+
+// To ensure no breaking changes, we preserve the legacy way of positioning
+// absolute children and determine if we should use it using an errata.
+static void positionAbsoluteChildLegacy(
+    const yoga::Node* const containingNode,
+    const yoga::Node* const parent,
+    yoga::Node* child,
+    const Direction direction,
+    const FlexDirection axis,
+    const bool isMainAxis,
+    const float containingBlockWidth,
+    const float containingBlockHeight) {
+  const bool isAxisRow = isRow(axis);
+  const bool shouldCenter = isMainAxis
+      ? parent->getStyle().justifyContent() == Justify::Center
+      : resolveChildAlignment(parent, child) == Align::Center;
+  const bool shouldFlexEnd = isMainAxis
+      ? parent->getStyle().justifyContent() == Justify::FlexEnd
+      : ((resolveChildAlignment(parent, child) == Align::FlexEnd) ^
+         (parent->getStyle().flexWrap() == Wrap::WrapReverse));
+
+  if (child->isFlexEndPositionDefined(axis, direction) &&
+      !child->isFlexStartPositionDefined(axis, direction)) {
+    child->setLayoutPosition(
+        containingNode->getLayout().measuredDimension(dimension(axis)) -
+            child->getLayout().measuredDimension(dimension(axis)) -
+            containingNode->getFlexEndBorder(axis, direction) -
+            child->getFlexEndMargin(
+                axis,
+                direction,
+                isAxisRow ? containingBlockWidth : containingBlockHeight) -
+            child->getFlexEndPosition(
+                axis,
+                direction,
+                isAxisRow ? containingBlockWidth : containingBlockHeight),
+        flexStartEdge(axis));
+  } else if (
+      !child->isFlexStartPositionDefined(axis, direction) && shouldCenter) {
+    child->setLayoutPosition(
+        (parent->getLayout().measuredDimension(dimension(axis)) -
+         child->getLayout().measuredDimension(dimension(axis))) /
+            2.0f,
+        flexStartEdge(axis));
+  } else if (
+      !child->isFlexStartPositionDefined(axis, direction) && shouldFlexEnd) {
+    child->setLayoutPosition(
+        (parent->getLayout().measuredDimension(dimension(axis)) -
+         child->getLayout().measuredDimension(dimension(axis))),
+        flexStartEdge(axis));
+  } else if (
+      parent->getConfig()->isExperimentalFeatureEnabled(
+          ExperimentalFeature::AbsolutePercentageAgainstPaddingEdge) &&
+      child->isFlexStartPositionDefined(axis, direction)) {
+    child->setLayoutPosition(
+        child->getFlexStartPosition(
+            axis,
+            direction,
+            containingNode->getLayout().measuredDimension(dimension(axis))) +
+            containingNode->getFlexStartBorder(axis, direction) +
+            child->getFlexStartMargin(
+                axis,
+                direction,
+                isAxisRow ? containingBlockWidth : containingBlockHeight),
+        flexStartEdge(axis));
+  }
+}
+
+/*
+ * Absolutely positioned nodes do not participate in flex layout and thus their
+ * positions can be determined independently from the rest of their siblings.
+ * For each axis there are essentially two cases:
+ *
+ * 1) The node has insets defined. In this case we can just use these to
+ *    determine the position of the node.
+ * 2) The node does not have insets defined. In this case we look at the style
+ *    of the parent to position the node. Things like justify content and
+ *    align content will move absolute children around. If none of these
+ *    special properties are defined, the child is positioned at the start
+ *    (defined by flex direction) of the leading flex line.
+ *
+ * This function does that positioning for the given axis. The spec has more
+ * information on this topic: https://www.w3.org/TR/css-flexbox-1/#abspos-items
+ */
+static void positionAbsoluteChildImpl(
+    const yoga::Node* const containingNode,
+    const yoga::Node* const parent,
+    yoga::Node* child,
+    const Direction direction,
+    const FlexDirection axis,
+    const bool isMainAxis,
+    const float containingBlockWidth,
+    const float containingBlockHeight) {
+  const bool isAxisRow = isRow(axis);
+  const float containingBlockSize =
+      isAxisRow ? containingBlockWidth : containingBlockHeight;
+
+  // The inline-start position takes priority over the end position in the case
+  // that they are both set and the node has a fixed width. Thus we only have 2
+  // cases here: if inline-start is defined and if inline-end is defined.
+  //
+  // Despite checking inline-start to honor prioritization of insets, we write
+  // to the flex-start edge because this algorithm works by positioning on the
+  // flex-start edge and then filling in the flex-end direction at the end if
+  // necessary.
+  if (child->isInlineStartPositionDefined(axis, direction)) {
+    const float positionRelativeToInlineStart =
+        child->getInlineStartPosition(axis, direction, containingBlockSize) +
+        containingNode->getInlineStartBorder(axis, direction) +
+        child->getInlineStartMargin(axis, direction, containingBlockSize);
+    const float positionRelativeToFlexStart =
+        inlineStartEdge(axis, direction) != flexStartEdge(axis)
+        ? getPositionOfOppositeEdge(
+              positionRelativeToInlineStart, axis, containingNode, child)
+        : positionRelativeToInlineStart;
+
+    child->setLayoutPosition(positionRelativeToFlexStart, flexStartEdge(axis));
+  } else if (child->isInlineEndPositionDefined(axis, direction)) {
+    const float positionRelativeToInlineStart =
+        containingNode->getLayout().measuredDimension(dimension(axis)) -
+        child->getLayout().measuredDimension(dimension(axis)) -
+        containingNode->getInlineEndBorder(axis, direction) -
+        child->getInlineEndMargin(axis, direction, containingBlockSize) -
+        child->getInlineEndPosition(axis, direction, containingBlockSize);
+    const float positionRelativeToFlexStart =
+        inlineStartEdge(axis, direction) != flexStartEdge(axis)
+        ? getPositionOfOppositeEdge(
+              positionRelativeToInlineStart, axis, containingNode, child)
+        : positionRelativeToInlineStart;
+
+    child->setLayoutPosition(positionRelativeToFlexStart, flexStartEdge(axis));
+  } else {
+    isMainAxis ? justifyAbsoluteChild(
+                     parent, child, direction, axis, containingBlockWidth)
+               : alignAbsoluteChild(
+                     parent, child, direction, axis, containingBlockWidth);
+  }
+}
+
+static void positionAbsoluteChild(
+    const yoga::Node* const containingNode,
+    const yoga::Node* const parent,
+    yoga::Node* child,
+    const Direction direction,
+    const FlexDirection axis,
+    const bool isMainAxis,
+    const float containingBlockWidth,
+    const float containingBlockHeight) {
+  child->hasErrata(Errata::AbsolutePositioning) ? positionAbsoluteChildLegacy(
+                                                      containingNode,
+                                                      parent,
+                                                      child,
+                                                      direction,
+                                                      axis,
+                                                      isMainAxis,
+                                                      containingBlockWidth,
+                                                      containingBlockHeight)
+                                                : positionAbsoluteChildImpl(
+                                                      containingNode,
+                                                      parent,
+                                                      child,
+                                                      direction,
+                                                      axis,
+                                                      isMainAxis,
+                                                      containingBlockWidth,
+                                                      containingBlockHeight);
+}
+
+void layoutAbsoluteChild(
+    const yoga::Node* const containingNode,
+    const yoga::Node* const node,
+    yoga::Node* const child,
+    const float containingBlockWidth,
+    const float containingBlockHeight,
+    const SizingMode widthMode,
+    const Direction direction,
+    LayoutData& layoutMarkerData,
+    const uint32_t depth,
+    const uint32_t generationCount) {
+  const FlexDirection mainAxis =
+      resolveDirection(node->getStyle().flexDirection(), direction);
+  const FlexDirection crossAxis = resolveCrossDirection(mainAxis, direction);
+  const bool isMainAxisRow = isRow(mainAxis);
+
+  float childWidth = YGUndefined;
+  float childHeight = YGUndefined;
+  SizingMode childWidthSizingMode = SizingMode::MaxContent;
+  SizingMode childHeightSizingMode = SizingMode::MaxContent;
+
+  auto marginRow =
+      child->getMarginForAxis(FlexDirection::Row, containingBlockWidth);
+  auto marginColumn =
+      child->getMarginForAxis(FlexDirection::Column, containingBlockWidth);
+
+  if (child->hasDefiniteLength(Dimension::Width, containingBlockWidth)) {
+    childWidth = child->getResolvedDimension(Dimension::Width)
+                     .resolve(containingBlockWidth)
+                     .unwrap() +
+        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->isFlexStartPositionDefined(FlexDirection::Row, direction) &&
+        child->isFlexEndPositionDefined(FlexDirection::Row, direction)) {
+      childWidth =
+          containingNode->getLayout().measuredDimension(Dimension::Width) -
+          (containingNode->getFlexStartBorder(FlexDirection::Row, direction) +
+           containingNode->getFlexEndBorder(FlexDirection::Row, direction)) -
+          (child->getFlexStartPosition(
+               FlexDirection::Row, direction, containingBlockWidth) +
+           child->getFlexEndPosition(
+               FlexDirection::Row, direction, containingBlockWidth));
+      childWidth = boundAxis(
+          child,
+          FlexDirection::Row,
+          childWidth,
+          containingBlockWidth,
+          containingBlockWidth);
+    }
+  }
+
+  if (child->hasDefiniteLength(Dimension::Height, containingBlockHeight)) {
+    childHeight = child->getResolvedDimension(Dimension::Height)
+                      .resolve(containingBlockHeight)
+                      .unwrap() +
+        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->isFlexStartPositionDefined(FlexDirection::Column, direction) &&
+        child->isFlexEndPositionDefined(FlexDirection::Column, direction)) {
+      childHeight =
+          containingNode->getLayout().measuredDimension(Dimension::Height) -
+          (containingNode->getFlexStartBorder(
+               FlexDirection::Column, direction) +
+           containingNode->getFlexEndBorder(FlexDirection::Column, direction)) -
+          (child->getFlexStartPosition(
+               FlexDirection::Column, direction, containingBlockHeight) +
+           child->getFlexEndPosition(
+               FlexDirection::Column, direction, containingBlockHeight));
+      childHeight = boundAxis(
+          child,
+          FlexDirection::Column,
+          childHeight,
+          containingBlockHeight,
+          containingBlockWidth);
+    }
+  }
+
+  // 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.
+  const auto& childStyle = child->getStyle();
+  if (yoga::isUndefined(childWidth) ^ yoga::isUndefined(childHeight)) {
+    if (childStyle.aspectRatio().isDefined()) {
+      if (yoga::isUndefined(childWidth)) {
+        childWidth = marginRow +
+            (childHeight - marginColumn) * childStyle.aspectRatio().unwrap();
+      } else if (yoga::isUndefined(childHeight)) {
+        childHeight = marginColumn +
+            (childWidth - marginRow) / childStyle.aspectRatio().unwrap();
+      }
+    }
+  }
+
+  // If we're still missing one or the other dimension, measure the content.
+  if (yoga::isUndefined(childWidth) || yoga::isUndefined(childHeight)) {
+    childWidthSizingMode = yoga::isUndefined(childWidth)
+        ? SizingMode::MaxContent
+        : SizingMode::StretchFit;
+    childHeightSizingMode = yoga::isUndefined(childHeight)
+        ? SizingMode::MaxContent
+        : SizingMode::StretchFit;
+
+    // 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 && yoga::isUndefined(childWidth) &&
+        widthMode != SizingMode::MaxContent &&
+        yoga::isDefined(containingBlockWidth) && containingBlockWidth > 0) {
+      childWidth = containingBlockWidth;
+      childWidthSizingMode = SizingMode::FitContent;
+    }
+
+    calculateLayoutInternal(
+        child,
+        childWidth,
+        childHeight,
+        direction,
+        childWidthSizingMode,
+        childHeightSizingMode,
+        containingBlockWidth,
+        containingBlockHeight,
+        false,
+        LayoutPassReason::kAbsMeasureChild,
+        layoutMarkerData,
+        depth,
+        generationCount);
+    childWidth = child->getLayout().measuredDimension(Dimension::Width) +
+        child->getMarginForAxis(FlexDirection::Row, containingBlockWidth);
+    childHeight = child->getLayout().measuredDimension(Dimension::Height) +
+        child->getMarginForAxis(FlexDirection::Column, containingBlockWidth);
+  }
+
+  calculateLayoutInternal(
+      child,
+      childWidth,
+      childHeight,
+      direction,
+      SizingMode::StretchFit,
+      SizingMode::StretchFit,
+      containingBlockWidth,
+      containingBlockHeight,
+      true,
+      LayoutPassReason::kAbsLayout,
+      layoutMarkerData,
+      depth,
+      generationCount);
+
+  positionAbsoluteChild(
+      containingNode,
+      node,
+      child,
+      direction,
+      mainAxis,
+      true /*isMainAxis*/,
+      containingBlockWidth,
+      containingBlockHeight);
+  positionAbsoluteChild(
+      containingNode,
+      node,
+      child,
+      direction,
+      crossAxis,
+      false /*isMainAxis*/,
+      containingBlockWidth,
+      containingBlockHeight);
+}
+
+void layoutAbsoluteDescendants(
+    yoga::Node* containingNode,
+    yoga::Node* currentNode,
+    SizingMode widthSizingMode,
+    Direction currentNodeDirection,
+    LayoutData& layoutMarkerData,
+    uint32_t currentDepth,
+    uint32_t generationCount,
+    float currentNodeMainOffsetFromContainingBlock,
+    float currentNodeCrossOffsetFromContainingBlock) {
+  const FlexDirection mainAxis = resolveDirection(
+      currentNode->getStyle().flexDirection(), currentNodeDirection);
+  const FlexDirection crossAxis =
+      resolveCrossDirection(mainAxis, currentNodeDirection);
+  for (auto child : currentNode->getChildren()) {
+    if (child->getStyle().display() == Display::None) {
+      continue;
+    } else if (child->getStyle().positionType() == PositionType::Absolute) {
+      layoutAbsoluteChild(
+          containingNode,
+          currentNode,
+          child,
+          containingNode->getLayout().measuredDimension(Dimension::Width) -
+              containingNode->getBorderForAxis(FlexDirection::Row),
+          containingNode->getLayout().measuredDimension(Dimension::Height) -
+              containingNode->getBorderForAxis(FlexDirection::Column),
+          widthSizingMode,
+          currentNodeDirection,
+          layoutMarkerData,
+          currentDepth,
+          generationCount);
+
+      const bool isMainAxisRow = isRow(mainAxis);
+      const bool mainInsetsDefined = isMainAxisRow
+          ? child->getStyle().horizontalInsetsDefined()
+          : child->getStyle().verticalInsetsDefined();
+      const bool crossInsetsDefined = isMainAxisRow
+          ? child->getStyle().verticalInsetsDefined()
+          : child->getStyle().horizontalInsetsDefined();
+
+      const float childMainOffsetFromParent = mainInsetsDefined
+          ? (child->getLayout().position(flexStartEdge(mainAxis)) -
+             currentNodeMainOffsetFromContainingBlock)
+          : child->getLayout().position(flexStartEdge(mainAxis));
+      const float childCrossOffsetFromParent = crossInsetsDefined
+          ? (child->getLayout().position(flexStartEdge(crossAxis)) -
+             currentNodeCrossOffsetFromContainingBlock)
+          : child->getLayout().position(flexStartEdge(crossAxis));
+
+      child->setLayoutPosition(
+          childMainOffsetFromParent, flexStartEdge(mainAxis));
+      child->setLayoutPosition(
+          childCrossOffsetFromParent, flexStartEdge(crossAxis));
+
+      if (needsTrailingPosition(mainAxis)) {
+        setChildTrailingPosition(currentNode, child, mainAxis);
+      }
+      if (needsTrailingPosition(crossAxis)) {
+        setChildTrailingPosition(currentNode, child, crossAxis);
+      }
+    } else if (
+        child->getStyle().positionType() == PositionType::Static &&
+        !child->alwaysFormsContainingBlock()) {
+      const Direction childDirection =
+          child->resolveDirection(currentNodeDirection);
+      const float childMainOffsetFromContainingBlock =
+          currentNodeMainOffsetFromContainingBlock +
+          child->getLayout().position(flexStartEdge(mainAxis));
+      const float childCrossOffsetFromContainingBlock =
+          currentNodeCrossOffsetFromContainingBlock +
+          child->getLayout().position(flexStartEdge(crossAxis));
+
+      layoutAbsoluteDescendants(
+          containingNode,
+          child,
+          widthSizingMode,
+          childDirection,
+          layoutMarkerData,
+          currentDepth + 1,
+          generationCount,
+          childMainOffsetFromContainingBlock,
+          childCrossOffsetFromContainingBlock);
+    }
+  }
+}
+} // namespace facebook::yoga
+ yoga/yoga/algorithm/AbsoluteLayout.h view
@@ -0,0 +1,38 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/event/event.h>
+#include <yoga/node/Node.h>
+
+namespace facebook::yoga {
+
+void layoutAbsoluteChild(
+    const yoga::Node* const containingNode,
+    const yoga::Node* const node,
+    yoga::Node* const child,
+    const float containingBlockWidth,
+    const float containingBlockHeight,
+    const SizingMode widthMode,
+    const Direction direction,
+    LayoutData& layoutMarkerData,
+    const uint32_t depth,
+    const uint32_t generationCount);
+
+void layoutAbsoluteDescendants(
+    yoga::Node* containingNode,
+    yoga::Node* currentNode,
+    SizingMode widthSizingMode,
+    Direction currentNodeDirection,
+    LayoutData& layoutMarkerData,
+    uint32_t currentDepth,
+    uint32_t generationCount,
+    float currentNodeMainOffsetFromContainingBlock,
+    float currentNodeCrossOffsetFromContainingBlock);
+
+} // namespace facebook::yoga
+ yoga/yoga/algorithm/Align.h view
@@ -0,0 +1,29 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>
+
+#include <yoga/algorithm/FlexDirection.h>
+#include <yoga/node/Node.h>
+
+namespace facebook::yoga {
+
+inline Align resolveChildAlignment(
+    const yoga::Node* node,
+    const yoga::Node* child) {
+  const Align align = child->getStyle().alignSelf() == Align::Auto
+      ? node->getStyle().alignItems()
+      : child->getStyle().alignSelf();
+  if (align == Align::Baseline && isColumn(node->getStyle().flexDirection())) {
+    return Align::FlexStart;
+  }
+  return align;
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/algorithm/Baseline.cpp view
@@ -0,0 +1,82 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>
+
+#include <yoga/algorithm/Align.h>
+#include <yoga/algorithm/Baseline.h>
+#include <yoga/debug/AssertFatal.h>
+#include <yoga/event/event.h>
+
+namespace facebook::yoga {
+
+float calculateBaseline(const yoga::Node* node) {
+  if (node->hasBaselineFunc()) {
+    Event::publish<Event::NodeBaselineStart>(node);
+
+    const float baseline = node->baseline(
+        node->getLayout().measuredDimension(Dimension::Width),
+        node->getLayout().measuredDimension(Dimension::Height));
+
+    Event::publish<Event::NodeBaselineEnd>(node);
+
+    yoga::assertFatalWithNode(
+        node,
+        !std::isnan(baseline),
+        "Expect custom baseline function to not return NaN");
+    return baseline;
+  }
+
+  yoga::Node* baselineChild = nullptr;
+  const size_t childCount = node->getChildCount();
+  for (size_t i = 0; i < childCount; i++) {
+    auto child = node->getChild(i);
+    if (child->getLineIndex() > 0) {
+      break;
+    }
+    if (child->getStyle().positionType() == PositionType::Absolute) {
+      continue;
+    }
+    if (resolveChildAlignment(node, child) == Align::Baseline ||
+        child->isReferenceBaseline()) {
+      baselineChild = child;
+      break;
+    }
+
+    if (baselineChild == nullptr) {
+      baselineChild = child;
+    }
+  }
+
+  if (baselineChild == nullptr) {
+    return node->getLayout().measuredDimension(Dimension::Height);
+  }
+
+  const float baseline = calculateBaseline(baselineChild);
+  return baseline + baselineChild->getLayout().position(Edge::Top);
+}
+
+bool isBaselineLayout(const yoga::Node* node) {
+  if (isColumn(node->getStyle().flexDirection())) {
+    return false;
+  }
+  if (node->getStyle().alignItems() == Align::Baseline) {
+    return true;
+  }
+  const auto childCount = node->getChildCount();
+  for (size_t i = 0; i < childCount; i++) {
+    auto child = node->getChild(i);
+    if (child->getStyle().positionType() != PositionType::Absolute &&
+        child->getStyle().alignSelf() == Align::Baseline) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/algorithm/Baseline.h view
@@ -0,0 +1,21 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>
+#include <yoga/node/Node.h>
+
+namespace facebook::yoga {
+
+// Calculate baseline represented as an offset from the top edge of the node.
+float calculateBaseline(const yoga::Node* node);
+
+// Whether any of the children of this node participate in baseline alignment
+bool isBaselineLayout(const yoga::Node* node);
+
+} // namespace facebook::yoga
+ yoga/yoga/algorithm/BoundAxis.h view
@@ -0,0 +1,70 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/algorithm/FlexDirection.h>
+#include <yoga/enums/Dimension.h>
+#include <yoga/enums/FlexDirection.h>
+#include <yoga/node/Node.h>
+#include <yoga/numeric/Comparison.h>
+#include <yoga/numeric/FloatOptional.h>
+
+namespace facebook::yoga {
+
+inline float paddingAndBorderForAxis(
+    const yoga::Node* const node,
+    const FlexDirection axis,
+    const float widthSize) {
+  // The total padding/border for a given axis does not depend on the direction
+  // so hardcoding LTR here to avoid piping direction to this function
+  return node->getInlineStartPaddingAndBorder(axis, Direction::LTR, widthSize) +
+      node->getInlineEndPaddingAndBorder(axis, Direction::LTR, widthSize);
+}
+
+inline FloatOptional boundAxisWithinMinAndMax(
+    const yoga::Node* const node,
+    const FlexDirection axis,
+    const FloatOptional value,
+    const float axisSize) {
+  FloatOptional min;
+  FloatOptional max;
+
+  if (isColumn(axis)) {
+    min = node->getStyle().minDimension(Dimension::Height).resolve(axisSize);
+    max = node->getStyle().maxDimension(Dimension::Height).resolve(axisSize);
+  } else if (isRow(axis)) {
+    min = node->getStyle().minDimension(Dimension::Width).resolve(axisSize);
+    max = node->getStyle().maxDimension(Dimension::Width).resolve(axisSize);
+  }
+
+  if (max >= FloatOptional{0} && value > max) {
+    return max;
+  }
+
+  if (min >= FloatOptional{0} && value < min) {
+    return min;
+  }
+
+  return value;
+}
+
+// Like boundAxisWithinMinAndMax but also ensures that the value doesn't
+// go below the padding and border amount.
+inline float boundAxis(
+    const yoga::Node* const node,
+    const FlexDirection axis,
+    const float value,
+    const float axisSize,
+    const float widthSize) {
+  return yoga::maxOrDefined(
+      boundAxisWithinMinAndMax(node, axis, FloatOptional{value}, axisSize)
+          .unwrap(),
+      paddingAndBorderForAxis(node, axis, widthSize));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/algorithm/Cache.cpp view
@@ -0,0 +1,121 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/algorithm/Cache.h>
+#include <yoga/algorithm/PixelGrid.h>
+#include <yoga/numeric/Comparison.h>
+
+namespace facebook::yoga {
+
+static inline bool sizeIsExactAndMatchesOldMeasuredSize(
+    SizingMode sizeMode,
+    float size,
+    float lastComputedSize) {
+  return sizeMode == SizingMode::StretchFit &&
+      yoga::inexactEquals(size, lastComputedSize);
+}
+
+static inline bool oldSizeIsMaxContentAndStillFits(
+    SizingMode sizeMode,
+    float size,
+    SizingMode lastSizeMode,
+    float lastComputedSize) {
+  return sizeMode == SizingMode::FitContent &&
+      lastSizeMode == SizingMode::MaxContent &&
+      (size >= lastComputedSize || yoga::inexactEquals(size, lastComputedSize));
+}
+
+static inline bool newSizeIsStricterAndStillValid(
+    SizingMode sizeMode,
+    float size,
+    SizingMode lastSizeMode,
+    float lastSize,
+    float lastComputedSize) {
+  return lastSizeMode == SizingMode::FitContent &&
+      sizeMode == SizingMode::FitContent && yoga::isDefined(lastSize) &&
+      yoga::isDefined(size) && yoga::isDefined(lastComputedSize) &&
+      lastSize > size &&
+      (lastComputedSize <= size || yoga::inexactEquals(size, lastComputedSize));
+}
+
+bool canUseCachedMeasurement(
+    const SizingMode widthMode,
+    const float availableWidth,
+    const SizingMode heightMode,
+    const float availableHeight,
+    const SizingMode lastWidthMode,
+    const float lastAvailableWidth,
+    const SizingMode lastHeightMode,
+    const float lastAvailableHeight,
+    const float lastComputedWidth,
+    const float lastComputedHeight,
+    const float marginRow,
+    const float marginColumn,
+    const yoga::Config* const config) {
+  if ((yoga::isDefined(lastComputedHeight) && lastComputedHeight < 0) ||
+      ((yoga::isDefined(lastComputedWidth)) && lastComputedWidth < 0)) {
+    return false;
+  }
+
+  const float pointScaleFactor = config->getPointScaleFactor();
+
+  bool useRoundedComparison = config != nullptr && pointScaleFactor != 0;
+  const float effectiveWidth = useRoundedComparison
+      ? roundValueToPixelGrid(availableWidth, pointScaleFactor, false, false)
+      : availableWidth;
+  const float effectiveHeight = useRoundedComparison
+      ? roundValueToPixelGrid(availableHeight, pointScaleFactor, false, false)
+      : availableHeight;
+  const float effectiveLastWidth = useRoundedComparison
+      ? roundValueToPixelGrid(
+            lastAvailableWidth, pointScaleFactor, false, false)
+      : lastAvailableWidth;
+  const float effectiveLastHeight = useRoundedComparison
+      ? roundValueToPixelGrid(
+            lastAvailableHeight, pointScaleFactor, false, false)
+      : lastAvailableHeight;
+
+  const bool hasSameWidthSpec = lastWidthMode == widthMode &&
+      yoga::inexactEquals(effectiveLastWidth, effectiveWidth);
+  const bool hasSameHeightSpec = lastHeightMode == heightMode &&
+      yoga::inexactEquals(effectiveLastHeight, effectiveHeight);
+
+  const bool widthIsCompatible =
+      hasSameWidthSpec ||
+      sizeIsExactAndMatchesOldMeasuredSize(
+          widthMode, availableWidth - marginRow, lastComputedWidth) ||
+      oldSizeIsMaxContentAndStillFits(
+          widthMode,
+          availableWidth - marginRow,
+          lastWidthMode,
+          lastComputedWidth) ||
+      newSizeIsStricterAndStillValid(
+          widthMode,
+          availableWidth - marginRow,
+          lastWidthMode,
+          lastAvailableWidth,
+          lastComputedWidth);
+
+  const bool heightIsCompatible = hasSameHeightSpec ||
+      sizeIsExactAndMatchesOldMeasuredSize(
+                                      heightMode,
+                                      availableHeight - marginColumn,
+                                      lastComputedHeight) ||
+      oldSizeIsMaxContentAndStillFits(heightMode,
+                                      availableHeight - marginColumn,
+                                      lastHeightMode,
+                                      lastComputedHeight) ||
+      newSizeIsStricterAndStillValid(heightMode,
+                                     availableHeight - marginColumn,
+                                     lastHeightMode,
+                                     lastAvailableHeight,
+                                     lastComputedHeight);
+
+  return widthIsCompatible && heightIsCompatible;
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/algorithm/Cache.h view
@@ -0,0 +1,30 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/algorithm/SizingMode.h>
+#include <yoga/config/Config.h>
+
+namespace facebook::yoga {
+
+bool canUseCachedMeasurement(
+    SizingMode widthMode,
+    float availableWidth,
+    SizingMode heightMode,
+    float availableHeight,
+    SizingMode lastWidthMode,
+    float lastAvailableWidth,
+    SizingMode lastHeightMode,
+    float lastAvailableHeight,
+    float lastComputedWidth,
+    float lastComputedHeight,
+    float marginRow,
+    float marginColumn,
+    const yoga::Config* config);
+
+} // namespace facebook::yoga
+ yoga/yoga/algorithm/CalculateLayout.cpp view
@@ -0,0 +1,2485 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <algorithm>
+#include <atomic>
+#include <cfloat>
+#include <cmath>
+#include <cstring>
+
+#include <yoga/Yoga.h>
+
+#include <yoga/algorithm/AbsoluteLayout.h>
+#include <yoga/algorithm/Align.h>
+#include <yoga/algorithm/Baseline.h>
+#include <yoga/algorithm/BoundAxis.h>
+#include <yoga/algorithm/Cache.h>
+#include <yoga/algorithm/CalculateLayout.h>
+#include <yoga/algorithm/FlexDirection.h>
+#include <yoga/algorithm/FlexLine.h>
+#include <yoga/algorithm/PixelGrid.h>
+#include <yoga/algorithm/SizingMode.h>
+#include <yoga/algorithm/TrailingPosition.h>
+#include <yoga/debug/AssertFatal.h>
+#include <yoga/debug/Log.h>
+#include <yoga/debug/NodeToString.h>
+#include <yoga/event/event.h>
+#include <yoga/node/Node.h>
+#include <yoga/numeric/Comparison.h>
+#include <yoga/numeric/FloatOptional.h>
+
+namespace facebook::yoga {
+
+std::atomic<uint32_t> gCurrentGenerationCount(0);
+
+static void constrainMaxSizeForMode(
+    const yoga::Node* node,
+    FlexDirection axis,
+    float ownerAxisSize,
+    float ownerWidth,
+    /*in_out*/ SizingMode* mode,
+    /*in_out*/ float* size) {
+  const FloatOptional maxSize =
+      node->getStyle().maxDimension(dimension(axis)).resolve(ownerAxisSize) +
+      FloatOptional(node->getMarginForAxis(axis, ownerWidth));
+  switch (*mode) {
+    case SizingMode::StretchFit:
+    case SizingMode::FitContent:
+      *size = (maxSize.isUndefined() || *size < maxSize.unwrap())
+          ? *size
+          : maxSize.unwrap();
+      break;
+    case SizingMode::MaxContent:
+      if (maxSize.isDefined()) {
+        *mode = SizingMode::FitContent;
+        *size = maxSize.unwrap();
+      }
+      break;
+  }
+}
+
+static void computeFlexBasisForChild(
+    const yoga::Node* const node,
+    yoga::Node* const child,
+    const float width,
+    const SizingMode widthMode,
+    const float height,
+    const float ownerWidth,
+    const float ownerHeight,
+    const SizingMode heightMode,
+    const Direction direction,
+    LayoutData& layoutMarkerData,
+    const uint32_t depth,
+    const uint32_t generationCount) {
+  const FlexDirection mainAxis =
+      resolveDirection(node->getStyle().flexDirection(), direction);
+  const bool isMainAxisRow = isRow(mainAxis);
+  const float mainAxisSize = isMainAxisRow ? width : height;
+  const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight;
+
+  float childWidth;
+  float childHeight;
+  SizingMode childWidthSizingMode;
+  SizingMode childHeightSizingMode;
+
+  const FloatOptional resolvedFlexBasis =
+      child->resolveFlexBasisPtr().resolve(mainAxisownerSize);
+  const bool isRowStyleDimDefined =
+      child->hasDefiniteLength(Dimension::Width, ownerWidth);
+  const bool isColumnStyleDimDefined =
+      child->hasDefiniteLength(Dimension::Height, ownerHeight);
+
+  if (resolvedFlexBasis.isDefined() && yoga::isDefined(mainAxisSize)) {
+    if (child->getLayout().computedFlexBasis.isUndefined() ||
+        (child->getConfig()->isExperimentalFeatureEnabled(
+             ExperimentalFeature::WebFlexBasis) &&
+         child->getLayout().computedFlexBasisGeneration != generationCount)) {
+      const FloatOptional paddingAndBorder =
+          FloatOptional(paddingAndBorderForAxis(child, mainAxis, ownerWidth));
+      child->setLayoutComputedFlexBasis(
+          yoga::maxOrDefined(resolvedFlexBasis, paddingAndBorder));
+    }
+  } else if (isMainAxisRow && isRowStyleDimDefined) {
+    // The width is definite, so use that as the flex basis.
+    const FloatOptional paddingAndBorder = FloatOptional(
+        paddingAndBorderForAxis(child, FlexDirection::Row, ownerWidth));
+
+    child->setLayoutComputedFlexBasis(yoga::maxOrDefined(
+        child->getResolvedDimension(Dimension::Width).resolve(ownerWidth),
+        paddingAndBorder));
+  } else if (!isMainAxisRow && isColumnStyleDimDefined) {
+    // The height is definite, so use that as the flex basis.
+    const FloatOptional paddingAndBorder = FloatOptional(
+        paddingAndBorderForAxis(child, FlexDirection::Column, ownerWidth));
+    child->setLayoutComputedFlexBasis(yoga::maxOrDefined(
+        child->getResolvedDimension(Dimension::Height).resolve(ownerHeight),
+        paddingAndBorder));
+  } else {
+    // Compute the flex basis and hypothetical main size (i.e. the clamped flex
+    // basis).
+    childWidth = YGUndefined;
+    childHeight = YGUndefined;
+    childWidthSizingMode = SizingMode::MaxContent;
+    childHeightSizingMode = SizingMode::MaxContent;
+
+    auto marginRow = child->getMarginForAxis(FlexDirection::Row, ownerWidth);
+    auto marginColumn =
+        child->getMarginForAxis(FlexDirection::Column, ownerWidth);
+
+    if (isRowStyleDimDefined) {
+      childWidth = child->getResolvedDimension(Dimension::Width)
+                       .resolve(ownerWidth)
+                       .unwrap() +
+          marginRow;
+      childWidthSizingMode = SizingMode::StretchFit;
+    }
+    if (isColumnStyleDimDefined) {
+      childHeight = child->getResolvedDimension(Dimension::Height)
+                        .resolve(ownerHeight)
+                        .unwrap() +
+          marginColumn;
+      childHeightSizingMode = SizingMode::StretchFit;
+    }
+
+    // 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() == Overflow::Scroll) ||
+        node->getStyle().overflow() != Overflow::Scroll) {
+      if (yoga::isUndefined(childWidth) && yoga::isDefined(width)) {
+        childWidth = width;
+        childWidthSizingMode = SizingMode::FitContent;
+      }
+    }
+
+    if ((isMainAxisRow && node->getStyle().overflow() == Overflow::Scroll) ||
+        node->getStyle().overflow() != Overflow::Scroll) {
+      if (yoga::isUndefined(childHeight) && yoga::isDefined(height)) {
+        childHeight = height;
+        childHeightSizingMode = SizingMode::FitContent;
+      }
+    }
+
+    const auto& childStyle = child->getStyle();
+    if (childStyle.aspectRatio().isDefined()) {
+      if (!isMainAxisRow && childWidthSizingMode == SizingMode::StretchFit) {
+        childHeight = marginColumn +
+            (childWidth - marginRow) / childStyle.aspectRatio().unwrap();
+        childHeightSizingMode = SizingMode::StretchFit;
+      } else if (
+          isMainAxisRow && childHeightSizingMode == SizingMode::StretchFit) {
+        childWidth = marginRow +
+            (childHeight - marginColumn) * childStyle.aspectRatio().unwrap();
+        childWidthSizingMode = SizingMode::StretchFit;
+      }
+    }
+
+    // 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 =
+        yoga::isDefined(width) && widthMode == SizingMode::StretchFit;
+    const bool childWidthStretch =
+        resolveChildAlignment(node, child) == Align::Stretch &&
+        childWidthSizingMode != SizingMode::StretchFit;
+    if (!isMainAxisRow && !isRowStyleDimDefined && hasExactWidth &&
+        childWidthStretch) {
+      childWidth = width;
+      childWidthSizingMode = SizingMode::StretchFit;
+      if (childStyle.aspectRatio().isDefined()) {
+        childHeight =
+            (childWidth - marginRow) / childStyle.aspectRatio().unwrap();
+        childHeightSizingMode = SizingMode::StretchFit;
+      }
+    }
+
+    const bool hasExactHeight =
+        yoga::isDefined(height) && heightMode == SizingMode::StretchFit;
+    const bool childHeightStretch =
+        resolveChildAlignment(node, child) == Align::Stretch &&
+        childHeightSizingMode != SizingMode::StretchFit;
+    if (isMainAxisRow && !isColumnStyleDimDefined && hasExactHeight &&
+        childHeightStretch) {
+      childHeight = height;
+      childHeightSizingMode = SizingMode::StretchFit;
+
+      if (childStyle.aspectRatio().isDefined()) {
+        childWidth =
+            (childHeight - marginColumn) * childStyle.aspectRatio().unwrap();
+        childWidthSizingMode = SizingMode::StretchFit;
+      }
+    }
+
+    constrainMaxSizeForMode(
+        child,
+        FlexDirection::Row,
+        ownerWidth,
+        ownerWidth,
+        &childWidthSizingMode,
+        &childWidth);
+    constrainMaxSizeForMode(
+        child,
+        FlexDirection::Column,
+        ownerHeight,
+        ownerWidth,
+        &childHeightSizingMode,
+        &childHeight);
+
+    // Measure the child
+    calculateLayoutInternal(
+        child,
+        childWidth,
+        childHeight,
+        direction,
+        childWidthSizingMode,
+        childHeightSizingMode,
+        ownerWidth,
+        ownerHeight,
+        false,
+        LayoutPassReason::kMeasureChild,
+        layoutMarkerData,
+        depth,
+        generationCount);
+
+    child->setLayoutComputedFlexBasis(FloatOptional(yoga::maxOrDefined(
+        child->getLayout().measuredDimension(dimension(mainAxis)),
+        paddingAndBorderForAxis(child, mainAxis, ownerWidth))));
+  }
+  child->setLayoutComputedFlexBasisGeneration(generationCount);
+}
+
+static void measureNodeWithMeasureFunc(
+    yoga::Node* const node,
+    float availableWidth,
+    float availableHeight,
+    const SizingMode widthSizingMode,
+    const SizingMode heightSizingMode,
+    const float ownerWidth,
+    const float ownerHeight,
+    LayoutData& layoutMarkerData,
+    const LayoutPassReason reason) {
+  yoga::assertFatalWithNode(
+      node,
+      node->hasMeasureFunc(),
+      "Expected node to have custom measure function");
+
+  if (widthSizingMode == SizingMode::MaxContent) {
+    availableWidth = YGUndefined;
+  }
+  if (heightSizingMode == SizingMode::MaxContent) {
+    availableHeight = YGUndefined;
+  }
+
+  const auto& layout = node->getLayout();
+  const float paddingAndBorderAxisRow = layout.padding(Edge::Left) +
+      layout.padding(Edge::Right) + layout.border(Edge::Left) +
+      layout.border(Edge::Right);
+  const float paddingAndBorderAxisColumn = layout.padding(Edge::Top) +
+      layout.padding(Edge::Bottom) + layout.border(Edge::Top) +
+      layout.border(Edge::Bottom);
+
+  // We want to make sure we don't call measure with negative size
+  const float innerWidth = yoga::isUndefined(availableWidth)
+      ? availableWidth
+      : yoga::maxOrDefined(0.0f, availableWidth - paddingAndBorderAxisRow);
+  const float innerHeight = yoga::isUndefined(availableHeight)
+      ? availableHeight
+      : yoga::maxOrDefined(0.0f, availableHeight - paddingAndBorderAxisColumn);
+
+  if (widthSizingMode == SizingMode::StretchFit &&
+      heightSizingMode == SizingMode::StretchFit) {
+    // Don't bother sizing the text if both dimensions are already defined.
+    node->setLayoutMeasuredDimension(
+        boundAxis(
+            node, FlexDirection::Row, availableWidth, ownerWidth, ownerWidth),
+        Dimension::Width);
+    node->setLayoutMeasuredDimension(
+        boundAxis(
+            node,
+            FlexDirection::Column,
+            availableHeight,
+            ownerHeight,
+            ownerWidth),
+        Dimension::Height);
+  } else {
+    Event::publish<Event::MeasureCallbackStart>(node);
+
+    // Measure the text under the current constraints.
+    const YGSize measuredSize = node->measure(
+        innerWidth,
+        measureMode(widthSizingMode),
+        innerHeight,
+        measureMode(heightSizingMode));
+
+    layoutMarkerData.measureCallbacks += 1;
+    layoutMarkerData.measureCallbackReasonsCount[static_cast<size_t>(reason)] +=
+        1;
+
+    Event::publish<Event::MeasureCallbackEnd>(
+        node,
+        {innerWidth,
+         unscopedEnum(measureMode(widthSizingMode)),
+         innerHeight,
+         unscopedEnum(measureMode(heightSizingMode)),
+         measuredSize.width,
+         measuredSize.height,
+         reason});
+
+    node->setLayoutMeasuredDimension(
+        boundAxis(
+            node,
+            FlexDirection::Row,
+            (widthSizingMode == SizingMode::MaxContent ||
+             widthSizingMode == SizingMode::FitContent)
+                ? measuredSize.width + paddingAndBorderAxisRow
+                : availableWidth,
+            ownerWidth,
+            ownerWidth),
+        Dimension::Width);
+
+    node->setLayoutMeasuredDimension(
+        boundAxis(
+            node,
+            FlexDirection::Column,
+            (heightSizingMode == SizingMode::MaxContent ||
+             heightSizingMode == SizingMode::FitContent)
+                ? measuredSize.height + paddingAndBorderAxisColumn
+                : availableHeight,
+            ownerHeight,
+            ownerWidth),
+        Dimension::Height);
+  }
+}
+
+// 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 measureNodeWithoutChildren(
+    yoga::Node* const node,
+    const float availableWidth,
+    const float availableHeight,
+    const SizingMode widthSizingMode,
+    const SizingMode heightSizingMode,
+    const float ownerWidth,
+    const float ownerHeight) {
+  const auto& layout = node->getLayout();
+
+  float width = availableWidth;
+  if (widthSizingMode == SizingMode::MaxContent ||
+      widthSizingMode == SizingMode::FitContent) {
+    width = layout.padding(Edge::Left) + layout.padding(Edge::Right) +
+        layout.border(Edge::Left) + layout.border(Edge::Right);
+  }
+  node->setLayoutMeasuredDimension(
+      boundAxis(node, FlexDirection::Row, width, ownerWidth, ownerWidth),
+      Dimension::Width);
+
+  float height = availableHeight;
+  if (heightSizingMode == SizingMode::MaxContent ||
+      heightSizingMode == SizingMode::FitContent) {
+    height = layout.padding(Edge::Top) + layout.padding(Edge::Bottom) +
+        layout.border(Edge::Top) + layout.border(Edge::Bottom);
+  }
+  node->setLayoutMeasuredDimension(
+      boundAxis(node, FlexDirection::Column, height, ownerHeight, ownerWidth),
+      Dimension::Height);
+}
+
+static bool measureNodeWithFixedSize(
+    yoga::Node* const node,
+    const float availableWidth,
+    const float availableHeight,
+    const SizingMode widthSizingMode,
+    const SizingMode heightSizingMode,
+    const float ownerWidth,
+    const float ownerHeight) {
+  if ((yoga::isDefined(availableWidth) &&
+       widthSizingMode == SizingMode::FitContent && availableWidth <= 0.0f) ||
+      (yoga::isDefined(availableHeight) &&
+       heightSizingMode == SizingMode::FitContent && availableHeight <= 0.0f) ||
+      (widthSizingMode == SizingMode::StretchFit &&
+       heightSizingMode == SizingMode::StretchFit)) {
+    node->setLayoutMeasuredDimension(
+        boundAxis(
+            node,
+            FlexDirection::Row,
+            yoga::isUndefined(availableWidth) ||
+                    (widthSizingMode == SizingMode::FitContent &&
+                     availableWidth < 0.0f)
+                ? 0.0f
+                : availableWidth,
+            ownerWidth,
+            ownerWidth),
+        Dimension::Width);
+
+    node->setLayoutMeasuredDimension(
+        boundAxis(
+            node,
+            FlexDirection::Column,
+            yoga::isUndefined(availableHeight) ||
+                    (heightSizingMode == SizingMode::FitContent &&
+                     availableHeight < 0.0f)
+                ? 0.0f
+                : availableHeight,
+            ownerHeight,
+            ownerWidth),
+        Dimension::Height);
+    return true;
+  }
+
+  return false;
+}
+
+static void zeroOutLayoutRecursively(yoga::Node* const node) {
+  node->getLayout() = {};
+  node->setLayoutDimension(0, Dimension::Width);
+  node->setLayoutDimension(0, Dimension::Height);
+  node->setHasNewLayout(true);
+
+  node->cloneChildrenIfNeeded();
+  for (const auto child : node->getChildren()) {
+    zeroOutLayoutRecursively(child);
+  }
+}
+
+static float calculateAvailableInnerDimension(
+    const yoga::Node* const node,
+    const Dimension dimension,
+    const float availableDim,
+    const float paddingAndBorder,
+    const float ownerDim) {
+  float availableInnerDim = availableDim - paddingAndBorder;
+  // Max dimension overrides predefined dimension value; Min dimension in turn
+  // overrides both of the above
+  if (yoga::isDefined(availableInnerDim)) {
+    // We want to make sure our available height does not violate min and max
+    // constraints
+    const FloatOptional minDimensionOptional =
+        node->getStyle().minDimension(dimension).resolve(ownerDim);
+    const float minInnerDim = minDimensionOptional.isUndefined()
+        ? 0.0f
+        : minDimensionOptional.unwrap() - paddingAndBorder;
+
+    const FloatOptional maxDimensionOptional =
+        node->getStyle().maxDimension(dimension).resolve(ownerDim);
+
+    const float maxInnerDim = maxDimensionOptional.isUndefined()
+        ? FLT_MAX
+        : maxDimensionOptional.unwrap() - paddingAndBorder;
+    availableInnerDim = yoga::maxOrDefined(
+        yoga::minOrDefined(availableInnerDim, maxInnerDim), minInnerDim);
+  }
+
+  return availableInnerDim;
+}
+
+static float computeFlexBasisForChildren(
+    yoga::Node* const node,
+    const float availableInnerWidth,
+    const float availableInnerHeight,
+    SizingMode widthSizingMode,
+    SizingMode heightSizingMode,
+    Direction direction,
+    FlexDirection mainAxis,
+    bool performLayout,
+    LayoutData& layoutMarkerData,
+    const uint32_t depth,
+    const uint32_t generationCount) {
+  float totalOuterFlexBasis = 0.0f;
+  YGNodeRef singleFlexChild = nullptr;
+  const auto& children = node->getChildren();
+  SizingMode sizingModeMainDim =
+      isRow(mainAxis) ? widthSizingMode : heightSizingMode;
+  // 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 (sizingModeMainDim == SizingMode::StretchFit) {
+    for (auto child : children) {
+      if (child->isNodeFlexible()) {
+        if (singleFlexChild != nullptr ||
+            yoga::inexactEquals(child->resolveFlexGrow(), 0.0f) ||
+            yoga::inexactEquals(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() == Display::None) {
+      zeroOutLayoutRecursively(child);
+      child->setHasNewLayout(true);
+      child->setDirty(false);
+      continue;
+    }
+    if (performLayout) {
+      // Set the initial position (relative to the owner).
+      const Direction childDirection = child->resolveDirection(direction);
+      const float mainDim =
+          isRow(mainAxis) ? availableInnerWidth : availableInnerHeight;
+      const float crossDim =
+          isRow(mainAxis) ? availableInnerHeight : availableInnerWidth;
+      child->setPosition(
+          childDirection, mainDim, crossDim, availableInnerWidth);
+    }
+
+    if (child->getStyle().positionType() == PositionType::Absolute) {
+      continue;
+    }
+    if (child == singleFlexChild) {
+      child->setLayoutComputedFlexBasisGeneration(generationCount);
+      child->setLayoutComputedFlexBasis(FloatOptional(0));
+    } else {
+      computeFlexBasisForChild(
+          node,
+          child,
+          availableInnerWidth,
+          widthSizingMode,
+          availableInnerHeight,
+          availableInnerWidth,
+          availableInnerHeight,
+          heightSizingMode,
+          direction,
+          layoutMarkerData,
+          depth,
+          generationCount);
+    }
+
+    totalOuterFlexBasis +=
+        (child->getLayout().computedFlexBasis.unwrap() +
+         child->getMarginForAxis(mainAxis, availableInnerWidth));
+  }
+
+  return totalOuterFlexBasis;
+}
+
+// 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 distributeFreeSpaceFirstPass is called.
+static float distributeFreeSpaceSecondPass(
+    FlexLine& flexLine,
+    yoga::Node* const node,
+    const FlexDirection mainAxis,
+    const FlexDirection crossAxis,
+    const float mainAxisownerSize,
+    const float availableInnerMainDim,
+    const float availableInnerCrossDim,
+    const float availableInnerWidth,
+    const float availableInnerHeight,
+    const bool mainAxisOverflows,
+    const SizingMode sizingModeCrossDim,
+    const bool performLayout,
+    LayoutData& layoutMarkerData,
+    const uint32_t depth,
+    const uint32_t generationCount) {
+  float childFlexBasis = 0;
+  float flexShrinkScaledFactor = 0;
+  float flexGrowFactor = 0;
+  float deltaFreeSpace = 0;
+  const bool isMainAxisRow = isRow(mainAxis);
+  const bool isNodeFlexWrap = node->getStyle().flexWrap() != Wrap::NoWrap;
+
+  for (auto currentLineChild : flexLine.itemsInFlow) {
+    childFlexBasis = boundAxisWithinMinAndMax(
+                         currentLineChild,
+                         mainAxis,
+                         currentLineChild->getLayout().computedFlexBasis,
+                         mainAxisownerSize)
+                         .unwrap();
+    float updatedMainSize = childFlexBasis;
+
+    if (yoga::isDefined(flexLine.layout.remainingFreeSpace) &&
+        flexLine.layout.remainingFreeSpace < 0) {
+      flexShrinkScaledFactor =
+          -currentLineChild->resolveFlexShrink() * childFlexBasis;
+      // Is this child able to shrink?
+      if (flexShrinkScaledFactor != 0) {
+        float childSize;
+
+        if (yoga::isDefined(flexLine.layout.totalFlexShrinkScaledFactors) &&
+            flexLine.layout.totalFlexShrinkScaledFactors == 0) {
+          childSize = childFlexBasis + flexShrinkScaledFactor;
+        } else {
+          childSize = childFlexBasis +
+              (flexLine.layout.remainingFreeSpace /
+               flexLine.layout.totalFlexShrinkScaledFactors) *
+                  flexShrinkScaledFactor;
+        }
+
+        updatedMainSize = boundAxis(
+            currentLineChild,
+            mainAxis,
+            childSize,
+            availableInnerMainDim,
+            availableInnerWidth);
+      }
+    } else if (
+        yoga::isDefined(flexLine.layout.remainingFreeSpace) &&
+        flexLine.layout.remainingFreeSpace > 0) {
+      flexGrowFactor = currentLineChild->resolveFlexGrow();
+
+      // Is this child able to grow?
+      if (!std::isnan(flexGrowFactor) && flexGrowFactor != 0) {
+        updatedMainSize = boundAxis(
+            currentLineChild,
+            mainAxis,
+            childFlexBasis +
+                flexLine.layout.remainingFreeSpace /
+                    flexLine.layout.totalFlexGrowFactors * flexGrowFactor,
+            availableInnerMainDim,
+            availableInnerWidth);
+      }
+    }
+
+    deltaFreeSpace += updatedMainSize - childFlexBasis;
+
+    const float marginMain =
+        currentLineChild->getMarginForAxis(mainAxis, availableInnerWidth);
+    const float marginCross =
+        currentLineChild->getMarginForAxis(crossAxis, availableInnerWidth);
+
+    float childCrossSize;
+    float childMainSize = updatedMainSize + marginMain;
+    SizingMode childCrossSizingMode;
+    SizingMode childMainSizingMode = SizingMode::StretchFit;
+
+    const auto& childStyle = currentLineChild->getStyle();
+    if (childStyle.aspectRatio().isDefined()) {
+      childCrossSize = isMainAxisRow
+          ? (childMainSize - marginMain) / childStyle.aspectRatio().unwrap()
+          : (childMainSize - marginMain) * childStyle.aspectRatio().unwrap();
+      childCrossSizingMode = SizingMode::StretchFit;
+
+      childCrossSize += marginCross;
+    } else if (
+        !std::isnan(availableInnerCrossDim) &&
+        !currentLineChild->hasDefiniteLength(
+            dimension(crossAxis), availableInnerCrossDim) &&
+        sizingModeCrossDim == SizingMode::StretchFit &&
+        !(isNodeFlexWrap && mainAxisOverflows) &&
+        resolveChildAlignment(node, currentLineChild) == Align::Stretch &&
+        currentLineChild->getFlexStartMarginValue(crossAxis).unit() !=
+            Unit::Auto &&
+        currentLineChild->marginTrailingValue(crossAxis).unit() != Unit::Auto) {
+      childCrossSize = availableInnerCrossDim;
+      childCrossSizingMode = SizingMode::StretchFit;
+    } else if (!currentLineChild->hasDefiniteLength(
+                   dimension(crossAxis), availableInnerCrossDim)) {
+      childCrossSize = availableInnerCrossDim;
+      childCrossSizingMode = yoga::isUndefined(childCrossSize)
+          ? SizingMode::MaxContent
+          : SizingMode::FitContent;
+    } else {
+      childCrossSize =
+          currentLineChild->getResolvedDimension(dimension(crossAxis))
+              .resolve(availableInnerCrossDim)
+              .unwrap() +
+          marginCross;
+      const bool isLoosePercentageMeasurement =
+          currentLineChild->getResolvedDimension(dimension(crossAxis)).unit() ==
+              Unit::Percent &&
+          sizingModeCrossDim != SizingMode::StretchFit;
+      childCrossSizingMode =
+          yoga::isUndefined(childCrossSize) || isLoosePercentageMeasurement
+          ? SizingMode::MaxContent
+          : SizingMode::StretchFit;
+    }
+
+    constrainMaxSizeForMode(
+        currentLineChild,
+        mainAxis,
+        availableInnerMainDim,
+        availableInnerWidth,
+        &childMainSizingMode,
+        &childMainSize);
+    constrainMaxSizeForMode(
+        currentLineChild,
+        crossAxis,
+        availableInnerCrossDim,
+        availableInnerWidth,
+        &childCrossSizingMode,
+        &childCrossSize);
+
+    const bool requiresStretchLayout =
+        !currentLineChild->hasDefiniteLength(
+            dimension(crossAxis), availableInnerCrossDim) &&
+        resolveChildAlignment(node, currentLineChild) == Align::Stretch &&
+        currentLineChild->getFlexStartMarginValue(crossAxis).unit() !=
+            Unit::Auto &&
+        currentLineChild->marginTrailingValue(crossAxis).unit() != Unit::Auto;
+
+    const float childWidth = isMainAxisRow ? childMainSize : childCrossSize;
+    const float childHeight = !isMainAxisRow ? childMainSize : childCrossSize;
+
+    const SizingMode childWidthSizingMode =
+        isMainAxisRow ? childMainSizingMode : childCrossSizingMode;
+    const SizingMode childHeightSizingMode =
+        !isMainAxisRow ? childMainSizingMode : childCrossSizingMode;
+
+    const bool isLayoutPass = performLayout && !requiresStretchLayout;
+    // Recursively call the layout algorithm for this child with the updated
+    // main size.
+    calculateLayoutInternal(
+        currentLineChild,
+        childWidth,
+        childHeight,
+        node->getLayout().direction(),
+        childWidthSizingMode,
+        childHeightSizingMode,
+        availableInnerWidth,
+        availableInnerHeight,
+        isLayoutPass,
+        isLayoutPass ? LayoutPassReason::kFlexLayout
+                     : LayoutPassReason::kFlexMeasure,
+        layoutMarkerData,
+        depth,
+        generationCount);
+    node->setLayoutHadOverflow(
+        node->getLayout().hadOverflow() ||
+        currentLineChild->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 distributeFreeSpaceFirstPass(
+    FlexLine& flexLine,
+    const FlexDirection 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 currentLineChild : flexLine.itemsInFlow) {
+    float childFlexBasis = boundAxisWithinMinAndMax(
+                               currentLineChild,
+                               mainAxis,
+                               currentLineChild->getLayout().computedFlexBasis,
+                               mainAxisownerSize)
+                               .unwrap();
+
+    if (flexLine.layout.remainingFreeSpace < 0) {
+      flexShrinkScaledFactor =
+          -currentLineChild->resolveFlexShrink() * childFlexBasis;
+
+      // Is this child able to shrink?
+      if (yoga::isDefined(flexShrinkScaledFactor) &&
+          flexShrinkScaledFactor != 0) {
+        baseMainSize = childFlexBasis +
+            flexLine.layout.remainingFreeSpace /
+                flexLine.layout.totalFlexShrinkScaledFactors *
+                flexShrinkScaledFactor;
+        boundMainSize = boundAxis(
+            currentLineChild,
+            mainAxis,
+            baseMainSize,
+            availableInnerMainDim,
+            availableInnerWidth);
+        if (yoga::isDefined(baseMainSize) && yoga::isDefined(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;
+          flexLine.layout.totalFlexShrinkScaledFactors -=
+              (-currentLineChild->resolveFlexShrink() *
+               currentLineChild->getLayout().computedFlexBasis.unwrap());
+        }
+      }
+    } else if (
+        yoga::isDefined(flexLine.layout.remainingFreeSpace) &&
+        flexLine.layout.remainingFreeSpace > 0) {
+      flexGrowFactor = currentLineChild->resolveFlexGrow();
+
+      // Is this child able to grow?
+      if (yoga::isDefined(flexGrowFactor) && flexGrowFactor != 0) {
+        baseMainSize = childFlexBasis +
+            flexLine.layout.remainingFreeSpace /
+                flexLine.layout.totalFlexGrowFactors * flexGrowFactor;
+        boundMainSize = boundAxis(
+            currentLineChild,
+            mainAxis,
+            baseMainSize,
+            availableInnerMainDim,
+            availableInnerWidth);
+
+        if (yoga::isDefined(baseMainSize) && yoga::isDefined(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;
+          flexLine.layout.totalFlexGrowFactors -= flexGrowFactor;
+        }
+      }
+    }
+  }
+  flexLine.layout.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
+// the first pass. 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/CSS-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 resolveFlexibleLength(
+    yoga::Node* const node,
+    FlexLine& flexLine,
+    const FlexDirection mainAxis,
+    const FlexDirection crossAxis,
+    const float mainAxisownerSize,
+    const float availableInnerMainDim,
+    const float availableInnerCrossDim,
+    const float availableInnerWidth,
+    const float availableInnerHeight,
+    const bool mainAxisOverflows,
+    const SizingMode sizingModeCrossDim,
+    const bool performLayout,
+    LayoutData& layoutMarkerData,
+    const uint32_t depth,
+    const uint32_t generationCount) {
+  const float originalFreeSpace = flexLine.layout.remainingFreeSpace;
+  // First pass: detect the flex items whose min/max constraints trigger
+  distributeFreeSpaceFirstPass(
+      flexLine,
+      mainAxis,
+      mainAxisownerSize,
+      availableInnerMainDim,
+      availableInnerWidth);
+
+  // Second pass: resolve the sizes of the flexible items
+  const float distributedFreeSpace = distributeFreeSpaceSecondPass(
+      flexLine,
+      node,
+      mainAxis,
+      crossAxis,
+      mainAxisownerSize,
+      availableInnerMainDim,
+      availableInnerCrossDim,
+      availableInnerWidth,
+      availableInnerHeight,
+      mainAxisOverflows,
+      sizingModeCrossDim,
+      performLayout,
+      layoutMarkerData,
+      depth,
+      generationCount);
+
+  flexLine.layout.remainingFreeSpace = originalFreeSpace - distributedFreeSpace;
+}
+
+static void justifyMainAxis(
+    yoga::Node* const node,
+    FlexLine& flexLine,
+    const size_t startOfLineIndex,
+    const FlexDirection mainAxis,
+    const FlexDirection crossAxis,
+    const Direction direction,
+    const SizingMode sizingModeMainDim,
+    const SizingMode sizingModeCrossDim,
+    const float mainAxisownerSize,
+    const float ownerWidth,
+    const float availableInnerMainDim,
+    const float availableInnerCrossDim,
+    const float availableInnerWidth,
+    const bool performLayout) {
+  const auto& style = node->getStyle();
+
+  const float leadingPaddingAndBorderMain =
+      node->hasErrata(Errata::StartingEndingEdgeFromFlexDirection)
+      ? node->getInlineStartPaddingAndBorder(mainAxis, direction, ownerWidth)
+      : node->getFlexStartPaddingAndBorder(mainAxis, direction, ownerWidth);
+  const float trailingPaddingAndBorderMain =
+      node->hasErrata(Errata::StartingEndingEdgeFromFlexDirection)
+      ? node->getInlineEndPaddingAndBorder(mainAxis, direction, ownerWidth)
+      : node->getFlexEndPaddingAndBorder(mainAxis, direction, ownerWidth);
+
+  const float gap = node->getGapForAxis(mainAxis);
+  // 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 (sizingModeMainDim == SizingMode::FitContent &&
+      flexLine.layout.remainingFreeSpace > 0) {
+    if (style.minDimension(dimension(mainAxis)).isDefined() &&
+        style.minDimension(dimension(mainAxis))
+            .resolve(mainAxisownerSize)
+            .isDefined()) {
+      // 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 = style.minDimension(dimension(mainAxis))
+                                            .resolve(mainAxisownerSize)
+                                            .unwrap() -
+          leadingPaddingAndBorderMain - trailingPaddingAndBorderMain;
+      const float occupiedSpaceByChildNodes =
+          availableInnerMainDim - flexLine.layout.remainingFreeSpace;
+      flexLine.layout.remainingFreeSpace = yoga::maxOrDefined(
+          0.0f, minAvailableMainDim - occupiedSpaceByChildNodes);
+    } else {
+      flexLine.layout.remainingFreeSpace = 0;
+    }
+  }
+
+  int numberOfAutoMarginsOnCurrentLine = 0;
+  for (size_t i = startOfLineIndex; i < flexLine.endOfLineIndex; i++) {
+    auto child = node->getChild(i);
+    if (child->getStyle().positionType() != PositionType::Absolute) {
+      if (child->getFlexStartMarginValue(mainAxis).unit() == Unit::Auto) {
+        numberOfAutoMarginsOnCurrentLine++;
+      }
+      if (child->marginTrailingValue(mainAxis).unit() == Unit::Auto) {
+        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 = gap;
+  const Justify justifyContent = node->getStyle().justifyContent();
+
+  if (numberOfAutoMarginsOnCurrentLine == 0) {
+    switch (justifyContent) {
+      case Justify::Center:
+        leadingMainDim = flexLine.layout.remainingFreeSpace / 2;
+        break;
+      case Justify::FlexEnd:
+        leadingMainDim = flexLine.layout.remainingFreeSpace;
+        break;
+      case Justify::SpaceBetween:
+        if (flexLine.itemsInFlow.size() > 1) {
+          betweenMainDim +=
+              yoga::maxOrDefined(flexLine.layout.remainingFreeSpace, 0.0f) /
+              static_cast<float>(flexLine.itemsInFlow.size() - 1);
+        }
+        break;
+      case Justify::SpaceEvenly:
+        // Space is distributed evenly across all elements
+        leadingMainDim = flexLine.layout.remainingFreeSpace /
+            static_cast<float>(flexLine.itemsInFlow.size() + 1);
+        betweenMainDim += leadingMainDim;
+        break;
+      case Justify::SpaceAround:
+        // Space on the edges is half of the space between elements
+        leadingMainDim = 0.5f * flexLine.layout.remainingFreeSpace /
+            static_cast<float>(flexLine.itemsInFlow.size());
+        betweenMainDim += leadingMainDim * 2;
+        break;
+      case Justify::FlexStart:
+        break;
+    }
+  }
+
+  flexLine.layout.mainDim = leadingPaddingAndBorderMain + leadingMainDim;
+  flexLine.layout.crossDim = 0;
+
+  float maxAscentForCurrentLine = 0;
+  float maxDescentForCurrentLine = 0;
+  bool isNodeBaselineLayout = isBaselineLayout(node);
+  for (size_t i = startOfLineIndex; i < flexLine.endOfLineIndex; i++) {
+    const auto child = node->getChild(i);
+    const Style& childStyle = child->getStyle();
+    const LayoutResults& childLayout = child->getLayout();
+    if (childStyle.display() == Display::None) {
+      continue;
+    }
+    if (childStyle.positionType() == PositionType::Absolute &&
+        child->isInlineStartPositionDefined(mainAxis, direction)) {
+      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(
+            child->getInlineStartPosition(
+                mainAxis, direction, availableInnerMainDim) +
+                node->getInlineStartBorder(mainAxis, direction) +
+                child->getInlineStartMargin(
+                    mainAxis, direction, availableInnerWidth),
+            flexStartEdge(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() != PositionType::Absolute) {
+        if (child->getFlexStartMarginValue(mainAxis).unit() == Unit::Auto) {
+          flexLine.layout.mainDim += flexLine.layout.remainingFreeSpace /
+              static_cast<float>(numberOfAutoMarginsOnCurrentLine);
+        }
+
+        if (performLayout) {
+          child->setLayoutPosition(
+              childLayout.position(flexStartEdge(mainAxis)) +
+                  flexLine.layout.mainDim,
+              flexStartEdge(mainAxis));
+        }
+
+        if (child != flexLine.itemsInFlow.back()) {
+          flexLine.layout.mainDim += betweenMainDim;
+        }
+
+        if (child->marginTrailingValue(mainAxis).unit() == Unit::Auto) {
+          flexLine.layout.mainDim += flexLine.layout.remainingFreeSpace /
+              static_cast<float>(numberOfAutoMarginsOnCurrentLine);
+        }
+        bool canSkipFlex =
+            !performLayout && sizingModeCrossDim == SizingMode::StretchFit;
+        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
+          // dimensionWithMargin.
+          flexLine.layout.mainDim +=
+              child->getMarginForAxis(mainAxis, availableInnerWidth) +
+              childLayout.computedFlexBasis.unwrap();
+          flexLine.layout.crossDim = availableInnerCrossDim;
+        } else {
+          // The main dimension is the sum of all the elements dimension plus
+          // the spacing.
+          flexLine.layout.mainDim +=
+              child->dimensionWithMargin(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 = calculateBaseline(child) +
+                child->getInlineStartMargin(
+                    FlexDirection::Column, direction, availableInnerWidth);
+            const float descent =
+                child->getLayout().measuredDimension(Dimension::Height) +
+                child->getMarginForAxis(
+                    FlexDirection::Column, availableInnerWidth) -
+                ascent;
+
+            maxAscentForCurrentLine =
+                yoga::maxOrDefined(maxAscentForCurrentLine, ascent);
+            maxDescentForCurrentLine =
+                yoga::maxOrDefined(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
+            flexLine.layout.crossDim = yoga::maxOrDefined(
+                flexLine.layout.crossDim,
+                child->dimensionWithMargin(crossAxis, availableInnerWidth));
+          }
+        }
+      } else if (performLayout) {
+        child->setLayoutPosition(
+            childLayout.position(flexStartEdge(mainAxis)) +
+                node->getInlineStartBorder(mainAxis, direction) +
+                leadingMainDim,
+            flexStartEdge(mainAxis));
+      }
+    }
+  }
+  flexLine.layout.mainDim += trailingPaddingAndBorderMain;
+
+  if (isNodeBaselineLayout) {
+    flexLine.layout.crossDim =
+        maxAscentForCurrentLine + maxDescentForCurrentLine;
+  }
+}
+
+//
+// This is the main routine that implements a subset of the flexbox layout
+// algorithm described in the W3C CSS documentation:
+// https://www.w3.org/TR/CSS3-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 laid 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)
+//    - widthSizingMode: indicates the sizing rules for the width (see below
+//      for explanation)
+//    - heightSizingMode: 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 laid 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.
+//
+//    When calling calculateLayoutImpl and calculateLayoutInternal, if the
+//    caller passes an available size of undefined then it must also pass a
+//    measure mode of SizingMode::MaxContent in that dimension.
+//
+static void calculateLayoutImpl(
+    yoga::Node* const node,
+    const float availableWidth,
+    const float availableHeight,
+    const Direction ownerDirection,
+    const SizingMode widthSizingMode,
+    const SizingMode heightSizingMode,
+    const float ownerWidth,
+    const float ownerHeight,
+    const bool performLayout,
+    LayoutData& layoutMarkerData,
+    const uint32_t depth,
+    const uint32_t generationCount,
+    const LayoutPassReason reason) {
+  yoga::assertFatalWithNode(
+      node,
+      yoga::isUndefined(availableWidth)
+          ? widthSizingMode == SizingMode::MaxContent
+          : true,
+      "availableWidth is indefinite so widthSizingMode must be "
+      "SizingMode::MaxContent");
+  yoga::assertFatalWithNode(
+      node,
+      yoga::isUndefined(availableHeight)
+          ? heightSizingMode == SizingMode::MaxContent
+          : true,
+      "availableHeight is indefinite so heightSizingMode must be "
+      "SizingMode::MaxContent");
+
+  (performLayout ? layoutMarkerData.layouts : layoutMarkerData.measures) += 1;
+
+  // Set the resolved resolution in the node's layout.
+  const Direction direction = node->resolveDirection(ownerDirection);
+  node->setLayoutDirection(direction);
+
+  const FlexDirection flexRowDirection =
+      resolveDirection(FlexDirection::Row, direction);
+  const FlexDirection flexColumnDirection =
+      resolveDirection(FlexDirection::Column, direction);
+
+  const Edge startEdge = direction == Direction::LTR ? Edge::Left : Edge::Right;
+  const Edge endEdge = direction == Direction::LTR ? Edge::Right : Edge::Left;
+
+  const float marginRowLeading =
+      node->getInlineStartMargin(flexRowDirection, direction, ownerWidth);
+  node->setLayoutMargin(marginRowLeading, startEdge);
+  const float marginRowTrailing =
+      node->getInlineEndMargin(flexRowDirection, direction, ownerWidth);
+  node->setLayoutMargin(marginRowTrailing, endEdge);
+  const float marginColumnLeading =
+      node->getInlineStartMargin(flexColumnDirection, direction, ownerWidth);
+  node->setLayoutMargin(marginColumnLeading, Edge::Top);
+  const float marginColumnTrailing =
+      node->getInlineEndMargin(flexColumnDirection, direction, ownerWidth);
+  node->setLayoutMargin(marginColumnTrailing, Edge::Bottom);
+
+  const float marginAxisRow = marginRowLeading + marginRowTrailing;
+  const float marginAxisColumn = marginColumnLeading + marginColumnTrailing;
+
+  node->setLayoutBorder(
+      node->getInlineStartBorder(flexRowDirection, direction), startEdge);
+  node->setLayoutBorder(
+      node->getInlineEndBorder(flexRowDirection, direction), endEdge);
+  node->setLayoutBorder(
+      node->getInlineStartBorder(flexColumnDirection, direction), Edge::Top);
+  node->setLayoutBorder(
+      node->getInlineEndBorder(flexColumnDirection, direction), Edge::Bottom);
+
+  node->setLayoutPadding(
+      node->getInlineStartPadding(flexRowDirection, direction, ownerWidth),
+      startEdge);
+  node->setLayoutPadding(
+      node->getInlineEndPadding(flexRowDirection, direction, ownerWidth),
+      endEdge);
+  node->setLayoutPadding(
+      node->getInlineStartPadding(flexColumnDirection, direction, ownerWidth),
+      Edge::Top);
+  node->setLayoutPadding(
+      node->getInlineEndPadding(flexColumnDirection, direction, ownerWidth),
+      Edge::Bottom);
+
+  if (node->hasMeasureFunc()) {
+    measureNodeWithMeasureFunc(
+        node,
+        availableWidth - marginAxisRow,
+        availableHeight - marginAxisColumn,
+        widthSizingMode,
+        heightSizingMode,
+        ownerWidth,
+        ownerHeight,
+        layoutMarkerData,
+        reason);
+    return;
+  }
+
+  const auto childCount = node->getChildCount();
+  if (childCount == 0) {
+    measureNodeWithoutChildren(
+        node,
+        availableWidth - marginAxisRow,
+        availableHeight - marginAxisColumn,
+        widthSizingMode,
+        heightSizingMode,
+        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 &&
+      measureNodeWithFixedSize(
+          node,
+          availableWidth - marginAxisRow,
+          availableHeight - marginAxisColumn,
+          widthSizingMode,
+          heightSizingMode,
+          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 FlexDirection mainAxis =
+      resolveDirection(node->getStyle().flexDirection(), direction);
+  const FlexDirection crossAxis = resolveCrossDirection(mainAxis, direction);
+  const bool isMainAxisRow = isRow(mainAxis);
+  const bool isNodeFlexWrap = node->getStyle().flexWrap() != Wrap::NoWrap;
+
+  const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight;
+  const float crossAxisownerSize = isMainAxisRow ? ownerHeight : ownerWidth;
+
+  const float paddingAndBorderAxisMain =
+      paddingAndBorderForAxis(node, mainAxis, ownerWidth);
+  const float paddingAndBorderAxisCross =
+      paddingAndBorderForAxis(node, crossAxis, ownerWidth);
+  const float leadingPaddingAndBorderCross =
+      node->getInlineStartPaddingAndBorder(crossAxis, direction, ownerWidth);
+
+  SizingMode sizingModeMainDim =
+      isMainAxisRow ? widthSizingMode : heightSizingMode;
+  SizingMode sizingModeCrossDim =
+      isMainAxisRow ? heightSizingMode : widthSizingMode;
+
+  const float paddingAndBorderAxisRow =
+      isMainAxisRow ? paddingAndBorderAxisMain : paddingAndBorderAxisCross;
+  const float paddingAndBorderAxisColumn =
+      isMainAxisRow ? paddingAndBorderAxisCross : paddingAndBorderAxisMain;
+
+  // STEP 2: DETERMINE AVAILABLE SIZE IN MAIN AND CROSS DIRECTIONS
+
+  float availableInnerWidth = calculateAvailableInnerDimension(
+      node,
+      Dimension::Width,
+      availableWidth - marginAxisRow,
+      paddingAndBorderAxisRow,
+      ownerWidth);
+  float availableInnerHeight = calculateAvailableInnerDimension(
+      node,
+      Dimension::Height,
+      availableHeight - marginAxisColumn,
+      paddingAndBorderAxisColumn,
+      ownerHeight);
+
+  float availableInnerMainDim =
+      isMainAxisRow ? availableInnerWidth : availableInnerHeight;
+  const float availableInnerCrossDim =
+      isMainAxisRow ? availableInnerHeight : availableInnerWidth;
+
+  // STEP 3: DETERMINE FLEX BASIS FOR EACH ITEM
+
+  // Computed basis + margins + gap
+  float totalMainDim = 0;
+  totalMainDim += computeFlexBasisForChildren(
+      node,
+      availableInnerWidth,
+      availableInnerHeight,
+      widthSizingMode,
+      heightSizingMode,
+      direction,
+      mainAxis,
+      performLayout,
+      layoutMarkerData,
+      depth,
+      generationCount);
+
+  if (childCount > 1) {
+    totalMainDim +=
+        node->getGapForAxis(mainAxis) * static_cast<float>(childCount - 1);
+  }
+
+  const bool mainAxisOverflows =
+      (sizingModeMainDim != SizingMode::MaxContent) &&
+      totalMainDim > availableInnerMainDim;
+
+  if (isNodeFlexWrap && mainAxisOverflows &&
+      sizingModeMainDim == SizingMode::FitContent) {
+    sizingModeMainDim = SizingMode::StretchFit;
+  }
+  // STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
+
+  // Indexes of children that represent the first and last items in the line.
+  size_t startOfLineIndex = 0;
+  size_t endOfLineIndex = 0;
+
+  // Number of lines.
+  size_t lineCount = 0;
+
+  // Accumulated cross dimensions of all lines so far.
+  float totalLineCrossDim = 0;
+
+  const float crossAxisGap = node->getGapForAxis(crossAxis);
+
+  // Max main dimension of all the lines.
+  float maxLineMainDim = 0;
+  for (; endOfLineIndex < childCount;
+       lineCount++, startOfLineIndex = endOfLineIndex) {
+    auto flexLine = calculateFlexLine(
+        node,
+        ownerDirection,
+        mainAxisownerSize,
+        availableInnerWidth,
+        availableInnerMainDim,
+        startOfLineIndex,
+        lineCount);
+
+    endOfLineIndex = flexLine.endOfLineIndex;
+
+    // If we don't need to measure the cross axis, we can skip the entire flex
+    // step.
+    const bool canSkipFlex =
+        !performLayout && sizingModeCrossDim == SizingMode::StretchFit;
+
+    // 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 (sizingModeMainDim != SizingMode::StretchFit) {
+      const auto& style = node->getStyle();
+      const float minInnerWidth =
+          style.minDimension(Dimension::Width).resolve(ownerWidth).unwrap() -
+          paddingAndBorderAxisRow;
+      const float maxInnerWidth =
+          style.maxDimension(Dimension::Width).resolve(ownerWidth).unwrap() -
+          paddingAndBorderAxisRow;
+      const float minInnerHeight =
+          style.minDimension(Dimension::Height).resolve(ownerHeight).unwrap() -
+          paddingAndBorderAxisColumn;
+      const float maxInnerHeight =
+          style.maxDimension(Dimension::Height).resolve(ownerHeight).unwrap() -
+          paddingAndBorderAxisColumn;
+
+      const float minInnerMainDim =
+          isMainAxisRow ? minInnerWidth : minInnerHeight;
+      const float maxInnerMainDim =
+          isMainAxisRow ? maxInnerWidth : maxInnerHeight;
+
+      if (yoga::isDefined(minInnerMainDim) &&
+          flexLine.sizeConsumed < minInnerMainDim) {
+        availableInnerMainDim = minInnerMainDim;
+      } else if (
+          yoga::isDefined(maxInnerMainDim) &&
+          flexLine.sizeConsumed > maxInnerMainDim) {
+        availableInnerMainDim = maxInnerMainDim;
+      } else {
+        bool useLegacyStretchBehaviour =
+            node->hasErrata(Errata::StretchFlexBasis);
+
+        if (!useLegacyStretchBehaviour &&
+            ((yoga::isDefined(flexLine.layout.totalFlexGrowFactors) &&
+              flexLine.layout.totalFlexGrowFactors == 0) ||
+             (yoga::isDefined(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 = flexLine.sizeConsumed;
+        }
+
+        sizeBasedOnContent = !useLegacyStretchBehaviour;
+      }
+    }
+
+    if (!sizeBasedOnContent && yoga::isDefined(availableInnerMainDim)) {
+      flexLine.layout.remainingFreeSpace =
+          availableInnerMainDim - flexLine.sizeConsumed;
+    } else if (flexLine.sizeConsumed < 0) {
+      // availableInnerMainDim is indefinite which means the node is being sized
+      // based on its content. sizeConsumed is negative which means
+      // the node will allocate 0 points for its content. Consequently,
+      // remainingFreeSpace is 0 - sizeConsumed.
+      flexLine.layout.remainingFreeSpace = -flexLine.sizeConsumed;
+    }
+
+    if (!canSkipFlex) {
+      resolveFlexibleLength(
+          node,
+          flexLine,
+          mainAxis,
+          crossAxis,
+          mainAxisownerSize,
+          availableInnerMainDim,
+          availableInnerCrossDim,
+          availableInnerWidth,
+          availableInnerHeight,
+          mainAxisOverflows,
+          sizingModeCrossDim,
+          performLayout,
+          layoutMarkerData,
+          depth,
+          generationCount);
+    }
+
+    node->setLayoutHadOverflow(
+        node->getLayout().hadOverflow() ||
+        (flexLine.layout.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.
+
+    justifyMainAxis(
+        node,
+        flexLine,
+        startOfLineIndex,
+        mainAxis,
+        crossAxis,
+        direction,
+        sizingModeMainDim,
+        sizingModeCrossDim,
+        mainAxisownerSize,
+        ownerWidth,
+        availableInnerMainDim,
+        availableInnerCrossDim,
+        availableInnerWidth,
+        performLayout);
+
+    float containerCrossAxis = availableInnerCrossDim;
+    if (sizingModeCrossDim == SizingMode::MaxContent ||
+        sizingModeCrossDim == SizingMode::FitContent) {
+      // Compute the cross axis from the max cross dimension of the children.
+      containerCrossAxis =
+          boundAxis(
+              node,
+              crossAxis,
+              flexLine.layout.crossDim + paddingAndBorderAxisCross,
+              crossAxisownerSize,
+              ownerWidth) -
+          paddingAndBorderAxisCross;
+    }
+
+    // If there's no flex wrap, the cross dimension is defined by the container.
+    if (!isNodeFlexWrap && sizingModeCrossDim == SizingMode::StretchFit) {
+      flexLine.layout.crossDim = availableInnerCrossDim;
+    }
+
+    // As-per https://www.w3.org/TR/css-flexbox-1/#cross-sizing, the
+    // cross-size of the line within a single-line container should be bound to
+    // min/max constraints before alignment within the line. In a multi-line
+    // container, affecting alignment between the lines.
+    if (!isNodeFlexWrap) {
+      flexLine.layout.crossDim =
+          boundAxis(
+              node,
+              crossAxis,
+              flexLine.layout.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 (size_t i = startOfLineIndex; i < endOfLineIndex; i++) {
+        const auto child = node->getChild(i);
+        if (child->getStyle().display() == Display::None) {
+          continue;
+        }
+        if (child->getStyle().positionType() == PositionType::Absolute) {
+          // 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->isInlineStartPositionDefined(crossAxis, direction);
+          if (isChildLeadingPosDefined) {
+            child->setLayoutPosition(
+                child->getInlineStartPosition(
+                    crossAxis, direction, availableInnerCrossDim) +
+                    node->getInlineStartBorder(crossAxis, direction) +
+                    child->getInlineStartMargin(
+                        crossAxis, direction, availableInnerWidth),
+                flexStartEdge(crossAxis));
+          }
+          // If leading position is not defined or calculations result in Nan,
+          // default to border + margin
+          if (!isChildLeadingPosDefined ||
+              yoga::isUndefined(
+                  child->getLayout().position(flexStartEdge(crossAxis)))) {
+            child->setLayoutPosition(
+                node->getInlineStartBorder(crossAxis, direction) +
+                    child->getInlineStartMargin(
+                        crossAxis, direction, availableInnerWidth),
+                flexStartEdge(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 Align alignItem = resolveChildAlignment(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 == Align::Stretch &&
+              child->getFlexStartMarginValue(crossAxis).unit() != Unit::Auto &&
+              child->marginTrailingValue(crossAxis).unit() != Unit::Auto) {
+            // If the child defines a definite size for its cross axis, there's
+            // no need to stretch.
+            if (!child->hasDefiniteLength(
+                    dimension(crossAxis), availableInnerCrossDim)) {
+              float childMainSize =
+                  child->getLayout().measuredDimension(dimension(mainAxis));
+              const auto& childStyle = child->getStyle();
+              float childCrossSize = childStyle.aspectRatio().isDefined()
+                  ? child->getMarginForAxis(crossAxis, availableInnerWidth) +
+                      (isMainAxisRow
+                           ? childMainSize / childStyle.aspectRatio().unwrap()
+                           : childMainSize * childStyle.aspectRatio().unwrap())
+                  : flexLine.layout.crossDim;
+
+              childMainSize +=
+                  child->getMarginForAxis(mainAxis, availableInnerWidth);
+
+              SizingMode childMainSizingMode = SizingMode::StretchFit;
+              SizingMode childCrossSizingMode = SizingMode::StretchFit;
+              constrainMaxSizeForMode(
+                  child,
+                  mainAxis,
+                  availableInnerMainDim,
+                  availableInnerWidth,
+                  &childMainSizingMode,
+                  &childMainSize);
+              constrainMaxSizeForMode(
+                  child,
+                  crossAxis,
+                  availableInnerCrossDim,
+                  availableInnerWidth,
+                  &childCrossSizingMode,
+                  &childCrossSize);
+
+              const float childWidth =
+                  isMainAxisRow ? childMainSize : childCrossSize;
+              const float childHeight =
+                  !isMainAxisRow ? childMainSize : childCrossSize;
+
+              auto alignContent = node->getStyle().alignContent();
+              auto crossAxisDoesNotGrow =
+                  alignContent != Align::Stretch && isNodeFlexWrap;
+              const SizingMode childWidthSizingMode =
+                  yoga::isUndefined(childWidth) ||
+                      (!isMainAxisRow && crossAxisDoesNotGrow)
+                  ? SizingMode::MaxContent
+                  : SizingMode::StretchFit;
+              const SizingMode childHeightSizingMode =
+                  yoga::isUndefined(childHeight) ||
+                      (isMainAxisRow && crossAxisDoesNotGrow)
+                  ? SizingMode::MaxContent
+                  : SizingMode::StretchFit;
+
+              calculateLayoutInternal(
+                  child,
+                  childWidth,
+                  childHeight,
+                  direction,
+                  childWidthSizingMode,
+                  childHeightSizingMode,
+                  availableInnerWidth,
+                  availableInnerHeight,
+                  true,
+                  LayoutPassReason::kStretch,
+                  layoutMarkerData,
+                  depth,
+                  generationCount);
+            }
+          } else {
+            const float remainingCrossDim = containerCrossAxis -
+                child->dimensionWithMargin(crossAxis, availableInnerWidth);
+
+            if (child->getFlexStartMarginValue(crossAxis).unit() ==
+                    Unit::Auto &&
+                child->marginTrailingValue(crossAxis).unit() == Unit::Auto) {
+              leadingCrossDim +=
+                  yoga::maxOrDefined(0.0f, remainingCrossDim / 2);
+            } else if (
+                child->marginTrailingValue(crossAxis).unit() == Unit::Auto) {
+              // No-Op
+            } else if (
+                child->getFlexStartMarginValue(crossAxis).unit() ==
+                Unit::Auto) {
+              leadingCrossDim += yoga::maxOrDefined(0.0f, remainingCrossDim);
+            } else if (alignItem == Align::FlexStart) {
+              // No-Op
+            } else if (alignItem == Align::Center) {
+              leadingCrossDim += remainingCrossDim / 2;
+            } else {
+              leadingCrossDim += remainingCrossDim;
+            }
+          }
+          // And we apply the position
+          child->setLayoutPosition(
+              child->getLayout().position(flexStartEdge(crossAxis)) +
+                  totalLineCrossDim + leadingCrossDim,
+              flexStartEdge(crossAxis));
+        }
+      }
+    }
+
+    const float appliedCrossGap = lineCount != 0 ? crossAxisGap : 0.0f;
+    totalLineCrossDim += flexLine.layout.crossDim + appliedCrossGap;
+    maxLineMainDim =
+        yoga::maxOrDefined(maxLineMainDim, flexLine.layout.mainDim);
+  }
+
+  // STEP 8: MULTI-LINE CONTENT ALIGNMENT
+  // currentLead stores the size of the cross dim
+  if (performLayout && (isNodeFlexWrap || isBaselineLayout(node))) {
+    float leadPerLine = 0;
+    float currentLead = leadingPaddingAndBorderCross;
+
+    const float unclampedCrossDim = sizingModeCrossDim == SizingMode::StretchFit
+        ? availableInnerCrossDim + paddingAndBorderAxisCross
+        : node->hasDefiniteLength(dimension(crossAxis), crossAxisownerSize)
+        ? node->getResolvedDimension(dimension(crossAxis))
+              .resolve(crossAxisownerSize)
+              .unwrap()
+        : totalLineCrossDim + paddingAndBorderAxisCross;
+
+    const float innerCrossDim =
+        boundAxis(node, crossAxis, unclampedCrossDim, ownerHeight, ownerWidth) -
+        paddingAndBorderAxisCross;
+
+    const float remainingAlignContentDim = innerCrossDim - totalLineCrossDim;
+    switch (node->getStyle().alignContent()) {
+      case Align::FlexEnd:
+        currentLead += remainingAlignContentDim;
+        break;
+      case Align::Center:
+        currentLead += remainingAlignContentDim / 2;
+        break;
+      case Align::Stretch:
+        if (innerCrossDim > totalLineCrossDim) {
+          leadPerLine =
+              remainingAlignContentDim / static_cast<float>(lineCount);
+        }
+        break;
+      case Align::SpaceAround:
+        if (innerCrossDim > totalLineCrossDim) {
+          currentLead +=
+              remainingAlignContentDim / (2 * static_cast<float>(lineCount));
+          leadPerLine =
+              remainingAlignContentDim / static_cast<float>(lineCount);
+        } else {
+          currentLead += remainingAlignContentDim / 2;
+        }
+        break;
+      case Align::SpaceEvenly:
+        if (innerCrossDim > totalLineCrossDim) {
+          currentLead +=
+              remainingAlignContentDim / static_cast<float>(lineCount + 1);
+          leadPerLine =
+              remainingAlignContentDim / static_cast<float>(lineCount + 1);
+        } else {
+          currentLead += remainingAlignContentDim / 2;
+        }
+        break;
+      case Align::SpaceBetween:
+        if (innerCrossDim > totalLineCrossDim && lineCount > 1) {
+          leadPerLine =
+              remainingAlignContentDim / static_cast<float>(lineCount - 1);
+        }
+        break;
+      case Align::Auto:
+      case Align::FlexStart:
+      case Align::Baseline:
+        break;
+    }
+    size_t endIndex = 0;
+    for (size_t i = 0; i < lineCount; i++) {
+      const size_t startIndex = endIndex;
+      size_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 auto child = node->getChild(ii);
+        if (child->getStyle().display() == Display::None) {
+          continue;
+        }
+        if (child->getStyle().positionType() != PositionType::Absolute) {
+          if (child->getLineIndex() != i) {
+            break;
+          }
+          if (child->isLayoutDimensionDefined(crossAxis)) {
+            lineHeight = yoga::maxOrDefined(
+                lineHeight,
+                child->getLayout().measuredDimension(dimension(crossAxis)) +
+                    child->getMarginForAxis(crossAxis, availableInnerWidth));
+          }
+          if (resolveChildAlignment(node, child) == Align::Baseline) {
+            const float ascent = calculateBaseline(child) +
+                child->getInlineStartMargin(
+                    FlexDirection::Column, direction, availableInnerWidth);
+            const float descent =
+                child->getLayout().measuredDimension(Dimension::Height) +
+                child->getMarginForAxis(
+                    FlexDirection::Column, availableInnerWidth) -
+                ascent;
+            maxAscentForCurrentLine =
+                yoga::maxOrDefined(maxAscentForCurrentLine, ascent);
+            maxDescentForCurrentLine =
+                yoga::maxOrDefined(maxDescentForCurrentLine, descent);
+            lineHeight = yoga::maxOrDefined(
+                lineHeight, maxAscentForCurrentLine + maxDescentForCurrentLine);
+          }
+        }
+      }
+      endIndex = ii;
+      currentLead += i != 0 ? crossAxisGap : 0;
+
+      if (performLayout) {
+        for (ii = startIndex; ii < endIndex; ii++) {
+          const auto child = node->getChild(ii);
+          if (child->getStyle().display() == Display::None) {
+            continue;
+          }
+          if (child->getStyle().positionType() != PositionType::Absolute) {
+            switch (resolveChildAlignment(node, child)) {
+              case Align::FlexStart: {
+                child->setLayoutPosition(
+                    currentLead +
+                        child->getInlineStartMargin(
+                            crossAxis, direction, availableInnerWidth),
+                    flexStartEdge(crossAxis));
+                break;
+              }
+              case Align::FlexEnd: {
+                child->setLayoutPosition(
+                    currentLead + lineHeight -
+                        child->getInlineEndMargin(
+                            crossAxis, direction, availableInnerWidth) -
+                        child->getLayout().measuredDimension(
+                            dimension(crossAxis)),
+                    flexStartEdge(crossAxis));
+                break;
+              }
+              case Align::Center: {
+                float childHeight =
+                    child->getLayout().measuredDimension(dimension(crossAxis));
+
+                child->setLayoutPosition(
+                    currentLead + (lineHeight - childHeight) / 2,
+                    flexStartEdge(crossAxis));
+                break;
+              }
+              case Align::Stretch: {
+                child->setLayoutPosition(
+                    currentLead +
+                        child->getInlineStartMargin(
+                            crossAxis, direction, availableInnerWidth),
+                    flexStartEdge(crossAxis));
+
+                // Remeasure child with the line height as it as been only
+                // measured with the owners height yet.
+                if (!child->hasDefiniteLength(
+                        dimension(crossAxis), availableInnerCrossDim)) {
+                  const float childWidth = isMainAxisRow
+                      ? (child->getLayout().measuredDimension(
+                             Dimension::Width) +
+                         child->getMarginForAxis(mainAxis, availableInnerWidth))
+                      : leadPerLine + lineHeight;
+
+                  const float childHeight = !isMainAxisRow
+                      ? (child->getLayout().measuredDimension(
+                             Dimension::Height) +
+                         child->getMarginForAxis(
+                             crossAxis, availableInnerWidth))
+                      : leadPerLine + lineHeight;
+
+                  if (!(yoga::inexactEquals(
+                            childWidth,
+                            child->getLayout().measuredDimension(
+                                Dimension::Width)) &&
+                        yoga::inexactEquals(
+                            childHeight,
+                            child->getLayout().measuredDimension(
+                                Dimension::Height)))) {
+                    calculateLayoutInternal(
+                        child,
+                        childWidth,
+                        childHeight,
+                        direction,
+                        SizingMode::StretchFit,
+                        SizingMode::StretchFit,
+                        availableInnerWidth,
+                        availableInnerHeight,
+                        true,
+                        LayoutPassReason::kMultilineStretch,
+                        layoutMarkerData,
+                        depth,
+                        generationCount);
+                  }
+                }
+                break;
+              }
+              case Align::Baseline: {
+                child->setLayoutPosition(
+                    currentLead + maxAscentForCurrentLine -
+                        calculateBaseline(child) +
+                        child->getInlineStartPosition(
+                            FlexDirection::Column,
+                            direction,
+                            availableInnerCrossDim),
+                    Edge::Top);
+
+                break;
+              }
+              case Align::Auto:
+              case Align::SpaceBetween:
+              case Align::SpaceAround:
+              case Align::SpaceEvenly:
+                break;
+            }
+          }
+        }
+      }
+      currentLead = currentLead + leadPerLine + lineHeight;
+    }
+  }
+
+  // STEP 9: COMPUTING FINAL DIMENSIONS
+
+  node->setLayoutMeasuredDimension(
+      boundAxis(
+          node,
+          FlexDirection::Row,
+          availableWidth - marginAxisRow,
+          ownerWidth,
+          ownerWidth),
+      Dimension::Width);
+
+  node->setLayoutMeasuredDimension(
+      boundAxis(
+          node,
+          FlexDirection::Column,
+          availableHeight - marginAxisColumn,
+          ownerHeight,
+          ownerWidth),
+      Dimension::Height);
+
+  // If the user didn't specify a width or height for the node, set the
+  // dimensions based on the children.
+  if (sizingModeMainDim == SizingMode::MaxContent ||
+      (node->getStyle().overflow() != Overflow::Scroll &&
+       sizingModeMainDim == SizingMode::FitContent)) {
+    // 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(
+        boundAxis(
+            node, mainAxis, maxLineMainDim, mainAxisownerSize, ownerWidth),
+        dimension(mainAxis));
+
+  } else if (
+      sizingModeMainDim == SizingMode::FitContent &&
+      node->getStyle().overflow() == Overflow::Scroll) {
+    node->setLayoutMeasuredDimension(
+        yoga::maxOrDefined(
+            yoga::minOrDefined(
+                availableInnerMainDim + paddingAndBorderAxisMain,
+                boundAxisWithinMinAndMax(
+                    node,
+                    mainAxis,
+                    FloatOptional{maxLineMainDim},
+                    mainAxisownerSize)
+                    .unwrap()),
+            paddingAndBorderAxisMain),
+        dimension(mainAxis));
+  }
+
+  if (sizingModeCrossDim == SizingMode::MaxContent ||
+      (node->getStyle().overflow() != Overflow::Scroll &&
+       sizingModeCrossDim == SizingMode::FitContent)) {
+    // 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(
+        boundAxis(
+            node,
+            crossAxis,
+            totalLineCrossDim + paddingAndBorderAxisCross,
+            crossAxisownerSize,
+            ownerWidth),
+        dimension(crossAxis));
+
+  } else if (
+      sizingModeCrossDim == SizingMode::FitContent &&
+      node->getStyle().overflow() == Overflow::Scroll) {
+    node->setLayoutMeasuredDimension(
+        yoga::maxOrDefined(
+            yoga::minOrDefined(
+                availableInnerCrossDim + paddingAndBorderAxisCross,
+                boundAxisWithinMinAndMax(
+                    node,
+                    crossAxis,
+                    FloatOptional{
+                        totalLineCrossDim + paddingAndBorderAxisCross},
+                    crossAxisownerSize)
+                    .unwrap()),
+            paddingAndBorderAxisCross),
+        dimension(crossAxis));
+  }
+
+  // As we only wrapped in normal direction yet, we need to reverse the
+  // positions on wrap-reverse.
+  if (performLayout && node->getStyle().flexWrap() == Wrap::WrapReverse) {
+    for (size_t i = 0; i < childCount; i++) {
+      const auto child = node->getChild(i);
+      if (child->getStyle().positionType() != PositionType::Absolute) {
+        child->setLayoutPosition(
+            node->getLayout().measuredDimension(dimension(crossAxis)) -
+                child->getLayout().position(flexStartEdge(crossAxis)) -
+                child->getLayout().measuredDimension(dimension(crossAxis)),
+            flexStartEdge(crossAxis));
+      }
+    }
+  }
+
+  if (performLayout) {
+    // STEP 10: SIZING AND POSITIONING ABSOLUTE CHILDREN
+    if (!node->hasErrata(Errata::PositionStaticBehavesLikeRelative)) {
+      // Let the containing block layout its absolute descendants. By definition
+      // the containing block will not be static unless we are at the root.
+      if (node->getStyle().positionType() != PositionType::Static ||
+          node->alwaysFormsContainingBlock() || depth == 1) {
+        layoutAbsoluteDescendants(
+            node,
+            node,
+            isMainAxisRow ? sizingModeMainDim : sizingModeCrossDim,
+            direction,
+            layoutMarkerData,
+            depth,
+            generationCount,
+            0.0f,
+            0.0f);
+      }
+    } else {
+      for (auto child : node->getChildren()) {
+        if (child->getStyle().display() == Display::None ||
+            child->getStyle().positionType() != PositionType::Absolute) {
+          continue;
+        }
+        const bool absolutePercentageAgainstPaddingEdge =
+            node->getConfig()->isExperimentalFeatureEnabled(
+                ExperimentalFeature::AbsolutePercentageAgainstPaddingEdge);
+
+        layoutAbsoluteChild(
+            node,
+            node,
+            child,
+            absolutePercentageAgainstPaddingEdge
+                ? node->getLayout().measuredDimension(Dimension::Width)
+                : availableInnerWidth,
+            absolutePercentageAgainstPaddingEdge
+                ? node->getLayout().measuredDimension(Dimension::Height)
+                : availableInnerHeight,
+            isMainAxisRow ? sizingModeMainDim : sizingModeCrossDim,
+            direction,
+            layoutMarkerData,
+            depth,
+            generationCount);
+      }
+    }
+
+    // STEP 11: SETTING TRAILING POSITIONS FOR CHILDREN
+    const bool needsMainTrailingPos = needsTrailingPosition(mainAxis);
+    const bool needsCrossTrailingPos = needsTrailingPosition(crossAxis);
+
+    if (needsMainTrailingPos || needsCrossTrailingPos) {
+      for (size_t i = 0; i < childCount; i++) {
+        const auto child = node->getChild(i);
+        // Absolute children will be handled by their containing block since we
+        // cannot guarantee that their positions are set when their parents are
+        // done with layout.
+        if (child->getStyle().display() == Display::None ||
+            (!node->hasErrata(Errata::PositionStaticBehavesLikeRelative) &&
+             child->getStyle().positionType() == PositionType::Absolute)) {
+          continue;
+        }
+        if (needsMainTrailingPos) {
+          setChildTrailingPosition(node, child, mainAxis);
+        }
+
+        if (needsCrossTrailingPos) {
+          setChildTrailingPosition(node, child, crossAxis);
+        }
+      }
+    }
+  }
+}
+
+bool gPrintChanges = false;
+bool gPrintSkips = false;
+
+static const char* spacer =
+    "                                                            ";
+
+static const char* spacerWithLength(const unsigned long level) {
+  const size_t spacerLen = strlen(spacer);
+  if (level > spacerLen) {
+    return &spacer[0];
+  } else {
+    return &spacer[spacerLen - level];
+  }
+}
+
+static const char* sizingModeName(
+    const SizingMode mode,
+    const bool performLayout) {
+  switch (mode) {
+    case SizingMode::MaxContent:
+      return performLayout ? "LAY_UNDEFINED" : "UNDEFINED";
+    case SizingMode::StretchFit:
+      return performLayout ? "LAY_EXACTLY" : "EXACTLY";
+    case SizingMode::FitContent:
+      return performLayout ? "LAY_AT_MOST" : "AT_MOST";
+  }
+  return "";
+}
+
+//
+// This is a wrapper around the calculateLayoutImpl function. It determines
+// whether the layout request is redundant and can be skipped.
+//
+// Parameters:
+//  Input parameters are the same as calculateLayoutImpl (see above)
+//  Return parameter is true if layout was performed, false if skipped
+//
+bool calculateLayoutInternal(
+    yoga::Node* const node,
+    const float availableWidth,
+    const float availableHeight,
+    const Direction ownerDirection,
+    const SizingMode widthSizingMode,
+    const SizingMode heightSizingMode,
+    const float ownerWidth,
+    const float ownerHeight,
+    const bool performLayout,
+    const LayoutPassReason reason,
+    LayoutData& layoutMarkerData,
+    uint32_t depth,
+    const uint32_t generationCount) {
+  LayoutResults* layout = &node->getLayout();
+
+  depth++;
+
+  const bool needToVisitNode =
+      (node->isDirty() && layout->generationCount != generationCount) ||
+      layout->lastOwnerDirection != ownerDirection;
+
+  if (needToVisitNode) {
+    // Invalidate the cached results.
+    layout->nextCachedMeasurementsIndex = 0;
+    layout->cachedLayout.availableWidth = -1;
+    layout->cachedLayout.availableHeight = -1;
+    layout->cachedLayout.widthSizingMode = SizingMode::MaxContent;
+    layout->cachedLayout.heightSizingMode = SizingMode::MaxContent;
+    layout->cachedLayout.computedWidth = -1;
+    layout->cachedLayout.computedHeight = -1;
+  }
+
+  CachedMeasurement* 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 laid 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->hasMeasureFunc()) {
+    const float marginAxisRow =
+        node->getMarginForAxis(FlexDirection::Row, ownerWidth);
+    const float marginAxisColumn =
+        node->getMarginForAxis(FlexDirection::Column, ownerWidth);
+
+    // First, try to use the layout cache.
+    if (canUseCachedMeasurement(
+            widthSizingMode,
+            availableWidth,
+            heightSizingMode,
+            availableHeight,
+            layout->cachedLayout.widthSizingMode,
+            layout->cachedLayout.availableWidth,
+            layout->cachedLayout.heightSizingMode,
+            layout->cachedLayout.availableHeight,
+            layout->cachedLayout.computedWidth,
+            layout->cachedLayout.computedHeight,
+            marginAxisRow,
+            marginAxisColumn,
+            node->getConfig())) {
+      cachedResults = &layout->cachedLayout;
+    } else {
+      // Try to use the measurement cache.
+      for (size_t i = 0; i < layout->nextCachedMeasurementsIndex; i++) {
+        if (canUseCachedMeasurement(
+                widthSizingMode,
+                availableWidth,
+                heightSizingMode,
+                availableHeight,
+                layout->cachedMeasurements[i].widthSizingMode,
+                layout->cachedMeasurements[i].availableWidth,
+                layout->cachedMeasurements[i].heightSizingMode,
+                layout->cachedMeasurements[i].availableHeight,
+                layout->cachedMeasurements[i].computedWidth,
+                layout->cachedMeasurements[i].computedHeight,
+                marginAxisRow,
+                marginAxisColumn,
+                node->getConfig())) {
+          cachedResults = &layout->cachedMeasurements[i];
+          break;
+        }
+      }
+    }
+  } else if (performLayout) {
+    if (yoga::inexactEquals(
+            layout->cachedLayout.availableWidth, availableWidth) &&
+        yoga::inexactEquals(
+            layout->cachedLayout.availableHeight, availableHeight) &&
+        layout->cachedLayout.widthSizingMode == widthSizingMode &&
+        layout->cachedLayout.heightSizingMode == heightSizingMode) {
+      cachedResults = &layout->cachedLayout;
+    }
+  } else {
+    for (uint32_t i = 0; i < layout->nextCachedMeasurementsIndex; i++) {
+      if (yoga::inexactEquals(
+              layout->cachedMeasurements[i].availableWidth, availableWidth) &&
+          yoga::inexactEquals(
+              layout->cachedMeasurements[i].availableHeight, availableHeight) &&
+          layout->cachedMeasurements[i].widthSizingMode == widthSizingMode &&
+          layout->cachedMeasurements[i].heightSizingMode == heightSizingMode) {
+        cachedResults = &layout->cachedMeasurements[i];
+        break;
+      }
+    }
+  }
+
+  if (!needToVisitNode && cachedResults != nullptr) {
+    layout->setMeasuredDimension(
+        Dimension::Width, cachedResults->computedWidth);
+    layout->setMeasuredDimension(
+        Dimension::Height, cachedResults->computedHeight);
+
+    (performLayout ? layoutMarkerData.cachedLayouts
+                   : layoutMarkerData.cachedMeasures) += 1;
+
+    if (gPrintChanges && gPrintSkips) {
+      yoga::log(
+          node,
+          LogLevel::Verbose,
+          "%s%d.{[skipped] ",
+          spacerWithLength(depth),
+          depth);
+      node->print();
+      yoga::log(
+          node,
+          LogLevel::Verbose,
+          "wm: %s, hm: %s, aw: %f ah: %f => d: (%f, %f) %s\n",
+          sizingModeName(widthSizingMode, performLayout),
+          sizingModeName(heightSizingMode, performLayout),
+          availableWidth,
+          availableHeight,
+          cachedResults->computedWidth,
+          cachedResults->computedHeight,
+          LayoutPassReasonToString(reason));
+    }
+  } else {
+    if (gPrintChanges) {
+      yoga::log(
+          node,
+          LogLevel::Verbose,
+          "%s%d.{%s",
+          spacerWithLength(depth),
+          depth,
+          needToVisitNode ? "*" : "");
+      node->print();
+      yoga::log(
+          node,
+          LogLevel::Verbose,
+          "wm: %s, hm: %s, aw: %f ah: %f %s\n",
+          sizingModeName(widthSizingMode, performLayout),
+          sizingModeName(heightSizingMode, performLayout),
+          availableWidth,
+          availableHeight,
+          LayoutPassReasonToString(reason));
+    }
+
+    calculateLayoutImpl(
+        node,
+        availableWidth,
+        availableHeight,
+        ownerDirection,
+        widthSizingMode,
+        heightSizingMode,
+        ownerWidth,
+        ownerHeight,
+        performLayout,
+        layoutMarkerData,
+        depth,
+        generationCount,
+        reason);
+
+    if (gPrintChanges) {
+      yoga::log(
+          node,
+          LogLevel::Verbose,
+          "%s%d.}%s",
+          spacerWithLength(depth),
+          depth,
+          needToVisitNode ? "*" : "");
+      node->print();
+      yoga::log(
+          node,
+          LogLevel::Verbose,
+          "wm: %s, hm: %s, d: (%f, %f) %s\n",
+          sizingModeName(widthSizingMode, performLayout),
+          sizingModeName(heightSizingMode, performLayout),
+          layout->measuredDimension(Dimension::Width),
+          layout->measuredDimension(Dimension::Height),
+          LayoutPassReasonToString(reason));
+    }
+
+    layout->lastOwnerDirection = ownerDirection;
+
+    if (cachedResults == nullptr) {
+      layoutMarkerData.maxMeasureCache = std::max(
+          layoutMarkerData.maxMeasureCache,
+          layout->nextCachedMeasurementsIndex + 1u);
+
+      if (layout->nextCachedMeasurementsIndex ==
+          LayoutResults::MaxCachedMeasurements) {
+        if (gPrintChanges) {
+          yoga::log(node, LogLevel::Verbose, "Out of cache entries!\n");
+        }
+        layout->nextCachedMeasurementsIndex = 0;
+      }
+
+      CachedMeasurement* 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->widthSizingMode = widthSizingMode;
+      newCacheEntry->heightSizingMode = heightSizingMode;
+      newCacheEntry->computedWidth =
+          layout->measuredDimension(Dimension::Width);
+      newCacheEntry->computedHeight =
+          layout->measuredDimension(Dimension::Height);
+    }
+  }
+
+  if (performLayout) {
+    node->setLayoutDimension(
+        node->getLayout().measuredDimension(Dimension::Width),
+        Dimension::Width);
+    node->setLayoutDimension(
+        node->getLayout().measuredDimension(Dimension::Height),
+        Dimension::Height);
+
+    node->setHasNewLayout(true);
+    node->setDirty(false);
+  }
+
+  layout->generationCount = generationCount;
+
+  LayoutType layoutType;
+  if (performLayout) {
+    layoutType = !needToVisitNode && cachedResults == &layout->cachedLayout
+        ? LayoutType::kCachedLayout
+        : LayoutType::kLayout;
+  } else {
+    layoutType = cachedResults != nullptr ? LayoutType::kCachedMeasure
+                                          : LayoutType::kMeasure;
+  }
+  Event::publish<Event::NodeLayout>(node, {layoutType});
+
+  return (needToVisitNode || cachedResults == nullptr);
+}
+
+void calculateLayout(
+    yoga::Node* const node,
+    const float ownerWidth,
+    const float ownerHeight,
+    const Direction ownerDirection) {
+  Event::publish<Event::LayoutPassStart>(node);
+  LayoutData markerData = {};
+
+  // 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.fetch_add(1, std::memory_order_relaxed);
+  node->resolveDimension();
+  float width = YGUndefined;
+  SizingMode widthSizingMode = SizingMode::MaxContent;
+  const auto& style = node->getStyle();
+  if (node->hasDefiniteLength(Dimension::Width, ownerWidth)) {
+    width =
+        (node->getResolvedDimension(dimension(FlexDirection::Row))
+             .resolve(ownerWidth)
+             .unwrap() +
+         node->getMarginForAxis(FlexDirection::Row, ownerWidth));
+    widthSizingMode = SizingMode::StretchFit;
+  } else if (style.maxDimension(Dimension::Width)
+                 .resolve(ownerWidth)
+                 .isDefined()) {
+    width = style.maxDimension(Dimension::Width).resolve(ownerWidth).unwrap();
+    widthSizingMode = SizingMode::FitContent;
+  } else {
+    width = ownerWidth;
+    widthSizingMode = yoga::isUndefined(width) ? SizingMode::MaxContent
+                                               : SizingMode::StretchFit;
+  }
+
+  float height = YGUndefined;
+  SizingMode heightSizingMode = SizingMode::MaxContent;
+  if (node->hasDefiniteLength(Dimension::Height, ownerHeight)) {
+    height =
+        (node->getResolvedDimension(dimension(FlexDirection::Column))
+             .resolve(ownerHeight)
+             .unwrap() +
+         node->getMarginForAxis(FlexDirection::Column, ownerWidth));
+    heightSizingMode = SizingMode::StretchFit;
+  } else if (style.maxDimension(Dimension::Height)
+                 .resolve(ownerHeight)
+                 .isDefined()) {
+    height =
+        style.maxDimension(Dimension::Height).resolve(ownerHeight).unwrap();
+    heightSizingMode = SizingMode::FitContent;
+  } else {
+    height = ownerHeight;
+    heightSizingMode = yoga::isUndefined(height) ? SizingMode::MaxContent
+                                                 : SizingMode::StretchFit;
+  }
+  if (calculateLayoutInternal(
+          node,
+          width,
+          height,
+          ownerDirection,
+          widthSizingMode,
+          heightSizingMode,
+          ownerWidth,
+          ownerHeight,
+          true,
+          LayoutPassReason::kInitial,
+          markerData,
+          0, // tree root
+          gCurrentGenerationCount.load(std::memory_order_relaxed))) {
+    node->setPosition(
+        node->getLayout().direction(), ownerWidth, ownerHeight, ownerWidth);
+    roundLayoutResultsToPixelGrid(node, 0.0f, 0.0f);
+
+#ifdef DEBUG
+    if (node->getConfig()->shouldPrintTree()) {
+      yoga::print(
+          node,
+          PrintOptions::Layout | PrintOptions::Children | PrintOptions::Style);
+    }
+#endif
+  }
+
+  Event::publish<Event::LayoutPassEnd>(node, {&markerData});
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/algorithm/CalculateLayout.h view
@@ -0,0 +1,38 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>
+#include <yoga/algorithm/FlexDirection.h>
+#include <yoga/event/event.h>
+#include <yoga/node/Node.h>
+
+namespace facebook::yoga {
+
+void calculateLayout(
+    yoga::Node* const node,
+    const float ownerWidth,
+    const float ownerHeight,
+    const Direction ownerDirection);
+
+bool calculateLayoutInternal(
+    yoga::Node* const node,
+    const float availableWidth,
+    const float availableHeight,
+    const Direction ownerDirection,
+    const SizingMode widthSizingMode,
+    const SizingMode heightSizingMode,
+    const float ownerWidth,
+    const float ownerHeight,
+    const bool performLayout,
+    const LayoutPassReason reason,
+    LayoutData& layoutMarkerData,
+    const uint32_t depth,
+    const uint32_t generationCount);
+
+} // namespace facebook::yoga
+ yoga/yoga/algorithm/FlexDirection.h view
@@ -0,0 +1,143 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>
+
+#include <yoga/debug/AssertFatal.h>
+#include <yoga/enums/Dimension.h>
+#include <yoga/enums/Direction.h>
+#include <yoga/enums/Edge.h>
+#include <yoga/enums/FlexDirection.h>
+
+namespace facebook::yoga {
+
+inline bool isRow(const FlexDirection flexDirection) {
+  return flexDirection == FlexDirection::Row ||
+      flexDirection == FlexDirection::RowReverse;
+}
+
+inline bool isColumn(const FlexDirection flexDirection) {
+  return flexDirection == FlexDirection::Column ||
+      flexDirection == FlexDirection::ColumnReverse;
+}
+
+inline FlexDirection resolveDirection(
+    const FlexDirection flexDirection,
+    const Direction direction) {
+  if (direction == Direction::RTL) {
+    if (flexDirection == FlexDirection::Row) {
+      return FlexDirection::RowReverse;
+    } else if (flexDirection == FlexDirection::RowReverse) {
+      return FlexDirection::Row;
+    }
+  }
+
+  return flexDirection;
+}
+
+inline FlexDirection resolveCrossDirection(
+    const FlexDirection flexDirection,
+    const Direction direction) {
+  return isColumn(flexDirection)
+      ? resolveDirection(FlexDirection::Row, direction)
+      : FlexDirection::Column;
+}
+
+inline Edge flexStartEdge(const FlexDirection flexDirection) {
+  switch (flexDirection) {
+    case FlexDirection::Column:
+      return Edge::Top;
+    case FlexDirection::ColumnReverse:
+      return Edge::Bottom;
+    case FlexDirection::Row:
+      return Edge::Left;
+    case FlexDirection::RowReverse:
+      return Edge::Right;
+  }
+
+  fatalWithMessage("Invalid FlexDirection");
+}
+
+inline Edge flexEndEdge(const FlexDirection flexDirection) {
+  switch (flexDirection) {
+    case FlexDirection::Column:
+      return Edge::Bottom;
+    case FlexDirection::ColumnReverse:
+      return Edge::Top;
+    case FlexDirection::Row:
+      return Edge::Right;
+    case FlexDirection::RowReverse:
+      return Edge::Left;
+  }
+
+  fatalWithMessage("Invalid FlexDirection");
+}
+
+inline Edge inlineStartEdge(
+    const FlexDirection flexDirection,
+    const Direction direction) {
+  if (isRow(flexDirection)) {
+    return direction == Direction::RTL ? Edge::Right : Edge::Left;
+  }
+
+  return Edge::Top;
+}
+
+inline Edge inlineEndEdge(
+    const FlexDirection flexDirection,
+    const Direction direction) {
+  if (isRow(flexDirection)) {
+    return direction == Direction::RTL ? Edge::Left : Edge::Right;
+  }
+
+  return Edge::Bottom;
+}
+
+/**
+ * The physical edges that Edge::Start and Edge::End correspond to (e.g.
+ * left/right) are soley dependent on the direction. However, there are cases
+ * where we want the flex start/end edge (i.e. which edge is the start/end
+ * for laying out flex items), which can be distinct from the corresponding
+ * inline edge. In these cases we need to know which "relative edge"
+ * (Edge::Start/Edge::End) corresponds to the said flex start/end edge as these
+ * relative edges can be used instead of physical ones when defining certain
+ * attributes like border or padding.
+ */
+inline Edge flexStartRelativeEdge(
+    FlexDirection flexDirection,
+    Direction direction) {
+  const Edge leadLayoutEdge = inlineStartEdge(flexDirection, direction);
+  const Edge leadFlexItemEdge = flexStartEdge(flexDirection);
+  return leadLayoutEdge == leadFlexItemEdge ? Edge::Start : Edge::End;
+}
+
+inline Edge flexEndRelativeEdge(
+    FlexDirection flexDirection,
+    Direction direction) {
+  const Edge trailLayoutEdge = inlineEndEdge(flexDirection, direction);
+  const Edge trailFlexItemEdge = flexEndEdge(flexDirection);
+  return trailLayoutEdge == trailFlexItemEdge ? Edge::End : Edge::Start;
+}
+
+inline Dimension dimension(const FlexDirection flexDirection) {
+  switch (flexDirection) {
+    case FlexDirection::Column:
+      return Dimension::Height;
+    case FlexDirection::ColumnReverse:
+      return Dimension::Height;
+    case FlexDirection::Row:
+      return Dimension::Width;
+    case FlexDirection::RowReverse:
+      return Dimension::Width;
+  }
+
+  fatalWithMessage("Invalid FlexDirection");
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/algorithm/FlexLine.cpp view
@@ -0,0 +1,113 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>
+
+#include <yoga/algorithm/BoundAxis.h>
+#include <yoga/algorithm/FlexDirection.h>
+#include <yoga/algorithm/FlexLine.h>
+
+namespace facebook::yoga {
+
+FlexLine calculateFlexLine(
+    yoga::Node* const node,
+    const Direction ownerDirection,
+    const float mainAxisownerSize,
+    const float availableInnerWidth,
+    const float availableInnerMainDim,
+    const size_t startOfLineIndex,
+    const size_t lineCount) {
+  std::vector<yoga::Node*> itemsInFlow;
+  itemsInFlow.reserve(node->getChildren().size());
+
+  float sizeConsumed = 0.0f;
+  float totalFlexGrowFactors = 0.0f;
+  float totalFlexShrinkScaledFactors = 0.0f;
+  size_t endOfLineIndex = startOfLineIndex;
+  size_t firstElementInLineIndex = startOfLineIndex;
+
+  float sizeConsumedIncludingMinConstraint = 0;
+  const FlexDirection mainAxis = resolveDirection(
+      node->getStyle().flexDirection(), node->resolveDirection(ownerDirection));
+  const bool isNodeFlexWrap = node->getStyle().flexWrap() != Wrap::NoWrap;
+  const float gap = node->getGapForAxis(mainAxis);
+
+  // Add items to the current line until it's full or we run out of items.
+  for (; endOfLineIndex < node->getChildren().size(); endOfLineIndex++) {
+    auto child = node->getChild(endOfLineIndex);
+    if (child->getStyle().display() == Display::None ||
+        child->getStyle().positionType() == PositionType::Absolute) {
+      if (firstElementInLineIndex == endOfLineIndex) {
+        // We haven't found the first contributing element in the line yet.
+        firstElementInLineIndex++;
+      }
+      continue;
+    }
+
+    const bool isFirstElementInLine =
+        (endOfLineIndex - firstElementInLineIndex) == 0;
+
+    child->setLineIndex(lineCount);
+    const float childMarginMainAxis =
+        child->getMarginForAxis(mainAxis, availableInnerWidth);
+    const float childLeadingGapMainAxis = isFirstElementInLine ? 0.0f : gap;
+    const float flexBasisWithMinAndMaxConstraints =
+        boundAxisWithinMinAndMax(
+            child,
+            mainAxis,
+            child->getLayout().computedFlexBasis,
+            mainAxisownerSize)
+            .unwrap();
+
+    // 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 (sizeConsumedIncludingMinConstraint + flexBasisWithMinAndMaxConstraints +
+                childMarginMainAxis + childLeadingGapMainAxis >
+            availableInnerMainDim &&
+        isNodeFlexWrap && itemsInFlow.size() > 0) {
+      break;
+    }
+
+    sizeConsumedIncludingMinConstraint += flexBasisWithMinAndMaxConstraints +
+        childMarginMainAxis + childLeadingGapMainAxis;
+    sizeConsumed += flexBasisWithMinAndMaxConstraints + childMarginMainAxis +
+        childLeadingGapMainAxis;
+
+    if (child->isNodeFlexible()) {
+      totalFlexGrowFactors += child->resolveFlexGrow();
+
+      // Unlike the grow factor, the shrink factor is scaled relative to the
+      // child dimension.
+      totalFlexShrinkScaledFactors += -child->resolveFlexShrink() *
+          child->getLayout().computedFlexBasis.unwrap();
+    }
+
+    itemsInFlow.push_back(child);
+  }
+
+  // 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;
+  }
+
+  return FlexLine{
+      std::move(itemsInFlow),
+      sizeConsumed,
+      endOfLineIndex,
+      FlexLineRunningLayout{
+          totalFlexGrowFactors,
+          totalFlexShrinkScaledFactors,
+      }};
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/algorithm/FlexLine.h view
@@ -0,0 +1,74 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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 <vector>
+
+#include <yoga/Yoga.h>
+#include <yoga/node/Node.h>
+
+namespace facebook::yoga {
+
+struct FlexLineRunningLayout {
+  // Total flex grow factors of flex items which are to be laid in the current
+  // line. This is decremented as free space is distributed.
+  float totalFlexGrowFactors{0.0f};
+
+  // Total flex shrink factors of flex items which are to be laid in the current
+  // line. This is decremented as free space is distributed.
+  float totalFlexShrinkScaledFactors{0.0f};
+
+  // The amount of available space within inner dimensions of the line which may
+  // still be distributed.
+  float remainingFreeSpace{0.0f};
+
+  // 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{0.0f};
+
+  // 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{0.0f};
+};
+
+struct FlexLine {
+  // List of children which are part of the line flow. This means they are not
+  // positioned absolutely, or with `display: "none"`, and do not overflow the
+  // available dimensions.
+  const std::vector<yoga::Node*> itemsInFlow{};
+
+  // 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.
+  const float sizeConsumed{0.0f};
+
+  // The index of the first item beyond the current line.
+  const size_t endOfLineIndex{0};
+
+  // Layout information about the line computed in steps after line-breaking
+  FlexLineRunningLayout layout{};
+};
+
+// Calculates where a line starting at a given index should break, returning
+// information about the collective children on the liune.
+//
+// This function assumes that all the children of node have their
+// computedFlexBasis properly computed(To do this use
+// computeFlexBasisForChildren function).
+FlexLine calculateFlexLine(
+    yoga::Node* const node,
+    Direction ownerDirection,
+    float mainAxisownerSize,
+    float availableInnerWidth,
+    float availableInnerMainDim,
+    size_t startOfLineIndex,
+    size_t lineCount);
+
+} // namespace facebook::yoga
+ yoga/yoga/algorithm/PixelGrid.cpp view
@@ -0,0 +1,132 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>
+
+#include <yoga/algorithm/PixelGrid.h>
+#include <yoga/numeric/Comparison.h>
+
+namespace facebook::yoga {
+
+float roundValueToPixelGrid(
+    const double value,
+    const double pointScaleFactor,
+    const bool forceCeil,
+    const bool forceFloor) {
+  double scaledValue = value * pointScaleFactor;
+  // We want to calculate `fractial` such that `floor(scaledValue) = scaledValue
+  // - fractial`.
+  double fractial = fmod(scaledValue, 1.0);
+  if (fractial < 0) {
+    // This branch is for handling negative numbers for `value`.
+    //
+    // Regarding `floor` and `ceil`. Note that for a number x, `floor(x) <= x <=
+    // ceil(x)` even for negative numbers. Here are a couple of examples:
+    //   - x =  2.2: floor( 2.2) =  2, ceil( 2.2) =  3
+    //   - x = -2.2: floor(-2.2) = -3, ceil(-2.2) = -2
+    //
+    // Regarding `fmodf`. For fractional negative numbers, `fmodf` returns a
+    // negative number. For example, `fmodf(-2.2) = -0.2`. However, we want
+    // `fractial` to be the number such that subtracting it from `value` will
+    // give us `floor(value)`. In the case of negative numbers, adding 1 to
+    // `fmodf(value)` gives us this. Let's continue the example from above:
+    //   - fractial = fmodf(-2.2) = -0.2
+    //   - Add 1 to the fraction: fractial2 = fractial + 1 = -0.2 + 1 = 0.8
+    //   - Finding the `floor`: -2.2 - fractial2 = -2.2 - 0.8 = -3
+    ++fractial;
+  }
+  if (yoga::inexactEquals(fractial, 0)) {
+    // First we check if the value is already rounded
+    scaledValue = scaledValue - fractial;
+  } else if (yoga::inexactEquals(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.0;
+  } else if (forceFloor) {
+    scaledValue = scaledValue - fractial;
+  } else {
+    // Finally we just round the value
+    scaledValue = scaledValue - fractial +
+        (!std::isnan(fractial) &&
+                 (fractial > 0.5 || yoga::inexactEquals(fractial, 0.5))
+             ? 1.0
+             : 0.0);
+  }
+  return (std::isnan(scaledValue) || std::isnan(pointScaleFactor))
+      ? YGUndefined
+      : (float)(scaledValue / pointScaleFactor);
+}
+
+void roundLayoutResultsToPixelGrid(
+    yoga::Node* const node,
+    const double absoluteLeft,
+    const double absoluteTop) {
+  const auto pointScaleFactor = node->getConfig()->getPointScaleFactor();
+
+  const double nodeLeft = node->getLayout().position(Edge::Left);
+  const double nodeTop = node->getLayout().position(Edge::Top);
+
+  const double nodeWidth = node->getLayout().dimension(Dimension::Width);
+  const double nodeHeight = node->getLayout().dimension(Dimension::Height);
+
+  const double absoluteNodeLeft = absoluteLeft + nodeLeft;
+  const double absoluteNodeTop = absoluteTop + nodeTop;
+
+  const double absoluteNodeRight = absoluteNodeLeft + nodeWidth;
+  const double absoluteNodeBottom = absoluteNodeTop + nodeHeight;
+
+  if (pointScaleFactor != 0.0f) {
+    // 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() == NodeType::Text;
+
+    node->setLayoutPosition(
+        roundValueToPixelGrid(nodeLeft, pointScaleFactor, false, textRounding),
+        Edge::Left);
+
+    node->setLayoutPosition(
+        roundValueToPixelGrid(nodeTop, pointScaleFactor, false, textRounding),
+        Edge::Top);
+
+    // 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 =
+        !yoga::inexactEquals(fmod(nodeWidth * pointScaleFactor, 1.0), 0) &&
+        !yoga::inexactEquals(fmod(nodeWidth * pointScaleFactor, 1.0), 1.0);
+    const bool hasFractionalHeight =
+        !yoga::inexactEquals(fmod(nodeHeight * pointScaleFactor, 1.0), 0) &&
+        !yoga::inexactEquals(fmod(nodeHeight * pointScaleFactor, 1.0), 1.0);
+
+    node->setLayoutDimension(
+        roundValueToPixelGrid(
+            absoluteNodeRight,
+            pointScaleFactor,
+            (textRounding && hasFractionalWidth),
+            (textRounding && !hasFractionalWidth)) -
+            roundValueToPixelGrid(
+                absoluteNodeLeft, pointScaleFactor, false, textRounding),
+        Dimension::Width);
+
+    node->setLayoutDimension(
+        roundValueToPixelGrid(
+            absoluteNodeBottom,
+            pointScaleFactor,
+            (textRounding && hasFractionalHeight),
+            (textRounding && !hasFractionalHeight)) -
+            roundValueToPixelGrid(
+                absoluteNodeTop, pointScaleFactor, false, textRounding),
+        Dimension::Height);
+  }
+
+  for (yoga::Node* child : node->getChildren()) {
+    roundLayoutResultsToPixelGrid(child, absoluteNodeLeft, absoluteNodeTop);
+  }
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/algorithm/PixelGrid.h view
@@ -0,0 +1,29 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>
+#include <yoga/node/Node.h>
+
+namespace facebook::yoga {
+
+// Round a point value to the nearest physical pixel based on DPI
+// (pointScaleFactor)
+float roundValueToPixelGrid(
+    const double value,
+    const double pointScaleFactor,
+    const bool forceCeil,
+    const bool forceFloor);
+
+// Round the layout results of a node and its subtree to the pixel grid.
+void roundLayoutResultsToPixelGrid(
+    yoga::Node* const node,
+    const double absoluteLeft,
+    const double absoluteTop);
+
+} // namespace facebook::yoga
+ yoga/yoga/algorithm/SizingMode.h view
@@ -0,0 +1,73 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/debug/AssertFatal.h>
+#include <yoga/enums/MeasureMode.h>
+
+namespace facebook::yoga {
+
+/**
+ * Corresponds to a CSS auto box sizes. Missing "min-content", as Yoga does not
+ * current support automatic minimum sizes.
+ * https://www.w3.org/TR/css-sizing-3/#auto-box-sizes
+ * https://www.w3.org/TR/css-flexbox-1/#min-size-auto
+ */
+enum class SizingMode {
+  /**
+   * The size a box would take if its outer size filled the available space in
+   * the given axis; in other words, the stretch fit into the available space,
+   * if that is definite. Undefined if the available space is indefinite.
+   */
+  StretchFit,
+
+  /**
+   * A box’s “ideal” size in a given axis when given infinite available space.
+   * Usually this is the smallest size the box could take in that axis while
+   * still fitting around its contents, i.e. minimizing unfilled space while
+   * avoiding overflow.
+   */
+  MaxContent,
+
+  /**
+   * If the available space in a given axis is definite, equal to
+   * clamp(min-content size, stretch-fit size, max-content size) (i.e.
+   * max(min-content size, min(max-content size, stretch-fit size))). When
+   * sizing under a min-content constraint, equal to the min-content size.
+   * Otherwise, equal to the max-content size in that axis.
+   */
+  FitContent,
+};
+
+inline MeasureMode measureMode(SizingMode mode) {
+  switch (mode) {
+    case SizingMode::StretchFit:
+      return MeasureMode::Exactly;
+    case SizingMode::MaxContent:
+      return MeasureMode::Undefined;
+    case SizingMode::FitContent:
+      return MeasureMode::AtMost;
+  }
+
+  fatalWithMessage("Invalid SizingMode");
+}
+
+inline SizingMode sizingMode(MeasureMode mode) {
+  switch (mode) {
+    case MeasureMode::Exactly:
+      return SizingMode::StretchFit;
+    case MeasureMode::Undefined:
+      return SizingMode::MaxContent;
+    case MeasureMode::AtMost:
+      return SizingMode::FitContent;
+  }
+
+  fatalWithMessage("Invalid MeasureMode");
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/algorithm/TrailingPosition.h view
@@ -0,0 +1,44 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>
+#include <yoga/algorithm/FlexDirection.h>
+#include <yoga/event/event.h>
+#include <yoga/node/Node.h>
+
+namespace facebook::yoga {
+
+// Given an offset to an edge, returns the offset to the opposite edge on the
+// same axis. This assumes that the width/height of both nodes is determined at
+// this point.
+inline float getPositionOfOppositeEdge(
+    float position,
+    FlexDirection axis,
+    const yoga::Node* const containingNode,
+    const yoga::Node* const node) {
+  return containingNode->getLayout().measuredDimension(dimension(axis)) -
+      node->getLayout().measuredDimension(dimension(axis)) - position;
+}
+
+inline void setChildTrailingPosition(
+    const yoga::Node* const node,
+    yoga::Node* const child,
+    const FlexDirection axis) {
+  child->setLayoutPosition(
+      getPositionOfOppositeEdge(
+          child->getLayout().position(flexStartEdge(axis)), axis, node, child),
+      flexEndEdge(axis));
+}
+
+inline bool needsTrailingPosition(const FlexDirection axis) {
+  return axis == FlexDirection::RowReverse ||
+      axis == FlexDirection::ColumnReverse;
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/config/Config.cpp view
@@ -0,0 +1,128 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/config/Config.h>
+#include <yoga/debug/Log.h>
+#include <yoga/node/Node.h>
+
+namespace facebook::yoga {
+
+bool configUpdateInvalidatesLayout(
+    const Config& oldConfig,
+    const Config& newConfig) {
+  return oldConfig.getErrata() != newConfig.getErrata() ||
+      oldConfig.getEnabledExperiments() != newConfig.getEnabledExperiments() ||
+      oldConfig.getPointScaleFactor() != newConfig.getPointScaleFactor() ||
+      oldConfig.useWebDefaults() != newConfig.useWebDefaults();
+}
+
+Config::Config(YGLogger logger) : cloneNodeCallback_{nullptr} {
+  setLogger(logger);
+}
+
+void Config::setUseWebDefaults(bool useWebDefaults) {
+  useWebDefaults_ = useWebDefaults;
+}
+
+bool Config::useWebDefaults() const {
+  return useWebDefaults_;
+}
+
+void Config::setShouldPrintTree(bool printTree) {
+  printTree_ = printTree;
+}
+
+bool Config::shouldPrintTree() const {
+  return printTree_;
+}
+
+void Config::setExperimentalFeatureEnabled(
+    ExperimentalFeature feature,
+    bool enabled) {
+  experimentalFeatures_.set(static_cast<size_t>(feature), enabled);
+}
+
+bool Config::isExperimentalFeatureEnabled(ExperimentalFeature feature) const {
+  return experimentalFeatures_.test(static_cast<size_t>(feature));
+}
+
+ExperimentalFeatureSet Config::getEnabledExperiments() const {
+  return experimentalFeatures_;
+}
+
+void Config::setErrata(Errata errata) {
+  errata_ = errata;
+}
+
+void Config::addErrata(Errata errata) {
+  errata_ |= errata;
+}
+
+void Config::removeErrata(Errata errata) {
+  errata_ &= (~errata);
+}
+
+Errata Config::getErrata() const {
+  return errata_;
+}
+
+bool Config::hasErrata(Errata errata) const {
+  return (errata_ & errata) != Errata::None;
+}
+
+void Config::setPointScaleFactor(float pointScaleFactor) {
+  pointScaleFactor_ = pointScaleFactor;
+}
+
+float Config::getPointScaleFactor() const {
+  return pointScaleFactor_;
+}
+
+void Config::setContext(void* context) {
+  context_ = context;
+}
+
+void* Config::getContext() const {
+  return context_;
+}
+
+void Config::setLogger(YGLogger logger) {
+  logger_ = logger;
+}
+
+void Config::log(
+    const yoga::Node* node,
+    LogLevel logLevel,
+    const char* format,
+    va_list args) const {
+  logger_(this, node, unscopedEnum(logLevel), format, args);
+}
+
+void Config::setCloneNodeCallback(YGCloneNodeFunc cloneNode) {
+  cloneNodeCallback_ = cloneNode;
+}
+
+YGNodeRef Config::cloneNode(
+    YGNodeConstRef node,
+    YGNodeConstRef owner,
+    size_t childIndex) const {
+  YGNodeRef clone = nullptr;
+  if (cloneNodeCallback_ != nullptr) {
+    clone = cloneNodeCallback_(node, owner, childIndex);
+  }
+  if (clone == nullptr) {
+    clone = YGNodeClone(node);
+  }
+  return clone;
+}
+
+/*static*/ const Config& Config::getDefault() {
+  static Config config{getDefaultLogger()};
+  return config;
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/config/Config.h view
@@ -0,0 +1,93 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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 <bitset>
+
+#include <yoga/Yoga.h>
+#include <yoga/enums/Errata.h>
+#include <yoga/enums/ExperimentalFeature.h>
+#include <yoga/enums/LogLevel.h>
+
+// Tag struct used to form the opaque YGConfigRef for the public C API
+struct YGConfig {};
+
+namespace facebook::yoga {
+
+class Config;
+class Node;
+
+using ExperimentalFeatureSet = std::bitset<ordinalCount<ExperimentalFeature>()>;
+
+// Whether moving a node from an old to new config should dirty previously
+// calculated layout results.
+bool configUpdateInvalidatesLayout(
+    const Config& oldConfig,
+    const Config& newConfig);
+
+class YG_EXPORT Config : public ::YGConfig {
+ public:
+  Config(YGLogger logger);
+
+  void setUseWebDefaults(bool useWebDefaults);
+  bool useWebDefaults() const;
+
+  void setShouldPrintTree(bool printTree);
+  bool shouldPrintTree() const;
+
+  void setExperimentalFeatureEnabled(ExperimentalFeature feature, bool enabled);
+  bool isExperimentalFeatureEnabled(ExperimentalFeature feature) const;
+  ExperimentalFeatureSet getEnabledExperiments() const;
+
+  void setErrata(Errata errata);
+  void addErrata(Errata errata);
+  void removeErrata(Errata errata);
+  Errata getErrata() const;
+  bool hasErrata(Errata errata) const;
+
+  void setPointScaleFactor(float pointScaleFactor);
+  float getPointScaleFactor() const;
+
+  void setContext(void* context);
+  void* getContext() const;
+
+  void setLogger(YGLogger logger);
+  void log(
+      const yoga::Node* node,
+      LogLevel logLevel,
+      const char* format,
+      va_list args) const;
+
+  void setCloneNodeCallback(YGCloneNodeFunc cloneNode);
+  YGNodeRef
+  cloneNode(YGNodeConstRef node, YGNodeConstRef owner, size_t childIndex) const;
+
+  static const Config& getDefault();
+
+ private:
+  YGCloneNodeFunc cloneNodeCallback_;
+  YGLogger logger_;
+
+  bool useWebDefaults_ : 1 = false;
+  bool printTree_ : 1 = false;
+
+  ExperimentalFeatureSet experimentalFeatures_{};
+  Errata errata_ = Errata::None;
+  float pointScaleFactor_ = 1.0f;
+  void* context_ = nullptr;
+};
+
+inline Config* resolveRef(const YGConfigRef ref) {
+  return static_cast<Config*>(ref);
+}
+
+inline const Config* resolveRef(const YGConfigConstRef ref) {
+  return static_cast<const Config*>(ref);
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/debug/AssertFatal.cpp view
@@ -0,0 +1,53 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <exception>
+#include <stdexcept>
+
+#include <yoga/config/Config.h>
+#include <yoga/debug/AssertFatal.h>
+#include <yoga/debug/Log.h>
+#include <yoga/node/Node.h>
+
+namespace facebook::yoga {
+
+[[noreturn]] void fatalWithMessage(const char* message) {
+#if defined(__cpp_exceptions)
+  throw std::logic_error(message);
+#else
+  std::terminate();
+#endif
+}
+
+void assertFatal(const bool condition, const char* message) {
+  if (!condition) {
+    yoga::log(LogLevel::Fatal, "%s\n", message);
+    fatalWithMessage(message);
+  }
+}
+
+void assertFatalWithNode(
+    const yoga::Node* const node,
+    const bool condition,
+    const char* message) {
+  if (!condition) {
+    yoga::log(node, LogLevel::Fatal, "%s\n", message);
+    fatalWithMessage(message);
+  }
+}
+
+void assertFatalWithConfig(
+    const yoga::Config* const config,
+    const bool condition,
+    const char* message) {
+  if (!condition) {
+    yoga::log(config, LogLevel::Fatal, "%s\n", message);
+    fatalWithMessage(message);
+  }
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/debug/AssertFatal.h view
@@ -0,0 +1,29 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>
+
+namespace facebook::yoga {
+
+class Node;
+class Config;
+
+[[noreturn]] void fatalWithMessage(const char* message);
+
+void assertFatal(bool condition, const char* message);
+void assertFatalWithNode(
+    const yoga::Node* node,
+    bool condition,
+    const char* message);
+void assertFatalWithConfig(
+    const yoga::Config* config,
+    bool condition,
+    const char* message);
+
+} // namespace facebook::yoga
+ yoga/yoga/debug/Log.cpp view
@@ -0,0 +1,107 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/debug/Log.h>
+
+#ifdef ANDROID
+#include <android/log.h>
+#endif
+
+namespace facebook::yoga {
+
+namespace {
+
+void vlog(
+    const yoga::Config* config,
+    const yoga::Node* node,
+    LogLevel level,
+    const char* format,
+    va_list args) {
+  if (config == nullptr) {
+    getDefaultLogger()(nullptr, node, unscopedEnum(level), format, args);
+  } else {
+    config->log(node, level, format, args);
+  }
+}
+} // namespace
+
+void log(LogLevel level, const char* format, ...) noexcept {
+  va_list args;
+  va_start(args, format);
+  vlog(nullptr, nullptr, level, format, args);
+  va_end(args);
+}
+
+void log(
+    const yoga::Node* node,
+    LogLevel level,
+    const char* format,
+    ...) noexcept {
+  va_list args;
+  va_start(args, format);
+  vlog(
+      node == nullptr ? nullptr : node->getConfig(), node, level, format, args);
+  va_end(args);
+}
+
+void log(
+    const yoga::Config* config,
+    LogLevel level,
+    const char* format,
+    ...) noexcept {
+  va_list args;
+  va_start(args, format);
+  vlog(config, nullptr, level, format, args);
+  va_end(args);
+}
+
+YGLogger getDefaultLogger() {
+  return [](const YGConfigConstRef /*config*/,
+            const YGNodeConstRef /*node*/,
+            YGLogLevel level,
+            const char* format,
+            va_list args) -> int {
+#ifdef ANDROID
+    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;
+    }
+    return __android_log_vprint(androidLevel, "yoga", format, args);
+#else
+    switch (level) {
+      case YGLogLevelError:
+      case YGLogLevelFatal:
+        return vfprintf(stderr, format, args);
+      case YGLogLevelWarn:
+      case YGLogLevelInfo:
+      case YGLogLevelDebug:
+      case YGLogLevelVerbose:
+      default:
+        return vprintf(format, args);
+    }
+#endif
+  };
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/debug/Log.h view
@@ -0,0 +1,34 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>
+
+#include <yoga/config/Config.h>
+#include <yoga/enums/LogLevel.h>
+#include <yoga/node/Node.h>
+
+namespace facebook::yoga {
+
+void log(LogLevel level, const char* format, ...) noexcept;
+
+void log(
+    const yoga::Node* node,
+    LogLevel level,
+    const char* message,
+    ...) noexcept;
+
+void log(
+    const yoga::Config* config,
+    LogLevel level,
+    const char* format,
+    ...) noexcept;
+
+YGLogger getDefaultLogger();
+
+} // namespace facebook::yoga
+ yoga/yoga/debug/NodeToString.cpp view
@@ -0,0 +1,210 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#ifdef DEBUG
+
+#include <stdarg.h>
+
+#include <yoga/debug/Log.h>
+#include <yoga/debug/NodeToString.h>
+#include <yoga/numeric/Comparison.h>
+
+namespace facebook::yoga {
+
+static void indent(std::string& base, uint32_t level) {
+  for (uint32_t i = 0; i < level; ++i) {
+    base.append("  ");
+  }
+}
+
+static void appendFormattedString(std::string& str, const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  va_list argsCopy;
+  va_copy(argsCopy, args);
+  std::vector<char> buf(1 + static_cast<size_t>(vsnprintf(NULL, 0, fmt, args)));
+  va_end(args);
+  vsnprintf(buf.data(), buf.size(), fmt, argsCopy);
+  va_end(argsCopy);
+  std::string result = std::string(buf.begin(), buf.end() - 1);
+  str.append(result);
+}
+
+static void appendFloatOptionalIfDefined(
+    std::string& base,
+    const std::string key,
+    const FloatOptional num) {
+  if (num.isDefined()) {
+    appendFormattedString(base, "%s: %g; ", key.c_str(), num.unwrap());
+  }
+}
+
+static void appendNumberIfNotUndefined(
+    std::string& base,
+    const std::string key,
+    const Style::Length& number) {
+  if (number.unit() != Unit::Undefined) {
+    if (number.unit() == Unit::Auto) {
+      base.append(key + ": auto; ");
+    } else {
+      std::string unit = number.unit() == Unit::Point ? "px" : "%%";
+      appendFormattedString(
+          base,
+          "%s: %g%s; ",
+          key.c_str(),
+          number.value().unwrap(),
+          unit.c_str());
+    }
+  }
+}
+
+static void appendNumberIfNotAuto(
+    std::string& base,
+    const std::string& key,
+    const Style::Length& number) {
+  if (number.unit() != Unit::Auto) {
+    appendNumberIfNotUndefined(base, key, number);
+  }
+}
+
+static void appendNumberIfNotZero(
+    std::string& base,
+    const std::string& str,
+    const Style::Length& number) {
+  if (number.unit() == Unit::Auto) {
+    base.append(str + ": auto; ");
+  } else if (!yoga::inexactEquals(number.value().unwrap(), 0)) {
+    appendNumberIfNotUndefined(base, str, number);
+  }
+}
+
+template <auto Field>
+static void
+appendEdges(std::string& base, const std::string& key, const Style& style) {
+  for (auto edge : ordinals<Edge>()) {
+    std::string str = key + "-" + toString(edge);
+    appendNumberIfNotZero(base, str, (style.*Field)(edge));
+  }
+}
+
+void nodeToString(
+    std::string& str,
+    const yoga::Node* node,
+    PrintOptions options,
+    uint32_t level) {
+  indent(str, level);
+  appendFormattedString(str, "<div ");
+
+  if ((options & PrintOptions::Layout) == PrintOptions::Layout) {
+    appendFormattedString(str, "layout=\"");
+    appendFormattedString(
+        str, "width: %g; ", node->getLayout().dimension(Dimension::Width));
+    appendFormattedString(
+        str, "height: %g; ", node->getLayout().dimension(Dimension::Height));
+    appendFormattedString(
+        str, "top: %g; ", node->getLayout().position(Edge::Top));
+    appendFormattedString(
+        str, "left: %g;", node->getLayout().position(Edge::Left));
+    appendFormattedString(str, "\" ");
+  }
+
+  if ((options & PrintOptions::Style) == PrintOptions::Style) {
+    appendFormattedString(str, "style=\"");
+    const auto& style = node->getStyle();
+    if (style.flexDirection() != yoga::Node{}.getStyle().flexDirection()) {
+      appendFormattedString(
+          str, "flex-direction: %s; ", toString(style.flexDirection()));
+    }
+    if (style.justifyContent() != yoga::Node{}.getStyle().justifyContent()) {
+      appendFormattedString(
+          str, "justify-content: %s; ", toString(style.justifyContent()));
+    }
+    if (style.alignItems() != yoga::Node{}.getStyle().alignItems()) {
+      appendFormattedString(
+          str, "align-items: %s; ", toString(style.alignItems()));
+    }
+    if (style.alignContent() != yoga::Node{}.getStyle().alignContent()) {
+      appendFormattedString(
+          str, "align-content: %s; ", toString(style.alignContent()));
+    }
+    if (style.alignSelf() != yoga::Node{}.getStyle().alignSelf()) {
+      appendFormattedString(
+          str, "align-self: %s; ", toString(style.alignSelf()));
+    }
+    appendFloatOptionalIfDefined(str, "flex-grow", style.flexGrow());
+    appendFloatOptionalIfDefined(str, "flex-shrink", style.flexShrink());
+    appendNumberIfNotAuto(str, "flex-basis", style.flexBasis());
+    appendFloatOptionalIfDefined(str, "flex", style.flex());
+
+    if (style.flexWrap() != yoga::Node{}.getStyle().flexWrap()) {
+      appendFormattedString(str, "flex-wrap: %s; ", toString(style.flexWrap()));
+    }
+
+    if (style.overflow() != yoga::Node{}.getStyle().overflow()) {
+      appendFormattedString(str, "overflow: %s; ", toString(style.overflow()));
+    }
+
+    if (style.display() != yoga::Node{}.getStyle().display()) {
+      appendFormattedString(str, "display: %s; ", toString(style.display()));
+    }
+    appendEdges<&Style::margin>(str, "margin", style);
+    appendEdges<&Style::padding>(str, "padding", style);
+    appendEdges<&Style::border>(str, "border", style);
+
+    if (style.gap(Gutter::All).isDefined()) {
+      appendNumberIfNotUndefined(str, "gap", style.gap(Gutter::All));
+    } else {
+      appendNumberIfNotUndefined(str, "column-gap", style.gap(Gutter::Column));
+      appendNumberIfNotUndefined(str, "row-gap", style.gap(Gutter::Row));
+    }
+
+    appendNumberIfNotAuto(str, "width", style.dimension(Dimension::Width));
+    appendNumberIfNotAuto(str, "height", style.dimension(Dimension::Height));
+    appendNumberIfNotAuto(
+        str, "max-width", style.maxDimension(Dimension::Width));
+    appendNumberIfNotAuto(
+        str, "max-height", style.maxDimension(Dimension::Height));
+    appendNumberIfNotAuto(
+        str, "min-width", style.minDimension(Dimension::Width));
+    appendNumberIfNotAuto(
+        str, "min-height", style.minDimension(Dimension::Height));
+
+    if (style.positionType() != yoga::Node{}.getStyle().positionType()) {
+      appendFormattedString(
+          str, "position: %s; ", toString(style.positionType()));
+    }
+
+    appendEdges<&Style::position>(str, "position", style);
+    appendFormattedString(str, "\" ");
+
+    if (node->hasMeasureFunc()) {
+      appendFormattedString(str, "has-custom-measure=\"true\"");
+    }
+  }
+  appendFormattedString(str, ">");
+
+  const size_t childCount = node->getChildCount();
+  if ((options & PrintOptions::Children) == PrintOptions::Children &&
+      childCount > 0) {
+    for (size_t i = 0; i < childCount; i++) {
+      appendFormattedString(str, "\n");
+      nodeToString(str, node->getChild(i), options, level + 1);
+    }
+    appendFormattedString(str, "\n");
+    indent(str, level);
+  }
+  appendFormattedString(str, "</div>");
+}
+
+void print(const yoga::Node* node, PrintOptions options) {
+  std::string str;
+  yoga::nodeToString(str, node, options, 0);
+  yoga::log(node, LogLevel::Debug, str.c_str());
+}
+
+} // namespace facebook::yoga
+#endif
+ yoga/yoga/debug/NodeToString.h view
@@ -0,0 +1,29 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#ifdef DEBUG
+
+#pragma once
+
+#include <string>
+
+#include <yoga/enums/PrintOptions.h>
+#include <yoga/node/Node.h>
+
+namespace facebook::yoga {
+
+void nodeToString(
+    std::string& str,
+    const yoga::Node* node,
+    PrintOptions options,
+    uint32_t level);
+
+void print(const yoga::Node* node, PrintOptions options);
+
+} // namespace facebook::yoga
+
+#endif
+ yoga/yoga/enums/Align.h view
@@ -0,0 +1,47 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class Align : uint8_t {
+  Auto = YGAlignAuto,
+  FlexStart = YGAlignFlexStart,
+  Center = YGAlignCenter,
+  FlexEnd = YGAlignFlexEnd,
+  Stretch = YGAlignStretch,
+  Baseline = YGAlignBaseline,
+  SpaceBetween = YGAlignSpaceBetween,
+  SpaceAround = YGAlignSpaceAround,
+  SpaceEvenly = YGAlignSpaceEvenly,
+};
+
+template <>
+constexpr int32_t ordinalCount<Align>() {
+  return 9;
+}
+
+constexpr Align scopedEnum(YGAlign unscoped) {
+  return static_cast<Align>(unscoped);
+}
+
+constexpr YGAlign unscopedEnum(Align scoped) {
+  return static_cast<YGAlign>(scoped);
+}
+
+inline const char* toString(Align e) {
+  return YGAlignToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/Dimension.h view
@@ -0,0 +1,40 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class Dimension : uint8_t {
+  Width = YGDimensionWidth,
+  Height = YGDimensionHeight,
+};
+
+template <>
+constexpr int32_t ordinalCount<Dimension>() {
+  return 2;
+}
+
+constexpr Dimension scopedEnum(YGDimension unscoped) {
+  return static_cast<Dimension>(unscoped);
+}
+
+constexpr YGDimension unscopedEnum(Dimension scoped) {
+  return static_cast<YGDimension>(scoped);
+}
+
+inline const char* toString(Dimension e) {
+  return YGDimensionToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/Direction.h view
@@ -0,0 +1,41 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class Direction : uint8_t {
+  Inherit = YGDirectionInherit,
+  LTR = YGDirectionLTR,
+  RTL = YGDirectionRTL,
+};
+
+template <>
+constexpr int32_t ordinalCount<Direction>() {
+  return 3;
+}
+
+constexpr Direction scopedEnum(YGDirection unscoped) {
+  return static_cast<Direction>(unscoped);
+}
+
+constexpr YGDirection unscopedEnum(Direction scoped) {
+  return static_cast<YGDirection>(scoped);
+}
+
+inline const char* toString(Direction e) {
+  return YGDirectionToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/Display.h view
@@ -0,0 +1,40 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class Display : uint8_t {
+  Flex = YGDisplayFlex,
+  None = YGDisplayNone,
+};
+
+template <>
+constexpr int32_t ordinalCount<Display>() {
+  return 2;
+}
+
+constexpr Display scopedEnum(YGDisplay unscoped) {
+  return static_cast<Display>(unscoped);
+}
+
+constexpr YGDisplay unscopedEnum(Display scoped) {
+  return static_cast<YGDisplay>(scoped);
+}
+
+inline const char* toString(Display e) {
+  return YGDisplayToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/Edge.h view
@@ -0,0 +1,47 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class Edge : uint8_t {
+  Left = YGEdgeLeft,
+  Top = YGEdgeTop,
+  Right = YGEdgeRight,
+  Bottom = YGEdgeBottom,
+  Start = YGEdgeStart,
+  End = YGEdgeEnd,
+  Horizontal = YGEdgeHorizontal,
+  Vertical = YGEdgeVertical,
+  All = YGEdgeAll,
+};
+
+template <>
+constexpr int32_t ordinalCount<Edge>() {
+  return 9;
+}
+
+constexpr Edge scopedEnum(YGEdge unscoped) {
+  return static_cast<Edge>(unscoped);
+}
+
+constexpr YGEdge unscopedEnum(Edge scoped) {
+  return static_cast<YGEdge>(scoped);
+}
+
+inline const char* toString(Edge e) {
+  return YGEdgeToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/Errata.h view
@@ -0,0 +1,42 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class Errata : uint32_t {
+  None = YGErrataNone,
+  StretchFlexBasis = YGErrataStretchFlexBasis,
+  StartingEndingEdgeFromFlexDirection = YGErrataStartingEndingEdgeFromFlexDirection,
+  PositionStaticBehavesLikeRelative = YGErrataPositionStaticBehavesLikeRelative,
+  AbsolutePositioning = YGErrataAbsolutePositioning,
+  All = YGErrataAll,
+  Classic = YGErrataClassic,
+};
+
+YG_DEFINE_ENUM_FLAG_OPERATORS(Errata)
+
+constexpr Errata scopedEnum(YGErrata unscoped) {
+  return static_cast<Errata>(unscoped);
+}
+
+constexpr YGErrata unscopedEnum(Errata scoped) {
+  return static_cast<YGErrata>(scoped);
+}
+
+inline const char* toString(Errata e) {
+  return YGErrataToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/ExperimentalFeature.h view
@@ -0,0 +1,40 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class ExperimentalFeature : uint8_t {
+  WebFlexBasis = YGExperimentalFeatureWebFlexBasis,
+  AbsolutePercentageAgainstPaddingEdge = YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge,
+};
+
+template <>
+constexpr int32_t ordinalCount<ExperimentalFeature>() {
+  return 2;
+}
+
+constexpr ExperimentalFeature scopedEnum(YGExperimentalFeature unscoped) {
+  return static_cast<ExperimentalFeature>(unscoped);
+}
+
+constexpr YGExperimentalFeature unscopedEnum(ExperimentalFeature scoped) {
+  return static_cast<YGExperimentalFeature>(scoped);
+}
+
+inline const char* toString(ExperimentalFeature e) {
+  return YGExperimentalFeatureToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/FlexDirection.h view
@@ -0,0 +1,42 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class FlexDirection : uint8_t {
+  Column = YGFlexDirectionColumn,
+  ColumnReverse = YGFlexDirectionColumnReverse,
+  Row = YGFlexDirectionRow,
+  RowReverse = YGFlexDirectionRowReverse,
+};
+
+template <>
+constexpr int32_t ordinalCount<FlexDirection>() {
+  return 4;
+}
+
+constexpr FlexDirection scopedEnum(YGFlexDirection unscoped) {
+  return static_cast<FlexDirection>(unscoped);
+}
+
+constexpr YGFlexDirection unscopedEnum(FlexDirection scoped) {
+  return static_cast<YGFlexDirection>(scoped);
+}
+
+inline const char* toString(FlexDirection e) {
+  return YGFlexDirectionToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/Gutter.h view
@@ -0,0 +1,41 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class Gutter : uint8_t {
+  Column = YGGutterColumn,
+  Row = YGGutterRow,
+  All = YGGutterAll,
+};
+
+template <>
+constexpr int32_t ordinalCount<Gutter>() {
+  return 3;
+}
+
+constexpr Gutter scopedEnum(YGGutter unscoped) {
+  return static_cast<Gutter>(unscoped);
+}
+
+constexpr YGGutter unscopedEnum(Gutter scoped) {
+  return static_cast<YGGutter>(scoped);
+}
+
+inline const char* toString(Gutter e) {
+  return YGGutterToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/Justify.h view
@@ -0,0 +1,44 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class Justify : uint8_t {
+  FlexStart = YGJustifyFlexStart,
+  Center = YGJustifyCenter,
+  FlexEnd = YGJustifyFlexEnd,
+  SpaceBetween = YGJustifySpaceBetween,
+  SpaceAround = YGJustifySpaceAround,
+  SpaceEvenly = YGJustifySpaceEvenly,
+};
+
+template <>
+constexpr int32_t ordinalCount<Justify>() {
+  return 6;
+}
+
+constexpr Justify scopedEnum(YGJustify unscoped) {
+  return static_cast<Justify>(unscoped);
+}
+
+constexpr YGJustify unscopedEnum(Justify scoped) {
+  return static_cast<YGJustify>(scoped);
+}
+
+inline const char* toString(Justify e) {
+  return YGJustifyToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/LogLevel.h view
@@ -0,0 +1,44 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class LogLevel : uint8_t {
+  Error = YGLogLevelError,
+  Warn = YGLogLevelWarn,
+  Info = YGLogLevelInfo,
+  Debug = YGLogLevelDebug,
+  Verbose = YGLogLevelVerbose,
+  Fatal = YGLogLevelFatal,
+};
+
+template <>
+constexpr int32_t ordinalCount<LogLevel>() {
+  return 6;
+}
+
+constexpr LogLevel scopedEnum(YGLogLevel unscoped) {
+  return static_cast<LogLevel>(unscoped);
+}
+
+constexpr YGLogLevel unscopedEnum(LogLevel scoped) {
+  return static_cast<YGLogLevel>(scoped);
+}
+
+inline const char* toString(LogLevel e) {
+  return YGLogLevelToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/MeasureMode.h view
@@ -0,0 +1,41 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class MeasureMode : uint8_t {
+  Undefined = YGMeasureModeUndefined,
+  Exactly = YGMeasureModeExactly,
+  AtMost = YGMeasureModeAtMost,
+};
+
+template <>
+constexpr int32_t ordinalCount<MeasureMode>() {
+  return 3;
+}
+
+constexpr MeasureMode scopedEnum(YGMeasureMode unscoped) {
+  return static_cast<MeasureMode>(unscoped);
+}
+
+constexpr YGMeasureMode unscopedEnum(MeasureMode scoped) {
+  return static_cast<YGMeasureMode>(scoped);
+}
+
+inline const char* toString(MeasureMode e) {
+  return YGMeasureModeToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/NodeType.h view
@@ -0,0 +1,40 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class NodeType : uint8_t {
+  Default = YGNodeTypeDefault,
+  Text = YGNodeTypeText,
+};
+
+template <>
+constexpr int32_t ordinalCount<NodeType>() {
+  return 2;
+}
+
+constexpr NodeType scopedEnum(YGNodeType unscoped) {
+  return static_cast<NodeType>(unscoped);
+}
+
+constexpr YGNodeType unscopedEnum(NodeType scoped) {
+  return static_cast<YGNodeType>(scoped);
+}
+
+inline const char* toString(NodeType e) {
+  return YGNodeTypeToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/Overflow.h view
@@ -0,0 +1,41 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class Overflow : uint8_t {
+  Visible = YGOverflowVisible,
+  Hidden = YGOverflowHidden,
+  Scroll = YGOverflowScroll,
+};
+
+template <>
+constexpr int32_t ordinalCount<Overflow>() {
+  return 3;
+}
+
+constexpr Overflow scopedEnum(YGOverflow unscoped) {
+  return static_cast<Overflow>(unscoped);
+}
+
+constexpr YGOverflow unscopedEnum(Overflow scoped) {
+  return static_cast<YGOverflow>(scoped);
+}
+
+inline const char* toString(Overflow e) {
+  return YGOverflowToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/PositionType.h view
@@ -0,0 +1,41 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class PositionType : uint8_t {
+  Static = YGPositionTypeStatic,
+  Relative = YGPositionTypeRelative,
+  Absolute = YGPositionTypeAbsolute,
+};
+
+template <>
+constexpr int32_t ordinalCount<PositionType>() {
+  return 3;
+}
+
+constexpr PositionType scopedEnum(YGPositionType unscoped) {
+  return static_cast<PositionType>(unscoped);
+}
+
+constexpr YGPositionType unscopedEnum(PositionType scoped) {
+  return static_cast<YGPositionType>(scoped);
+}
+
+inline const char* toString(PositionType e) {
+  return YGPositionTypeToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/PrintOptions.h view
@@ -0,0 +1,38 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class PrintOptions : uint32_t {
+  Layout = YGPrintOptionsLayout,
+  Style = YGPrintOptionsStyle,
+  Children = YGPrintOptionsChildren,
+};
+
+YG_DEFINE_ENUM_FLAG_OPERATORS(PrintOptions)
+
+constexpr PrintOptions scopedEnum(YGPrintOptions unscoped) {
+  return static_cast<PrintOptions>(unscoped);
+}
+
+constexpr YGPrintOptions unscopedEnum(PrintOptions scoped) {
+  return static_cast<YGPrintOptions>(scoped);
+}
+
+inline const char* toString(PrintOptions e) {
+  return YGPrintOptionsToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/Unit.h view
@@ -0,0 +1,42 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class Unit : uint8_t {
+  Undefined = YGUnitUndefined,
+  Point = YGUnitPoint,
+  Percent = YGUnitPercent,
+  Auto = YGUnitAuto,
+};
+
+template <>
+constexpr int32_t ordinalCount<Unit>() {
+  return 4;
+}
+
+constexpr Unit scopedEnum(YGUnit unscoped) {
+  return static_cast<Unit>(unscoped);
+}
+
+constexpr YGUnit unscopedEnum(Unit scoped) {
+  return static_cast<YGUnit>(scoped);
+}
+
+inline const char* toString(Unit e) {
+  return YGUnitToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/Wrap.h view
@@ -0,0 +1,41 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @generated by enums.py
+// clang-format off
+#pragma once
+
+#include <cstdint>
+#include <yoga/YGEnums.h>
+#include <yoga/enums/YogaEnums.h>
+
+namespace facebook::yoga {
+
+enum class Wrap : uint8_t {
+  NoWrap = YGWrapNoWrap,
+  Wrap = YGWrapWrap,
+  WrapReverse = YGWrapWrapReverse,
+};
+
+template <>
+constexpr int32_t ordinalCount<Wrap>() {
+  return 3;
+}
+
+constexpr Wrap scopedEnum(YGWrap unscoped) {
+  return static_cast<Wrap>(unscoped);
+}
+
+constexpr YGWrap unscopedEnum(Wrap scoped) {
+  return static_cast<YGWrap>(scoped);
+}
+
+inline const char* toString(Wrap e) {
+  return YGWrapToString(unscopedEnum(e));
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/enums/YogaEnums.h view
@@ -0,0 +1,85 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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 <bit>
+#include <iterator>
+#include <type_traits>
+
+namespace facebook::yoga {
+
+/**
+ * Concept for any enum/enum class
+ */
+template <typename EnumT>
+concept Enumeration = std::is_enum_v<EnumT>;
+
+/**
+ * Count of ordinals in a Yoga enum which is sequential
+ */
+template <Enumeration EnumT>
+constexpr int32_t ordinalCount();
+
+/**
+ * Concept for a yoga enum which is sequential
+ */
+template <typename EnumT>
+concept HasOrdinality = (ordinalCount<EnumT>() > 0);
+
+/**
+ * Count of bits needed to represent every ordinal
+ */
+template <HasOrdinality EnumT>
+constexpr int32_t bitCount() {
+  return std::bit_width(
+      static_cast<std::underlying_type_t<EnumT>>(ordinalCount<EnumT>() - 1));
+}
+
+/**
+ * Polyfill of C++ 23 to_underlying()
+ * https://en.cppreference.com/w/cpp/utility/to_underlying
+ */
+constexpr auto to_underlying(Enumeration auto e) noexcept {
+  return static_cast<std::underlying_type_t<decltype(e)>>(e);
+}
+
+/**
+ * Convenience function to iterate through every value in a Yoga enum as part of
+ * a range-based for loop.
+ */
+template <HasOrdinality EnumT>
+auto ordinals() {
+  struct Iterator {
+    EnumT e{};
+
+    EnumT operator*() const {
+      return e;
+    }
+
+    Iterator& operator++() {
+      e = static_cast<EnumT>(to_underlying(e) + 1);
+      return *this;
+    }
+
+    bool operator==(const Iterator& other) const = default;
+    bool operator!=(const Iterator& other) const = default;
+  };
+
+  struct Range {
+    Iterator begin() const {
+      return Iterator{};
+    }
+    Iterator end() const {
+      return Iterator{static_cast<EnumT>(ordinalCount<EnumT>())};
+    }
+  };
+
+  return Range{};
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/event/event.cpp view
@@ -0,0 +1,87 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include "event.h"
+#include <atomic>
+#include <memory>
+
+namespace facebook::yoga {
+
+const char* LayoutPassReasonToString(const LayoutPassReason value) {
+  switch (value) {
+    case LayoutPassReason::kInitial:
+      return "initial";
+    case LayoutPassReason::kAbsLayout:
+      return "abs_layout";
+    case LayoutPassReason::kStretch:
+      return "stretch";
+    case LayoutPassReason::kMultilineStretch:
+      return "multiline_stretch";
+    case LayoutPassReason::kFlexLayout:
+      return "flex_layout";
+    case LayoutPassReason::kMeasureChild:
+      return "measure";
+    case LayoutPassReason::kAbsMeasureChild:
+      return "abs_measure";
+    case LayoutPassReason::kFlexMeasure:
+      return "flex_measure";
+    default:
+      return "unknown";
+  }
+}
+
+namespace {
+
+struct Node {
+  std::function<Event::Subscriber> subscriber = nullptr;
+  Node* next = nullptr;
+
+  Node(std::function<Event::Subscriber>&& subscriber)
+      : subscriber{std::move(subscriber)} {}
+};
+
+std::atomic<Node*> subscribers{nullptr};
+
+Node* push(Node* newHead) {
+  Node* oldHead;
+  do {
+    oldHead = subscribers.load(std::memory_order_relaxed);
+    if (newHead != nullptr) {
+      newHead->next = oldHead;
+    }
+  } while (!subscribers.compare_exchange_weak(
+      oldHead, newHead, std::memory_order_release, std::memory_order_relaxed));
+  return oldHead;
+}
+
+} // namespace
+
+void Event::reset() {
+  auto head = push(nullptr);
+  while (head != nullptr) {
+    auto current = head;
+    head = head->next;
+    delete current;
+  }
+}
+
+void Event::subscribe(std::function<Subscriber>&& subscriber) {
+  push(new Node{std::move(subscriber)});
+}
+
+void Event::publish(
+    YGNodeConstRef node,
+    Type eventType,
+    const Data& eventData) {
+  for (auto subscriber = subscribers.load(std::memory_order_relaxed);
+       subscriber != nullptr;
+       subscriber = subscriber->next) {
+    subscriber->subscriber(node, eventType, eventData);
+  }
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/event/event.h view
@@ -0,0 +1,127 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/Yoga.h>
+
+#include <stdint.h>
+#include <array>
+#include <functional>
+#include <vector>
+
+namespace facebook::yoga {
+
+enum struct LayoutType : int {
+  kLayout = 0,
+  kMeasure = 1,
+  kCachedLayout = 2,
+  kCachedMeasure = 3
+};
+
+enum struct LayoutPassReason : int {
+  kInitial = 0,
+  kAbsLayout = 1,
+  kStretch = 2,
+  kMultilineStretch = 3,
+  kFlexLayout = 4,
+  kMeasureChild = 5,
+  kAbsMeasureChild = 6,
+  kFlexMeasure = 7,
+  COUNT
+};
+
+struct LayoutData {
+  int layouts;
+  int measures;
+  uint32_t maxMeasureCache;
+  int cachedLayouts;
+  int cachedMeasures;
+  int measureCallbacks;
+  std::array<int, static_cast<uint8_t>(LayoutPassReason::COUNT)>
+      measureCallbackReasonsCount;
+};
+
+const char* LayoutPassReasonToString(const LayoutPassReason value);
+
+struct YG_EXPORT Event {
+  enum Type {
+    NodeAllocation,
+    NodeDeallocation,
+    NodeLayout,
+    LayoutPassStart,
+    LayoutPassEnd,
+    MeasureCallbackStart,
+    MeasureCallbackEnd,
+    NodeBaselineStart,
+    NodeBaselineEnd,
+  };
+  class Data;
+  using Subscriber = void(YGNodeConstRef, Type, Data);
+  using Subscribers = std::vector<std::function<Subscriber>>;
+
+  template <Type E>
+  struct TypedData {};
+
+  class Data {
+    const void* data_;
+
+   public:
+    template <Type E>
+    Data(const TypedData<E>& data) : data_{&data} {}
+
+    template <Type E>
+    const TypedData<E>& get() const {
+      return *static_cast<const TypedData<E>*>(data_);
+    }
+  };
+
+  static void reset();
+
+  static void subscribe(std::function<Subscriber>&& subscriber);
+
+  template <Type E>
+  static void publish(YGNodeConstRef node, const TypedData<E>& eventData = {}) {
+    publish(node, E, Data{eventData});
+  }
+
+ private:
+  static void publish(YGNodeConstRef, Type, const Data&);
+};
+
+template <>
+struct Event::TypedData<Event::NodeAllocation> {
+  YGConfigConstRef config;
+};
+
+template <>
+struct Event::TypedData<Event::NodeDeallocation> {
+  YGConfigConstRef config;
+};
+
+template <>
+struct Event::TypedData<Event::LayoutPassEnd> {
+  LayoutData* layoutData;
+};
+
+template <>
+struct Event::TypedData<Event::MeasureCallbackEnd> {
+  float width;
+  YGMeasureMode widthMeasureMode;
+  float height;
+  YGMeasureMode heightMeasureMode;
+  float measuredWidth;
+  float measuredHeight;
+  const LayoutPassReason reason;
+};
+
+template <>
+struct Event::TypedData<Event::NodeLayout> {
+  LayoutType layoutType;
+};
+
+} // namespace facebook::yoga
+ yoga/yoga/node/CachedMeasurement.h view
@@ -0,0 +1,53 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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 <cmath>
+
+#include <yoga/Yoga.h>
+
+#include <yoga/algorithm/SizingMode.h>
+#include <yoga/numeric/Comparison.h>
+
+namespace facebook::yoga {
+
+struct CachedMeasurement {
+  float availableWidth{-1};
+  float availableHeight{-1};
+  SizingMode widthSizingMode{SizingMode::MaxContent};
+  SizingMode heightSizingMode{SizingMode::MaxContent};
+
+  float computedWidth{-1};
+  float computedHeight{-1};
+
+  bool operator==(CachedMeasurement measurement) const {
+    bool isEqual = widthSizingMode == measurement.widthSizingMode &&
+        heightSizingMode == measurement.heightSizingMode;
+
+    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;
+  }
+};
+
+} // namespace facebook::yoga
+ yoga/yoga/node/LayoutResults.cpp view
@@ -0,0 +1,47 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <cmath>
+
+#include <yoga/node/LayoutResults.h>
+#include <yoga/numeric/Comparison.h>
+
+namespace facebook::yoga {
+
+bool LayoutResults::operator==(LayoutResults layout) const {
+  bool isEqual = yoga::inexactEquals(position_, layout.position_) &&
+      yoga::inexactEquals(dimensions_, layout.dimensions_) &&
+      yoga::inexactEquals(margin_, layout.margin_) &&
+      yoga::inexactEquals(border_, layout.border_) &&
+      yoga::inexactEquals(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 < LayoutResults::MaxCachedMeasurements && 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;
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/node/LayoutResults.h view
@@ -0,0 +1,133 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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 <array>
+
+#include <yoga/debug/AssertFatal.h>
+#include <yoga/enums/Dimension.h>
+#include <yoga/enums/Direction.h>
+#include <yoga/enums/Edge.h>
+#include <yoga/node/CachedMeasurement.h>
+#include <yoga/numeric/FloatOptional.h>
+
+namespace facebook::yoga {
+
+struct LayoutResults {
+  // This value was chosen based on empirical data:
+  // 98% of analyzed layouts require less than 8 entries.
+  static constexpr int32_t MaxCachedMeasurements = 8;
+
+  uint32_t computedFlexBasisGeneration = 0;
+  FloatOptional computedFlexBasis = {};
+
+  // Instead of recomputing the entire layout every single time, we cache some
+  // information to break early when nothing changed
+  uint32_t generationCount = 0;
+  Direction lastOwnerDirection = Direction::Inherit;
+
+  uint32_t nextCachedMeasurementsIndex = 0;
+  std::array<CachedMeasurement, MaxCachedMeasurements> cachedMeasurements = {};
+
+  CachedMeasurement cachedLayout{};
+
+  Direction direction() const {
+    return direction_;
+  }
+
+  void setDirection(Direction direction) {
+    direction_ = direction;
+  }
+
+  bool hadOverflow() const {
+    return hadOverflow_;
+  }
+
+  void setHadOverflow(bool hadOverflow) {
+    hadOverflow_ = hadOverflow;
+  }
+
+  float dimension(Dimension axis) const {
+    return dimensions_[yoga::to_underlying(axis)];
+  }
+
+  void setDimension(Dimension axis, float dimension) {
+    dimensions_[yoga::to_underlying(axis)] = dimension;
+  }
+
+  float measuredDimension(Dimension axis) const {
+    return measuredDimensions_[yoga::to_underlying(axis)];
+  }
+
+  void setMeasuredDimension(Dimension axis, float dimension) {
+    measuredDimensions_[yoga::to_underlying(axis)] = dimension;
+  }
+
+  float position(Edge cardinalEdge) const {
+    assertCardinalEdge(cardinalEdge);
+    return position_[yoga::to_underlying(cardinalEdge)];
+  }
+
+  void setPosition(Edge cardinalEdge, float dimension) {
+    assertCardinalEdge(cardinalEdge);
+    position_[yoga::to_underlying(cardinalEdge)] = dimension;
+  }
+
+  float margin(Edge cardinalEdge) const {
+    assertCardinalEdge(cardinalEdge);
+    return margin_[yoga::to_underlying(cardinalEdge)];
+  }
+
+  void setMargin(Edge cardinalEdge, float dimension) {
+    assertCardinalEdge(cardinalEdge);
+    margin_[yoga::to_underlying(cardinalEdge)] = dimension;
+  }
+
+  float border(Edge cardinalEdge) const {
+    assertCardinalEdge(cardinalEdge);
+    return border_[yoga::to_underlying(cardinalEdge)];
+  }
+
+  void setBorder(Edge cardinalEdge, float dimension) {
+    assertCardinalEdge(cardinalEdge);
+    border_[yoga::to_underlying(cardinalEdge)] = dimension;
+  }
+
+  float padding(Edge cardinalEdge) const {
+    assertCardinalEdge(cardinalEdge);
+    return padding_[yoga::to_underlying(cardinalEdge)];
+  }
+
+  void setPadding(Edge cardinalEdge, float dimension) {
+    assertCardinalEdge(cardinalEdge);
+    padding_[yoga::to_underlying(cardinalEdge)] = dimension;
+  }
+
+  bool operator==(LayoutResults layout) const;
+  bool operator!=(LayoutResults layout) const {
+    return !(*this == layout);
+  }
+
+ private:
+  static inline void assertCardinalEdge(Edge edge) {
+    assertFatal(
+        static_cast<int>(edge) <= 3, "Edge must be top/left/bottom/right");
+  }
+
+  Direction direction_ : bitCount<Direction>() = Direction::Inherit;
+  bool hadOverflow_ : 1 = false;
+
+  std::array<float, 2> dimensions_ = {{YGUndefined, YGUndefined}};
+  std::array<float, 2> measuredDimensions_ = {{YGUndefined, YGUndefined}};
+  std::array<float, 4> position_ = {};
+  std::array<float, 4> margin_ = {};
+  std::array<float, 4> border_ = {};
+  std::array<float, 4> padding_ = {};
+};
+
+} // namespace facebook::yoga
+ yoga/yoga/node/Node.cpp view
@@ -0,0 +1,730 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <algorithm>
+#include <cstddef>
+#include <iostream>
+
+#include <yoga/algorithm/FlexDirection.h>
+#include <yoga/debug/AssertFatal.h>
+#include <yoga/node/Node.h>
+#include <yoga/numeric/Comparison.h>
+
+namespace facebook::yoga {
+
+Node::Node() : Node{&Config::getDefault()} {}
+
+Node::Node(const yoga::Config* config) : config_{config} {
+  yoga::assertFatal(
+      config != nullptr, "Attempting to construct Node with null config");
+
+  if (config->useWebDefaults()) {
+    useWebDefaults();
+  }
+}
+
+Node::Node(Node&& node) {
+  hasNewLayout_ = node.hasNewLayout_;
+  isReferenceBaseline_ = node.isReferenceBaseline_;
+  isDirty_ = node.isDirty_;
+  nodeType_ = node.nodeType_;
+  context_ = node.context_;
+  measureFunc_ = node.measureFunc_;
+  baselineFunc_ = node.baselineFunc_;
+  printFunc_ = node.printFunc_;
+  dirtiedFunc_ = node.dirtiedFunc_;
+  style_ = node.style_;
+  layout_ = node.layout_;
+  lineIndex_ = node.lineIndex_;
+  owner_ = node.owner_;
+  children_ = std::move(node.children_);
+  config_ = node.config_;
+  resolvedDimensions_ = node.resolvedDimensions_;
+  for (auto c : children_) {
+    c->setOwner(this);
+  }
+}
+
+void Node::print() {
+  if (printFunc_ != nullptr) {
+    printFunc_(this);
+  }
+}
+
+// TODO: Edge value resolution should be moved to `yoga::Style`
+template <auto Field>
+Style::Length Node::computeEdgeValueForRow(Edge rowEdge, Edge edge) const {
+  if ((style_.*Field)(rowEdge).isDefined()) {
+    return (style_.*Field)(rowEdge);
+  } else if ((style_.*Field)(edge).isDefined()) {
+    return (style_.*Field)(edge);
+  } else if ((style_.*Field)(Edge::Horizontal).isDefined()) {
+    return (style_.*Field)(Edge::Horizontal);
+  } else {
+    return (style_.*Field)(Edge::All);
+  }
+}
+
+// TODO: Edge value resolution should be moved to `yoga::Style`
+template <auto Field>
+Style::Length Node::computeEdgeValueForColumn(Edge edge) const {
+  if ((style_.*Field)(edge).isDefined()) {
+    return (style_.*Field)(edge);
+  } else if ((style_.*Field)(Edge::Vertical).isDefined()) {
+    return (style_.*Field)(Edge::Vertical);
+  } else {
+    return (style_.*Field)(Edge::All);
+  }
+}
+
+Edge Node::getInlineStartEdgeUsingErrata(
+    FlexDirection flexDirection,
+    Direction direction) const {
+  return hasErrata(Errata::StartingEndingEdgeFromFlexDirection)
+      ? flexStartEdge(flexDirection)
+      : inlineStartEdge(flexDirection, direction);
+}
+
+Edge Node::getInlineEndEdgeUsingErrata(
+    FlexDirection flexDirection,
+    Direction direction) const {
+  return hasErrata(Errata::StartingEndingEdgeFromFlexDirection)
+      ? flexEndEdge(flexDirection)
+      : inlineEndEdge(flexDirection, direction);
+}
+
+Edge Node::getFlexStartRelativeEdgeUsingErrata(
+    FlexDirection flexDirection,
+    Direction direction) const {
+  return hasErrata(Errata::StartingEndingEdgeFromFlexDirection)
+      ? Edge::Start
+      : flexStartRelativeEdge(flexDirection, direction);
+}
+
+Edge Node::getFlexEndRelativeEdgeUsingErrata(
+    FlexDirection flexDirection,
+    Direction direction) const {
+  return hasErrata(Errata::StartingEndingEdgeFromFlexDirection)
+      ? Edge::End
+      : flexEndRelativeEdge(flexDirection, direction);
+}
+
+bool Node::isFlexStartPositionDefined(FlexDirection axis, Direction direction)
+    const {
+  auto leadingPosition = isRow(axis)
+      ? computeEdgeValueForRow<&Style::position>(
+            getFlexStartRelativeEdgeUsingErrata(axis, direction),
+            flexStartEdge(axis))
+      : computeEdgeValueForColumn<&Style::position>(flexStartEdge(axis));
+
+  return leadingPosition.isDefined();
+}
+
+bool Node::isInlineStartPositionDefined(FlexDirection axis, Direction direction)
+    const {
+  Edge startEdge = getInlineStartEdgeUsingErrata(axis, direction);
+  Style::Length leadingPosition = isRow(axis)
+      ? computeEdgeValueForRow<&Style::position>(Edge::Start, startEdge)
+      : computeEdgeValueForColumn<&Style::position>(startEdge);
+
+  return leadingPosition.isDefined();
+}
+
+bool Node::isFlexEndPositionDefined(FlexDirection axis, Direction direction)
+    const {
+  auto trailingPosition = isRow(axis)
+      ? computeEdgeValueForRow<&Style::position>(
+            getFlexEndRelativeEdgeUsingErrata(axis, direction),
+            flexEndEdge(axis))
+      : computeEdgeValueForColumn<&Style::position>(flexEndEdge(axis));
+
+  return !trailingPosition.isUndefined();
+}
+
+bool Node::isInlineEndPositionDefined(FlexDirection axis, Direction direction)
+    const {
+  Edge endEdge = getInlineEndEdgeUsingErrata(axis, direction);
+  Style::Length trailingPosition = isRow(axis)
+      ? computeEdgeValueForRow<&Style::position>(Edge::End, endEdge)
+      : computeEdgeValueForColumn<&Style::position>(endEdge);
+
+  return trailingPosition.isDefined();
+}
+
+float Node::getFlexStartPosition(
+    FlexDirection axis,
+    Direction direction,
+    float axisSize) const {
+  auto leadingPosition = isRow(axis)
+      ? computeEdgeValueForRow<&Style::position>(
+            getFlexStartRelativeEdgeUsingErrata(axis, direction),
+            flexStartEdge(axis))
+      : computeEdgeValueForColumn<&Style::position>(flexStartEdge(axis));
+
+  return leadingPosition.resolve(axisSize).unwrapOrDefault(0.0f);
+}
+
+float Node::getInlineStartPosition(
+    FlexDirection axis,
+    Direction direction,
+    float axisSize) const {
+  Edge startEdge = getInlineStartEdgeUsingErrata(axis, direction);
+  Style::Length leadingPosition = isRow(axis)
+      ? computeEdgeValueForRow<&Style::position>(Edge::Start, startEdge)
+      : computeEdgeValueForColumn<&Style::position>(startEdge);
+
+  return leadingPosition.resolve(axisSize).unwrapOrDefault(0.0f);
+}
+
+float Node::getFlexEndPosition(
+    FlexDirection axis,
+    Direction direction,
+    float axisSize) const {
+  auto trailingPosition = isRow(axis)
+      ? computeEdgeValueForRow<&Style::position>(
+            getFlexEndRelativeEdgeUsingErrata(axis, direction),
+            flexEndEdge(axis))
+      : computeEdgeValueForColumn<&Style::position>(flexEndEdge(axis));
+
+  return trailingPosition.resolve(axisSize).unwrapOrDefault(0.0f);
+}
+
+float Node::getInlineEndPosition(
+    FlexDirection axis,
+    Direction direction,
+    float axisSize) const {
+  Edge endEdge = getInlineEndEdgeUsingErrata(axis, direction);
+  Style::Length trailingPosition = isRow(axis)
+      ? computeEdgeValueForRow<&Style::position>(Edge::End, endEdge)
+      : computeEdgeValueForColumn<&Style::position>(endEdge);
+
+  return trailingPosition.resolve(axisSize).unwrapOrDefault(0.0f);
+}
+
+float Node::getFlexStartMargin(
+    FlexDirection axis,
+    Direction direction,
+    float widthSize) const {
+  auto leadingMargin = isRow(axis)
+      ? computeEdgeValueForRow<&Style::margin>(
+            getFlexStartRelativeEdgeUsingErrata(axis, direction),
+            flexStartEdge(axis))
+      : computeEdgeValueForColumn<&Style::margin>(flexStartEdge(axis));
+
+  return leadingMargin.resolve(widthSize).unwrapOrDefault(0.0f);
+}
+
+float Node::getInlineStartMargin(
+    FlexDirection axis,
+    Direction direction,
+    float widthSize) const {
+  Edge startEdge = getInlineStartEdgeUsingErrata(axis, direction);
+  Style::Length leadingMargin = isRow(axis)
+      ? computeEdgeValueForRow<&Style::margin>(Edge::Start, startEdge)
+      : computeEdgeValueForColumn<&Style::margin>(startEdge);
+
+  return leadingMargin.resolve(widthSize).unwrapOrDefault(0.0f);
+}
+
+float Node::getFlexEndMargin(
+    FlexDirection axis,
+    Direction direction,
+    float widthSize) const {
+  auto trailingMargin = isRow(axis)
+      ? computeEdgeValueForRow<&Style::margin>(
+            getFlexEndRelativeEdgeUsingErrata(axis, direction),
+            flexEndEdge(axis))
+      : computeEdgeValueForColumn<&Style::margin>(flexEndEdge(axis));
+
+  return trailingMargin.resolve(widthSize).unwrapOrDefault(0.0f);
+}
+
+float Node::getInlineEndMargin(
+    FlexDirection axis,
+    Direction direction,
+    float widthSize) const {
+  Edge endEdge = getInlineEndEdgeUsingErrata(axis, direction);
+  Style::Length trailingMargin = isRow(axis)
+      ? computeEdgeValueForRow<&Style::margin>(Edge::End, endEdge)
+      : computeEdgeValueForColumn<&Style::margin>(endEdge);
+
+  return trailingMargin.resolve(widthSize).unwrapOrDefault(0.0f);
+}
+
+float Node::getInlineStartBorder(FlexDirection axis, Direction direction)
+    const {
+  Edge startEdge = getInlineStartEdgeUsingErrata(axis, direction);
+  Style::Length leadingBorder = isRow(axis)
+      ? computeEdgeValueForRow<&Style::border>(Edge::Start, startEdge)
+      : computeEdgeValueForColumn<&Style::border>(startEdge);
+
+  return maxOrDefined(leadingBorder.value().unwrap(), 0.0f);
+}
+
+float Node::getFlexStartBorder(FlexDirection axis, Direction direction) const {
+  Style::Length leadingBorder = isRow(axis)
+      ? computeEdgeValueForRow<&Style::border>(
+            getFlexStartRelativeEdgeUsingErrata(axis, direction),
+            flexStartEdge(axis))
+      : computeEdgeValueForColumn<&Style::border>(flexStartEdge(axis));
+
+  return maxOrDefined(leadingBorder.value().unwrap(), 0.0f);
+}
+
+float Node::getInlineEndBorder(FlexDirection axis, Direction direction) const {
+  Edge endEdge = getInlineEndEdgeUsingErrata(axis, direction);
+  Style::Length trailingBorder = isRow(axis)
+      ? computeEdgeValueForRow<&Style::border>(Edge::End, endEdge)
+      : computeEdgeValueForColumn<&Style::border>(endEdge);
+
+  return maxOrDefined(trailingBorder.value().unwrap(), 0.0f);
+}
+
+float Node::getFlexEndBorder(FlexDirection axis, Direction direction) const {
+  Style::Length trailingBorder = isRow(axis)
+      ? computeEdgeValueForRow<&Style::border>(
+            getFlexEndRelativeEdgeUsingErrata(axis, direction),
+            flexEndEdge(axis))
+      : computeEdgeValueForColumn<&Style::border>(flexEndEdge(axis));
+
+  return maxOrDefined(trailingBorder.value().unwrap(), 0.0f);
+}
+
+float Node::getInlineStartPadding(
+    FlexDirection axis,
+    Direction direction,
+    float widthSize) const {
+  Edge startEdge = getInlineStartEdgeUsingErrata(axis, direction);
+  Style::Length leadingPadding = isRow(axis)
+      ? computeEdgeValueForRow<&Style::padding>(Edge::Start, startEdge)
+      : computeEdgeValueForColumn<&Style::padding>(startEdge);
+
+  return maxOrDefined(leadingPadding.resolve(widthSize).unwrap(), 0.0f);
+}
+
+float Node::getFlexStartPadding(
+    FlexDirection axis,
+    Direction direction,
+    float widthSize) const {
+  auto leadingPadding = isRow(axis)
+      ? computeEdgeValueForRow<&Style::padding>(
+            getFlexStartRelativeEdgeUsingErrata(axis, direction),
+            flexStartEdge(axis))
+      : computeEdgeValueForColumn<&Style::padding>(flexStartEdge(axis));
+
+  return maxOrDefined(leadingPadding.resolve(widthSize).unwrap(), 0.0f);
+}
+
+float Node::getInlineEndPadding(
+    FlexDirection axis,
+    Direction direction,
+    float widthSize) const {
+  Edge endEdge = getInlineEndEdgeUsingErrata(axis, direction);
+  Style::Length trailingPadding = isRow(axis)
+      ? computeEdgeValueForRow<&Style::padding>(Edge::End, endEdge)
+      : computeEdgeValueForColumn<&Style::padding>(endEdge);
+
+  return maxOrDefined(trailingPadding.resolve(widthSize).unwrap(), 0.0f);
+}
+
+float Node::getFlexEndPadding(
+    FlexDirection axis,
+    Direction direction,
+    float widthSize) const {
+  auto trailingPadding = isRow(axis)
+      ? computeEdgeValueForRow<&Style::padding>(
+            getFlexEndRelativeEdgeUsingErrata(axis, direction),
+            flexEndEdge(axis))
+      : computeEdgeValueForColumn<&Style::padding>(flexEndEdge(axis));
+
+  return maxOrDefined(trailingPadding.resolve(widthSize).unwrap(), 0.0f);
+}
+
+float Node::getInlineStartPaddingAndBorder(
+    FlexDirection axis,
+    Direction direction,
+    float widthSize) const {
+  return getInlineStartPadding(axis, direction, widthSize) +
+      getInlineStartBorder(axis, direction);
+}
+
+float Node::getFlexStartPaddingAndBorder(
+    FlexDirection axis,
+    Direction direction,
+    float widthSize) const {
+  return getFlexStartPadding(axis, direction, widthSize) +
+      getFlexStartBorder(axis, direction);
+}
+
+float Node::getInlineEndPaddingAndBorder(
+    FlexDirection axis,
+    Direction direction,
+    float widthSize) const {
+  return getInlineEndPadding(axis, direction, widthSize) +
+      getInlineEndBorder(axis, direction);
+}
+
+float Node::getFlexEndPaddingAndBorder(
+    FlexDirection axis,
+    Direction direction,
+    float widthSize) const {
+  return getFlexEndPadding(axis, direction, widthSize) +
+      getFlexEndBorder(axis, direction);
+}
+
+float Node::getBorderForAxis(FlexDirection axis) const {
+  return getInlineStartBorder(axis, Direction::LTR) +
+      getInlineEndBorder(axis, Direction::LTR);
+}
+
+float Node::getMarginForAxis(FlexDirection axis, float widthSize) const {
+  // The total margin for a given axis does not depend on the direction
+  // so hardcoding LTR here to avoid piping direction to this function
+  return getInlineStartMargin(axis, Direction::LTR, widthSize) +
+      getInlineEndMargin(axis, Direction::LTR, widthSize);
+}
+
+float Node::getGapForAxis(FlexDirection axis) const {
+  auto gap = isRow(axis) ? style_.resolveColumnGap() : style_.resolveRowGap();
+  // TODO: Validate percentage gap, and expose ability to set percentage to
+  // public API
+  return maxOrDefined(gap.resolve(0.0f /*ownerSize*/).unwrap(), 0.0f);
+}
+
+YGSize Node::measure(
+    float width,
+    MeasureMode widthMode,
+    float height,
+    MeasureMode heightMode) {
+  return measureFunc_(
+      this, width, unscopedEnum(widthMode), height, unscopedEnum(heightMode));
+}
+
+float Node::baseline(float width, float height) const {
+  return baselineFunc_(this, width, height);
+}
+
+float Node::dimensionWithMargin(
+    const FlexDirection axis,
+    const float widthSize) {
+  return getLayout().measuredDimension(dimension(axis)) +
+      getMarginForAxis(axis, widthSize);
+}
+
+bool Node::isLayoutDimensionDefined(const FlexDirection axis) {
+  const float value = getLayout().measuredDimension(dimension(axis));
+  return yoga::isDefined(value) && value >= 0.0f;
+}
+
+// Setters
+
+void Node::setMeasureFunc(YGMeasureFunc measureFunc) {
+  if (measureFunc == nullptr) {
+    // TODO: t18095186 Move nodeType to opt-in function and mark appropriate
+    // places in Litho
+    setNodeType(NodeType::Default);
+  } else {
+    yoga::assertFatalWithNode(
+        this,
+        children_.size() == 0,
+        "Cannot set measure function: Nodes with measure functions cannot have "
+        "children.");
+    // TODO: t18095186 Move nodeType to opt-in function and mark appropriate
+    // places in Litho
+    setNodeType(NodeType::Text);
+  }
+
+  measureFunc_ = measureFunc;
+}
+
+void Node::replaceChild(Node* child, size_t index) {
+  children_[index] = child;
+}
+
+void Node::replaceChild(Node* oldChild, Node* newChild) {
+  std::replace(children_.begin(), children_.end(), oldChild, newChild);
+}
+
+void Node::insertChild(Node* child, size_t index) {
+  children_.insert(children_.begin() + static_cast<ptrdiff_t>(index), child);
+}
+
+void Node::setConfig(yoga::Config* config) {
+  yoga::assertFatal(
+      config != nullptr, "Attempting to set a null config on a Node");
+  yoga::assertFatalWithConfig(
+      config,
+      config->useWebDefaults() == config_->useWebDefaults(),
+      "UseWebDefaults may not be changed after constructing a Node");
+
+  if (yoga::configUpdateInvalidatesLayout(*config_, *config)) {
+    markDirtyAndPropagate();
+  }
+
+  config_ = config;
+}
+
+void Node::setDirty(bool isDirty) {
+  if (isDirty == isDirty_) {
+    return;
+  }
+  isDirty_ = isDirty;
+  if (isDirty && dirtiedFunc_) {
+    dirtiedFunc_(this);
+  }
+}
+
+bool Node::removeChild(Node* child) {
+  std::vector<Node*>::iterator p =
+      std::find(children_.begin(), children_.end(), child);
+  if (p != children_.end()) {
+    children_.erase(p);
+    return true;
+  }
+  return false;
+}
+
+void Node::removeChild(size_t index) {
+  children_.erase(children_.begin() + static_cast<ptrdiff_t>(index));
+}
+
+void Node::setLayoutDirection(Direction direction) {
+  layout_.setDirection(direction);
+}
+
+void Node::setLayoutMargin(float margin, Edge edge) {
+  layout_.setMargin(edge, margin);
+}
+
+void Node::setLayoutBorder(float border, Edge edge) {
+  layout_.setBorder(edge, border);
+}
+
+void Node::setLayoutPadding(float padding, Edge edge) {
+  layout_.setPadding(edge, padding);
+}
+
+void Node::setLayoutLastOwnerDirection(Direction direction) {
+  layout_.lastOwnerDirection = direction;
+}
+
+void Node::setLayoutComputedFlexBasis(const FloatOptional computedFlexBasis) {
+  layout_.computedFlexBasis = computedFlexBasis;
+}
+
+void Node::setLayoutPosition(float position, Edge edge) {
+  layout_.setPosition(edge, position);
+}
+
+void Node::setLayoutComputedFlexBasisGeneration(
+    uint32_t computedFlexBasisGeneration) {
+  layout_.computedFlexBasisGeneration = computedFlexBasisGeneration;
+}
+
+void Node::setLayoutMeasuredDimension(
+    float measuredDimension,
+    Dimension dimension) {
+  layout_.setMeasuredDimension(dimension, measuredDimension);
+}
+
+void Node::setLayoutHadOverflow(bool hadOverflow) {
+  layout_.setHadOverflow(hadOverflow);
+}
+
+void Node::setLayoutDimension(float LengthValue, Dimension dimension) {
+  layout_.setDimension(dimension, LengthValue);
+}
+
+// If both left and right are defined, then use left. Otherwise return +left or
+// -right depending on which is defined. Ignore statically positioned nodes as
+// insets do not apply to them.
+float Node::relativePosition(
+    FlexDirection axis,
+    Direction direction,
+    float axisSize) const {
+  if (style_.positionType() == PositionType::Static &&
+      !hasErrata(Errata::PositionStaticBehavesLikeRelative)) {
+    return 0;
+  }
+  if (isInlineStartPositionDefined(axis, direction)) {
+    return getInlineStartPosition(axis, direction, axisSize);
+  }
+
+  return -1 * getInlineEndPosition(axis, direction, axisSize);
+}
+
+void Node::setPosition(
+    const Direction 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 Direction directionRespectingRoot =
+      owner_ != nullptr ? direction : Direction::LTR;
+  const FlexDirection mainAxis =
+      yoga::resolveDirection(style_.flexDirection(), directionRespectingRoot);
+  const FlexDirection crossAxis =
+      yoga::resolveCrossDirection(mainAxis, directionRespectingRoot);
+
+  // In the case of position static these are just 0. See:
+  // https://www.w3.org/TR/css-position-3/#valdef-position-static
+  const float relativePositionMain =
+      relativePosition(mainAxis, directionRespectingRoot, mainSize);
+  const float relativePositionCross =
+      relativePosition(crossAxis, directionRespectingRoot, crossSize);
+
+  const Edge mainAxisLeadingEdge =
+      getInlineStartEdgeUsingErrata(mainAxis, direction);
+  const Edge mainAxisTrailingEdge =
+      getInlineEndEdgeUsingErrata(mainAxis, direction);
+  const Edge crossAxisLeadingEdge =
+      getInlineStartEdgeUsingErrata(crossAxis, direction);
+  const Edge crossAxisTrailingEdge =
+      getInlineEndEdgeUsingErrata(crossAxis, direction);
+
+  setLayoutPosition(
+      (getInlineStartMargin(mainAxis, direction, ownerWidth) +
+       relativePositionMain),
+      mainAxisLeadingEdge);
+  setLayoutPosition(
+      (getInlineEndMargin(mainAxis, direction, ownerWidth) +
+       relativePositionMain),
+      mainAxisTrailingEdge);
+  setLayoutPosition(
+      (getInlineStartMargin(crossAxis, direction, ownerWidth) +
+       relativePositionCross),
+      crossAxisLeadingEdge);
+  setLayoutPosition(
+      (getInlineEndMargin(crossAxis, direction, ownerWidth) +
+       relativePositionCross),
+      crossAxisTrailingEdge);
+}
+
+Style::Length Node::getFlexStartMarginValue(FlexDirection axis) const {
+  if (isRow(axis) && style_.margin(Edge::Start).isDefined()) {
+    return style_.margin(Edge::Start);
+  } else {
+    return style_.margin(flexStartEdge(axis));
+  }
+}
+
+Style::Length Node::marginTrailingValue(FlexDirection axis) const {
+  if (isRow(axis) && style_.margin(Edge::End).isDefined()) {
+    return style_.margin(Edge::End);
+  } else {
+    return style_.margin(flexEndEdge(axis));
+  }
+}
+
+Style::Length Node::resolveFlexBasisPtr() const {
+  Style::Length flexBasis = style_.flexBasis();
+  if (flexBasis.unit() != Unit::Auto && flexBasis.unit() != Unit::Undefined) {
+    return flexBasis;
+  }
+  if (style_.flex().isDefined() && style_.flex().unwrap() > 0.0f) {
+    return config_->useWebDefaults() ? value::ofAuto() : value::points(0);
+  }
+  return value::ofAuto();
+}
+
+void Node::resolveDimension() {
+  const Style& style = getStyle();
+  for (auto dim : {Dimension::Width, Dimension::Height}) {
+    if (style.maxDimension(dim).isDefined() &&
+        yoga::inexactEquals(style.maxDimension(dim), style.minDimension(dim))) {
+      resolvedDimensions_[yoga::to_underlying(dim)] = style.maxDimension(dim);
+    } else {
+      resolvedDimensions_[yoga::to_underlying(dim)] = style.dimension(dim);
+    }
+  }
+}
+
+Direction Node::resolveDirection(const Direction ownerDirection) {
+  if (style_.direction() == Direction::Inherit) {
+    return ownerDirection != Direction::Inherit ? ownerDirection
+                                                : Direction::LTR;
+  } else {
+    return style_.direction();
+  }
+}
+
+void Node::clearChildren() {
+  children_.clear();
+  children_.shrink_to_fit();
+}
+
+// Other Methods
+
+void Node::cloneChildrenIfNeeded() {
+  size_t i = 0;
+  for (Node*& child : children_) {
+    if (child->getOwner() != this) {
+      child = resolveRef(config_->cloneNode(child, this, i));
+      child->setOwner(this);
+    }
+    i += 1;
+  }
+}
+
+void Node::markDirtyAndPropagate() {
+  if (!isDirty_) {
+    setDirty(true);
+    setLayoutComputedFlexBasis(FloatOptional());
+    if (owner_) {
+      owner_->markDirtyAndPropagate();
+    }
+  }
+}
+
+float Node::resolveFlexGrow() const {
+  // Root nodes flexGrow should always be 0
+  if (owner_ == nullptr) {
+    return 0.0;
+  }
+  if (style_.flexGrow().isDefined()) {
+    return style_.flexGrow().unwrap();
+  }
+  if (style_.flex().isDefined() && style_.flex().unwrap() > 0.0f) {
+    return style_.flex().unwrap();
+  }
+  return Style::DefaultFlexGrow;
+}
+
+float Node::resolveFlexShrink() const {
+  if (owner_ == nullptr) {
+    return 0.0;
+  }
+  if (style_.flexShrink().isDefined()) {
+    return style_.flexShrink().unwrap();
+  }
+  if (!config_->useWebDefaults() && style_.flex().isDefined() &&
+      style_.flex().unwrap() < 0.0f) {
+    return -style_.flex().unwrap();
+  }
+  return config_->useWebDefaults() ? Style::WebDefaultFlexShrink
+                                   : Style::DefaultFlexShrink;
+}
+
+bool Node::isNodeFlexible() {
+  return (
+      (style_.positionType() != PositionType::Absolute) &&
+      (resolveFlexGrow() != 0 || resolveFlexShrink() != 0));
+}
+
+void Node::reset() {
+  yoga::assertFatalWithNode(
+      this,
+      children_.size() == 0,
+      "Cannot reset a node which still has children attached");
+  yoga::assertFatalWithNode(
+      this, owner_ == nullptr, "Cannot reset a node still attached to a owner");
+
+  *this = Node{getConfig()};
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/node/Node.h view
@@ -0,0 +1,405 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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 <cstdint>
+#include <vector>
+
+#include <yoga/Yoga.h>
+
+#include <yoga/config/Config.h>
+#include <yoga/enums/Dimension.h>
+#include <yoga/enums/Direction.h>
+#include <yoga/enums/Edge.h>
+#include <yoga/enums/Errata.h>
+#include <yoga/enums/MeasureMode.h>
+#include <yoga/enums/NodeType.h>
+#include <yoga/node/LayoutResults.h>
+#include <yoga/style/Style.h>
+
+// Tag struct used to form the opaque YGNodeRef for the public C API
+struct YGNode {};
+
+namespace facebook::yoga {
+
+class YG_EXPORT Node : public ::YGNode {
+ public:
+  Node();
+  explicit Node(const Config* config);
+
+  Node(Node&&);
+
+  // Does not expose true value semantics, as children are not cloned eagerly.
+  // Should we remove this?
+  Node(const Node& node) = default;
+
+  // assignment means potential leaks of existing children, or alternatively
+  // freeing unowned memory, double free, or freeing stack memory.
+  Node& operator=(const Node&) = delete;
+
+  // Getters
+  void* getContext() const {
+    return context_;
+  }
+
+  bool alwaysFormsContainingBlock() const {
+    return alwaysFormsContainingBlock_;
+  }
+
+  void print();
+
+  bool getHasNewLayout() const {
+    return hasNewLayout_;
+  }
+
+  NodeType getNodeType() const {
+    return nodeType_;
+  }
+
+  bool hasMeasureFunc() const noexcept {
+    return measureFunc_ != nullptr;
+  }
+
+  YGSize measure(float, MeasureMode, float, MeasureMode);
+
+  bool hasBaselineFunc() const noexcept {
+    return baselineFunc_ != nullptr;
+  }
+
+  float baseline(float width, float height) const;
+
+  float dimensionWithMargin(const FlexDirection axis, const float widthSize);
+
+  bool isLayoutDimensionDefined(const FlexDirection axis);
+
+  /**
+   * Whether the node has a "definite length" along the given axis.
+   * https://www.w3.org/TR/css-sizing-3/#definite
+   */
+  inline bool hasDefiniteLength(Dimension dimension, float ownerSize) {
+    auto usedValue = getResolvedDimension(dimension).resolve(ownerSize);
+    return usedValue.isDefined() && usedValue.unwrap() >= 0.0f;
+  }
+
+  bool hasErrata(Errata errata) const {
+    return config_->hasErrata(errata);
+  }
+
+  YGDirtiedFunc getDirtiedFunc() const {
+    return dirtiedFunc_;
+  }
+
+  // For Performance reasons passing as reference.
+  Style& getStyle() {
+    return style_;
+  }
+
+  const Style& getStyle() const {
+    return style_;
+  }
+
+  // For Performance reasons passing as reference.
+  LayoutResults& getLayout() {
+    return layout_;
+  }
+
+  const LayoutResults& getLayout() const {
+    return layout_;
+  }
+
+  size_t getLineIndex() const {
+    return lineIndex_;
+  }
+
+  bool isReferenceBaseline() const {
+    return isReferenceBaseline_;
+  }
+
+  // returns the Node that owns this Node. An owner is used to identify
+  // the YogaTree that a Node belongs to. This method will return the parent
+  // of the Node when a Node only belongs to one YogaTree or nullptr when
+  // the Node is shared between two or more YogaTrees.
+  Node* getOwner() const {
+    return owner_;
+  }
+
+  const std::vector<Node*>& getChildren() const {
+    return children_;
+  }
+
+  Node* getChild(size_t index) const {
+    return children_.at(index);
+  }
+
+  size_t getChildCount() const {
+    return children_.size();
+  }
+
+  const Config* getConfig() const {
+    return config_;
+  }
+
+  bool isDirty() const {
+    return isDirty_;
+  }
+
+  std::array<Style::Length, 2> getResolvedDimensions() const {
+    return resolvedDimensions_;
+  }
+
+  Style::Length getResolvedDimension(Dimension dimension) const {
+    return resolvedDimensions_[static_cast<size_t>(dimension)];
+  }
+
+  // Methods related to positions, margin, padding and border
+  bool isFlexStartPositionDefined(FlexDirection axis, Direction direction)
+      const;
+  bool isInlineStartPositionDefined(FlexDirection axis, Direction direction)
+      const;
+  bool isFlexEndPositionDefined(FlexDirection axis, Direction direction) const;
+  bool isInlineEndPositionDefined(FlexDirection axis, Direction direction)
+      const;
+  float getFlexStartPosition(
+      FlexDirection axis,
+      Direction direction,
+      float axisSize) const;
+  float getInlineStartPosition(
+      FlexDirection axis,
+      Direction direction,
+      float axisSize) const;
+  float getFlexEndPosition(
+      FlexDirection axis,
+      Direction direction,
+      float axisSize) const;
+  float getInlineEndPosition(
+      FlexDirection axis,
+      Direction direction,
+      float axisSize) const;
+  float getFlexStartMargin(
+      FlexDirection axis,
+      Direction direction,
+      float widthSize) const;
+  float getInlineStartMargin(
+      FlexDirection axis,
+      Direction direction,
+      float widthSize) const;
+  float getFlexEndMargin(
+      FlexDirection axis,
+      Direction direction,
+      float widthSize) const;
+  float getInlineEndMargin(
+      FlexDirection axis,
+      Direction direction,
+      float widthSize) const;
+  float getFlexStartBorder(FlexDirection flexDirection, Direction direction)
+      const;
+  float getInlineStartBorder(FlexDirection flexDirection, Direction direction)
+      const;
+  float getFlexEndBorder(FlexDirection flexDirection, Direction direction)
+      const;
+  float getInlineEndBorder(FlexDirection flexDirection, Direction direction)
+      const;
+  float getFlexStartPadding(
+      FlexDirection axis,
+      Direction direction,
+      float widthSize) const;
+  float getInlineStartPadding(
+      FlexDirection axis,
+      Direction direction,
+      float widthSize) const;
+  float getFlexEndPadding(
+      FlexDirection axis,
+      Direction direction,
+      float widthSize) const;
+  float getInlineEndPadding(
+      FlexDirection axis,
+      Direction direction,
+      float widthSize) const;
+  float getFlexStartPaddingAndBorder(
+      FlexDirection axis,
+      Direction direction,
+      float widthSize) const;
+  float getInlineStartPaddingAndBorder(
+      FlexDirection axis,
+      Direction direction,
+      float widthSize) const;
+  float getFlexEndPaddingAndBorder(
+      FlexDirection axis,
+      Direction direction,
+      float widthSize) const;
+  float getInlineEndPaddingAndBorder(
+      FlexDirection axis,
+      Direction direction,
+      float widthSize) const;
+  float getBorderForAxis(FlexDirection axis) const;
+  float getMarginForAxis(FlexDirection axis, float widthSize) const;
+  float getGapForAxis(FlexDirection axis) const;
+  // Setters
+
+  void setContext(void* context) {
+    context_ = context;
+  }
+
+  void setAlwaysFormsContainingBlock(bool alwaysFormsContainingBlock) {
+    alwaysFormsContainingBlock_ = alwaysFormsContainingBlock;
+  }
+
+  void setPrintFunc(YGPrintFunc printFunc) {
+    printFunc_ = printFunc;
+  }
+
+  void setHasNewLayout(bool hasNewLayout) {
+    hasNewLayout_ = hasNewLayout;
+  }
+
+  void setNodeType(NodeType nodeType) {
+    nodeType_ = nodeType;
+  }
+
+  void setMeasureFunc(YGMeasureFunc measureFunc);
+
+  void setBaselineFunc(YGBaselineFunc baseLineFunc) {
+    baselineFunc_ = baseLineFunc;
+  }
+
+  void setDirtiedFunc(YGDirtiedFunc dirtiedFunc) {
+    dirtiedFunc_ = dirtiedFunc;
+  }
+
+  void setStyle(const Style& style) {
+    style_ = style;
+  }
+
+  void setLayout(const LayoutResults& layout) {
+    layout_ = layout;
+  }
+
+  void setLineIndex(size_t lineIndex) {
+    lineIndex_ = lineIndex;
+  }
+
+  void setIsReferenceBaseline(bool isReferenceBaseline) {
+    isReferenceBaseline_ = isReferenceBaseline;
+  }
+
+  void setOwner(Node* owner) {
+    owner_ = owner;
+  }
+
+  void setChildren(const std::vector<Node*>& children) {
+    children_ = children;
+  }
+
+  // TODO: rvalue override for setChildren
+
+  void setConfig(Config* config);
+
+  void setDirty(bool isDirty);
+  void setLayoutLastOwnerDirection(Direction direction);
+  void setLayoutComputedFlexBasis(const FloatOptional computedFlexBasis);
+  void setLayoutComputedFlexBasisGeneration(
+      uint32_t computedFlexBasisGeneration);
+  void setLayoutMeasuredDimension(float measuredDimension, Dimension dimension);
+  void setLayoutHadOverflow(bool hadOverflow);
+  void setLayoutDimension(float LengthValue, Dimension dimension);
+  void setLayoutDirection(Direction direction);
+  void setLayoutMargin(float margin, Edge edge);
+  void setLayoutBorder(float border, Edge edge);
+  void setLayoutPadding(float padding, Edge edge);
+  void setLayoutPosition(float position, Edge edge);
+  void setPosition(
+      const Direction direction,
+      const float mainSize,
+      const float crossSize,
+      const float ownerWidth);
+
+  // Other methods
+  Style::Length getFlexStartMarginValue(FlexDirection axis) const;
+  Style::Length marginTrailingValue(FlexDirection axis) const;
+  Style::Length resolveFlexBasisPtr() const;
+  void resolveDimension();
+  Direction resolveDirection(const Direction ownerDirection);
+  void clearChildren();
+  /// Replaces the occurrences of oldChild with newChild
+  void replaceChild(Node* oldChild, Node* newChild);
+  void replaceChild(Node* child, size_t index);
+  void insertChild(Node* child, size_t index);
+  /// Removes the first occurrence of child
+  bool removeChild(Node* child);
+  void removeChild(size_t index);
+
+  void cloneChildrenIfNeeded();
+  void markDirtyAndPropagate();
+  float resolveFlexGrow() const;
+  float resolveFlexShrink() const;
+  bool isNodeFlexible();
+  void reset();
+
+ private:
+  // Used to allow resetting the node
+  Node& operator=(Node&&) = default;
+
+  float relativePosition(
+      FlexDirection axis,
+      Direction direction,
+      const float axisSize) const;
+
+  Edge getInlineStartEdgeUsingErrata(
+      FlexDirection flexDirection,
+      Direction direction) const;
+  Edge getInlineEndEdgeUsingErrata(
+      FlexDirection flexDirection,
+      Direction direction) const;
+  Edge getFlexStartRelativeEdgeUsingErrata(
+      FlexDirection flexDirection,
+      Direction direction) const;
+  Edge getFlexEndRelativeEdgeUsingErrata(
+      FlexDirection flexDirection,
+      Direction direction) const;
+
+  void useWebDefaults() {
+    style_.setFlexDirection(FlexDirection::Row);
+    style_.setAlignContent(Align::Stretch);
+  }
+
+  template <auto Field>
+  Style::Length computeEdgeValueForColumn(Edge edge) const;
+
+  template <auto Field>
+  Style::Length computeEdgeValueForRow(Edge rowEdge, Edge edge) const;
+
+  bool hasNewLayout_ : 1 = true;
+  bool isReferenceBaseline_ : 1 = false;
+  bool isDirty_ : 1 = false;
+  bool alwaysFormsContainingBlock_ : 1 = false;
+  NodeType nodeType_ : bitCount<NodeType>() = NodeType::Default;
+  void* context_ = nullptr;
+  YGMeasureFunc measureFunc_ = {nullptr};
+  YGBaselineFunc baselineFunc_ = {nullptr};
+  YGPrintFunc printFunc_ = {nullptr};
+  YGDirtiedFunc dirtiedFunc_ = nullptr;
+  Style style_ = {};
+  LayoutResults layout_ = {};
+  size_t lineIndex_ = 0;
+  Node* owner_ = nullptr;
+  std::vector<Node*> children_ = {};
+  const Config* config_;
+  std::array<Style::Length, 2> resolvedDimensions_ = {
+      {value::undefined(), value::undefined()}};
+};
+
+inline Node* resolveRef(const YGNodeRef ref) {
+  return static_cast<Node*>(ref);
+}
+
+inline const Node* resolveRef(const YGNodeConstRef ref) {
+  return static_cast<const Node*>(ref);
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/numeric/Comparison.h view
@@ -0,0 +1,81 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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 <concepts>
+
+#include <yoga/Yoga.h>
+
+namespace facebook::yoga {
+
+constexpr bool isUndefined(std::floating_point auto value) {
+  return value != value;
+}
+
+constexpr bool isDefined(std::floating_point auto value) {
+  return !isUndefined(value);
+}
+
+/**
+ * Constexpr version of `std::isinf` before C++ 23
+ */
+constexpr bool isinf(auto value) {
+  return value == +std::numeric_limits<decltype(value)>::infinity() ||
+      value == -std::numeric_limits<decltype(value)>::infinity();
+}
+
+constexpr auto maxOrDefined(
+    std::floating_point auto a,
+    std::floating_point auto b) {
+  if (yoga::isDefined(a) && yoga::isDefined(b)) {
+    return std::max(a, b);
+  }
+  return yoga::isUndefined(a) ? b : a;
+}
+
+constexpr auto minOrDefined(
+    std::floating_point auto a,
+    std::floating_point auto b) {
+  if (yoga::isDefined(a) && yoga::isDefined(b)) {
+    return std::min(a, b);
+  }
+
+  return yoga::isUndefined(a) ? b : a;
+}
+
+// Custom equality functions using a hardcoded epsilon of 0.0001f, or returning
+// true if both floats are NaN.
+inline bool inexactEquals(float a, float b) {
+  if (yoga::isDefined(a) && yoga::isDefined(b)) {
+    return std::abs(a - b) < 0.0001f;
+  }
+  return yoga::isUndefined(a) && yoga::isUndefined(b);
+}
+
+inline bool inexactEquals(double a, double b) {
+  if (yoga::isDefined(a) && yoga::isDefined(b)) {
+    return std::abs(a - b) < 0.0001;
+  }
+  return yoga::isUndefined(a) && yoga::isUndefined(b);
+}
+
+template <std::size_t Size, typename ElementT>
+bool inexactEquals(
+    const std::array<ElementT, Size>& val1,
+    const std::array<ElementT, Size>& val2) {
+  bool areEqual = true;
+  for (std::size_t i = 0; i < Size && areEqual; ++i) {
+    areEqual = inexactEquals(val1[i], val2[i]);
+  }
+  return areEqual;
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/numeric/FloatOptional.h view
@@ -0,0 +1,93 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/numeric/Comparison.h>
+#include <limits>
+
+namespace facebook::yoga {
+
+struct FloatOptional {
+ private:
+  float value_ = std::numeric_limits<float>::quiet_NaN();
+
+ public:
+  explicit constexpr FloatOptional(float value) : value_(value) {}
+  constexpr FloatOptional() = default;
+
+  // returns the wrapped value, or a value x with YGIsUndefined(x) == true
+  constexpr float unwrap() const {
+    return value_;
+  }
+
+  constexpr float unwrapOrDefault(float defaultValue) const {
+    return isUndefined() ? defaultValue : value_;
+  }
+
+  constexpr bool isUndefined() const {
+    return yoga::isUndefined(value_);
+  }
+
+  constexpr bool isDefined() const {
+    return yoga::isDefined(value_);
+  }
+};
+
+// operators take FloatOptional by value, as it is a 32bit value
+
+constexpr bool operator==(FloatOptional lhs, FloatOptional rhs) {
+  return lhs.unwrap() == rhs.unwrap() ||
+      (lhs.isUndefined() && rhs.isUndefined());
+}
+constexpr bool operator!=(FloatOptional lhs, FloatOptional rhs) {
+  return !(lhs == rhs);
+}
+
+constexpr bool operator==(FloatOptional lhs, float rhs) {
+  return lhs == FloatOptional{rhs};
+}
+constexpr bool operator!=(FloatOptional lhs, float rhs) {
+  return !(lhs == rhs);
+}
+
+constexpr bool operator==(float lhs, FloatOptional rhs) {
+  return rhs == lhs;
+}
+constexpr bool operator!=(float lhs, FloatOptional rhs) {
+  return !(lhs == rhs);
+}
+
+constexpr FloatOptional operator+(FloatOptional lhs, FloatOptional rhs) {
+  return FloatOptional{lhs.unwrap() + rhs.unwrap()};
+}
+
+constexpr bool operator>(FloatOptional lhs, FloatOptional rhs) {
+  return lhs.unwrap() > rhs.unwrap();
+}
+
+constexpr bool operator<(FloatOptional lhs, FloatOptional rhs) {
+  return lhs.unwrap() < rhs.unwrap();
+}
+
+constexpr bool operator>=(FloatOptional lhs, FloatOptional rhs) {
+  return lhs > rhs || lhs == rhs;
+}
+
+constexpr bool operator<=(FloatOptional lhs, FloatOptional rhs) {
+  return lhs < rhs || lhs == rhs;
+}
+
+constexpr FloatOptional maxOrDefined(FloatOptional lhs, FloatOptional rhs) {
+  return FloatOptional{yoga::maxOrDefined(lhs.unwrap(), rhs.unwrap())};
+}
+
+inline bool inexactEquals(FloatOptional lhs, FloatOptional rhs) {
+  return yoga::inexactEquals(lhs.unwrap(), rhs.unwrap());
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/style/CompactValue.h view
@@ -0,0 +1,177 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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 <bit>
+#include <cmath>
+#include <cstdint>
+#include <limits>
+
+#include <yoga/YGMacros.h>
+#include <yoga/YGValue.h>
+
+#include <yoga/numeric/Comparison.h>
+#include <yoga/style/StyleLength.h>
+
+static_assert(
+    std::numeric_limits<float>::is_iec559,
+    "facebook::yoga::detail::CompactValue only works with IEEE754 floats");
+
+#ifdef YOGA_COMPACT_VALUE_TEST
+#define VISIBLE_FOR_TESTING public:
+#else
+#define VISIBLE_FOR_TESTING private:
+#endif
+
+namespace facebook::yoga {
+
+// This class stores YGValue in 32 bits.
+// - The value does not matter for Undefined and Auto. NaNs are used for their
+//   representation.
+// - To differentiate between Point and Percent, one exponent bit is used.
+//   Supported the range [0x40, 0xbf] (0xbf is inclusive for point, but
+//   exclusive for percent).
+// - Value ranges:
+//   points:  1.08420217e-19f to 36893485948395847680
+//            0x00000000         0x3fffffff
+//   percent: 1.08420217e-19f to 18446742974197923840
+//            0x40000000         0x7f7fffff
+// - Zero is supported, negative zero is not
+// - values outside of the representable range are clamped
+class CompactValue {
+  friend constexpr bool operator==(CompactValue, CompactValue) noexcept;
+
+ public:
+  static constexpr auto LOWER_BOUND = 1.08420217e-19f;
+  static constexpr auto UPPER_BOUND_POINT = 36893485948395847680.0f;
+  static constexpr auto UPPER_BOUND_PERCENT = 18446742974197923840.0f;
+
+  static constexpr CompactValue ofUndefined() noexcept {
+    return CompactValue{};
+  }
+
+  static constexpr CompactValue ofAuto() noexcept {
+    return CompactValue{AUTO_BITS};
+  }
+
+  constexpr CompactValue() noexcept = default;
+
+  explicit constexpr CompactValue(const StyleLength& x) noexcept {
+    switch (x.unit()) {
+      case Unit::Undefined:
+        *this = ofUndefined();
+        break;
+      case Unit::Auto:
+        *this = ofAuto();
+        break;
+      case Unit::Point:
+        *this = of<Unit::Point>(x.value().unwrap());
+        break;
+      case Unit::Percent:
+        *this = of<Unit::Percent>(x.value().unwrap());
+        break;
+    }
+  }
+
+  explicit operator StyleLength() const noexcept {
+    if (repr_ == 0x7FC00000) {
+      return value::undefined();
+    }
+
+    switch (repr_) {
+      case AUTO_BITS:
+        return value::ofAuto();
+      case ZERO_BITS_POINT:
+        return value::points(0);
+      case ZERO_BITS_PERCENT:
+        return value::percent(0);
+    }
+
+    auto data = repr_;
+    data &= ~PERCENT_BIT;
+    data += BIAS;
+
+    if (repr_ & 0x40000000) {
+      return value::percent(std::bit_cast<float>(data));
+    } else {
+      return value::points(std::bit_cast<float>(data));
+    }
+  }
+
+  bool isUndefined() const noexcept {
+    return (
+        repr_ != AUTO_BITS && repr_ != ZERO_BITS_POINT &&
+        repr_ != ZERO_BITS_PERCENT && std::isnan(std::bit_cast<float>(repr_)));
+  }
+
+  bool isDefined() const noexcept {
+    return !isUndefined();
+  }
+
+  bool isAuto() const noexcept {
+    return repr_ == AUTO_BITS;
+  }
+
+ private:
+  template <Unit UnitT>
+  static CompactValue of(float value) noexcept {
+    if (value == 0.0f || (value < LOWER_BOUND && value > -LOWER_BOUND)) {
+      constexpr auto zero =
+          UnitT == Unit::Percent ? ZERO_BITS_PERCENT : ZERO_BITS_POINT;
+      return {zero};
+    }
+
+    constexpr auto upperBound =
+        UnitT == Unit::Percent ? UPPER_BOUND_PERCENT : UPPER_BOUND_POINT;
+    if (value > upperBound || value < -upperBound) {
+      value = copysignf(upperBound, value);
+    }
+
+    uint32_t unitBit = UnitT == Unit::Percent ? PERCENT_BIT : 0;
+    auto data = std::bit_cast<uint32_t>(value);
+    data -= BIAS;
+    data |= unitBit;
+    return {data};
+  }
+
+  uint32_t repr_{0x7FC00000};
+
+  static constexpr uint32_t BIAS = 0x20000000;
+  static constexpr uint32_t PERCENT_BIT = 0x40000000;
+
+  // these are signaling NaNs with specific bit pattern as payload they will be
+  // silenced whenever going through an FPU operation on ARM + x86
+  static constexpr uint32_t AUTO_BITS = 0x7faaaaaa;
+  static constexpr uint32_t ZERO_BITS_POINT = 0x7f8f0f0f;
+  static constexpr uint32_t ZERO_BITS_PERCENT = 0x7f80f0f0;
+
+  constexpr CompactValue(uint32_t data) noexcept : repr_(data) {}
+
+  VISIBLE_FOR_TESTING uint32_t repr() {
+    return repr_;
+  }
+};
+
+template <>
+CompactValue CompactValue::of<Unit::Undefined>(float) noexcept = delete;
+template <>
+CompactValue CompactValue::of<Unit::Auto>(float) noexcept = delete;
+
+constexpr bool operator==(CompactValue a, CompactValue b) noexcept {
+  return a.repr_ == b.repr_;
+}
+
+constexpr bool operator!=(CompactValue a, CompactValue b) noexcept {
+  return !(a == b);
+}
+
+inline bool inexactEquals(CompactValue a, CompactValue b) {
+  return inexactEquals((StyleLength)a, (StyleLength)b);
+}
+
+} // namespace facebook::yoga
+ yoga/yoga/style/Style.h view
@@ -0,0 +1,296 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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 <cstdint>
+#include <type_traits>
+
+#include <yoga/Yoga.h>
+
+#include <yoga/enums/Align.h>
+#include <yoga/enums/Dimension.h>
+#include <yoga/enums/Direction.h>
+#include <yoga/enums/Display.h>
+#include <yoga/enums/Edge.h>
+#include <yoga/enums/FlexDirection.h>
+#include <yoga/enums/Gutter.h>
+#include <yoga/enums/Justify.h>
+#include <yoga/enums/Overflow.h>
+#include <yoga/enums/PositionType.h>
+#include <yoga/enums/Unit.h>
+#include <yoga/enums/Wrap.h>
+#include <yoga/numeric/FloatOptional.h>
+#include <yoga/style/CompactValue.h>
+#include <yoga/style/StyleLength.h>
+
+namespace facebook::yoga {
+
+class YG_EXPORT Style {
+ public:
+  using Length = StyleLength;
+
+  static constexpr float DefaultFlexGrow = 0.0f;
+  static constexpr float DefaultFlexShrink = 0.0f;
+  static constexpr float WebDefaultFlexShrink = 1.0f;
+
+  Direction direction() const {
+    return direction_;
+  }
+  void setDirection(Direction value) {
+    direction_ = value;
+  }
+
+  FlexDirection flexDirection() const {
+    return flexDirection_;
+  }
+  void setFlexDirection(FlexDirection value) {
+    flexDirection_ = value;
+  }
+
+  Justify justifyContent() const {
+    return justifyContent_;
+  }
+  void setJustifyContent(Justify value) {
+    justifyContent_ = value;
+  }
+
+  Align alignContent() const {
+    return alignContent_;
+  }
+  void setAlignContent(Align value) {
+    alignContent_ = value;
+  }
+
+  Align alignItems() const {
+    return alignItems_;
+  }
+  void setAlignItems(Align value) {
+    alignItems_ = value;
+  }
+
+  Align alignSelf() const {
+    return alignSelf_;
+  }
+  void setAlignSelf(Align value) {
+    alignSelf_ = value;
+  }
+
+  PositionType positionType() const {
+    return positionType_;
+  }
+  void setPositionType(PositionType value) {
+    positionType_ = value;
+  }
+
+  Wrap flexWrap() const {
+    return flexWrap_;
+  }
+  void setFlexWrap(Wrap value) {
+    flexWrap_ = value;
+  }
+
+  Overflow overflow() const {
+    return overflow_;
+  }
+  void setOverflow(Overflow value) {
+    overflow_ = value;
+  }
+
+  Display display() const {
+    return display_;
+  }
+  void setDisplay(Display value) {
+    display_ = value;
+  }
+
+  FloatOptional flex() const {
+    return flex_;
+  }
+  void setFlex(FloatOptional value) {
+    flex_ = value;
+  }
+
+  FloatOptional flexGrow() const {
+    return flexGrow_;
+  }
+  void setFlexGrow(FloatOptional value) {
+    flexGrow_ = value;
+  }
+
+  FloatOptional flexShrink() const {
+    return flexShrink_;
+  }
+  void setFlexShrink(FloatOptional value) {
+    flexShrink_ = value;
+  }
+
+  Style::Length flexBasis() const {
+    return (Style::Length)flexBasis_;
+  }
+  void setFlexBasis(Style::Length value) {
+    flexBasis_ = CompactValue(value);
+  }
+
+  Style::Length margin(Edge edge) const {
+    return (Style::Length)margin_[yoga::to_underlying(edge)];
+  }
+  void setMargin(Edge edge, Style::Length value) {
+    margin_[yoga::to_underlying(edge)] = CompactValue(value);
+  }
+
+  Style::Length position(Edge edge) const {
+    return (Style::Length)position_[yoga::to_underlying(edge)];
+  }
+  void setPosition(Edge edge, Style::Length value) {
+    position_[yoga::to_underlying(edge)] = CompactValue(value);
+  }
+
+  Style::Length padding(Edge edge) const {
+    return (Style::Length)padding_[yoga::to_underlying(edge)];
+  }
+  void setPadding(Edge edge, Style::Length value) {
+    padding_[yoga::to_underlying(edge)] = CompactValue(value);
+  }
+
+  Style::Length border(Edge edge) const {
+    return (Style::Length)border_[yoga::to_underlying(edge)];
+  }
+  void setBorder(Edge edge, Style::Length value) {
+    border_[yoga::to_underlying(edge)] = CompactValue(value);
+  }
+
+  Style::Length gap(Gutter gutter) const {
+    return (Style::Length)gap_[yoga::to_underlying(gutter)];
+  }
+  void setGap(Gutter gutter, Style::Length value) {
+    gap_[yoga::to_underlying(gutter)] = CompactValue(value);
+  }
+
+  Style::Length dimension(Dimension axis) const {
+    return (Style::Length)dimensions_[yoga::to_underlying(axis)];
+  }
+  void setDimension(Dimension axis, Style::Length value) {
+    dimensions_[yoga::to_underlying(axis)] = CompactValue(value);
+  }
+
+  Style::Length minDimension(Dimension axis) const {
+    return (Style::Length)minDimensions_[yoga::to_underlying(axis)];
+  }
+  void setMinDimension(Dimension axis, Style::Length value) {
+    minDimensions_[yoga::to_underlying(axis)] = CompactValue(value);
+  }
+
+  Style::Length maxDimension(Dimension axis) const {
+    return (Style::Length)maxDimensions_[yoga::to_underlying(axis)];
+  }
+  void setMaxDimension(Dimension axis, Style::Length value) {
+    maxDimensions_[yoga::to_underlying(axis)] = CompactValue(value);
+  }
+
+  FloatOptional aspectRatio() const {
+    return aspectRatio_;
+  }
+  void setAspectRatio(FloatOptional value) {
+    aspectRatio_ = value;
+  }
+
+  Style::Length resolveColumnGap() const {
+    if (gap_[yoga::to_underlying(Gutter::Column)].isDefined()) {
+      return (Style::Length)gap_[yoga::to_underlying(Gutter::Column)];
+    } else {
+      return (Style::Length)gap_[yoga::to_underlying(Gutter::All)];
+    }
+  }
+
+  Style::Length resolveRowGap() const {
+    if (gap_[yoga::to_underlying(Gutter::Row)].isDefined()) {
+      return (Style::Length)gap_[yoga::to_underlying(Gutter::Row)];
+    } else {
+      return (Style::Length)gap_[yoga::to_underlying(Gutter::All)];
+    }
+  }
+
+  bool horizontalInsetsDefined() const {
+    return position_[YGEdge::YGEdgeLeft].isDefined() ||
+        position_[YGEdge::YGEdgeRight].isDefined() ||
+        position_[YGEdge::YGEdgeAll].isDefined() ||
+        position_[YGEdge::YGEdgeHorizontal].isDefined() ||
+        position_[YGEdge::YGEdgeStart].isDefined() ||
+        position_[YGEdge::YGEdgeEnd].isDefined();
+  }
+
+  bool verticalInsetsDefined() const {
+    return position_[YGEdge::YGEdgeTop].isDefined() ||
+        position_[YGEdge::YGEdgeBottom].isDefined() ||
+        position_[YGEdge::YGEdgeAll].isDefined() ||
+        position_[YGEdge::YGEdgeVertical].isDefined();
+  }
+
+  bool operator==(const Style& other) const {
+    return direction_ == other.direction_ &&
+        flexDirection_ == other.flexDirection_ &&
+        justifyContent_ == other.justifyContent_ &&
+        alignContent_ == other.alignContent_ &&
+        alignItems_ == other.alignItems_ && alignSelf_ == other.alignSelf_ &&
+        positionType_ == other.positionType_ && flexWrap_ == other.flexWrap_ &&
+        overflow_ == other.overflow_ && display_ == other.display_ &&
+        inexactEquals(flex_, other.flex_) &&
+        inexactEquals(flexGrow_, other.flexGrow_) &&
+        inexactEquals(flexShrink_, other.flexShrink_) &&
+        inexactEquals(flexBasis_, other.flexBasis_) &&
+        inexactEquals(margin_, other.margin_) &&
+        inexactEquals(position_, other.position_) &&
+        inexactEquals(padding_, other.padding_) &&
+        inexactEquals(border_, other.border_) &&
+        inexactEquals(gap_, other.gap_) &&
+        inexactEquals(dimensions_, other.dimensions_) &&
+        inexactEquals(minDimensions_, other.minDimensions_) &&
+        inexactEquals(maxDimensions_, other.maxDimensions_) &&
+        inexactEquals(aspectRatio_, other.aspectRatio_);
+  }
+
+  bool operator!=(const Style& other) const {
+    return !(*this == other);
+  }
+
+ private:
+  using Dimensions = std::array<CompactValue, ordinalCount<Dimension>()>;
+  using Edges = std::array<CompactValue, ordinalCount<Edge>()>;
+  using Gutters = std::array<CompactValue, ordinalCount<Gutter>()>;
+
+  Direction direction_ : bitCount<Direction>() = Direction::Inherit;
+  FlexDirection flexDirection_
+      : bitCount<FlexDirection>() = FlexDirection::Column;
+  Justify justifyContent_ : bitCount<Justify>() = Justify::FlexStart;
+  Align alignContent_ : bitCount<Align>() = Align::FlexStart;
+  Align alignItems_ : bitCount<Align>() = Align::Stretch;
+  Align alignSelf_ : bitCount<Align>() = Align::Auto;
+  PositionType positionType_
+      : bitCount<PositionType>() = PositionType::Relative;
+  Wrap flexWrap_ : bitCount<Wrap>() = Wrap::NoWrap;
+  Overflow overflow_ : bitCount<Overflow>() = Overflow::Visible;
+  Display display_ : bitCount<Display>() = Display::Flex;
+
+  FloatOptional flex_{};
+  FloatOptional flexGrow_{};
+  FloatOptional flexShrink_{};
+  CompactValue flexBasis_{CompactValue::ofAuto()};
+  Edges margin_{};
+  Edges position_{};
+  Edges padding_{};
+  Edges border_{};
+  Gutters gap_{};
+  Dimensions dimensions_{CompactValue::ofAuto(), CompactValue::ofAuto()};
+  Dimensions minDimensions_{};
+  Dimensions maxDimensions_{};
+  FloatOptional aspectRatio_{};
+};
+
+} // namespace facebook::yoga
+ yoga/yoga/style/StyleLength.h view
@@ -0,0 +1,139 @@+/*
+ * Copyright (c) Meta Platforms, Inc. and 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/enums/Unit.h>
+#include <yoga/numeric/FloatOptional.h>
+
+namespace facebook::yoga {
+
+/**
+ * Style::Length represents a CSS Value which may be one of:
+ * 1. Undefined
+ * 2. A keyword (e.g. auto)
+ * 3. A CSS <length-percentage> value:
+ *    a. <length> value (e.g. 10px)
+ *    b. <percentage> value of a reference <length>
+ * 4. (soon) A math function which returns a <length-percentage> value
+ *
+ * References:
+ * 1. https://www.w3.org/TR/css-values-4/#lengths
+ * 2. https://www.w3.org/TR/css-values-4/#percentage-value
+ * 3. https://www.w3.org/TR/css-values-4/#mixed-percentages
+ * 4. https://www.w3.org/TR/css-values-4/#math
+ */
+class StyleLength {
+ public:
+  constexpr StyleLength() = default;
+
+  constexpr static StyleLength points(float value) {
+    return yoga::isUndefined(value) || yoga::isinf(value)
+        ? undefined()
+        : StyleLength{FloatOptional{value}, Unit::Point};
+  }
+
+  constexpr static StyleLength percent(float value) {
+    return yoga::isUndefined(value) || yoga::isinf(value)
+        ? undefined()
+        : StyleLength{FloatOptional{value}, Unit::Percent};
+  }
+
+  constexpr static StyleLength ofAuto() {
+    return StyleLength{{}, Unit::Auto};
+  }
+
+  constexpr static StyleLength undefined() {
+    return StyleLength{{}, Unit::Undefined};
+  }
+
+  constexpr bool isAuto() const {
+    return unit_ == Unit::Auto;
+  }
+
+  constexpr bool isUndefined() const {
+    return unit_ == Unit::Undefined;
+  }
+
+  constexpr bool isDefined() const {
+    return !isUndefined();
+  }
+
+  constexpr FloatOptional value() const {
+    return value_;
+  }
+
+  constexpr Unit unit() const {
+    return unit_;
+  }
+
+  constexpr FloatOptional resolve(float referenceLength) {
+    switch (unit_) {
+      case Unit::Point:
+        return value_;
+      case Unit::Percent:
+        return FloatOptional{value_.unwrap() * referenceLength * 0.01f};
+      default:
+        return FloatOptional{};
+    }
+  }
+
+  explicit constexpr operator YGValue() const {
+    return YGValue{value_.unwrap(), unscopedEnum(unit_)};
+  }
+
+  constexpr bool operator==(const StyleLength& rhs) const {
+    return value_ == rhs.value_ && unit_ == rhs.unit_;
+  }
+
+ private:
+  // We intentionally do not allow direct construction using value and unit, to
+  // avoid invalid, or redundant combinations.
+  constexpr StyleLength(FloatOptional value, Unit unit)
+      : value_(value), unit_(unit) {}
+
+  FloatOptional value_{};
+  Unit unit_{Unit::Undefined};
+};
+
+inline bool inexactEquals(const StyleLength& a, const StyleLength& b) {
+  return a.unit() == b.unit() && inexactEquals(a.value(), b.value());
+}
+
+namespace value {
+
+/**
+ * Canonical unit (one YGUnitPoint)
+ */
+constexpr StyleLength points(float value) {
+  return StyleLength::points(value);
+}
+
+/**
+ * Percent of reference
+ */
+constexpr StyleLength percent(float value) {
+  return StyleLength::percent(value);
+}
+
+/**
+ * "auto" keyword
+ */
+constexpr StyleLength ofAuto() {
+  return StyleLength::ofAuto();
+}
+
+/**
+ * Undefined
+ */
+constexpr StyleLength undefined() {
+  return StyleLength::undefined();
+}
+
+} // namespace value
+
+} // namespace facebook::yoga