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