diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index 05b862ffe590e5..7a8deae4116050 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -981,6 +981,10 @@ 3DFE0D1B1DF8575800459392 /* YGMacros.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 130A77041DF767AF001F9587 /* YGMacros.h */; }; 3DFE0D1C1DF8575800459392 /* Yoga.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 130A77081DF767AF001F9587 /* Yoga.h */; }; 3EDCA8A51D3591E700450C31 /* RCTErrorInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EDCA8A41D3591E700450C31 /* RCTErrorInfo.m */; }; + 5376C5E41FC6DDBC0083513D /* YGNodePrint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5376C5E11FC6DDB20083513D /* YGNodePrint.cpp */; }; + 5376C5E51FC6DDBD0083513D /* YGNodePrint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5376C5E11FC6DDB20083513D /* YGNodePrint.cpp */; }; + 5376C5E61FC6DDC10083513D /* YGNodePrint.h in Headers */ = {isa = PBXBuildFile; fileRef = 5376C5E01FC6DDB20083513D /* YGNodePrint.h */; }; + 5376C5E71FC6DDC20083513D /* YGNodePrint.h in Headers */ = {isa = PBXBuildFile; fileRef = 5376C5E01FC6DDB20083513D /* YGNodePrint.h */; }; 53D123971FBF1DF5001B8A10 /* libyoga.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D3C059A1DE3340900C268FA /* libyoga.a */; }; 53D1239A1FBF1EF2001B8A10 /* YGEnums.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53CBF1861FB4FE80002CBB31 /* YGEnums.cpp */; }; 53D1239B1FBF1EF4001B8A10 /* YGEnums.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53CBF1861FB4FE80002CBB31 /* YGEnums.cpp */; }; @@ -2051,6 +2055,8 @@ 3EDCA8A21D3591E700450C31 /* RCTErrorCustomizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTErrorCustomizer.h; sourceTree = ""; }; 3EDCA8A31D3591E700450C31 /* RCTErrorInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTErrorInfo.h; sourceTree = ""; }; 3EDCA8A41D3591E700450C31 /* RCTErrorInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTErrorInfo.m; sourceTree = ""; }; + 5376C5E01FC6DDB20083513D /* YGNodePrint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGNodePrint.h; sourceTree = ""; }; + 5376C5E11FC6DDB20083513D /* YGNodePrint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGNodePrint.cpp; sourceTree = ""; }; 53CBF1851FB4FE80002CBB31 /* Yoga-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Yoga-internal.h"; sourceTree = ""; }; 53CBF1861FB4FE80002CBB31 /* YGEnums.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGEnums.cpp; sourceTree = ""; }; 53CBF1871FB4FE80002CBB31 /* Yoga.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Yoga.cpp; sourceTree = ""; }; @@ -2215,6 +2221,8 @@ 130A77021DF767AF001F9587 /* yoga */ = { isa = PBXGroup; children = ( + 5376C5E11FC6DDB20083513D /* YGNodePrint.cpp */, + 5376C5E01FC6DDB20083513D /* YGNodePrint.h */, 53CBF1861FB4FE80002CBB31 /* YGEnums.cpp */, 53CBF1881FB4FE80002CBB31 /* YGNodeList.cpp */, 53CBF1851FB4FE80002CBB31 /* Yoga-internal.h */, @@ -3100,6 +3108,7 @@ 3DFE0D161DF8574D00459392 /* YGEnums.h in Headers */, 3DFE0D171DF8574D00459392 /* YGMacros.h in Headers */, 3DFE0D181DF8574D00459392 /* YGNodeList.h in Headers */, + 5376C5E71FC6DDC20083513D /* YGNodePrint.h in Headers */, 3DFE0D191DF8574D00459392 /* Yoga.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3177,6 +3186,7 @@ 133957881DF76D3500EC27BE /* YGEnums.h in Headers */, 1339578B1DF76D3500EC27BE /* Yoga.h in Headers */, 1339578A1DF76D3500EC27BE /* YGNodeList.h in Headers */, + 5376C5E61FC6DDC10083513D /* YGNodePrint.h in Headers */, 133957891DF76D3500EC27BE /* YGMacros.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4053,6 +4063,7 @@ 53D123A01FBF1EFF001B8A10 /* Yoga.cpp in Sources */, 53D1239A1FBF1EF2001B8A10 /* YGEnums.cpp in Sources */, 53D1239C1FBF1EF7001B8A10 /* YGNodeList.cpp in Sources */, + 5376C5E41FC6DDBC0083513D /* YGNodePrint.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4063,6 +4074,7 @@ 53D123A11FBF1EFF001B8A10 /* Yoga.cpp in Sources */, 53D1239B1FBF1EF4001B8A10 /* YGEnums.cpp in Sources */, 53D1239D1FBF1EF7001B8A10 /* YGNodeList.cpp in Sources */, + 5376C5E51FC6DDBD0083513D /* YGNodePrint.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/React/ReactLegacy.xcodeproj/project.pbxproj b/React/ReactLegacy.xcodeproj/project.pbxproj index 99f9374ca3624f..fc24bfc3c5e615 100644 --- a/React/ReactLegacy.xcodeproj/project.pbxproj +++ b/React/ReactLegacy.xcodeproj/project.pbxproj @@ -679,6 +679,10 @@ 3DFE0D1B1DF8575800459392 /* YGMacros.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 130A77041DF767AF001F9587 /* YGMacros.h */; }; 3DFE0D1C1DF8575800459392 /* Yoga.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 130A77081DF767AF001F9587 /* Yoga.h */; }; 3EDCA8A51D3591E700450C31 /* RCTErrorInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EDCA8A41D3591E700450C31 /* RCTErrorInfo.m */; }; + 53330EE71FC6EE74008D7FA9 /* YGNodePrint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53330EE41FC6EE70008D7FA9 /* YGNodePrint.cpp */; }; + 53330EE81FC6EE75008D7FA9 /* YGNodePrint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53330EE41FC6EE70008D7FA9 /* YGNodePrint.cpp */; }; + 53330EEA1FC6EE7F008D7FA9 /* YGNodePrint.h in Headers */ = {isa = PBXBuildFile; fileRef = 53330EE31FC6EE70008D7FA9 /* YGNodePrint.h */; }; + 53330EEB1FC6EE7F008D7FA9 /* YGNodePrint.h in Headers */ = {isa = PBXBuildFile; fileRef = 53330EE31FC6EE70008D7FA9 /* YGNodePrint.h */; }; 53CBF1BF1FB50263002CBB31 /* Yoga-internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 53CBF1BB1FB50262002CBB31 /* Yoga-internal.h */; }; 53CBF1C01FB50263002CBB31 /* YGEnums.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53CBF1BC1FB50263002CBB31 /* YGEnums.cpp */; }; 53CBF1C11FB50263002CBB31 /* Yoga.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53CBF1BD1FB50263002CBB31 /* Yoga.cpp */; }; @@ -1347,6 +1351,8 @@ 3EDCA8A21D3591E700450C31 /* RCTErrorCustomizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTErrorCustomizer.h; sourceTree = ""; }; 3EDCA8A31D3591E700450C31 /* RCTErrorInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTErrorInfo.h; sourceTree = ""; }; 3EDCA8A41D3591E700450C31 /* RCTErrorInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTErrorInfo.m; sourceTree = ""; }; + 53330EE31FC6EE70008D7FA9 /* YGNodePrint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGNodePrint.h; sourceTree = ""; }; + 53330EE41FC6EE70008D7FA9 /* YGNodePrint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGNodePrint.cpp; sourceTree = ""; }; 53CBF1BB1FB50262002CBB31 /* Yoga-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Yoga-internal.h"; sourceTree = ""; }; 53CBF1BC1FB50263002CBB31 /* YGEnums.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGEnums.cpp; sourceTree = ""; }; 53CBF1BD1FB50263002CBB31 /* Yoga.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Yoga.cpp; sourceTree = ""; }; @@ -1464,6 +1470,8 @@ 130A77021DF767AF001F9587 /* yoga */ = { isa = PBXGroup; children = ( + 53330EE41FC6EE70008D7FA9 /* YGNodePrint.cpp */, + 53330EE31FC6EE70008D7FA9 /* YGNodePrint.h */, 53CBF1BC1FB50263002CBB31 /* YGEnums.cpp */, 53CBF1BE1FB50263002CBB31 /* YGNodeList.cpp */, 53CBF1BB1FB50262002CBB31 /* Yoga-internal.h */, @@ -2048,6 +2056,7 @@ 3DFE0D171DF8574D00459392 /* YGMacros.h in Headers */, 3DFE0D181DF8574D00459392 /* YGNodeList.h in Headers */, 3DFE0D191DF8574D00459392 /* Yoga.h in Headers */, + 53330EEB1FC6EE7F008D7FA9 /* YGNodePrint.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2077,6 +2086,7 @@ 1339578B1DF76D3500EC27BE /* Yoga.h in Headers */, 1339578A1DF76D3500EC27BE /* YGNodeList.h in Headers */, 133957891DF76D3500EC27BE /* YGMacros.h in Headers */, + 53330EEA1FC6EE7F008D7FA9 /* YGNodePrint.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2615,6 +2625,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 53330EE71FC6EE74008D7FA9 /* YGNodePrint.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2622,6 +2633,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 53330EE81FC6EE75008D7FA9 /* YGNodePrint.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/ReactCommon/yoga/Android.mk b/ReactCommon/yoga/Android.mk index b9a460e7ca7b99..0b7d7237219430 100644 --- a/ReactCommon/yoga/Android.mk +++ b/ReactCommon/yoga/Android.mk @@ -7,7 +7,8 @@ LOCAL_MODULE := yogacore LOCAL_SRC_FILES := \ yoga/Yoga.cpp \ yoga/YGEnums.cpp \ - yoga/YGNodeList.cpp + yoga/YGNodeList.cpp \ + yoga/YGNodePrint.cpp LOCAL_C_INCLUDES := $(LOCAL_PATH) LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) diff --git a/ReactCommon/yoga/yoga/YGNodePrint.cpp b/ReactCommon/yoga/yoga/YGNodePrint.cpp new file mode 100644 index 00000000000000..0d8ee75bdac4ff --- /dev/null +++ b/ReactCommon/yoga/yoga/YGNodePrint.cpp @@ -0,0 +1,220 @@ +/* + * 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 +#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(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, "
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 = YGNodeListCount(node->children); + 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, "
"); +} +} // namespace yoga +} // namespace facebook diff --git a/ReactCommon/yoga/yoga/YGNodePrint.h b/ReactCommon/yoga/yoga/YGNodePrint.h new file mode 100644 index 00000000000000..18942b7bfd19a6 --- /dev/null +++ b/ReactCommon/yoga/yoga/YGNodePrint.h @@ -0,0 +1,24 @@ +/** + * 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 + +#include "Yoga.h" + +namespace facebook { +namespace yoga { + +void YGNodeToString( + std::string* str, + YGNodeRef node, + YGPrintOptions options, + uint32_t level); + +} // namespace yoga +} // namespace facebook diff --git a/ReactCommon/yoga/yoga/Yoga-internal.h b/ReactCommon/yoga/yoga/Yoga-internal.h index 7689b9257b4a0e..b85db0ea895d81 100644 --- a/ReactCommon/yoga/yoga/Yoga-internal.h +++ b/ReactCommon/yoga/yoga/Yoga-internal.h @@ -8,6 +8,8 @@ */ #pragma once +#include "YGNodeList.h" +#include "Yoga.h" YG_EXTERN_C_BEGIN @@ -17,3 +19,209 @@ WIN_EXPORT float YGRoundValueToPixelGrid(const float value, 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; + YGNodeListRef 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 = nullptr, + .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); diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 960a4f3bb3f582..8ff8921abbd0ff 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -10,6 +10,7 @@ #include #include "YGNodeList.h" +#include "YGNodePrint.h" #include "Yoga-internal.h" #include "Yoga.h" @@ -30,202 +31,6 @@ __forceinline const float fmaxf(const float a, const float b) { #endif #endif -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; - YGNodeListRef 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 = nullptr, - .nextChild = nullptr, - .measure = nullptr, - .baseline = nullptr, - .print = nullptr, - .config = nullptr, - .context = nullptr, - .isDirty = false, - .hasNewLayout = true, - .nodeType = YGNodeTypeDefault, - .resolvedDimensions = {[YGDimensionWidth] = &YGValueUndefined, - [YGDimensionHeight] = &YGValueUndefined}, -}; - #ifdef ANDROID static int YGAndroidLog(const YGConfigRef config, const YGNodeRef node, @@ -316,9 +121,10 @@ bool YGFloatIsUndefined(const float value) { return isnan(value); } -static inline const YGValue *YGComputedEdgeValue(const YGValue edges[YGEdgeCount], - const YGEdge edge, - const YGValue *const defaultValue) { +const YGValue* YGComputedEdgeValue( + const YGValue edges[YGEdgeCount], + const YGEdge edge, + const YGValue* const defaultValue) { if (edges[edge].unit != YGUnitUndefined) { return &edges[edge]; } @@ -940,7 +746,7 @@ bool YGLayoutNodeInternal(const YGNodeRef node, const char *reason, const YGConfigRef config); -static inline bool YGValueEqual(const YGValue a, const YGValue b) { +bool YGValueEqual(const YGValue a, const YGValue b) { if (a.unit != b.unit) { return false; } @@ -963,222 +769,18 @@ static inline void YGResolveDimensions(YGNodeRef node) { } } -static inline bool YGFloatsEqual(const float a, const float b) { +bool YGFloatsEqual(const float a, const float b) { if (YGFloatIsUndefined(a)) { return YGFloatIsUndefined(b); } return fabs(a - b) < 0.0001f; } -typedef struct YGStringStream { - char *str; - uint32_t length; - uint32_t capacity; -} YGStringStream; - -static void YGWriteToStringStream(YGStringStream *stream, const char *format, ...) { - va_list args; - va_start(args, format); - va_list argsCopy; - va_copy(argsCopy, args); - int available = stream->capacity - stream->length; - int required = vsnprintf(nullptr, 0, format, args); - va_end(args); - if (required >= available) { - char *newStr = (char *) realloc(stream->str, sizeof(char) * (stream->capacity) * 2); - if (newStr != nullptr) { - stream->str = newStr; - stream->capacity *= 2; - available = stream->capacity - stream->length; - } - }; - vsnprintf(stream->str + stream->length, available, format, argsCopy); - if (required < available) { - stream->length += required; - } else { - stream->length = stream->capacity - 1; - } - va_end(argsCopy); -} - -static void YGIndent(YGStringStream *stream, const uint32_t n) { - for (uint32_t i = 0; i < n; i++) { - YGWriteToStringStream(stream, " "); - } -} - -static void YGPrintNumberIfNotUndefinedf(YGStringStream *stream, - const char *str, - const float number) { - if (!YGFloatIsUndefined(number)) { - YGWriteToStringStream(stream, "%s: %g; ", str, number); - } -} - -static void YGPrintNumberIfNotUndefined(YGStringStream *stream, - const char *str, - const YGValue *const number) { - if (number->unit != YGUnitUndefined) { - if (number->unit == YGUnitAuto) { - YGWriteToStringStream(stream, "%s: auto; ", str); - } else { - const char *unit = number->unit == YGUnitPoint ? "px" : "%%"; - YGWriteToStringStream(stream, "%s: %g%s; ", str, number->value, unit); - } - } -} - -static void YGPrintNumberIfNotAuto(YGStringStream *stream, - const char *str, - const YGValue *const number) { - if (number->unit != YGUnitAuto) { - YGPrintNumberIfNotUndefined(stream, str, number); - } -} - -static void YGPrintEdgeIfNotUndefined(YGStringStream *stream, - const char *str, - const YGValue *edges, - const YGEdge edge) { - YGPrintNumberIfNotUndefined(stream, str, YGComputedEdgeValue(edges, edge, &YGValueUndefined)); -} - -static void YGPrintNumberIfNotZero(YGStringStream *stream, - const char *str, - const YGValue *const number) { - if (!YGFloatsEqual(number->value, 0)) { - YGPrintNumberIfNotUndefined(stream, str, number); - } -} - -static bool YGFourValuesEqual(const YGValue four[4]) { - return YGValueEqual(four[0], four[1]) && YGValueEqual(four[0], four[2]) && - YGValueEqual(four[0], four[3]); -} - -static void YGPrintEdges(YGStringStream *stream, const char *str, const YGValue *edges) { - if (YGFourValuesEqual(edges)) { - YGPrintNumberIfNotZero(stream, str, &edges[YGEdgeLeft]); - } else { - for (uint32_t edge = 0; edge < YGEdgeCount; edge++) { - char buf[30]; - snprintf(buf, sizeof(buf), "%s-%s", str, YGEdgeToString((YGEdge)edge)); - YGPrintNumberIfNotZero(stream, buf, &edges[edge]); - } - } -} - -static void YGNodeToString(YGStringStream *stream, - const YGNodeRef node, - const YGPrintOptions options, - const uint32_t level) { - YGIndent(stream, level); - YGWriteToStringStream(stream, "
print) { - node->print(node); - } - - if (options & YGPrintOptionsLayout) { - YGWriteToStringStream(stream, "layout=\""); - YGWriteToStringStream(stream, "width: %g; ", node->layout.dimensions[YGDimensionWidth]); - YGWriteToStringStream(stream, "height: %g; ", node->layout.dimensions[YGDimensionHeight]); - YGWriteToStringStream(stream, "top: %g; ", node->layout.position[YGEdgeTop]); - YGWriteToStringStream(stream, "left: %g;", node->layout.position[YGEdgeLeft]); - YGWriteToStringStream(stream, "\" "); - } - - if (options & YGPrintOptionsStyle) { - YGWriteToStringStream(stream, "style=\""); - if (node->style.flexDirection != gYGNodeDefaults.style.flexDirection) { - YGWriteToStringStream(stream, - "flex-direction: %s; ", - YGFlexDirectionToString(node->style.flexDirection)); - } - if (node->style.justifyContent != gYGNodeDefaults.style.justifyContent) { - YGWriteToStringStream(stream, - "justify-content: %s; ", - YGJustifyToString(node->style.justifyContent)); - } - if (node->style.alignItems != gYGNodeDefaults.style.alignItems) { - YGWriteToStringStream(stream, "align-items: %s; ", YGAlignToString(node->style.alignItems)); - } - if (node->style.alignContent != gYGNodeDefaults.style.alignContent) { - YGWriteToStringStream(stream, "align-content: %s; ", YGAlignToString(node->style.alignContent)); - } - if (node->style.alignSelf != gYGNodeDefaults.style.alignSelf) { - YGWriteToStringStream(stream, "align-self: %s; ", YGAlignToString(node->style.alignSelf)); - } - - YGPrintNumberIfNotUndefinedf(stream, "flex-grow", node->style.flexGrow); - YGPrintNumberIfNotUndefinedf(stream, "flex-shrink", node->style.flexShrink); - YGPrintNumberIfNotAuto(stream, "flex-basis", &node->style.flexBasis); - YGPrintNumberIfNotUndefinedf(stream, "flex", node->style.flex); - - if (node->style.flexWrap != gYGNodeDefaults.style.flexWrap) { - YGWriteToStringStream(stream, "flexWrap: %s; ", YGWrapToString(node->style.flexWrap)); - } - - if (node->style.overflow != gYGNodeDefaults.style.overflow) { - YGWriteToStringStream(stream, "overflow: %s; ", YGOverflowToString(node->style.overflow)); - } - - if (node->style.display != gYGNodeDefaults.style.display) { - YGWriteToStringStream(stream, "display: %s; ", YGDisplayToString(node->style.display)); - } - - YGPrintEdges(stream, "margin", node->style.margin); - YGPrintEdges(stream, "padding", node->style.padding); - YGPrintEdges(stream, "border", node->style.border); - - YGPrintNumberIfNotAuto(stream, "width", &node->style.dimensions[YGDimensionWidth]); - YGPrintNumberIfNotAuto(stream, "height", &node->style.dimensions[YGDimensionHeight]); - YGPrintNumberIfNotAuto(stream, "max-width", &node->style.maxDimensions[YGDimensionWidth]); - YGPrintNumberIfNotAuto(stream, "max-height", &node->style.maxDimensions[YGDimensionHeight]); - YGPrintNumberIfNotAuto(stream, "min-width", &node->style.minDimensions[YGDimensionWidth]); - YGPrintNumberIfNotAuto(stream, "min-height", &node->style.minDimensions[YGDimensionHeight]); - - if (node->style.positionType != gYGNodeDefaults.style.positionType) { - YGWriteToStringStream(stream, - "position: %s; ", - YGPositionTypeToString(node->style.positionType)); - } - - YGPrintEdgeIfNotUndefined(stream, "left", node->style.position, YGEdgeLeft); - YGPrintEdgeIfNotUndefined(stream, "right", node->style.position, YGEdgeRight); - YGPrintEdgeIfNotUndefined(stream, "top", node->style.position, YGEdgeTop); - YGPrintEdgeIfNotUndefined(stream, "bottom", node->style.position, YGEdgeBottom); - YGWriteToStringStream(stream, "\" "); - - if (node->measure != nullptr) { - YGWriteToStringStream(stream, "has-custom-measure=\"true\""); - } - } - YGWriteToStringStream(stream, ">"); - - const uint32_t childCount = YGNodeListCount(node->children); - if (options & YGPrintOptionsChildren && childCount > 0) { - for (uint32_t i = 0; i < childCount; i++) { - YGWriteToStringStream(stream, "\n"); - YGNodeToString(stream, YGNodeGetChild(node, i), options, level + 1); - } - YGWriteToStringStream(stream, "\n"); - YGIndent(stream, level); - } - YGWriteToStringStream(stream, "
"); -} - static void YGNodePrintInternal(const YGNodeRef node, const YGPrintOptions options) { - YGStringStream stream; - stream.str = (char *) malloc(sizeof(char) * 1024); - stream.length = 0; - stream.capacity = 1024; - if (stream.str != nullptr) { - YGNodeToString(&stream, node, options, 0); - YGLog(node, YGLogLevelDebug, stream.str); - free(stream.str); - } + std::string str; + facebook::yoga::YGNodeToString(&str, node, options, 0); + YGLog(node, YGLogLevelDebug, str.c_str()); } void YGNodePrint(const YGNodeRef node, const YGPrintOptions options) {